diff --git a/.github/images/addin-samples-gallery-screenshot.jpg b/.github/images/addin-samples-gallery-screenshot.jpg deleted file mode 100644 index df1f9c7a7..000000000 Binary files a/.github/images/addin-samples-gallery-screenshot.jpg and /dev/null differ diff --git a/.github/images/addin-samples-gallery-screenshot.png b/.github/images/addin-samples-gallery-screenshot.png new file mode 100644 index 000000000..cbdbe07e2 Binary files /dev/null and b/.github/images/addin-samples-gallery-screenshot.png differ diff --git a/.github/images/chili-peppers.jpg b/.github/images/chili-peppers.jpg new file mode 100644 index 000000000..4645d4e04 Binary files /dev/null and b/.github/images/chili-peppers.jpg differ diff --git a/.github/images/crustacean.jpg b/.github/images/crustacean.jpg new file mode 100644 index 000000000..121835e5a Binary files /dev/null and b/.github/images/crustacean.jpg differ diff --git a/.github/images/dried-legume.jpg b/.github/images/dried-legume.jpg new file mode 100644 index 000000000..9e2889b05 Binary files /dev/null and b/.github/images/dried-legume.jpg differ diff --git a/.github/images/fruit.jpg b/.github/images/fruit.jpg new file mode 100644 index 000000000..a487e83b5 Binary files /dev/null and b/.github/images/fruit.jpg differ diff --git a/.github/images/green-leaf.jpg b/.github/images/green-leaf.jpg new file mode 100644 index 000000000..0b96fbfcf Binary files /dev/null and b/.github/images/green-leaf.jpg differ diff --git a/.github/images/microsoft-logo.png b/.github/images/microsoft-logo.png new file mode 100644 index 000000000..06600fee7 Binary files /dev/null and b/.github/images/microsoft-logo.png differ diff --git a/.github/images/msn-logo.png b/.github/images/msn-logo.png new file mode 100644 index 000000000..87619f937 Binary files /dev/null and b/.github/images/msn-logo.png differ diff --git a/.github/images/xbox-logo.png b/.github/images/xbox-logo.png new file mode 100644 index 000000000..fbe7abfad Binary files /dev/null and b/.github/images/xbox-logo.png differ diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml new file mode 100644 index 000000000..4cacb51af --- /dev/null +++ b/.github/policies/resourceManagement.yml @@ -0,0 +1,155 @@ +id: +name: GitOps.PullRequestIssueManagement +description: GitOps.PullRequestIssueManagement primitive +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + scheduledSearches: + - description: + frequencies: + - hourly: + hour: 3 + filters: + - isIssue + - isOpen + - hasLabel: + label: 'Needs: author feedback' + - noActivitySince: + days: 4 + - isNotLabeledWith: + label: 'Status: no recent activity' + actions: + - addLabel: + label: 'Status: no recent activity' + - addReply: + reply: This issue has been automatically marked as stale because it is marked as needing author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. Thank you for your interest in Office Add-ins! + - description: + frequencies: + - hourly: + hour: 3 + filters: + - isIssue + - isOpen + - hasLabel: + label: 'Needs: author feedback' + - hasLabel: + label: 'Status: no recent activity' + - noActivitySince: + days: 3 + actions: + - addReply: + reply: This issue has been closed due to inactivity. Please comment if you still need assistance and we'll re-open the issue. + - closeIssue + - description: + frequencies: + - hourly: + hour: 3 + filters: + - isIssue + - isOpen + - hasLabel: + label: 'Type: programming question' + actions: + - addReply: + reply: Thanks for your interest in Office Add-ins development! Feedback here is intended for reporting problems with Script Lab *snippets*. Can you please post your question to Stack Overflow with the [office-js](https://stackoverflow.com/questions/tagged/office-js) tag? By posting how-to questions like this to Stack Overflow, you'll not only be able to reach a broader audience of folks who have expertise in the area, but will also enable others to benefit from any answers that are provided there. Thanks! + - closeIssue + - description: + frequencies: + - hourly: + hour: 3 + filters: + - isIssue + - isOpen + - hasLabel: + label: 'Type: product feature request' + actions: + - addReply: + reply: Thanks for your interest in Office Add-ins development! Feedback here is intended for reporting problems with Script Lab *snippets*. Can you please post this feature request to the [Microsoft 365 Developer Platform Tech Community](https://techcommunity.microsoft.com/t5/microsoft-365-developer-platform/idb-p/Microsoft365DeveloperPlatform)? Feature Requests submitted to Tech Community are regularly reviewed by the product teams as they plan future releases. Thanks! + - closeIssue + eventResponderTasks: + - if: + - payloadType: Issues + - isAction: + action: Opened + - not: isAssignedToSomeone + then: + - addLabel: + label: 'Needs: triage :mag:' + description: + - if: + - payloadType: Issues + - not: + isAction: + action: Closed + - hasLabel: + label: 'Status: no recent activity' + then: + - removeLabel: + label: 'Status: no recent activity' + description: + - if: + - payloadType: Issue_Comment + - hasLabel: + label: 'Status: no recent activity' + then: + - removeLabel: + label: 'Status: no recent activity' + description: + - if: + - payloadType: Issue_Comment + - isAction: + action: Created + - isActivitySender: + issueAuthor: True + - hasLabel: + label: 'Needs: author feedback' + then: + - addLabel: + label: 'Needs: attention :wave:' + - removeLabel: + label: 'Needs: author feedback' + description: + - if: + - payloadType: Pull_Request + then: + - inPrLabel: + label: 'Status: in PR' + description: + - if: + - payloadType: Issues + - labelAdded: + label: 'Status: in PR' + - hasLabel: + label: 'Status: under investigation' + then: + - removeLabel: + label: 'Status: under investigation' + description: + triggerOnOwnActions: true + - if: + - payloadType: Issues + - labelAdded: + label: 'Status: in PR' + - hasLabel: + label: 'Status: in backlog' + then: + - removeLabel: + label: 'Status: in backlog' + description: + triggerOnOwnActions: true + - if: + - payloadType: Issues + - labelAdded: + label: 'Status: in PR' + - hasLabel: + label: 'Needs: attention :wave:' + then: + - removeLabel: + label: 'Needs: attention :wave:' + description: + triggerOnOwnActions: true +onFailure: +onSuccess: diff --git a/.github/workflows/auto-publish.yml b/.github/workflows/auto-publish.yml new file mode 100644 index 000000000..72a284cc6 --- /dev/null +++ b/.github/workflows/auto-publish.yml @@ -0,0 +1,39 @@ +name: auto-publish +run-name: Automatically publish snippets +on: + schedule: + - cron: '15 10 * * TUE' + - cron: '15 10 * * THU' +jobs: + auto-publish: + runs-on: ubuntu-latest + permissions: + contents: write + defaults: + run: + shell: bash + working-directory: ./ + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Check out main + run: | + echo "Checking out main branch" + git config user.name github-actions + git config user.email github-actions@github.com + git checkout main + - name: Check out prod + run: | + echo "Checking out prod branch" + git checkout prod + - name: Merge from main into prod + run: | + echo "Merging from main to prod" + git merge main + - name: Push changes + run: | + echo "Pushing changes to prod branch" + git push origin prod + diff --git a/.gitignore b/.gitignore index 1cb7fa7e3..2d2f29ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,9 @@ typings/** **/*.js **/*.map npm-debug.log* +~$* # Used to ignore "playlists", but having those checked-in for diffing purposes is very useful, so undoing the ignore: -# playlists/** \ No newline at end of file +# playlists/** + +package-lock.json \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 6f4f7b895..11946a9fd 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6.9.4 \ No newline at end of file +6.10.0 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9be1eebd3..000000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: node_js - -cache: - directories: - - node_modules - -git: - depth: 3 - -node_js: -- 6.9.4 - -install: -- npm install - -before_script: -- npm run lint -- npm run tsc - -script: -- npm run build -- npm run deploy - -notifications: - webhooks: - urls: - - https://outlook.office.com/webhook/cd954b0a-08e5-4935-933b-a1cda4e6d5e9@72f988bf-86f1-41af-91ab-2d7cd011db47/TravisCI/c7d4bdd9ff6d4f2e8bce8919d416a064/5bf9ad7e-4cad-45e8-9812-e553da1c05c6 - on_success: change - on_failure: always - on_start: change \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 4e2e4803e..e414c1f67 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,8 +9,28 @@ "request": "launch", "name": "Launch Program", "program": "${workspaceRoot}\\config\\build.js", + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", "outFiles": [] }, + // { + // "type": "node", + // "request": "launch", + // "name": "Launch Program", + // "program": "${workspaceRoot}\\config\\deploy.js", + // "cwd": "${workspaceFolder}", + // "console": "integratedTerminal", + // "outFiles": [], + // "env": { + // "TRAVIS": "true", + // "TRAVIS_BRANCH": "main", + // "TRAVIS_PULL_REQUEST": "false", + // "TRAVIS_COMMIT_MESSAGE": "Deploy", + // "GH_ACCOUNT": "OfficeDev", + // "GH_REPO": "office-js-snippets", + // "GH_TOKEN": + // } + // }, { "type": "node", "request": "attach", diff --git a/README.md b/README.md index 18f5517b7..0fe20ada1 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,101 @@ -[![Build Status](https://travis-ci.com/OfficeDev/office-js-snippets.svg?token=paK2s5RGiCpVHK6bYoFs&branch=master)](https://travis-ci.org/OfficeDev/office-js-snippets) - # Office JS Snippets -A collection of code snippets built with [Script Lab](github.com/OfficeDev/script-lab) -![Script Lab import gallery screenshot](.github/images/addin-samples-gallery-screenshot.jpg) +A collection of code snippets built with [Script Lab](//github.com/OfficeDev/script-lab) +![Script Lab import gallery screenshot](.github/images/addin-samples-gallery-screenshot.png) ## To contribute: -> Note: For all command line interface (CLI) commands mentioned in these instructions, you can use either Git Bash or a Node Command Prompt. +> **Note**: For all command line interface (CLI) commands mentioned in these instructions, you can use either Git Bash or a Node Command Prompt. ### One-time tasks + 1. [Fork](https://help.github.com/articles/about-forks/) this project into your GitHub account. -2. Clone your fork to your development computer. -3. Ensure that you have Node, version 6.10+, installed. (To check the version run the command `node -v`.) -4. Install `yarn` as a global package `npm install yarn --global`. -5. Be sure your CLI is in the root of the office-js-snippets repo and run `yarn install`. (It is similar to `npm install`.) -6. Set up the original \OfficeDev\office-js-snippets as the upstream repo for your local repo by following the steps in [Configuring a remote for a fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/). -7. If you'll be using Visual Studio Code as your editor, install the [TSLint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint) extension for Visual Studio Code. +1. Clone your fork to your development computer. +1. Ensure that you have Node, version 6.10+, installed. (To check the version run the command `node -v`.) +1. Be sure your CLI is in the root of the office-js-snippets repo and run `npm install` to install all dependencies. +1. Set up the original \OfficeDev\office-js-snippets as the upstream repo for your local repo by following the steps in [Configuring a remote for a fork](https://help.github.com/articles/configuring-a-remote-for-a-fork/). +1. If you'll be using Visual Studio Code as your editor, install the [TSLint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint) extension for Visual Studio Code. ### Adding a new sample -> For the git tasks in this procedure, the instructions assume that you are using a CLI. You are welcome to use a GUI git client. Consult the client's help to learn how to carry out the same tasks. +> For the git tasks in this procedure, the instructions assume that you're using a CLI. You are welcome to use a GUI git client. Consult the client's help to learn how to carry out the same tasks. -1. Create a snippet using [Script Lab](https://github.com/OfficeDev/script-lab/blob/master/README.md#what-is). Ensure that the name and description are what you want to be shown publicly. Use standard TypeScript indentation. Improper indentation can cause a failure of the build that you run in a later step. See also the **Style guidelines** section below. -2. Choose the Share icon, and then choose **Copy to Clipboard**. -3. Paste the contents into a text editor. -4. Near the top of the file, you will see the line `api_set: {}`. This needs to be changed to specify the host API version of the most recently added API that is used in your snippet. For example, if the snippet is for Excel and it uses some APIs that were introduced in Excel API 1.3, some in 1.4, and some in 1.5, then you need to specify `ExcelApi 1.5` as the value of the `api_set` property. Put a line break and four spaces before the value and no {} characters. To continue the example, when you're done the property would look like this: -``` -api_set: - ExcelApi: 1.5 -``` -5. Check the name and description property values, also near the top of the file, and edit as needed. -6. Save the file **somewhere outside of the office-js-snippets project**. (You will move it into the project in a later step.) The file name must have a ".yaml" extension and it must be in [`kebab-case`](http://wiki.c2.com/?KebabCase). For examples, see the existing *.yaml files in the subfolders of the `samples` folder of the project. -7. Make sure the master branch of your fork is in sync with the master branch of the upstream \OfficeDev\office-js-snippets repo by following the steps in [Syncing a fork](https://help.github.com/articles/syncing-a-fork/). -8. Create a new branch at the **office-js-snippets** root folder of your local repo by running the command `git checkout -b {name_of_your_new_branch}`. (This will create and checkout the new branch. *Stay in this branch for all the remaining steps.*) Each snippet should have its own branch. Suggestion: use the name of the yaml file that you created above (without the extension) as the branch name. -9. Decide the project folder to which your snippet should be added. All snippets must be inside the `samples` folder. The structure of the subfolders is: - - The base folders such as `Excel`, `Word` etc. are all the various broad-level categories. - - Inside of each base folder, there are group folders for the group in which a snippet belongs. - - Inside of each group folder, there are `.yaml` which represent a snippet. - - > Note: If your snippet doesn't fit well with any existing group folder, you may want to create a new group folder inside the base folder. If the existing folders in the base folder begin with numbers, such as `03-range`, then your new folder should also begin with a number. The numbers determine the sequence of the groups in Script Lab, so use a number that is between the numbers of the groups between which you want the new folder to appear. - -10. Open one of the `.yaml` files already in the group folder. If it has an `order` property near the top, then the snippets in the group folder are ordered in a particular sequence in Script Lab. Add an `order` property to the top of your `.yaml` file and give it a number that is between the order numbers of the snippets between which you want it to appear. -11. Copy your `.yaml` file to the chosen group folder. -12. Run `npm start`. If there are no problems, the output will end with a `Done!`. If there are errors, review the output to check what caused the build validation to fail, and fix as needed. See **Known errors and fixes** below. - - > Note: The `npm start` command adds an `id` property to the top of the file. - -13. Re-run `npm start`, and fix errors, until the build succeeds. -14. Run `git status`. You should see that, in addition to your new `.yaml` file (or possibly new folder), a `playlist\{host}.yaml` file (where `{host}` is `excel`, `word`, etc.) has also been changed. This is expected. The build tool you just ran added a reference to your new snippet to this file. -15. Run the following two commands. The commit message should be a brief description of what the snippet demonstrates; for example, `"shows how to use getWhatever method"`. -``` -git add -A -git commit -m "{commit message}" -``` -16. Push the snippet to your fork by running: -``` -git push --set-upstream origin {name_of_your_new_branch} -``` -17. You now create a [pull request](https://help.github.com/articles/about-pull-requests/). In your fork on GitHub, *switch to your new branch*. -18. Choose **New pull request**. -19. On the **Open a pull request** page, verify that - - the base fork is `OfficeDev/office-js-snippets` - - the base branch is `master` - - the head fork is `{your-GitHub-account}/office-js-snippets` - - the "compare" branch is `{name_of_your_new_branch}`. -20. The title of the pull request defaults to your commit message. Change it as needed and optionally add a comment to provide additional information about the pull request to the reviewers. -21. All pull requests to office-js-snippets must be approved by at least one reviewer. On the right side of the page is a **Reviewers** section. You can optionally suggest one or more people to review the pull request. (GitHub sometimes lists one or more admins of the repo by default, but it is not consistent in doing this.) Your pull request will be reviewed even if you don't suggest anyone. -22. Choose **Create pull request**. The page for your pull request will open. There will initially be a message on the page saying **Some checks haven’t completed yet**. An online version of the same build tool that you ran locally is testing the files again. It usually takes a few minutes. -> Note: Since your pull request passed locally, it should pass the online test too. Once it a while, the online test fails when the local test passed. This is usually a bug in the online test service. If this happens, cancel the pull request, wait a few hours, and then repeat the steps for creating a pull request. -23. The reviewer(s) may make comments on your pull request and ask you to make changes. Make changes in Script Lab and then repeat the process of creating the `.yaml` file. You do not have to create the new branch again, but make sure it is checked out when you copy the changed `.yaml` file over the previous version. After you commit and push the changed version to your fork, the new version is automatically added to your existing pull request. *Do **not** create a new pull request.* -24. When the reviewer(s) are satisfied, your pull request will be merged to the `master` branch and the pull request will be closed. - - > Note: In a few days, the repo admins will merge your snippet into the `prod` branch. It will then appear in **Samples** area of Script Lab. (It is in the **My Snippets** area as soon as you create it.) - -25. Optionally, you can delete the branch you created from your fork and/or your local clone. +1. Create a snippet using [Script Lab](https://github.com/OfficeDev/script-lab/blob/master/README.md#what-is). Ensure that the name and description are what you want to be shown publicly. Make sure to keep your snippet small. Use standard TypeScript indentation. Improper indentation can cause a failure of the build that you run in a later step. See also the [**Style guidelines**](#style-guidelines) and [**Size restrictions**](#size-restrictions) sections below. +1. Choose the Share icon, and then choose **Copy to Clipboard**. +1. Paste the contents into a text editor. +1. Near the top of the file, you will see the line `api_set: {}`. This needs to be changed to specify the host API version of the most recently added API that is used in your snippet. For example, if the snippet is for Excel and it uses some APIs that were introduced in Excel API 1.3, some in 1.4, and some in 1.5, then you need to specify `ExcelApi 1.5` as the value of the `api_set` property. Put a line break and four spaces before the value and no {} characters. To continue the example, when you're done the property would look like this: + + ```yaml + api_set: + ExcelApi: '1.5' + ``` + +1. Check the name and description property values, also near the top of the file, and edit as needed. +1. Save the file **somewhere outside of the office-js-snippets project**. (You will move it into the project in a later step.) The file name must have a ".yaml" extension and it must be in [`kebab-case`](http://wiki.c2.com/?KebabCase). For examples, see the existing *.yaml files in the subfolders of the `samples` folder of the project. +1. Make sure the main branch of your fork is in sync with the main branch of the upstream \OfficeDev\office-js-snippets repo by following the steps in [Syncing a fork](https://help.github.com/articles/syncing-a-fork/). +1. Create a new branch at the **office-js-snippets** root folder of your local repo by running the command `git checkout -b {name_of_your_new_branch}`. (This will create and checkout the new branch. *Stay in this branch for all the remaining steps.*) Each snippet should have its own branch. Suggestion: use the name of the yaml file that you created above (without the extension) as the branch name. +1. Decide the folder where your snippet should be added. All snippet files must reside within the appropriate subfolder inside the `samples` folder. Within the `samples` folder, the structure of subfolders is as follows: + + - The base folders such as `excel`, `word`, etc. primarily represent the various host applications. + - Within each base folder, group folders organize snippets into various categories. + - Within each group folder, each .yaml file represents a snippet. + + > **Note**: If your snippet doesn't fit with any existing group folder, create a new group folder inside the base folder. If the existing folders in the base folder begin with numbers, such as `03-range`, then your new folder should also begin with a number. Since the numbers determine the sequence of the groups in Script Lab, use a number between the numbers of the groups between which you want the new folder to appear. + +1. Open one of the `.yaml` files already in the group folder. If it has an `order` property near the top, then the snippets in the group folder are ordered in a particular sequence in Script Lab. Add an `order` property to the top of your `.yaml` file and give it a number that is between the order numbers of the snippets between which you want it to appear. +1. Copy your `.yaml` file to the chosen group folder. +1. Run `npm start`. If there are no problems, the output will end with a `Done!`. If there are errors, review the output to check what caused the build validation to fail, and fix as needed. See [**Known errors and fixes**](#known-errors-and-fixes-in-the-build-tool) for more information. + + > **Note**: The `npm start` command adds an `id` property to the top of the file. + +1. Re-run `npm start`, and fix errors, until the build succeeds. +1. Run `git status`. You should see that, in addition to your new `.yaml` file (or possibly new folder), a `playlist\{host}.yaml` file (where `{host}` is `excel`, `word`, etc.) has also been changed. This is expected. The build tool you just ran added a reference to your new snippet to this file. +1. Run the following two commands. The commit message should be a brief description of what the snippet demonstrates; for example, `"shows how to use getWhatever method"`. + + ``` + git add -A + git commit -m "{commit message}" + ``` + +1. Push the snippet to your fork by running: + + ``` + git push --set-upstream origin {name_of_your_new_branch} + ``` + +1. You now create a [pull request](https://help.github.com/articles/about-pull-requests/). In your fork on GitHub, *switch to your new branch*. +1. Choose **New pull request**. +1. On the **Open a pull request** page, verify that: + + - the base fork is `OfficeDev/office-js-snippets` + - the base branch is `main` + - the head fork is `{your-GitHub-account}/office-js-snippets` + - the "compare" branch is `{name_of_your_new_branch}`. + +1. The title of the pull request defaults to your commit message. Change it as needed and optionally add a comment to provide additional information about the pull request to the reviewers. +1. All pull requests to office-js-snippets must be approved by at least one reviewer. On the right side of the page is a **Reviewers** section. You can optionally suggest one or more people to review the pull request. (GitHub sometimes lists one or more admins of the repo by default, but it is not consistent in doing this.) Your pull request will be reviewed even if you don't suggest anyone. +1. Choose **Create pull request**. The page for your pull request will open. There will initially be a message on the page saying **Some checks haven’t completed yet**. An online version of the same build tool that you ran locally is testing the files again. It usually takes a few minutes. + + > **Note**: Since your pull request passed locally, it should pass the online test too. Once in a while, the online test fails when the local test passed. This is usually a bug in the online test service. If this happens, cancel the pull request, wait a few hours, and then repeat the steps for creating a pull request. + +1. The reviewers may make comments on your pull request and ask you to make changes. Make changes in Script Lab and then repeat the process of creating the `.yaml` file. You do not have to create the new branch again, but make sure it is checked out when you copy the changed `.yaml` file over the previous version. After you commit and push the changed version to your fork, the new version is automatically added to your existing pull request. *Do **not** create a new pull request.* +1. When the reviewers are satisfied, your pull request will be merged to the `main` branch and the pull request will be closed. + + > **Note**: In a few days, the repo admins will merge your snippet into the `prod` branch. It will then appear in **Samples** area of Script Lab. (It is in the **My Snippets** area as soon as you create it.) + +1. Optionally, you can delete the branch you created from your fork and/or your local clone. #### Known errors and fixes in the build tool -- An error saying that `name` has upper-case letters or other disallowed characters is *not* referring to the `name` property in the file. It is referring to the file name itself. You'll also get this error, if the file extension is not `.yaml`. +- An error saying that `name` has upper-case letters or other disallowed characters is *not* referring to the `name` property in the file. It is referring to the file name itself. You'll also get this error, if the file extension is not `.yaml`. -## Style guidelines: +## Style guidelines Basic snippet structure is as follows: ```ts -$("#run").click(() => tryCatch(run)); +$("#run").on("click", () => tryCatch(run)); async function run() { await Word.run(async (context) => { @@ -111,17 +120,35 @@ async function tryCatch(callback) { A few style rules to observe: -* Use standard TypeScript indentation. -* For each button, define a corresponding `async` function that is to be executed when the button is clicked. The `async` function can be called "run" if there is only one button on the page -- otherwise, name it as you will. -* Each button-click handler should invoke the `tryCatch` function, passing in the name of the `async` function to be executed when the button is clicked. -* All HTML IDs should be `all-lower-case-and-hyphenated`. -* Unless you are explicitly showing pretty UI, I wouldn't do the popup notification except for one or two samples. It's a lot of HTML & JS code, and it's also not strictly Fabric-y (there is a more "correct" way of doing this with components). -* Strings should be in double-quotes. -* Don't forget the semicolons. -* `Libraries` in snippets must have a specific version. Eg. `jquery@3.1.1`. +- Use standard TypeScript indentation. +- For each button, define a corresponding `async` function to be run when the button is clicked. The `async` function can be called "run" if there is only one button on the page -- otherwise, name it as you will. +- Each button-click handler should invoke the `tryCatch` function, passing in the name of the `async` function to be executed when the button is clicked. +- All HTML IDs should be `all-lower-case-and-hyphenated`. +- Unless you are explicitly showing pretty UI, you don't have to do the popup notification except for one or two samples. It's a lot of HTML & JS code, and also not strictly Fabric-y (there is a more "correct" way of doing this with components). +- Strings should be in double-quotes. +- Don't forget the semicolons. +- `Libraries` in snippets must have a specific version. Eg. `jquery@3.1.1`. + +## Size restrictions + +Script Lab is designed for you to play with small code samples. Generally, a snippet should be at most a few hundred lines and a few thousand characters. + +Your snippet can use hard-coded data. A small amount of data (say, a few hundred characters) is OK to hard code in Script Lab. However, for larger pieces of data, we recommend that you store those externally then load them at runtime with a command like `fetch`. + +Keep your snippets and hard-coded data small since storing several large snippets could exceed Script Lab's storage and cause issues when loading Script Lab. ## Debugging the build script -* The scripts for building/validating the snippets are under the `config` folder -- in particular, under `build.ts`. There is also a `deploy.ts` for copying the built files to their final location.) +- The scripts for building/validating the snippets are under the `config` folder -- in particular, under `build.ts`. + +> **Note**: If debugging in Visual Studio Code, you can use "F5" to attach the debugger, but be sure to run `npm run tsc` before you do (and after any code change!). `F5` is not set to recompile! + +## Join the Microsoft 365 Developer Program + +Join the [Microsoft 365 Developer Program](https://aka.ms/m365devprogram) to get resources and information to help you build solutions for the Microsoft 365 platform, including recommendations tailored to your areas of interest. + +You might also qualify for a free developer subscription that's renewable for 90 days and comes configured with sample data; for details, see the [FAQ](https://learn.microsoft.com/office/developer-program/microsoft-365-developer-program-faq#who-qualifies-for-a-microsoft-365-e5-developer-subscription-). + +--- -> **NOTE**: If debugging in Visual Studio Code, you can use "F5" to attach the debugger, but be sure to run `npm run tsc` before you do (and after any code change!). `F5` is not set to recompile! +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..4a0f12f81 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how a threat actor might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + diff --git a/config/build.documentation.ts b/config/build.documentation.ts index 2d522db74..ee9d8f653 100644 --- a/config/build.documentation.ts +++ b/config/build.documentation.ts @@ -1,18 +1,19 @@ import * as path from 'path'; import * as fs from 'fs'; import * as jsyaml from 'js-yaml'; -import { Dictionary } from '@microsoft/office-js-helpers'; +import { Dictionary } from './helpers'; -import { SnippetProcessedData, banner, readDir, officeHostsToAppNames, writeFile, rmRf, mkDir } from './helpers'; +import { SnippetProcessedData, readDir, writeFile, rmRf, mkDir } from './helpers'; import { status } from './status'; +const ExcelJS = require('exceljs'); const SNIPPET_EXTRACTOR_METADATA_FOLDER_NAME = 'snippet-extractor-metadata'; interface MappingFileRowData { - class: string; member: string; snippetId: string; snippetFunction: string + package: string, class: string; member: string; memberId: string, snippetId: string; snippetFunction: string } const headerNames: (keyof MappingFileRowData)[] = - ['class', 'member', 'snippetId', 'snippetFunction']; + ['package', 'class', 'member', 'memberId', 'snippetId', 'snippetFunction']; export async function buildReferenceDocSnippetExtracts( @@ -34,11 +35,9 @@ export async function buildReferenceDocSnippetExtracts( await rmRf('snippet-extractor-output'); await mkDir('snippet-extractor-output'); - await Promise.all(snippetExtractsPerHost.map((extracts, index) => { - let contents = jsyaml.safeDump(extracts); - let fileName = `snippet-extractor-output/${files[index].substr(0, '.xlsx'.length)}.yaml`; - return writeFile(path.resolve(fileName), contents); - })); + + const contents = snippetExtractsPerHost.map(extracts => jsyaml.dump(extracts)).join(''); + await writeFile(path.resolve(`snippet-extractor-output/snippets.yaml`), contents); } async function buildSnippetExtractsPerHost( @@ -46,56 +45,40 @@ async function buildSnippetExtractsPerHost( snippetIdsToFilenames: { [key: string]: string }, accumulatedErrors: Array ): Promise<{ [key: string]: string[] }> { - const hostName = officeHostsToAppNames[ - filename.substr(0, filename.length - '.xlsx'.length).toUpperCase()]; - - banner(`Extracting reference-doc snippet bits for ${hostName}`); const lines: MappingFileRowData[] = - await new Promise((resolve: (data: MappingFileRowData[]) => void, reject) => { - const parseXlsx = require('excel'); - + await new Promise(async (resolve: (data: MappingFileRowData[]) => void, reject) => { const fullFilePath = path.join( path.resolve(SNIPPET_EXTRACTOR_METADATA_FOLDER_NAME), filename ); - parseXlsx(fullFilePath, (err, rows: any[][]) => { - if (err) { - reject(err); - } + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.readFile(fullFilePath); + const worksheet = workbook.worksheets[0]; + if (worksheet.rowCount < 2) { + reject(new Error('No data rows found')); + } - if (rows.length < 2) { - reject(new Error('No data rows found')); - } + if (worksheet.getRow(1).cellCount !== headerNames.length) { + reject( + new Error('Unexpected number of columns. Expecting the following ' + + headerNames.length + ' columns: ' + + headerNames.map(name => `"${name}"`).join(', ') + ) + ); + } - if (rows[0].length !== headerNames.length) { - reject( - new Error('Unexpected number of columns. Expecting the following ' + - headerNames.length + ' columns: ' + - headerNames.map(name => `"${name}"`).join(', ') - ) - ); + let mappedRowData: MappingFileRowData[] = []; + worksheet.eachRow((row, rowNumber) => { + if (rowNumber !== 1 && !row.getCell(1).value.startsWith('//')) { + let result: MappingFileRowData = {} as any; + row.eachCell((cell, index) => { + result[headerNames[index - 1]] = cell.value; + }); + mappedRowData.push(result); } - - // Remove the first line, since it's the header line - rows.splice(0, 1); - - resolve( - rows - .map((row: string[]) => { - if (row.find(text => text.startsWith('//'))) { - return null; - } - - let result: MappingFileRowData = {} as any; - row.forEach((column: string, index) => { - result[headerNames[index]] = column; - }); - return result; - }) - .filter(item => item) - ); }); + resolve(mappedRowData.filter(item => item)); }); const allSnippetData: { [key: string]: string[] } = {}; @@ -104,13 +87,23 @@ async function buildSnippetExtractsPerHost( .filter(item => item) .forEach((text, index) => { const row = lines[index]; - const fullName = `${hostName}.${row.class}.${row.member}`; + let hostName = row.package; + + let fullName; + if (row.member) { /* If the mapping is for a field */ + fullName = `${hostName}.${row.class.trim()}#${row.member.trim()}:member`; + if (row.memberId) { + fullName += `(${row.memberId})`; + } + } else { /* If the mapping is for a top-level sample (like an enum) */ + fullName = `${hostName}.${row.class.trim()}:${row.memberId.trim()}`; + } + if (!allSnippetData[fullName]) { allSnippetData[fullName] = []; } allSnippetData[fullName].push(text); }); - return allSnippetData; } @@ -126,7 +119,7 @@ function getExtractedDataFromSnippet( const filename = snippetIdsToFilenames[row.snippetId]; if (filename) { try { - const script = (jsyaml.safeLoad(fs.readFileSync(filename).toString()) as ISnippet).script.content; + const script = (jsyaml.load(fs.readFileSync(filename).toString()) as ISnippet).script.content; const fullSnippetTextArray = script.split('\n') .map(line => line.replace(/\r/, '')); @@ -134,15 +127,30 @@ function getExtractedDataFromSnippet( let arrayIndex = fullSnippetTextArray.findIndex(text => text.indexOf(targetText) >= 0); if (arrayIndex < 0) { - throw new Error(`Could not find the text "${targetText}" within snippet "${filename}"`); + throw new Error(`Invalid entry in the metadata mapping file -- snippet function "${row.snippetFunction}" does not exist within snippet "${filename}"`); } + + let jsDocCommentIndex = -1; + if (arrayIndex > 0 && fullSnippetTextArray[arrayIndex - 1].indexOf('*/') >= 0) { + for (let i = arrayIndex - 1; i >= 0; i--) { + if (fullSnippetTextArray[i].indexOf('/**') >= 0) { + jsDocCommentIndex = i; + break; + } + } + } + const functionDeclarationLine = fullSnippetTextArray[arrayIndex]; const functionHasNoParams = functionDeclarationLine.indexOf(targetText + ')') >= 0; const spaceFollowedByWordsRegex = /^(\s*)(.*)$/; const preWhitespaceCount = spaceFollowedByWordsRegex.exec(functionDeclarationLine)[1].length; const targetClosingText = ' '.repeat(preWhitespaceCount) + '}'; - fullSnippetTextArray.splice(0, arrayIndex + (functionHasNoParams ? 1 : 0)); + if (jsDocCommentIndex >= 0) { + fullSnippetTextArray.splice(0, jsDocCommentIndex); + } else { + fullSnippetTextArray.splice(0, arrayIndex + (functionHasNoParams ? 1 : 0)); + } const closingIndex = fullSnippetTextArray.findIndex(text => text.indexOf(targetClosingText) === 0); if (closingIndex < 0) { @@ -152,10 +160,14 @@ function getExtractedDataFromSnippet( const indented = fullSnippetTextArray.slice(0, closingIndex + (functionHasNoParams ? 0 : 1)); const whitespaceCountOnFirstLine = spaceFollowedByWordsRegex.exec(fullSnippetTextArray[0])[1].length; - text = indented + // Place snippet location as comment. + const editedFilename = filename.substring(filename.lastIndexOf('samples')).replace(/\\/g, '/'); + text = '// Link to full sample: https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/' + editedFilename + '\n\n'; + + text += indented .map(line => { - if (line.substr(0, whitespaceCountOnFirstLine).trim().length === 0) { - return line.substr(whitespaceCountOnFirstLine); + if (line.substring(0, whitespaceCountOnFirstLine).trim().length === 0) { + return line.substring(whitespaceCountOnFirstLine); } else { return line; } @@ -164,7 +176,7 @@ function getExtractedDataFromSnippet( } catch (exception) { accumulatedErrors.push(`${row.snippetId}: ${exception.message || exception}`); - }; + } } else { accumulatedErrors.push(`Could not find snippet id "${row.snippetId}" in mapping table`); } diff --git a/config/build.ts b/config/build.ts index 5769c0733..042846a8e 100644 --- a/config/build.ts +++ b/config/build.ts @@ -2,26 +2,22 @@ import * as path from 'path'; import { isNil, isString, isArray, isEmpty, sortBy, cloneDeep } from 'lodash'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; +import escapeStringRegexp from 'escape-string-regexp'; import { status } from './status'; import { SnippetFileInput, SnippetProcessedData, - getDestinationBranch, followsNamingGuidelines, isCUID, - rmRf, mkDir, getFiles, writeFile, loadFileContents, banner, getPrintableDetails + followsNamingGuidelines, isCUID, + rmRf, mkDir, readDir, getFiles, writeFile, banner, getPrintableDetails, Dictionary } from './helpers'; import { buildReferenceDocSnippetExtracts } from './build.documentation'; import { getShareableYaml } from './snippet.helpers'; import { processLibraries } from './libraries.processor'; import { startCase, groupBy, map } from 'lodash'; -import { Dictionary } from '@microsoft/office-js-helpers'; import * as jsyaml from 'js-yaml'; -import 'rxjs/add/operator/merge'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/filter'; -import escapeStringRegexp = require('escape-string-regexp'); +import * as fsx from 'fs-extra'; -const { GH_ACCOUNT, GH_REPO, TRAVIS_BRANCH } = process.env; const PRIVATE_SAMPLES = 'private-samples'; const PUBLIC_SAMPLES = 'samples'; const snippetFilesToUpdate: Array<{ path: string; contents: string }> = []; @@ -40,7 +36,7 @@ const defaultApiSets = { 'WordApi': 1.1 } - /* any other hosts is allowed to have no API sets specified*/ + // any other host is allowed to have no API sets specified }; @@ -51,6 +47,7 @@ const defaultApiSets = { .then(updateModifiedFiles) .then(() => checkSnippetsForUniqueIDs(processedSnippets)) .then(() => generatePlaylists(processedSnippets)) + .then(copyAndUpdatePlaylistFolders) .then(() => buildReferenceDocSnippetExtracts(processedSnippets, accumulatedErrors)) .then(() => { if (accumulatedErrors.length > 0) { @@ -66,18 +63,15 @@ const defaultApiSets = { })(); -async function processSnippets(processedSnippets) { - return new Promise((resolve, reject) => { - banner('Loading & processing snippets'); - let files$ = getFiles(path.resolve(PRIVATE_SAMPLES)); - files$ = files$.merge(getFiles(path.resolve(PUBLIC_SAMPLES))); +async function processSnippets(processedSnippets: Dictionary) { + banner('Loading & processing snippets'); + let files: SnippetFileInput[] = [] + .concat(getFiles(path.resolve(PRIVATE_SAMPLES))) + .concat(getFiles(path.resolve(PUBLIC_SAMPLES))); - files$ - .mergeMap((file) => (processAndValidateSnippet(file))) - .filter(file => file !== null) - .map(file => processedSnippets.add(file.rawUrl, file)) - .subscribe(null, reject, resolve); - }); + (await Promise.all(files.map(file => processAndValidateSnippet(file)))) + .filter(file => file !== null) + .map(file => processedSnippets.set(file.rawUrl, file)); // Helpers: @@ -89,8 +83,8 @@ async function processSnippets(processedSnippets) { let dir = file.isPublic ? PUBLIC_SAMPLES : PRIVATE_SAMPLES; const fullPath = path.resolve(dir, file.relativePath); - const originalFileContents = (await loadFileContents(fullPath)).trim(); - let snippet: ISnippet = jsyaml.safeLoad(originalFileContents); + const originalFileContents = fsx.readFileSync(fullPath).toString().trim(); + let snippet = jsyaml.load(originalFileContents) as ISnippet; // Do validations & auto-corrections validateStringFieldNotEmptyOrThrow(snippet, 'name'); @@ -109,7 +103,11 @@ async function processSnippets(processedSnippets) { const additionalFields: ISnippet = {}; additionalFields.id = snippet.id; additionalFields.api_set = snippet.api_set; - additionalFields.author = snippet.author; + + // Only set author field if it has a value + if (snippet.author) { + additionalFields.author = snippet.author; + } if ((typeof (snippet as any).order) !== 'undefined') { // # for ordering, if present (used for samples only) @@ -126,21 +124,22 @@ async function processSnippets(processedSnippets) { messages.push(chalk.bold.yellow('Final snippet != original snippet. Queueing to write in new changes.')); snippetFilesToUpdate.push({ path: fullPath, contents: finalFileContents }); } - status.complete(true /*success*/, `Processing ${file.relativePath}`, messages); const rawUrl = `https://raw.githubusercontent.com/` + - `${GH_ACCOUNT || ''}/${GH_REPO || ''}/${getDestinationBranch(TRAVIS_BRANCH) || ''}` + + `OfficeDev/office-js-snippets/main` + `/${dir}/${file.host}/${file.group}/${file.file_name}`; if (messages.findIndex(item => item instanceof Error) >= 0) { accumulatedErrors.push(`One or more critical errors on ${file.relativePath}`); } - // Define dictionary of words in file.group that require special casing + // Define dictionary of words in file.group that require special casing or punctuation let dictionary = { 'Apis': 'APIs', - 'Xml': 'XML' + 'Pivottable': 'PivotTable', + 'Xml': 'XML', + 'On Premises': 'On-Premises' }; let groupName = replaceUsingDictionary(dictionary, startCase(file.group)); @@ -169,6 +168,15 @@ async function processSnippets(processedSnippets) { function replaceUsingDictionary(dictionary: { [key: string]: string }, originalName: string): string { let text = startCase(file.group); + + // First try to replace multi-word phrases + for (const [key, value] of Object.entries(dictionary)) { + if (key.includes(' ') && text.includes(key)) { + text = text.replace(new RegExp(key, 'g'), value); + } + } + + // Then replace individual words let parts = text.split(' ').map(item => dictionary[item] || item); return parts.join(' '); } @@ -176,8 +184,8 @@ async function processSnippets(processedSnippets) { function validateProperFabric(snippet: ISnippet): void { const libs = snippet.libraries.split('\n').map(reference => reference.trim()); - if (libs.indexOf('office-ui-fabric-js@1.4.0/dist/css/fabric.min.css') >= 0) { - if (libs.indexOf('office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css') <= 0) { + if (libs.indexOf('office-ui-fabric-core@11.1.0/dist/css/fabric.min.css') >= 0) { + if (libs.indexOf('office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css') <= 0) { throw new Error('Fabric reference is specified, without a reference to a corresponding "fabric.components.min.css". Please add this second Fabric reference as well.'); } } @@ -228,8 +236,8 @@ async function processSnippets(processedSnippets) { const isOfficeSnippet = officeHosts.indexOf(host.toUpperCase()) >= 0; const canonicalOfficeJsReference = 'https://appsforoffice.microsoft.com/lib/1/hosted/office.js'; const betaOfficeJsReference = 'https://appsforoffice.microsoft.com/lib/beta/hosted/office.js'; - const officeDTS = '@types/office-js'; - const betaOfficeDTS = '@microsoft/office-js@beta/dist/office.d.ts'; + const officeDTS = 'https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts'; + const betaOfficeDTS = 'https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts'; const officeJsReferences = snippet.libraries.split('\n') @@ -239,13 +247,12 @@ async function processSnippets(processedSnippets) { const officeDtsReferences = snippet.libraries.split('\n') .map(reference => reference.trim()) - .filter(reference => reference.match(/.*((@types\/office-js)|(office\.d\.ts))$/gi)); + .filter(reference => reference.match(/.*((@types\/office-js(-preview)?)|((index|office)\.d\.ts))$/gi)); /* Note: regex matches: - - @types/office-js - - https://unpkg.com/etc/office.d.ts + - https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + - https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts But not: - - @types/office-jsfake - - https://unpkg.com/etc/office.d.ts.ish + - https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.tsfake - office.d.ts.unrelated */ @@ -272,7 +279,6 @@ async function processSnippets(processedSnippets) { let snippetOfficeReferenceIsOk = officeJsReferences[0] === canonicalOfficeJsReference || - host.toUpperCase() === 'OUTLOOK' /* for now, outlook does not want to use cannonical Office.js due to bug #65. */ || (group.indexOf('preview-apis') >= 0 && officeJsReferences[0] === betaOfficeJsReference); if (!snippetOfficeReferenceIsOk) { @@ -369,11 +375,12 @@ async function processSnippets(processedSnippets) { const defaultSubstitutions = { 'jquery': 'jquery@3.1.1', - 'office-ui-fabric-js/dist/js/fabric.min.js': 'office-ui-fabric-js@1.4.0/dist/js/fabric.min.js', + 'office-ui-fabric-js/dist/js/fabric.min.js': 'office-ui-fabric-js@1.5.0/dist/js/fabric.min.js', '@microsoft/office-js-helpers/dist/office.helpers.min.js': '@microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js', 'core-js/client/core.min.js': 'core-js@2.4.1/client/core.min.js', - 'office-ui-fabric-js/dist/css/fabric.min.css': 'office-ui-fabric-js@1.4.0/dist/css/fabric.min.css', - 'office-ui-fabric-js/dist/css/fabric.components.min.css': 'office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css' + 'office-ui-fabric-core/dist/css/fabric.min.css': 'office-ui-fabric-core@11.1.0/dist/css/fabric.min.css', + 'office-ui-fabric-js/dist/css/fabric.min.css': 'office-ui-fabric-core@11.1.0/dist/css/fabric.min.css', + 'office-ui-fabric-js/dist/css/fabric.components.min.css': 'office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css' }; let hadDefaultSubstitution = false; @@ -422,13 +429,22 @@ async function processSnippets(processedSnippets) { } function validateTabsInsteadOfSpaces(snippet: ISnippet, messages: any[]): void { - const codeFields = [snippet.template.content, snippet.script.content, snippet.style.content, snippet.libraries]; - if (codeFields.findIndex(code => code.indexOf('\t') >= 0) >= 0) { - snippet.template.content = snippet.template.content.replace(/\t/g, ' '); - snippet.script.content = snippet.script.content.replace(/\t/g, ' '); - snippet.style.content = snippet.style.content.replace(/\t/g, ' '); + let replacedTabs = false; + ['template', 'script', 'style'].forEach(fieldName => { + if (snippet[fieldName]) { + if (snippet[fieldName].content.indexOf('\t') >= 0) { + replacedTabs = true; + snippet[fieldName].content = snippet[fieldName].content.replace(/\t/g, ' '); + } + } + }); + + if (snippet.libraries.indexOf('\t') >= 0) { + replacedTabs = true; snippet.libraries = snippet.libraries.replace(/\t/g, ' '); + } + if (replacedTabs) { messages.push('Snippet had one or more fields (template/script/style/libraries) ' + 'that contained tabs instead of spaces. Replacing everything with 4 spaces.'); } @@ -485,7 +501,7 @@ async function generatePlaylists(processedSnippets: Dictionary(); for (let processedSnippet of processedSnippets.values()) { if (processedSnippet.isPublic) { - processedPublicSnippets.add(processedSnippet.rawUrl, processedSnippet); + processedPublicSnippets.set(processedSnippet.rawUrl, processedSnippet); } } @@ -502,7 +518,7 @@ async function generatePlaylists(processedSnippets: Dictionary { const creatingStatusText = `Creating ${host}.yaml`; status.add(creatingStatusText); - items = sortBy(items, sortingCriteria); + items = sortBy(items, sortingCriteria) as any; /* Having sorted the items -- which may have included a number in the group name! -- remove the group number if any @@ -533,7 +549,7 @@ async function generatePlaylists(processedSnippets: Dictionary { const creatingStatusText = `Creating ${host}.json`; status.add(creatingStatusText); - items = sortBy(items, sortingCriteria); + items = sortBy(items, sortingCriteria) as any; let hostMapping = {} as { [id: string]: string }; items.forEach(item => { @@ -573,6 +589,50 @@ async function generatePlaylists(processedSnippets: Dictionary updateCopiedFile(playlistsProdFolderPath, file)))); + + /* Copying view directory */ + let viewProdFolderName = `view-prod`; + status.add(`Creating \'${viewProdFolderName}\' folder`); + await rmRf(viewProdFolderName); + let viewProdFolderPath = await mkDir(viewProdFolderName); + status.complete(true /*success*/, `Creating \'${viewProdFolderName}\' folder`); + + await fsx.copy('view', viewProdFolderName); + let viewFiles = await readDir(viewProdFolderPath); + (await Promise.all(viewFiles.map(file => updateCopiedFile(viewProdFolderPath, file)))); +} + +// helper for copyAndUpdatePlaylistFolders +async function updateCopiedFile(folderPath: string, filePath: string) { + const fullPath = path.resolve(folderPath, filePath); + let content = fsx.readFileSync(fullPath).toString().trim().replace( + /\/OfficeDev\/office-js-snippets\/main/g, + '/OfficeDev/office-js-snippets/prod'); + const fileUpdates = []; + fileUpdates.push( + Promise.resolve() + .then(async () => { + const updatingStatusText = `Updating copied file ${fullPath}`; + status.add(updatingStatusText); + await writeFile(fullPath, content); + status.complete(true /*succeeded*/, updatingStatusText); + }) + ); +} + function handleError(error: any | any[]) { if (!isArray(error)) { error = [error]; diff --git a/config/deploy.ts b/config/deploy.ts deleted file mode 100644 index 77d10aa4c..000000000 --- a/config/deploy.ts +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env node --harmony - -import * as chalk from 'chalk'; -import * as shell from 'shelljs'; -import { forIn } from 'lodash'; -import { isString } from 'lodash'; -import { banner, getDestinationBranch } from './helpers'; - -interface IEnvironmentVariables { - TRAVIS: string, - TRAVIS_BRANCH: string, - TRAVIS_PULL_REQUEST: string, - TRAVIS_COMMIT_MESSAGE: string, - GH_ACCOUNT: string, - GH_REPO: string, - GH_TOKEN: string -} - -const environmentVariables: IEnvironmentVariables = process.env; - -(() => { - try { - // Note, if precheck fails, it will do its own banner, so only need to focus on the true case. - if (precheck()) { - const destinationBranch = getDestinationBranch(environmentVariables.TRAVIS_BRANCH); - const repoUrl = `https://github.com/${environmentVariables.GH_ACCOUNT}/${environmentVariables.GH_REPO}/tree/${destinationBranch}`; - banner('Starting deployment', repoUrl); - - const start = Date.now(); - shell.exec('git config --add user.name "Travis CI"'); - shell.exec('git config --add user.email "travis.ci@microsoft.com"'); - shell.exec('git checkout --orphan newbranch'); - shell.exec('git reset'); - - execCommand('git add -f samples private-samples playlists view snippet-extractor-output README.md'); - execCommand(`git commit -m "Travis auto-deploy of ${environmentVariables.TRAVIS_COMMIT_MESSAGE.replace(/\W/g, '_')}"`); - - const tokenizedGitHubGitUrl = `https://<<>>@github.com/${environmentVariables.GH_ACCOUNT}/${environmentVariables.GH_REPO}.git`; - execCommand(`git push ${tokenizedGitHubGitUrl} -q -f -u HEAD:refs/heads/${destinationBranch}`, { - token: environmentVariables.GH_TOKEN - }); - - const end = Date.now(); - - banner('Deployment succeeded', `Successfully deployed to ${repoUrl} in ${(end - start) / 1000} seconds.`, chalk.bold.green); - } - } - catch (error) { - banner('An error has occurred', error.message || error, chalk.bold.red); - banner('DEPLOYMENT DID NOT GET TRIGGERED', error.message || error, chalk.bold.red); - - // Note: Don't exit the process with "process.exit(1);", since deployment - // failure does not imply dev failure, so don't want to "break the build". - // But do want to make it very obvious that deployment went wrong when - // looking at the logs. - } - - process.exit(0); -})(); - - -function precheck() { - /* Check if the code is running inside of travis.ci. If not abort immediately. */ - if (!environmentVariables.TRAVIS) { - banner('Deployment skipped', 'Not running inside of Travis.', chalk.yellow.bold); - return false; - } - - // Careful! Need this check because otherwise, a pull request against master would immediately trigger a deployment. - if (environmentVariables.TRAVIS_PULL_REQUEST !== 'false') { - banner('Deployment skipped', 'Skipping deploy for pull requests.', chalk.yellow.bold); - return false; - } - - if (getDestinationBranch(environmentVariables.TRAVIS_BRANCH) == null) { - banner('Deployment skipped', 'Skipping deploy for pull requests.', chalk.yellow.bold); - return false; - } - - /* Check if the username is configured. If not abort immediately. */ - const requiredFields: Array = ['GH_ACCOUNT', 'GH_REPO', 'GH_TOKEN']; - requiredFields.forEach(key => { - if (!isString(environmentVariables[key])) { - throw new Error(`"${key}" is a required global variables.`); - } - }); - - return true; -} - -/** - * Execute a shall command. - * @param originalSanitizedCommand - The command to execute. Note that if it contains something secret, put it in triple <<>> syntax, as the command itself will get echo-ed. - * @param secretSubstitutions - key-value pairs to substitute into the command when executing. Having any secret substitutions will automatically make the command run silently. - */ -function execCommand(originalSanitizedCommand: string, secretSubstitutions = {}) { - console.log(originalSanitizedCommand); - - let hadSecrets = false; - let command = originalSanitizedCommand; - forIn(secretSubstitutions, (value, key) => { - hadSecrets = true; - command = replaceAll(command, '<<<' + key + '>>>', value); - }); - - if (hadSecrets) { - console.log(chalk.yellow('Command contained secret substitution values; running the `shell.exec` silently')); - } - - let result: any = shell.exec(command, hadSecrets ? { silent: true } : null); - if (result.code !== 0) { - throw new Error(`An error occurred while executing "${originalSanitizedCommand}"`); - } -} - -function replaceAll(source, search, replacement) { - return source.split(search).join(replacement); -} diff --git a/config/helpers.ts b/config/helpers.ts index c933485fa..d0798f6bb 100644 --- a/config/helpers.ts +++ b/config/helpers.ts @@ -1,26 +1,10 @@ import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; -import * as chalk from 'chalk'; +import chalk from 'chalk'; import * as jsyaml from 'js-yaml'; -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/mergeMap'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/from'; -import 'rxjs/add/observable/of'; -import 'rxjs/add/observable/throw'; -import { console } from './status'; -import * as rimraf from 'rimraf'; - -export const officeHostsToAppNames = { - 'ACCESS': 'Access', - 'EXCEL': 'Excel', - 'ONENOTE': 'OneNote', - 'OUTLOOK': 'Outlook', - 'POWERPOINT': 'PowerPoint', - 'PROJECT': 'Project', - 'WORD': 'Word' -}; +import { rimraf } from 'rimraf'; +import { isObject, isNil, isString, isEmpty } from 'lodash'; export interface SnippetFileInput { file_name: string; @@ -54,7 +38,7 @@ export interface SnippetProcessedData { * @param message Message of the banner. * @param chalkFunction Chalk color function. */ -export const banner = (title: string, message: string = null, chalkFn: chalk.ChalkChain = null) => { +export const banner = (title: string, message: string = null, chalkFn: any = null) => { if (!chalkFn) { chalkFn = chalk.bold; } @@ -70,7 +54,7 @@ export const banner = (title: string, message: string = null, chalkFn: chalk.Cha }; export function getPrintableDetails(item: any, indent: number) { - const details = jsyaml.safeDump(item, { + const details = jsyaml.dump(item, { indent: 4, lineWidth: -1, skipInvalid: true @@ -79,18 +63,6 @@ export function getPrintableDetails(item: any, indent: number) { return details.split('\n').map(line => new Array(indent).join(' ') + line).join('\n'); } -export const getDestinationBranch = (sourceBranch: 'master' | 'prod' | any): 'deploy-beta' | 'deploy-prod' | null => { - if (sourceBranch === 'master') { - return 'deploy-beta'; - } - else if (sourceBranch === 'prod') { - return 'deploy-prod'; - } - else { - return null; - } -}; - /** * Creates a folder. * @param dir An absolute path to the directory. @@ -110,16 +82,11 @@ export const mkDir = (dir: string) => * Deletes a folder. * @param dir An absolute path to the directory. */ -export const rmRf = (dir: string) => - new Promise((resolve, reject) => { - const location = path.resolve(dir); - rimraf(location, (err) => { - if (err) { - return reject(err); - } - return resolve(location); - }); - }); +export const rmRf = async (dir: string): Promise => { + const location = path.resolve(dir); + await rimraf(location); + return location; +}; /** * Load all the files and folders in a given directory. @@ -141,7 +108,7 @@ export const readDir = (dir: string) => * @param contents */ export const writeFile = (filename: string, contents: string) => - new Promise((resolve, reject) => { + new Promise((resolve, reject) => { fs.writeFile(filename, contents, (err) => { if (err) { return reject(err); @@ -164,38 +131,12 @@ export const isDir = (path: string) => }); }); - -/** - * Load the contents of the YAML file. - * @param path Absolute to the yaml file. - */ -export const loadFileContents = (path: string) => - new Promise(async (resolve, reject) => { - let pathIsDirectory = await isDir(path); - if (pathIsDirectory) { - return reject(new Error(`Cannot open a directory @ ${chalk.bold.red(path)}`)); - } - else { - fs.readFile(path, 'UTF8', (err, contents) => { - try { - if (err) { - return reject(err); - } - return resolve(contents); - } - catch (err) { - reject(err); - } - }); - } - }); - /** * Check the file path against validations and return a 'File' object. * @param fullPath An absolute path to the file. * @param root An absolute path to the root directory. */ -export const getFileMetadata = (fullPath: string, root: string) => { +export function getFileMetadata(fullPath: string, root: string): SnippetFileInput { /* Determine the platform as windows uses '\' where as linux uses '/' */ const delimiter = os.platform() === 'win32' ? '\\' : '/'; @@ -207,7 +148,7 @@ export const getFileMetadata = (fullPath: string, root: string) => { /* Additional must be null or empty */ if (additional && additional.length > 0) { - throw new Error(`Invalid folder structure at ${chalk.bold.red(relativePath)}.File ${chalk.bold.yellow(name)} was located too deep.`); + throw new Error(`Invalid folder structure at ${chalk.bold.red(relativePath)}.File ${chalk.bold.yellow(file_name)} was located too deep.`); } if (host == null) { @@ -216,60 +157,45 @@ export const getFileMetadata = (fullPath: string, root: string) => { host = host.toLowerCase(); - return Observable.of({ + return { relativePath: relativePath, fullPath, isPublic: !(/[\\/]private-samples$/.test(root)), host, group, file_name - }); -}; + }; +} /** - * Recurrsively crawl through a folder and return all the files in it. + * Recursively crawl through a folder and return all the files in it. * @param root An absolute path to the directory. */ -export function getFiles(root: string): Observable { - return getFilesHelper(root, root); +export function getFiles(root: string): SnippetFileInput[] { + let files: SnippetFileInput[] = []; + syncRecurseThroughDirectory(root); + return files; + + + // Helper + function syncRecurseThroughDirectory(dir: string) { + fs.readdirSync(dir) + .filter(file => !['.DS_Store'].includes(file)) + .forEach(file => { + const fullPath = path.join(dir, file); + const withoutExt = file.replace('.yaml', ''); + + /* Check for file/folder naming guidelines */ + if (!followsNamingGuidelines(withoutExt)) { + throw new Error(`Invalid name at ${chalk.bold.red(fullPath)}. Name must only contain lowercase letters, numbers, and hyphens.`); + } - /** A recursive helper: - * @param dir An absolute path to the directory. - * @param root An absolute path to the root directory. - */ - function getFilesHelper(dir: string, root: string): Observable { - /* - * Convert all the files into an Observable stream of files. - * This allows us to focus the remainder of the operations - * on a PER FILE basis. - */ - return Observable - .from(readDir(dir)) - .mergeMap(files => Observable.from(files)) - .mergeMap((file) => { - const filePath = path.join(dir, file); - const withoutExt = file.replace('.yaml', ''); - - /* Check for file/folder naming guidelines */ - if (!followsNamingGuidelines(withoutExt)) { - throw new Error(`Invalid name at ${chalk.bold.red(filePath)}. Name must only contain lowercase letters, numbers, and hyphens.`); - } - - /* - * Check if the file is a folder and either return - * an Observable to the recurrsive walk operation or - * return an Observable of the file object itself. - */ - return Observable - .from(isDir(filePath)) - .mergeMap(pathIsDirectory => { - const files$ = pathIsDirectory ? - getFilesHelper(filePath, root) : - getFileMetadata(filePath, root); - return files$.catch(error => Observable.throw(error)); - }) - .catch(error => Observable.throw(error)); - }); + if (fs.statSync(fullPath).isDirectory()) { + syncRecurseThroughDirectory(fullPath); + } else { + files.push(getFileMetadata(fullPath, root)); + } + }); } } @@ -277,14 +203,12 @@ export function getFiles(root: string): Observable { Naming guidelines: only allow lowercase letters, numbers, and hyphens OK: - sample sample-with-hyphen sample-es5 BAD: - sample with space Any-uppercase anyWhere @@ -309,3 +233,139 @@ export function isCUID(id: string) { export function pause(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } + +/** + * Helper for creating and querying Dictionaries. + * A wrapper around ES6 Maps. + */ +export class Dictionary { + protected _items: Map; + + /** + * @constructor + * @param {object} items Initial seed of items. + */ + constructor(items?: { [index: string]: T } | Array<[string, T]> | Map) { + if (isNil(items)) { + this._items = new Map(); + } + else if (items instanceof Set) { + throw new TypeError(`Invalid type of argument: Set`); + } + else if (items instanceof Map) { + this._items = new Map(items); + } + else if (Array.isArray(items)) { + this._items = new Map(items); + } + else if (isObject(items)) { + this._items = new Map(); + for (const key of Object.keys(items)) { + this._items.set(key, items[key]); + } + } + else { + throw new TypeError(`Invalid type of argument: ${typeof items}`); + } + } + + /** + * Gets an item from the dictionary. + * + * @param {string} key The key of the item. + * @return {object} Returns an item if found. + */ + get(key: string): T { + return this._items.get(key); + } + + /** + * Inserts an item into the dictionary. + * If an item already exists with the same key, it will be overridden by the new value. + * + * @param {string} key The key of the item. + * @param {object} value The item to be added. + * @return {object} Returns the added item. + */ + set(key: string, value: T): T { + this._validateKey(key); + this._items.set(key, value); + return value; + } + + /** + * Removes an item from the dictionary. + * Will throw if the key doesn't exist. + * + * @param {string} key The key of the item. + * @return {object} Returns the deleted item. + */ + delete(key: string): T { + if (!this.has(key)) { + throw new ReferenceError(`Key: ${key} not found.`); + } + let value = this._items.get(key); + this._items.delete(key); + return value; + } + + /** + * Clears the dictionary. + */ + clear(): void { + this._items.clear(); + } + + /** + * Check if the dictionary contains the given key. + * + * @param {string} key The key of the item. + * @return {boolean} Returns true if the key was found. + */ + has(key: string): boolean { + this._validateKey(key); + return this._items.has(key); + } + + /** + * Lists all the keys in the dictionary. + * + * @return {array} Returns all the keys. + */ + keys(): Array { + return Array.from(this._items.keys()); + } + + /** + * Lists all the values in the dictionary. + * + * @return {array} Returns all the values. + */ + values(): Array { + return Array.from(this._items.values()); + } + + /** + * Get a shallow copy of the underlying map. + * + * @return {object} Returns the shallow copy of the map. + */ + clone(): Map { + return new Map(this._items); + } + + /** + * Number of items in the dictionary. + * + * @return {number} Returns the number of items in the dictionary. + */ + get count(): number { + return this._items.size; + } + + private _validateKey(key: string): void { + if (!isString(key) || isEmpty(key)) { + throw new TypeError('Key needs to be a string'); + } + } +} diff --git a/config/snippet.helpers.ts b/config/snippet.helpers.ts index f2574957d..449e40d59 100644 --- a/config/snippet.helpers.ts +++ b/config/snippet.helpers.ts @@ -91,7 +91,7 @@ function scrubCarriageReturns(snippet: ISnippet) { export function getScrubbedSnippet(snippet: ISnippet, keep: SnippetFieldType): ISnippet { let copy = {}; forIn(snippetFields, (fieldType, fieldName) => { - if (fieldType & keep) { + if (fieldType & keep && snippet[fieldName] !== undefined) { copy[fieldName] = snippet[fieldName]; } }); @@ -103,7 +103,7 @@ export function getShareableYaml(rawSnippet: ISnippet, additionalFields: ISnippe const snippet = { ...getScrubbedSnippet(rawSnippet, SnippetFieldType.PUBLIC), ...additionalFields }; scrubCarriageReturns(snippet); - return jsyaml.safeDump(snippet, { + return jsyaml.dump(snippet, { indent: 4, lineWidth: -1, sortKeys: ((a, b) => snippetFieldSortingOrder[a] - snippetFieldSortingOrder[b]), diff --git a/config/status.ts b/config/status.ts index 99d95f234..2f953ee73 100644 --- a/config/status.ts +++ b/config/status.ts @@ -1,28 +1,40 @@ -import * as nodeStatus from 'node-status'; -import * as chalk from 'chalk'; -import { isString, find, isNil, isArray } from 'lodash'; +import chalk from 'chalk'; +import { isString, isNil, isArray } from 'lodash'; interface IStage { steps: any[]; count: number; doneStep: (completed: boolean, message?: string) => void; -}; +} export class Status { stages: IStage; steps: { [step: string]: boolean } = {}; get console() { - return nodeStatus.console(); + // Return the global console object methods + return { + log: global.console.log.bind(global.console), + error: global.console.error.bind(global.console), + warn: global.console.warn.bind(global.console), + info: global.console.info.bind(global.console) + }; } constructor() { - /* Initialize the status library */ - this.stages = nodeStatus.addItem('stages', { - steps: [] - }); + /* Initialize the simple status system */ + this.stages = { + steps: [], + count: 0, + doneStep: this.doneStep.bind(this) + }; + } - nodeStatus.start(); + private doneStep(completed: boolean, message?: string): void { + const symbol = completed ? chalk.green('✓') : chalk.red('✗'); + if (message) { + global.console.log(`${symbol} ${message}`); + } } /** @@ -37,22 +49,18 @@ export class Status { success = success && additionalDetails.findIndex(item => item instanceof Error) < 0; const messageArray = getDetailsArray(); + const symbol = success ? chalk.green('✓') : chalk.red('✗'); - if (messageArray.length === 0) { - this.stages.doneStep(success); - } else { - // Add a newline before - messageArray.splice(0, 0, ''); - this.stages.doneStep(success, messageArray.join('\n * ') + '\n'); - //FIXME `${chalk.bold.red('WARNING: one of the messages above was an error')}`) - } - - this.steps[stage] = false; + // Log the completion with symbol + global.console.log(`${symbol} ${stage}`); - if (!find(this.steps as any, (item) => item === true)) { - nodeStatus.stop(); + if (messageArray.length > 0) { + messageArray.forEach(msg => { + global.console.log(` * ${msg}`); + }); } + this.steps[stage] = false; // Helper: function getDetailsArray() { @@ -79,17 +87,18 @@ export class Status { }) .filter(item => !isNil(item)); } - }; + } /** - * Add a new stage and complete the previous stage. + * Add a new stage and mark it as started. * @param stage Name of the stage. */ add(stage: string) { this.stages.steps.push(stage); this.steps[stage] = true; - }; -}; + global.console.log(chalk.cyan(`○ ${stage}`)); + } +} export const status = new Status(); export const console = status.console; diff --git a/package.json b/package.json index 4accfbdc8..457b9471d 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,12 @@ "description": "A collection of samples using the Office JavaScript API", "main": "config/compile.js", "engines": { - "node": ">=6.9.4" + "node": ">=6.10.0" }, "scripts": { "start": "npm run tsc && npm run build && npm run lint", "tsc": "tsc -p tsconfig.json", "build": "node config/build.js", - "deploy": "node config/deploy.js", "lint": "tslint --project tsconfig.json" }, "repository": { @@ -24,24 +23,22 @@ }, "homepage": "https://github.com/OfficeDev/office-js-snippets#readme", "dependencies": { - "@microsoft/office-js-helpers": "^0.5.0", - "chalk": "1.1.3", - "escape-string-regexp": "^1.0.5", - "excel": "^0.1.7", - "js-yaml": "3.7.0", - "lodash": "4.17.4", - "node-status": "1.0.0", - "rimraf": "2.5.4", - "rxjs": "5.2.0", - "shelljs": "0.7.7" + "chalk": "^4.1.2", + "escape-string-regexp": "^4.0.0", + "exceljs": "^4.4.0", + "fs-extra": "11.3.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "rimraf": "^6.0.1", + "shelljs": "^0.10.0" }, "devDependencies": { - "@types/chalk": "0.4.31", - "@types/js-yaml": "3.5.29", - "@types/lodash": "4.14.54", - "@types/node": "7.0.7", - "@types/shelljs": "0.7.0", - "tslint": "4.5.1", - "typescript": "2.2.1" + "@types/fs-extra": "^11.0.4", + "@types/js-yaml": "^4.0.9", + "@types/lodash": "^4.17.20", + "@types/node": "^24.5.2", + "@types/shelljs": "^0.8.17", + "tslint": "^6.1.3", + "typescript": "^5.9.2" } } diff --git a/playlists-prod/excel.yaml b/playlists-prod/excel.yaml new file mode 100644 index 000000000..059d3893b --- /dev/null +++ b/playlists-prod/excel.yaml @@ -0,0 +1,1436 @@ +- 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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/samples/excel/10-chart/chart-trendlines.yaml + group: Chart + api_set: + ExcelApi: '1.7' +- id: excel-chart-data-labels + name: Data labels + fileName: chart-data-labels.yaml + description: Add and style data labels for your charts. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-labels.yaml + group: Chart + api_set: + ExcelApi: '1.19' +- id: excel-chart-leader-lines + name: Leader lines + fileName: chart-leader-lines.yaml + description: Show and hide leader lines for chart labels. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + group: Chart + api_set: + ExcelApi: '1.19' +- 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/prod/samples/excel/12-comments-and-notes/comment-basics.yaml + group: Comments And Notes + 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/prod/samples/excel/12-comments-and-notes/comment-mentions.yaml + group: Comments And Notes + 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/prod/samples/excel/12-comments-and-notes/comment-replies.yaml + group: Comments And Notes + 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/prod/samples/excel/12-comments-and-notes/comment-resolution.yaml + group: Comments And Notes + api_set: + ExcelApi: '1.10' +- id: excel-note-basics + name: Notes + fileName: excel-note-basics.yaml + description: Adds, edits, and removes notes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + group: Comments And Notes + api_set: + ExcelApi: '1.18' +- 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/prod/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/prod/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 + description: Calculates the volume of a sphere. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/basic-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-volatile + name: Volatile function + fileName: volatile-function.yaml + description: Rolls a 6 sided die that returns a possible new value every calculation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/volatile-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-streaming + name: Streaming function + fileName: streaming-function.yaml + description: A streaming function that continuously increments the cell value. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/streaming-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-web-call + name: Web request to GitHub API + fileName: web-call-function.yaml + description: Calls the GitHub API to get the star count for an org/user and repository. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/web-call-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-errors + name: Custom functions errors + fileName: custom-functions-errors.yaml + description: Returns the "#NUM!" error as part of a 2-dimensional array. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/custom-functions-errors.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.2 +- id: excel-data-types-custom-functions + name: 'Data types: Custom functions' + fileName: data-types-custom-functions.yaml + description: >- + This sample shows how to write custom functions that return entity value + data types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/data-types-custom-functions.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.4 +- id: excel-custom-functions-custom-enum + name: Function with custom enums + fileName: custom-enum.yaml + description: >- + Use custom enums as parameters in a custom function that searches for + flights. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/custom-enum.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.5 +- 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/prod/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/prod/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-doubles + name: 'Data types: Formatted numbers' + fileName: data-types-formatted-number.yaml + description: >- + This sample shows how to set and get formatted numbers using double data + types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/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/prod/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/prod/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 and change error values' + fileName: data-types-error-values.yaml + description: >- + This sample shows how to set a cell value to an error data type, and then + update the value of cells that contain an error data type. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/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/prod/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/prod/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/prod/samples/excel/20-data-types/data-types-references.yaml + group: Data Types + api_set: + ExcelApi: '1.16' +- id: excel-data-types-basic-types + name: Basic types with metadata + fileName: data-types-basic-types.yaml + description: This sample shows how to work with metadata on basic types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-basic-types.yaml + group: Data Types + api_set: + ExcelApi: '1.19' +- 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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/samples/excel/42-range/range-dependents.yaml + group: Range + api_set: + ExcelAPI: '1.15' +- id: excel-cell-controls + name: Checkboxes + fileName: range-cell-control.yaml + description: This sample shows how to add and remove checkboxes from a table. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + group: Range + api_set: + ExcelApi: '1.18' +- 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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/samples/excel/44-shape/shape-textboxes.yaml + group: Shape + api_set: + ExcelApi: '1.9' +- id: excel-shape-get-active + name: Get active shape image + fileName: shape-get-active.yaml + description: Get an image of the active shape in your workbook. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-get-active.yaml + group: Shape + api_set: + ExcelApi: '1.19' +- 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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml + group: Workbook + api_set: + ExcelAPI: '1.13' +- id: excel-workbook-built-in-function + name: Use built-in Excel functions + fileName: workbook-built-in-functions.yaml + description: Use the VLOOKUP and SUM built-in Excel functions. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-built-in-functions.yaml + group: Workbook + api_set: + ExcelAPI: '1.2' +- 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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/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/prod/samples/excel/99-just-for-fun/color-wheel.yaml + group: Just For Fun + api_set: + ExcelApi: '1.4' \ No newline at end of file diff --git a/playlists-prod/outlook.yaml b/playlists-prod/outlook.yaml new file mode 100644 index 000000000..9a1b827bc --- /dev/null +++ b/playlists-prod/outlook.yaml @@ -0,0 +1,843 @@ +- id: outlook-roaming-settings-roaming-settings + name: Use add-in settings + fileName: roaming-settings.yaml + description: Gets, sets, saves, and removes add-in roaming settings. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml + group: Roaming Settings + api_set: + Mailbox: '1.1' +- id: outlook-item-custom-properties-load-set-get-save + name: Work with item custom properties + fileName: load-set-get-save.yaml + description: >- + Gets the custom properties that the add-in placed on the current item, sets + a new one, gets it, removes it, and saves all custom properties back to the + item. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + group: Item Custom Properties + api_set: + Mailbox: '1.1' +- id: outlook-item-body-get-selected-data + name: Get selected text (Compose) + fileName: get-selected-data.yaml + description: Gets the selected text in the item body or subject in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-selected-data.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-replace-selected-text + name: Replace selected text in item body + fileName: replace-selected-text.yaml + description: >- + Replaces selected text in a message or appointment's body with specified + text. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/replace-selected-text.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-add-inline-base64-image + name: Add inline Base64-encoded image to message or appointment body (Compose) + fileName: add-inline-base64-image.yaml + description: >- + Add an inline Base64-encoded image to the body of a message or appointment + being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/add-inline-base64-image.yaml + group: Item Body + api_set: + Mailbox: '1.8' +- id: outlook-item-body-get-body-format + name: Get the item's body format + fileName: get-body-format.yaml + description: Gets a message or appointment's body format (plain text or HTML). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-body-format.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-append-text-on-send + name: Append text to item body on send + fileName: append-text-on-send.yaml + description: Appends text to the end of the message or appointment's body once it's sent. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/append-text-on-send.yaml + group: Item Body + api_set: + Mailbox: '1.9' +- id: outlook-item-body-prepend-text-to-item-body + name: Prepend text to item body + fileName: prepend-text-to-item-body.yaml + description: Adds text to the beginning of the message or appointment's body. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-to-item-body.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-prepend-text-on-send + name: Prepend text to item body on send + fileName: prepend-text-on-send.yaml + description: >- + Prepends text to the beginning of the message or appointment's body once + it's sent. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-on-send.yaml + group: Item Body + api_set: + Mailbox: '1.13' +- id: outlook-item-save-and-close-close + name: Close the item + fileName: close.yaml + description: Closes the item (compose mode) + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close.yaml + group: Item Save And Close + api_set: + Mailbox: '1.3' +- id: outlook-close-async + name: Close the current message and discard changes (Message Compose) + fileName: close-async.yaml + description: Closes the current message and discards any unsaved changes when specified. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close-async.yaml + group: Item Save And Close + api_set: + Mailbox: '1.14' +- id: outlook-item-save-and-close-save + name: Save the item + fileName: save.yaml + description: Saves the item (compose mode) + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/save.yaml + group: Item Save And Close + api_set: + Mailbox: '1.3' +- id: outlook-recipients-and-attendees-get-from-message-read + name: Get from (Message Read) + fileName: get-from-message-read.yaml + description: Gets who the message is from in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-from-message-compose + name: Get from (Message Compose) + fileName: get-from-message-compose.yaml + description: Gets who the message is from in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-recipients-and-attendees-get-to-message-read + name: Get to (Message Read) + fileName: get-to-message-read.yaml + description: Gets the To line recipients of the message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-to-message-compose + name: Get and set to (Message Compose) + fileName: get-set-to-message-compose.yaml + description: Gets and sets the To line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-cc-message-read + name: Get cc (Message Read) + fileName: get-cc-message-read.yaml + description: Gets the Cc line recipients of the message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-cc-message-compose + name: Get and set cc (Message Compose) + fileName: get-set-cc-message-compose.yaml + description: Gets and sets the Cc line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-bcc-message-compose + name: Get and set bcc (Message Compose) + fileName: get-set-bcc-message-compose.yaml + description: Gets and sets the Bcc line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-sender-message-read + name: Get sender (Message Read) + fileName: get-sender-message-read.yaml + description: Gets the sender in Message Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-required-attendees-appointment-attendee + name: Get required attendees (Appointment Attendee) + fileName: get-required-attendees-appointment-attendee.yaml + description: Gets the required attendees in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: >- + outlook-recipients-and-attendees-get-set-required-attendees-appointment-organizer + name: Get and set required attendees (Appointment Organizer) + fileName: get-set-required-attendees-appointment-organizer.yaml + description: Gets and sets the required attendees in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-optional-attendees-appointment-attendee + name: Get optional attendees (Appointment Attendee) + fileName: get-optional-attendees-appointment-attendee.yaml + description: Gets the optional attendees in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: >- + outlook-recipients-and-attendees-get-set-optional-attendees-appointment-organizer + name: Get and set optional attendees (Appointment Organizer) + fileName: get-set-optional-attendees-appointment-organizer.yaml + description: Gets and sets the optional attendees in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-organizer-appointment-attendee + name: Get organizer (Appointment Attendee) + fileName: get-organizer-appointment-attendee.yaml + description: Gets the organizer in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-organizer-appointment-organizer + name: Get organizer (Appointment Organizer) + fileName: get-organizer-appointment-organizer.yaml + description: Gets the organizer in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-recipients-and-attendees-get-all-attendees + name: Get all attendees + fileName: get-all-attendees.yaml + description: Gets all appointment attendees and organizes them by their response. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-notifications-add-getall-remove + name: Work with notification messages + fileName: add-getall-remove.yaml + description: >- + Adds different kinds of notification messages, gets all notifications, and + replaces and removes an individual notification message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + group: Notifications + api_set: + Mailbox: '1.10' +- id: outlook-attachments-attachments-compose + name: Manipulate attachments (Item Compose) + fileName: attachments-compose.yaml + description: >- + Adds, gets, and removes attachments from a message or an appointment in + Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + group: Attachments + api_set: + Mailbox: '1.8' +- id: outlook-attachments-get-attachment-content + name: Get attachment content + fileName: get-attachment-content.yaml + description: Gets the attachment content in read or compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + group: Attachments + api_set: + Mailbox: '1.8' +- id: outlook-attachments-get-attachments-read + name: Get attachments (Item Read) + fileName: get-attachments-read.yaml + description: Gets the attachments of a message or an appointment in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml + group: Attachments + api_set: + Mailbox: '1.1' +- id: outlook-categories-work-with-categories + name: Work with item categories + fileName: work-with-categories.yaml + description: Gets, adds, and removes categories assigned to the item. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + group: Categories + api_set: + Mailbox: '1.8' +- id: outlook-categories-work-with-master-categories + name: Work with the categories master list + fileName: work-with-master-categories.yaml + description: Gets, adds, and removes categories in the master list for the mailbox. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + group: Categories + api_set: + Mailbox: '1.8' +- id: outlook-recurrence-get-series-id + name: Get the series ID + fileName: get-series-id.yaml + description: Gets the series ID. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-recurrence-get-recurrence-read + name: Get recurrence (Read) + fileName: get-recurrence-read.yaml + description: Gets the recurrence pattern of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-recurrence-read.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-recurrence-get-set-recurrence-appointment-organizer + name: Get and set recurrence (Appointment Organizer) + fileName: get-set-recurrence-appointment-organizer.yaml + description: Gets and sets the recurrence pattern in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-display-items-display-new-message + name: Create a new message + fileName: display-new-message.yaml + description: >- + Opens a new message form with a sample content, recipients, and an inline + image attachment + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-message.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-new-appointment + name: Create a new appointment + fileName: display-new-appointment.yaml + description: Opens a new appointment form with sample content and a few fields populated. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-appointment.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-existing-message + name: Open a message + fileName: display-existing-message.yaml + description: Displays an existing message in a separate window + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-message.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-existing-appointment + name: Open an appointment + fileName: display-existing-appointment.yaml + description: Displays existing appointment in a separate window + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-appointment.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-reply-forms + name: Create replies + fileName: display-reply-forms.yaml + description: Opens reply and reply-all message forms with sample reply content. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-reply-with-attachments + name: Create a reply with attachments + fileName: display-reply-with-attachments.yaml + description: Opens a reply or reply-all message form and adds sample attachments. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-sensitivity-labels-sensitivity-labels-catalog + name: Work with the sensitivity labels catalog + fileName: sensitivity-labels-catalog.yaml + description: >- + Determines if sensitivity labels are enabled on the mailbox and retrieves + all available labels from the catalog. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml + group: Sensitivity Label + api_set: + Mailbox: '1.13' +- id: outlook-sensitivity-labels-sensitivity-label + name: Work with sensitivity labels (Compose) + fileName: sensitivity-label.yaml + description: >- + Gets and sets the sensitivity label on a message or appointment in compose + mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + group: Sensitivity Label + api_set: + Mailbox: '1.13' +- id: outlook-delegates-and-shared-folders-get-shared-properties + name: Identify a shared folder or shared mailbox context + fileName: get-shared-properties.yaml + description: >- + Identifies whether the current mail item is in a shared folder or shared + mailbox by getting its properties. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + group: Delegates And Shared Folders + api_set: + Mailbox: '1.13' +- id: outlook-mime-headers-get-internet-headers-message-read + name: Get internet headers + fileName: get-internet-headers-message-read.yaml + description: Gets internet headers on a message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml + group: Mime Headers + api_set: + Mailbox: '1.8' +- id: outlook-mime-headers-manage-custom-internet-headers-message-compose + name: Work with custom internet headers + fileName: manage-custom-internet-headers-message-compose.yaml + description: >- + Sets, gets, and removes custom internet headers on a message in Compose + mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + group: Mime Headers + api_set: + Mailbox: '1.8' +- id: outlook-regex-matches-contextual + name: Get regex matches (Item Read, contextual) + fileName: contextual.yaml + description: Gets regex matches when the add-in is opened as a contextual add-in. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + group: Regex Matches + api_set: + Mailbox: '1.6' +- id: outlook-events-drag-drop-item + name: Drag and drop an item into the task pane + fileName: drag-drop-item.yaml + description: >- + Handles the drag-and-drop event when a user drags and drops messages and + file attachments into the add-in task pane. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + group: Events + api_set: + Mailbox: '1.5' +- id: outlook-tokens-and-service-calls-ids-and-urls + name: Endpoint URLs and item IDs in Exchange on-premises environments + fileName: ids-and-urls.yaml + description: >- + Retrieves the Exchange Web Services (EWS) endpoint URL and item IDs and + converts item IDs for different protocols. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.5' +- id: outlook-tokens-and-service-calls-user-identity-token + name: Get a user identity token in Exchange on-premises environments + fileName: user-identity-token.yaml + description: >- + Gets a user identity token for authentication flows in an Exchange + on-premises environment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-user-callback-token + name: Get a callback token in Exchange on-premises environments + fileName: user-callback-token.yaml + description: >- + Gets a callback token to call Outlook services from an add-in's backend + service in an Exchange on-premises environment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-make-ews-request-async + name: >- + Get a message using Exchange Web Services (EWS) in Exchange on-premises + environments + fileName: make-ews-request-async.yaml + description: >- + Uses EWS in an Exchange on-premises environment to get a message without any + backend code. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-send-message-using-make-ews-request-async + name: >- + Send a message using Exchange Web Services (EWS) in Exchange on-premises + environments + fileName: send-message-using-make-ews-request-async.yaml + description: >- + Uses EWS in an Exchange on-premises environment to send a message without + any backend code. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-get-icaluid-as-organizer + name: Get an appointment's iCalUId as the organizer (Exchange on-premises only) + fileName: get-icaluid-as-organizer.yaml + description: >- + Uses Exchange Web Services (EWS) in an Exchange on-premises environment to + get an appointment's iCalUId value where the user is the organizer. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.3' +- id: outlook-tokens-and-service-calls-get-icaluid-as-attendee + name: Get an appointment's iCalUId as an attendee (Exchange on-premises only) + fileName: get-icaluid-as-attendee.yaml + description: >- + Uses Exchange Web Services (EWS) in an Exchange on-premises environment to + get an appointment's iCalUId value where the user is an attendee. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-subject-read + name: Get the subject (Read) + fileName: get-subject-read.yaml + description: Gets the subject of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-subject-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-subject-compose + name: Get and set the subject (Compose) + fileName: get-set-subject-compose.yaml + description: Gets and sets the subject of an item in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-item-body-set-selected-data + name: Replace selected text in item body or subject (Compose) + fileName: set-selected-data.yaml + description: Replaces the selected text in the item body or subject in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/set-selected-data.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-internet-message-id-read + name: Get the internet message ID (Message Read) + fileName: get-internet-message-id-read.yaml + description: Gets the internet message ID of a message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-item-class-read + name: Get the item class (Read) + fileName: get-item-class-read.yaml + description: Gets the item class of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-item-type + name: Get the item type + fileName: get-item-type.yaml + description: Gets the item type. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-start-read + name: Get the start date and time (Read) + fileName: get-start-read.yaml + description: Gets the start date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-start-appointment-organizer + name: Get and set the start date and time (Appointment Organizer) + fileName: get-set-start-appointment-organizer.yaml + description: Gets and sets the start date and time of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-end-read + name: Get the end date and time (Read) + fileName: get-end-read.yaml + description: Gets the end date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-end-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-end-appointment-organizer + name: Get and set the end date and time (Appointment Organizer) + fileName: get-set-end-appointment-organizer.yaml + description: Gets and sets the end date and time of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-location-read + name: Get the location (Read) + fileName: get-location-read.yaml + description: Gets the location of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-location-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-location-appointment-organizer + name: Get and set the location (Appointment Organizer) + fileName: get-set-location-appointment-organizer.yaml + description: Gets and sets the location of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-add-remove-enhancedlocation-appointment + name: Manage the locations of an appointment + fileName: get-add-remove-enhancedlocation-appointment.yaml + description: Gets, adds, and removes locations on an appointment (enhancedLocation API). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + group: Other Item APIs + api_set: + Mailbox: '1.8' +- id: outlook-other-item-apis-get-normalized-subject-read + name: Get the normalized subject (Read) + fileName: get-normalized-subject-read.yaml + description: Gets the normalized subject of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-conversation-id-message + name: Get the conversation ID (Message) + fileName: get-conversation-id-message.yaml + description: Gets the conversation ID of a message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-date-time-created-read + name: Get the creation date and time (Read) + fileName: get-date-time-created-read.yaml + description: Gets the creation date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-date-time-modified-read + name: Get the last-modified date and time (Read) + fileName: get-date-time-modified-read.yaml + description: Gets the last-modified date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-diagnostic-information + name: Get mailbox diagnostic information + fileName: get-diagnostic-information.yaml + description: Gets a mailbox's diagnostic information. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-work-with-client-signatures + name: Work with client signatures (Compose) + fileName: work-with-client-signatures.yaml + description: >- + Checks if the client signature is enabled, disables the client signature, + gets the compose type, and sets a signature in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + group: Other Item APIs + api_set: + Mailbox: '1.10' +- id: outlook-other-item-apis-session-data-apis + name: Work with session data APIs (Compose) + fileName: session-data-apis.yaml + description: Sets, gets, gets all, removes, and clears session data in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + group: Other Item APIs + api_set: + Mailbox: '1.11' +- id: outlook-delay-message-delivery + name: Get and set message delivery (Message Compose) + fileName: delay-message-delivery.yaml + description: Gets and sets the delivery date and time of a message in compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/delay-message-delivery.yaml + group: Other Item APIs + api_set: + Mailbox: '1.13' +- id: outlook-other-item-apis-get-message-properties + name: Get properties of selected messages (Message Compose, Message Read) + fileName: get-message-properties.yaml + description: Gets the properties of multiple selected messages. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-message-properties.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-other-item-apis-get-set-sensitivity-level + name: Get and set the sensitivity level (Appointment Organizer) + fileName: get-set-sensitivity-level.yaml + description: Gets and sets the sensitivity level of an appointment being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-eml-format + name: Get the Base64-encoded EML format of a message (Message Read) + fileName: get-eml-format.yaml + description: Gets the Base64-encoded EML format of a message in read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-eml-format.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-in-reply-to + name: Get the ID of the message being replied to (Message Compose) + fileName: get-in-reply-to.yaml + description: Retrieves the ID of the message being replied to by the current message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-in-reply-to.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-conversation-index + name: Get the position of a message in a conversation (Message Compose) + fileName: get-conversation-index.yaml + description: >- + Retrieves the Base64-encoded position of the current message in a + conversation thread. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-index.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-item-class-async + name: Get item class (Message Compose) + fileName: get-item-class-async.yaml + description: Retrieves the item class property of the message being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-async.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-other-item-apis-item-id-compose + name: Get an item ID in compose mode + fileName: item-id-compose.yaml + description: Gets an item ID in compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/item-id-compose.yaml + group: Other Item APIs + api_set: + Mailbox: '1.8' +- id: outlook-send-async + name: Send the current message or appointment (Compose) + fileName: send-async.yaml + description: Sends the current message or appointment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/send-async.yaml + group: Other Item APIs + api_set: + Mailbox: '1.15' +- id: outlook-other-item-apis-get-loaded-message-properties + name: Get properties of a loaded message (Message Compose, Message Read) + fileName: get-loaded-message-properties.yaml + description: Gets the properties of the currently loaded message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml + group: Other Item APIs + api_set: + Mailbox: '1.15' +- id: outlook-get-set-isalldayevent + name: Get and set the isAllDayEvent property (Appointment Organizer) + fileName: get-set-isalldayevent.yaml + description: Gets and sets the isAllDayEvent property of an appointment being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + group: Preview APIs + api_set: + Mailbox: preview +- id: outlook-set-displayed-body-subject + name: Temporarily set the body or subject displayed in a message (Message Read) + fileName: set-displayed-body-subject.yaml + description: >- + Temporarily sets the content displayed in the body or subject of a message + in read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + group: Preview APIs + api_set: + Mailbox: preview \ No newline at end of file diff --git a/playlists-prod/powerpoint.yaml b/playlists-prod/powerpoint.yaml new file mode 100644 index 000000000..1864b7799 --- /dev/null +++ b/playlists-prod/powerpoint.yaml @@ -0,0 +1,189 @@ +- id: powerpoint-basics-basic-api-call-ts + name: Basic API call (TypeScript) + fileName: basic-api-call-ts.yaml + description: Performs a basic PowerPoint API call using TypeScript. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-api-call-ts.yaml + group: Basics + api_set: + PowerPointApi: '1.4' +- id: powerpoint-basics-basic-api-call-js + name: Basic API call (JavaScript) + fileName: basic-api-call-js.yaml + description: Performs a basic PowerPoint API call using JavaScript. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-api-call-js.yaml + group: Basics + api_set: + PowerPointApi: '1.4' +- id: powerpoint-basics-basic-common-api-call + name: Basic API call (Office 2013) + fileName: basic-common-api-call.yaml + description: >- + Executes a basic PowerPoint API call using the "common API" syntax + (compatible with Office 2013). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-common-api-call.yaml + group: Basics + api_set: + Selection: '1.1' +- id: powerpoint-create-presentation + name: Create presentation + fileName: create-presentation.yaml + description: >- + Creates a new, empty presentation and creates a new presentation by copying + an existing one. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/document/create-presentation.yaml + group: Document + api_set: + PowerPointApi: '1.1' +- id: powerpoint-hyperlinks-manage-hyperlinks + name: Get hyperlinks + fileName: manage-hyperlinks.yaml + description: Gets the hyperlinks found in a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml + group: Hyperlinks + api_set: + PowerPointApi: '1.6' +- id: powerpoint-basics-insert-image + name: Insert Image + fileName: insert-image.yaml + description: Inserts an image to the current slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/images/insert-image.yaml + group: Images + api_set: {} +- id: powerpoint-basics-insert-svg + name: Insert SVG + fileName: insert-svg.yaml + description: Inserts an SVG image using an XML string. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/images/insert-svg.yaml + group: Images + api_set: {} +- id: powerpoint-scenarios-searches-wikipedia-api + name: Search Wikipedia + fileName: searches-wikipedia-api.yaml + description: Searches Wikipedia based on the selected text in the presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/scenarios/searches-wikipedia-api.yaml + group: Scenarios + api_set: {} +- id: powerpoint-shapes + name: Insert shape, line, and text box + fileName: shapes.yaml + description: Inserts geometric shapes, lines, and text boxes to a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.4' +- id: powerpoint-shapes-get-set-shapes + name: Get, set, load, and save shapes + fileName: get-set-shapes.yaml + description: Get and set one or more selected shapes. Load and save one or more shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.5' +- id: powerpoint-shapes-get-shapes-by-type + name: Select shapes by type + fileName: get-shapes-by-type.yaml + description: Gets shapes in a slide based on their type, such as GeometricShape or Line. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + group: Shapes + api_set: + PowerPointApi: '1.4' +- id: powerpoint-shapes-add-modify-tables + name: Add and modify tables + fileName: add-modify-tables.yaml + description: Shows how to add and modify tables in a presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-shapes-binding-to-shapes + name: Binding to shapes + fileName: binding-to-shapes.yaml + description: Shows how to create binding references for images and work with z-order. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-shapes-group-ungroup-shapes + name: Group and ungroup shapes + fileName: group-ungroup-shapes.yaml + description: Shows how to create two shapes then group and ungroup them. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-add-slides + name: Add slides to a presentation + fileName: add-slides.yaml + description: Adds a slide and optionally specifies the slide master and layout. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.3' +- id: powerpoint-insert-slides + name: Insert slides from other presentation + fileName: insert-slides.yaml + description: Inserts slides from another PowerPoint file into the current presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.5' +- id: powerpoint-basics-get-slide-metadata + name: Get slide metadata + fileName: get-slide-metadata.yaml + description: Gets the title, index, and ID of the selected slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-slide-metadata.yaml + group: Slide Management + api_set: {} +- id: powerpoint-slide-management-get-set-slides + name: Get, set, load, and save slides + fileName: get-set-slides.yaml + description: Get and set one or more selected slides. Load and save one or more slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.5' +- id: powerpoint-slide-management-export-import-slide + name: Export and import slide + fileName: export-import-slide.yaml + description: Shows how to export and import a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml + group: Slide Management + api_set: + PowerPointApi: '1.8' +- id: powerpoint-tags + name: Work with tags + fileName: tags.yaml + description: Use tags to process subsets of slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + group: Tags + api_set: + PowerPointApi: '1.3' +- id: powerpoint-text-get-set-textrange + name: Work with text range selections + fileName: get-set-textrange.yaml + description: Get, set, load, and save text range selections. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + group: Text + api_set: + PowerPointApi: '1.8' \ No newline at end of file diff --git a/playlists-prod/project.yaml b/playlists-prod/project.yaml new file mode 100644 index 000000000..ac477f709 --- /dev/null +++ b/playlists-prod/project.yaml @@ -0,0 +1,11 @@ +- id: project-basics-basic-common-api-call + name: Basic API call (Office 2013) + fileName: basic-common-api-call.yaml + description: >- + Executes a basic Project API call using the "common API" syntax (compatible + with Office 2013). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/project/basics/basic-common-api-call.yaml + group: Basics + api_set: + Selection: 1.1 \ No newline at end of file diff --git a/playlists-prod/word.yaml b/playlists-prod/word.yaml new file mode 100644 index 000000000..f55d4a138 --- /dev/null +++ b/playlists-prod/word.yaml @@ -0,0 +1,638 @@ +- id: word-basics-basic-api-call + name: Basic API call (TypeScript) + fileName: basic-api-call.yaml + description: Performs a basic Word API call using TypeScript. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-api-call.yaml + group: Basics + api_set: + WordApi: '1.1' +- id: word-basics-api-call-es5 + name: Basic API call (JavaScript) + fileName: basic-api-call-es5.yaml + description: Performs a basic Word API call using plain JavaScript & Promises. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-api-call-es5.yaml + group: Basics + api_set: + WordApi: '1.1' +- id: word-basics-basic-common-api-call + name: Basic API call (Office 2013) + fileName: basic-common-api-call.yaml + description: >- + Performs a basic Word API call using JavaScript with the "common API" syntax + (compatible with Office 2013). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-common-api-call.yaml + group: Basics + api_set: + Selection: 1.1 +- id: word-content-controls-insert-and-change-content-controls + name: Content control basics + fileName: insert-and-change-content-controls.yaml + description: Inserts, updates, and retrieves content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml + group: Content Controls + api_set: + WordApi: '1.1' +- id: word-content-controls-content-control-onadded-event + name: On adding content controls + fileName: content-control-onadded-event.yaml + description: >- + Registers, triggers, and deregisters onAdded event that tracks the addition + of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onentered-event + name: On entering content controls + fileName: content-control-onentered-event.yaml + description: >- + Registers, triggers, and deregisters onEntered event that tracks when the + cursor is placed within content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onselectionchanged-event + name: On changing selection in content controls + fileName: content-control-onselectionchanged-event.yaml + description: >- + Registers, triggers, and deregisters onSelectionChanged event that tracks + when selections are changed in content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-ondatachanged-event + name: On changing data in content controls + fileName: content-control-ondatachanged-event.yaml + description: >- + Registers, triggers, and deregisters onDataChanged event that tracks when + data is changed in content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onexited-event + name: On exiting content controls + fileName: content-control-onexited-event.yaml + description: >- + Registers, triggers, and deregisters onExited event that tracks when the + cursor is removed from within content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-ondeleted-event + name: On deleting content controls + fileName: content-control-ondeleted-event.yaml + description: >- + Registers, triggers, and deregisters onDeleted event that tracks the removal + of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-insert-and-change-checkbox-content-control + name: Manage checkbox content controls + fileName: insert-and-change-checkbox-content-control.yaml + description: Inserts, updates, retrieves, and deletes checkbox content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.7' +- id: word-content-controls-insert-and-change-combo-box-content-control + name: Manage combo box content controls + fileName: insert-and-change-combo-box-content-control.yaml + description: Inserts, updates, and deletes combo box content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.9' +- id: word-content-controls-insert-and-change-dropdown-list-content-control + name: Manage dropdown list content controls + fileName: insert-and-change-dropdown-list-content-control.yaml + description: Inserts, updates, and deletes dropdown list content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.9' +- id: word-content-controls-get-change-tracking-states + name: Get change tracking states of content controls + fileName: get-change-tracking-states.yaml + description: Gets change tracking states of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/get-change-tracking-states.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-images-insert-and-get-pictures + name: Use inline pictures + fileName: insert-and-get-pictures.yaml + description: Inserts and gets inline pictures. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + group: Images + api_set: + WordApiDesktop: '1.1' +- id: word-lists-insert-list + name: Create a list + fileName: insert-list.yaml + description: Inserts a new list into the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + group: Lists + api_set: + WordApi: '1.3' +- id: word-lists-manage-styles + name: Get list styles + fileName: manage-list-styles.yaml + description: This sample shows how to get the list styles in the current document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + group: Lists + api_set: + WordApiDesktop: '1.1' +- id: word-lists-organize-list + name: Organize a list + fileName: organize-list.yaml + description: Shows how to create and organize a list. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + group: Lists + api_set: + WordApi: '1.3' +- id: word-paragraph-get-paragraph-on-insertion-point + name: Get paragraph from insertion point + fileName: get-paragraph-on-insertion-point.yaml + description: Gets the full paragraph containing the insertion point. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-insert-line-and-page-breaks + name: Insert breaks + fileName: insert-line-and-page-breaks.yaml + description: Inserts page and line breaks in a document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-line-and-page-breaks.yaml + group: Paragraph + api_set: + WordApi: '1.2' +- id: word-paragraph-insert-in-different-locations + name: Insert content at different locations + fileName: insert-in-different-locations.yaml + description: Inserts content at different document locations. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-in-different-locations.yaml + group: Paragraph + api_set: + WordApi: '1.2' +- id: word-paragraph-insert-formatted-text + name: Insert formatted text + fileName: insert-formatted-text.yaml + description: Formats text with pre-built and custom styles. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-formatted-text.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-insert-header-and-footer + name: Insert headers and footers + fileName: insert-header-and-footer.yaml + description: Inserts headers and footers in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-header-and-footer.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-paragraph-properties + name: Paragraph properties + fileName: paragraph-properties.yaml + description: Sets indentation, space between paragraphs, and other paragraph properties. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-search + name: Search + fileName: search.yaml + description: Shows basic and advanced search capabilities. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/search.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-get-word-count + name: Get word count + fileName: get-word-count.yaml + description: Counts how many times a word or term appears in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-word-count.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-get-text + name: Get text + fileName: get-text.yaml + description: >- + Shows how to get paragraph text, including hidden text and text marked for + deletion. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-text.yaml + group: Paragraph + api_set: + WordApi: '1.7' +- id: word-paragraph-onadded-event + name: On adding paragraphs + fileName: onadded-event.yaml + description: >- + Registers, triggers, and deregisters the onParagraphAdded event that tracks + the addition of paragraphs. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + group: Paragraph + api_set: + WordApi: '1.6' +- id: word-paragraph-onchanged-event + name: On changing content in paragraphs + fileName: onchanged-event.yaml + description: >- + Registers, triggers, and deregisters the onParagraphChanged event that + tracks when content is changed in paragraphs. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml + group: Paragraph + api_set: + WordApi: '1.6' +- id: word-paragraph-ondeleted-event + name: On deleting paragraphs + fileName: ondeleted-event.yaml + description: >- + Registers, triggers, and deregisters the onParagraphDeleted event that + tracks the removal of paragraphs. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml + group: Paragraph + api_set: + WordApi: '1.6' +- id: word-properties-get-built-in-properties + name: Built-in document properties + fileName: get-built-in-properties.yaml + description: Gets built-in document properties. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/get-built-in-properties.yaml + group: Properties + api_set: + WordApi: '1.1' +- id: word-properties-read-write-custom-document-properties + name: Custom document properties + fileName: read-write-custom-document-properties.yaml + description: Adds and reads custom document properties of different types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + group: Properties + api_set: + WordApi: '1.3' +- id: word-ranges-scroll-to-range + name: Scroll to a range + fileName: scroll-to-range.yaml + description: Scrolls to a range with and without selection. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/scroll-to-range.yaml + group: Ranges + api_set: + WordApi: '1.2' +- id: word-ranges-split-words-of-first-paragraph + name: Split a paragraph into ranges + fileName: split-words-of-first-paragraph.yaml + description: >- + Splits a paragraph into word ranges and then traverses all the ranges to + format each word, producing a "karaoke" effect. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/split-words-of-first-paragraph.yaml + group: Ranges + api_set: + WordApi: '1.3' +- id: word-ranges-compare-location + name: Compare range locations + fileName: compare-location.yaml + description: This sample shows how to compare the locations of two ranges. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/compare-location.yaml + group: Ranges + api_set: + WordApi: '1.3' +- id: word-ranges-get-pages + name: Work with pages, panes, and windows + fileName: get-pages.yaml + description: Shows how to work with pages, panes, and windows. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + group: Ranges + api_set: + WordApiDesktop: '1.2' +- id: word-tables-table-cell-access + name: Create and access a table + fileName: table-cell-access.yaml + description: Creates a table and accesses a specific cell. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + group: Tables + api_set: + WordApi: '1.3' +- id: word-tables-manage-formatting + name: Table formatting + fileName: manage-formatting.yaml + description: >- + Gets the formatting details of a table, a table row, and a table cell, + including borders, alignment, and cell padding. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + group: Tables + api_set: + WordApi: '1.3' +- id: word-tables-manage-custom-style + name: Manage custom table style + fileName: manage-custom-style.yaml + description: >- + Shows how to manage primarily margins and alignments of a custom table style + in the current document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml + group: Tables + api_set: + WordApiDesktop: '1.1' +- id: word-shapes-manage-shapes-text-boxes + name: Work with shapes and text boxes + fileName: manage-shapes-text-boxes.yaml + description: Shows how to work with shapes and text boxes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-manage-geometric-shapes + name: Manage geometric shapes + fileName: manage-geometric-shapes.yaml + description: Shows how to work with geometric shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-group-ungroup + name: Group and ungroup shapes + fileName: group-ungroup.yaml + description: Shows how to group and ungroup shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-manage-canvases + name: Work with canvases + fileName: manage-canvases.yaml + description: Shows how to work with canvases. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-canvases.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-document-manage-body + name: Manage body + fileName: manage-body.yaml + description: Shows how to manage the document body. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + group: Document + api_set: + WordApi: '1.2' +- id: word-document-insert-section-breaks + name: Add a section + fileName: insert-section-breaks.yaml + description: Shows how to insert section breaks in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-section-breaks.yaml + group: Document + api_set: + WordApi: '1.1' +- id: word-document-insert-external-document + name: Insert an external document + fileName: insert-external-document.yaml + description: >- + Inserts the content (with or without settings) of an external document into + the current document. Settings include formatting, change-tracking mode, + custom properties, and XML parts. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + group: Document + api_set: + WordApi: '1.7' +- id: word-document-manage-change-tracking + name: Track changes + fileName: manage-change-tracking.yaml + description: >- + This sample shows how to get and set the change tracking mode and get the + before and after of reviewed text. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-tracked-changes + name: Manage tracked changes + fileName: manage-tracked-changes.yaml + description: >- + This samples shows how to manage tracked changes, including accepting and + rejecting changes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + group: Document + api_set: + WordApi: '1.6' +- id: word-document-manage-comments + name: Manage comments + fileName: manage-comments.yaml + description: >- + This sample shows how to perform basic comments operations, including + insert, reply, get, edit, resolve, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-footnotes + name: Manage footnotes + fileName: manage-footnotes.yaml + description: >- + This sample shows how to perform basic footnote operations, including + insert, get, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-fields + name: Manage fields + fileName: manage-fields.yaml + description: >- + This sample shows how to perform basic operations on fields, including + insert, get, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-settings + name: Manage settings + fileName: manage-settings.yaml + description: >- + This sample shows how to add, edit, get, and delete custom settings on a + document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-custom-xml-part-ns + name: Manage a CustomXmlPart with the namespace + fileName: manage-custom-xml-part-ns.yaml + description: >- + This sample shows how to add, query, replace, edit, and delete a custom XML + part in a document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-custom-xml-part + name: Manage a CustomXmlPart without the namespace + fileName: manage-custom-xml-part.yaml + description: >- + This sample shows how to add, query, edit, and delete a custom XML part in a + document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-styles + name: Manage styles + fileName: manage-styles.yaml + description: >- + This sample shows how to perform operations on the styles in the current + document and how to add and delete custom styles. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + group: Document + api_set: + WordApiDesktop: '1.1' +- id: word-document-get-external-styles + name: Get styles from external document + fileName: get-external-styles.yaml + description: This sample shows how to get styles from an external document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/get-external-styles.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-save-close + name: Manage document save and close + fileName: save-close.yaml + description: Shows how to manage saving and closing document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-annotations + name: Manage annotations + fileName: manage-annotations.yaml + description: >- + Shows how to leverage the Writing Assistance API to manage annotations and + use annotation events. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + group: Document + api_set: + WordApi: '1.8' +- id: word-document-compare-documents + name: Compare documents + fileName: compare-documents.yaml + description: Compares two documents (the current one and a specified external one). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/compare-documents.yaml + group: Document + api_set: + WordApiDesktop: '1.1' +- id: word-scenarios-doc-assembly + name: Document assembly + fileName: doc-assembly.yaml + description: Composes different parts of a Word document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + group: Scenarios + api_set: + WordApi: '1.1' +- id: word-scenarios-multiple-property-set + name: Set multiple properties at once + 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/prod/samples/word/90-scenarios/multiple-property-set.yaml + group: Scenarios + api_set: + WordApi: '1.3' +- id: word-scenarios-correlated-objects-pattern + name: Correlated objects pattern + fileName: correlated-objects-pattern.yaml + description: Shows the performance benefits of avoiding `context.sync` calls in a loop. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/correlated-objects-pattern.yaml + group: Scenarios + api_set: + WordApi: '1.4' +- id: word-close-document-window + name: Close document window + fileName: close-document-window.yaml + description: Shows how to close document window. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/close-document-window.yaml + group: Preview APIs + api_set: + WordApi: '1.10' +- id: word-insert-and-change-content-controls + name: Content control basics + fileName: insert-and-change-content-controls.yaml + description: Inserts, updates, and retrieves content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/insert-and-change-content-controls.yaml + group: Preview APIs + api_set: + WordApi: '1.10' +- id: word-manage-comments + name: Manage comments + fileName: manage-comments.yaml + description: >- + This sample shows how to perform operations on comments (including insert, + reply, get, edit, resolve, and delete) and use comment events. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + group: Preview APIs + api_set: + WordApi: '1.10' \ No newline at end of file diff --git a/playlists/excel.yaml b/playlists/excel.yaml index 7e76e4ec4..5aa863380 100644 --- a/playlists/excel.yaml +++ b/playlists/excel.yaml @@ -1,593 +1,1397 @@ -- id: excel-basic-api-call - name: Basic API call +- id: excel-basics-basic-api-call + name: Basic API call (TypeScript) fileName: basic-api-call.yaml - description: Executes a basic Excel API call + description: Performs a basic Excel API call using TypeScript. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/01-basics/basic-api-call.yaml + 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-basic-api-call-es5 + ExcelApi: '1.1' +- id: excel-basics-basic-api-call-es5 name: Basic API call (JavaScript) fileName: basic-api-call-es5.yaml - description: Executes a basic Excel API call using plain JavaScript & Promises + description: Performs a basic Excel API call using plain JavaScript & Promises. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/01-basics/basic-api-call-es5.yaml + 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 + ExcelApi: '1.1' - id: excel-basics-basic-common-api-call name: Basic API call (Office 2013) fileName: basic-common-api-call.yaml description: >- - Executes a basic Excel API call using the "common API" syntax (compatible - with Office 2013). + Performs a basic Excel API call using JavaScript with the "common API" + syntax (compatible with Office 2013). rawUrl: >- - https://raw.githubusercontent.com////samples/excel/01-basics/basic-common-api-call.yaml + 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-advanced-report-generation - name: Report generation - fileName: report-generation.yaml +- 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: >- - Writes data to the workbook, reads and applies basic formatting, and adds a - chart bound to that data. + Creates a bubble chart with each data row represented as a single chart + series (bubble). rawUrl: >- - https://raw.githubusercontent.com////samples/excel/20-scenarios/report-generation.yaml - group: Scenarios + 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.1 + 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-chart-data-labels + name: Data labels + fileName: chart-data-labels.yaml + description: Add and style data labels for your charts. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-labels.yaml + group: Chart + api_set: + ExcelApi: '1.19' +- id: excel-chart-leader-lines + name: Leader lines + fileName: chart-leader-lines.yaml + description: Show and hide leader lines for chart labels. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-leader-lines.yaml + group: Chart + api_set: + ExcelApi: '1.19' +- 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-comments-and-notes/comment-basics.yaml + group: Comments And Notes + 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-comments-and-notes/comment-mentions.yaml + group: Comments And Notes + 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-comments-and-notes/comment-replies.yaml + group: Comments And Notes + 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-comments-and-notes/comment-resolution.yaml + group: Comments And Notes + api_set: + ExcelApi: '1.10' +- id: excel-note-basics + name: Notes + fileName: excel-note-basics.yaml + description: Adds, edits, and removes notes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/excel-note-basics.yaml + group: Comments And Notes + api_set: + ExcelApi: '1.18' - id: excel-range-conditional-formatting-basic - name: Conditional Formatting for Ranges - Basic + name: Basic conditional formatting fileName: conditional-formatting-basic.yaml - description: Apply common types of conditional formatting to ranges. + 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 + description: Calculates the volume of a sphere. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/basic-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-volatile + name: Volatile function + fileName: volatile-function.yaml + description: Rolls a 6 sided die that returns a possible new value every calculation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/volatile-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-streaming + name: Streaming function + fileName: streaming-function.yaml + description: A streaming function that continuously increments the cell value. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/streaming-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-web-call + name: Web request to GitHub API + fileName: web-call-function.yaml + description: Calls the GitHub API to get the star count for an org/user and repository. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/web-call-function.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.1 +- id: excel-custom-functions-errors + name: Custom functions errors + fileName: custom-functions-errors.yaml + description: Returns the "#NUM!" error as part of a 2-dimensional array. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/custom-functions-errors.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.2 +- id: excel-data-types-custom-functions + name: 'Data types: Custom functions' + fileName: data-types-custom-functions.yaml + description: >- + This sample shows how to write custom functions that return entity value + data types. + rawUrl: >- + 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-functions-custom-enum + name: Function with custom enums + fileName: custom-enum.yaml + description: >- + Use custom enums as parameters in a custom function that searches for + flights. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/custom-enum.yaml + group: Custom Functions + api_set: + CustomFunctionsRuntime: 1.5 +- 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////samples/excel/30-range/conditional-formatting-basic.yaml + 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-doubles + name: 'Data types: Formatted numbers' + fileName: data-types-formatted-number.yaml + description: >- + This sample shows how to set and get formatted numbers using double data + types. + 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 and change error values' + fileName: data-types-error-values.yaml + description: >- + This sample shows how to set a cell value to an error data type, and then + update the value of cells that contain 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-types-basic-types + name: Basic types with metadata + fileName: data-types-basic-types.yaml + description: This sample shows how to work with metadata on basic types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-basic-types.yaml + group: Data Types + api_set: + ExcelApi: '1.19' +- 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.6 -- id: excel-range-copy-multiply-values - name: Copy and multiply values - fileName: copy-multiply-values.yaml - description: Copy and multiply values in a range + 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////samples/excel/30-range/copy-multiply-values.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-copyfrom.yaml group: Range api_set: - ExcelApi: 1.1 -- id: excel-range-create-and-use-range-intersection - name: Create and Use an Intersection of Ranges - fileName: create-and-use-range-intersection.yaml - description: Create a an intersection of two ranges and make a chart of it. + 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////samples/excel/30-range/create-and-use-range-intersection.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-areas.yaml group: Range api_set: - ExcelApi: 1.4 + 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: Format a range + 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////samples/excel/30-range/formatting.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/cell-properties.yaml group: Range api_set: - ExcelApi: 1.1 -- id: excel-range-insert-delete-clear-range - name: 'Insert, delete, clear range' + 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: 'Insert, delete and clear a range' + 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////samples/excel/30-range/insert-delete-clear-range.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/outline.yaml group: Range api_set: - ExcelApi: 1.1 -- id: excel-range-range-operations - name: Range operations - fileName: range-operations.yaml - description: 'Bounding rect, intersection, offset and resized range' + 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////samples/excel/30-range/range-operations.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-relationships.yaml group: Range api_set: - ExcelApi: 1.1 + 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: Get and set the currently selected range + description: Gets and sets the currently selected range. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/30-range/selected-range.yaml + 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-range-set-get-values - name: Set and get values - fileName: set-get-values.yaml - description: Set and get values and formulas for a range + 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////samples/excel/30-range/set-get-values.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/precedents.yaml group: Range api_set: - ExcelApi: 1.1 -- id: excel-range-test-for-used-range - name: Test for used range - fileName: test-for-used-range.yaml - description: Create a chart from a table only if there's data in the table. + 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////samples/excel/30-range/test-for-used-range.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/style.yaml group: Range api_set: - ExcelApi: 1.4 -- id: excel-range-working-with-dates - name: Working with dates - fileName: working-with-dates.yaml + 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: >- - Setting and getting date values in a range and manipulating them using the - Moment JavaScript library with the Moment-MSDate plug-in + Applies formulas that use dynamic arrays and displays information about the + ranges used to display the data. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/30-range/working-with-dates.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/dynamic-arrays.yaml group: Range api_set: - ExcelApi: 1.1 -- id: excel-worksheet-activeworksheet - name: Active worksheet - fileName: activeworksheet.yaml - description: Get and set the active worksheet + 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////samples/excel/35-worksheet/activeworksheet.yaml - group: Worksheet + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/used-range.yaml + group: Range 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: 'Add, delete, rename and change the position of a worksheet' + 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////samples/excel/35-worksheet/add-delete-rename-move-worksheet.yaml - group: Worksheet + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/set-get-values.yaml + group: Range api_set: - ExcelApi: 1.1 -- id: excel-worksheet-hide-unhide-worksheet - name: Hide and unhide worksheet - fileName: hide-unhide-worksheet.yaml - description: Hide and unhide a worksheet + 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////samples/excel/35-worksheet/hide-unhide-worksheet.yaml - group: Worksheet + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-merged-ranges.yaml + group: Range api_set: - ExcelApi: 1.1 -- id: excel-worksheet-list-worksheets - name: List worksheets - fileName: list-worksheets.yaml - description: List the worksheets in the workbook + 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////samples/excel/35-worksheet/list-worksheets.yaml - group: Worksheet + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-get-range-edge.yaml + group: Range api_set: - ExcelApi: 1.1 -- id: excel-worksheet-reference-worksheets-by-relative-position - name: Reference worksheets by relative position - fileName: reference-worksheets-by-relative-position.yaml + ExcelAPI: '1.13' +- id: excel-direct-dependents + name: Direct dependents + fileName: range-direct-dependents.yaml description: >- - Shows how to use the worksheet shortcut methods, such as getFirst, getLast, - getPrevious, and getNext. + 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////samples/excel/35-worksheet/reference-worksheets-by-relative-position.yaml - group: Worksheet + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-direct-dependents.yaml + group: Range api_set: - ExcelApi: 1.5 -- id: excel-worksheet-worksheet-range-cell - name: Worksheet range and cell - fileName: worksheet-range-cell.yaml - description: Get a range or a cell in a worksheet + 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////samples/excel/35-worksheet/worksheet-range-cell.yaml - group: Worksheet + 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-cell-controls + name: Checkboxes + fileName: range-cell-control.yaml + description: This sample shows how to add and remove checkboxes from a table. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-cell-control.yaml + group: Range api_set: - ExcelApi: 1.1 + ExcelApi: '1.18' +- 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-shape-get-active + name: Get active shape image + fileName: shape-get-active.yaml + description: Get an image of the active shape in your workbook. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-get-active.yaml + group: Shape + api_set: + ExcelApi: '1.19' - 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: Add rows and columns to a table + description: Adds rows and columns to a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/add-rows-and-columns-to-a-table.yaml + 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.1 + ExcelApi: '1.4' - id: excel-table-convert-range-to-table - name: Convert a range to a table + name: Convert a range fileName: convert-range-to-table.yaml - description: Convert a range to a table + description: Converts a range to a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/convert-range-to-table.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/convert-range-to-table.yaml group: Table api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' - id: excel-table-create-table name: Create a table fileName: create-table.yaml - description: Creates a table with four columns and seven rows. + description: Creates a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/create-table.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/create-table.yaml group: Table api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' - id: excel-table-filter-data name: Filter data fileName: filter-data.yaml - description: Filter data in a table + description: Filters table data. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/filter-data.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/filter-data.yaml group: Table api_set: - ExcelApi: 1.1 -- id: excel-table-format-table - name: Format table - fileName: format-table.yaml - description: Format a table + ExcelApi: '1.4' +- id: excel-table-formatting + name: Formatting + fileName: formatting.yaml + description: Formats a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/format-table.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/formatting.yaml group: Table api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' - id: excel-table-get-data-from-table - name: Get data from a table + name: Get data fileName: get-data-from-table.yaml - description: Get data from a table + description: Gets data from a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/get-data-from-table.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/get-data-from-table.yaml group: Table api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' - id: excel-table-get-visible-range-of-a-filtered-table - name: Get visible range from a filtered table + name: Get visible range fileName: get-visible-range-of-a-filtered-table.yaml - description: Get visible range from a filtered table + description: Gets the visible range from a filtered table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/get-visible-range-of-a-filtered-table.yaml + 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.1 + ExcelApi: '1.4' - id: excel-table-import-json-data name: Import JSON data fileName: import-json-data.yaml - description: Import JSON data into a table + description: Imports JSON data into a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/import-json-data.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/import-json-data.yaml group: Table api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' - id: excel-table-sort-data - name: Sort table data + name: Sort data fileName: sort-data.yaml - description: Sort table data + description: Sorts the data within a table. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/40-table/sort-data.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/sort-data.yaml group: Table api_set: - ExcelApi: 1.1 -- id: excel-create-and-use-named-item-for-range - name: Create and use named range item - fileName: create-and-use-named-item-for-range.yaml - description: Create and use named range item + 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////samples/excel/45-named-item/create-and-use-named-item-for-range.yaml - group: Named Item - api_set: - ExcelApi: 1.4 -- id: excel-named-item-create-and-remove-named-item - name: Create and remove named items - fileName: create-and-remove-named-item.yaml - description: Create and remove named items for a formula - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/45-named-item/create-and-remove-named-item.yaml - group: Named Item - api_set: - ExcelApi: 1.4 -- id: excel-named-item-create-named-item - name: Create a named item - fileName: create-named-item.yaml - description: Create a named item for a formula - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/45-named-item/create-named-item.yaml - group: Named Item - api_set: - ExcelApi: 1.4 -- id: excel-named-item-list-named-items - name: List all named items in a workbook - fileName: list-named-items.yaml - description: List all named items in a workbook - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/45-named-item/list-named-items.yaml - group: Named Item - api_set: - ExcelApi: 1.3 -- id: excel-chart-create-column-clustered-chart - name: Column clustered chart - fileName: create-column-clustered-chart.yaml - description: Create a column clustered chart - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/50-chart/create-column-clustered-chart.yaml - group: Chart - api_set: - ExcelApi: 1.1 -- id: excel-chart-create-doughnut-chart - name: Doughnut chart - fileName: create-doughnut-chart.yaml - description: Create a doughnut chart - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/50-chart/create-doughnut-chart.yaml - group: Chart - api_set: - ExcelApi: 1.1 -- id: excel-chart-create-line-chart - name: Line chart - fileName: create-line-chart.yaml - description: Create a line chart - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/50-chart/create-line-chart.yaml - group: Chart - api_set: - ExcelApi: 1.1 -- id: excel-chart-create-xyscatter-chart - name: XY scatter chart - fileName: create-xyscatter-chart.yaml - description: Draws a basic XY scatter chart - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/50-chart/create-xyscatter-chart.yaml - group: Chart - api_set: - ExcelApi: 1.1 -- id: excel-pivottable-refresh-pivot-table - name: Refresh pivot table - fileName: refresh-pivot-table.yaml - description: Refresh pivot table - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/55-pivot-table/refresh-pivot-table.yaml - group: Pivot Table - api_set: - ExcelApi: 1.3 -- id: excel-events-data-changed - name: Handle the data changed event - fileName: data-changed.yaml - description: This snippet shows how to register a handler for the data-changed event. - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/70-events/data-changed.yaml - group: Events - api_set: - ExcelApi: 1.3 -- id: excel-events-selection-changed - name: Selection Changed - fileName: selection-changed.yaml - description: Add and remove an event handler on the selection changed event - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/70-events/selection-changed.yaml - group: Events + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/resize-table.yaml + group: Table api_set: - ExcelApi: 1.2 -- id: excel-events-setting-changed - name: Handle the settings-changed event - fileName: setting-changed.yaml - description: This snippet shows how to register a handler for the SettingsChanged event. + 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////samples/excel/70-events/setting-changed.yaml - group: Events + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-get-active-cell.yaml + group: Workbook api_set: - ExcelApi: 1.4 + ExcelApi: '1.7' - id: excel-settings-create-get-change-delete-settings - name: 'Create, get, change, and delete a setting' + name: Add-in settings fileName: create-get-change-delete-settings.yaml - description: 'Show how to create, get, change, and delete settings in the document.' + description: >- + Creates, gets, changes, and deletes settings that are unique to the specific + workbook and add-in combination. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/80-settings/create-get-change-delete-settings.yaml - group: Settings + 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-document-get-file-in-slices-async - name: Get file (using slicing) - fileName: get-file-in-slices-async.yaml + ExcelApi: '1.4' +- id: excel-workbook-calculation + name: Calculations + fileName: workbook-calculation.yaml description: >- - Use slicing to get the byte array and base64-encoded string that represent - the current document. + Demonstrates the calculation APIs of the workbook: events for when the + worksheet recalculates and application-level calculation controls. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/82-document/get-file-in-slices-async.yaml - group: Document + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-calculation.yaml + group: Workbook api_set: - ExcelApi: 1.1 -- id: excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts - name: 'Create, set, get, and delete custom XML part' - fileName: create-set-get-and-delete-custom-xml-parts.yaml - description: 'Shows how to create, set, get, and delete a custom XML part.' + 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////samples/excel/85-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml - group: Custom XML Parts + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/create-workbook.yaml + group: Workbook api_set: - ExcelApi: 1.5 -- id: excel-custom-xml-parts-test-xml-for-unique-namespace - name: Test custom XML part for unique namespace - fileName: test-xml-for-unique-namespace.yaml + ExcelApi: '1.8' +- id: excel-culture-info + name: Culture info + fileName: culture-info.yaml description: >- - Shows how to test to see if there is only one XML part for a specified - namespace. + This sample shows how to apply the cultural settings APIs to help normalize + data. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/85-custom-xml-parts/test-xml-for-unique-namespace.yaml - group: Custom XML Parts + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/culture-info.yaml + group: Workbook api_set: - ExcelApi: 1.5 -- id: excel-multiple-property-set - name: Multiple Property Set - fileName: multiple-property-set.yaml - description: Setting multiple properties at once with the rich API object set() method. + 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-workbook-built-in-function + name: Use built-in Excel functions + fileName: workbook-built-in-functions.yaml + description: Use the VLOOKUP and SUM built-in Excel functions. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-built-in-functions.yaml + group: Workbook + api_set: + ExcelAPI: '1.2' +- id: excel-worksheet-active-worksheet + name: Active worksheet + fileName: active-worksheet.yaml + description: Gets and sets the active worksheet. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/88-common-patterns/multiple-property-set.yaml - group: Common Patterns + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/active-worksheet.yaml + group: Worksheet api_set: - ExcelApi: 1.4 -- id: excel-chart-axis - name: Chart axis - fileName: chart-axis.yaml - description: 'Get, set, and remove axis unit, label and title in a chart.' + 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////samples/excel/89-preview-apis/chart-axis.yaml - group: Preview APIs + 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.7 -- id: excel-chart-legend - name: Chart legend - fileName: chart-legend.yaml - description: Format legend font + 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////samples/excel/89-preview-apis/chart-legend.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-auto-filter.yaml + group: Worksheet api_set: - ExcelAPI: 1.7 -- id: excel-chart-point - name: Chart point - fileName: chart-point.yaml - description: Set chart point color. + 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////samples/excel/89-preview-apis/chart-point.yaml - group: Preview APIs + 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-chart-series - name: Chart series - fileName: chart-series.yaml - description: 'Add, set, and delete a series in a chart.' + 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////samples/excel/89-preview-apis/chart-series.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-find-all.yaml + group: Worksheet api_set: - ExcelAPI: 1.7 -- id: excel-chart-series-markers - name: Chart series markers - fileName: chart-series-markers.yaml - description: Set chart series marker properties + 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////samples/excel/89-preview-apis/chart-series-markers.yaml - group: Preview APIs + 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-chart-trendlines - name: Chart trendlines - fileName: chart-trendlines.yaml - description: 'Add, get, and format trendlines in a chart.' + 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////samples/excel/89-preview-apis/chart-trendlines.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-range-cell.yaml + group: Worksheet api_set: - ExcelAPI: 1.7 -- id: excel-document-properties - name: Document properties - fileName: document-properties.yaml - description: Set and get document properties. + 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////samples/excel/89-preview-apis/document-properties.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/gridlines.yaml + group: Worksheet api_set: - ExcelApi: 1.7 -- id: excel-events-table-changed - name: Events - Table changed - fileName: events-table-changed.yaml - description: Add event handlers for table onDataChanged and onSelectionChanged events + 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////samples/excel/89-preview-apis/events-table-changed.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/list-worksheets.yaml + group: Worksheet api_set: - ExcelApi: 1.7 -- id: excel-events-tablecollection-changed - name: Events - Table collection changed - fileName: events-tablecollection-changed.yaml - description: Add event handlers for table collection onDataChanged event + 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////samples/excel/89-preview-apis/events-tablecollection-changed.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-page-layout.yaml + group: Worksheet api_set: - ExcelApi: 1.7 -- id: excel-events-worksheet-activated - name: Events - Worksheet activated - fileName: events-worksheet-activated.yaml - description: Add event handlers for worksheet onActivated and onDeactivated events + 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////samples/excel/89-preview-apis/events-worksheet-activated.yaml - group: Preview APIs + 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.7 -- id: excel-events-worksheet-changed - name: Events - Worksheet changed - fileName: events-worksheet-changed.yaml - description: Add event handlers for worksheet onDataChanged and onAdded events + 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////samples/excel/89-preview-apis/events-worksheet-changed.yaml - group: Preview APIs + 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-update-named-item - name: Update a named item - fileName: update-named-item.yaml - description: Create and then update a named item + ExcelApi: '1.7' +- id: excel-worksheet-visibility + name: Visibility + fileName: worksheet-visibility.yaml + description: Hides and unhides a worksheet. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/89-preview-apis/update-named-item.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-visibility.yaml + group: Worksheet api_set: - ExcelApi: 1.7 -- id: excel-range-hyperlink - name: Range hyperlink - fileName: range-hyperlink.yaml - description: 'Create, update, and clear a hyperlink for a range.' + 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////samples/excel/89-preview-apis/range-hyperlink.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/performance-optimization.yaml + group: Scenarios api_set: - ExcelApi: 1.7 -- id: excel-range-text-orientation - name: Range text orientation - fileName: range-text-orientation.yaml - description: Set and get the text orientation within a range + 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////samples/excel/89-preview-apis/range-text-orientation.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/report-generation.yaml + group: Scenarios api_set: - ExcelApi: 1.7 -- id: excel-style - name: Style - fileName: style.yaml - description: 'Add, apply, get and delete styles.' + 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////samples/excel/89-preview-apis/style.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/multiple-property-set.yaml + group: Scenarios api_set: - ExcelApi: 1.7 -- id: excel-gridlines - name: Worksheet gridlines - fileName: worksheet-gridlines.yaml - description: Hide and show gridlines in a worksheet + 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////samples/excel/89-preview-apis/worksheet-gridlines.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/working-with-dates.yaml + group: Scenarios api_set: - ExcelAPI: 1.7 -- id: excel-worksheet-tab-color - name: Worksheet tab color - fileName: worksheet-tab-color.yaml - description: Set and get the tab color of a worksheet + 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////samples/excel/89-preview-apis/worksheet-tab-color.yaml - group: Preview APIs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/currency-converter.yaml + group: Scenarios api_set: - ExcelApi: 1.7 -- id: excel-worksheet-freeze-panes - name: Manage frozen panes in a worksheet - fileName: worksheet-freeze-panes.yaml + ExcelApi: '1.4' +- id: excel-just-for-fun-patterns + name: Colorful Patterns + fileName: patterns.yaml description: >- - Freeze columns, freeze rows, freeze a range, and manage frozen panes in a - worksheet. + Uses range formatting to draw interesting pattern. Contributed by Alexander + Zlatkovski. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/89-preview-apis/worksheet-freeze-panes.yaml - group: Preview APIs + 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.7 + ExcelApi: '1.4' - id: excel-just-for-fun-gradient name: Gradient fileName: gradient.yaml @@ -595,32 +1399,30 @@ Uses range formatting and external libraries to draw a colorful gradient within a range. Contributed by Alexander Zlatkovski. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/90-just-for-fun/gradient.yaml + 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.2 -- id: excel-just-for-fun-patterns - name: Colorful Patterns - fileName: patterns.yaml - description: >- - Shows how to use range formatting to draw interesting pattern. Contributed - by Alexander Zlatkovski - rawUrl: >- - https://raw.githubusercontent.com////samples/excel/90-just-for-fun/patterns.yaml - group: Just For Fun - api_set: - ExcelApi: 1.2 + ExcelApi: '1.4' - id: excel-just-for-fun-path-finder-game name: Path finder fileName: path-finder-game.yaml description: >- - Using range formatting to play a "pathfinder game". Contributed by Alexander - Zlatkovski + 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////samples/excel/90-just-for-fun/path-finder-game.yaml + 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.2 + ExcelApi: '1.9' - id: excel-just-for-fun-color-wheel name: Wheel of colors fileName: color-wheel.yaml @@ -628,7 +1430,7 @@ Uses chart formatting to draw a wheel with changing colors. Contributed by Alexander Zlatkovski. rawUrl: >- - https://raw.githubusercontent.com////samples/excel/90-just-for-fun/color-wheel.yaml + 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.1 + ExcelApi: '1.4' diff --git a/playlists/outlook.yaml b/playlists/outlook.yaml index 8c6436a54..557b89f9a 100644 --- a/playlists/outlook.yaml +++ b/playlists/outlook.yaml @@ -1,24 +1,843 @@ -- id: outlook-compose-basics-get-item-subject - name: Get Item Subject - fileName: get-item-subject.yaml - description: Gets the subject of a compose item - rawUrl: >- - https://raw.githubusercontent.com////samples/outlook/01-compose-basics/get-item-subject.yaml - group: Compose Basics - api_set: {} -- id: outlook-compose-basics-get-selected-text - name: Get Selected Text - fileName: get-selected-text.yaml - description: Outputs the text selected from either the body or subject. - rawUrl: >- - https://raw.githubusercontent.com////samples/outlook/01-compose-basics/get-selected-text.yaml - group: Compose Basics - api_set: {} -- id: outlook-compose-basics-set-selected-text - name: Set Selected Text - fileName: set-selected-text.yaml - description: Changes the value of selected text in body or subject. - rawUrl: >- - https://raw.githubusercontent.com////samples/outlook/01-compose-basics/set-selected-text.yaml - group: Compose Basics - api_set: {} +- id: outlook-roaming-settings-roaming-settings + name: Use add-in settings + fileName: roaming-settings.yaml + description: Gets, sets, saves, and removes add-in roaming settings. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/10-roaming-settings/roaming-settings.yaml + group: Roaming Settings + api_set: + Mailbox: '1.1' +- id: outlook-item-custom-properties-load-set-get-save + name: Work with item custom properties + fileName: load-set-get-save.yaml + description: >- + Gets the custom properties that the add-in placed on the current item, sets + a new one, gets it, removes it, and saves all custom properties back to the + item. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + group: Item Custom Properties + api_set: + Mailbox: '1.1' +- id: outlook-item-body-get-selected-data + name: Get selected text (Compose) + fileName: get-selected-data.yaml + description: Gets the selected text in the item body or subject in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/get-selected-data.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-replace-selected-text + name: Replace selected text in item body + fileName: replace-selected-text.yaml + description: >- + Replaces selected text in a message or appointment's body with specified + text. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/replace-selected-text.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-add-inline-base64-image + name: Add inline Base64-encoded image to message or appointment body (Compose) + fileName: add-inline-base64-image.yaml + description: >- + Add an inline Base64-encoded image to the body of a message or appointment + being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/add-inline-base64-image.yaml + group: Item Body + api_set: + Mailbox: '1.8' +- id: outlook-item-body-get-body-format + name: Get the item's body format + fileName: get-body-format.yaml + description: Gets a message or appointment's body format (plain text or HTML). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/get-body-format.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-append-text-on-send + name: Append text to item body on send + fileName: append-text-on-send.yaml + description: Appends text to the end of the message or appointment's body once it's sent. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/append-text-on-send.yaml + group: Item Body + api_set: + Mailbox: '1.9' +- id: outlook-item-body-prepend-text-to-item-body + name: Prepend text to item body + fileName: prepend-text-to-item-body.yaml + description: Adds text to the beginning of the message or appointment's body. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/prepend-text-to-item-body.yaml + group: Item Body + api_set: + Mailbox: '1.1' +- id: outlook-item-body-prepend-text-on-send + name: Prepend text to item body on send + fileName: prepend-text-on-send.yaml + description: >- + Prepends text to the beginning of the message or appointment's body once + it's sent. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/prepend-text-on-send.yaml + group: Item Body + api_set: + Mailbox: '1.13' +- id: outlook-item-save-and-close-close + name: Close the item + fileName: close.yaml + description: Closes the item (compose mode) + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/close.yaml + group: Item Save And Close + api_set: + Mailbox: '1.3' +- id: outlook-close-async + name: Close the current message and discard changes (Message Compose) + fileName: close-async.yaml + description: Closes the current message and discards any unsaved changes when specified. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/close-async.yaml + group: Item Save And Close + api_set: + Mailbox: '1.14' +- id: outlook-item-save-and-close-save + name: Save the item + fileName: save.yaml + description: Saves the item (compose mode) + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/save.yaml + group: Item Save And Close + api_set: + Mailbox: '1.3' +- id: outlook-recipients-and-attendees-get-from-message-read + name: Get from (Message Read) + fileName: get-from-message-read.yaml + description: Gets who the message is from in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-from-message-compose + name: Get from (Message Compose) + fileName: get-from-message-compose.yaml + description: Gets who the message is from in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-recipients-and-attendees-get-to-message-read + name: Get to (Message Read) + fileName: get-to-message-read.yaml + description: Gets the To line recipients of the message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-to-message-compose + name: Get and set to (Message Compose) + fileName: get-set-to-message-compose.yaml + description: Gets and sets the To line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-cc-message-read + name: Get cc (Message Read) + fileName: get-cc-message-read.yaml + description: Gets the Cc line recipients of the message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-cc-message-compose + name: Get and set cc (Message Compose) + fileName: get-set-cc-message-compose.yaml + description: Gets and sets the Cc line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-set-bcc-message-compose + name: Get and set bcc (Message Compose) + fileName: get-set-bcc-message-compose.yaml + description: Gets and sets the Bcc line recipients of the message in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-sender-message-read + name: Get sender (Message Read) + fileName: get-sender-message-read.yaml + description: Gets the sender in Message Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-required-attendees-appointment-attendee + name: Get required attendees (Appointment Attendee) + fileName: get-required-attendees-appointment-attendee.yaml + description: Gets the required attendees in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: >- + outlook-recipients-and-attendees-get-set-required-attendees-appointment-organizer + name: Get and set required attendees (Appointment Organizer) + fileName: get-set-required-attendees-appointment-organizer.yaml + description: Gets and sets the required attendees in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-optional-attendees-appointment-attendee + name: Get optional attendees (Appointment Attendee) + fileName: get-optional-attendees-appointment-attendee.yaml + description: Gets the optional attendees in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: >- + outlook-recipients-and-attendees-get-set-optional-attendees-appointment-organizer + name: Get and set optional attendees (Appointment Organizer) + fileName: get-set-optional-attendees-appointment-organizer.yaml + description: Gets and sets the optional attendees in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-organizer-appointment-attendee + name: Get organizer (Appointment Attendee) + fileName: get-organizer-appointment-attendee.yaml + description: Gets the organizer in Appointment Attendee mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.1' +- id: outlook-recipients-and-attendees-get-organizer-appointment-organizer + name: Get organizer (Appointment Organizer) + fileName: get-organizer-appointment-organizer.yaml + description: Gets the organizer in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-recipients-and-attendees-get-all-attendees + name: Get all attendees + fileName: get-all-attendees.yaml + description: Gets all appointment attendees and organizes them by their response. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml + group: Recipients And Attendees + api_set: + Mailbox: '1.7' +- id: outlook-notifications-add-getall-remove + name: Work with notification messages + fileName: add-getall-remove.yaml + description: >- + Adds different kinds of notification messages, gets all notifications, and + replaces and removes an individual notification message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/35-notifications/add-getall-remove.yaml + group: Notifications + api_set: + Mailbox: '1.10' +- id: outlook-attachments-attachments-compose + name: Manipulate attachments (Item Compose) + fileName: attachments-compose.yaml + description: >- + Adds, gets, and removes attachments from a message or an appointment in + Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/attachments-compose.yaml + group: Attachments + api_set: + Mailbox: '1.8' +- id: outlook-attachments-get-attachment-content + name: Get attachment content + fileName: get-attachment-content.yaml + description: Gets the attachment content in read or compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/get-attachment-content.yaml + group: Attachments + api_set: + Mailbox: '1.8' +- id: outlook-attachments-get-attachments-read + name: Get attachments (Item Read) + fileName: get-attachments-read.yaml + description: Gets the attachments of a message or an appointment in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/get-attachments-read.yaml + group: Attachments + api_set: + Mailbox: '1.1' +- id: outlook-categories-work-with-categories + name: Work with item categories + fileName: work-with-categories.yaml + description: Gets, adds, and removes categories assigned to the item. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/45-categories/work-with-categories.yaml + group: Categories + api_set: + Mailbox: '1.8' +- id: outlook-categories-work-with-master-categories + name: Work with the categories master list + fileName: work-with-master-categories.yaml + description: Gets, adds, and removes categories in the master list for the mailbox. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/45-categories/work-with-master-categories.yaml + group: Categories + api_set: + Mailbox: '1.8' +- id: outlook-recurrence-get-series-id + name: Get the series ID + fileName: get-series-id.yaml + description: Gets the series ID. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-series-id.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-recurrence-get-recurrence-read + name: Get recurrence (Read) + fileName: get-recurrence-read.yaml + description: Gets the recurrence pattern of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-recurrence-read.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-recurrence-get-set-recurrence-appointment-organizer + name: Get and set recurrence (Appointment Organizer) + fileName: get-set-recurrence-appointment-organizer.yaml + description: Gets and sets the recurrence pattern in Appointment Organizer mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + group: Recurrence + api_set: + Mailbox: '1.7' +- id: outlook-display-items-display-new-message + name: Create a new message + fileName: display-new-message.yaml + description: >- + Opens a new message form with a sample content, recipients, and an inline + image attachment + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-new-message.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-new-appointment + name: Create a new appointment + fileName: display-new-appointment.yaml + description: Opens a new appointment form with sample content and a few fields populated. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-new-appointment.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-existing-message + name: Open a message + fileName: display-existing-message.yaml + description: Displays an existing message in a separate window + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-existing-message.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-existing-appointment + name: Open an appointment + fileName: display-existing-appointment.yaml + description: Displays existing appointment in a separate window + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-existing-appointment.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-reply-forms + name: Create replies + fileName: display-reply-forms.yaml + description: Opens reply and reply-all message forms with sample reply content. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-reply-forms.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-display-items-display-reply-with-attachments + name: Create a reply with attachments + fileName: display-reply-with-attachments.yaml + description: Opens a reply or reply-all message form and adds sample attachments. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-reply-with-attachments.yaml + group: Display Items + api_set: + Mailbox: '1.9' +- id: outlook-sensitivity-labels-sensitivity-labels-catalog + name: Work with the sensitivity labels catalog + fileName: sensitivity-labels-catalog.yaml + description: >- + Determines if sensitivity labels are enabled on the mailbox and retrieves + all available labels from the catalog. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml + group: Sensitivity Label + api_set: + Mailbox: '1.13' +- id: outlook-sensitivity-labels-sensitivity-label + name: Work with sensitivity labels (Compose) + fileName: sensitivity-label.yaml + description: >- + Gets and sets the sensitivity label on a message or appointment in compose + mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + group: Sensitivity Label + api_set: + Mailbox: '1.13' +- id: outlook-delegates-and-shared-folders-get-shared-properties + name: Identify a shared folder or shared mailbox context + fileName: get-shared-properties.yaml + description: >- + Identifies whether the current mail item is in a shared folder or shared + mailbox by getting its properties. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + group: Delegates And Shared Folders + api_set: + Mailbox: '1.13' +- id: outlook-mime-headers-get-internet-headers-message-read + name: Get internet headers + fileName: get-internet-headers-message-read.yaml + description: Gets internet headers on a message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml + group: Mime Headers + api_set: + Mailbox: '1.8' +- id: outlook-mime-headers-manage-custom-internet-headers-message-compose + name: Work with custom internet headers + fileName: manage-custom-internet-headers-message-compose.yaml + description: >- + Sets, gets, and removes custom internet headers on a message in Compose + mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + group: Mime Headers + api_set: + Mailbox: '1.8' +- id: outlook-regex-matches-contextual + name: Get regex matches (Item Read, contextual) + fileName: contextual.yaml + description: Gets regex matches when the add-in is opened as a contextual add-in. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/75-regex-matches/contextual.yaml + group: Regex Matches + api_set: + Mailbox: '1.6' +- id: outlook-events-drag-drop-item + name: Drag and drop an item into the task pane + fileName: drag-drop-item.yaml + description: >- + Handles the drag-and-drop event when a user drags and drops messages and + file attachments into the add-in task pane. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/80-events/drag-drop-item.yaml + group: Events + api_set: + Mailbox: '1.5' +- id: outlook-tokens-and-service-calls-ids-and-urls + name: Endpoint URLs and item IDs in Exchange on-premises environments + fileName: ids-and-urls.yaml + description: >- + Retrieves the Exchange Web Services (EWS) endpoint URL and item IDs and + converts item IDs for different protocols. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.5' +- id: outlook-tokens-and-service-calls-user-identity-token + name: Get a user identity token in Exchange on-premises environments + fileName: user-identity-token.yaml + description: >- + Gets a user identity token for authentication flows in an Exchange + on-premises environment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-user-callback-token + name: Get a callback token in Exchange on-premises environments + fileName: user-callback-token.yaml + description: >- + Gets a callback token to call Outlook services from an add-in's backend + service in an Exchange on-premises environment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-make-ews-request-async + name: >- + Get a message using Exchange Web Services (EWS) in Exchange on-premises + environments + fileName: make-ews-request-async.yaml + description: >- + Uses EWS in an Exchange on-premises environment to get a message without any + backend code. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-send-message-using-make-ews-request-async + name: >- + Send a message using Exchange Web Services (EWS) in Exchange on-premises + environments + fileName: send-message-using-make-ews-request-async.yaml + description: >- + Uses EWS in an Exchange on-premises environment to send a message without + any backend code. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-tokens-and-service-calls-get-icaluid-as-organizer + name: Get an appointment's iCalUId as the organizer (Exchange on-premises only) + fileName: get-icaluid-as-organizer.yaml + description: >- + Uses Exchange Web Services (EWS) in an Exchange on-premises environment to + get an appointment's iCalUId value where the user is the organizer. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.3' +- id: outlook-tokens-and-service-calls-get-icaluid-as-attendee + name: Get an appointment's iCalUId as an attendee (Exchange on-premises only) + fileName: get-icaluid-as-attendee.yaml + description: >- + Uses Exchange Web Services (EWS) in an Exchange on-premises environment to + get an appointment's iCalUId value where the user is an attendee. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml + group: Tokens For Exchange On-Premises + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-subject-read + name: Get the subject (Read) + fileName: get-subject-read.yaml + description: Gets the subject of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-subject-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-subject-compose + name: Get and set the subject (Compose) + fileName: get-set-subject-compose.yaml + description: Gets and sets the subject of an item in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-item-body-set-selected-data + name: Replace selected text in item body or subject (Compose) + fileName: set-selected-data.yaml + description: Replaces the selected text in the item body or subject in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/set-selected-data.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-internet-message-id-read + name: Get the internet message ID (Message Read) + fileName: get-internet-message-id-read.yaml + description: Gets the internet message ID of a message in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-item-class-read + name: Get the item class (Read) + fileName: get-item-class-read.yaml + description: Gets the item class of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-class-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-item-type + name: Get the item type + fileName: get-item-type.yaml + description: Gets the item type. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-type.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-start-read + name: Get the start date and time (Read) + fileName: get-start-read.yaml + description: Gets the start date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-start-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-start-appointment-organizer + name: Get and set the start date and time (Appointment Organizer) + fileName: get-set-start-appointment-organizer.yaml + description: Gets and sets the start date and time of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-end-read + name: Get the end date and time (Read) + fileName: get-end-read.yaml + description: Gets the end date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-end-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-end-appointment-organizer + name: Get and set the end date and time (Appointment Organizer) + fileName: get-set-end-appointment-organizer.yaml + description: Gets and sets the end date and time of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-location-read + name: Get the location (Read) + fileName: get-location-read.yaml + description: Gets the location of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-location-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-set-location-appointment-organizer + name: Get and set the location (Appointment Organizer) + fileName: get-set-location-appointment-organizer.yaml + description: Gets and sets the location of an appointment in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-add-remove-enhancedlocation-appointment + name: Manage the locations of an appointment + fileName: get-add-remove-enhancedlocation-appointment.yaml + description: Gets, adds, and removes locations on an appointment (enhancedLocation API). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + group: Other Item APIs + api_set: + Mailbox: '1.8' +- id: outlook-other-item-apis-get-normalized-subject-read + name: Get the normalized subject (Read) + fileName: get-normalized-subject-read.yaml + description: Gets the normalized subject of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-conversation-id-message + name: Get the conversation ID (Message) + fileName: get-conversation-id-message.yaml + description: Gets the conversation ID of a message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-date-time-created-read + name: Get the creation date and time (Read) + fileName: get-date-time-created-read.yaml + description: Gets the creation date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-date-time-modified-read + name: Get the last-modified date and time (Read) + fileName: get-date-time-modified-read.yaml + description: Gets the last-modified date and time of an item in Read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-get-diagnostic-information + name: Get mailbox diagnostic information + fileName: get-diagnostic-information.yaml + description: Gets a mailbox's diagnostic information. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml + group: Other Item APIs + api_set: + Mailbox: '1.1' +- id: outlook-other-item-apis-work-with-client-signatures + name: Work with client signatures (Compose) + fileName: work-with-client-signatures.yaml + description: >- + Checks if the client signature is enabled, disables the client signature, + gets the compose type, and sets a signature in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + group: Other Item APIs + api_set: + Mailbox: '1.10' +- id: outlook-other-item-apis-session-data-apis + name: Work with session data APIs (Compose) + fileName: session-data-apis.yaml + description: Sets, gets, gets all, removes, and clears session data in Compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/session-data-apis.yaml + group: Other Item APIs + api_set: + Mailbox: '1.11' +- id: outlook-delay-message-delivery + name: Get and set message delivery (Message Compose) + fileName: delay-message-delivery.yaml + description: Gets and sets the delivery date and time of a message in compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/delay-message-delivery.yaml + group: Other Item APIs + api_set: + Mailbox: '1.13' +- id: outlook-other-item-apis-get-message-properties + name: Get properties of selected messages (Message Compose, Message Read) + fileName: get-message-properties.yaml + description: Gets the properties of multiple selected messages. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-message-properties.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-other-item-apis-get-set-sensitivity-level + name: Get and set the sensitivity level (Appointment Organizer) + fileName: get-set-sensitivity-level.yaml + description: Gets and sets the sensitivity level of an appointment being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-eml-format + name: Get the Base64-encoded EML format of a message (Message Read) + fileName: get-eml-format.yaml + description: Gets the Base64-encoded EML format of a message in read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-eml-format.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-in-reply-to + name: Get the ID of the message being replied to (Message Compose) + fileName: get-in-reply-to.yaml + description: Retrieves the ID of the message being replied to by the current message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-in-reply-to.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-conversation-index + name: Get the position of a message in a conversation (Message Compose) + fileName: get-conversation-index.yaml + description: >- + Retrieves the Base64-encoded position of the current message in a + conversation thread. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-conversation-index.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-get-item-class-async + name: Get item class (Message Compose) + fileName: get-item-class-async.yaml + description: Retrieves the item class property of the message being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-class-async.yaml + group: Other Item APIs + api_set: + Mailbox: '1.14' +- id: outlook-other-item-apis-item-id-compose + name: Get an item ID in compose mode + fileName: item-id-compose.yaml + description: Gets an item ID in compose mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/item-id-compose.yaml + group: Other Item APIs + api_set: + Mailbox: '1.8' +- id: outlook-send-async + name: Send the current message or appointment (Compose) + fileName: send-async.yaml + description: Sends the current message or appointment. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/send-async.yaml + group: Other Item APIs + api_set: + Mailbox: '1.15' +- id: outlook-other-item-apis-get-loaded-message-properties + name: Get properties of a loaded message (Message Compose, Message Read) + fileName: get-loaded-message-properties.yaml + description: Gets the properties of the currently loaded message. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml + group: Other Item APIs + api_set: + Mailbox: '1.15' +- id: outlook-get-set-isalldayevent + name: Get and set the isAllDayEvent property (Appointment Organizer) + fileName: get-set-isalldayevent.yaml + description: Gets and sets the isAllDayEvent property of an appointment being composed. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + group: Preview APIs + api_set: + Mailbox: preview +- id: outlook-set-displayed-body-subject + name: Temporarily set the body or subject displayed in a message (Message Read) + fileName: set-displayed-body-subject.yaml + description: >- + Temporarily sets the content displayed in the body or subject of a message + in read mode. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + group: Preview APIs + api_set: + Mailbox: preview diff --git a/playlists/powerpoint.yaml b/playlists/powerpoint.yaml index ca8001efd..46985f3bc 100644 --- a/playlists/powerpoint.yaml +++ b/playlists/powerpoint.yaml @@ -1,19 +1,21 @@ -- id: powerpoint-basics-get-slide-metadata - name: Get slide metadata - fileName: get-slide-metadata.yaml - description: 'Gets the title, index, and ID of the selected slide(s).' +- id: powerpoint-basics-basic-api-call-ts + name: Basic API call (TypeScript) + fileName: basic-api-call-ts.yaml + description: Performs a basic PowerPoint API call using TypeScript. rawUrl: >- - https://raw.githubusercontent.com////samples/powerpoint/basics/get-slide-metadata.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-api-call-ts.yaml group: Basics - api_set: {} -- id: powerpoint-basics-insert-image - name: Insert Image - fileName: insert-image.yaml - description: Inserts an image to the current slide. + api_set: + PowerPointApi: '1.4' +- id: powerpoint-basics-basic-api-call-js + name: Basic API call (JavaScript) + fileName: basic-api-call-js.yaml + description: Performs a basic PowerPoint API call using JavaScript. rawUrl: >- - https://raw.githubusercontent.com////samples/powerpoint/basics/insert-image.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-api-call-js.yaml group: Basics - api_set: {} + api_set: + PowerPointApi: '1.4' - id: powerpoint-basics-basic-common-api-call name: Basic API call (Office 2013) fileName: basic-common-api-call.yaml @@ -21,7 +23,167 @@ Executes a basic PowerPoint API call using the "common API" syntax (compatible with Office 2013). rawUrl: >- - https://raw.githubusercontent.com////samples/powerpoint/basics/basic-common-api-call.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-common-api-call.yaml group: Basics api_set: - Selection: 1.1 + Selection: '1.1' +- id: powerpoint-create-presentation + name: Create presentation + fileName: create-presentation.yaml + description: >- + Creates a new, empty presentation and creates a new presentation by copying + an existing one. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/document/create-presentation.yaml + group: Document + api_set: + PowerPointApi: '1.1' +- id: powerpoint-hyperlinks-manage-hyperlinks + name: Get hyperlinks + fileName: manage-hyperlinks.yaml + description: Gets the hyperlinks found in a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml + group: Hyperlinks + api_set: + PowerPointApi: '1.6' +- id: powerpoint-basics-insert-image + name: Insert Image + fileName: insert-image.yaml + description: Inserts an image to the current slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/images/insert-image.yaml + group: Images + api_set: {} +- id: powerpoint-basics-insert-svg + name: Insert SVG + fileName: insert-svg.yaml + description: Inserts an SVG image using an XML string. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/images/insert-svg.yaml + group: Images + api_set: {} +- id: powerpoint-scenarios-searches-wikipedia-api + name: Search Wikipedia + fileName: searches-wikipedia-api.yaml + description: Searches Wikipedia based on the selected text in the presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/scenarios/searches-wikipedia-api.yaml + group: Scenarios + api_set: {} +- id: powerpoint-shapes + name: Insert shape, line, and text box + fileName: shapes.yaml + description: Inserts geometric shapes, lines, and text boxes to a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.4' +- id: powerpoint-shapes-get-set-shapes + name: Get, set, load, and save shapes + fileName: get-set-shapes.yaml + description: Get and set one or more selected shapes. Load and save one or more shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/get-set-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.5' +- id: powerpoint-shapes-get-shapes-by-type + name: Select shapes by type + fileName: get-shapes-by-type.yaml + description: Gets shapes in a slide based on their type, such as GeometricShape or Line. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/get-shapes-by-type.yaml + group: Shapes + api_set: + PowerPointApi: '1.4' +- id: powerpoint-shapes-add-modify-tables + name: Add and modify tables + fileName: add-modify-tables.yaml + description: Shows how to add and modify tables in a presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/add-modify-tables.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-shapes-binding-to-shapes + name: Binding to shapes + fileName: binding-to-shapes.yaml + description: Shows how to create binding references for images and work with z-order. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/binding-to-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-shapes-group-ungroup-shapes + name: Group and ungroup shapes + fileName: group-ungroup-shapes.yaml + description: Shows how to create two shapes then group and ungroup them. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/group-ungroup-shapes.yaml + group: Shapes + api_set: + PowerPointApi: '1.8' +- id: powerpoint-add-slides + name: Add slides to a presentation + fileName: add-slides.yaml + description: Adds a slide and optionally specifies the slide master and layout. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/add-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.3' +- id: powerpoint-insert-slides + name: Insert slides from other presentation + fileName: insert-slides.yaml + description: Inserts slides from another PowerPoint file into the current presentation. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/insert-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.5' +- id: powerpoint-basics-get-slide-metadata + name: Get slide metadata + fileName: get-slide-metadata.yaml + description: Gets the title, index, and ID of the selected slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/get-slide-metadata.yaml + group: Slide Management + api_set: {} +- id: powerpoint-slide-management-get-set-slides + name: Get, set, load, and save slides + fileName: get-set-slides.yaml + description: Get and set one or more selected slides. Load and save one or more slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/get-set-slides.yaml + group: Slide Management + api_set: + PowerPointApi: '1.5' +- id: powerpoint-slide-management-export-import-slide + name: Export and import slide + fileName: export-import-slide.yaml + description: Shows how to export and import a slide. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/export-import-slide.yaml + group: Slide Management + api_set: + PowerPointApi: '1.8' +- id: powerpoint-tags + name: Work with tags + fileName: tags.yaml + description: Use tags to process subsets of slides. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/tags/tags.yaml + group: Tags + api_set: + PowerPointApi: '1.3' +- id: powerpoint-text-get-set-textrange + name: Work with text range selections + fileName: get-set-textrange.yaml + description: Get, set, load, and save text range selections. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/text/get-set-textrange.yaml + group: Text + api_set: + PowerPointApi: '1.8' diff --git a/playlists/project.yaml b/playlists/project.yaml index 165ac7d8c..a28427026 100644 --- a/playlists/project.yaml +++ b/playlists/project.yaml @@ -5,7 +5,7 @@ Executes a basic Project API call using the "common API" syntax (compatible with Office 2013). rawUrl: >- - https://raw.githubusercontent.com////samples/project/basics/basic-common-api-call.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/project/basics/basic-common-api-call.yaml group: Basics api_set: Selection: 1.1 diff --git a/playlists/word.yaml b/playlists/word.yaml index 00ca85c66..d36dd59b1 100644 --- a/playlists/word.yaml +++ b/playlists/word.yaml @@ -1,199 +1,638 @@ - id: word-basics-basic-api-call - name: Basic API call + name: Basic API call (TypeScript) fileName: basic-api-call.yaml - description: Executes a basic Word API call using TypeScript. + description: Performs a basic Word API call using TypeScript. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/basic-api-call.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-api-call.yaml group: Basics api_set: - WordApi: 1.1 -- id: word-basic-api-call-es5 + WordApi: '1.1' +- id: word-basics-api-call-es5 name: Basic API call (JavaScript) fileName: basic-api-call-es5.yaml description: Performs a basic Word API call using plain JavaScript & Promises. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/basic-api-call-es5.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-api-call-es5.yaml group: Basics api_set: - WordApi: 1.1 -- id: word-basics-basic-doc-assembly - name: Basic document assembly - fileName: basic-doc-assembly.yaml - description: Basic document assembly capabilities of the Word JavaScript API. + WordApi: '1.1' +- id: word-basics-basic-common-api-call + name: Basic API call (Office 2013) + fileName: basic-common-api-call.yaml + description: >- + Performs a basic Word API call using JavaScript with the "common API" syntax + (compatible with Office 2013). rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/basic-doc-assembly.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-common-api-call.yaml group: Basics api_set: - WordApi: 1.1 -- id: word-basics-insert-and-get-pictures - name: Inline pictures + Selection: 1.1 +- id: word-content-controls-insert-and-change-content-controls + name: Content control basics + fileName: insert-and-change-content-controls.yaml + description: Inserts, updates, and retrieves content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-content-controls.yaml + group: Content Controls + api_set: + WordApi: '1.1' +- id: word-content-controls-content-control-onadded-event + name: On adding content controls + fileName: content-control-onadded-event.yaml + description: >- + Registers, triggers, and deregisters onAdded event that tracks the addition + of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onadded-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onentered-event + name: On entering content controls + fileName: content-control-onentered-event.yaml + description: >- + Registers, triggers, and deregisters onEntered event that tracks when the + cursor is placed within content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onentered-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onselectionchanged-event + name: On changing selection in content controls + fileName: content-control-onselectionchanged-event.yaml + description: >- + Registers, triggers, and deregisters onSelectionChanged event that tracks + when selections are changed in content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-ondatachanged-event + name: On changing data in content controls + fileName: content-control-ondatachanged-event.yaml + description: >- + Registers, triggers, and deregisters onDataChanged event that tracks when + data is changed in content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-onexited-event + name: On exiting content controls + fileName: content-control-onexited-event.yaml + description: >- + Registers, triggers, and deregisters onExited event that tracks when the + cursor is removed from within content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onexited-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-content-control-ondeleted-event + name: On deleting content controls + fileName: content-control-ondeleted-event.yaml + description: >- + Registers, triggers, and deregisters onDeleted event that tracks the removal + of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-ondeleted-event.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-content-controls-insert-and-change-checkbox-content-control + name: Manage checkbox content controls + fileName: insert-and-change-checkbox-content-control.yaml + description: Inserts, updates, retrieves, and deletes checkbox content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.7' +- id: word-content-controls-insert-and-change-combo-box-content-control + name: Manage combo box content controls + fileName: insert-and-change-combo-box-content-control.yaml + description: Inserts, updates, and deletes combo box content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.9' +- id: word-content-controls-insert-and-change-dropdown-list-content-control + name: Manage dropdown list content controls + fileName: insert-and-change-dropdown-list-content-control.yaml + description: Inserts, updates, and deletes dropdown list content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + group: Content Controls + api_set: + WordApi: '1.9' +- id: word-content-controls-get-change-tracking-states + name: Get change tracking states of content controls + fileName: get-change-tracking-states.yaml + description: Gets change tracking states of content controls. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/get-change-tracking-states.yaml + group: Content Controls + api_set: + WordApi: '1.5' +- id: word-images-insert-and-get-pictures + name: Use inline pictures fileName: insert-and-get-pictures.yaml - description: Shows how to insert and get inline pictures. + description: Inserts and gets inline pictures. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/insert-and-get-pictures.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/15-images/insert-and-get-pictures.yaml + group: Images api_set: - WordApi: 1.1 -- id: word-basics-insert-formatted-text - name: Insert formatted text - fileName: insert-formatted-text.yaml - description: Shows how to use formatting objects as well as applying pre-built styles. + WordApiDesktop: '1.1' +- id: word-lists-insert-list + name: Create a list + fileName: insert-list.yaml + description: Inserts a new list into the document. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/insert-formatted-text.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/insert-list.yaml + group: Lists api_set: - WordApi: 1.1 -- id: word-basics-insert-header - name: Insert header - fileName: insert-header.yaml - description: Demonstrates how to insert a header in the document. + WordApi: '1.3' +- id: word-lists-manage-styles + name: Get list styles + fileName: manage-list-styles.yaml + description: This sample shows how to get the list styles in the current document. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/insert-header.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/manage-list-styles.yaml + group: Lists + api_set: + WordApiDesktop: '1.1' +- id: word-lists-organize-list + name: Organize a list + fileName: organize-list.yaml + description: Shows how to create and organize a list. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/organize-list.yaml + group: Lists api_set: - WordApi: 1.1 -- id: word-basics-insert-line-and-page-breaks + WordApi: '1.3' +- id: word-paragraph-get-paragraph-on-insertion-point + name: Get paragraph from insertion point + fileName: get-paragraph-on-insertion-point.yaml + description: Gets the full paragraph containing the insertion point. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-insert-line-and-page-breaks name: Insert breaks fileName: insert-line-and-page-breaks.yaml - description: Shows how to insert page and line breaks in a document. + description: Inserts page and line breaks in a document. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/insert-line-and-page-breaks.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-line-and-page-breaks.yaml + group: Paragraph api_set: - WordApi: 1.1 -- id: word-basics-search + WordApi: '1.2' +- id: word-paragraph-insert-in-different-locations + name: Insert content at different locations + fileName: insert-in-different-locations.yaml + description: Inserts content at different document locations. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-in-different-locations.yaml + group: Paragraph + api_set: + WordApi: '1.2' +- id: word-paragraph-insert-formatted-text + name: Insert formatted text + fileName: insert-formatted-text.yaml + description: Formats text with pre-built and custom styles. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-formatted-text.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-insert-header-and-footer + name: Insert headers and footers + fileName: insert-header-and-footer.yaml + description: Inserts headers and footers in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-header-and-footer.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-paragraph-properties + name: Paragraph properties + fileName: paragraph-properties.yaml + description: Sets indentation, space between paragraphs, and other paragraph properties. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/paragraph-properties.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-search name: Search fileName: search.yaml description: Shows basic and advanced search capabilities. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/search.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/search.yaml + group: Paragraph api_set: - WordApi: 1.1 -- id: word-basics-basic-common-api-call - name: Basic API call (Office 2013) - fileName: basic-common-api-call.yaml + WordApi: '1.1' +- id: word-paragraph-get-word-count + name: Get word count + fileName: get-word-count.yaml + description: Counts how many times a word or term appears in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-word-count.yaml + group: Paragraph + api_set: + WordApi: '1.1' +- id: word-paragraph-get-text + name: Get text + fileName: get-text.yaml description: >- - Executes a basic Word API call using the "common API" syntax (compatible - with Office 2013). + Shows how to get paragraph text, including hidden text and text marked for + deletion. rawUrl: >- - https://raw.githubusercontent.com////samples/word/01-basics/basic-common-api-call.yaml - group: Basics + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-text.yaml + group: Paragraph api_set: - Selection: 1.1 -- id: word-basics-insert-in-different-locations - name: Insert locations. - fileName: insert-in-different-locations.yaml - description: Shows how to insert content using the different available locations. + WordApi: '1.7' +- id: word-paragraph-onadded-event + name: On adding paragraphs + fileName: onadded-event.yaml + description: >- + Registers, triggers, and deregisters the onParagraphAdded event that tracks + the addition of paragraphs. rawUrl: >- - https://raw.githubusercontent.com////samples/word/02-paragraphs/insert-in-different-locations.yaml - group: Paragraphs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/onadded-event.yaml + group: Paragraph api_set: - WordApi: 1.1 -- id: word-paragraphs-get-paragraph-on-insertion-point - name: Get paragraph from insertion point - fileName: get-paragraph-on-insertion-point.yaml - description: Gets the full paragraph containing the insertion point. + WordApi: '1.6' +- id: word-paragraph-onchanged-event + name: On changing content in paragraphs + fileName: onchanged-event.yaml + description: >- + Registers, triggers, and deregisters the onParagraphChanged event that + tracks when content is changed in paragraphs. rawUrl: >- - https://raw.githubusercontent.com////samples/word/02-paragraphs/get-paragraph-on-insertion-point.yaml - group: Paragraphs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/onchanged-event.yaml + group: Paragraph api_set: - WordApi: 1.1 -- id: word-paragraphs-paragraph-properties - name: Paragraph properties - fileName: paragraph-properties.yaml + WordApi: '1.6' +- id: word-paragraph-ondeleted-event + name: On deleting paragraphs + fileName: ondeleted-event.yaml description: >- - Shows how to set indentation, space between paragraphs and other paragraph - properties. + Registers, triggers, and deregisters the onParagraphDeleted event that + tracks the removal of paragraphs. rawUrl: >- - https://raw.githubusercontent.com////samples/word/02-paragraphs/paragraph-properties.yaml - group: Paragraphs + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/ondeleted-event.yaml + group: Paragraph api_set: - WordApi: 1.1 -- id: word-content-controls-insert-and-change-content-controls - name: Content control basics - fileName: insert-and-change-content-controls.yaml - description: 'Insertion, manipulation and retrieval of content controls.' + WordApi: '1.6' +- id: word-properties-get-built-in-properties + name: Built-in document properties + fileName: get-built-in-properties.yaml + description: Gets built-in document properties. rawUrl: >- - https://raw.githubusercontent.com////samples/word/03-content-controls/insert-and-change-content-controls.yaml - group: Content Controls + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/30-properties/get-built-in-properties.yaml + group: Properties + api_set: + WordApi: '1.1' +- id: word-properties-read-write-custom-document-properties + name: Custom document properties + fileName: read-write-custom-document-properties.yaml + description: Adds and reads custom document properties of different types. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/30-properties/read-write-custom-document-properties.yaml + group: Properties api_set: - WordApi: 1.1 -- id: word-basics-scroll-to-range - name: Scroll to range + WordApi: '1.3' +- id: word-ranges-scroll-to-range + name: Scroll to a range fileName: scroll-to-range.yaml - description: Shows how to scroll to a range with and without selection. + description: Scrolls to a range with and without selection. rawUrl: >- - https://raw.githubusercontent.com////samples/word/04-range/scroll-to-range.yaml - group: Range + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/scroll-to-range.yaml + group: Ranges api_set: - WordApi: 1.1 -- id: word-range-split-words-of-first-paragraph - name: Range manipulation + WordApi: '1.2' +- id: word-ranges-split-words-of-first-paragraph + name: Split a paragraph into ranges fileName: split-words-of-first-paragraph.yaml description: >- - Show how to split a paragraph into word ranges and then traverses all the - ranges to format each word, producing a "karaoke" effect. + Splits a paragraph into word ranges and then traverses all the ranges to + format each word, producing a "karaoke" effect. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/split-words-of-first-paragraph.yaml + group: Ranges + api_set: + WordApi: '1.3' +- id: word-ranges-compare-location + name: Compare range locations + fileName: compare-location.yaml + description: This sample shows how to compare the locations of two ranges. rawUrl: >- - https://raw.githubusercontent.com////samples/word/04-range/split-words-of-first-paragraph.yaml - group: Range + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/compare-location.yaml + group: Ranges api_set: - WordApi: 1.1 + WordApi: '1.3' +- id: word-ranges-get-pages + name: Work with pages, panes, and windows + fileName: get-pages.yaml + description: Shows how to work with pages, panes, and windows. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/get-pages.yaml + group: Ranges + api_set: + WordApiDesktop: '1.2' - id: word-tables-table-cell-access - name: Table cell access + name: Create and access a table fileName: table-cell-access.yaml - description: Shows how to access a specific cell in a table. + description: Creates a table and accesses a specific cell. rawUrl: >- - https://raw.githubusercontent.com////samples/word/05-tables/table-cell-access.yaml + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/table-cell-access.yaml group: Tables api_set: - WordApi: 1.1 -- id: word-lists-insert-list - name: List creation - fileName: insert-list.yaml - description: Inserts a new list into the document. + WordApi: '1.3' +- id: word-tables-manage-formatting + name: Table formatting + fileName: manage-formatting.yaml + description: >- + Gets the formatting details of a table, a table row, and a table cell, + including borders, alignment, and cell padding. rawUrl: >- - https://raw.githubusercontent.com////samples/word/06-lists/insert-list.yaml - group: Lists + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/manage-formatting.yaml + group: Tables api_set: - WordApi: 1.1 -- id: word-basics-read-write-custom-document-properties - name: Read-write custom document properties - fileName: read-write-custom-document-properties.yaml + WordApi: '1.3' +- id: word-tables-manage-custom-style + name: Manage custom table style + fileName: manage-custom-style.yaml description: >- - This sample shows how to add custom document properties of different types - and how to read them as well. + Shows how to manage primarily margins and alignments of a custom table style + in the current document. rawUrl: >- - https://raw.githubusercontent.com////samples/word/07-custom-properties/read-write-custom-document-properties.yaml - group: Custom Properties + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/manage-custom-style.yaml + group: Tables api_set: - WordApi: 1.1 -- id: word-custom-properties-get-built-in-properties - name: Get built-in document properties. - fileName: get-built-in-properties.yaml - description: Shows how to get built-in document properties. + WordApiDesktop: '1.1' +- id: word-shapes-manage-shapes-text-boxes + name: Work with shapes and text boxes + fileName: manage-shapes-text-boxes.yaml + description: Shows how to work with shapes and text boxes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-shapes-text-boxes.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-manage-geometric-shapes + name: Manage geometric shapes + fileName: manage-geometric-shapes.yaml + description: Shows how to work with geometric shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-geometric-shapes.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-group-ungroup + name: Group and ungroup shapes + fileName: group-ungroup.yaml + description: Shows how to group and ungroup shapes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/group-ungroup.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-shapes-manage-canvases + name: Work with canvases + fileName: manage-canvases.yaml + description: Shows how to work with canvases. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-canvases.yaml + group: Shapes + api_set: + WordApiDesktop: '1.2' +- id: word-document-manage-body + name: Manage body + fileName: manage-body.yaml + description: Shows how to manage the document body. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-body.yaml + group: Document + api_set: + WordApi: '1.2' +- id: word-document-insert-section-breaks + name: Add a section + fileName: insert-section-breaks.yaml + description: Shows how to insert section breaks in the document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/insert-section-breaks.yaml + group: Document + api_set: + WordApi: '1.1' +- id: word-document-insert-external-document + name: Insert an external document + fileName: insert-external-document.yaml + description: >- + Inserts the content (with or without settings) of an external document into + the current document. Settings include formatting, change-tracking mode, + custom properties, and XML parts. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/insert-external-document.yaml + group: Document + api_set: + WordApi: '1.7' +- id: word-document-manage-change-tracking + name: Track changes + fileName: manage-change-tracking.yaml + description: >- + This sample shows how to get and set the change tracking mode and get the + before and after of reviewed text. rawUrl: >- - https://raw.githubusercontent.com////samples/word/07-custom-properties/get-built-in-properties.yaml - group: Custom Properties + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-change-tracking.yaml + group: Document api_set: - WordApi: 1.1 -- id: word-common-patterns-multiple-property-set - name: Multiple Property Set + WordApi: '1.4' +- id: word-document-manage-tracked-changes + name: Manage tracked changes + fileName: manage-tracked-changes.yaml + description: >- + This samples shows how to manage tracked changes, including accepting and + rejecting changes. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-tracked-changes.yaml + group: Document + api_set: + WordApi: '1.6' +- id: word-document-manage-comments + name: Manage comments + fileName: manage-comments.yaml + description: >- + This sample shows how to perform basic comments operations, including + insert, reply, get, edit, resolve, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-comments.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-footnotes + name: Manage footnotes + fileName: manage-footnotes.yaml + description: >- + This sample shows how to perform basic footnote operations, including + insert, get, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-footnotes.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-fields + name: Manage fields + fileName: manage-fields.yaml + description: >- + This sample shows how to perform basic operations on fields, including + insert, get, and delete. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-fields.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-settings + name: Manage settings + fileName: manage-settings.yaml + description: >- + This sample shows how to add, edit, get, and delete custom settings on a + document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-settings.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-custom-xml-part-ns + name: Manage a CustomXmlPart with the namespace + fileName: manage-custom-xml-part-ns.yaml + description: >- + This sample shows how to add, query, replace, edit, and delete a custom XML + part in a document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-custom-xml-part-ns.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-custom-xml-part + name: Manage a CustomXmlPart without the namespace + fileName: manage-custom-xml-part.yaml + description: >- + This sample shows how to add, query, edit, and delete a custom XML part in a + document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-custom-xml-part.yaml + group: Document + api_set: + WordApi: '1.4' +- id: word-document-manage-styles + name: Manage styles + fileName: manage-styles.yaml + description: >- + This sample shows how to perform operations on the styles in the current + document and how to add and delete custom styles. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-styles.yaml + group: Document + api_set: + WordApiDesktop: '1.1' +- id: word-document-get-external-styles + name: Get styles from external document + fileName: get-external-styles.yaml + description: This sample shows how to get styles from an external document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/get-external-styles.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-save-close + name: Manage document save and close + fileName: save-close.yaml + description: Shows how to manage saving and closing document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/save-close.yaml + group: Document + api_set: + WordApi: '1.5' +- id: word-document-manage-annotations + name: Manage annotations + fileName: manage-annotations.yaml + description: >- + Shows how to leverage the Writing Assistance API to manage annotations and + use annotation events. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-annotations.yaml + group: Document + api_set: + WordApi: '1.8' +- id: word-document-compare-documents + name: Compare documents + fileName: compare-documents.yaml + description: Compares two documents (the current one and a specified external one). + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/compare-documents.yaml + group: Document + api_set: + WordApiDesktop: '1.1' +- id: word-scenarios-doc-assembly + name: Document assembly + fileName: doc-assembly.yaml + description: Composes different parts of a Word document. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/doc-assembly.yaml + group: Scenarios + api_set: + WordApi: '1.1' +- id: word-scenarios-multiple-property-set + name: Set multiple properties at once fileName: multiple-property-set.yaml - description: Setting multiple properties at once with the API object set() method. + description: Sets multiple properties at once with the API object set() method. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/multiple-property-set.yaml + group: Scenarios + api_set: + WordApi: '1.3' +- id: word-scenarios-correlated-objects-pattern + name: Correlated objects pattern + fileName: correlated-objects-pattern.yaml + description: Shows the performance benefits of avoiding `context.sync` calls in a loop. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/correlated-objects-pattern.yaml + group: Scenarios + api_set: + WordApi: '1.4' +- id: word-close-document-window + name: Close document window + fileName: close-document-window.yaml + description: Shows how to close document window. + rawUrl: >- + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/close-document-window.yaml + group: Preview APIs + api_set: + WordApi: '1.10' +- id: word-insert-and-change-content-controls + name: Content control basics + fileName: insert-and-change-content-controls.yaml + description: Inserts, updates, and retrieves content controls. rawUrl: >- - https://raw.githubusercontent.com////samples/word/50-common-patterns/multiple-property-set.yaml - group: Common Patterns + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/insert-and-change-content-controls.yaml + group: Preview APIs api_set: - WordApi: 1.4 -- id: word-fabric-insert-form-data - name: Fabric JS - Using form data - fileName: fabric-insert-form-data.yaml + WordApi: '1.10' +- id: word-manage-comments + name: Manage comments + fileName: manage-comments.yaml description: >- - Takes form data entered in the task pane and pushes it into the document. - This is meant to show the use of common Fabric elements. + This sample shows how to perform operations on comments (including insert, + reply, get, edit, resolve, and delete) and use comment events. rawUrl: >- - https://raw.githubusercontent.com////samples/word/99-fabric/fabric-insert-form-data.yaml - group: Fabric + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/manage-comments.yaml + group: Preview APIs api_set: - WordApi: 1.1 + WordApi: '1.10' diff --git a/private-samples/excel/20-chart/chart-title-js.yaml b/private-samples/excel/20-chart/chart-title-js.yaml deleted file mode 100644 index a2cbe8f29..000000000 --- a/private-samples/excel/20-chart/chart-title-js.yaml +++ /dev/null @@ -1,152 +0,0 @@ -id: excel-chart-chart-title-js -name: Chart title - JS -description: Set and get the title of a chart -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(() => tryCatch(setup)); - - $("#set-title").click(() => tryCatch(setTitle)); - $("#get-title").click(() => tryCatch(getTitle)); - - function setTitle() { - return Excel.run(function (ctx) { - var chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); - - chart.title.text = "My Chart"; - chart.title.visible = true; - chart.title.overlay = false; - - return ctx.sync() - .then(function () { - console.log("Chart title has been updated"); - }) - }); - } - - function getTitle() { - return Excel.run(function (ctx) { - var chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); - chart.load('title/text'); - - return ctx.sync() - .then(function () { - console.log("Chart title is '" + chart.title.text + "'"); - }) - }); - } - - async function setup() { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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] - ]); - - const salesTable = sheet.tables.getItem("SalesTable"); - - const dataRange = salesTable.getDataBodyRange(); - - let chart = sheet.charts.add("ColumnClustered", dataRange, "auto"); - - 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"); - - chart.name = "Chart1"; - - await context.sync(); - sheet.activate(); - }); - } - - - /** 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 how to set and get the title of a chart using the Excel JavaScript API.

-
- -
-

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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/private-samples/excel/20-chart/chart-title-ts.yaml b/private-samples/excel/20-chart/chart-title-ts.yaml index b447e235a..4c046d4e0 100644 --- a/private-samples/excel/20-chart/chart-title-ts.yaml +++ b/private-samples/excel/20-chart/chart-title-ts.yaml @@ -7,14 +7,14 @@ api_set: ExcelApi: 1.1 script: content: | - $("#setup").click(() => tryCatch(setup)); + $("#setup").on("click", () => tryCatch(setup)); - $("#set-title").click(() => tryCatch(setTitle)); - $("#get-title").click(() => tryCatch(getTitle)); + $("#set-title").on("click", () => tryCatch(setTitle)); + $("#get-title").on("click", () => tryCatch(getTitle)); async function setTitle() { await Excel.run(async (ctx) => { - var chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); + const chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); chart.title.text = "My Chart"; chart.title.visible = true; @@ -28,7 +28,7 @@ script: async function getTitle() { await Excel.run(async (ctx) => { - var chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); + const chart = ctx.workbook.worksheets.getItem("Sample").charts.getItem("Chart1"); chart.load('title/text'); await ctx.sync(); @@ -40,9 +40,8 @@ script: async function setup() { await Excel.run(async (context) => { - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("Sample"); + // NOTE: This is throw an error if a worksheet named "Sample" already exists. + const sheet = context.workbook.worksheets.add("Sample"); let expensesTable = sheet.tables.add('A1:E1', true); @@ -89,25 +88,24 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); + console.log(error); } } language: typescript template: content: |- -
+

This sample shows how to set and get the title of a chart using the Excel JavaScript API.

-
+

Set up

-
+

Try it out

+ 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: '' + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/01-basics/basic-api-call.yaml b/samples/excel/01-basics/basic-api-call.yaml index 13d6b377b..3c2d0ae06 100644 --- a/samples/excel/01-basics/basic-api-call.yaml +++ b/samples/excel/01-basics/basic-api-call.yaml @@ -1,14 +1,14 @@ order: 1 -id: excel-basic-api-call -name: Basic API call -description: Executes a basic Excel API call +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 + ExcelApi: '1.1' script: - content: | - $("#run").click(() => tryCatch(run)); + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); async function run() { await Excel.run(async (context) => { @@ -28,33 +28,40 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | -

Executes a simple code snippet.

- + 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: '' + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/01-basics/basic-common-api-call.yaml b/samples/excel/01-basics/basic-common-api-call.yaml index 689b93f26..cbb1a8992 100644 --- a/samples/excel/01-basics/basic-common-api-call.yaml +++ b/samples/excel/01-basics/basic-common-api-call.yaml @@ -1,47 +1,58 @@ -order: 1000 +order: 3 id: excel-basics-basic-common-api-call name: Basic API call (Office 2013) -description: Executes a basic Excel API call using the "common API" syntax (compatible with 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); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { - Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { - if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); - } else { - console.log(`The selected data is "${asyncResult.value}".`); + 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: | - + 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: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-axis-formatting.yaml b/samples/excel/10-chart/chart-axis-formatting.yaml new file mode 100644 index 000000000..d6cec75ad --- /dev/null +++ b/samples/excel/10-chart/chart-axis-formatting.yaml @@ -0,0 +1,160 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("format-horizontal-axis").addEventListener("click", () => tryCatch(formatHorizontalAxis)); + document.getElementById("format-vertical-axis").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-axis.yaml b/samples/excel/10-chart/chart-axis.yaml new file mode 100644 index 000000000..788450358 --- /dev/null +++ b/samples/excel/10-chart/chart-axis.yaml @@ -0,0 +1,227 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("get-axis-unit").addEventListener("click", () => tryCatch(getAxisUnit)); + document.getElementById("change-axis-unit").addEventListener("click", () => tryCatch(changeAxisUnit)); + document.getElementById("remove-axis-label").addEventListener("click", () => tryCatch(removeAxisLabel)); + document.getElementById("show-axis-label").addEventListener("click", () => tryCatch(showAxisLabel)); + document.getElementById("set-axis-title").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..9a80e9d81 --- /dev/null +++ b/samples/excel/10-chart/chart-bubble-chart.yaml @@ -0,0 +1,160 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-bubble-chart").addEventListener("click", () => tryCatch(createBubbleChart)); + document.getElementById("get-chart-series-dimension-values").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-create-several-charts.yaml b/samples/excel/10-chart/chart-create-several-charts.yaml new file mode 100644 index 000000000..f76ef24c9 --- /dev/null +++ b/samples/excel/10-chart/chart-create-several-charts.yaml @@ -0,0 +1,319 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-column-clustered-chart").addEventListener("click", () => tryCatch(createColumnClusteredChart)); + document.getElementById("create-line-chart").addEventListener("click", () => tryCatch(createLineChart)); + document.getElementById("create-xy-scatter-chart").addEventListener("click", () => tryCatch(createXYScatterChart)); + document.getElementById("create-area-chart").addEventListener("click", () => tryCatch(createAreaStackedChart)); + document.getElementById("create-radar-chart").addEventListener("click", () => tryCatch(createRadarFilledChart)); + document.getElementById("create-pie-chart").addEventListener("click", () => tryCatch(createPieChart)); + document.getElementById("create-3d-chart").addEventListener("click", () => tryCatch(create3DChart)); + document.getElementById("create-cylinder-chart").addEventListener("click", () => tryCatch(createCylinderChart)); + document.getElementById("create-bar-100-chart").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/10-chart/chart-data-labels.yaml b/samples/excel/10-chart/chart-data-labels.yaml new file mode 100644 index 000000000..5e3113b8c --- /dev/null +++ b/samples/excel/10-chart/chart-data-labels.yaml @@ -0,0 +1,278 @@ +order: 16 +id: excel-chart-data-labels +name: Data labels +description: Add and style data labels for your charts. +host: EXCEL +api_set: + ExcelApi: '1.19' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-data-labels").addEventListener("click", () => tryCatch(addDataLabels)); + document.getElementById("style-data-label-substrings").addEventListener("click", () => tryCatch(styleDataLabelSubstrings)); + document.getElementById("change-label-to-round-rectangle").addEventListener("click", () => tryCatch(changeLabelShapesToRoundRectangle)); + document.getElementById("change-label-to-assorted").addEventListener("click", () => tryCatch(changeLabelShapesToAssorted)); + + // Define the worksheet name for the sample. + const sheetName = "Sample"; + + async function addDataLabels() { + // This function adds data labels to specific chart points + // and sets their text and position. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.points.load("dataLabel"); + await context.sync(); + + // Define properties for data label positioning and shape. + const labelProperties = [ + { + top: 70, + geometricShapeType: Excel.GeometricShapeType.rectangle + }, + { + top: 200, + geometricShapeType: Excel.GeometricShapeType.rectangle + } + ]; + + // Add data labels to specific chart points and set their text and properties. + for (let i = 0; i < dataLabelInfo.length; i++) { + const point = series.points.getItemAt(dataLabelInfo[i].index); + point.hasDataLabel = true; + + const dataLabel = point.dataLabel; + dataLabel.text = dataLabelInfo[i].news; + dataLabel.set(labelProperties[i]); + } + await context.sync(); + }); + } + + async function styleDataLabelSubstrings() { + // This function styles substrings within data label text using font formatting. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.load("points"); + await context.sync(); + + series.points.load("items"); + await context.sync(); + + // Style a substring in the first data label. + let searchString = "sports"; + let dataLabel = series.points.getItemAt(dataLabelInfo[0].index).dataLabel.load("text"); + await context.sync(); + let substringStart = dataLabel.text.indexOf(searchString); + let subLabel = dataLabel.getSubstring(substringStart, searchString.length); + subLabel.font.size = 13; + subLabel.font.bold = true; + + // Style a substring in the second data label. + searchString = "'Titanic'"; + dataLabel = series.points.getItemAt(dataLabelInfo[1].index).dataLabel.load("text"); + await context.sync(); + + substringStart = dataLabel.text.indexOf(searchString); + subLabel = dataLabel.getSubstring(substringStart, searchString.length); + subLabel.font.name = "Calibri"; + subLabel.font.size = 13; + subLabel.font.italic = true; + subLabel.font.color = "blue"; + await context.sync(); + }); + } + + async function changeLabelShapesToRoundRectangle() { + // This function changes the geometric shape of data labels to round rectangles. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.load("*"); + await context.sync(); + + series.points.load("*"); + await context.sync(); + + // Set both data labels to round rectangle shape. + let dataLabel = series.points.getItemAt(dataLabelInfo[0].index).dataLabel; + dataLabel.geometricShapeType = Excel.GeometricShapeType.roundRectangle; + + dataLabel = series.points.getItemAt(dataLabelInfo[1].index).dataLabel; + dataLabel.geometricShapeType = Excel.GeometricShapeType.roundRectangle; + await context.sync(); + }); + } + + async function changeLabelShapesToAssorted() { + // This function changes data labels to different geometric shapes with custom formatting. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + + // Set first data label to snip1Rectangle shape. + let dataLabel = series.points.getItemAt(dataLabelInfo[0].index).dataLabel; + dataLabel.geometricShapeType = Excel.GeometricShapeType.snip1Rectangle; + + // Set second data label to snip2DiagonalRectangle shape with light green fill. + dataLabel = series.points.getItemAt(dataLabelInfo[1].index).dataLabel; + dataLabel.geometricShapeType = Excel.GeometricShapeType.snip2DiagonalRectangle; + dataLabel.format.fill.setSolidColor("90EE90"); + await context.sync(); + }); + } + + /** Create sample data and a line chart for the data labels demo. */ + async function setup() { + await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject(sheetName).delete(); + const sheet = context.workbook.worksheets.add(sheetName); + + // Add sample data to the worksheet. + const dataRange = sheet.getRange("A1:B32"); + dataRange.values = sampleData; + + sheet.activate(); + await context.sync(); + + // Create a line chart with markers. + const chart = sheet.charts.add(Excel.ChartType.lineMarkers, dataRange); + + // Position and format the chart. + chart.setPosition("D4", "Q25"); + chart.legend.visible = false; + chart.title.text = "Product price"; + chart.title.format.font.size = 20; + chart.axes.valueAxis.minimum = 80; + + 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); + } + } + + // Save chart data labels as an object for use throughout the sample. + const dataLabelInfo = [ + { + index: 11, + date: "7/12/2023", + news: "The city holds a sports event." + }, + { + index: 20, + date: "7/21/2023", + news: "The movie 'Titanic' returns to the cinema." + } + ]; + + // Sample data for the chart. + const sampleData = [ + ["Date", "Price"], + ["7/1/2023", 100], + ["7/2/2023", 96.71], + ["7/3/2023", 103.24], + ["7/4/2023", 109.09], + ["7/5/2023", 113.68], + ["7/6/2023", 118.68], + ["7/7/2023", 123.2], + ["7/8/2023", 135.05], + ["7/9/2023", 138.68], + ["7/10/2023", 129.63], + ["7/11/2023", 130.85], + ["7/12/2023", 135.71], + ["7/13/2023", 124.83], + ["7/14/2023", 118.94], + ["7/15/2023", 119.63], + ["7/16/2023", 127.2], + ["7/17/2023", 113.98], + ["7/18/2023", 110.32], + ["7/19/2023", 119.3], + ["7/20/2023", 120.36], + ["7/21/2023", 111.88], + ["7/22/2023", 118.88], + ["7/23/2023", 124.37], + ["7/24/2023", 119.53], + ["7/25/2023", 133.42], + ["7/26/2023", 125.67], + ["7/27/2023", 135.82], + ["7/28/2023", 137.87], + ["7/29/2023", 138.9], + ["7/30/2023", 139.36], + ["7/31/2023", 138.75] + ]; + language: typescript +template: + content: |- +
+

This sample shows how to create data labels for charts and adjust the font and appearance of those labels.

+
+
+

Set up

+ +
+
+

Add data labels to the chart

+ +
+
+

Style data labels

+ +
+
+ +
+
+ +
+ 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-data-source.yaml b/samples/excel/10-chart/chart-data-source.yaml new file mode 100644 index 000000000..59e74e3f5 --- /dev/null +++ b/samples/excel/10-chart/chart-data-source.yaml @@ -0,0 +1,119 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("log-chart-series-source").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-data-table.yaml b/samples/excel/10-chart/chart-data-table.yaml new file mode 100644 index 000000000..423e060b2 --- /dev/null +++ b/samples/excel/10-chart/chart-data-table.yaml @@ -0,0 +1,157 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-column-clustered-chart").addEventListener("click", () => tryCatch(createColumnClusteredChart)); + document.getElementById("add-chart-data-table").addEventListener("click", () => tryCatch(addChartDataTable)); + document.getElementById("format-chart-data-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-formatting.yaml b/samples/excel/10-chart/chart-formatting.yaml new file mode 100644 index 000000000..79a031e34 --- /dev/null +++ b/samples/excel/10-chart/chart-formatting.yaml @@ -0,0 +1,217 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("format-chart").addEventListener("click", () => tryCatch(formatChart)); + document.getElementById("show-datalabels").addEventListener("click", () => tryCatch(dataLabels)); + document.getElementById("change-color").addEventListener("click", () => tryCatch(changeColor)); + document.getElementById("clear").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-leader-lines.yaml b/samples/excel/10-chart/chart-leader-lines.yaml new file mode 100644 index 000000000..c49f07acb --- /dev/null +++ b/samples/excel/10-chart/chart-leader-lines.yaml @@ -0,0 +1,185 @@ +order: 17 +id: excel-chart-leader-lines +name: Leader lines +description: Show and hide leader lines for chart labels. +host: EXCEL +api_set: + ExcelApi: '1.19' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-data-labels").addEventListener("click", () => tryCatch(addDataLabels)); + document.getElementById("hide-chart-leader-lines").addEventListener("click", () => tryCatch(hideChartLeaderLines)); + document.getElementById("show-chart-leader-lines").addEventListener("click", () => tryCatch(showChartLeaderLines)); + document.getElementById("change-leader-line-format").addEventListener("click", () => tryCatch(changeLeaderLineFormat)); + + const sheetName = "Sample"; + + async function addDataLabels() { + // The following code adds data labels to the chart and positions them to demonstrate leader lines. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + + // Enable data labels for the series. Leader lines are enabled by default. + series.hasDataLabels = true; + series.points.load("items"); + await context.sync(); + + // Load the top position for each data label. + series.points.items.forEach((point) => point.dataLabel.load("top")); + await context.sync(); + + // Move some data labels to create distance from their chart points. + const point1 = series.points.items[1]; + const point2 = series.points.items[2]; + point1.dataLabel.top -= 50; + point2.dataLabel.top += 50; + + // Format the data labels. + series.dataLabels.geometricShapeType = Excel.GeometricShapeType.rectangle; + series.dataLabels.showCategoryName = true; + series.dataLabels.format.border.weight = 1; + + await context.sync(); + }); + } + + async function hideChartLeaderLines() { + // The following code disables leader lines for chart data labels. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + + // Disable leader lines. + dataLabels.showLeaderLines = false; + + await context.sync(); + }); + } + + async function showChartLeaderLines() { + // The following code enables leader lines for chart data labels. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + + // Enable leader lines. + dataLabels.showLeaderLines = true; + + await context.sync(); + }); + } + + async function changeLeaderLineFormat() { + // The following code changes the format of leader lines. It adjusts color, weight, and line style. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + const lineFormat = dataLabels.leaderLines.format; + + // Set leader line formatting properties. + lineFormat.line.color = "blue"; + lineFormat.line.weight = 2; + lineFormat.line.lineStyle = Excel.ChartLineStyle.dot; + + await context.sync(); + }); + } + + /** Create sample data and a line chart for the leader lines demo. */ + async function setup() { + await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject(sheetName).delete(); + const sheet = context.workbook.worksheets.add(sheetName); + + // Add sample data to the worksheet. + const dataRange = sheet.getRange("A1:C4"); + dataRange.values = sampleData; + + // Create a line chart. + const chart = sheet.charts.add(Excel.ChartType.line, dataRange); + chart.title.text = "Sales Quantity"; + + 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 data for the chart. */ + const sampleData = [ + ["Type", "Product A", "Product B"], + ["Q1", 15, 20], + ["Q2", 22, 15], + ["Q3", 33, 47] + ]; + language: typescript +template: + content: |- +
+

This sample shows how to add leader lines for data labels on your 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/chart-legend.yaml b/samples/excel/10-chart/chart-legend.yaml similarity index 69% rename from samples/excel/89-preview-apis/chart-legend.yaml rename to samples/excel/10-chart/chart-legend.yaml index 4c2ef448b..5e2cabac5 100644 --- a/samples/excel/89-preview-apis/chart-legend.yaml +++ b/samples/excel/10-chart/chart-legend.yaml @@ -1,15 +1,14 @@ -order: 2 +order: 8 id: excel-chart-legend -name: Chart legend -description: Format legend font +name: Legend +description: Formats the legend's font. host: EXCEL api_set: - ExcelAPI: 1.7 + ExcelApi: '1.7' script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#format-legend-font").click(() => tryCatch(formatLegendFont)); - + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("format-legend-font").addEventListener("click", () => tryCatch(formatLegendFont)); async function formatLegendFont() { await Excel.run(async (context) => { @@ -33,8 +32,9 @@ script: async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let expensesTable = sheet.tables.add('A1:E1', true); expensesTable.name = "SalesTable"; @@ -49,10 +49,8 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); createChart(context); addVerticalAxisLabel(context); @@ -72,7 +70,7 @@ script: chart.setPosition("A15", "F30"); chart.title.text = "Quarterly sales chart"; - chart.legend.position = "right" + chart.legend.position = "Right" chart.legend.format.fill.setSolidColor("white"); chart.dataLabels.format.font.size = 15; chart.dataLabels.format.font.color = "black"; @@ -82,12 +80,11 @@ script: } function addVerticalAxisLabel(context: Excel.RequestContext) { + const sheet = context.workbook.worksheets.getItem("Sample"); - const sheet = context.workbook.worksheets.getItem("Sample"); - - let chart = sheet.charts.getItemAt(0); - let axis = chart.axes.valueAxis; - axis.displayUnit = "Thousands"; + let chart = sheet.charts.getItemAt(0); + let axis = chart.axes.valueAxis; + axis.displayUnit = "Thousands"; } /** Default helper for invoking an action and handling errors. */ @@ -96,25 +93,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | + content: |- section.samples { margin-top: 20px; } @@ -134,18 +129,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/chart-point.yaml b/samples/excel/10-chart/chart-point.yaml similarity index 66% rename from samples/excel/89-preview-apis/chart-point.yaml rename to samples/excel/10-chart/chart-point.yaml index 181bf5ffa..627984a03 100644 --- a/samples/excel/89-preview-apis/chart-point.yaml +++ b/samples/excel/10-chart/chart-point.yaml @@ -1,14 +1,14 @@ -order: 3 +order: 9 id: excel-chart-point -name: Chart point -description: Set chart point color. +name: Points +description: Sets the color of a point on the chart. host: EXCEL api_set: - ExcelAPI: 1.7 + ExcelApi: '1.7' script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#set-chart-point-color").click(() => tryCatch(setChartPointColor)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-chart-point-color").addEventListener("click", () => tryCatch(setChartPointColor)); async function setChartPointColor() { await Excel.run(async (context) => { @@ -20,16 +20,15 @@ script: // Set color for chart point. point.format.fill.setSolidColor('red'); - await context.sync(); - - OfficeHelpers.UI.notify("Successfully set chart point color to red (for the third item in series 1)."); + await context.sync(); }); } async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let expensesTable = sheet.tables.add('A1:E1', true); expensesTable.name = "SalesTable"; @@ -44,10 +43,8 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); createChart(context); sheet.activate(); @@ -66,7 +63,7 @@ script: chart.setPosition("A15", "F30"); chart.title.text = "Quarterly sales chart"; - chart.legend.position = "right" + chart.legend.position = "Right" chart.legend.format.fill.setSolidColor("white"); chart.dataLabels.format.font.size = 15; chart.dataLabels.format.font.color = "black"; @@ -78,37 +75,31 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |+ -
+ content: |- +

This sample shows how to set chart point color.

- -
+

Set up

- -
+

Try it out

- language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -120,18 +111,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/chart-series-markers.yaml b/samples/excel/10-chart/chart-series-markers.yaml similarity index 70% rename from samples/excel/89-preview-apis/chart-series-markers.yaml rename to samples/excel/10-chart/chart-series-markers.yaml index 1af78d5f6..6d319a862 100644 --- a/samples/excel/89-preview-apis/chart-series-markers.yaml +++ b/samples/excel/10-chart/chart-series-markers.yaml @@ -1,14 +1,14 @@ -order: 5 +order: 11 id: excel-chart-series-markers -name: Chart series markers -description: Set chart series marker properties +name: Series markers +description: Sets the chart series marker properties. host: EXCEL api_set: - ExcelAPI: 1.7 + ExcelApi: '1.7' script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-markers").click(() => tryCatch(setMarkers)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-markers").addEventListener("click", () => tryCatch(setMarkers)); async function setMarkers() { await Excel.run(async (context) => { @@ -17,7 +17,7 @@ script: let dataRange = sheet.getRange("A1:E7"); // Create an XY scatter chart. - let chart = sheet.charts.add("XYScatterSmooth", dataRange, "auto"); + let chart = sheet.charts.add("XYScatterSmooth", dataRange, "Auto"); chart.title.text = "Bicycle Parts Quarterly Sales"; let series = chart.series; @@ -42,8 +42,9 @@ script: async function setup() { await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let salesTable = sheet.tables.add('A1:E1', true); salesTable.name = "SalesTable"; @@ -58,10 +59,8 @@ script: ["Spokes", 6005, 7634, 4589, 765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); sheet.activate(); @@ -75,25 +74,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | + content: |- section.samples { margin-top: 20px; } @@ -114,17 +111,8 @@ style: } language: css libraries: |- - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-series-plotorder.yaml b/samples/excel/10-chart/chart-series-plotorder.yaml new file mode 100644 index 000000000..69ce579ef --- /dev/null +++ b/samples/excel/10-chart/chart-series-plotorder.yaml @@ -0,0 +1,129 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("order-series-plot").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-series.yaml b/samples/excel/10-chart/chart-series.yaml new file mode 100644 index 000000000..afec9522f --- /dev/null +++ b/samples/excel/10-chart/chart-series.yaml @@ -0,0 +1,145 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-series").addEventListener("click", () => tryCatch(addSeries)); + document.getElementById("delete-series").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/10-chart/chart-title-format.yaml b/samples/excel/10-chart/chart-title-format.yaml new file mode 100644 index 000000000..b080b8b5f --- /dev/null +++ b/samples/excel/10-chart/chart-title-format.yaml @@ -0,0 +1,153 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("change-title-format").addEventListener("click", () => tryCatch(changeTitleFormat)); + document.getElementById("change-title-substring").addEventListener("click", () => tryCatch(changeTitleSubstring)); + document.getElementById("change-title-orientation").addEventListener("click", () => tryCatch(changeTitleOrientation)); + document.getElementById("add-title-shadow").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/chart-trendlines.yaml b/samples/excel/10-chart/chart-trendlines.yaml similarity index 75% rename from samples/excel/89-preview-apis/chart-trendlines.yaml rename to samples/excel/10-chart/chart-trendlines.yaml index 0d83989bc..ee4b19ffe 100644 --- a/samples/excel/89-preview-apis/chart-trendlines.yaml +++ b/samples/excel/10-chart/chart-trendlines.yaml @@ -1,17 +1,17 @@ -order: 6 +order: 14 id: excel-chart-trendlines -name: Chart trendlines -description: 'Add, get, and format trendlines in a chart.' +name: Trendlines +description: Adds, gets, and formats trendlines in a chart. host: EXCEL api_set: - ExcelAPI: 1.7 + 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)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-trendline").addEventListener("click", () => tryCatch(addTrendline)); + document.getElementById("get-trendline").addEventListener("click", () => tryCatch(getTrendline)); + document.getElementById("get-trendline-color").addEventListener("click", () => tryCatch(getTrendlineColor)); + document.getElementById("set-trendline-color").addEventListener("click", () => tryCatch(setTrendlineColor)); async function addTrendline() { await Excel.run(async (context) => { @@ -49,7 +49,6 @@ script: let seriesCollection = sheet.charts.getItemAt(0).series; // Get the color of the chart trendline. - // In this example, it's #4472c4 which is blue. let trendline = seriesCollection.getItemAt(0).trendlines.getItem(0); let line = trendline.format.line; line.load("color"); @@ -79,8 +78,9 @@ script: async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let expensesTable = sheet.tables.add('A1:E1', true); expensesTable.name = "SalesTable"; @@ -95,10 +95,8 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); createChart(context); sheet.activate(); @@ -117,7 +115,7 @@ script: chart.setPosition("A15", "F30"); chart.title.text = "Quarterly sales chart"; - chart.legend.position = "right" + chart.legend.position = "Right" chart.legend.format.fill.setSolidColor("white"); chart.dataLabels.format.font.size = 15; chart.dataLabels.format.font.color = "black"; @@ -132,53 +130,46 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | + content: |- section.samples { margin-top: 20px; } @@ -190,18 +181,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..a9df8e856 --- /dev/null +++ b/samples/excel/10-chart/create-doughnut-chart.yaml @@ -0,0 +1,144 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-doughnut-chart").addEventListener("click", () => tryCatch(createChart)); + document.getElementById("add-series").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/12-comments-and-notes/comment-basics.yaml b/samples/excel/12-comments-and-notes/comment-basics.yaml new file mode 100644 index 000000000..2739d6a08 --- /dev/null +++ b/samples/excel/12-comments-and-notes/comment-basics.yaml @@ -0,0 +1,137 @@ +order: 1 +id: excel-comment-basics +name: Comment basics +description: Adds, edits, and removes comments. +host: EXCEL +api_set: + ExcelApi: '1.10' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-comment-to-selected-cell").addEventListener("click", () => tryCatch(addCommentToSelectedCell)); + document.getElementById("add-comment-to-cell").addEventListener("click", () => tryCatch(addCommentToCell)); + document.getElementById("get-comment-metadata").addEventListener("click", () => tryCatch(getCommentMetadata)); + document.getElementById("edit-comment").addEventListener("click", () => tryCatch(editComment)); + document.getElementById("delete-comment").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/12-comments-and-notes/comment-mentions.yaml b/samples/excel/12-comments-and-notes/comment-mentions.yaml new file mode 100644 index 000000000..7c4755829 --- /dev/null +++ b/samples/excel/12-comments-and-notes/comment-mentions.yaml @@ -0,0 +1,96 @@ +order: 2 +id: excel-comment-mentions +name: Comment mentions +description: Mentions someone in a comment. +host: EXCEL +api_set: + ExcelApi: '1.11' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-comment-with-mention").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/12-comments-and-notes/comment-replies.yaml b/samples/excel/12-comments-and-notes/comment-replies.yaml new file mode 100644 index 000000000..ae02603bd --- /dev/null +++ b/samples/excel/12-comments-and-notes/comment-replies.yaml @@ -0,0 +1,158 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-first-comment-reply").addEventListener("click", () => tryCatch(addFirstCommentReply)); + document.getElementById("add-second-comment-reply").addEventListener("click", () => tryCatch(addSecondCommentReply)); + document.getElementById("get-comment-reply-metadata").addEventListener("click", () => tryCatch(getCommentReplyMetadata)); + document.getElementById("edit-comment-reply").addEventListener("click", () => tryCatch(editCommentReply)); + document.getElementById("delete-comment-reply").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/12-comments-and-notes/comment-resolution.yaml b/samples/excel/12-comments-and-notes/comment-resolution.yaml new file mode 100644 index 000000000..bfb60392a --- /dev/null +++ b/samples/excel/12-comments-and-notes/comment-resolution.yaml @@ -0,0 +1,107 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-comment").addEventListener("click", () => tryCatch(addComment)); + document.getElementById("resolve-comment").addEventListener("click", () => tryCatch(resolveComment)); + document.getElementById("reopen-comment").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/12-comments-and-notes/excel-note-basics.yaml b/samples/excel/12-comments-and-notes/excel-note-basics.yaml new file mode 100644 index 000000000..582c5d52c --- /dev/null +++ b/samples/excel/12-comments-and-notes/excel-note-basics.yaml @@ -0,0 +1,162 @@ +order: 5 +id: excel-note-basics +name: Notes +description: Adds, edits, and removes notes. +host: EXCEL +api_set: + ExcelApi: '1.18' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-note-to-selected-cell").addEventListener("click", () => tryCatch(addNoteToSelectedCell)); + document.getElementById("add-note-to-cell").addEventListener("click", () => tryCatch(addNoteToCell)); + document.getElementById("change-note-visibility").addEventListener("click", () => tryCatch(changeNoteVisibility)); + document.getElementById("edit-note-content").addEventListener("click", () => tryCatch(editNoteContent)); + document.getElementById("edit-note-size").addEventListener("click", () => tryCatch(editNoteSize)); + document.getElementById("delete-note").addEventListener("click", () => tryCatch(deleteNote)); + + async function addNoteToSelectedCell() { + // This function adds a note to the selected cell. + await Excel.run(async (context) => { + const selectedRange = context.workbook.getSelectedRange(); + + // Note that an InvalidArgument error is thrown if multiple cells are selected. + context.workbook.notes.add(selectedRange, "The first note."); + await context.sync(); + }); + } + + async function addNoteToCell() { + // This function adds a note to cell A2. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + + // Note that an InvalidArgument error is thrown if multiple cells are passed to `notes.add`. + sheet.notes.add("A2", "The second note."); + await context.sync(); + }); + } + + async function changeNoteVisibility() { + // This function sets the note on cell A1 to visible. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const firstNote = sheet.notes.getItem("A1"); + + firstNote.load(); + await context.sync(); + + firstNote.visible = true; + }); + } + + async function editNoteContent() { + // This function changes the content in the first note. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.content = "Changing the content of the first note."; + await context.sync(); + }); + } + + async function editNoteSize() { + // This function changes the height and width of the first note. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.height = 200; + note.width = 400; + await context.sync(); + }); + } + + async function deleteNote() { + // This function deletes the note from cell A2. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItem("A2"); + note.delete(); + + await context.sync(); + }); + } + + /** Set up Sample worksheet. */ + async function setup() { + await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject("Notes").delete(); + const sheet = context.workbook.worksheets.add("Notes"); + + 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 notes: Add notes, edit content, size, and visibility, and remove notes.

+
+
+

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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..7e207e842 --- /dev/null +++ b/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml @@ -0,0 +1,230 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("apply-conditional-formats-default-priority").addEventListener("click", () => tryCatch(applyConditionalFormatsWithDefaultPriority)); + document.getElementById("apply-conditional-formats-explicit-priority").addEventListener("click", () => tryCatch(applyPrioritizedConditionalFormats)); + document.getElementById("apply-conditional-formats-stop-if-true").addEventListener("click", () => tryCatch(applyPrioritizedConditionalFormatsWithStopOnTrue)); + document.getElementById("remove-conditional-format").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-range/conditional-formatting-basic.yaml b/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml similarity index 78% rename from samples/excel/30-range/conditional-formatting-basic.yaml rename to samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml index 83d468cf8..5c6d0b0e3 100644 --- a/samples/excel/30-range/conditional-formatting-basic.yaml +++ b/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml @@ -1,21 +1,23 @@ +order: 1 id: excel-range-conditional-formatting-basic -name: Conditional Formatting for Ranges - Basic -description: Apply common types of conditional formatting to ranges. +name: Basic conditional formatting +description: Applies common types of conditional formatting to ranges. host: EXCEL api_set: - ExcelApi: 1.6 + 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-custom-format").click(() => tryCatch(applyCustomFormat)); - $("#list-conditional-formats").click(() => tryCatch(listConditionalFormats)); - $("#clear-all-conditional-formats").click(() => tryCatch(clearAllConditionalFormats)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("apply-color-scale-format").addEventListener("click", () => tryCatch(applyColorScaleFormat)); + document.getElementById("apply-preset-format").addEventListener("click", () => tryCatch(applyPresetFormat)); + document.getElementById("apply-databar-format").addEventListener("click", () => tryCatch(applyDataBarFormat)); + document.getElementById("apply-icon-set-format").addEventListener("click", () => tryCatch(applyIconSetFormat)); + document.getElementById("apply-text-format").addEventListener("click", () => tryCatch(applyTextFormat)); + document.getElementById("apply-cell-value-format").addEventListener("click", () => tryCatch(applyCellValueFormat)); + document.getElementById("apply-top-bottom-format").addEventListener("click", () => tryCatch(applyTopBottomFormat)); + document.getElementById("apply-custom-format").addEventListener("click", () => tryCatch(applyCustomFormat)); + document.getElementById("list-conditional-formats").addEventListener("click", () => tryCatch(listConditionalFormats)); + document.getElementById("clear-all-conditional-formats").addEventListener("click", () => tryCatch(clearAllConditionalFormats)); async function applyColorScaleFormat() { await Excel.run(async (context) => { @@ -77,8 +79,8 @@ script: 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 this method does below, because every + 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. */ @@ -126,6 +128,19 @@ script: }); } + 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"); @@ -156,19 +171,12 @@ script: await context.sync(); - $("#conditional-formats li").remove(); if (cfRangePairs.length > 0) { cfRangePairs.forEach(item => { - let $p = $("

").text( - `${item.cf.type}`) - let $li = $(`
  • `); - $li.append($p); - $("#conditional-formats").append($li); - $(".conditional-formats").show()[0].scrollIntoView(); - }) - } - else { - OfficeHelpers.UI.notify("None to display", "No conditional formats in workbook", "warning"); + console.log(item.cf.type); + }); + } else { + console.log("No conditional formats applied."); } }); } @@ -181,14 +189,17 @@ script: await context.sync(); - $(".conditional-formats").hide(); + document.querySelectorAll(".conditional-formats").forEach(element => { + element.style.display = "none"; + }); }); } async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + queueCommandsToCreateTemperatureTable(sheet); queueCommandsToCreateSalesTable(sheet); queueCommandsToCreateProjectTable(sheet); @@ -258,38 +269,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | - - -
    -
    -
    -
    -
    -
    - -
    - -
    + content: |- +

    This sample shows how to apply conditional formatting to ranges.

    - -
    +

    Set up

    - -
    +

    Try it out

    + + - -
    - - language: html style: @@ -347,35 +340,10 @@ style: margin-left: 20px; min-width: 80px; } - - body { - margin: 0; - padding: 0; - } - - #main { - margin: 10px; - } - - .ms-MessageBanner { - display: none; - } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.6.0/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/16-custom-functions/basic-function.yaml b/samples/excel/16-custom-functions/basic-function.yaml new file mode 100644 index 000000000..918cd2354 --- /dev/null +++ b/samples/excel/16-custom-functions/basic-function.yaml @@ -0,0 +1,23 @@ +order: 1 +id: excel-custom-functions-basic +name: Basic custom function +description: Calculates the volume of a sphere. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.1 +script: + content: | + /** + * Calculates the volume of a sphere. + * @customfunction + * @param {number} radius + * @returns The volume of the sphere. + */ + function sphereVolume(radius) { + return Math.pow(radius, 3) * 4 * Math.PI / 3; + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + core-js@2.4.1/client/core.min.js diff --git a/samples/excel/16-custom-functions/custom-enum.yaml b/samples/excel/16-custom-functions/custom-enum.yaml new file mode 100644 index 000000000..5eb140f97 --- /dev/null +++ b/samples/excel/16-custom-functions/custom-enum.yaml @@ -0,0 +1,90 @@ +order: 7 +id: excel-custom-functions-custom-enum +name: Function with custom enums +description: Use custom enums as parameters in a custom function that searches for flights. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.5 +script: + content: | + /** + * A custom enum representing different airports. + * @customenum {string} + */ + enum Airports { + // Beijing is the capital of China. + Beijing = "PEK", + + // Shanghai is a major financial hub in China. + Shanghai = "PVG", + + // Seattle is known for its tech industry and the Space Needle. + Seattle = "SEA", + + // San Francisco is famous for the Golden Gate Bridge and tech startups. + SanFrancisco = "SFO", + + // Tokyo is the capital of Japan and known for its modern architecture and culture. + Tokyo = "HND" + } + + /** + * A custom enum representing the days of the week. + * @customenum {number} + */ + enum DayOfWeek { + Monday = 1, + Tuesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, + Sunday = 7 + } + + /** + * A function that shows how to use custom enums to get a flight schedule. + * @customfunction + * @param {Airports} departure Where the flight departs. + * @param {Airports} destination Where the flight arrives. + * @param {DayOfWeek[]} day Days of the week when the flight is available. + * @returns The available flight schedule. + */ + function fetchFlightSchedule(departure: Airports, destination: Airports, day: DayOfWeek[]): string[][] { + const flights: string[][] = []; + + // Use the `Airports` enum for both the `departure` and `destination` parameters. + flights.push(["Flights from " + departure + " to " + destination, "", "", "", ""]); + + flights.push(["Day", "Flight Number", "Departure Time", "Arrival Time", "Price"]); + const daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + + day.forEach((d) => { + const dayName = daysOfWeek[d - 1]; + const numberOfFlights = Math.floor(Math.random() * 3) + 1; // 1 to 3 flights + + for (let i = 0; i < numberOfFlights; i++) { + const flightNumber = `AA${Math.floor(Math.random() * 900) + 100}`; + const departureTime = `${Math.floor(Math.random() * 12) + 1}:00 ${Math.random() > 0.5 ? "AM" : "PM"}`; + const arrivalTime = `${Math.floor(Math.random() * 12) + 1}:00 ${Math.random() > 0.5 ? "AM" : "PM"}`; + const price = `$${Math.floor(Math.random() * 500) + 100}`; + + flights.push([dayName, flightNumber, departureTime, arrivalTime, price]); + } + }); + + return flights; + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + office-ui-fabric-js@1.5.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/16-custom-functions/custom-functions-errors.yaml b/samples/excel/16-custom-functions/custom-functions-errors.yaml new file mode 100644 index 000000000..bfca8594a --- /dev/null +++ b/samples/excel/16-custom-functions/custom-functions-errors.yaml @@ -0,0 +1,38 @@ +order: 5 +id: excel-custom-functions-errors +name: Custom functions errors +description: Returns the "#NUM!" error as part of a 2-dimensional array. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.2 +script: + content: |- + /** + * Returns the #NUM! error as part of a 2-dimensional array. + * @customfunction + * @param {number} first First parameter. + * @param {number} second Second parameter. + * @param {number} third Third parameter. + * @returns {number[][]} Three results, as a 2-dimensional array. + */ + function returnInvalidNumberError(first, second, third) { + // Use the `CustomFunctions.Error` object to retrieve an invalid number error. + const error = new CustomFunctions.Error( + CustomFunctions.ErrorCode.invalidNumber, // Corresponds to the #NUM! error in the Excel UI. + ); + + // Enter logic that processes the first, second, and third input parameters. + // Imagine that the second calculation results in an invalid number error. + const firstResult = first; + const secondResult = error; + const thirdResult = third; + + // Return the results of the first and third parameter calculations + // and a #NUM! error in place of the second result. + return [[firstResult], [secondResult], [thirdResult]]; + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + core-js@2.4.1/client/core.min.js diff --git a/samples/excel/16-custom-functions/data-types-custom-functions.yaml b/samples/excel/16-custom-functions/data-types-custom-functions.yaml new file mode 100644 index 000000000..3a32c08ee --- /dev/null +++ b/samples/excel/16-custom-functions/data-types-custom-functions.yaml @@ -0,0 +1,334 @@ +order: 6 +id: excel-data-types-custom-functions +name: 'Data types: Custom functions' +description: This sample shows how to write custom functions that return entity value data types. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.4 +script: + content: | + /** + * Search for products that match a given substring. Try =SCRIPTLAB.DATATYPESCUSTOMFUNCTIONS.PRODUCTSEARCH("chef", false). + * @customfunction + * @param {string} query The string to search for in the sample JSON data. + * @param {boolean} [completeMatch] Define whether the search should be a match of the whole product name or part of the product name. If omitted, completeMatch = false. + * @return {Promise} Search results as one or more data type entity values. + */ + async function productSearch(query: string, completeMatch?: boolean): Promise { + // This function searches a set of sample JSON data for the string entered in the + // custom function, and then returns the search result as one or more entity values. + + // Set up an error to use if a matching product doesn't exist in the JSON data. + const notAvailableError = { + type: "Error", + errorType: "NotAvailable" + }; + + // Search the sample JSON data for matching product names. + try { + if (completeMatch === null) { + completeMatch = false + } + + console.log(`Searching for ${query}...`); + const searchResult = await searchProduct(query, completeMatch); + + // If the search result is empty, return the error. + if (searchResult.length == 0) { + return [[notAvailableError]]; + } + + // Create product entities for each of the products returned in the search result. + const entities = searchResult.map((product) => [makeProductEntity(product)]); + return entities; + } catch (error) { + console.error(error); + } + } + + // Helper function to create entities from product properties. + function makeProductEntity(product?: any) { + const entity: Excel.EntityCellValue = { + type: "Entity", + text: product.productName, + properties: { + "Product ID": { + type: "String", + basicValue: product.productID.toString() || "" + }, + "Product Name": { + type: "String", + basicValue: product.productName || "" + }, + "Quantity Per Unit": { + type: "String", + basicValue: product.quantityPerUnit || "" + }, + // Add Unit Price as a formatted number. + "Unit Price": { + type: "Double", + basicValue: product.unitPrice, + numberFormat: "$* #,##0.00" + }, + Discontinued: { + type: "Boolean", + basicValue: product.discontinued || false + } + }, + 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"] + }, + { + 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: "WebImage", + address: product.productImage || "" + }; + entity.layouts.card.mainImage = { property: "Image" }; + } + + return entity; + } + + // Helper function to search the sample JSON product data. + function searchProduct(query: string, completeMatch: boolean): any { + const queryUpperCase = query.toUpperCase(); + if (completeMatch === true) { + return products.filter((p) => p.productName.toUpperCase() === queryUpperCase); + } else { + return products.filter((p) => p.productName.toUpperCase().indexOf(queryUpperCase) >= 0); + } + } + + /** 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: "" + }, + ]; + + 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 +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + core-js@2.4.1/client/core.min.js + @types/core-js diff --git a/samples/excel/16-custom-functions/streaming-function.yaml b/samples/excel/16-custom-functions/streaming-function.yaml new file mode 100644 index 000000000..8959a13e4 --- /dev/null +++ b/samples/excel/16-custom-functions/streaming-function.yaml @@ -0,0 +1,33 @@ +order: 3 +id: excel-custom-functions-streaming +name: Streaming function +description: A streaming function that continuously increments the cell value. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.1 +script: + content: | + /** @CustomFunction + * @description Increments the cell with a given amount at a specified interval in milliseconds. + * @param {number} amount - The amount to add to the cell value on each increment. + * @param {number} interval - The time in milliseconds to wait before the next increment on the cell. + * @param {CustomFunctions.StreamingInvocation} invocation - Parameter to send results to Excel + * or respond to the user canceling the function. + * @returns An incrementing value. + */ + function increment(amount: number, interval: number, invocation: CustomFunctions.StreamingInvocation): void { + let result = 0; + const timer = setInterval(() => { + result += amount; + invocation.setResult(result); + }, interval); + + invocation.onCanceled = () => { + clearInterval(timer); + } + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + core-js@2.4.1/client/core.min.js diff --git a/samples/excel/16-custom-functions/volatile-function.yaml b/samples/excel/16-custom-functions/volatile-function.yaml new file mode 100644 index 000000000..810a61631 --- /dev/null +++ b/samples/excel/16-custom-functions/volatile-function.yaml @@ -0,0 +1,22 @@ +order: 2 +id: excel-custom-functions-volatile +name: Volatile function +description: Rolls a 6 sided die that returns a possible new value every calculation. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.1 +script: + content: | + /** @CustomFunction + * @description Simulates rolling a 6-sided die. + * @returns A whole number from 1 to 6. + * @volatile + */ + function roll6sided(): number { + return Math.floor(Math.random() * 6) + 1; + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + core-js@2.4.1/client/core.min.js diff --git a/samples/excel/16-custom-functions/web-call-function.yaml b/samples/excel/16-custom-functions/web-call-function.yaml new file mode 100644 index 000000000..930651c9a --- /dev/null +++ b/samples/excel/16-custom-functions/web-call-function.yaml @@ -0,0 +1,33 @@ +order: 4 +id: excel-custom-functions-web-call +name: Web request to GitHub API +description: Calls the GitHub API to get the star count for an org/user and repository. +host: EXCEL +api_set: + CustomFunctionsRuntime: 1.1 +script: + content: | + /** + * Gets the star count for a given org/user and repo. Try =GETSTARCOUNT("officedev","office-js") + * @customfunction + * @param userName Name of org or user. + * @param repoName Name of the repo. + * @return Number of stars. + */ + async function getStarCount(userName = "OfficeDev", repoName = "office-js") { + //You can change this URL to any web request you want to work with. + const url = `https://api.github.com/repos/${userName}/${repoName}`; + const response = await fetch(url); + + //Expect that status code is in 200-299 range + if (!response.ok) { + throw new Error(response.statusText); + } + const jsonResponse = await response.json(); + return jsonResponse.watchers_count; + } + language: typescript +libraries: | + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + core-js@2.4.1/client/core.min.js diff --git a/samples/excel/85-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 similarity index 50% rename from samples/excel/85-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml rename to samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml index a1fcfb516..a3bd21c84 100644 --- a/samples/excel/85-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 @@ -1,19 +1,19 @@ +order: 1 id: excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts -name: 'Create, set, get, and delete custom XML part' -description: 'Shows how to create, set, get, and delete a custom XML part.' +name: Using custom XML parts +description: Creates, sets, gets, and deletes a custom XML part. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.5 + 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)); + content: |- + document.getElementById("create-custom-xml-part").addEventListener("click", () => tryCatch(createCustomXmlPart)); + document.getElementById("change-custom-xml-part").addEventListener("click", () => tryCatch(changeCustomXmlPart)); + document.getElementById("delete-custom-xml-part").addEventListener("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"; @@ -24,7 +24,7 @@ script: await context.sync(); const readableXml = addLineBreaksToXML(xmlBlob.value); - $("#display-xml").text(readableXml); + document.getElementById("display-xml").textContent = readableXml; // Store the XML part's ID in a setting. const settings = context.workbook.settings; @@ -37,52 +37,52 @@ script: async function changeCustomXmlPart() { await Excel.run(async (context) => { const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - + const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); await context.sync(); - - 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(); + if (xmlPartIDSetting.value) { + const customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value); - const readableXml = addLineBreaksToXML(xmlBlob.value); - $("#display-xml").text(readableXml); + // The setXml method does a whole-for-whole replacement + // of the entire XML. + customXmlPart.setXml("JohnHitomi"); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); - await context.sync(); + const readableXml = addLineBreaksToXML(xmlBlob.value); + document.getElementById("display-xml").textContent = readableXml; + await context.sync(); + } }); } async function deleteCustomXmlPart() { await Excel.run(async (context) => { const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - + const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); await context.sync(); - - 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 (xmlPartIDSetting.value) { + let customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value); + const xmlBlob = customXmlPart.getXml(); + customXmlPart.delete(); + customXmlPart = context.workbook.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); - if (customXmlPart.isNullObject) { - $("#display-xml").text(`The XML part with the id ${xmlPartIDSetting.value} has been deleted.`); + await context.sync(); - // 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); - } + if (customXmlPart.isNullObject) { + document.getElementById("display-xml").textContent = `The XML part with the id ${xmlPartIDSetting.value} has been deleted.`; - await context.sync(); + // 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}` + document.getElementById("display-xml").textContent = strangeMessage; + } + + await context.sync(); + } }); } @@ -97,18 +97,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |+ -
    + 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 delete the XML part.

    +

    Press the button to delete the XML part.

    - -
    +

    XML part display

    - language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -145,21 +142,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/85-custom-xml-parts/test-xml-for-unique-namespace.yaml b/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml similarity index 61% rename from samples/excel/85-custom-xml-parts/test-xml-for-unique-namespace.yaml rename to samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml index 7c527741e..0ffaf7ac0 100644 --- a/samples/excel/85-custom-xml-parts/test-xml-for-unique-namespace.yaml +++ b/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml @@ -1,19 +1,20 @@ +order: 2 id: excel-custom-xml-parts-test-xml-for-unique-namespace -name: Test custom XML part for unique namespace -description: Shows how to test to see if there is only one XML part for a specified 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 + 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)); + content: |- + document.getElementById("create-custom-xml-part").addEventListener("click", () => tryCatch(createCustomXmlPart)); + document.getElementById("test-for-unique-namespace").addEventListener("click", () => tryCatch(testForUniqueNamespace)); + document.getElementById("delete-all-custom-xml-parts").addEventListener("click", () => tryCatch(deleteAllCustomXmlParts)); async function createCustomXmlPart() { await Excel.run(async (context) => { - $("#display-xml").text(""); + document.getElementById("display-xml").textContent = ""; // You must have the xmlns attribute to populate the // CustomXml.namespaceUri property. @@ -25,7 +26,7 @@ script: // Make it a bit more readable. const readableXml = xmlBlob.value.replace(/>\n<"); - $("#display-xml").text(readableXml); + document.getElementById("display-xml").textContent = readableXml; await context.sync(); }); @@ -33,7 +34,7 @@ script: async function testForUniqueNamespace() { await Excel.run(async (context) => { - $("#display-xml").text(""); + document.getElementById("display-xml").textContent = ""; const contosoNamespace = "http://schemas.contoso.com/review/1.0"; const customXmlParts = context.workbook.customXmlParts; const filteredXmlParts = customXmlParts.getByNamespace(contosoNamespace); @@ -50,12 +51,11 @@ script: // 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}`); + document.getElementById("display-xml").textContent = `The only XML part in the namespace ${contosoNamespace} is: + ${readableXml}`; } else { - OfficeHelpers.UI.notify(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. - There should be exactly 1.`); + console.log(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. There should be exactly 1.`); } await context.sync(); @@ -64,7 +64,7 @@ script: async function deleteAllCustomXmlParts() { await Excel.run(async (context) => { - $("#display-xml").text(""); + document.getElementById("display-xml").textContent = ""; const customXmlParts = context.workbook.customXmlParts; customXmlParts.load("items"); @@ -84,42 +84,39 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |+ -
    + 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 "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.

    +

    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 the button below to delete all the XML parts.

    +

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

    - -
    +

    XML part display

    - language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -131,21 +128,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/20-data-types/data-types-basic-types.yaml b/samples/excel/20-data-types/data-types-basic-types.yaml new file mode 100644 index 000000000..523da4b44 --- /dev/null +++ b/samples/excel/20-data-types/data-types-basic-types.yaml @@ -0,0 +1,362 @@ +order: 8 +id: excel-data-types-basic-types +name: Basic types with metadata +description: This sample shows how to work with metadata on basic types. +host: EXCEL +api_set: + ExcelApi: '1.19' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-basic-types-with-metadata").addEventListener("click", () => tryCatch(setBasicTypesWithMetadata)); + document.getElementById("set-referenced-values").addEventListener("click", () => tryCatch(setReferencedValues)); + document.getElementById("set-circular-reference-values").addEventListener("click", () => tryCatch(setCircularReferenceValues)); + document.getElementById("print-to-console").addEventListener("click", () => tryCatch(printToConsole)); + + const sheetName = "Sample"; + + /** Add basic types with metadata to the worksheet. */ + async function setBasicTypesWithMetadata() { + await Excel.run(async (context) => { + // Get the worksheet and target range. + const sheet = context.workbook.worksheets.getItem(sheetName); + const dataRange = sheet.getRange("A1:A4"); + + // Write a variety of basic types with metadata to the range. + dataRange.valuesAsJson = [ + [doubleWithFormatAndMetadata], + [doubleWithMetadata], + [stringWithMetadata], + [booleanWithMetadata] + ]; + + dataRange.format.autofitColumns(); + await context.sync(); + }); + } + + /** Set basic types with metadata that reference other basic types in the worksheet. */ + async function setReferencedValues() { + await Excel.run(async (context) => { + // Get the worksheet and target range. + const sheet = context.workbook.worksheets.getItem(sheetName); + const targetRange = sheet.getRange("A5"); + + // Write a string with metadata that references other values. + targetRange.valuesAsJson = [ + [stringWithReferencedValues] + ]; + targetRange.format.autofitColumns(); + + await context.sync(); + }); + } + + /** Set basic types with metadata that contain circular references. */ + async function setCircularReferenceValues() { + await Excel.run(async (context) => { + // Get the worksheet and target range. + const sheet = context.workbook.worksheets.getItem(sheetName); + const targetRange = sheet.getRange("A6"); + + // Write a string with metadata that contains circular references. + targetRange.valuesAsJson = [ + [stringWithCircularReferences] + ]; + targetRange.format.autofitColumns(); + + await context.sync(); + }); + } + + /** Get and log information about the basic types in the worksheet. */ + async function printToConsole() { + await Excel.run(async (context) => { + // Get the worksheet and target range. + const sheet = context.workbook.worksheets.getItem(sheetName); + const dataRange = sheet.getRange("A1:A6"); + + // Load the data type property of the range. + dataRange.load("valuesAsJson"); + await context.sync(); + + const dataValues = dataRange.valuesAsJson; + + // Print information about the data types to the console. + console.log("Basic types as an array:", dataValues); + }); + } + + /** Set up Sample worksheet. */ + async function setup() { + await Excel.run(async (context) => { + // Create a new worksheet and activate it. + context.workbook.worksheets.getItemOrNullObject(sheetName).delete(); + const sheet = context.workbook.worksheets.add(sheetName); + 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); + } + } + + /** Basic string value with metadata. */ + const basicStringValue: Excel.StringCellValue = { + type: Excel.CellValueType.string, + basicType: Excel.CellValueType.string, + basicValue: "This is a basic string value" + }; + + /** Basic double value with metadata. */ + const basicDoubleValue: Excel.DoubleCellValue = { + type: Excel.CellValueType.double, + basicType: Excel.CellValueType.double, + basicValue: 10 + }; + + /** Basic boolean value with metadata. */ + const basicBooleanValue: Excel.BooleanCellValue = { + type: Excel.CellValueType.boolean, + basicType: Excel.CellValueType.boolean, + basicValue: true + }; + + /** Web image cell value. */ + const imageCellValue: Excel.WebImageCellValue = { + type: "WebImage", + basicType: "Error", + basicValue: "#VALUE!", + address: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true", + }; + + /** Basic view layout with icon for card and compact views. */ + const basicViewLayoutWithIcon: Excel.BasicViewLayouts = { + card: { + title: "This is the title", + sections: [ + { + layout: "List", + properties: ["stringProperty", "booleanProperty", "doubleProperty"], + collapsed: false, + collapsible: true + } + ], + subTitle: { + property: "stringProperty" + }, + mainImage: { + property: "imageProperty" + } + }, + compact: { + icon: Excel.EntityCompactLayoutIcons.animalDog + } + }; + + /** Simple view layout without icon. */ + const basicViewLayoutSimple: Excel.BasicViewLayouts = { + card: { + title: "This is the title", + subTitle: { + property: "stringProperty" + } + } + }; + + /** Cell value provider attributes for data source attribution. */ + const cellValueProvider: Excel.CellValueProviderAttributes = { + description: "Microsoft Bing", + logoSourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true", + logoTargetAddress: "http://microsoft.com/" + }; + + /** Double value with formatting and metadata. */ + const doubleWithFormatAndMetadata: Excel.DoubleCellValue = { + type: Excel.CellValueType.double, + basicType: Excel.CellValueType.double, + basicValue: 300, + numberFormat: "$0.00", + properties: { + stringProperty: basicStringValue, + booleanProperty: basicBooleanValue, + doubleProperty: basicDoubleValue, + imageProperty: imageCellValue + }, + layouts: basicViewLayoutWithIcon, + provider: cellValueProvider + }; + + /** Double value with metadata but no special formatting. */ + const doubleWithMetadata: Excel.DoubleCellValue = { + type: Excel.CellValueType.double, + basicType: Excel.CellValueType.double, + basicValue: 123.45, + properties: { + stringProperty: basicStringValue, + booleanProperty: basicBooleanValue, + doubleProperty: basicDoubleValue, + imageProperty: imageCellValue + }, + layouts: basicViewLayoutSimple, + provider: cellValueProvider + }; + + /** String value with metadata. */ + const stringWithMetadata: Excel.StringCellValue = { + type: Excel.CellValueType.string, + basicType: Excel.CellValueType.string, + basicValue: "String with metadata", + properties: { + stringProperty: basicStringValue, + booleanProperty: basicBooleanValue, + doubleProperty: basicDoubleValue, + imageProperty: imageCellValue + }, + layouts: basicViewLayoutWithIcon, + provider: cellValueProvider + }; + + /** Boolean value with metadata. */ + const booleanWithMetadata: Excel.BooleanCellValue = { + type: Excel.CellValueType.boolean, + basicType: Excel.CellValueType.boolean, + basicValue: true, + properties: { + stringProperty: basicStringValue, + booleanProperty: basicBooleanValue, + doubleProperty: basicDoubleValue, + imageProperty: imageCellValue + }, + layouts: basicViewLayoutSimple, + provider: cellValueProvider + }; + + /** String with metadata that references other values. */ + const stringWithReferencedValues = { + type: Excel.CellValueType.string, + basicType: Excel.CellValueType.string, + basicValue: "String with referenced values", + properties: { + stringProperty: { + type: Excel.CellValueType.reference, + reference: 0 + }, + booleanProperty: { + type: Excel.CellValueType.reference, + reference: 1 + }, + doubleWithFormatProperty: { + type: Excel.CellValueType.reference, + reference: 2 + }, + doubleProperty: { + type: Excel.CellValueType.reference, + reference: 3 + } + }, + referencedValues: [stringWithMetadata, booleanWithMetadata, doubleWithFormatAndMetadata, doubleWithMetadata], + layouts: { + compact: { + icon: Excel.EntityCompactLayoutIcons.apple + } + } + }; + + /** String with metadata that contains circular references. */ + const stringWithCircularReferences = { + type: Excel.CellValueType.string, + basicType: Excel.CellValueType.string, + basicValue: "String with circular references", + properties: { + doubleProperty: { + type: Excel.CellValueType.double, + basicType: Excel.CellValueType.double, + basicValue: 10, + properties: { + stringProperty: basicStringValue, + doubleProperty: basicDoubleValue, + booleanProperty: basicBooleanValue, + rootProperty: { + type: Excel.CellValueType.reference, + reference: 0 + } + }, + referencedValues: [ + { + type: Excel.ReferenceValueType.root + } + ] + } + }, + layouts: { + compact: { + icon: Excel.EntityCompactLayoutIcons.animalTurtle + } + } + }; + language: typescript +template: + content: |- +
    +

    This sample shows how to create basic types with metadata and then work with those basic types.

    +
    +
    +

    Set up

    + +
    +
    +

    Try it out

    +

    Add basic types to the worksheet. Select the icon in each cell to see a data type card with metadata.

    + +
    +
    +

    Add a basic type with referenced values. Open the data type card to see other values in the worksheet that this basic type references—it references cells A1, A2, A3, and A4.

    + +
    +
    +

    Add a basic type with circular references. Open the data type card and select the doubleProperty to see the circular references.

    + +
    +
    +

    Print information about each of your basic types to 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/20-data-types/data-types-entity-attribution.yaml b/samples/excel/20-data-types/data-types-entity-attribution.yaml new file mode 100644 index 000000000..497c603ec --- /dev/null +++ b/samples/excel/20-data-types/data-types-entity-attribution.yaml @@ -0,0 +1,228 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-entities-to-table").addEventListener("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: { /* Excel.EntityPropertyType */ + "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: { /* Excel.EntityViewLayouts */ + card: { /* Excel.EntityCardLayout */ + title: { property: "Product Name" }, + sections: [ /* Excel.CardLayoutSection */ + { + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/20-data-types/data-types-entity-icons.yaml b/samples/excel/20-data-types/data-types-entity-icons.yaml new file mode 100644 index 000000000..b9bac49e6 --- /dev/null +++ b/samples/excel/20-data-types/data-types-entity-icons.yaml @@ -0,0 +1,114 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-icons").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/20-data-types/data-types-entity-values.yaml b/samples/excel/20-data-types/data-types-entity-values.yaml new file mode 100644 index 000000000..577b39f18 --- /dev/null +++ b/samples/excel/20-data-types/data-types-entity-values.yaml @@ -0,0 +1,601 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("addEntitiesToTable").addEventListener("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: "" + }, + { + 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: "" + }, + { + productID: 4, + productName: "Chef Anton's Cajun Seasoning", + supplierID: 2, + categoryID: 2, + quantityPerUnit: "48 - 6 oz jars", + unitPrice: 22, + discontinued: false, + productImage: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/chili-peppers.jpg?raw=true" + }, + { + productID: 5, + productName: "Chef Anton's Gumbo Mix", + supplierID: 2, + categoryID: 2, + quantityPerUnit: "36 boxes", + unitPrice: 21.35, + discontinued: true, + productImage: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/crustacean.jpg?raw=true" + }, + { + productID: 6, + productName: "Grandma's Boysenberry Spread", + supplierID: 3, + categoryID: 2, + quantityPerUnit: "12 - 8 oz jars", + unitPrice: 25, + discontinued: false, + productImage: "" + }, + { + productID: 7, + productName: "Uncle Bob's Organic Dried Pears", + supplierID: 3, + categoryID: 7, + quantityPerUnit: "12 - 1 lb pkgs.", + unitPrice: 30, + discontinued: false, + productImage: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/fruit.jpg?raw=true" + }, + { + productID: 8, + productName: "Northwoods Cranberry Sauce", + supplierID: 3, + categoryID: 2, + quantityPerUnit: "12 - 12 oz jars", + unitPrice: 40, + discontinued: false, + productImage: "" + }, + { + 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: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/dried-legume.jpg?raw=true" + }, + { + productID: 11, + productName: "Queso Cabrales", + supplierID: 5, + categoryID: 4, + quantityPerUnit: "1 kg pkg.", + unitPrice: 21, + discontinued: false, + productImage: "" + }, + { + productID: 12, + productName: "Queso Manchego La Pastora", + supplierID: 5, + categoryID: 4, + quantityPerUnit: "10 - 500 g pkgs.", + unitPrice: 38, + discontinued: false, + productImage: "" + }, + { + productID: 13, + productName: "Konbu", + supplierID: 6, + categoryID: 8, + quantityPerUnit: "2 kg box", + unitPrice: 6, + discontinued: false, + productImage: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/green-leaf.jpg?raw=true" + }, + { + productID: 14, + productName: "Tofu", + supplierID: 6, + categoryID: 7, + quantityPerUnit: "40 - 100 g pkgs.", + unitPrice: 23.25, + discontinued: false, + productImage: "" + }, + { + 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: "https://github.com/OfficeDev/office-js-snippets/blob/prod/.github/images/crustacean.jpg?raw=true" + }, + { + productID: 19, + productName: "Teatime Chocolate Biscuits", + supplierID: 8, + categoryID: 3, + quantityPerUnit: "10 boxes x 12 pieces", + unitPrice: 9.2, + discontinued: false, + productImage: "" + }, + { + productID: 20, + productName: "Sir Rodney's Marmalade", + supplierID: 8, + categoryID: 3, + quantityPerUnit: "30 gift boxes", + unitPrice: 81, + discontinued: false, + productImage: "" + } + ]; + + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..26fe44110 --- /dev/null +++ b/samples/excel/20-data-types/data-types-error-values.yaml @@ -0,0 +1,113 @@ +order: 4 +id: excel-data-types-error-values +name: 'Data types: Set and change error values' +description: This sample shows how to set a cell value to an error data type, and then update the value of cells that contain an error data type. +host: EXCEL +api_set: + ExcelApi: '1.16' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-busy-error").addEventListener("click", () => tryCatch(setBusyError)); + document.getElementById("change-busy-error").addEventListener("click", () => tryCatch(changeBusyError)); + + 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 changeBusyError() { + // This function checks if the used range contains a #BUSY! error, and then updates all the cells in the range that contain the error. + await Excel.run(async (context) => { + // Retrieve the Sample worksheet and the used range on that sheet. + const sheet = context.workbook.worksheets.getItemOrNullObject("Sample"); + const usedRange = sheet.getUsedRange(); + + // Load the `valuesAsJson` property for comparison. + usedRange.load("valuesAsJson"); + await context.sync(); + + // Check if the used range contains a #BUSY! error. + if (usedRange.valuesAsJson[0][0]["errorType"] == Excel.ErrorCellValueType.busy) { + // If the used range contains a #BUSY! error, load and change those values. + usedRange.load("values"); + await context.sync(); + usedRange.values = [["Process unavailable."]]; + } + + 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. The sample then checks to see if the worksheet contains a #BUSY! error, and then updates all cells that contain a #BUSY! error.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..e072889de --- /dev/null +++ b/samples/excel/20-data-types/data-types-formatted-number.yaml @@ -0,0 +1,151 @@ +order: 1 +id: excel-data-types-doubles +name: 'Data types: Formatted numbers' +description: This sample shows how to set and get formatted numbers using double data types. +host: EXCEL +api_set: + ExcelApi: '1.16' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-double-as-date").addEventListener("click", () => tryCatch(setDoubleAsDate)); + document.getElementById("set-double-as-currency").addEventListener("click", () => tryCatch(setDoubleAsCurrency)); + document.getElementById("get-double").addEventListener("click", () => tryCatch(getDouble)); + + async function setDoubleAsDate() { + // This function creates a double 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.double, + basicValue: 32889.0, + numberFormat: "m/d/yyyy" + } + ] + ]; + await context.sync(); + }); + } + + async function setDoubleAsCurrency() { + // This function creates a double 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.double, + basicValue: 12.34, + numberFormat: "$* #,##0.00" + } + ] + ]; + + await context.sync(); + }); + } + + async function getDouble() { + // 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.DoubleCellValue).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.DoubleCellValue).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 double data types to create formatted numbers.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/20-data-types/data-types-references.yaml b/samples/excel/20-data-types/data-types-references.yaml new file mode 100644 index 000000000..e139b4da9 --- /dev/null +++ b/samples/excel/20-data-types/data-types-references.yaml @@ -0,0 +1,339 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-entities-to-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..d42de34d6 --- /dev/null +++ b/samples/excel/20-data-types/data-types-web-image.yaml @@ -0,0 +1,189 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("insert-image").addEventListener("click", () => tryCatch(insertImage)); + document.getElementById("retrieve-image-info").addEventListener("click", () => tryCatch(retrieveImageInfo)); + document.getElementById("open-image").addEventListener("click", () => tryCatch(openImage)); + document.getElementById("clear-form").addEventListener("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 = (document.getElementById("url") as HTMLInputElement).value; + const imageAltText = (document.getElementById("alt-text") as HTMLInputElement).value; + 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. + (document.getElementById("url") as HTMLInputElement).value = webImageUrl; + (document.getElementById("alt-text") as HTMLInputElement).value = 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. + (document.getElementById("url") as HTMLInputElement).value = ""; + (document.getElementById("alt-text") as HTMLInputElement).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"); + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/22-data-validation/data-validation.yaml b/samples/excel/22-data-validation/data-validation.yaml new file mode 100644 index 000000000..d808941a2 --- /dev/null +++ b/samples/excel/22-data-validation/data-validation.yaml @@ -0,0 +1,184 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("positive-number").addEventListener("click", () => tryCatch(addPositiveNumberRequirement)); + document.getElementById("require-approved-location").addEventListener("click", () => tryCatch(requireApprovedName)); + document.getElementById("comment-redundancy").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/26-document/custom-properties.yaml b/samples/excel/26-document/custom-properties.yaml new file mode 100644 index 000000000..4ca88f810 --- /dev/null +++ b/samples/excel/26-document/custom-properties.yaml @@ -0,0 +1,136 @@ +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: |- + document.getElementById("set-custom-doc-property").addEventListener("click", () => tryCatch(setCustomDocProperty)); + document.getElementById("get-custom-doc-properties").addEventListener("click", () => tryCatch(getCustomDocProperties)); + document.getElementById("set-custom-worksheet-property").addEventListener("click", () => tryCatch(setCustomWorksheetProperty)); + document.getElementById("get-custom-worksheet-properties").addEventListener("click", () => tryCatch(getCustomWorksheetProperties)); + + /* To learn how to view document properties in the UI, + * see https://support.microsoft.com/office/21D604C2-481E-4379-8E54-1DD4622C6B75 + */ + + async function setCustomDocProperty() { + await Excel.run(async (context) => { + // Get the key/value pair from the task pane. + const userKey = document.getElementById("key").textContent; + const userValue = document.getElementById("value").textContent; + + // 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 = document.getElementById("key").textContent; + const userValue = document.getElementById("value").textContent; + + // 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/82-document/get-file-in-slices-async.yaml b/samples/excel/26-document/get-file-in-slices-async.yaml similarity index 68% rename from samples/excel/82-document/get-file-in-slices-async.yaml rename to samples/excel/26-document/get-file-in-slices-async.yaml index 4c616e88a..9c1cff8ca 100644 --- a/samples/excel/82-document/get-file-in-slices-async.yaml +++ b/samples/excel/26-document/get-file-in-slices-async.yaml @@ -1,14 +1,15 @@ +order: 1 id: excel-document-get-file-in-slices-async -name: Get file (using slicing) -description: Use slicing to get the byte array and base64-encoded string that represent the current document. +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.1 + ExcelApi: '1.4' script: content: |- - $("#setup").click(() => tryCatch(setup)); - $("#get-file").click(() => tryCatch(getCurrentFile)); - + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("get-file").addEventListener("click", () => tryCatch(getCurrentFile)); + document.getElementById("new-workbook-from-file").addEventListener("click", () => tryCatch(newWorkbookFromFile)); function getCurrentFile() { const sliceSize = 4096; /*Bytes*/ @@ -25,8 +26,7 @@ script: }); function onError(error: Office.Error): void { - OfficeHelpers.UI.notify('Error', error.message); - OfficeHelpers.Utilities.log(error); + console.error(error); } function onSuccess(byteArray: number[]) { @@ -35,9 +35,11 @@ script: console.log("Received the full contents of the file."); let base64string = base64js.fromByteArray(byteArray); - $('#file-contents').val(base64string).show(); + const fileContentsElement = document.getElementById("file-contents") as HTMLTextAreaElement; + fileContentsElement.value = base64string; + fileContentsElement.style.display = "block"; - OfficeHelpers.UI.notify("The base64-encoded string that represents the current document has been written to the text box below. To validate the string, use an online tool such as https://www.base64decode.org/ to decode the string, and then open the resulting file."); + 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."); } } @@ -81,10 +83,19 @@ script: } } + async function newWorkbookFromFile() { + const fileContentsElement = document.getElementById("file-contents"); + const fileContentsText = fileContentsElement.textContent; + await Excel.createWorkbook(fileContentsText).catch(function (error) { + console.error(error); + }); + } + async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let expensesTable = sheet.tables.add('A1:E1', true); expensesTable.name = "SalesTable"; @@ -99,11 +110,9 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); + createChart(context); sheet.activate(); @@ -121,7 +130,7 @@ script: chart.setPosition("A15", "F30"); chart.title.text = "Quarterly sales chart"; - chart.legend.position = "right" + chart.legend.position = "Right" chart.legend.format.fill.setSolidColor("white"); chart.dataLabels.format.font.size = 15; chart.dataLabels.format.font.color = "black"; @@ -136,42 +145,47 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 + /** 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.

    + 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: | + content: |- section.samples { margin-top: 20px; } @@ -190,22 +204,11 @@ style: } language: css libraries: |- - # Office.js https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery - https://unpkg.com/base64-js@1.2.1/base64js.min.js \ No newline at end of file + https://unpkg.com/base64-js@1.2.1/base64js.min.js diff --git a/samples/excel/89-preview-apis/document-properties.yaml b/samples/excel/26-document/properties.yaml similarity index 74% rename from samples/excel/89-preview-apis/document-properties.yaml rename to samples/excel/26-document/properties.yaml index 2de1cf2bc..e6de99c1a 100644 --- a/samples/excel/89-preview-apis/document-properties.yaml +++ b/samples/excel/26-document/properties.yaml @@ -1,17 +1,17 @@ -order: 7 +order: 2 id: excel-document-properties -name: Document properties -description: Set and get document properties. +name: Properties +description: Gets and sets document properties. host: EXCEL api_set: - ExcelApi: 1.7 + 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)); + content: |- + document.getElementById("set-doc-properties").addEventListener("click", () => tryCatch(setDocProperties)); + document.getElementById("get-doc-properties").addEventListener("click", () => tryCatch(getDocProperties)); + document.getElementById("set-custom-doc-properties").addEventListener("click", () => tryCatch(setCustomDocProperties)); + document.getElementById("get-custom-doc-properties").addEventListener("click", () => tryCatch(getCustomDocProperties)); + document.getElementById("get-count-custom-doc-properties").addEventListener("click", () => tryCatch(getCountCustomDocProperties)); async function setDocProperties() { await Excel.run(async (context) => { @@ -36,7 +36,7 @@ script: await context.sync(); - OfficeHelpers.UI.notify("Set the following document properties: title, subject, keywords, comments, category, manager, company."); + console.log("Set the following document properties: title, subject, keywords, comments, category, manager, company."); }); } @@ -52,7 +52,7 @@ script: // Write the document properties to the console. // To learn how to view document properties in the UI, - // see https://support.office.com/en-us/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75 + // see https://support.microsoft.com/office/21D604C2-481E-4379-8E54-1DD4622C6B75 console.log("Author: " + docProperties.author); console.log("Last author : " + docProperties.lastAuthor); console.log("Revision number: " + docProperties.revisionNumber); @@ -77,7 +77,7 @@ script: await context.sync(); - OfficeHelpers.UI.notify("Successfully set custom document properties."); + console.log("Successfully set custom document properties."); }); } @@ -91,7 +91,7 @@ script: // Write the custom document properties to the console. // To learn how to view document properties in the UI, - // see https://support.office.com/en-us/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75 + // see https://support.microsoft.com/office/21D604C2-481E-4379-8E54-1DD4622C6B75 console.log("Custom key : " + customProperty.key); console.log("Custom value : " + customProperty.value); @@ -117,51 +117,45 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |+ -
    + content: |- +

    This sample shows how to set and get document properties.

    - -
    +

    Try it out

    - -
    +
    - -
    +
    - -
    +
    - -
    +
    - language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -173,18 +167,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/data-change-event-details.yaml b/samples/excel/30-events/data-change-event-details.yaml new file mode 100644 index 000000000..83fb96270 --- /dev/null +++ b/samples/excel/30-events/data-change-event-details.yaml @@ -0,0 +1,109 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-handler").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/70-events/data-changed.yaml b/samples/excel/30-events/data-changed.yaml similarity index 55% rename from samples/excel/70-events/data-changed.yaml rename to samples/excel/30-events/data-changed.yaml index f6c7c14e4..4418efaff 100644 --- a/samples/excel/70-events/data-changed.yaml +++ b/samples/excel/30-events/data-changed.yaml @@ -1,40 +1,47 @@ +order: 5 id: excel-events-data-changed -name: Handle the data changed event -description: This snippet shows how to register a handler for the data-changed event. +name: Data changed event +description: Registers an event handler that runs when data is changed. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.3 + ExcelApi: '1.4' script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#register-data-changed-handler").click(() => tryCatch(registerDataChangedHandler)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-data-changed-handler").addEventListener("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 dataRange = salesTable.getDataBodyRange(); - const salesByQuarterBinding = context.workbook.bindings.add(dataRange, "range", "SalesByQuarter"); + const salesByQuarterBinding = context.workbook.bindings.add(salesTable.getRange(), "Table", "SalesByQuarter"); salesByQuarterBinding.onDataChanged.add(onSalesDataChanged); - OfficeHelpers.UI.notify("The handler is registered.", "Change the value in one of the data cells and watch this message banner. (Be sure to complete the edit by pressing Enter or clicking in another cell.)"); + console.log("The data changed handler is registered."); await context.sync(); }); } - async function onSalesDataChanged() { + async function onSalesDataChanged(eventArgs: Excel.BindingDataChangedEventArgs) { await Excel.run(async (context) => { - OfficeHelpers.UI.notify("Data was changed!!!!", ""); + 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) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); + 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"]]; @@ -61,25 +68,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | - /* Your style goes here */ + 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: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/event-column-and-row-sort.yaml b/samples/excel/30-events/event-column-and-row-sort.yaml new file mode 100644 index 000000000..8fe197053 --- /dev/null +++ b/samples/excel/30-events/event-column-and-row-sort.yaml @@ -0,0 +1,200 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-sort-handlers").addEventListener("click", () => tryCatch(registerSortHandlers)); + document.getElementById("register-row-sort-handler").addEventListener("click", () => tryCatch(registerRowSortHandler)); + document.getElementById("register-column-sort-handler").addEventListener("click", () => tryCatch(registerColumnSortHandler)); + document.getElementById("sort-q1").addEventListener("click", () => tryCatch(sortTopToBottom, "Q1")); + document.getElementById("sort-q3").addEventListener("click", () => tryCatch(sortTopToBottom, "Q3")); + document.getElementById("sort-apples").addEventListener("click", () => tryCatch(sortLeftToRight, "Apples")); + document.getElementById("sort-quinces").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/event-worksheet-single-click.yaml b/samples/excel/30-events/event-worksheet-single-click.yaml new file mode 100644 index 000000000..613db7ddb --- /dev/null +++ b/samples/excel/30-events/event-worksheet-single-click.yaml @@ -0,0 +1,70 @@ +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: |- + document.getElementById("register-click-handler").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-chart-activated.yaml b/samples/excel/30-events/events-chart-activated.yaml new file mode 100644 index 000000000..a3e824e2b --- /dev/null +++ b/samples/excel/30-events/events-chart-activated.yaml @@ -0,0 +1,174 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-onactivated-deactivated-handlers").addEventListener("click", () => tryCatch(registerActivationHandlers)); + document.getElementById("create-pie-chart").addEventListener("click", () => tryCatch(createPieChart)); + document.getElementById("create-cylinder-chart").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-chartcollection-added-activated.yaml b/samples/excel/30-events/events-chartcollection-added-activated.yaml new file mode 100644 index 000000000..09ea40ada --- /dev/null +++ b/samples/excel/30-events/events-chartcollection-added-activated.yaml @@ -0,0 +1,155 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-chartcollection-handlers").addEventListener("click", () => tryCatch(registerChartCollectionHandlers)); + document.getElementById("add-chart").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..451e5852c --- /dev/null +++ b/samples/excel/30-events/events-comment-event-handler.yaml @@ -0,0 +1,175 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("add-comment").addEventListener("click", () => tryCatch(addComment)); + document.getElementById("edit-comment").addEventListener("click", () => tryCatch(editComment)); + document.getElementById("delete-comment").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/30-events/events-disable-events.yaml b/samples/excel/30-events/events-disable-events.yaml new file mode 100644 index 000000000..80390cd6a --- /dev/null +++ b/samples/excel/30-events/events-disable-events.yaml @@ -0,0 +1,181 @@ +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: |- + document.getElementById("toggleEvents").addEventListener("click", () => tryCatch(toggleEvents)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("refreshData").addEventListener("click", () => tryCatch(addOrRefreshData)); + document.getElementById("registerSumChangedHandlers").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-formula-changed.yaml b/samples/excel/30-events/events-formula-changed.yaml new file mode 100644 index 000000000..fddc2c4a5 --- /dev/null +++ b/samples/excel/30-events/events-formula-changed.yaml @@ -0,0 +1,125 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-formula-change-handler").addEventListener("click", () => tryCatch(registerFormulaChangeHandler)); + document.getElementById("trigger-formula-change").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/events-table-changed.yaml b/samples/excel/30-events/events-table-changed.yaml similarity index 58% rename from samples/excel/89-preview-apis/events-table-changed.yaml rename to samples/excel/30-events/events-table-changed.yaml index 5dce217da..e5dfb7b9f 100644 --- a/samples/excel/89-preview-apis/events-table-changed.yaml +++ b/samples/excel/30-events/events-table-changed.yaml @@ -1,27 +1,25 @@ -order: 8 +order: 12 id: excel-events-table-changed -name: Events - Table changed -description: Add event handlers for table onDataChanged and onSelectionChanged events +name: Table events +description: Registers event handlers that run when a table is changed or selected. host: EXCEL api_set: - ExcelApi: 1.7 + ExcelApi: '1.7' script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#egister-on-data-changed-handler").click(() => tryCatch(registerOnDataChangedHandler)); - $("#change-data").click(() => tryCatch(changeData)); - $("#register-on-selection-changed-handler").click(() => tryCatch(registerOnSelectionChangedHandler)); - $("#change-selection").click(() => tryCatch(changeSelection)); - - async function registerOnDataChangedHandler() { + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-on-changed-handler").addEventListener("click", () => tryCatch(registerOnChangedHandler)); + document.getElementById("change-data").addEventListener("click", () => tryCatch(changeData)); + document.getElementById("register-on-selection-changed-handler").addEventListener("click", () => tryCatch(registerOnSelectionChangedHandler)); + document.getElementById("change-selection").addEventListener("click", () => tryCatch(changeSelection)); + + async function registerOnChangedHandler() { await Excel.run(async (context) => { let table = context.workbook.tables.getItemAt(0); - table.onDataChanged.add(onDataChange); + table.onChanged.add(onChange); await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the onDataChanged event", - "Try changing a cell value in the table, and watch the console output."); + console.log("A handler has been registered for the onChanged event"); }); } @@ -33,14 +31,13 @@ script: range.format.autofitColumns(); await context.sync(); - console.log("B7 value has been changed."); }); } - async function onDataChange(event) { + async function onChange(event) { await Excel.run(async (context) => { - console.log("Handler for table onDataChanged event has been triggered. Data changed address : " + event.address); + console.log("Handler for table onChanged event has been triggered. Data changed address: " + event.address); }); } @@ -50,9 +47,7 @@ script: table.onSelectionChanged.add(onSelectionChange); await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for table onSelectionChanged event", - "Try changing a range selection in the table, and watch the console output."); + console.log("A handler has been registered for table onSelectionChanged event"); }); } @@ -68,14 +63,15 @@ script: 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); + console.log("Handler for table onSelectionChanged event has been triggered. The new selection is: " + args.address); }); } async function setup() { await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let salesTable = sheet.tables.add('A1:E1', true); salesTable.name = "SalesTable"; @@ -90,13 +86,10 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); + sheet.activate(); await context.sync(); }); } @@ -107,58 +100,48 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 event handlers for table onDataChanged and onSelectionChanged events.

    + 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: | + content: |- section.samples { margin-top: 20px; } @@ -170,18 +153,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/events-tablecollection-changed.yaml b/samples/excel/30-events/events-tablecollection-changed.yaml similarity index 65% rename from samples/excel/89-preview-apis/events-tablecollection-changed.yaml rename to samples/excel/30-events/events-tablecollection-changed.yaml index 13cb90273..4e1d575b3 100644 --- a/samples/excel/89-preview-apis/events-tablecollection-changed.yaml +++ b/samples/excel/30-events/events-tablecollection-changed.yaml @@ -1,25 +1,23 @@ -order: 9 +order: 10 id: excel-events-tablecollection-changed -name: Events - Table collection changed -description: Add event handlers for table collection onDataChanged event +name: Table collection events +description: Registers an event handler that runs when a table collection is changed. host: EXCEL api_set: - ExcelApi: 1.7 + ExcelApi: '1.7' script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#register-on-data-changed-handler").click(() => tryCatch(registerOnDataChangedHandler)); - $("#change-data").click(() => tryCatch(changeData)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-on-changed-handler").addEventListener("click", () => tryCatch(registerOnChangedHandler)); + document.getElementById("change-data").addEventListener("click", () => tryCatch(changeData)); - async function registerOnDataChangedHandler() { + async function registerOnChangedHandler() { await Excel.run(async (context) => { let tables = context.workbook.tables; - tables.onDataChanged.add(onDataChange); + tables.onChanged.add(onChange); await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the table collection onDataChanged event", - "Try changing cell values in the tables, and watch the console output."); + console.log("A handler has been registered for the table collection onChanged event"); }); } @@ -27,7 +25,7 @@ script: await Excel.run(async (context) => { let sheet = context.workbook.worksheets.getItem("Sample"); - // Change two values to trigger two table onDataChanged events for demonstration purposes. + // 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"); @@ -40,7 +38,7 @@ script: }); } - async function onDataChange(event) { + 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); @@ -48,7 +46,7 @@ script: await context.sync(); - console.log("Handler for table collection onDataChanged event has been triggered. Data changed address : " + event.address); + 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); }); @@ -56,8 +54,9 @@ script: async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + createSalesTable(sheet); createReturnsTable(sheet); @@ -108,44 +107,37 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 an event handler for table collection onDataChanged event.

    + 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: | + content: |- section.samples { margin-top: 20px; } @@ -157,18 +149,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-workbook-activated.yaml b/samples/excel/30-events/events-workbook-activated.yaml new file mode 100644 index 000000000..40f11633c --- /dev/null +++ b/samples/excel/30-events/events-workbook-activated.yaml @@ -0,0 +1,73 @@ +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: |- + document.getElementById("register-event-handler").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml b/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml new file mode 100644 index 000000000..166a02278 --- /dev/null +++ b/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml @@ -0,0 +1,228 @@ +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: |- + document.getElementById("register-on-add-handler").addEventListener("click", () => tryCatch(registerOnAddHandler)); + document.getElementById("add-worksheet").addEventListener("click", () => tryCatch(addWorksheet)); + + document.getElementById("register-on-activate-handler").addEventListener("click", () => tryCatch(registerOnActivateHandler)); + document.getElementById("register-on-deactivate-handler").addEventListener("click", () => tryCatch(registerOnDeactivateHandler)); + document.getElementById("delete-worksheet").addEventListener("click", () => tryCatch(deleteWorksheet)); + + document.getElementById("create-setting").addEventListener("click", () => tryCatch(createSetting)); + document.getElementById("change-setting").addEventListener("click", () => tryCatch(changeSetting)); + document.getElementById("register-settings-changed-handler").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/30-events/events-worksheet-protection.yaml b/samples/excel/30-events/events-worksheet-protection.yaml new file mode 100644 index 000000000..8b83fc7cc --- /dev/null +++ b/samples/excel/30-events/events-worksheet-protection.yaml @@ -0,0 +1,105 @@ +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: |- + document.getElementById("register-event").addEventListener("click", () => tryCatch(registerEvent)); + document.getElementById("change-protection").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-events/events-worksheet.yaml b/samples/excel/30-events/events-worksheet.yaml new file mode 100644 index 000000000..77b2aee9b --- /dev/null +++ b/samples/excel/30-events/events-worksheet.yaml @@ -0,0 +1,225 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("register-on-selection-changed-handler").addEventListener("click", () => tryCatch(registerSelectionChangedHandler)); + document.getElementById("select-range").addEventListener("click", () => tryCatch(selectRange)); + + document.getElementById("register-on-changed-handler").addEventListener("click", () => tryCatch(registerOnChangedHandler)); + document.getElementById("register-onCalculated-handler").addEventListener("click", () => tryCatch(registerOnCalculatedHandler)); + document.getElementById("recalculate").addEventListener("click", () => tryCatch(recalculate)); + + document.getElementById("delete-data").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..cce99d599 --- /dev/null +++ b/samples/excel/30-events/selection-changed-events.yaml @@ -0,0 +1,149 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-event-handlers").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/30-range/copy-multiply-values.yaml b/samples/excel/30-range/copy-multiply-values.yaml deleted file mode 100644 index 868222cf4..000000000 --- a/samples/excel/30-range/copy-multiply-values.yaml +++ /dev/null @@ -1,181 +0,0 @@ -id: excel-range-copy-multiply-values -name: Copy and multiply values -description: Copy and multiply values in a range -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |+ - $("#setup").click(setup); - - $("#copy-values").click(copyValues); - $("#multiply-values-for-loop").click(multiplyValuesForLoop); - $("#multiply-values-map").click(multiplyValuesMap); - - async function copyValues() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const fromRange = sheet.getRange("B2:E5"); - fromRange.load("values"); - - await context.sync(); - - const toRange = sheet.getRange("B10:E13"); - toRange.values = fromRange.values; - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function multiplyValuesForLoop() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("C3:C5"); - range.load("values"); - - await context.sync(); - - var newValues = range.values; - for (var i = 0; i < newValues.length; i++){ - for (var j = 0; j < newValues[i].length; j++){ - newValues[i][j] = newValues[i][j] * 10; - } - } - range.values = newValues; - - range.format.autofitColumns(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function multiplyValuesMap() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const range = sheet.getRange("C3:C5"); - range.load("values"); - - await context.sync(); - - range.values = range.values.map( - (rowValues) => rowValues.map((cellValue) => cellValue * 10) - ); - - range.format.autofitColumns(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - language: typescript -template: - content: | -
    -

    This sample shows how to copy, move and multiply the values in a range using the Excel API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/create-and-use-range-intersection.yaml b/samples/excel/30-range/create-and-use-range-intersection.yaml deleted file mode 100644 index 6400c637b..000000000 --- a/samples/excel/30-range/create-and-use-range-intersection.yaml +++ /dev/null @@ -1,164 +0,0 @@ -id: excel-range-create-and-use-range-intersection -name: Create and Use an Intersection of Ranges -description: Create a an intersection of two ranges and make a chart of it. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.4 -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-sales-contest-charts").click(() => tryCatch(createContestCharts)); - - 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 method for how to - // test this code path. - reportMissingData("Asian"); - } else { - createContinentChart(sheet, "Asian", asianContestRange, "A9", "F24"); - } - - if (europeanContestRange.isNullObject) { - // See the declaration of this method 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 method, - // (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". - OfficeHelpers.UI.notify(`Missing ${continent} Data`, `There is no data for the ${continent} teams.`); - } - - async function setup() { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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, [ - ["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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
    -

    This sample shows how to use the range.getIntersectionOrNullObject method to work with an intersection of 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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/formatting.yaml b/samples/excel/30-range/formatting.yaml deleted file mode 100644 index 5716574fc..000000000 --- a/samples/excel/30-range/formatting.yaml +++ /dev/null @@ -1,136 +0,0 @@ -id: excel-range-formatting -name: Formatting -description: Format a range -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - - $("#set-font-and-fill-color").click(setFontAndFillColor); - $("#set-number-format").click(setNumberFormat); - - async function setFontAndFillColor() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setNumberFormat() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to format a range using the Excel API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/insert-delete-clear-range.yaml b/samples/excel/30-range/insert-delete-clear-range.yaml deleted file mode 100644 index 51c7ef353..000000000 --- a/samples/excel/30-range/insert-delete-clear-range.yaml +++ /dev/null @@ -1,155 +0,0 @@ -id: excel-range-insert-delete-clear-range -name: 'Insert, delete, clear range' -description: 'Insert, delete and clear a range' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - - $("#insert-range").click(insertRange); - $("#delete-range").click(deleteRange); - $("#clear-range").click(clearRange); - - async function insertRange() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function deleteRange() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function clearRange() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - let range = sheet.getRange("E2:E5"); - - range.clear(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/range-operations.yaml b/samples/excel/30-range/range-operations.yaml deleted file mode 100644 index 877304e81..000000000 --- a/samples/excel/30-range/range-operations.yaml +++ /dev/null @@ -1,181 +0,0 @@ -id: excel-range-range-operations -name: Range operations -description: 'Bounding rect, intersection, offset and resized range' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#bounding-rect").click(boundingRect); - $("#intersection").click(intersection); - $("#offset-range").click(offsetRange); - $("#resized-range").click(resizedRange); - - async function boundingRect() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("B2:D5"); - const rangeB = sheet.getRange("D4:F8"); - - const boundingRect = rangeA.getBoundingRect(rangeB); - boundingRect.format.fill.color = "Blue"; - boundingRect.getCell(0, 0).values = [["Bounding Rect"]]; - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function intersection() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("B2:D5"); - const rangeB = sheet.getRange("D4:F8"); - - const intersection = rangeA.getIntersection(rangeB); - intersection.format.fill.color = "Blue"; - intersection.getCell(0, 0).values = [["Intersection"]]; - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function offsetRange() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeA = sheet.getRange("B2:D5"); - - const offsetRange = rangeA.getOffsetRange(6, 3); - offsetRange.format.fill.color = "Blue"; - offsetRange.getCell(0, 0).values = [["OffsetRange(6,3)"]]; - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function resizedRange() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const rangeB = sheet.getRange("D4:F8"); - - const resizedRange = rangeB.getResizedRange(2, -1); - resizedRange.format.fill.color = "Blue"; - resizedRange.getCell(0, 0).values = [["ResizedRange(2,-1)"]]; - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); - - const rangeA = sheet.getRange("B2:D5"); - rangeA.format.fill.color = "green"; - rangeA.getCell(0, 0).values = [["Range A"]]; - - const rangeB = sheet.getRange("D4:F8"); - rangeB.format.fill.color = "yellow"; - rangeB.getCell(0, 0).values = [["Range B"]]; - - sheet.activate(); - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/selected-range.yaml b/samples/excel/30-range/selected-range.yaml deleted file mode 100644 index 3803a1dca..000000000 --- a/samples/excel/30-range/selected-range.yaml +++ /dev/null @@ -1,93 +0,0 @@ -id: excel-range-selected-range -name: Selected range -description: Get and set the currently selected range -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#get-selection").click(getSelection); - $("#set-selection").click(setSelection); - - async function getSelection() { - try { - 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}"`) - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setSelection() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - const range = sheet.getRange("B2:E6"); - - range.select(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/set-get-values.yaml b/samples/excel/30-range/set-get-values.yaml deleted file mode 100644 index 2d97f04cc..000000000 --- a/samples/excel/30-range/set-get-values.yaml +++ /dev/null @@ -1,292 +0,0 @@ -id: excel-range-set-get-values -name: Set and get values -description: Set and get values and formulas for a range -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - - $("#set-value").click(setValue); - $("#set-values").click(setValues); - $("#set-formula").click(setFormula); - $("#set-formulas").click(setFormulas); - $("#set-formulas-r1c1").click(setFormulasR1C1); - $("#get-values").click(getValues); - $("#get-texts").click(getTexts); - $("#get-formulas").click(getFormulas); - - async function setValue() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setValues() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setFormula() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setFormulas() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setFormulasR1C1() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getValues() { - try { - 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)); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getTexts() { - try { - 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)); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getFormulas() { - try { - 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)); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to set and get values and formulas for a range using the Excel API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/test-for-used-range.yaml b/samples/excel/30-range/test-for-used-range.yaml deleted file mode 100644 index 8de8fd2ff..000000000 --- a/samples/excel/30-range/test-for-used-range.yaml +++ /dev/null @@ -1,126 +0,0 @@ -id: excel-range-test-for-used-range -name: Test for used range -description: Create 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-empty-table").click(() => tryCatch(tryCreateChartFromEmptyTable)); - - 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) { - OfficeHelpers.UI.notify("Need Data to Make Chart", "To create a meaningful chart, 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 setup() { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to format a range using the Excel API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/30-range/working-with-dates.yaml b/samples/excel/30-range/working-with-dates.yaml deleted file mode 100644 index 70f20e225..000000000 --- a/samples/excel/30-range/working-with-dates.yaml +++ /dev/null @@ -1,162 +0,0 @@ -id: excel-range-working-with-dates -name: Working with dates -description: Setting and getting date values in a range and manipulating them using the Moment JavaScript library with the Moment-MSDate plug-in -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - declare var moment: any; - - $("#setup").click(setup); - $("#set-date-value-using-timestamp").click(setDateValueUsingTimestamp); - $("#get-date-value").click(getDateValue); - - async function setDateValueUsingTimestamp() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getDateValue() { - try { - 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}`) - - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - moment@2.18.1 - moment-msdate@0.2.2 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ 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 new file mode 100644 index 000000000..05d26ce65 --- /dev/null +++ b/samples/excel/34-named-item/create-and-remove-named-item.yaml @@ -0,0 +1,231 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("add-name-to-total").addEventListener("click", () => tryCatch(addNameToTotal)); + document.getElementById("add-name-to-header").addEventListener("click", () => tryCatch(addNameToHeader)); + document.getElementById("format-named-range").addEventListener("click", () => tryCatch(formatRangeByName)); + document.getElementById("remove-name").addEventListener("click", () => tryCatch(removeName)); + document.getElementById("list-named-items").addEventListener("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) => { + // Log all the named items in the active worksheet. + 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++) { + const namedItem : Excel.NamedItem = namedItems.items[i]; + console.log(JSON.stringify(namedItem)) + "\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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/89-preview-apis/update-named-item.yaml b/samples/excel/34-named-item/update-named-item.yaml similarity index 55% rename from samples/excel/89-preview-apis/update-named-item.yaml rename to samples/excel/34-named-item/update-named-item.yaml index e7f4fba6a..a82b5408c 100644 --- a/samples/excel/89-preview-apis/update-named-item.yaml +++ b/samples/excel/34-named-item/update-named-item.yaml @@ -1,32 +1,38 @@ -order: 12 +order: 2 id: excel-update-named-item -name: Update a named item -description: Create and then update a named item +name: Update +description: Creates and then updates a named item. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.7 + ExcelApi: '1.7' script: content: |- - $("#add-named-item").click(() => tryCatch(addNamedItem)); - $("#update-named-item").click(() => tryCatch(updateNamedItem)); - $("#setup").click(() => tryCatch(setup)); + document.getElementById("add-named-item").addEventListener("click", () => tryCatch(addNamedItem)); + document.getElementById("update-named-item").addEventListener("click", () => tryCatch(updateNamedItem)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); async function addNamedItem() { await Excel.run(async (context) => { const sheet = context.workbook.worksheets.getItem("Sample"); - // 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(); - + // Check if the named item already exists + const myNamedItem = sheet.names.getItemOrNullObject("MyRange"); + myNamedItem.load("no-properties-needed"); await context.sync(); - OfficeHelpers.UI.notify(`Just created the named item "${namedItems.items[0].name}" located here: ${namedItems.items[0].formula}`); + 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"); + } }); } @@ -37,30 +43,27 @@ script: // Get the named item const myNamedItem = sheet.names.getItemOrNullObject("MyRange"); myNamedItem.load("name, formula"); - await context.sync(); if (myNamedItem.isNullObject) { - OfficeHelpers.UI.notify(`There is no named item with the name "MyRange".`); - } else { - + 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(); - OfficeHelpers.UI.notify(`Just updated the named item "${myNamedItem.name}" -- it's now located here: ${myNamedItem.formula}`); + 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 - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + sheet.activate(); // Format the first range @@ -81,18 +84,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel JavaScript API.

    +
    +

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

    - -
    +

    Setup

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -120,17 +122,8 @@ style: } language: css libraries: |- - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/35-worksheet/activeworksheet.yaml b/samples/excel/35-worksheet/activeworksheet.yaml deleted file mode 100644 index 13a8a7086..000000000 --- a/samples/excel/35-worksheet/activeworksheet.yaml +++ /dev/null @@ -1,144 +0,0 @@ -id: excel-worksheet-activeworksheet -name: Active worksheet -description: Get and set the active worksheet -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |- - $("#setup").click(setup); - - $("#get-active-worksheet").click(getActiveWorksheet); - $("#set-active-worksheet").click(setActiveWorksheet); - - async function getActiveWorksheet() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setActiveWorksheet() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - 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(); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/35-worksheet/add-delete-rename-move-worksheet.yaml b/samples/excel/35-worksheet/add-delete-rename-move-worksheet.yaml deleted file mode 100644 index cacb0eb7f..000000000 --- a/samples/excel/35-worksheet/add-delete-rename-move-worksheet.yaml +++ /dev/null @@ -1,170 +0,0 @@ -id: excel-worksheet-add-delete-rename-move-worksheet -name: 'Add, delete, rename and move worksheet' -description: 'Add, delete, rename and change the position of a worksheet' -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#add-worksheet").click(addWorksheet); - $("#delete-worksheet").click(deleteWorksheet); - $("#rename-worksheet").click(renameWorksheet); - $("#move-worksheet").click(moveWorksheet); - - async function addWorksheet() { - try { - 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}`) - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function deleteWorksheet() { - try { - 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"); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function renameWorksheet() { - try { - await Excel.run(async (context) => { - const currentSheet = context.workbook.worksheets.getActiveWorksheet(); - - currentSheet.name = await uniqueWorksheetName(context); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - 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() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/35-worksheet/hide-unhide-worksheet.yaml b/samples/excel/35-worksheet/hide-unhide-worksheet.yaml deleted file mode 100644 index 3ba949c3c..000000000 --- a/samples/excel/35-worksheet/hide-unhide-worksheet.yaml +++ /dev/null @@ -1,117 +0,0 @@ -id: excel-worksheet-hide-unhide-worksheet -name: Hide and unhide worksheet -description: Hide and unhide a worksheet -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#hide-worksheet").click(hideWorksheet); - $("#unhide-worksheet").click(unhideWorksheet); - - async function hideWorksheet() { - try { - 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"); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function unhideWorksheet() { - try { - 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"); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - 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)); - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/35-worksheet/list-worksheets.yaml b/samples/excel/35-worksheet/list-worksheets.yaml deleted file mode 100644 index c6b6e5674..000000000 --- a/samples/excel/35-worksheet/list-worksheets.yaml +++ /dev/null @@ -1,79 +0,0 @@ -id: excel-worksheet-list-worksheets -name: List worksheets -description: List the worksheets in the workbook -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#list-worksheets").click(listWorksheets); - - async function listWorksheets() { - try { - 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); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/35-worksheet/worksheet-range-cell.yaml b/samples/excel/35-worksheet/worksheet-range-cell.yaml deleted file mode 100644 index b358358d5..000000000 --- a/samples/excel/35-worksheet/worksheet-range-cell.yaml +++ /dev/null @@ -1,179 +0,0 @@ -id: excel-worksheet-worksheet-range-cell -name: Worksheet range and cell -description: Get a range or a cell in a worksheet -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - - $("#get-used-range").click(getUsedRange); - $("#get-entire-range").click(getEntireRange); - $("#get-range").click(getRange); - $("#get-cell").click(getCell); - - async function getUsedRange() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getEntireRange() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getRange() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.Utilities.log(error); - } - } - - async function getCell() { - try { - 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}"`); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to get a range or a cell in a worksheet using the Excel API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/38-pivottable/pivottable-calculations.yaml b/samples/excel/38-pivottable/pivottable-calculations.yaml new file mode 100644 index 000000000..602a9788e --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-calculations.yaml @@ -0,0 +1,204 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("deletePivot").addEventListener("click", () => tryCatch(deletePivot)); + document.getElementById("showPercentages").addEventListener("click", () => tryCatch(showPercentages)); + document.getElementById("showDifferenceFrom").addEventListener("click", () => tryCatch(showDifferenceFrom)); + document.getElementById("showSums").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-create-and-modify.yaml b/samples/excel/38-pivottable/pivottable-create-and-modify.yaml new file mode 100644 index 000000000..a69c70a56 --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-create-and-modify.yaml @@ -0,0 +1,268 @@ +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: |- + document.getElementById("deletePivot").addEventListener("click", () => tryCatch(deletePivot)); + document.getElementById("createWithNames").addEventListener("click", () => tryCatch(createWithNames)); + document.getElementById("addRow").addEventListener("click", () => tryCatch(addRow)); + document.getElementById("removeRow").addEventListener("click", () => tryCatch(removeRow)); + document.getElementById("toggleColumn").addEventListener("click", () => tryCatch(toggleColumn)); + document.getElementById("addValues").addEventListener("click", () => tryCatch(addValues)); + document.getElementById("changeHierarchyNames").addEventListener("click", () => tryCatch(changeHierarchyNames)); + document.getElementById("changeLayout").addEventListener("click", () => tryCatch(changeLayout)); + document.getElementById("setup").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml b/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml new file mode 100644 index 000000000..7dd446c5d --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml @@ -0,0 +1,223 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("deletePivot").addEventListener("click", () => tryCatch(deletePivot)); + document.getElementById("filter").addEventListener("click", () => tryCatch(filter)); + document.getElementById("getCrateTotal").addEventListener("click", () => tryCatch(getCrateTotal)); + document.getElementById("minFunc").addEventListener("click", () => tryCatch(minFunc)); + document.getElementById("maxFunc").addEventListener("click", () => tryCatch(maxFunc)); + document.getElementById("countFunc").addEventListener("click", () => tryCatch(countFunc)); + document.getElementById("avgFunc").addEventListener("click", () => tryCatch(avgFunc)); + document.getElementById("sumFunc").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-get-pivottables.yaml b/samples/excel/38-pivottable/pivottable-get-pivottables.yaml new file mode 100644 index 000000000..2f65a1dbb --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-get-pivottables.yaml @@ -0,0 +1,190 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("get-pivottables-in-workbook").addEventListener("click", () => tryCatch(getPivotTablesInWorkbook)); + document.getElementById("get-pivottables-in-worksheet").addEventListener("click", () => tryCatch(getPivotTablesInWorksheet)); + document.getElementById("get-pivottables-in-selected-range").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-pivotfilters.yaml b/samples/excel/38-pivottable/pivottable-pivotfilters.yaml new file mode 100644 index 000000000..1d2bcef68 --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-pivotfilters.yaml @@ -0,0 +1,318 @@ +order: 5 +id: excel-pivottables-pivotfilters +name: PivotFilters +description: Applies PivotFilters to a PivotTable. +host: EXCEL +api_set: + ExcelAPI: '1.12' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("manual-filter").addEventListener("click", () => tryCatch(manualFilter)); + document.getElementById("date-filter").addEventListener("click", () => tryCatch(dateFilter)); + document.getElementById("value-filter").addEventListener("click", () => tryCatch(valueFilter)); + document.getElementById("label-filter").addEventListener("click", () => tryCatch(labelFilter)); + document.getElementById("clear-filters").addEventListener("click", () => tryCatch(clearFilters)); + document.getElementById("log-filters").addEventListener("click", () => tryCatch(logFilters)); + document.getElementById("get-crate-total").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-pivotlayout.yaml b/samples/excel/38-pivottable/pivottable-pivotlayout.yaml new file mode 100644 index 000000000..28b07c491 --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-pivotlayout.yaml @@ -0,0 +1,316 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("change-layout").addEventListener("click", () => tryCatch(changeLayout)); + document.getElementById("add-alt-text").addEventListener("click", () => tryCatch(addAltText)); + document.getElementById("add-line-spacing").addEventListener("click", () => tryCatch(addLineSpacing)); + document.getElementById("repeat-item-labels").addEventListener("click", () => tryCatch(repeatItemLabels)); + document.getElementById("toggle-field-headers").addEventListener("click", () => tryCatch(toggleFieldHeaders)); + document.getElementById("toggle-grand-totals").addEventListener("click", () => tryCatch(toggleGrandTotals)); + document.getElementById("set-empty-cell-text").addEventListener("click", () => tryCatch(setEmptyCellText)); + document.getElementById("toggle-fill-empty-cells").addEventListener("click", () => tryCatch(toggleFillEmptyCells)); + document.getElementById("toggle-auto-format").addEventListener("click", () => tryCatch(toggleAutoFormat)); + document.getElementById("toggle-preserve-formatting").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-refresh.yaml b/samples/excel/38-pivottable/pivottable-refresh.yaml new file mode 100644 index 000000000..e2975ff72 --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-refresh.yaml @@ -0,0 +1,133 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("refresh-pivottable").addEventListener("click", () => tryCatch(refreshPivotTable)); + document.getElementById("add-table-row").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-slicer.yaml b/samples/excel/38-pivottable/pivottable-slicer.yaml new file mode 100644 index 000000000..15c781177 --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-slicer.yaml @@ -0,0 +1,207 @@ +order: 9 +id: excel-pivottable-slicer +name: Slicer +description: Adds a slicer to a PivotTable. +host: EXCEL +api_set: + ExcelApi: '1.10' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-pivot-table").addEventListener("click", () => tryCatch(addPivotTable)); + document.getElementById("add-slicer").addEventListener("click", () => tryCatch(addSlicer)); + document.getElementById("format-slicer").addEventListener("click", () => tryCatch(formatSlicer)); + document.getElementById("apply-style").addEventListener("click", () => tryCatch(applyStyle)); + document.getElementById("add-filters").addEventListener("click", () => tryCatch(addFilters)); + document.getElementById("remove-filters").addEventListener("click", () => tryCatch(removeFilters)); + document.getElementById("remove-slicer").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/38-pivottable/pivottable-source-data.yaml b/samples/excel/38-pivottable/pivottable-source-data.yaml new file mode 100644 index 000000000..75014fedb --- /dev/null +++ b/samples/excel/38-pivottable/pivottable-source-data.yaml @@ -0,0 +1,127 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("get-pivottable-data-source").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/40-table/add-rows-and-columns-to-a-table.yaml b/samples/excel/40-table/add-rows-and-columns-to-a-table.yaml deleted file mode 100644 index e68fef3ed..000000000 --- a/samples/excel/40-table/add-rows-and-columns-to-a-table.yaml +++ /dev/null @@ -1,207 +0,0 @@ -id: excel-table-add-rows-and-columns-to-a-table -name: Add rows and columns -description: Add rows and columns to a table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |+ - $("#setup").click(setup); - $("#add-column").click(addColumn); - $("#add-calculated-column").click(addCalculatedColumn); - $("#add-row").click(addRow); - - async function addColumn() { - try { - await setup(); - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.columns.add(null, [ - ["Day of the Week"], - ["Saturday"], - ["Friday"], - ["Monday"], - ["Thursday"], - ["Sunday"], - ["Saturday"], - ["Monday"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function addCalculatedColumn() { - try { - await setup(); - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.columns.add(null, [ - ["Type of the Day"], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'], - ['=IF(OR((TEXT([DATE], "dddd") = "Saturday"), (TEXT([DATE], "dddd") = "Sunday")), "Weekend", "Weekday")'] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function addRow() { - try { - await setup(); - 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"], - ["1/21/2017", "COHO VINEYARD", "Restaurant", "$33"], - ["1/25/2017", "BELLOWS COLLEGE", "Education", "$350"], - ["1/28/2017", "TREY RESEARCH", "Other", "$135"], - ["1/31/2017", "BEST FOR YOU ORGANICS COMPANY", "Groceries", "$97"] - ]); - - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - /** Create a new table with sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - language: typescript -template: - content: | -
    -

    This sample shows how to add columns and rows to a table using the Excel JavaScript API.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.6.5/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/convert-range-to-table.yaml b/samples/excel/40-table/convert-range-to-table.yaml deleted file mode 100644 index 5ce7ebc20..000000000 --- a/samples/excel/40-table/convert-range-to-table.yaml +++ /dev/null @@ -1,125 +0,0 @@ -id: excel-table-convert-range-to-table -name: Convert a range to a table -description: Convert a range to a table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |+ - $("#setup").click(setup); - $("#convert-range-to-table").click(convertRangeToTable); - - async function convertRangeToTable() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a range */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample");; - - const sheet = context.workbook.worksheets.getItem("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; - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - - - - language: typescript -template: - content: | -
    -

    This sample shows how to convert a range to a table using the Excel JavaScript API.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/create-table.yaml b/samples/excel/40-table/create-table.yaml deleted file mode 100644 index 58e1eb1cc..000000000 --- a/samples/excel/40-table/create-table.yaml +++ /dev/null @@ -1,94 +0,0 @@ -id: excel-table-create-table -name: Create a table -description: Creates a table with four columns and seven rows. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#create-table").click(createTable); - - async function createTable() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to create a table using the Excel JavaScript API.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/filter-data.yaml b/samples/excel/40-table/filter-data.yaml deleted file mode 100644 index b990cd153..000000000 --- a/samples/excel/40-table/filter-data.yaml +++ /dev/null @@ -1,153 +0,0 @@ -id: excel-table-filter-data -name: Filter data -description: Filter data in a table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#filter-table").click(filterTable); - $("#clear-filters").click(clearFilters); - - async function filterTable() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function clearFilters() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - expensesTable.clearFilters(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a new table with sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

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

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/format-table.yaml b/samples/excel/40-table/format-table.yaml deleted file mode 100644 index 2b7db1456..000000000 --- a/samples/excel/40-table/format-table.yaml +++ /dev/null @@ -1,127 +0,0 @@ -id: excel-table-format-table -name: Format table -description: Format a table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#format-table").click(formatTable); - - async function formatTable() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a new table with sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to format the different components of a table using the Excel JavaScript API.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/get-data-from-table.yaml b/samples/excel/40-table/get-data-from-table.yaml deleted file mode 100644 index d119b6e83..000000000 --- a/samples/excel/40-table/get-data-from-table.yaml +++ /dev/null @@ -1,146 +0,0 @@ -id: excel-table-get-data-from-table -name: Get data from a table -description: Get data from a table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#get-data-from-table").click(getData); - - async function getData() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a new table with some sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |+ -
    -

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

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/get-visible-range-of-a-filtered-table.yaml b/samples/excel/40-table/get-visible-range-of-a-filtered-table.yaml deleted file mode 100644 index d348ba119..000000000 --- a/samples/excel/40-table/get-visible-range-of-a-filtered-table.yaml +++ /dev/null @@ -1,187 +0,0 @@ -id: excel-table-get-visible-range-of-a-filtered-table -name: Get visible range from a filtered table -description: Get visible range from a filtered table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |+ - $("#create-table").click(createTable); - $("#filter-table").click(filterTable); - $("#get-range").click(getRange); - $("#get-visible-range").click(getVisibleRange); - - async function getVisibleRange() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function getRange() { - try { - 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(); - }) - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a new table with some sample data*/ - async function createTable() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }) - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Filter the table*/ - async function filterTable() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - language: typescript -template: - content: |+ -
    -

    This sample shows how to filter the data in a table using different filter types using the Excel JavaScript API. This snippet prints the results in the console below.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/40-table/sort-data.yaml b/samples/excel/40-table/sort-data.yaml deleted file mode 100644 index 7ea0db4d0..000000000 --- a/samples/excel/40-table/sort-data.yaml +++ /dev/null @@ -1,128 +0,0 @@ -id: excel-table-sort-data -name: Sort table data -description: Sort table data -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#sort-table").click(sortTable); - - async function sortTable() { - try { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - // Queue a command to sort by most expensive transactions at the top (Amount, descending order) - var sortRange = expensesTable.getDataBodyRange(); - - sortRange.sort.apply([ - { - key: 3, - ascending: false, - }, - ]); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - /** Create a new table with sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to sort the data in a table using the Excel JavaScript API.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/42-range/cell-properties.yaml b/samples/excel/42-range/cell-properties.yaml new file mode 100644 index 000000000..acf10f685 --- /dev/null +++ b/samples/excel/42-range/cell-properties.yaml @@ -0,0 +1,186 @@ +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: |- + document.getElementById("set-cell-properties").addEventListener("click", () => tryCatch(setCellProperties)); + document.getElementById("get-cell-properties").addEventListener("click", () => tryCatch(getCellProperties)); + document.getElementById("setup").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/dynamic-arrays.yaml b/samples/excel/42-range/dynamic-arrays.yaml new file mode 100644 index 000000000..f2ab8a567 --- /dev/null +++ b/samples/excel/42-range/dynamic-arrays.yaml @@ -0,0 +1,177 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("copy-table-headers").addEventListener("click", () => tryCatch(copyTableHeaders)); + document.getElementById("apply-filter-function").addEventListener("click", () => tryCatch(applyFilterFunction)); + document.getElementById("display-spill-information").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/formatting.yaml b/samples/excel/42-range/formatting.yaml new file mode 100644 index 000000000..3e526ce4a --- /dev/null +++ b/samples/excel/42-range/formatting.yaml @@ -0,0 +1,116 @@ +order: 5 +id: excel-range-formatting +name: Formatting +description: Formats a range. +author: OfficeDev +host: EXCEL +api_set: + ExcelApi: '1.4' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("set-font-and-fill-color").addEventListener("click", () => tryCatch(setFontAndFillColor)); + document.getElementById("set-number-format").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/insert-delete-clear-range.yaml b/samples/excel/42-range/insert-delete-clear-range.yaml new file mode 100644 index 000000000..a762879be --- /dev/null +++ b/samples/excel/42-range/insert-delete-clear-range.yaml @@ -0,0 +1,129 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("insert-range").addEventListener("click", () => tryCatch(insertRange)); + document.getElementById("delete-range").addEventListener("click", () => tryCatch(deleteRange)); + document.getElementById("clear-range").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/42-range/outline.yaml b/samples/excel/42-range/outline.yaml new file mode 100644 index 000000000..f3c53898c --- /dev/null +++ b/samples/excel/42-range/outline.yaml @@ -0,0 +1,232 @@ +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: |- + document.getElementById("setup-data").addEventListener("click", () => tryCatch(setupData)); + document.getElementById("setup-totals").addEventListener("click", () => tryCatch(setupTotals)); + document.getElementById("group-rows").addEventListener("click", () => tryCatch(groupRows)); + document.getElementById("group-columns").addEventListener("click", () => tryCatch(groupColumns)); + document.getElementById("collapse-outline").addEventListener("click", () => tryCatch(collapseOutline)); + document.getElementById("expand-outline").addEventListener("click", () => tryCatch(expandOutline)); + document.getElementById("ungroup").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/precedents.yaml b/samples/excel/42-range/precedents.yaml new file mode 100644 index 000000000..d461dea31 --- /dev/null +++ b/samples/excel/42-range/precedents.yaml @@ -0,0 +1,209 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("select-first-cell").addEventListener("click", () => tryCatch(selectFirstCell)); + document.getElementById("select-second-cell").addEventListener("click", () => tryCatch(selectSecondCell)); + document.getElementById("get-direct-precedents").addEventListener("click", () => tryCatch(getDirectPrecedents)); + document.getElementById("get-all-precedents").addEventListener("click", () => tryCatch(getAllPrecedents)); + document.getElementById("clear-highlighting").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-areas.yaml b/samples/excel/42-range/range-areas.yaml new file mode 100644 index 000000000..23f24ddf6 --- /dev/null +++ b/samples/excel/42-range/range-areas.yaml @@ -0,0 +1,177 @@ +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: |- + document.getElementById("reset").addEventListener("click", () => tryCatch(reset)); + document.getElementById("color-selected-ranges").addEventListener("click", () => tryCatch(colorSelectedRanges)); + document.getElementById("color-specified-ranges").addEventListener("click", () => tryCatch(colorSpecifiedRanges)); + document.getElementById("color-all-formula-ranges").addEventListener("click", () => tryCatch(colorAllFormulaRanges)); + document.getElementById("color-all-logical-text-ranges").addEventListener("click", () => tryCatch(colorAllLogicalAndTextRanges)); + document.getElementById("read-properties-specified-ranges").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..3130ca6f8 --- /dev/null +++ b/samples/excel/42-range/range-auto-fill.yaml @@ -0,0 +1,148 @@ +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: |- + document.getElementById("setup-data").addEventListener("click", () => tryCatch(setupData)); + document.getElementById("setup-first-sums").addEventListener("click", () => tryCatch(setupFirstSums)); + document.getElementById("auto-fill-values").addEventListener("click", () => tryCatch(autoFillValues)); + document.getElementById("auto-fill-formats").addEventListener("click", () => tryCatch(autoFillFormats)); + document.getElementById("auto-fill-copy").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-cell-control.yaml b/samples/excel/42-range/range-cell-control.yaml new file mode 100644 index 000000000..430300414 --- /dev/null +++ b/samples/excel/42-range/range-cell-control.yaml @@ -0,0 +1,164 @@ +order: 23 +id: excel-cell-controls +name: Checkboxes +description: This sample shows how to add and remove checkboxes from a table. +host: EXCEL +api_set: + ExcelApi: '1.18' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-checkboxes").addEventListener("click", () => tryCatch(addCheckboxes)); + document.getElementById("change-checkbox").addEventListener("click", () => tryCatch(changeCheckbox)); + document.getElementById("remove-checkboxes").addEventListener("click", () => tryCatch(removeCheckboxes)); + document.getElementById("remove-content").addEventListener("click", () => tryCatch(removeContent)); + + async function addCheckboxes() { + // Add checkboxes to the table. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); + } + + async function changeCheckbox() { + // Change the value of the checkbox in B3. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + const range = sheet.getRange("B3"); + + range.values = [["TRUE"]]; + await context.sync(); + }); + } + + async function removeCheckboxes() { + // Remove checkboxes from the table. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the checkboxes back to boolean values. + range.control = { + type: Excel.CellControlType.empty + }; + await context.sync(); + }); + } + + async function removeContent() { + // Remove all content from the Analysis column. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Clear all the data from the second column. + range.clearOrResetContents(); + await context.sync(); + }); + } + + // Set up the sample content. + async function setup() { + await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + + const fruitTable = sheet.tables.add("A1:B1", true /*hasHeaders*/); + fruitTable.name = "FruitTable"; + + fruitTable.getHeaderRowRange().values = [["Fruit", "Analysis"]]; + + fruitTable.rows.add(null /*add at the end*/, [ + ["Apple", "TRUE"], + ["Kale", "FALSE"], + ["Orange", "TRUE"], + ["Pear", "TRUE"], + ["Mango", "TRUE"], + ["Dog", "FALSE"], + ["Strawberry", "TRUE"], + ["Chair", "FALSE"], + ["Tomato", "UNKNOWN"] /* Only boolean values will render as checkboxes. */ + ]); + + 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 creates and table and then shows how to add, remove, and change checkboxes 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-copyfrom.yaml b/samples/excel/42-range/range-copyfrom.yaml new file mode 100644 index 000000000..c48034c2c --- /dev/null +++ b/samples/excel/42-range/range-copyfrom.yaml @@ -0,0 +1,219 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("copyAll").addEventListener("click", () => tryCatch(copyAll)); + document.getElementById("copyFormula").addEventListener("click", () => tryCatch(copyFormula)); + document.getElementById("copyFormulaResult").addEventListener("click", () => tryCatch(copyFormulaResult)); + document.getElementById("copySingleAcrossRange").addEventListener("click", () => tryCatch(copySingleAcrossRange)); + document.getElementById("copyOnlyFormat").addEventListener("click", () => tryCatch(copyOnlyFormat)); + document.getElementById("skipBlanks").addEventListener("click", () => tryCatch(skipBlanks)); + document.getElementById("transpose").addEventListener("click", () => tryCatch(transpose)); + document.getElementById("move").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-dependents.yaml b/samples/excel/42-range/range-dependents.yaml new file mode 100644 index 000000000..3a7e6ccd5 --- /dev/null +++ b/samples/excel/42-range/range-dependents.yaml @@ -0,0 +1,168 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("select-D3").addEventListener("click", () => tryCatch(selectD3)); + document.getElementById("get-all-dependents").addEventListener("click", () => tryCatch(getAllDependents)); + document.getElementById("clear-highlighting").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-direct-dependents.yaml b/samples/excel/42-range/range-direct-dependents.yaml new file mode 100644 index 000000000..a4843dd2b --- /dev/null +++ b/samples/excel/42-range/range-direct-dependents.yaml @@ -0,0 +1,161 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("select-D3").addEventListener("click", () => tryCatch(selectD3)); + document.getElementById("select-E4").addEventListener("click", () => tryCatch(selectE4)); + document.getElementById("get-direct-dependents").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-find.yaml b/samples/excel/42-range/range-find.yaml new file mode 100644 index 000000000..a72156601 --- /dev/null +++ b/samples/excel/42-range/range-find.yaml @@ -0,0 +1,167 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("findText").addEventListener("click", () => tryCatch(findText)); + document.getElementById("findTextWithNullCheck").addEventListener("click", () => tryCatch(findTextWithNullCheck)); + document.getElementById("toggleComplete").addEventListener("click", () => tryCatch(toggleComplete)); + document.getElementById("toggleCase").addEventListener("click", () => tryCatch(toggleCase)); + document.getElementById("toggleDirection").addEventListener("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 searchText = (document.getElementById("searchText") as HTMLTextAreaElement).value; + const foundRange = searchRange.find(searchText, { + 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 searchText = (document.getElementById("searchText") as HTMLTextAreaElement).value; + const foundRange = searchRange.findOrNullObject(searchText, { + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-get-range-edge.yaml b/samples/excel/42-range/range-get-range-edge.yaml new file mode 100644 index 000000000..9d5a21ffe --- /dev/null +++ b/samples/excel/42-range/range-get-range-edge.yaml @@ -0,0 +1,225 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("select-E9").addEventListener("click", () => tryCatch(selectE9)); + document.getElementById("select-D8-E9").addEventListener("click", () => tryCatch(selectD8E9)); + document.getElementById("get-range-edge-left").addEventListener("click", () => tryCatch(getRangeEdgeLeft)); + document.getElementById("get-range-edge-up").addEventListener("click", () => tryCatch(getRangeEdgeUp)); + document.getElementById("get-extended-range-right").addEventListener("click", () => tryCatch(getExtendedRangeRight)); + document.getElementById("get-extended-range-down").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/89-preview-apis/range-hyperlink.yaml b/samples/excel/42-range/range-hyperlink.yaml similarity index 80% rename from samples/excel/89-preview-apis/range-hyperlink.yaml rename to samples/excel/42-range/range-hyperlink.yaml index 127e6b7f7..1b83b866e 100644 --- a/samples/excel/89-preview-apis/range-hyperlink.yaml +++ b/samples/excel/42-range/range-hyperlink.yaml @@ -1,19 +1,19 @@ -order: 13 +order: 7 id: excel-range-hyperlink -name: Range hyperlink -description: 'Create, update, and clear a hyperlink for a range.' +name: Hyperlinks +description: Creates, updates, and clears hyperlinks in a range. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.7 + ExcelApi: '1.7' script: - content: | - $("#setup").click(() => tryCatch(setup)); + content: |- + document.getElementById("setup").addEventListener("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)); + document.getElementById("create-url-hyperlinks").addEventListener("click", () => tryCatch(createUrlHyperlinks)); + document.getElementById("create-document-hyperlinks").addEventListener("click", () => tryCatch(createDocumentHyperlinks)); + document.getElementById("update-hyperlinks").addEventListener("click", () => tryCatch(updateHyperlinks)); + document.getElementById("clear-hyperlinks").addEventListener("click", () => tryCatch(clearHyperlinks)); async function createUrlHyperlinks() { await Excel.run(async (context) => { @@ -39,8 +39,6 @@ script: } await context.sync(); - - OfficeHelpers.UI.notify("Created a hyperlink to a URL for each of the products in the first table."); }); } @@ -68,8 +66,6 @@ script: } await context.sync(); - - OfficeHelpers.UI.notify("Created a hyperlink to a location in this workbook for each of the products in the second table."); }); } @@ -98,7 +94,7 @@ script: await context.sync(); - OfficeHelpers.UI.notify("Updated the hyperlink for each of the products in the first table."); + console.log("Updated the hyperlink for each of the products in the first table."); }); } @@ -116,7 +112,7 @@ script: let cellRange = productsRange.getCell(i, 0); // Clear the hyperlink. - // This eliminates the hyperlink but does not update text format. + // This removes the hyperlink but does not update text format. cellRange.clear(Excel.ClearApplyTo.hyperlinks); // Update text format. @@ -125,36 +121,29 @@ script: } await context.sync(); - - OfficeHelpers.UI.notify("Cleared all hyperlinks and reset text format."); }); } async function setup() { await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject("Orders").delete(); + const ordersSheet = context.workbook.worksheets.add("Orders"); - const ordersSheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Orders"); - - const appleSheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Apple"); + context.workbook.worksheets.getItemOrNullObject("Apple").delete(); + const appleSheet = context.workbook.worksheets.add("Apple"); - const bananaSheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Banana"); + context.workbook.worksheets.getItemOrNullObject("Banana").delete(); + const bananaSheet = context.workbook.worksheets.add("Banana"); - const melonSheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Melon"); + 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(); }); } @@ -277,42 +266,40 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    +
    +

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

    - -
    +

    Set up

    - -
    +

    Try it out

    +

    +

    +

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -324,18 +311,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..d6e4d7fe7 --- /dev/null +++ b/samples/excel/42-range/range-merged-ranges.yaml @@ -0,0 +1,131 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("create-merged-range").addEventListener("click", () => tryCatch(createMergedRange)); + document.getElementById("get-merged-range").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/range-relationships.yaml b/samples/excel/42-range/range-relationships.yaml new file mode 100644 index 000000000..9f6343134 --- /dev/null +++ b/samples/excel/42-range/range-relationships.yaml @@ -0,0 +1,254 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("bounding-rect").addEventListener("click", () => tryCatch(boundingRect)); + document.getElementById("intersection").addEventListener("click", () => tryCatch(intersection)); + document.getElementById("offset-range").addEventListener("click", () => tryCatch(offsetRange)); + document.getElementById("resized-range").addEventListener("click", () => tryCatch(resizedRange)); + document.getElementById("create-sales-contest-charts").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..b3227be4f --- /dev/null +++ b/samples/excel/42-range/range-remove-duplicates.yaml @@ -0,0 +1,125 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("delete-name").addEventListener("click", () => tryCatch(deleteName)); + document.getElementById("delete-distributor").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/range-text-orientation.yaml b/samples/excel/42-range/range-text-orientation.yaml similarity index 70% rename from samples/excel/89-preview-apis/range-text-orientation.yaml rename to samples/excel/42-range/range-text-orientation.yaml index 24de56767..60ef84009 100644 --- a/samples/excel/89-preview-apis/range-text-orientation.yaml +++ b/samples/excel/42-range/range-text-orientation.yaml @@ -1,16 +1,16 @@ -order: 14 +order: 15 id: excel-range-text-orientation -name: Range text orientation -description: Set and get the text orientation within a range +name: Text orientation +description: Gets and sets the text orientation within a range. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.7 + ExcelApi: '1.7' script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-text-orientation").click(() => tryCatch(setTextOrientation)); - $("#get-text-orientation").click(() => tryCatch(getTextOrientation)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-text-orientation").addEventListener("click", () => tryCatch(setTextOrientation)); + document.getElementById("get-text-orientation").addEventListener("click", () => tryCatch(getTextOrientation)); async function setTextOrientation() { await Excel.run(async (context) => { @@ -37,14 +37,14 @@ script: "null (which indicates that the text orientation for cells within the specified range is not uniform)" : range.format.textOrientation; - OfficeHelpers.UI.notify(`The text orientation within the range "${range.address}" is ${textOrientation}.`); + console.log(`The text orientation within the range "${range.address}" is ${textOrientation}.`); }); } async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); const data = [ ["Product", "Qty", "Unit Price", "Total Price"], @@ -69,25 +69,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | -
    + content: |- +

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

    - -
    +

    Set up

    - -
    +

    Try it out

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -113,18 +111,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/selected-range.yaml b/samples/excel/42-range/selected-range.yaml new file mode 100644 index 000000000..cc469f680 --- /dev/null +++ b/samples/excel/42-range/selected-range.yaml @@ -0,0 +1,80 @@ +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: |- + document.getElementById("get-selection").addEventListener("click", () => tryCatch(getSelection)); + document.getElementById("set-selection").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/42-range/set-get-values.yaml b/samples/excel/42-range/set-get-values.yaml new file mode 100644 index 000000000..373aa4107 --- /dev/null +++ b/samples/excel/42-range/set-get-values.yaml @@ -0,0 +1,233 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("set-value").addEventListener("click", () => tryCatch(setValue)); + document.getElementById("set-values").addEventListener("click", () => tryCatch(setValues)); + document.getElementById("set-formula").addEventListener("click", () => tryCatch(setFormula)); + document.getElementById("set-formulas").addEventListener("click", () => tryCatch(setFormulas)); + document.getElementById("set-formulas-r1c1").addEventListener("click", () => tryCatch(setFormulasR1C1)); + document.getElementById("get-values").addEventListener("click", () => tryCatch(getValues)); + document.getElementById("get-texts").addEventListener("click", () => tryCatch(getTexts)); + document.getElementById("get-formulas").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/style.yaml b/samples/excel/42-range/style.yaml similarity index 67% rename from samples/excel/89-preview-apis/style.yaml rename to samples/excel/42-range/style.yaml index 1f3f8f3e2..8ae288cd7 100644 --- a/samples/excel/89-preview-apis/style.yaml +++ b/samples/excel/42-range/style.yaml @@ -1,20 +1,20 @@ -order: 15 -id: excel-style +order: 14 +id: excel-range-style name: Style -description: 'Add, apply, get and delete styles.' +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 + 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)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-new-style").addEventListener("click", () => tryCatch(addNewStyle)); + document.getElementById("apply-new-style").addEventListener("click", () => tryCatch(applyNewStyle)); + document.getElementById("apply-built-in-style").addEventListener("click", () => tryCatch(applyBuiltInStyle)); + document.getElementById("get-style-font").addEventListener("click", () => tryCatch(getStyleFontProperties)); + document.getElementById("get-style-alignment").addEventListener("click", () => tryCatch(getStyleAlignmentProperties)); + document.getElementById("delete-new-style").addEventListener("click", () => tryCatch(deleteNewStyle)); async function addNewStyle() { await Excel.run(async (context) => { @@ -27,15 +27,15 @@ script: let newStyle = styles.getItem("Diagonal Orientation Style"); // The "Diagonal Orientation Style" properties. - newStyle.orientation = 38; - newStyle.addIndent = true; + newStyle.textOrientation = 38; + newStyle.autoIndent = true; newStyle.includeProtection = true; newStyle.shrinkToFit = true; newStyle.locked = false; await context.sync(); - OfficeHelpers.UI.notify("Successfully added a new style with diagonal orientation to the Home tab ribbon."); + console.log("Successfully added a new style with diagonal orientation to the Home tab ribbon."); }); } @@ -85,13 +85,13 @@ script: async function getStyleAlignmentProperties() { await Excel.run(async (context) => { let style = context.workbook.styles.getItem("Diagonal Orientation Style"); - style.load("orientation, horizontalAlignment, addIndent, readingOrder, wrapText, includeProtection, shrinkToFit, locked"); + style.load("textOrientation, horizontalAlignment, autoIndent, readingOrder, wrapText, includeProtection, shrinkToFit, locked"); await context.sync(); - console.log("Orientation: " + style.orientation); + console.log("Orientation: " + style.textOrientation); console.log("Horizontal alignment: " + style.horizontalAlignment); - console.log("Add indent: " + style.addIndent); + console.log("Add indent: " + style.autoIndent); console.log("Reading order: " + style.readingOrder); console.log("Wrap text: " + style.wrapText); console.log("Include protection: " + style.includeProtection); @@ -110,14 +110,15 @@ script: await context.sync(); - OfficeHelpers.UI.notify("Successfully deleted the diagonal orientation style from the Home tab ribbon."); + console.log("Successfully deleted the diagonal orientation style from the Home tab ribbon."); }); } async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); + let salesTable = sheet.tables.add('A1:E1', true); salesTable.name = "SalesTable"; @@ -132,14 +133,10 @@ script: ["Spokes", 6005, 7634, 4589, 8765] ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); sheet.activate(); - await context.sync(); }); } @@ -150,69 +147,59 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |+ -
    + 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 and Delete new style will error if the style doesn't exist (that is, hasn't been added).

    +

    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: | + content: |- section.samples { margin-top: 20px; } @@ -224,18 +211,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/42-range/used-range.yaml b/samples/excel/42-range/used-range.yaml new file mode 100644 index 000000000..78b4cb8cf --- /dev/null +++ b/samples/excel/42-range/used-range.yaml @@ -0,0 +1,141 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("try-create-chart-from-table").addEventListener("click", () => tryCatch(tryCreateChartFromEmptyTable)); + document.getElementById("fill-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-create-and-delete.yaml b/samples/excel/44-shape/shape-create-and-delete.yaml new file mode 100644 index 000000000..4a07c2b60 --- /dev/null +++ b/samples/excel/44-shape/shape-create-and-delete.yaml @@ -0,0 +1,136 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("createHexagon").addEventListener("click", () => tryCatch(createHexagon)); + document.getElementById("createTriangle").addEventListener("click", () => tryCatch(createTriangle)); + document.getElementById("createSmileyFace").addEventListener("click", () => tryCatch(createSmileyFace)); + document.getElementById("removeAll").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-get-active.yaml b/samples/excel/44-shape/shape-get-active.yaml new file mode 100644 index 000000000..e97abfc29 --- /dev/null +++ b/samples/excel/44-shape/shape-get-active.yaml @@ -0,0 +1,175 @@ +order: 7 +id: excel-shape-get-active +name: Get active shape image +description: Get an image of the active shape in your workbook. +host: EXCEL +api_set: + ExcelApi: '1.19' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-shape-over-chart").addEventListener("click", () => tryCatch(addShapeOverChart)); + document.getElementById("group-chart-shapes").addEventListener("click", () => tryCatch(groupChartShapes)); + document.getElementById("get-active-shape").addEventListener("click", () => tryCatch(getActiveShape)); + + const sheetName = "Sample"; + + async function addShapeOverChart() { + // This method adds a shape to use as a chart title. + // It positions the shape over the chart on the worksheet. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + + // Create a rectangle shape for the chart title. + const shape = sheet.shapes.addGeometricShape(Excel.GeometricShapeType.rectangle); + shape.name = "ChartTitle"; + shape.height = 20; + shape.width = 90; + shape.textFrame.textRange.text = "Sales Quantity"; + shape.textFrame.textRange.font.size = 13; + + // Get chart positioning information to place the shape correctly. + const chart = sheet.charts.getItemAt(0); + chart.load("left, top"); + chart.plotArea.load("width"); + await context.sync(); + + // Position the shape above the chart. + shape.left = chart.left + chart.plotArea.width / 2.5; + shape.top = chart.top + 10; + + await context.sync(); + }); + } + + async function groupChartShapes() { + // This method groups the new chart title shape together with the existing chart. + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + + // Get the shapes to group. + const titleShape = sheet.shapes.getItem("ChartTitle"); + const chartShape = sheet.shapes.getItem("SalesChart"); + + // Create a group from the two shapes. + const shapeGroup = sheet.shapes.addGroup([titleShape, chartShape]); + shapeGroup.name = "GroupChart"; + + await context.sync(); + }); + } + + async function getActiveShape() { + // This method gets the active shape and displays it as an image in the task pane. + await Excel.run(async (context) => { + // Get the currently active shape, if any. + const activeShape = context.workbook.getActiveShapeOrNullObject(); + + if (activeShape) { + // Convert the active shape to an image. + const shapeImage = activeShape.getAsImage(Excel.PictureFormat.png); + await context.sync(); + + // Display the image in the task pane. + const imageContainer = document.getElementById("image"); + imageContainer.innerHTML = ''; // Clear the container before adding a new image. + const imageElement = document.createElement("img"); + imageElement.src = "data:image/png;base64," + shapeImage.value; + imageContainer.appendChild(imageElement); + } else { + console.log("No active shape"); + } + }); + } + + /** Create sample data and a line chart. */ + async function setup() { + await Excel.run(async (context) => { + context.workbook.worksheets.getItemOrNullObject(sheetName).delete(); + const sheet = context.workbook.worksheets.add(sheetName); + + // Add sample data to the worksheet. + const dataRange = sheet.getRange("A1:C4"); + dataRange.values = sampleData; + + // Create a line chart with markers. + const chart = sheet.charts.add(Excel.ChartType.lineMarkers, dataRange); + chart.name = "SalesChart"; + + 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 data for the chart. */ + const sampleData = [ + ["Type", "Product A", "Product B"], + ["Q1", 15, 20], + ["Q2", 22, 15], + ["Q3", 33, 47] + ]; + language: typescript +template: + content: |- +
    +

    This sample shows how to add a shape over a chart, group that new shape together with the existing chart, and then return an image of the chart (the active shape) to this task pane.

    +
    +
    +

    Set up

    + +
    +
    +

    Try it out

    +

    Add a shape to the workbook. This button adds a shape that covers the existing chart title with a new shape that contains text.

    + +
    +
    +

    Group the new chart title together with the existing chart.

    + +
    +
    +

    Get the active shape and display it as an image in this task pane. Make sure the chart is selected.

    + +
    +
    +

    Image of the active 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-groups.yaml b/samples/excel/44-shape/shape-groups.yaml new file mode 100644 index 000000000..27d563fc6 --- /dev/null +++ b/samples/excel/44-shape/shape-groups.yaml @@ -0,0 +1,151 @@ +order: 5 +id: excel-shape-groups +name: Shape groups +description: Groups and ungroups shapes. +host: EXCEL +api_set: + ExcelApi: '1.9' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("createShapes").addEventListener("click", () => tryCatch(createShapes)); + document.getElementById("groupShapes").addEventListener("click", () => tryCatch(groupShapes)); + document.getElementById("moveGroup").addEventListener("click", () => tryCatch(moveGroup)); + document.getElementById("ungroupShapes").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-images.yaml b/samples/excel/44-shape/shape-images.yaml new file mode 100644 index 000000000..f0dbed161 --- /dev/null +++ b/samples/excel/44-shape/shape-images.yaml @@ -0,0 +1,135 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("selectedFile").addEventListener("change", () => tryCatch(readImageFromFile)); + document.getElementById("flipImage").addEventListener("click", () => tryCatch(flipImage)); + document.getElementById("getImageFormat").addEventListener("click", () => tryCatch(getImageFormat)); + document.getElementById("writeOutImageString").addEventListener("click", () => tryCatch(writeOutImageString)); + + async function readImageFromFile() { + const myFile = document.getElementById("selectedFile") as HTMLInputElement; + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-lines.yaml b/samples/excel/44-shape/shape-lines.yaml new file mode 100644 index 000000000..521fcaa91 --- /dev/null +++ b/samples/excel/44-shape/shape-lines.yaml @@ -0,0 +1,225 @@ +order: 3 +id: excel-shape-lines +name: Lines +description: Creates and modifies line shapes. +host: EXCEL +api_set: + ExcelApi: '1.9' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("createShapes").addEventListener("click", () => tryCatch(createShapes)); + document.getElementById("addStraightLine").addEventListener("click", () => tryCatch(addStraightLine)); + document.getElementById("addCurvedLine").addEventListener("click", () => tryCatch(addCurvedLine)); + document.getElementById("arrowLine").addEventListener("click", () => tryCatch(arrowLine)); + document.getElementById("diamondLine").addEventListener("click", () => tryCatch(diamondLine)); + document.getElementById("connectStraightLine").addEventListener("click", () => tryCatch(connectStraightLine)); + document.getElementById("disconnectStraightLine").addEventListener("click", () => tryCatch(disconnectStraightLine)); + document.getElementById("connectCurvedLine").addEventListener("click", () => tryCatch(connectCurvedLine)); + document.getElementById("disconnectCurvedLine").addEventListener("click", () => tryCatch(disconnectCurvedLine)); + document.getElementById("deleteLines").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-move-and-order.yaml b/samples/excel/44-shape/shape-move-and-order.yaml new file mode 100644 index 000000000..fc9b2373d --- /dev/null +++ b/samples/excel/44-shape/shape-move-and-order.yaml @@ -0,0 +1,166 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("moveLeft").addEventListener("click", () => tryCatch(moveLeft)); + document.getElementById("moveDown").addEventListener("click", () => tryCatch(moveDown)); + document.getElementById("rotate").addEventListener("click", () => tryCatch(rotate)); + document.getElementById("scaleUp").addEventListener("click", () => tryCatch(scaleUp)); + document.getElementById("moveZOrderDown").addEventListener("click", () => tryCatch(moveZOrderDown)); + document.getElementById("createShapes").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/44-shape/shape-textboxes.yaml b/samples/excel/44-shape/shape-textboxes.yaml new file mode 100644 index 000000000..62d2ab023 --- /dev/null +++ b/samples/excel/44-shape/shape-textboxes.yaml @@ -0,0 +1,141 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("createGeometricShape").addEventListener("click", () => tryCatch(createGeometricShape)); + document.getElementById("createTextbox").addEventListener("click", () => tryCatch(createTextbox)); + document.getElementById("centerTextbox").addEventListener("click", () => tryCatch(centerTextbox)); + document.getElementById("autoSizeText").addEventListener("click", () => tryCatch(autoSizeText)); + document.getElementById("deleteText").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/45-named-item/create-and-remove-named-item.yaml b/samples/excel/45-named-item/create-and-remove-named-item.yaml deleted file mode 100644 index 3b1898cc1..000000000 --- a/samples/excel/45-named-item/create-and-remove-named-item.yaml +++ /dev/null @@ -1,189 +0,0 @@ -id: excel-named-item-create-and-remove-named-item -name: Create and remove named items -description: Create and remove named items for a formula -host: EXCEL -api_set: - ExcelApi: 1.4 -script: - content: | - $("#add-name").click(addName); - $("#remove-name").click(removeName); - $("#setup").click(setup); - - async function addName() { - try { - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function removeName() { - try { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - - sheet.names.getItem("TotalAmount").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])"]]; - - await context.sync(); - - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - - let sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - 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" - } - ]; - language: typescript -template: - content: |+ -
    -

    This sample shows how to create a named item using the Excel JavaScript API. Note that this API requires the Excel 1.4 requirement set.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/45-named-item/create-and-use-named-item-for-range.yaml b/samples/excel/45-named-item/create-and-use-named-item-for-range.yaml deleted file mode 100644 index 7e6e32fe3..000000000 --- a/samples/excel/45-named-item/create-and-use-named-item-for-range.yaml +++ /dev/null @@ -1,181 +0,0 @@ -id: excel-create-and-use-named-item-for-range -name: Create and use named range item -description: Create and use named range item -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.4 -script: - content: |- - $("#add-name").click(() => tryCatch(addName)); - $("#format-named-range").click(() => tryCatch(formatRangeByName)); - $("#setup").click(() => tryCatch(setup)); - - async function addName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const headerRange = sheet.getRange("A1:E1"); - sheet.names.add("ExpensesHeader", headerRange); - const namedItems = sheet.names.load("name, type"); - - await context.sync(); - - let namedItemsList = `This workbook contains ${namedItems.items.length} named item(s):`; - for (let i = 0; i < namedItems.items.length; i++) { - namedItemsList += JSON.stringify(namedItems.items[i]); - } - OfficeHelpers.UI.notify(namedItemsList); - - await context.sync(); - }); - } - - async function formatRangeByName() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const headerRowName = sheet.names.getItem("ExpensesHeader"); - const headerRange = headerRowName.getRange(); - headerRange.format.fill.color = "red"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - const 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, // Row position (null = at the bottom) - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |+ -
    -

    This sample shows how to create a named item using the Excel JavaScript API. Note that this API requires the Excel 1.4 requirement set.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/45-named-item/create-named-item.yaml b/samples/excel/45-named-item/create-named-item.yaml deleted file mode 100644 index 2c4a0ed1e..000000000 --- a/samples/excel/45-named-item/create-named-item.yaml +++ /dev/null @@ -1,151 +0,0 @@ -id: excel-named-item-create-named-item -name: Create a named item -description: Create a named item for a formula -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.4 -script: - content: | - $("#add-name").click(addName); - - async function addName() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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.names.add("TotalAmount", "=SUM(ExpensesTable[AMOUNT])"); - - sheet.getRange("D11").values = [["=TotalAmount"]]; - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - 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" - } - ]; - language: typescript -template: - content: |+ -
    -

    This sample shows how to create a named item using the Excel JavaScript API. Note that this API requires the Excel 1.4 requirement set.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/45-named-item/list-named-items.yaml b/samples/excel/45-named-item/list-named-items.yaml deleted file mode 100644 index 92855168a..000000000 --- a/samples/excel/45-named-item/list-named-items.yaml +++ /dev/null @@ -1,76 +0,0 @@ -id: excel-named-item-list-named-items -name: List all named items in a workbook -description: List all named items in a workbook -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.3 -script: - content: |- - $("#list-named-items").click(listNamedItems); - - async function listNamedItems() { - try { - await Excel.run(async (context) => { - - const namedItems = context.workbook.names.load(); - await context.sync(); - - console.log("This workbook 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(); - }) - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
    -

    This sample shows how to list all the defined named ranges using the Excel JavaScript API. Note that this snippet lists the results in the console below.

    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file 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 new file mode 100644 index 000000000..a50c23cf2 --- /dev/null +++ b/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml @@ -0,0 +1,171 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("add-row").addEventListener("click", () => tryCatch(addRow)); + document.getElementById("add-column").addEventListener("click", () => tryCatch(addColumn)); + document.getElementById("add-calculated-column").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/convert-range-to-table.yaml b/samples/excel/46-table/convert-range-to-table.yaml new file mode 100644 index 000000000..41472f1c0 --- /dev/null +++ b/samples/excel/46-table/convert-range-to-table.yaml @@ -0,0 +1,97 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("convert-range-to-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/create-table.yaml b/samples/excel/46-table/create-table.yaml new file mode 100644 index 000000000..fefc4246e --- /dev/null +++ b/samples/excel/46-table/create-table.yaml @@ -0,0 +1,83 @@ +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: |- + document.getElementById("create-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/filter-data.yaml b/samples/excel/46-table/filter-data.yaml new file mode 100644 index 000000000..6ed0d3812 --- /dev/null +++ b/samples/excel/46-table/filter-data.yaml @@ -0,0 +1,128 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("filter-table").addEventListener("click", () => tryCatch(filterTable)); + document.getElementById("clear-filters").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/formatting.yaml b/samples/excel/46-table/formatting.yaml new file mode 100644 index 000000000..7fdd568d8 --- /dev/null +++ b/samples/excel/46-table/formatting.yaml @@ -0,0 +1,104 @@ +order: 5 +id: excel-table-formatting +name: Formatting +description: Formats a table. +author: OfficeDev +host: EXCEL +api_set: + ExcelApi: '1.4' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("format-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/get-data-from-table.yaml b/samples/excel/46-table/get-data-from-table.yaml new file mode 100644 index 000000000..04533610a --- /dev/null +++ b/samples/excel/46-table/get-data-from-table.yaml @@ -0,0 +1,117 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("get-data-from-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css 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 new file mode 100644 index 000000000..64d67cb9e --- /dev/null +++ b/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml @@ -0,0 +1,140 @@ +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: |- + document.getElementById("create-table").addEventListener("click", () => tryCatch(createTable)); + document.getElementById("filter-table").addEventListener("click", () => tryCatch(filterTable)); + document.getElementById("get-range").addEventListener("click", () => tryCatch(getRange)); + document.getElementById("get-visible-range").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/40-table/import-json-data.yaml b/samples/excel/46-table/import-json-data.yaml similarity index 62% rename from samples/excel/40-table/import-json-data.yaml rename to samples/excel/46-table/import-json-data.yaml index ec8279d18..3c6f80d16 100644 --- a/samples/excel/40-table/import-json-data.yaml +++ b/samples/excel/46-table/import-json-data.yaml @@ -1,46 +1,35 @@ +order: 8 id: excel-table-import-json-data name: Import JSON data -description: Import JSON data into a table +description: Imports JSON data into a table. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.1 + ExcelApi: '1.4' script: - content: | - $("#import-json-data").click(importJsonData); + content: |- + document.getElementById("import-json-data").addEventListener("click", () => tryCatch(importJsonData)); async function importJsonData() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("Sample"); - - let expensesTable = sheet.tables.add("A1:D1", true); + 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"]]; - expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]]; - - const newData = transactions.map(item => + const newData = transactions.map(item => [item.DATE, item.MERCHANT, item.CATEGORY, item.AMOUNT]); - expensesTable.rows.add(null, newData); + expensesTable.rows.add(null, newData); - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } + sheet.activate(); + await context.sync(); + }); } const transactions = [ @@ -111,23 +100,32 @@ script: "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 the Excel JavaScript API.

    + content: |- +
    +

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

    - -
    +

    Try it out

    - language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -139,21 +137,9 @@ style: min-width: 80px; } language: css -libraries: | - // Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/resize-table.yaml b/samples/excel/46-table/resize-table.yaml new file mode 100644 index 000000000..5b41656d6 --- /dev/null +++ b/samples/excel/46-table/resize-table.yaml @@ -0,0 +1,100 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("resize-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/46-table/sort-data.yaml b/samples/excel/46-table/sort-data.yaml new file mode 100644 index 000000000..85780b33f --- /dev/null +++ b/samples/excel/46-table/sort-data.yaml @@ -0,0 +1,111 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("sort-table").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-chart/create-column-clustered-chart.yaml b/samples/excel/50-chart/create-column-clustered-chart.yaml deleted file mode 100644 index 9e01bd667..000000000 --- a/samples/excel/50-chart/create-column-clustered-chart.yaml +++ /dev/null @@ -1,136 +0,0 @@ -order: 1 -id: excel-chart-create-column-clustered-chart -name: Column clustered chart -description: Create a column clustered chart -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: |+ - $("#setup").click(setup); - $("#create-column-clustered-chart").click(createChart); - - async function createChart() { - try { - 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("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"); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - language: typescript -template: - content: |- -
    -

    This sample shows how to create a column clustered 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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/50-chart/create-doughnut-chart.yaml b/samples/excel/50-chart/create-doughnut-chart.yaml deleted file mode 100644 index 9a05ae1c7..000000000 --- a/samples/excel/50-chart/create-doughnut-chart.yaml +++ /dev/null @@ -1,141 +0,0 @@ -order: 2 -id: excel-chart-create-doughnut-chart -name: Doughnut chart -description: Create a doughnut chart -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#create-doughnut-chart").click(createChart); - - async function createChart() { - try { - 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 = "white"; - 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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
    -

    This sample shows how to create a doughnut 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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/50-chart/create-line-chart.yaml b/samples/excel/50-chart/create-line-chart.yaml deleted file mode 100644 index a11a70396..000000000 --- a/samples/excel/50-chart/create-line-chart.yaml +++ /dev/null @@ -1,119 +0,0 @@ -order: 3 -id: excel-chart-create-line-chart -name: Line chart -description: Create a line chart -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-line-chart").click(() => tryCatch(createLineChart)); - - 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("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"; - chart.title.text = "Bicycle Parts Quarterly Sales"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to create a line 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 - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/50-chart/create-xyscatter-chart.yaml b/samples/excel/50-chart/create-xyscatter-chart.yaml deleted file mode 100644 index 621603aee..000000000 --- a/samples/excel/50-chart/create-xyscatter-chart.yaml +++ /dev/null @@ -1,116 +0,0 @@ -order: 4 -id: excel-chart-create-xyscatter-chart -name: XY scatter chart -description: Draws a basic XY scatter chart -host: EXCEL -api_set: - ExcelApi: 1.1 -script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#create-xy-scatter-chart").click(() => tryCatch(createXYScatterChart)); - - - 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("XYScatter", dataRange, "auto"); - chart.title.text = "Bicycle Parts Quarterly Sales"; - - await context.sync(); - }); - } - - async function setup() { - await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
    -

    This sample shows how to draw a basic XY scatter 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 - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/80-settings/create-get-change-delete-settings.yaml b/samples/excel/50-workbook/create-get-change-delete-settings.yaml similarity index 64% rename from samples/excel/80-settings/create-get-change-delete-settings.yaml rename to samples/excel/50-workbook/create-get-change-delete-settings.yaml index 7c8ad61a1..43fd23536 100644 --- a/samples/excel/80-settings/create-get-change-delete-settings.yaml +++ b/samples/excel/50-workbook/create-get-change-delete-settings.yaml @@ -1,15 +1,16 @@ +order: 2 id: excel-settings-create-get-change-delete-settings -name: 'Create, get, change, and delete a setting' -description: 'Show how to create, get, change, and delete settings in the document.' +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 + ExcelApi: '1.4' script: - content: | - $("#create-setting").click(() => tryCatch(createSetting)); - $("#change-setting").click(() => tryCatch(changeSetting)); - $("#delete-setting").click(() => tryCatch(deleteSetting)); + content: |- + document.getElementById("create-setting").addEventListener("click", () => tryCatch(createSetting)); + document.getElementById("change-setting").addEventListener("click", () => tryCatch(changeSetting)); + document.getElementById("delete-setting").addEventListener("click", () => tryCatch(deleteSetting)); async function createSetting() { await Excel.run(async (context) => { @@ -20,9 +21,7 @@ script: await context.sync(); - OfficeHelpers.UI.notify(`Workbook needs review: ${needsReview.value}`); - - await context.sync(); + console.log(`Workbook needs review: ${needsReview.value}`); }); } @@ -36,9 +35,9 @@ script: await context.sync(); if (needsReview.isNullObject) { - OfficeHelpers.UI.notify("The setting has been deleted"); + console.log("The setting has been deleted"); } else { - OfficeHelpers.UI.notify("The setting was not deleted"); + console.log("The setting was not deleted"); } await context.sync(); @@ -49,7 +48,7 @@ script: await Excel.run(async (context) => { const settings = context.workbook.settings; - // The settings.add function is also how you change a + // The settings.add method is also how you change a // setting. There is no settings.setItem or setting.set // method. settings.add("NeedsReview", false); @@ -58,9 +57,7 @@ script: await context.sync(); - OfficeHelpers.UI.notify(`Workbook needs review: ${needsReview.value}`); - - await context.sync(); + console.log(`Workbook needs review: ${needsReview.value}`); }); } @@ -70,18 +67,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 file.

    +
    +

    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.

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -110,21 +106,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/50-workbook/create-workbook.yaml b/samples/excel/50-workbook/create-workbook.yaml new file mode 100644 index 000000000..6516a6b05 --- /dev/null +++ b/samples/excel/50-workbook/create-workbook.yaml @@ -0,0 +1,85 @@ +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: |- + document.getElementById("create-new-blank-workbook").addEventListener("click", () => tryCatch(createBlankWorkbook)); + document.getElementById("file").addEventListener("change", () => tryCatch(createWorkbookFromExisting)); + + async function createBlankWorkbook() { + await Excel.run(async (context) => { + Excel.createWorkbook(); + }); + } + + async function createWorkbookFromExisting() { + const myFile = document.getElementById("file") as HTMLInputElement; + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..03a3df575 --- /dev/null +++ b/samples/excel/50-workbook/culture-info-date-time.yaml @@ -0,0 +1,139 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("display-date-time-setting").addEventListener("click", () => tryCatch(displayDateTimeSetting)); + document.getElementById("write-date-time-setting").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/culture-info.yaml b/samples/excel/50-workbook/culture-info.yaml new file mode 100644 index 000000000..602c6e658 --- /dev/null +++ b/samples/excel/50-workbook/culture-info.yaml @@ -0,0 +1,151 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("display-culture-info").addEventListener("click", () => tryCatch(displayCultureInfo)); + document.getElementById("write-decimal").addEventListener("click", () => tryCatch(writeDecimal)); + document.getElementById("write-big-number").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/data-protection.yaml b/samples/excel/50-workbook/data-protection.yaml new file mode 100644 index 000000000..3597277aa --- /dev/null +++ b/samples/excel/50-workbook/data-protection.yaml @@ -0,0 +1,257 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("protect-data-in-worksheet").addEventListener("click", () => tryCatch(protectDataInWorksheet)); + document.getElementById("unprotect-data-in-worksheet").addEventListener("click", () => tryCatch(unprotectDataInWorksheet)); + document.getElementById("protect-workbook-structure").addEventListener("click", () => tryCatch(protectWorkbookStructure)); + document.getElementById("unprotect-workbook-structure").addEventListener("click", () => tryCatch(unprotectWorkbookStructure)); + document.getElementById("password-protect-data-in-worksheet").addEventListener("click", () => tryCatch(passwordProtectDataInWorksheet)); + document.getElementById("password-unprotect-data-in-worksheet").addEventListener("click", () => tryCatch(passwordUnprotectDataInWorksheet)); + document.getElementById("password-protect-workbook-structure").addEventListener("click", () => tryCatch(passwordProtectWorkbookStructure)); + document.getElementById("password-unprotect-workbook-structure").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/workbook-built-in-functions.yaml b/samples/excel/50-workbook/workbook-built-in-functions.yaml new file mode 100644 index 000000000..407a00492 --- /dev/null +++ b/samples/excel/50-workbook/workbook-built-in-functions.yaml @@ -0,0 +1,120 @@ +order: 10 +id: excel-workbook-built-in-function +name: Use built-in Excel functions +description: Use the VLOOKUP and SUM built-in Excel functions. +host: EXCEL +api_set: + ExcelAPI: '1.2' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("call-vlookup").addEventListener("click", () => tryCatch(callVlookup)); + document.getElementById("nest-functions").addEventListener("click", () => tryCatch(nestFunctions)); + + async function callVlookup() { + await Excel.run(async (context) => { + // This function uses VLOOKUP to find data in the "Wrench" row on the worksheet. + let range = context.workbook.worksheets.getItem("Sample").getRange("A1:D4"); + + // Get the value in the second column in the "Wrench" row. + let unitSoldInNov = context.workbook.functions.vlookup("Wrench", range, 2, false); + unitSoldInNov.load("value"); + + await context.sync(); + console.log(" Number of wrenches sold in November = " + unitSoldInNov.value); + }); + } + + async function nestFunctions() { + await Excel.run(async (context) => { + // This function uses VLOOKUP to find data in the "Wrench" row + // on the worksheet, and then it uses SUM to combine the values. + let range = context.workbook.worksheets.getItem("Sample").getRange("A1:D4"); + + // Get the values in the second, third, and fourth columns in the "Wrench" row, + // and combine those values with SUM. + let sumOfTwoLookups = context.workbook.functions.sum( + context.workbook.functions.vlookup("Wrench", range, 2, false), + context.workbook.functions.vlookup("Wrench", range, 3, false), + context.workbook.functions.vlookup("Wrench", range, 4, false) + ); + sumOfTwoLookups.load("value"); + + await context.sync(); + console.log(" Number of wrenches sold in November, December, and January = " + sumOfTwoLookups.value); + }); + } + + 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.getHeaderRowRange().values = [["Product", "November", "December", "January"]]; + + expensesTable.rows.add(null /*add at the end*/, [ + ["Hammer", "23", "18", "17"], + ["Wrench", "12", "11", "14"], + ["Saw", "5", "15", "19"] + ]); + + sheet.getUsedRange().format.autofitColumns(); + sheet.getUsedRange().format.autofitRows(); + sheet.getRange("A1").select(); + 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 and nest the built-in Excel functions VLOOKUP and SUM. The sample uses VLOOKUP to return data, and then it uses SUM to combine data returned by VLOOKUP.

    +
    +
    +

    Setup

    + +

    Try it out

    +

    Use VLOOKUP to return the number of wrenches sold in November.

    + +

    Use VLOOKUP to find the number of wrenches sold in November, December, and January, and then use SUM to combine the three values.

    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/workbook-calculation.yaml b/samples/excel/50-workbook/workbook-calculation.yaml new file mode 100644 index 000000000..83e0dfb71 --- /dev/null +++ b/samples/excel/50-workbook/workbook-calculation.yaml @@ -0,0 +1,191 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("register-onCalculated-handler").addEventListener("click", () => tryCatch(registerOnCalculatedHandler)); + document.getElementById("recalculate-single").addEventListener("click", () => tryCatch(recalculateSingle)); + document.getElementById("recalculate-column").addEventListener("click", () => tryCatch(recalculateColumn)); + document.getElementById("manual-calculations").addEventListener("click", () => tryCatch(switchToManualCalculations)); + document.getElementById("automatic-calculations").addEventListener("click", () => tryCatch(switchToAutomaticCalculations)); + document.getElementById("force-calculation").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/workbook-get-active-cell.yaml b/samples/excel/50-workbook/workbook-get-active-cell.yaml new file mode 100644 index 000000000..a0d0c7f07 --- /dev/null +++ b/samples/excel/50-workbook/workbook-get-active-cell.yaml @@ -0,0 +1,66 @@ +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: |- + document.getElementById("get-active-cell").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml b/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml new file mode 100644 index 000000000..00559fc11 --- /dev/null +++ b/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml @@ -0,0 +1,94 @@ +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: |- + document.getElementById("file").addEventListener("change", getBase64); + document.getElementById("insert-sheets").addEventListener("click", () => tryCatch(insertSheets)); + + let externalWorkbook; + + async function getBase64() { + // Retrieve the file and set up an HTML FileReader element. + const myFile = document.getElementById("file") as HTMLInputElement; + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/50-workbook/workbook-save-and-close.yaml b/samples/excel/50-workbook/workbook-save-and-close.yaml new file mode 100644 index 000000000..bccaac16a --- /dev/null +++ b/samples/excel/50-workbook/workbook-save-and-close.yaml @@ -0,0 +1,88 @@ +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: |- + document.getElementById("saveWithPrompt").addEventListener("click", () => tryCatch(saveWithPrompt)); + document.getElementById("saveWithoutPrompt").addEventListener("click", () => tryCatch(saveWithoutPrompt)); + document.getElementById("closeWithSave").addEventListener("click", () => tryCatch(closeWithSave)); + document.getElementById("closeWithoutSave").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/active-worksheet.yaml b/samples/excel/54-worksheet/active-worksheet.yaml new file mode 100644 index 000000000..ad537a483 --- /dev/null +++ b/samples/excel/54-worksheet/active-worksheet.yaml @@ -0,0 +1,124 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("get-active-worksheet").addEventListener("click", () => tryCatch(getActiveWorksheet)); + document.getElementById("set-active-worksheet").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml b/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml new file mode 100644 index 000000000..4f31e4fcf --- /dev/null +++ b/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml @@ -0,0 +1,144 @@ +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: |- + document.getElementById("add-worksheet").addEventListener("click", () => tryCatch(addWorksheet)); + document.getElementById("delete-worksheet").addEventListener("click", () => tryCatch(deleteWorksheet)); + document.getElementById("rename-worksheet").addEventListener("click", () => tryCatch(renameWorksheet)); + document.getElementById("move-worksheet").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/89-preview-apis/worksheet-gridlines.yaml b/samples/excel/54-worksheet/gridlines.yaml similarity index 60% rename from samples/excel/89-preview-apis/worksheet-gridlines.yaml rename to samples/excel/54-worksheet/gridlines.yaml index 778c62fc6..b82a15470 100644 --- a/samples/excel/89-preview-apis/worksheet-gridlines.yaml +++ b/samples/excel/54-worksheet/gridlines.yaml @@ -1,20 +1,20 @@ -order: 16 -id: excel-gridlines -name: Worksheet gridlines -description: Hide and show gridlines in a worksheet +order: 8 +id: excel-worksheet-gridlines +name: Gridlines +description: Hides and shows a worksheet's gridlines. author: OfficeDev host: EXCEL api_set: - ExcelAPI: 1.7 + ExcelApi: '1.8' script: - content: | - $("#hide-gridlines").click(() => tryCatch(hideGridlines)); - $("#show-gridlines").click(() => tryCatch(showGridlines)); + content: |- + document.getElementById("hide-gridlines").addEventListener("click", () => tryCatch(hideGridlines)); + document.getElementById("show-gridlines").addEventListener("click", () => tryCatch(showGridlines)); async function hideGridlines() { await Excel.run(async (context) => { const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.gridlines = false; + sheet.showGridlines = false; await context.sync(); }); @@ -23,7 +23,7 @@ script: async function showGridlines() { await Excel.run(async (context) => { const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.gridlines = true; + sheet.showGridlines = true; await context.sync(); }); @@ -35,18 +35,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    + content: |- +
    +

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

    - -
    +

    Try it out

    - language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -72,18 +70,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/list-worksheets.yaml b/samples/excel/54-worksheet/list-worksheets.yaml new file mode 100644 index 000000000..6bda99375 --- /dev/null +++ b/samples/excel/54-worksheet/list-worksheets.yaml @@ -0,0 +1,72 @@ +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: |- + document.getElementById("list-worksheets").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/35-worksheet/reference-worksheets-by-relative-position.yaml b/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml similarity index 76% rename from samples/excel/35-worksheet/reference-worksheets-by-relative-position.yaml rename to samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml index 6c63b267d..b1eb24c61 100644 --- a/samples/excel/35-worksheet/reference-worksheets-by-relative-position.yaml +++ b/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml @@ -1,15 +1,16 @@ +order: 11 id: excel-worksheet-reference-worksheets-by-relative-position name: Reference worksheets by relative position -description: 'Shows how to use the worksheet shortcut methods, such as getFirst, getLast, getPrevious, and getNext.' +description: Gets a worksheet by using its relative position within the workbook. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.5 + 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)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("compare-current-and-previous-year").addEventListener("click", () => tryCatch(compareCurrentWithPreviousTax)); + document.getElementById("compare-first-and-last-year").addEventListener("click", () => tryCatch(compareFirstWithMostRecentTaxRate)); async function setup() { await Excel.run(async (context) => { @@ -73,7 +74,7 @@ script: let currentYear = currentSheet.name.substr(5, 4); let previousYear = previousYearSheet.name.substr(5, 4); - OfficeHelpers.UI.notify("Two Year Tax Due Comparison", `Tax due for ${currentYear} was ${currentTaxDueRange.text[0][0]}\nTax due for ${previousYear} was ${previousTaxDueRange.text[0][0]}`) + 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(); }); @@ -100,7 +101,7 @@ script: let firstYear = firstSheet.name.substr(5, 4); let lastYear = lastSheet.name.substr(5, 4); - OfficeHelpers.UI.notify(`Tax Rate change from ${firstYear} to ${lastYear}`, `Tax rate for ${firstYear}: ${firstTaxRateRange.text[0][0]}\nTax rate for ${lastYear}: ${lastTaxRateRange.text[0][0]}`) + 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(); }); @@ -112,25 +113,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 position with the sheet.getNext, sheet.getPrevious, sheetCollection.getFirst, and sheetCollection.getLast methods.

    + 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.

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -155,21 +154,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/worksheet-tab-color.yaml b/samples/excel/54-worksheet/tab-color.yaml similarity index 68% rename from samples/excel/89-preview-apis/worksheet-tab-color.yaml rename to samples/excel/54-worksheet/tab-color.yaml index 21234cef5..eee99f9b4 100644 --- a/samples/excel/89-preview-apis/worksheet-tab-color.yaml +++ b/samples/excel/54-worksheet/tab-color.yaml @@ -1,17 +1,17 @@ -order: 17 +order: 12 id: excel-worksheet-tab-color -name: Worksheet tab color -description: Set and get the tab color of a worksheet +name: Tab color +description: Gets and sets the tab color of a worksheet. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.7 + 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)); + content: |- + document.getElementById("set-tab-color-to-hex-color").addEventListener("click", () => tryCatch(setTabColorToHexColor)); + document.getElementById("set-tab-color-to-named-color").addEventListener("click", () => tryCatch(setTabColorToNamedColor)); + document.getElementById("set-tab-color-to-default-color").addEventListener("click", () => tryCatch(setTabColorToDefaultColor)); + document.getElementById("get-tab-color").addEventListener("click", () => tryCatch(getTabColor)); async function setTabColorToHexColor() { await Excel.run(async (context) => { @@ -48,7 +48,7 @@ script: await context.sync(); let tabColor = activeSheet.tabColor === "" ? "the default color" : activeSheet.tabColor; - OfficeHelpers.UI.notify(`Tab color for the "${activeSheet.name}" worksheet is ${tabColor}.`); + console.log(`Tab color for the "${activeSheet.name}" worksheet is ${tabColor}.`); }); } @@ -58,18 +58,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    +
    +

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

    - -
    +

    Try it out

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -101,18 +100,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/worksheet-auto-filter.yaml b/samples/excel/54-worksheet/worksheet-auto-filter.yaml new file mode 100644 index 000000000..1450908f8 --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-auto-filter.yaml @@ -0,0 +1,212 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-percent-auto-filter").addEventListener("click", () => tryCatch(addPercentAutoFilter)); + document.getElementById("add-custom-auto-filter").addEventListener("click", () => tryCatch(addCustomAutoFilter)); + document.getElementById("randomize-data").addEventListener("click", () => tryCatch(randomizeData)); + document.getElementById("refresh-auto-filter").addEventListener("click", () => tryCatch(refreshAutoFilter)); + document.getElementById("clear-single-auto-filter").addEventListener("click", () => tryCatch(clearSingleAutoFilter)); + document.getElementById("remove-all-auto-filters").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/worksheet-copy.yaml b/samples/excel/54-worksheet/worksheet-copy.yaml new file mode 100644 index 000000000..5a3cc6818 --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-copy.yaml @@ -0,0 +1,103 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("copy-worksheet").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/worksheet-find-all.yaml b/samples/excel/54-worksheet/worksheet-find-all.yaml new file mode 100644 index 000000000..5b0af2ad4 --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-find-all.yaml @@ -0,0 +1,147 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("findCompleted").addEventListener("click", () => tryCatch(findCompleted)); + document.getElementById("findDelayed").addEventListener("click", () => tryCatch(findDelayed)); + document.getElementById("findCanceled").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/89-preview-apis/worksheet-freeze-panes.yaml b/samples/excel/54-worksheet/worksheet-freeze-panes.yaml similarity index 70% rename from samples/excel/89-preview-apis/worksheet-freeze-panes.yaml rename to samples/excel/54-worksheet/worksheet-freeze-panes.yaml index 8b8b33993..de0f26ae5 100644 --- a/samples/excel/89-preview-apis/worksheet-freeze-panes.yaml +++ b/samples/excel/54-worksheet/worksheet-freeze-panes.yaml @@ -1,20 +1,20 @@ -order: 18 +order: 6 id: excel-worksheet-freeze-panes -name: Manage frozen panes in a worksheet -description: 'Freeze columns, freeze rows, freeze a range, and manage frozen panes in a worksheet.' +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 + ExcelApi: '1.7' script: - content: | - $("#setup").click(() => tryCatch(setup)); + content: |- + document.getElementById("setup").addEventListener("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)); + document.getElementById("freeze-columns").addEventListener("click", () => tryCatch(freezeColumns)); + document.getElementById("freeze-rows").addEventListener("click", () => tryCatch(freezeRows)); + document.getElementById("freeze-at").addEventListener("click", () => tryCatch(freezeAt)); + document.getElementById("get-location").addEventListener("click", () => tryCatch(getLocation)); + document.getElementById("unfreeze-all-panes").addEventListener("click", () => tryCatch(unfreezeAllPanes)); async function freezeColumns() { await Excel.run(async (context) => { @@ -58,9 +58,9 @@ script: await context.sync(); if (frozenRange.isNullObject) { - OfficeHelpers.UI.notify(`The worksheet does not contain a frozen pane.`); + console.log(`The worksheet does not contain a frozen pane.`); } else { - OfficeHelpers.UI.notify(`The address of the frozen range (cells that are frozen in the top-and-left-most pane) is "${frozenRange.address}"`); + console.log(`The address of the frozen range (cells that are frozen in the top-and-left-most pane) is "${frozenRange.address}"`); } }); } @@ -76,8 +76,8 @@ script: async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); const productsData1 = [ ["Vegetables", "Qty", "Unit Price", "Total Price"], @@ -121,45 +121,43 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    +
    +

    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: | + content: |- section.samples { margin-top: 20px; } @@ -171,18 +169,9 @@ style: min-width: 80px; } language: css -libraries: | - https://appsforoffice.microsoft.com/lib/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..f94c050d7 --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-page-layout.yaml @@ -0,0 +1,210 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("setPageBreaks").addEventListener("click", () => tryCatch(setPageBreaks)); + document.getElementById("center").addEventListener("click", () => tryCatch(center)); + document.getElementById("setBlackAndWhite").addEventListener("click", () => tryCatch(setBlackAndWhite)); + document.getElementById("setPrintTitleRow").addEventListener("click", () => tryCatch(setPrintTitleRow)); + document.getElementById("setPrintArea").addEventListener("click", () => tryCatch(setPrintArea)); + document.getElementById("changeOrientation").addEventListener("click", () => tryCatch(changeOrientation)); + document.getElementById("setZoom").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/54-worksheet/worksheet-range-cell.yaml b/samples/excel/54-worksheet/worksheet-range-cell.yaml new file mode 100644 index 000000000..5e6e7340d --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-range-cell.yaml @@ -0,0 +1,148 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + document.getElementById("get-used-range").addEventListener("click", () => tryCatch(getUsedRange)); + document.getElementById("get-entire-range").addEventListener("click", () => tryCatch(getEntireRange)); + document.getElementById("get-range").addEventListener("click", () => tryCatch(getRange)); + document.getElementById("get-cell").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/excel/54-worksheet/worksheet-visibility.yaml b/samples/excel/54-worksheet/worksheet-visibility.yaml new file mode 100644 index 000000000..15dd5af96 --- /dev/null +++ b/samples/excel/54-worksheet/worksheet-visibility.yaml @@ -0,0 +1,123 @@ +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: |- + document.getElementById("hide-worksheet").addEventListener("click", () => tryCatch(hideWorksheet)); + document.getElementById("unhide-worksheet").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/55-pivot-table/refresh-pivot-table.yaml b/samples/excel/55-pivot-table/refresh-pivot-table.yaml deleted file mode 100644 index 03b5fbbb9..000000000 --- a/samples/excel/55-pivot-table/refresh-pivot-table.yaml +++ /dev/null @@ -1,139 +0,0 @@ -id: excel-pivottable-refresh-pivot-table -name: Refresh pivot table -description: Refresh pivot table -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.3 -script: - content: |+ - $("#setup").click(setup); - $("#refresh-pivot-table").click(refreshPivotTable); - - async function refreshPivotTable() { - await Excel.run(async (context) => { - try { - const sheet = context.workbook.worksheets.getItem("Sample"); - - // First, force a change in the table data by setting the value of Amount in the third row to $500 - const expensesTable = sheet.tables.getItem("ExpensesTable"); - - const range = expensesTable.columns.getItem("Amount").getDataBodyRange().getRow(2).values = [["$500"]]; - - await sheet.context.sync(); - - // Now, refresh the pivot table. This should pick up our changes made with code as well as any changes made in the UI - const expensesPivot = sheet.pivotTables.getItem("PivotTable1"); - - expensesPivot.refresh(); - - await context.sync(); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - }) - } - - /** Create a new table with some sample data */ - async function setup() { - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "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"] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - language: typescript -template: - content: |+ -
    -

    This sample shows how to refresh a PivotTable using the Excel JavaScript API. Note that this API requires the Excel 1.3 requirement set.

    -
    - -
    -

    Set up

    - -

    Next, click inside the table and insert a PivotTable using the Insert menu in Excel, specifying the following options.

    -

      -
    1. Choose Existing sheet.
    2. -
    3. Specify A15 as the location.
    4. -
    5. Select the Amount and Category columns.
    6. -
    7. Make sure the name of the PivotTable in the UI matches with the name specified in code.
    8. -
    -
    - -
    -

    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: | - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/70-events/selection-changed.yaml b/samples/excel/70-events/selection-changed.yaml deleted file mode 100644 index f721d3cbf..000000000 --- a/samples/excel/70-events/selection-changed.yaml +++ /dev/null @@ -1,137 +0,0 @@ -id: excel-events-selection-changed -name: Selection Changed -description: Add and remove an event handler on the selection changed event -host: EXCEL -api_set: - ExcelApi: 1.2 -script: - content: | - $("#add-event-handler").click(addEventHandler); - $("#remove-last-event-handler").click(removeLastEventHandler); - $("#remove-all-event-handlers").click(removeAllEventHandlers); - - let eventHandlers: Array<{ - workbook: Excel.Workbook, - handler: OfficeExtension.EventHandlerResult - }> = []; - - function addEventHandler() { - tryCatch(() => Excel.run(async (context) => { - let workbook = context.workbook; - let handler = workbook.onSelectionChanged.add(onSelectionChanged); - eventHandlers.push({ workbook, handler }); - - await context.sync(); - - OfficeHelpers.UI.notify("Event handler added", - "Try changing the selection, and watch the console output."); - })); - } - - async function removeLastEventHandler() { - let lastEventHandler = eventHandlers.pop(); - if (!lastEventHandler) { - OfficeHelpers.UI.notify("No event handlers added"); - return; - } - - let workbook = lastEventHandler.workbook; - tryCatch(() => Excel.run(workbook, async (context) => { - lastEventHandler.handler.remove(); - await context.sync(); - })); - } - - async function removeAllEventHandlers() { - if (eventHandlers.length === 0) { - OfficeHelpers.UI.notify("No event handlers added"); - return; - } - - tryCatch(async () => { - while (eventHandlers.length > 0) { - const lastEventHandler = eventHandlers.pop(); - await Excel.run(lastEventHandler.workbook, async (context) => { - lastEventHandler.handler.remove(); - await context.sync(); - }); - } - - OfficeHelpers.UI.notify("All event handlers removed"); - }) - } - - async function onSelectionChanged() { - tryCatch(() => Excel.run(async (context) => { - const range = context.workbook.getSelectedRange(); - range.format.fill.color = "yellow"; - range.load("address"); - - await context.sync(); - - console.log(`New selection is ${range.address}`); - })); - } - - - /** Default helper for invoking an action and handling errors. */ - async function tryCatch(callback: () => OfficeExtension.IPromise) { - try { - await callback(); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to add and remove an event handler on the selection changed event using the Excel JavaScript API.

    -
    - -
    -

    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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/70-events/setting-changed.yaml b/samples/excel/70-events/setting-changed.yaml deleted file mode 100644 index 30d76097b..000000000 --- a/samples/excel/70-events/setting-changed.yaml +++ /dev/null @@ -1,142 +0,0 @@ -id: excel-events-setting-changed -name: Handle the settings-changed event -description: This snippet shows how to register a handler for the SettingsChanged event. -author: OfficeDev -host: EXCEL -api_set: - ExcelApi: 1.4 -script: - content: | - $("#create-setting").click(() => tryCatch(createSetting)); - $("#change-setting").click(() => tryCatch(changeSetting)); - $("#register-settings-changed-handler").click(() => tryCatch(registerSettingsChangedHandler)); - - 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(); - - OfficeHelpers.UI.notify("Setting added", `Setting value is: ${needsReview.value}`); - - await context.sync(); - }); - } - - async function registerSettingsChangedHandler() { - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.onSettingsChanged.add(onChangedSetting); - OfficeHelpers.UI.notify("Handler registered", ""); - - await context.sync(); - }); - } - - 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(); - - OfficeHelpers.UI.notify("Setting changed", `The new value is: ${changedSetting.value}`); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - } - } - - async function changeSetting() { - - // The settings.add function 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: |- -
    -

    This sample shows how to register and use a handler for the SettingsChanged event.

    -
    - -
    -

    Try it out

    -

    Press the button to create and display a setting.

    - -

    Press the button to register a settings-changed handler.

    - -

    Press the button to change a setting and trigger the 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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/89-preview-apis/chart-axis.yaml b/samples/excel/89-preview-apis/chart-axis.yaml deleted file mode 100644 index 364c853b2..000000000 --- a/samples/excel/89-preview-apis/chart-axis.yaml +++ /dev/null @@ -1,82 +0,0 @@ -order: 1 -id: excel-chart-axis -name: Chart axis -description: 'Get, set, and remove axis unit, label and title in a chart.' -host: EXCEL -api_set: - ExcelAPI: 1.7 -script: - content: "$(\"#setup\").click(() => tryCatch(setup));\n$(\"#get-axis-unit\").click(() => tryCatch(getAxisUnit));\n$(\"#change-axis-unit\").click(() => tryCatch(changeAxisUnit));\n$(\"#remove-axis-label\").click(() => tryCatch(removeAxisLabel));\n$(\"#show-axis-label\").click(() => tryCatch(showAxisLabel));\n$(\"#set-axis-title\").click(() => tryCatch(setAxisTitle));\n \nasync function getAxisUnit() {\n await Excel.run(async (context) => {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n\n let chart = sheet.charts.getItemAt(0);\n let categoryAxis = chart.axes.categoryAxis;\n let valueAxis = chart.axes.valueAxis;\n\n // Load to get display unit.\n valueAxis.load(\"displayUnit\");\n \n await context.sync();\n\n OfficeHelpers.UI.notify(\"The vertical axis display unit is: \" + valueAxis.displayUnit);\n });\n}\n\nasync function changeAxisUnit() {\n await Excel.run(async (context) => {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n\n let chart = sheet.charts.getItemAt(0);\n let axis = chart.axes.valueAxis;\n\n // Set display unit.\n axis.displayUnit = \"Hundreds\";\n\n await context.sync();\n });\n}\n\nasync function removeAxisLabel() {\n await Excel.run(async (context) => {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n\_\n let chart = sheet.charts.getItemAt(0);\n let axis = chart.axes.valueAxis;\n\n // Remove display unit.\n axis.showDisplayUnitLabel = false;\n\n await context.sync();\n });\n}\n\nasync function showAxisLabel() {\n await Excel.run(async (context) => {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n\n let chart = sheet.charts.getItemAt(0);\n let axis = chart.axes.valueAxis;\n\n // Show display unit.\n axis.showDisplayUnitLabel = true;\n await context.sync();\n });\n}\n\nasync function setAxisTitle() {\n await Excel.run(async (context) => {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n\n let chart = sheet.charts.getItemAt(0);\n let categoryAxis = chart.axes.categoryAxis;\n\n // Set horizontal axis title.\n categoryAxis.title.text = \"Bicycle parts\";\n\n let valueAxis = chart.axes.valueAxis;\n\n // Set vertical axis title.\n valueAxis.title.text = \"Number of items\";\n \n // Show small gridlines.\n valueAxis.minorGridlines.visible = true;\n\n categoryAxis.title.load(\"text\");\n valueAxis.load(\"text\");\n valueAxis.minorGridlines.load(\"visible\");\n\n await context.sync();\n\n console.log(\"The category axis title is: \" + categoryAxis.title.text);\n console.log(\"The value axis title is: \" + valueAxis.title.text);\n \n OfficeHelpers.UI.notify(\"The minor gridlines visibility is set to: \" + valueAxis.minorGridlines.visible);\n });\n}\n\nasync function setup() {\n await Excel.run(async (context) => {\n const sheet = await OfficeHelpers.ExcelUtilities\n .forceCreateSheet(context.workbook, \"Sample\");\n let expensesTable = sheet.tables.add('A1:E1', true);\n expensesTable.name = \"SalesTable\";\n\n expensesTable.getHeaderRowRange().values = [[\"Product\", \"Qtr1\", \"Qtr2\", \"Qtr3\", \"Qtr4\"]];\n\n expensesTable.rows.add(null, [\n [\"Frames\", 5000, 7000, 6544, 4377],\n [\"Saddles\", 400, 323, 276, 651],\n [\"Brake levers\", 12000, 8766, 8456, 9812],\n [\"Chains\", 1550, 1088, 692, 853],\n [\"Mirrors\", 225, 600, 923, 544],\n [\"Spokes\", 6005, 7634, 4589, 8765]\n ]);\n\n if (Office.context.requirements.isSetSupported(\"ExcelApi\", 1.7)) {\n sheet.getUsedRange().format.autofitColumns();\n sheet.getUsedRange().format.autofitRows();\n }\n\n const chart = createChart(context);\n addVerticalAxisLabel(chart);\n sheet.activate();\n\n await context.sync();\n });\n}\n\nfunction createChart(context: Excel.RequestContext) {\n const sheet = context.workbook.worksheets.getItem(\"Sample\");\n const salesTable = sheet.tables.getItem(\"SalesTable\");\n\n const dataRange = salesTable.getRange();\n\n let chart = sheet.charts.add(\"ColumnClustered\", dataRange, Excel.ChartSeriesBy.columns);\n\n chart.setPosition(\"A15\", \"F30\");\n chart.title.text = \"Quarterly sales chart\";\n chart.legend.position = \"right\"\n chart.legend.format.fill.setSolidColor(\"white\");\n chart.dataLabels.format.font.size = 15;\n chart.dataLabels.format.font.color = \"black\";\n let points = chart.series.getItemAt(0).points;\n\n return chart;\n}\n\nfunction addVerticalAxisLabel(chart: Excel.Chart) {\n let axis = chart.axes.valueAxis;\n axis.displayUnit = \"Thousands\";\n}\n\n/** Default helper for invoking an action and handling errors. */\nasync function tryCatch(callback) {\n try {\n await callback();\n }\n catch (error) {\n OfficeHelpers.UI.notify(error);\n OfficeHelpers.Utilities.log(error);\n }\n}\n" - 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/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/89-preview-apis/chart-series.yaml b/samples/excel/89-preview-apis/chart-series.yaml deleted file mode 100644 index 662581296..000000000 --- a/samples/excel/89-preview-apis/chart-series.yaml +++ /dev/null @@ -1,180 +0,0 @@ -order: 4 -id: excel-chart-series -name: Chart series -description: 'Add, set, and delete a 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)); - $("#set-series-value").click(() => tryCatch(setSeriesValue)); - - 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"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - let series = seriesCollection.getItemAt(0); - - // Delete the first series. - series.delete(); - - await context.sync(); - }); - } - - async function setSeriesValue() { - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - - // Add new series. - let series = seriesCollection.add("New Product"); - let values = sheet.getRange("E2:E7"); - - // Set the vertical values for the series. - series.setValues(values); - seriesCollection.load("count"); - - await context.sync(); - - OfficeHelpers.UI.notify("Number of series = " + seriesCollection.count); - }); - } - - async function setup() { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - language: typescript -template: - content: | -
    -

    This sample shows how to add, set, 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/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/89-preview-apis/events-worksheet-activated.yaml b/samples/excel/89-preview-apis/events-worksheet-activated.yaml deleted file mode 100644 index d08e8697f..000000000 --- a/samples/excel/89-preview-apis/events-worksheet-activated.yaml +++ /dev/null @@ -1,173 +0,0 @@ -order: 10 -id: excel-events-worksheet-activated -name: Events - Worksheet activated -description: Add event handlers for worksheet onActivated and onDeactivated events -host: EXCEL -api_set: - ExcelApi: 1.7 -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#register-on-activate-handler").click(() => tryCatch(registerOnActivateHandler)); - $("#register-on-deactivate-handler").click(() => tryCatch(registerOnDeactivateHandler)); - $("#delete-worksheet").click(() => tryCatch(deleteWorksheet)); - - async function registerOnActivateHandler() { - await Excel.run(async (context) => { - let sheets = context.workbook.worksheets; - sheets.onActivated.add(onActivate); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnActivate event", - "Try selecting a different worksheet, and watch the console output."); - }); - } - - 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(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnDeactivate event", - "Try selecting a different worksheet, and watch the console output."); - }); - } - - 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) => { - 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 setup() { - await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - - language: typescript -template: - content: | -
    -

    This sample shows how to add event handlers for worksheet onActivated and onDeactivated events.

    -
    - -
    -

    Set up

    - -
    - -
    -

    Try it out

    - -
    - -
    - -
    - -
    -

    Deleting the current worksheet triggers the deactivate event and the activate event for the preceding 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/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/89-preview-apis/events-worksheet-changed.yaml b/samples/excel/89-preview-apis/events-worksheet-changed.yaml deleted file mode 100644 index b24f88a7d..000000000 --- a/samples/excel/89-preview-apis/events-worksheet-changed.yaml +++ /dev/null @@ -1,187 +0,0 @@ -order: 11 -id: excel-events-worksheet-changed -name: Events - Worksheet changed -description: Add event handlers for worksheet onDataChanged and onAdded events -host: EXCEL -api_set: - ExcelApi: 1.7 -script: - content: |+ - $("#setup").click(() => tryCatch(setup)); - $("#register-on-data-changed-handler").click(() => tryCatch(registerOnDataChangedHandler)); - $("#data-changed").click(() => tryCatch(changeData)); - $("#register-on-add-handler").click(() => tryCatch(registerOnAddHandler)); - $("#add-worksheet").click(() => tryCatch(addWorksheet)); - - async function registerOnDataChangedHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onDataChanged.add(onDataChange); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the onDataChanged event."); - }); - } - - 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 onDataChange(event) { - await Excel.run(async (context) => { - console.log("Handler for worksheet onDataChanged event has been triggered. Data changed address : " + event.address); - }); - } - - async function registerOnAddHandler() { - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets; - sheet.onAdded.add(onWorksheetAdd); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnAdded event", - "Try adding a worksheet, and watch the console output."); - }); - } - - 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 setup() { - await Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "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] - ]); - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.7)) { - 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) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - - language: typescript -template: - content: |+ -
    -

    This sample shows how to add event handlers for worksheet onDataChanged and onAdded events.

    -
    - -
    -

    Set up

    - -
    - -
    -

    Try it out

    - -
    - -
    -

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

    - -
    - -
    - -
    - -
    -

    Adding a worksheet triggers the on added event. You can add a worksheet 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/beta/hosted/office.js - https://appsforoffice.microsoft.com/lib/beta/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/excel/90-just-for-fun/gradient.yaml b/samples/excel/90-just-for-fun/gradient.yaml deleted file mode 100644 index 74dd5ef13..000000000 --- a/samples/excel/90-just-for-fun/gradient.yaml +++ /dev/null @@ -1,217 +0,0 @@ -order: 1 -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.2 -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) { - OfficeHelpers.Utilities.log(error); - } - - $drawButton.prop("disabled", false); - } - - /** Helper function to do the actual gradient-drawing */ - async function drawGradientHelper(context: Excel.RequestContext) { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Gradient", true /*clearOnly*/); - - sheet.getRange().format.set({ - rowHeight: 15, - columnWidth: 15, - fill: { - color: "#1e1e1e" - } - }); - - let originalSize = parseInt($('#size').val()); - - // Create a 2D in-memory array to hold the colors - const colors2D = Array(originalSize); - for (let row = 0; row < originalSize; row++) { - colors2D[row] = Array(originalSize); - } - - fillInColors(colors2D, originalSize); - - let range = sheet.getCell(1, 1).getResizedRange( - originalSize - 1, originalSize - 1); - for (let row = 0; row < originalSize; row++) { - for (let col = 0; col < originalSize; col++) { - range.getCell(row, col).format.fill.color = - colors2D[row][col]; - } - } - - sheet.activate(); - await context.sync(); - } - - function fillInColors(colors2D: string[][], size: number) { - 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(); - } - } - } - - /** 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: |- - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.6.3/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers/dist/office.helpers.d.ts - @types/jquery - - tinycolor2@1.4.1/tinycolor.js - @types/tinycolor2 - spectrum-colorpicker@1.8.0/spectrum.js - spectrum-colorpicker@1.8.0/spectrum.css - @types/spectrum \ No newline at end of file diff --git a/samples/excel/90-just-for-fun/patterns.yaml b/samples/excel/90-just-for-fun/patterns.yaml deleted file mode 100644 index 15d485ee0..000000000 --- a/samples/excel/90-just-for-fun/patterns.yaml +++ /dev/null @@ -1,208 +0,0 @@ -order: 2 -id: excel-just-for-fun-patterns -name: Colorful Patterns -description: Shows how to use range formatting to draw interesting pattern. Contributed by Alexander Zlatkovski -author: AlexanderZlatkovski -host: EXCEL -api_set: - ExcelApi: 1.2 -script: - content: |- - $("#squares").click(drawSquares); - $("#spiral").click(drawSpiral); - $("#decoration").click(drawDecoration); - - async function drawSquares() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Patterns", true /*clearOnly*/); - sheet.activate(); - formatBackground(sheet); - - const size = parseInt($("#size").val()); - - for (var 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); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - - async function drawSpiral() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Patterns", true /*clearOnly*/); - sheet.activate(); - formatBackground(sheet); - - const size = Math.floor(parseInt($("#size").val()) / 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); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function drawDecoration() { - try { - await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Patterns", true /*clearOnly*/); - sheet.activate(); - formatBackground(sheet); - - const size = Math.floor(parseInt($("#size").val()) / 2); - - for (var 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); - - var 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); - } - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - 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"; - } - 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: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file diff --git a/samples/excel/90-scenarios/currency-converter.yaml b/samples/excel/90-scenarios/currency-converter.yaml new file mode 100644 index 000000000..70f09cc0f --- /dev/null +++ b/samples/excel/90-scenarios/currency-converter.yaml @@ -0,0 +1,187 @@ +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 = {}; + + document.getElementById("convert").addEventListener("click", () => tryCatch(convert)); + document.getElementById("setup").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + moment@2.18.1 + moment-msdate@0.2.2 diff --git a/samples/excel/88-common-patterns/multiple-property-set.yaml b/samples/excel/90-scenarios/multiple-property-set.yaml similarity index 72% rename from samples/excel/88-common-patterns/multiple-property-set.yaml rename to samples/excel/90-scenarios/multiple-property-set.yaml index 9a5f0a5f8..56c6c6e30 100644 --- a/samples/excel/88-common-patterns/multiple-property-set.yaml +++ b/samples/excel/90-scenarios/multiple-property-set.yaml @@ -1,15 +1,16 @@ -id: excel-multiple-property-set -name: Multiple Property Set -description: Setting multiple properties at once with the rich API object set() method. +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 + ExcelApi: '1.4' script: - content: | - $("#setup").click(() => tryCatch(setup)); - $("#set-multiple-properties-with-object").click(() => tryCatch(setMultiplePropertiesWithObject)); - $("#copy-properties-from-range").click(() => tryCatch(copyPropertiesFromRange)); + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-multiple-properties-with-object").addEventListener("click", () => tryCatch(setMultiplePropertiesWithObject)); + document.getElementById("copy-properties-from-range").addEventListener("click", () => tryCatch(copyPropertiesFromRange)); async function setMultiplePropertiesWithObject() { await Excel.run(async (context) => { @@ -51,8 +52,8 @@ script: async function setup() { await Excel.run(async (context) => { - const sheet = await OfficeHelpers.ExcelUtilities - .forceCreateSheet(context.workbook, "Sample"); + context.workbook.worksheets.getItemOrNullObject("Sample").delete(); + const sheet = context.workbook.worksheets.add("Sample"); const groceryData = [ ["Product", "Qty", "Unit Price", "Total Price"], @@ -87,25 +88,23 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    + content: |- +
    +

    This sample shows how to format a range.

    - -
    +

    Set up

    - -
    +

    Try it out

    language: html style: - content: | + content: |- section.samples { margin-top: 20px; } @@ -128,21 +127,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/90-scenarios/performance-optimization.yaml b/samples/excel/90-scenarios/performance-optimization.yaml new file mode 100644 index 000000000..feb4400b0 --- /dev/null +++ b/samples/excel/90-scenarios/performance-optimization.yaml @@ -0,0 +1,193 @@ +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: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("refresh-data").addEventListener("click", () => tryCatch(refreshData)); + document.getElementById("toggle-tracking").addEventListener("click", () => tryCatch(toggleTracking)); + document.getElementById("toggle-screen-painting").addEventListener("click", () => tryCatch(toggleScreenPainting)); + document.getElementById("toggle-calculation").addEventListener("click", () => tryCatch(toggleCalculationMode)); + document.getElementById("recalculate").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + + https://unpkg.com/@microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js + https://unpkg.com/@microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/excel/20-scenarios/report-generation.yaml b/samples/excel/90-scenarios/report-generation.yaml similarity index 81% rename from samples/excel/20-scenarios/report-generation.yaml rename to samples/excel/90-scenarios/report-generation.yaml index ac3c27ada..749d8b54e 100644 --- a/samples/excel/20-scenarios/report-generation.yaml +++ b/samples/excel/90-scenarios/report-generation.yaml @@ -1,13 +1,14 @@ -id: excel-advanced-report-generation +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.' +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 + ExcelApi: '1.1' script: - content: | - $("#create-report").click(() => tryCatch(createReport)); + content: |- + document.getElementById("create-report").addEventListener("click", () => tryCatch(createReport)); /** Load sample data into a new worksheet and create a chart */ async function createReport() { @@ -31,8 +32,7 @@ script: } }); - OfficeHelpers.UI.notify("Sucess!", - "Report generation completed."); + console.log("Success!", "Report generation completed."); } async function writeSheetData(sheet: Excel.Worksheet) { @@ -97,7 +97,7 @@ script: 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.position = "Right" chart.legend.format.fill.setSolidColor("white"); chart.dataLabels.format.font.size = 15; chart.dataLabels.format.font.color = "black"; @@ -113,18 +113,17 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 using the Excel API.

    +
    +

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

    - -
    +

    Try it out

    language: html style: - content: | - .ms-MessageBanner { - display: none; - } - + content: |- section.samples { margin-top: 20px; } @@ -148,21 +143,9 @@ style: min-width: 80px; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ 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 new file mode 100644 index 000000000..d2a901c9f --- /dev/null +++ b/samples/excel/90-scenarios/working-with-dates.yaml @@ -0,0 +1,139 @@ +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; + + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("set-date-value-using-timestamp").addEventListener("click", () => tryCatch(setDateValueUsingTimestamp)); + document.getElementById("get-date-value").addEventListener("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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + + + moment@2.18.1 + moment-msdate@0.2.2 diff --git a/samples/excel/90-just-for-fun/color-wheel.yaml b/samples/excel/99-just-for-fun/color-wheel.yaml similarity index 74% rename from samples/excel/90-just-for-fun/color-wheel.yaml rename to samples/excel/99-just-for-fun/color-wheel.yaml index bf1ba7147..2e6b62749 100644 --- a/samples/excel/90-just-for-fun/color-wheel.yaml +++ b/samples/excel/99-just-for-fun/color-wheel.yaml @@ -1,17 +1,17 @@ -order: 4 +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.1 + ExcelApi: '1.4' script: - content: | - $("#wheel").click(wheelGo); - $("#stop").click(wheelStop); + content: |- + document.getElementById("wheel").addEventListener("click", wheelGo); + document.getElementById("stop").addEventListener("click", wheelStop); - let stop: boolean + let isStopped: boolean const pauseLength = 50; const numberOfSlices = 32; @@ -19,10 +19,11 @@ script: async function wheelGo() { try { Excel.run(async (context) => { - stop = false + isStopped = false; // Create a hidden sheet which will contain data for the color wheel chart: - const sheetSettings = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Color Wheel Settings", true /*clearOnly*/); + 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(); @@ -35,12 +36,13 @@ script: dataRange.values = matrix; // Create a sheet for the color wheel and format it - const sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Color Wheel", true /*clearOnly*/); + 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"); + let theWheel = sheet.charts.add(Excel.ChartType.pie, dataRange, "Auto"); theWheel.format.fill.setSolidColor('black') theWheel.setPosition("A1"); @@ -50,7 +52,7 @@ script: theWheel.legend.visible = false; let points = theWheel.series.getItemAt(0).points; - for (var i = 0; i < numberOfSlices; i++) { + for (let i = 0; i < numberOfSlices; i++) { points.getItemAt(i).format.fill.setSolidColor("black") } @@ -60,7 +62,7 @@ script: await pause(700); // Draw pretty colors, ad infinitum - while (!stop) { + while (!isStopped) { const colorMultiplier = 256 / numberOfSlices; await loopThroughColors(points, numberOfSlices * 2, i => rgb(255, colorMultiplier / 2 * i, 0)); /* red to orange to yellow*/ @@ -78,26 +80,26 @@ script: }); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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 (var i = 0; i < max; i++) { - if (stop) { + for (let i = 0; i < max; i++) { + if (isStopped) { return; } - var X = i % numberOfSlices; + let X = i % numberOfSlices; await pause(pauseLength); - var color = colorGenerator(i); + let color = colorGenerator(i); points.getItemAt(X).format.fill.setSolidColor(color); await points.context.sync(); } } function wheelStop() { - stop = true + isStopped = true; } function pause(milliseconds) { @@ -109,8 +111,10 @@ script: } language: typescript template: - content: |+ -

    Spin the rainbow wheel

    + content: |- +
    +

    Spin the rainbow wheel

    +

    - language: html style: - content: | + content: |- h2:not(:first-child) { margin-top: 35px; } @@ -140,21 +143,9 @@ style: min-width: 80px; } language: css -libraries: | - // Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - // CSS Libraries - 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 - - // NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - // IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/99-just-for-fun/gradient.yaml b/samples/excel/99-just-for-fun/gradient.yaml new file mode 100644 index 000000000..619402144 --- /dev/null +++ b/samples/excel/99-just-for-fun/gradient.yaml @@ -0,0 +1,237 @@ +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: |- + // Set up the click handler. + document.getElementById("draw-gradient").addEventListener("click", drawGradient); + document.getElementById("random").addEventListener("click", randomizeColors); + + /** Click-handler for drawing the gradient. */ + async function drawGradient() { + const drawButton = document.getElementById("draw-gradient") as HTMLButtonElement; + drawButton.disabled = true; + + try { + await Excel.run(drawGradientHelper); + } catch (error) { + console.log(error); + } + + drawButton.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((document.getElementById("size") as HTMLInputElement).value); + const colors2D = createColorArray(originalSize); + + // Retrieve color values from elements. + const topLeftColor = (document.getElementById("top-left") as HTMLInputElement).value; + const topRightColor = (document.getElementById("top-right") as HTMLInputElement).value; + const bottomLeftColor = (document.getElementById("bottom-left") as HTMLInputElement).value; + const bottomRightColor = (document.getElementById("bottom-right") as HTMLInputElement).value; + + // Convert HEX colors to RGB using TinyColor. + const topLeftRgb = tinycolor(topLeftColor).toRgb(); + const topRightRgb = tinycolor(topRightColor).toRgb(); + const bottomLeftRgb = tinycolor(bottomLeftColor).toRgb(); + const bottomRightRgb = tinycolor(bottomRightColor).toRgb(); + + 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); + } + + // Get the color values from the color pickers. + const topLeftColor = (document.getElementById("top-left") as HTMLInputElement).value; + const topRightColor = (document.getElementById("top-right") as HTMLInputElement).value; + const bottomLeftColor = (document.getElementById("bottom-left") as HTMLInputElement).value; + const bottomRightColor = (document.getElementById("bottom-right") as HTMLInputElement).value; + + // Convert HEX to RGB using TinyColor. + const topLeftRgb = tinycolor(topLeftColor).toRgb(); + const topRightRgb = tinycolor(topRightColor).toRgb(); + const bottomLeftRgb = tinycolor(bottomLeftColor).toRgb(); + const bottomRightRgb = tinycolor(bottomRightColor).toRgb(); + + const topColors = getColorsArray( + topLeftRgb, + topRightRgb, + size + ); + + const bottomColors = getColorsArray( + bottomLeftRgb, + bottomRightRgb, + 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, color2, 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 randomizeColors() { + // Select all color input elements. + const colorInputs = document.querySelectorAll("#color-table input[type='color']"); + + // Iterate through each color input and set a random color. + colorInputs.forEach((input) => { + const randomColor = tinycolor.random().toHexString(); + (input as HTMLInputElement).value = randomColor; + }); + } + language: typescript +template: + content: |- +
    +

    Color configuration

    +
    +
    +
    +
    Top left
    + + + + + + + + + +
    +
    + Bottom right +
    +
    + +

    Size + (width x height) +

    + + +
    +
    + Uses the TinyColor library. +
    +
    +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + + https://unpkg.com/tinycolor2@1.4.1/tinycolor.js + @types/tinycolor2 diff --git a/samples/excel/90-just-for-fun/path-finder-game.yaml b/samples/excel/99-just-for-fun/path-finder-game.yaml similarity index 79% rename from samples/excel/90-just-for-fun/path-finder-game.yaml rename to samples/excel/99-just-for-fun/path-finder-game.yaml index 030832862..812b2fdfd 100644 --- a/samples/excel/90-just-for-fun/path-finder-game.yaml +++ b/samples/excel/99-just-for-fun/path-finder-game.yaml @@ -1,18 +1,17 @@ order: 3 id: excel-just-for-fun-path-finder-game name: Path finder -description: Using range formatting to play a "pathfinder game". Contributed by Alexander Zlatkovski +description: Uses range formatting to play a "pathfinder game". Contributed by Alexander Zlatkovski. author: AlexanderZlatkovski host: EXCEL api_set: - ExcelApi: 1.2 + 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); + content: |- + document.getElementById("setup").addEventListener("click", setup); + document.getElementById("repeat").addEventListener("click", repeat); + document.getElementById("step-by-step").addEventListener("click", pruneTheGrid); + document.getElementById("all-at-once").addEventListener("click", allAtOnce); const GRID_ROW_COUNT = 25; const GRID_COLUMN_COUNT = 30; @@ -20,7 +19,7 @@ script: let matrixPrevious: string[][] function setup() { - const density = parseInt($("#density").val()) / 100; + const density = parseInt((document.getElementById("density") as HTMLInputElement).value) / 100; const symbol = "\u25cf"; const matrix = new Array(GRID_ROW_COUNT); @@ -32,7 +31,7 @@ script: } matrixPrevious = matrix; - $("#repeat").show(); + document.getElementById("repeat").style.display = "block"; setupHelper(matrix); } @@ -44,7 +43,8 @@ script: function setupHelper(matrix: string[][]) { tryCatch(() => Excel.run(async (context) => { - let sheet = await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Path Finder", true /*clearOnly*/); + context.workbook.worksheets.getItemOrNullObject("Path Finder").delete(); + const sheet = context.workbook.worksheets.add("Path Finder"); sheet.getRange().format.set({ columnWidth: 16, @@ -70,7 +70,8 @@ script: } async function pruneTheGrid() { - $pruneTheGrid.attr("disabled", "true"); + const pruneTheGrid = document.getElementById("step-by-step") as HTMLButtonElement; + pruneTheGrid.disabled = true; await tryCatch(() => Excel.run(async (context) => { const grid = context.workbook.worksheets @@ -83,11 +84,12 @@ script: await context.sync(); })); - $pruneTheGrid.removeAttr("disabled"); + pruneTheGrid.disabled = false; } async function allAtOnce() { - $allAtOnce.attr("disabled", "true"); + const allAtOnce = document.getElementById("all-at-once") as HTMLButtonElement; + allAtOnce.disabled = true; let counter = 0; await tryCatch(() => Excel.run(async (context) => { @@ -110,7 +112,7 @@ script: })); console.log("Count of iterations: " + counter); - $allAtOnce.removeAttr("disabled"); + allAtOnce.disabled = false; } @@ -167,19 +169,18 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | -
    + 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:

    -
    +

    - @@ -220,21 +219,9 @@ style: margin-bottom: 0; } language: css -libraries: | - # Office.js +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/99-just-for-fun/patterns.yaml b/samples/excel/99-just-for-fun/patterns.yaml new file mode 100644 index 000000000..76399f6c7 --- /dev/null +++ b/samples/excel/99-just-for-fun/patterns.yaml @@ -0,0 +1,192 @@ +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: |- + document.getElementById("squares").addEventListener("click", () => tryCatch(drawSquares)); + document.getElementById("spiral").addEventListener("click", () => tryCatch(drawSpiral)); + document.getElementById("decoration").addEventListener("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((document.getElementById("size") as HTMLInputElement).value); + + 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((document.getElementById("size") as HTMLInputElement).value) / 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((document.getElementById("size") as HTMLInputElement).value) / 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/excel/99-just-for-fun/tetrominos.yaml b/samples/excel/99-just-for-fun/tetrominos.yaml new file mode 100644 index 000000000..57441e125 --- /dev/null +++ b/samples/excel/99-just-for-fun/tetrominos.yaml @@ -0,0 +1,794 @@ +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: |- + document.getElementById("run").addEventListener("click", () => { + document.getElementById("setup").style.display = "none"; + tryCatch(run); + }); + document.getElementById("selectedFile").addEventListener("change", () => tryCatch(readImageFromFile)); + document.getElementById("focusButton").addEventListener("click", () => tryCatch(focus)); + + let backgroundPicture = getDefaultBackgroundPicture(); + + function readImageFromFile() { + const myFile = document.getElementById("selectedFile") as HTMLInputElement; + 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() { + document.getElementById("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); + } + } + + const container = document.getElementById("container"); + const sessionPane = document.getElementById("sessionPane"); + await run(container, sessionPane); + + container.focus(); + document.getElementById("focus").style.display = "block"; + }); + } + + /** Default helper for invoking an action and handling errors. */ + async function tryCatch(callback) { + try { + await callback(); + } catch (error) { + document.getElementById("setup").style.display = "block"; + // 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + + 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 96b8665bc..c303f62eb 100644 --- a/samples/excel/default.yaml +++ b/samples/excel/default.yaml @@ -4,15 +4,16 @@ description: Create a new snippet from a blank template. author: OfficeDev host: EXCEL api_set: - ExcelApi: 1.1 + ExcelApi: '1.1' script: - content: | - $("#run").click(() => tryCatch(run)); + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); async function run() { await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); - OfficeHelpers.UI.notify("Your code goes here"); + console.log("Your code goes here"); await context.sync(); }); @@ -24,33 +25,33 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/onenote/default.yaml b/samples/onenote/default.yaml index 3a336096a..16f59bda5 100644 --- a/samples/onenote/default.yaml +++ b/samples/onenote/default.yaml @@ -4,15 +4,14 @@ description: Create a new snippet from a blank template. author: OfficeDev host: ONENOTE api_set: - OneNoteApi: 1.1 + OneNoteApi: '1.1' script: - content: | - $("#run").click(() => tryCatch(run)); + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); async function run() { await OneNote.run(async (context) => { - - OfficeHelpers.UI.notify("Your code goes here"); + console.log("Your code goes here"); await context.sync(); }); @@ -24,33 +23,33 @@ script: await callback(); } catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/01-compose-basics/get-item-subject.yaml b/samples/outlook/01-compose-basics/get-item-subject.yaml deleted file mode 100644 index f460bac55..000000000 --- a/samples/outlook/01-compose-basics/get-item-subject.yaml +++ /dev/null @@ -1,46 +0,0 @@ -id: outlook-compose-basics-get-item-subject -name: Get Item Subject -description: Gets the subject of a compose item -host: OUTLOOK -api_set: {} -script: - content: | - $("#run").click(run); - - function run() { - let item = Office.context.mailbox.item as Office.ItemCompose; - item.subject.getAsync((result: Office.AsyncResult) => { - if (result.status !== Office.AsyncResultStatus.Succeeded) { - OfficeHelpers.UI.notify(`Action failed with message ${result.error.message}`); - return; - } - OfficeHelpers.UI.notify(`Subject is ${result.value}`); - }) - } - language: typescript -template: - content: | - - - language: html -style: - content: | - /* Your style goes here */ - language: css -libraries: | - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.js - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/outlook/01-compose-basics/get-selected-text.yaml b/samples/outlook/01-compose-basics/get-selected-text.yaml deleted file mode 100644 index eadb9e467..000000000 --- a/samples/outlook/01-compose-basics/get-selected-text.yaml +++ /dev/null @@ -1,46 +0,0 @@ -id: outlook-compose-basics-get-selected-text -name: Get Selected Text -description: Outputs the text selected from either the body or subject. -host: OUTLOOK -api_set: {} -script: - content: | - $("#run").click(run); - - function run() { - let item = Office.context.mailbox.item as Office.ItemCompose; - item.getSelectedDataAsync(Office.CoercionType.Text, (result: Office.AsyncResult) => { - if (result.status === Office.AsyncResultStatus.Failed) { - OfficeHelpers.UI.notify(`Action failed with error: ${result.error.message}`); - return; - } - OfficeHelpers.UI.notify(`Selected Text: ${result.value.data}`); - }) - } - language: typescript -template: - content: | - - - language: html -style: - content: | - /* Your style goes here */ - language: css -libraries: | - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.js - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/outlook/01-compose-basics/set-selected-text.yaml b/samples/outlook/01-compose-basics/set-selected-text.yaml deleted file mode 100644 index 1c3480df3..000000000 --- a/samples/outlook/01-compose-basics/set-selected-text.yaml +++ /dev/null @@ -1,44 +0,0 @@ -id: outlook-compose-basics-set-selected-text -name: Set Selected Text -description: Changes the value of selected text in body or subject. -host: OUTLOOK -api_set: {} -script: - content: | - $("#run").click(run); - - function run() { - let item = Office.context.mailbox.item as Office.ItemCompose; - item.setSelectedDataAsync("Hello World!", (result: Office.AsyncResult) => { - if (result.status === Office.AsyncResultStatus.Failed) { - OfficeHelpers.UI.notify(`Action failed with error: ${result.error.message}`) - } - }) - } - language: typescript -template: - content: | - - - language: html -style: - content: | - /* Your style goes here */ - language: css -libraries: | - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.js - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/outlook/10-roaming-settings/roaming-settings.yaml b/samples/outlook/10-roaming-settings/roaming-settings.yaml new file mode 100644 index 000000000..a24b5e596 --- /dev/null +++ b/samples/outlook/10-roaming-settings/roaming-settings.yaml @@ -0,0 +1,93 @@ +id: outlook-roaming-settings-roaming-settings +name: Use add-in settings +description: Gets, sets, saves, and removes add-in roaming settings. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + document.getElementById("set").addEventListener("click", set); + document.getElementById("save").addEventListener("click", save); + document.getElementById("remove").addEventListener("click", remove); + + function get() { + const settingName = (document.getElementById("settingName") as HTMLInputElement).value; + const settingValue = Office.context.roamingSettings.get(settingName); + (document.getElementById("settingValue") as HTMLInputElement).value = settingValue; + console.log(`The value of setting "${settingName}" is "${settingValue}".`); + } + + function set() { + const settingName = (document.getElementById("settingName") as HTMLInputElement).value; + const settingValue = (document.getElementById("settingValue") as HTMLInputElement).value; + Office.context.roamingSettings.set(settingName, settingValue); + console.log(`Setting "${settingName}" set to value "${settingValue}".`); + } + + function save() { + // Save settings in the mailbox to make it available in future sessions. + Office.context.roamingSettings.saveAsync(function(result) { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + } else { + console.log(`Settings saved with status: ${result.status}`); + } + }); + } + + function remove() { + // Remove the specified setting from the mailbox. + const settingName = (document.getElementById("settingName") as HTMLInputElement).value; + Office.context.roamingSettings.remove(settingName); + console.log(`The "${settingName}" setting has been removed.`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to set, save, and get add-in properties that can be accessed the next time the add-in is opened.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/15-item-custom-properties/load-set-get-save.yaml b/samples/outlook/15-item-custom-properties/load-set-get-save.yaml new file mode 100644 index 000000000..cd2502b98 --- /dev/null +++ b/samples/outlook/15-item-custom-properties/load-set-get-save.yaml @@ -0,0 +1,134 @@ +id: outlook-item-custom-properties-load-set-get-save +name: Work with item custom properties +description: Gets the custom properties that the add-in placed on the current item, sets a new one, gets it, removes it, and saves all custom properties back to the item. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + let customProps; + + document.getElementById("load").addEventListener("click", load); + document.getElementById("get").addEventListener("click", get); + document.getElementById("get-all").addEventListener("click", getAll); + document.getElementById("set").addEventListener("click", set); + document.getElementById("remove").addEventListener("click", remove); + document.getElementById("save").addEventListener("click", save); + + function load() { + Office.context.mailbox.item.loadCustomPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`loadCustomPropertiesAsync failed with message ${result.error.message}`); + return; + } + + customProps = result.value; + console.log("Loaded the CustomProperties object."); + }); + } + + function get() { + const propertyName = (document.getElementById("get-property-name") as HTMLInputElement).value; + const propertyValue = customProps.get(propertyName); + console.log(`The value of custom property "${propertyName}" is "${propertyValue}".`); + } + + function getAll() { + let allCustomProps; + if (Office.context.requirements.isSetSupported("Mailbox", "1.9")) { + allCustomProps = customProps.getAll(); + } else { + allCustomProps = customProps["rawData"]; + } + + console.log(allCustomProps); + } + + function set() { + const propertyName = (document.getElementById("set-property-name") as HTMLInputElement).value; + const propertyValue = (document.getElementById("property-value") as HTMLInputElement).value; + customProps.set(propertyName, propertyValue); + console.log(`Custom property "${propertyName}" set to value "${propertyValue}".`); + } + + function remove() { + const propertyName = (document.getElementById("remove-property-name") as HTMLInputElement).value; + customProps.remove(propertyName); + console.log(`Custom property "${propertyName}" removed.`); + } + + function save() { + customProps.saveAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`saveAsync failed with message ${result.error.message}`); + return; + } + + console.log(`Custom properties saved with status: ${result.status}`); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to set, save, and get the custom per-item properties of an add-in.

    +
    +
    +

    Try it out

    +

    First load the CustomProperties object of the mail item.

    + +
    + + +
    +
    + + +
    + +
    + + +
    + + +
    + + +
    + + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/20-item-body/add-inline-base64-image.yaml b/samples/outlook/20-item-body/add-inline-base64-image.yaml new file mode 100644 index 000000000..e97523983 --- /dev/null +++ b/samples/outlook/20-item-body/add-inline-base64-image.yaml @@ -0,0 +1,100 @@ +order: 3 +id: outlook-item-body-add-inline-base64-image +name: Add inline Base64-encoded image to message or appointment body (Compose) +description: Add an inline Base64-encoded image to the body of a message or appointment being composed. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("prepend-image").addEventListener("click", prependImage); + document.getElementById("append-image").addEventListener("click", appendImage); + + const base64String = + "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAnUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN0S+bUAAAAMdFJOUwAQIDBAUI+fr7/P7yEupu8AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAF8SURBVGhD7dfLdoMwDEVR6Cspzf9/b20QYOthS5Zn0Z2kVdY6O2WULrFYLBaLxd5ur4mDZD14b8ogWS/dtxV+dmx9ysA2QUj9TQRWv5D7HyKwuIW9n0vc8tkpHP0W4BOg3wQ8wtlvA+PC1e8Ao8Ld7wFjQtHvAiNC2e8DdqHqKwCrUPc1gE1AfRVgEXBfB+gF0lcCWoH2tYBOYPpqQCNwfT3QF9i+AegJfN8CtAWhbwJagtS3AbIg9o2AJMh9M5C+SVGBvx6zAfmT0r+Bv8JMwP4kyFPir+cswF5KL3WLv14zAFBCLf56Tw9cparFX4upgaJUtPhrOS1QlY5W+vWTXrGgBFB/b72ev3/0igUdQPppP/nfowfKUUEFcP207y/yxKmgAYQ+PywoAFOfCH3A2MdCFzD3kdADBvq10AGG+pXQBgb7pdAEhvuF0AIc/VtoAK7+JciAs38KIuDugyAC/v4hiMCE/i7IwLRBsh68N2WQjMVisVgs9i5bln8LGScNcCrONQAAAABJRU5ErkJggg=="; + + function prependImage() { + // Insert the Base64-encoded image to the beginning of the body. + Office.context.mailbox.item.addFileAttachmentFromBase64Async(base64String, "sample.png", { isInline: true }, (attachmentResult) => { + if (attachmentResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to attach file: ${attachmentResult.error.message}`); + return; + } + + Office.context.mailbox.item.body.prependAsync('', { coercionType: Office.CoercionType.Html }, (prependResult) => { + if (prependResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to prepend image to body: ${attachmentResult.error.message}`); + return; + } + + console.log("Inline Base64-encoded image added to the beginning of the body."); + }) + }); + } + + function appendImage() { + // Get the current body of the message or appointment. + Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, (bodyResult) => { + if (bodyResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to get body: ${bodyResult.error.message}`); + return; + } + + // Add the Base64-encoded image to the end of the body. + const options = { isInline: true, asyncContext: bodyResult.value }; + Office.context.mailbox.item.addFileAttachmentFromBase64Async(base64String, "sample.png", options, (attachResult) => { + if (attachResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to attach file: ${attachResult.error.message}`); + return; + } + + let body = attachResult.asyncContext; + body += ''; + + Office.context.mailbox.item.body.setAsync(body, { coercionType: Office.CoercionType.Html }, (setResult) => { + if (setResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to set body: ${setResult.error.message}`); + return; + } + + console.log("Inline Base64-encoded image added to the end of the body."); + }); + }); + }); + } + language: typescript +template: + content: |- +
    +

    This sample adds an inline Base64-encoded image to the body of the message or appointment being composed.

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/append-text-on-send.yaml b/samples/outlook/20-item-body/append-text-on-send.yaml new file mode 100644 index 000000000..b283f7abd --- /dev/null +++ b/samples/outlook/20-item-body/append-text-on-send.yaml @@ -0,0 +1,72 @@ +order: 5 +id: outlook-item-body-append-text-on-send +name: Append text to item body on send +description: Appends text to the end of the message or appointment's body once it's sent. +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + document.getElementById("append-on-send").addEventListener("click", appendOnSend); + + function appendOnSend() { + // This snippet appends text to the end of the message or appointment's body once it's sent. + const text = (document.getElementById("text-field") as HTMLInputElement).value; + + // It's recommended to call getTypeAsync and pass its returned value to the options.coercionType parameter of the appendOnSendAsync call. + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.appendOnSendAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" will be appended to the body once the message or appointment is sent. Send the mail item to test this feature.`); + }); + }); + } + language: typescript +template: + content: |- +
    +

    This sample appends text to the end of the message or appointment's body once it's sent.

    +

    Required mode: Compose

    +
    +
    +

    Try it out

    +

    Important: To use appendOnSendAsync, you must set AppendOnSend as an extended permission in the ExtendedPermissions manifest element. To learn more about append-on-send and its configuration, see Implement append-on-send in your Outlook 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/get-body-format.yaml b/samples/outlook/20-item-body/get-body-format.yaml new file mode 100644 index 000000000..b077f1147 --- /dev/null +++ b/samples/outlook/20-item-body/get-body-format.yaml @@ -0,0 +1,55 @@ +order: 4 +id: outlook-item-body-get-body-format +name: Get the item's body format +description: Gets a message or appointment's body format (plain text or HTML). +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-body-format").addEventListener("click", getBodyFormat); + + function getBodyFormat() { + // Get the mail item's body format (plain text or HTML) and log it to the console. + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log("Body format: " + asyncResult.value); + }); + } + language: typescript +template: + content: |- +
    +

    This sample gets the message or appointment's body format (plain text or HTML).

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/get-selected-data.yaml b/samples/outlook/20-item-body/get-selected-data.yaml new file mode 100644 index 000000000..90a1a202e --- /dev/null +++ b/samples/outlook/20-item-body/get-selected-data.yaml @@ -0,0 +1,56 @@ +order: 1 +id: outlook-item-body-get-selected-data +name: Get selected text (Compose) +description: Gets the selected text in the item body or subject in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-selected-data").addEventListener("click", getSelectedData); + + function getSelectedData() { + Office.context.mailbox.item.getSelectedDataAsync(Office.CoercionType.Text, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const text = asyncResult.value.data; + const prop = asyncResult.value.sourceProperty; + console.log("Selected text in " + prop + ": " + text); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the selected text in the item body or subject/title.

    +

    Required mode: Compose

    +
    +
    +

    Try it out

    +

    Select text in the item body or subject then push the Get selected text 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/prepend-text-on-send.yaml b/samples/outlook/20-item-body/prepend-text-on-send.yaml new file mode 100644 index 000000000..1b363be09 --- /dev/null +++ b/samples/outlook/20-item-body/prepend-text-on-send.yaml @@ -0,0 +1,72 @@ +order: 7 +id: outlook-item-body-prepend-text-on-send +name: Prepend text to item body on send +description: Prepends text to the beginning of the message or appointment's body once it's sent. +host: OUTLOOK +api_set: + Mailbox: '1.13' +script: + content: |- + document.getElementById("prepend-on-send").addEventListener("click", prependOnSend); + + function prependOnSend() { + // This snippet prepends text to the beginning of the message or appointment's body once it's sent. + const text = (document.getElementById("text-field") as HTMLInputElement).value; + + // It's recommended to call getTypeAsync and pass its returned value to the options.coercionType parameter of the prependOnSendAsync call. + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.prependOnSendAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" will be prepended to the body once the message or appointment is sent. Send the mail item to test this feature.`); + }); + }); + } + language: typescript +template: + content: |- +
    +

    This sample prepends text to the beginning of the message or appointment's body once it's sent.

    +

    Required mode: Compose

    +
    +
    +

    Try it out

    +

    Important: To use prependOnSendAsync, you must set AppendOnSend as an extended permission in the ExtendedPermissions manifest element. appendOnSendAsync and prependOnSendAsync both use the AppendOnSend extended permission. To learn more about prepend-on-send, see Prepend or append content to a message or appointment body on send.

    +
    + + +
    +
    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/prepend-text-to-item-body.yaml b/samples/outlook/20-item-body/prepend-text-to-item-body.yaml new file mode 100644 index 000000000..e9b2a5b1c --- /dev/null +++ b/samples/outlook/20-item-body/prepend-text-to-item-body.yaml @@ -0,0 +1,74 @@ +order: 6 +id: outlook-item-body-prepend-text-to-item-body +name: Prepend text to item body +description: Adds text to the beginning of the message or appointment's body. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("prepend").addEventListener("click", prependText); + + function prependText() { + /* This snippet adds text to the beginning of the message or appointment's body. + + When prepending a link in HTML markup to the body, you can disable the online link preview by setting the anchor tag's id attribute to "LPNoLP". For example, 'Click here!'. + */ + const text = (document.getElementById("text-field") as HTMLInputElement).value; + + // It's recommended to call getTypeAsync and pass its returned value to the options.coercionType parameter of the prependAsync call. + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.prependAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" prepended to the body.`); + }); + }); + } + language: typescript +template: + content: |- +
    +

    This sample adds text to the beginning of the message or appointment's body.

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/20-item-body/replace-selected-text.yaml b/samples/outlook/20-item-body/replace-selected-text.yaml new file mode 100644 index 000000000..425dcee0b --- /dev/null +++ b/samples/outlook/20-item-body/replace-selected-text.yaml @@ -0,0 +1,78 @@ +order: 2 +id: outlook-item-body-replace-selected-text +name: Replace selected text in item body +description: Replaces selected text in a message or appointment's body with specified text. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("replace-selection").addEventListener("click", replaceSelection); + + function replaceSelection() { + /* This snippet replaces selected text in a message or appointment's body with specified text. + + If you want to use a link in HTML markup as a value of the setSelectedDataAsync call's data parameter, you can disable online link preview by setting the anchor tag's id attribute to "LPNoLP". For example, 'Click here!'. + */ + const text = (document.getElementById("text-field") as HTMLInputElement).value; + + // It's recommended to call getTypeAsync and pass its returned value to the options.coercionType parameter of the prependAsync call. + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.setSelectedDataAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`Replaced selected text with "${text}".`); + }); + }); + } + language: typescript +template: + content: |- +
    +

    This sample replaces selected text in a message or appointment's body with specified text.

    +

    Required mode: Compose

    +
    +
    +

    Try it out

    +
      +
    1. Select text in the item's body.
    2. +
      +
    3. Enter text to replace the selected text.
    4. +
    +
    + +
    +
    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/25-item-save-and-close/close-async.yaml b/samples/outlook/25-item-save-and-close/close-async.yaml new file mode 100644 index 000000000..59b23949a --- /dev/null +++ b/samples/outlook/25-item-save-and-close/close-async.yaml @@ -0,0 +1,57 @@ +order: 2 +id: outlook-close-async +name: Close the current message and discard changes (Message Compose) +description: Closes the current message and discards any unsaved changes when specified. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("close-async").addEventListener("click", closeAsync); + + function closeAsync() { + // This snippet closes the current message being composed and discards any unsaved changes when the optional property, discardItem, is set to true. + // The API call works on a new message being composed, a reply, or an existing draft. + // When discardItem is set to false or isn't defined on a new message with unsaved changes, the user is prompted to save a draft, discard the changes, or cancel the close operation. + Office.context.mailbox.item.closeAsync( + { discardItem: true }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to close the current message being composed and discard any unsaved changes.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/25-item-save-and-close/close.yaml b/samples/outlook/25-item-save-and-close/close.yaml new file mode 100644 index 000000000..ffc78cc69 --- /dev/null +++ b/samples/outlook/25-item-save-and-close/close.yaml @@ -0,0 +1,46 @@ +order: 1 +id: outlook-item-save-and-close-close +name: Close the item +description: Closes the item (compose mode) +host: OUTLOOK +api_set: + Mailbox: '1.3' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.item.close(); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to close the item in compose mode.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/25-item-save-and-close/save.yaml b/samples/outlook/25-item-save-and-close/save.yaml new file mode 100644 index 000000000..b6c26f24b --- /dev/null +++ b/samples/outlook/25-item-save-and-close/save.yaml @@ -0,0 +1,53 @@ +order: 3 +id: outlook-item-save-and-close-save +name: Save the item +description: Saves the item (compose mode) +host: OUTLOOK +api_set: + Mailbox: '1.3' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.item.saveAsync(function (result) { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`saveAsync succeeded, itemId is ${result.value}`); + } + else { + console.error(`saveAsync failed with message ${result.error.message}`); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to save the item in compose mode.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml b/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml new file mode 100644 index 000000000..1f967c9d6 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml @@ -0,0 +1,124 @@ +order: 15 +id: outlook-recipients-and-attendees-get-all-attendees +name: Get all attendees +description: Gets all appointment attendees and organizes them by their response. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get-attendees").addEventListener("click", getAttendees); + + function getAttendees() { + // This snippet gets an appointment's required and optional attendees and groups them by their response. + const appointment = Office.context.mailbox.item; + let attendees; + if (Object.keys(appointment.organizer).length === 0) { + // Get attendees as the meeting organizer. + appointment.requiredAttendees.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.log(result.error.message); + return; + } + + attendees = result.value; + appointment.optionalAttendees.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.log(result.error.message); + return; + } + + attendees = attendees.concat(result.value); + + // Organize attendees by their meeting response and print this to the console. + organizeByResponse(attendees); + }); + }); + } else { + // Get attendees as a meeting attendee. + attendees = appointment.requiredAttendees; + attendees = attendees.concat(appointment.optionalAttendees); + + // Organize attendees by their meeting response and print this to the console. + organizeByResponse(attendees); + } + } + + function organizeByResponse(attendees) { + const accepted = []; + const declined = []; + const noResponse = []; + const tentative = []; + attendees.forEach(attendee => { + switch (attendee.appointmentResponse) { + case Office.MailboxEnums.ResponseType.Accepted: + accepted.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Declined: + declined.push(attendee); + break; + case Office.MailboxEnums.ResponseType.None: + noResponse.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Tentative: + tentative.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Organizer: + console.log(`Organizer: ${attendee.displayName}, ${attendee.emailAddress}`); + break; + } + }); + + // List attendees by their response. + console.log("Accepted: "); + printAttendees(accepted); + console.log("Declined: "); + printAttendees(declined); + console.log("Tentative: "); + printAttendees(tentative); + console.log("No response: "); + printAttendees(noResponse); + } + + function printAttendees(attendees) { + if (attendees.length === 0) { + console.log("None"); + } else { + attendees.forEach(attendee => { + console.log(` ${attendee.displayName}, ${attendee.emailAddress}`); + }); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get all appointment attendees and organize them by their response.

    +

    Required mode: Appointment Organizer, Appointment Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml b/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml new file mode 100644 index 000000000..a0982310c --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml @@ -0,0 +1,51 @@ +order: 5 +id: outlook-recipients-and-attendees-get-cc-message-read +name: Get cc (Message Read) +description: Gets the Cc line recipients of the message in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-cc").addEventListener("click", getCc); + + function getCc() { + const msgCc = Office.context.mailbox.item.cc; + console.log("Message copied to:"); + for (let i = 0; i < msgCc.length; i++) { + console.log(msgCc[i].displayName + " (" + msgCc[i].emailAddress + ")"); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the Cc line recipients of the email.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml b/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml new file mode 100644 index 000000000..7e9748c8a --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml @@ -0,0 +1,54 @@ +order: 2 +id: outlook-recipients-and-attendees-get-from-message-compose +name: Get from (Message Compose) +description: Gets who the message is from in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get-from").addEventListener("click", getFrom); + + function getFrom() { + Office.context.mailbox.item.from.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgFrom = asyncResult.value; + console.log("Message from: " + msgFrom.displayName + " (" + msgFrom.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get who an email is from.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml b/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml new file mode 100644 index 000000000..ce60520d5 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml @@ -0,0 +1,49 @@ +order: 1 +id: outlook-recipients-and-attendees-get-from-message-read +name: Get from (Message Read) +description: Gets who the message is from in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-from").addEventListener("click", getFrom); + + function getFrom() { + const msgFrom = Office.context.mailbox.item.from; + console.log("Message received from: " + msgFrom.displayName + " (" + msgFrom.emailAddress + ")"); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get who an email is from. In a delegate access scenario, the + from property represents the delegator. Tip: Use sender to get the delegate.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml b/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml new file mode 100644 index 000000000..5ce5b87d5 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml @@ -0,0 +1,57 @@ +order: 11 +id: outlook-recipients-and-attendees-get-optional-attendees-appointment-attendee +name: Get optional attendees (Appointment Attendee) +description: Gets the optional attendees in Appointment Attendee mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-optional-attendees").addEventListener("click", getOptionalAttendees); + + function getOptionalAttendees() { + const apptOptionalAttendees = Office.context.mailbox.item.optionalAttendees; + console.log("Optional attendees:"); + for (let i = 0; i < apptOptionalAttendees.length; i++) { + console.log( + apptOptionalAttendees[i].displayName + + " (" + + apptOptionalAttendees[i].emailAddress + + ") - response: " + + apptOptionalAttendees[i].appointmentResponse + ); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the optional attendees.

    +

    Required mode: Appointment Attendee

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml b/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml new file mode 100644 index 000000000..072d05ed5 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml @@ -0,0 +1,48 @@ +order: 13 +id: outlook-recipients-and-attendees-get-organizer-appointment-attendee +name: Get organizer (Appointment Attendee) +description: Gets the organizer in Appointment Attendee mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-organizer").addEventListener("click", getOrganizer); + + function getOrganizer() { + const apptOrganizer = Office.context.mailbox.item.organizer; + console.log("Organizer: " + apptOrganizer.displayName + " (" + apptOrganizer.emailAddress + ")"); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the appointment organizer.

    +

    Required mode: Appointment Attendee

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml b/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml new file mode 100644 index 000000000..9ddcf7cff --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml @@ -0,0 +1,54 @@ +order: 14 +id: outlook-recipients-and-attendees-get-organizer-appointment-organizer +name: Get organizer (Appointment Organizer) +description: Gets the organizer in Appointment Organizer mode. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get-organizer").addEventListener("click", getOrganizer); + + function getOrganizer() { + Office.context.mailbox.item.organizer.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOrganizer = asyncResult.value; + console.log("Organizer: " + apptOrganizer.displayName + " (" + apptOrganizer.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the appointment organizer.

    +

    Required mode: Appointment Organizer

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml b/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml new file mode 100644 index 000000000..ae9a35cde --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml @@ -0,0 +1,57 @@ +order: 9 +id: outlook-recipients-and-attendees-get-required-attendees-appointment-attendee +name: Get required attendees (Appointment Attendee) +description: Gets the required attendees in Appointment Attendee mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-required-attendees").addEventListener("click", getRequiredAttendees); + + function getRequiredAttendees() { + const apptRequiredAttendees = Office.context.mailbox.item.requiredAttendees; + console.log("Required attendees:"); + for (let i = 0; i < apptRequiredAttendees.length; i++) { + console.log( + apptRequiredAttendees[i].displayName + + " (" + + apptRequiredAttendees[i].emailAddress + + ") - response: " + + apptRequiredAttendees[i].appointmentResponse + ); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the required attendees.

    +

    Required mode: Appointment Attendee

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml b/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml new file mode 100644 index 000000000..6fa0dd908 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml @@ -0,0 +1,48 @@ +order: 8 +id: outlook-recipients-and-attendees-get-sender-message-read +name: Get sender (Message Read) +description: Gets the sender in Message Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-sender").addEventListener("click", getSender); + + function getSender() { + const msgSender = Office.context.mailbox.item.sender; + console.log("Sender: " + msgSender.displayName + " (" + msgSender.emailAddress + ")"); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the email sender. In a delegate access scenario, the sender is the delegate. Tip: Use the from property to get the delegator.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml b/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml new file mode 100644 index 000000000..62ca0621e --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml @@ -0,0 +1,77 @@ +order: 7 +id: outlook-recipients-and-attendees-get-set-bcc-message-compose +name: Get and set bcc (Message Compose) +description: Gets and sets the Bcc line recipients of the message in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-bcc").addEventListener("click", getBcc); + document.getElementById("set-bcc").addEventListener("click", setBcc); + + function getBcc() { + Office.context.mailbox.item.bcc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgBcc = asyncResult.value; + console.log("Message being blind-copied to:"); + for (let i = 0; i < msgBcc.length; i++) { + console.log(msgBcc[i].displayName + " (" + msgBcc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function setBcc() { + const email = (document.getElementById("emailBcc") as HTMLInputElement).value; + const emailArray = [email]; + Office.context.mailbox.item.bcc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Bcc field."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the Bcc line recipients of the email.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml b/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml new file mode 100644 index 000000000..04fdaf781 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml @@ -0,0 +1,77 @@ +order: 6 +id: outlook-recipients-and-attendees-get-set-cc-message-compose +name: Get and set cc (Message Compose) +description: Gets and sets the Cc line recipients of the message in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-cc").addEventListener("click", getCc); + document.getElementById("set-cc").addEventListener("click", setCc); + + function getCc() { + Office.context.mailbox.item.cc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgCc = asyncResult.value; + console.log("Message being copied to:"); + for (let i = 0; i < msgCc.length; i++) { + console.log(msgCc[i].displayName + " (" + msgCc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function setCc() { + const email = (document.getElementById("emailCc") as HTMLInputElement).value; + const emailArray = [email]; + Office.context.mailbox.item.cc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Cc field."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the Cc line recipients of the email.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml b/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml new file mode 100644 index 000000000..aa1180826 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml @@ -0,0 +1,83 @@ +order: 12 +id: outlook-recipients-and-attendees-get-set-optional-attendees-appointment-organizer +name: Get and set optional attendees (Appointment Organizer) +description: Gets and sets the optional attendees in Appointment Organizer mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-optional-attendees").addEventListener("click", getOptionalAttendees); + document.getElementById("set-optional-attendees").addEventListener("click", setOptionalAttendees); + + function getOptionalAttendees() { + Office.context.mailbox.item.optionalAttendees.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOptionalAttendees = asyncResult.value; + for (let i = 0; i < apptOptionalAttendees.length; i++) { + console.log( + "Optional attendees: " + + apptOptionalAttendees[i].displayName + + " (" + + apptOptionalAttendees[i].emailAddress + + ") - response: " + + apptOptionalAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function setOptionalAttendees() { + const email = (document.getElementById("emailOptional") as HTMLInputElement).value; + const emailArray = [email]; + Office.context.mailbox.item.optionalAttendees.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting optional attendees field."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the optional attendees.

    +

    Required mode: Appointment Organizer

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml b/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml new file mode 100644 index 000000000..cc3bf3fde --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml @@ -0,0 +1,83 @@ +order: 10 +id: outlook-recipients-and-attendees-get-set-required-attendees-appointment-organizer +name: Get and set required attendees (Appointment Organizer) +description: Gets and sets the required attendees in Appointment Organizer mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-required-attendees").addEventListener("click", getRequiredAttendees); + document.getElementById("set-required-attendees").addEventListener("click", setRequiredAttendees); + + function getRequiredAttendees() { + Office.context.mailbox.item.requiredAttendees.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptRequiredAttendees = asyncResult.value; + for (let i = 0; i < apptRequiredAttendees.length; i++) { + console.log( + "Required attendees: " + + apptRequiredAttendees[i].displayName + + " (" + + apptRequiredAttendees[i].emailAddress + + ") - response: " + + apptRequiredAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function setRequiredAttendees() { + const email = (document.getElementById("emailRequired") as HTMLInputElement).value; + const emailArray = [email]; + Office.context.mailbox.item.requiredAttendees.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting required attendees field."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the required attendees.

    +

    Required mode: Appointment Organizer

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml b/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml new file mode 100644 index 000000000..39a3128ca --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml @@ -0,0 +1,77 @@ +order: 4 +id: outlook-recipients-and-attendees-get-set-to-message-compose +name: Get and set to (Message Compose) +description: Gets and sets the To line recipients of the message in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-to").addEventListener("click", getTo); + document.getElementById("set-to").addEventListener("click", setTo); + + function getTo() { + Office.context.mailbox.item.to.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgTo = asyncResult.value; + console.log("Message being sent to:"); + for (let i = 0; i < msgTo.length; i++) { + console.log(msgTo[i].displayName + " (" + msgTo[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function setTo() { + const email = (document.getElementById("emailTo") as HTMLInputElement).value; + const emailArray = [email]; + Office.context.mailbox.item.to.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting To field."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the To line recipients of the email.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml b/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml new file mode 100644 index 000000000..cfa4204e8 --- /dev/null +++ b/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml @@ -0,0 +1,86 @@ +order: 3 +id: outlook-recipients-and-attendees-get-to-message-read +name: Get to (Message Read) +description: Gets the To line recipients of the message in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-to").addEventListener("click", getTo); + + function getTo() { + const msgTo = Office.context.mailbox.item.to; + const distributionLists = []; + const externalRecipients = []; + const internalRecipients = []; + const otherRecipients = []; + for (let i = 0; i < msgTo.length; i++) { + switch (msgTo[i].recipientType) { + case Office.MailboxEnums.RecipientType.DistributionList: + distributionLists.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.ExternalUser: + externalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.User: + internalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.Other: + otherRecipients.push(msgTo[i]); + } + } + + if (distributionLists.length > 0) { + console.log("Distribution Lists:"); + distributionLists.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + if (externalRecipients.length > 0) { + console.log("External Recipients:"); + externalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + if (internalRecipients.length > 0) { + console.log("Internal Recipients:"); + internalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + if (otherRecipients.length > 0) { + console.log("Other Recipients:"); + otherRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the To line recipients of the email.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/35-notifications/add-getall-remove.yaml b/samples/outlook/35-notifications/add-getall-remove.yaml new file mode 100644 index 000000000..a864ce4d1 --- /dev/null +++ b/samples/outlook/35-notifications/add-getall-remove.yaml @@ -0,0 +1,198 @@ +id: outlook-notifications-add-getall-remove +name: Work with notification messages +description: Adds different kinds of notification messages, gets all notifications, and replaces and removes an individual notification message. +host: OUTLOOK +api_set: + Mailbox: '1.10' +script: + content: |- + document.getElementById("addProgress").addEventListener("click", addProgress); + document.getElementById("addInformational").addEventListener("click", addInformational); + document.getElementById("addInformationalPersisted").addEventListener("click", addInformationalPersisted); + document.getElementById("addInsight").addEventListener("click", addInsight); + document.getElementById("addError").addEventListener("click", addError); + document.getElementById("getAll").addEventListener("click", getAll); + document.getElementById("replace").addEventListener("click", replace); + document.getElementById("remove").addEventListener("click", remove); + + function addProgress() { + // Adds a progress indicator to the mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, handleResult); + } + + function addInformational() { + // Adds an informational notification to the mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, handleResult); + } + + function addInformationalPersisted() { + // Adds a persistent information notification to the mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, handleResult); + } + + function addInsight() { + // Adds an informational message with actions to the mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + + const itemId = Office.context.mailbox.item.itemId; + const details = { + type: Office.MailboxEnums.ItemNotificationMessageType.InsightMessage, + message: "This is an insight notification with id = " + id, + icon: "PG.Icon.16", + actions: [ + { + actionText: "Open insight", + actionType: Office.MailboxEnums.ActionType.ShowTaskPane, + // Identify whether the current mail item is in read or compose mode to set the appropriate commandId value. + commandId: (itemId == undefined ? "PG.HelpCommand.Compose" : "PG.HelpCommand.Read"), + contextData: { a: "aValue", b: "bValue" } + } + ] + }; + + Office.context.mailbox.item.notificationMessages.addAsync(id, details, handleResult); + } + + function addError() { + // Adds an error notification to the mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ErrorMessage, + message: "Error notification message with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, handleResult); + } + + function getAll() { + // Gets all the notification messages and their keys for the current mail item. + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); + } + + function replace() { + // Replaces a notification message of a given key with another message. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); + } + + function remove() { + // Removes a notification message from the current mail item. + const id = (document.getElementById("notificationId") as HTMLInputElement).value; + Office.context.mailbox.item.notificationMessages.removeAsync(id, handleResult); + } + + function handleResult(result) { + // Helper method to display the result of an asynchronous call. + console.log(result); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to add different kinds of notification messages, get all, replace, and remove an individual notification message.

    +
    +
    +

    Try it out

    +
    + + +
    +

    Add a notification

    +

    To add a notification, enter a unique ID for the notification in the text field, then select one of the notification types below.

    +

    Note:

    +
      +
    • You can add a maximum of five notifications per mail item.
    • +
    • You can only add one insight notification to a mail item.
    • +
    • In Outlook on the web and in new Outlook on Windows, you can only add an insight notification to an item in compose mode.
    • +
    + +
    + +
    + +
    + +
    + +

    Get all notifications

    + +

    Replace a notification

    +

    To replace a notification with an informational message, enter the ID of the notification you want to replace in the text field, then select Replace notification.

    + +

    Remove a notification

    +

    To remove a notification, enter the ID of the notification you want to remove in the text field, then select Remove notification.

    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/40-attachments/attachments-compose.yaml b/samples/outlook/40-attachments/attachments-compose.yaml new file mode 100644 index 000000000..6d26d5131 --- /dev/null +++ b/samples/outlook/40-attachments/attachments-compose.yaml @@ -0,0 +1,160 @@ +id: outlook-attachments-attachments-compose +name: Manipulate attachments (Item Compose) +description: Adds, gets, and removes attachments from a message or an appointment in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("add").addEventListener("click", add); + document.getElementById("addBase64").addEventListener("click", addBase64); + document.getElementById("get").addEventListener("click", get); + document.getElementById("remove").addEventListener("click", remove); + + function add() { + const attachmentUrl = (document.getElementById("attachmentUrl") as HTMLInputElement).value; + Office.context.mailbox.item.addFileAttachmentAsync( + attachmentUrl, + getFileName(attachmentUrl), + { isInline: false }, + (result) => { + console.log(result); + } + ); + } + + function addBase64() { + const base64String = + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsSAAALEgHS3X78AAACRUlEQVRYw82XzXHbMBCFP2F8tzsQc8Ixyh0zoiuIXIGdCsxUYKqC0B04FdiuwMoM7mGOOIXqQGoAymXhgSX+itJM9kIRFLAP+3YXD5Pdbscx5oxaAIW8Ztr6l2PWmQwF4IyaieP53qdfAqQ8CwBn1JU4vpWhrbxXQA5MZfynANmcDIAzKgcy4FKGXsVJFf3nLgKyBQptfT4KQMRz2N0fcbxqmRMDWXflx0VPnrdArq0vekQ1Dv0UeHZGNebHhwjU8AzwKM43RyZnbAf58Q6ghudeWd0Aus0+5EcMIIRi3beua0D3Nm39BEAx3i7HTK4DEBJn5YxKOnaRA5+ErpMBWMpzDvx1RuXCcxOISlufAjfC7zgAsqsvUvMAD0ApPaEtGi9AIlUzKgJo60tt/SyKRkzLrAXERluf7W1gOICWaMyB386oooOWsIHvXbSoHuUSFovtHqicUVnH3EJoeT0aQEf5/XBGlc6otIOWBXAtPeZkAIJ9Bt6cUU9tZautX2nrk3MACHYr1ZKProKRtDw4o8pzAPjWo+NtpXTTvoteDDg8noDAcwbcRedAkGdFXyk2GEDcegVAFp2gyVDHjRQ4o6q2smoqtR5Hd+qMqtoALCWUUymr1m43QMZfOaMK4C0SrMsDANJ2E5FNcbdbjHC+ENl+H0myJFbLtaq4Rt8dyPBYRQV1E40nMv9rl7xrOw3DGb+Whcqu3i/OM6CUOWvgRlufNmnLYy4m77uJI7AXtdNcTDrU71LEyv7v01/N/ovL6bmu5/8A1tNWZldH0W4AAAAASUVORK5CYII="; + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + base64String, + "logo.png", + { isInline: false }, + (result) => { + console.log(result); + } + ); + } + + function get() { + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + if (result.value.length > 0) { + for (let i = 0; i < result.value.length; i++) { + const attachment = result.value[i]; + let attachmentType; + switch (attachment.attachmentType) { + case Office.MailboxEnums.AttachmentType.Cloud: + attachmentType = "Attachment is stored in a cloud location"; + break; + case Office.MailboxEnums.AttachmentType.File: + attachmentType = "Attachment is a file"; + break; + case Office.MailboxEnums.AttachmentType.Item: + attachmentType = "Attachment is an Exchange item"; + break; + } + console.log( + "ID: " + + attachment.id + + "\n" + + "Type: " + + attachmentType + + "\n" + + "Name: " + + attachment.name + + "\n" + + "Size: " + + attachment.size + + "\n" + + "isInline: " + + attachment.isInline + ); + } + } else { + console.log("No attachments on this message."); + } + }); + } + + function remove() { + Office.context.mailbox.item.removeAttachmentAsync( + (document.getElementById("attachmentId") as HTMLInputElement).value, + (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(`Attachment removed successfully.`); + } + ); + } + + function getFileName(url) { + const lastIndex = url.lastIndexOf("/"); + if (lastIndex >= 0) { + return url.substring(lastIndex + 1); + } + return url; + } + language: typescript +template: + content: |- +
    +

    This sample shows how to add, get, and remove attachments from a message or an appointment in Compose mode.

    +

    Required mode: Item Compose

    +
    +
    +

    Try it out

    +
    +

    ADD

    + +
    + + +
    + +
    +

    GET

    + +
    +

    REMOVE

    +
    + + +
    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/40-attachments/get-attachment-content.yaml b/samples/outlook/40-attachments/get-attachment-content.yaml new file mode 100644 index 000000000..b4c3f5fde --- /dev/null +++ b/samples/outlook/40-attachments/get-attachment-content.yaml @@ -0,0 +1,107 @@ +id: outlook-attachments-get-attachment-content +name: Get attachment content +description: Gets the attachment content in read or compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("attachment-content-compose").addEventListener("click", getAttachmentContentCompose); + document.getElementById("attachment-content-read").addEventListener("click", getAttachmentContentRead); + + function getAttachmentContentCompose() { + // Gets the attachments of the current message or appointment in compose mode. The getAttachmentsAsync call can only be used in compose mode. + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + if (result.value.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + for (let i = 0; i < result.value.length; i++) { + // Log the attachment type and its contents to the console. + Office.context.mailbox.item.getAttachmentContentAsync(result.value[i].id, handleAttachmentsCallback); + } + }); + } + + function getAttachmentContentRead() { + // Gets the attachments of the current message or appointment in read mode. The item.attachments call can only be used in read mode. + const item = Office.context.mailbox.item; + const attachments = item.attachments; + if (attachments.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + for (let i = 0; i < attachments.length; i++) { + // Log the attachment type and its contents to the console. + item.getAttachmentContentAsync(attachments[i].id, handleAttachmentsCallback); + } + } + + function handleAttachmentsCallback(result) { + // Identifies whether the attachment is a Base64-encoded string, .eml file, .icalendar file, or a URL. + switch (result.value.format) { + case Office.MailboxEnums.AttachmentContentFormat.Base64: + // Handle file attachment. + console.log("Attachment is a Base64-encoded string."); + break; + case Office.MailboxEnums.AttachmentContentFormat.Eml: + // Handle email item attachment. + console.log("Attachment is a message."); + break; + case Office.MailboxEnums.AttachmentContentFormat.ICalendar: + // Handle .icalender attachment. + console.log("Attachment is a calendar item."); + break; + case Office.MailboxEnums.AttachmentContentFormat.Url: + // Handle cloud attachment. + console.log("Attachment is a cloud attachment."); + break; + default: + // Handle attachment formats that aren't supported. + } + + console.log(result.value.content); + } + language: typescript +template: + content: |- +
    +

    This sample gets the attachment content from a message or an appointment in read or compose mode.

    +

    Required mode: Compose or Read

    +
    +
    +

    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; + min-width: 80px; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/40-attachments/get-attachments-read.yaml b/samples/outlook/40-attachments/get-attachments-read.yaml new file mode 100644 index 000000000..1177cb2b2 --- /dev/null +++ b/samples/outlook/40-attachments/get-attachments-read.yaml @@ -0,0 +1,59 @@ +id: outlook-attachments-get-attachments-read +name: Get attachments (Item Read) +description: Gets the attachments of a message or an appointment in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + const item = Office.context.mailbox.item; + + if (item.attachments.length > 0) { + for (let i = 0; i < item.attachments.length; i++) { + const attachment = item.attachments[i]; + console.log(`${i+1}. Name: ${attachment.name}`); + console.log(`ID: ${attachment.id}`); + console.log(`Type: ${attachment.attachmentType}`); + console.log(`Inline content: ${attachment.isInline}`); + console.log(`Size: ${attachment.size}`); + } + } else { + console.log("This mail item doesn't contain any attachments."); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the attachments of a message or an appointment in Read mode.

    +

    Required mode: Item Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/45-categories/work-with-categories.yaml b/samples/outlook/45-categories/work-with-categories.yaml new file mode 100644 index 000000000..c547ef97a --- /dev/null +++ b/samples/outlook/45-categories/work-with-categories.yaml @@ -0,0 +1,115 @@ +order: 1 +id: outlook-categories-work-with-categories +name: Work with item categories +description: Gets, adds, and removes categories assigned to the item. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("get-categories").addEventListener("click", getCategories); + document.getElementById("add-categories").addEventListener("click", addCategories); + document.getElementById("remove-categories").addEventListener("click", removeCategories); + + function getCategories() { + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function addCategories() { + // Note: In order for you to successfully add a category, + // it must be in the mailbox categories master list. + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function removeCategories() { + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get, add, and remove categories assigned to the item.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/45-categories/work-with-master-categories.yaml b/samples/outlook/45-categories/work-with-master-categories.yaml new file mode 100644 index 000000000..2e83b3645 --- /dev/null +++ b/samples/outlook/45-categories/work-with-master-categories.yaml @@ -0,0 +1,95 @@ +order: 2 +id: outlook-categories-work-with-master-categories +name: Work with the categories master list +description: Gets, adds, and removes categories in the master list for the mailbox. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("get-master-categories").addEventListener("click", getMasterCategories); + document.getElementById("add-master-categories").addEventListener("click", addMasterCategories); + document.getElementById("remove-master-categories").addEventListener("click", removeMasterCategories); + + function getMasterCategories() { + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Master categories:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories in the master list."); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function addMasterCategories() { + const masterCategoriesToAdd = [ + { + displayName: "TestCategory", + color: Office.MailboxEnums.CategoryColor.Preset0 + } + ]; + + Office.context.mailbox.masterCategories.addAsync(masterCategoriesToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully added categories to master list"); + } else { + console.log("masterCategories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } + + function removeMasterCategories() { + const masterCategoriesToRemove = ["TestCategory"]; + + Office.context.mailbox.masterCategories.removeAsync(masterCategoriesToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully removed categories from master list"); + } else { + console.log("masterCategories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get, add, and remove master categories on the mailbox.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/50-recurrence/get-recurrence-read.yaml b/samples/outlook/50-recurrence/get-recurrence-read.yaml new file mode 100644 index 000000000..0d37bbe0a --- /dev/null +++ b/samples/outlook/50-recurrence/get-recurrence-read.yaml @@ -0,0 +1,55 @@ +order: 2 +id: outlook-recurrence-get-recurrence-read +name: Get recurrence (Read) +description: Gets the recurrence pattern of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + const recurrence = Office.context.mailbox.item.recurrence; + + if (recurrence === undefined) { + console.log("This item is a message but not a meeting request."); + } else if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(JSON.stringify(recurrence)); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the item's recurrence pattern, if any.

    +

    Required modes: Appointment Attendee, Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/50-recurrence/get-series-id.yaml b/samples/outlook/50-recurrence/get-series-id.yaml new file mode 100644 index 000000000..e78ac2628 --- /dev/null +++ b/samples/outlook/50-recurrence/get-series-id.yaml @@ -0,0 +1,54 @@ +order: 1 +id: outlook-recurrence-get-series-id +name: Get the series ID +description: Gets the series ID. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get-series-id").addEventListener("click", getSeriesId); + + function getSeriesId() { + const seriesId = Office.context.mailbox.item.seriesId; + + if (seriesId === undefined) { + console.log("This is a message that's not a meeting request."); + } else if (seriesId === null) { + console.log("This is a single appointment, a parent series, or a meeting request for a series or single meeting."); + } else { + console.log("This is an instance belonging to series with ID " + seriesId); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the item's series ID, if any.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml b/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml new file mode 100644 index 000000000..d9eb6f01a --- /dev/null +++ b/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml @@ -0,0 +1,99 @@ +order: 3 +id: outlook-recurrence-get-set-recurrence-appointment-organizer +name: Get and set recurrence (Appointment Organizer) +description: Gets and sets the recurrence pattern in Appointment Organizer mode. +host: OUTLOOK +api_set: + Mailbox: '1.7' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + document.getElementById("set").addEventListener("click", set); + + function get() { + Office.context.mailbox.item.recurrence.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const recurrence = asyncResult.value; + if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(`Recurrence pattern: ${JSON.stringify(recurrence)}`); + } + } else { + console.error(asyncResult.error); + } + }); + } + + function set() { + // Important: Can only set the recurrence pattern of an appointment series. + + const currentDate = new Date(); + let seriesTimeObject: Office.SeriesTime; + // Set series start date to tomorrow. + seriesTimeObject.setStartDate(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDay() + 1); + // Set series end date to one year from now. + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, currentDate.getMonth() + 1, currentDate.getDay()); + // Set start time to 1:30 PM. + seriesTimeObject.setStartTime(13, 30); + // Set duration to 30 minutes. + seriesTimeObject.setDuration(30); + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the item's recurrence pattern, if any.

    +

    Required mode: Appointment Organizer

    +
    +
    +

    Try it out

    + +

    Note: You can only set the recurrence pattern on a series. + +

    +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/55-display-items/display-existing-appointment.yaml b/samples/outlook/55-display-items/display-existing-appointment.yaml new file mode 100644 index 000000000..aaa259233 --- /dev/null +++ b/samples/outlook/55-display-items/display-existing-appointment.yaml @@ -0,0 +1,68 @@ +order: 4 +id: outlook-display-items-display-existing-appointment +name: Open an appointment +description: Displays existing appointment in a separate window +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + // Pre-populate with current item ID. + (document.getElementById("itemId") as HTMLInputElement).value = Office.context.mailbox.item.itemId; + + document.getElementById("run").addEventListener("click", run); + document.getElementById("run-async").addEventListener("click", runAsync); + + function run() { + const itemId = (document.getElementById("itemId") as HTMLInputElement).value; + Office.context.mailbox.displayAppointmentForm(itemId); + } + + function runAsync() { + const itemId = (document.getElementById("itemId") as HTMLInputElement).value; + + // The async version will return error 9049 if the item is not found. + // The async version is only available starting with requirement set 1.9. + Office.context.mailbox.displayAppointmentFormAsync(itemId, function(asyncResult) { + console.log("Result: " + JSON.stringify(asyncResult)); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to display an existing appointment in a separate window.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/55-display-items/display-existing-message.yaml b/samples/outlook/55-display-items/display-existing-message.yaml new file mode 100644 index 000000000..4509b080b --- /dev/null +++ b/samples/outlook/55-display-items/display-existing-message.yaml @@ -0,0 +1,68 @@ +order: 3 +id: outlook-display-items-display-existing-message +name: Open a message +description: Displays an existing message in a separate window +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + // Pre-populate with current item ID. + (document.getElementById("itemId") as HTMLInputElement).value = Office.context.mailbox.item.itemId; + + document.getElementById("run").addEventListener("click", run); + document.getElementById("run-async").addEventListener("click", runAsync); + + function run() { + const itemId = (document.getElementById("itemId") as HTMLInputElement).value; + Office.context.mailbox.displayMessageForm(itemId); + } + + function runAsync() { + const itemId = (document.getElementById("itemId") as HTMLInputElement).value; + + // The async version will return error 9049 if the item is not found. + // The async version is only available starting with requirement set 1.9. + Office.context.mailbox.displayMessageFormAsync(itemId, function (asyncResult) { + console.log("Result: " + JSON.stringify(asyncResult)); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to display an existing message in a separate window.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/55-display-items/display-new-appointment.yaml b/samples/outlook/55-display-items/display-new-appointment.yaml new file mode 100644 index 000000000..f562ea6c9 --- /dev/null +++ b/samples/outlook/55-display-items/display-new-appointment.yaml @@ -0,0 +1,88 @@ +order: 2 +id: outlook-display-items-display-new-appointment +name: Create a new appointment +description: Opens a new appointment form with sample content and a few fields populated. +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + document.getElementById("run-async").addEventListener("click", runAsync); + + function run() { + const start = new Date(); + const end = new Date(); + end.setHours(start.getHours() + 1); + + Office.context.mailbox.displayNewAppointmentForm({ + requiredAttendees: ["bob@contoso.com"], + optionalAttendees: ["sam@contoso.com"], + start: start, + end: end, + location: "Home", + subject: "meeting", + resources: ["projector@contoso.com"], + body: "Hello World!" + }); + } + + function runAsync() { + const start = new Date(); + const end = new Date(); + end.setHours(start.getHours() + 1); + + // The async version is only available starting with requirement set 1.9, + // and provides a callback when the new appointment form has been created. + Office.context.mailbox.displayNewAppointmentFormAsync( + { + requiredAttendees: ["bob@contoso.com"], + optionalAttendees: ["sam@contoso.com"], + start: start, + end: end, + location: "Home", + subject: "meeting", + resources: ["projector@contoso.com"], + body: "Hello World!" + }, + function(asyncResult) { + console.log(JSON.stringify(asyncResult)); + } + ); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to display a new appointment and populate attendees, location, body, and a few other + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/55-display-items/display-new-message.yaml b/samples/outlook/55-display-items/display-new-message.yaml new file mode 100644 index 000000000..0302dc756 --- /dev/null +++ b/samples/outlook/55-display-items/display-new-message.yaml @@ -0,0 +1,87 @@ +order: 1 +id: outlook-display-items-display-new-message +name: Create a new message +description: Opens a new message form with a sample content, recipients, and an inline image attachment +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + document.getElementById("run-async").addEventListener("click", runAsync); + + function run() { + Office.context.mailbox.displayNewMessageForm({ + toRecipients: Office.context.mailbox.item.to, // Copies the To line from current item + ccRecipients: ["sam@contoso.com"], + subject: "Outlook add-ins are cool!", + htmlBody: 'Hello World!
    ', + attachments: [ + { + type: "file", + name: "image.png", + url: "https://i.imgur.com/9S36xvA.jpg", + isInline: true + } + ] + }); + } + + function runAsync() { + // The async version is only available starting with requirement set 1.9, + // and provides a callback when the new message form has been created. + Office.context.mailbox.displayNewMessageFormAsync( + { + toRecipients: Office.context.mailbox.item.to, // Copies the To line from current item + ccRecipients: ["sam@contoso.com"], + subject: "Outlook add-ins are cool!", + htmlBody: 'Hello World!
    ', + attachments: [ + { + type: "file", + name: "image.png", + url: "https://i.imgur.com/9S36xvA.jpg", + isInline: true + } + ] + }, + (asyncResult) => { + console.log(JSON.stringify(asyncResult)); + } + ); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to display a new message, populate recipients, subject, and body, and add an inline image attachment.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/55-display-items/display-reply-forms.yaml b/samples/outlook/55-display-items/display-reply-forms.yaml new file mode 100644 index 000000000..3759106b0 --- /dev/null +++ b/samples/outlook/55-display-items/display-reply-forms.yaml @@ -0,0 +1,80 @@ +order: 5 +id: outlook-display-items-display-reply-forms +name: Create replies +description: Opens reply and reply-all message forms with sample reply content. +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + document.getElementById("display-reply-form").addEventListener("click", displayReplyForm); + document.getElementById("display-reply-form-async").addEventListener("click", displayReplyFormAsync); + document.getElementById("display-reply-all-form").addEventListener("click", displayReplyAllForm); + document.getElementById("display-reply-all-form-async").addEventListener("click", displayReplyAllFormAsync); + + // The async version is only available starting with requirement set 1.9. + function displayReplyForm() { + Office.context.mailbox.item.displayReplyForm("This is a reply with some text in italics."); + } + + function displayReplyFormAsync() { + Office.context.mailbox.item.displayReplyFormAsync("This is a reply with some text in italics.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + } + + function displayReplyAllForm() { + Office.context.mailbox.item.displayReplyAllForm("This is a reply ALL with some bold text."); + } + + function displayReplyAllFormAsync() { + Office.context.mailbox.item.displayReplyAllFormAsync("This is a reply ALL with some bold text.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to create reply or reply-all messages and populate the body of the reply.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/55-display-items/display-reply-with-attachments.yaml b/samples/outlook/55-display-items/display-reply-with-attachments.yaml new file mode 100644 index 000000000..bb2dbd573 --- /dev/null +++ b/samples/outlook/55-display-items/display-reply-with-attachments.yaml @@ -0,0 +1,209 @@ +order: 6 +id: outlook-display-items-display-reply-with-attachments +name: Create a reply with attachments +description: Opens a reply or reply-all message form and adds sample attachments. +host: OUTLOOK +api_set: + Mailbox: '1.9' +script: + content: |- + document.getElementById("reply").addEventListener("click", reply); + document.getElementById("reply-async").addEventListener("click", replyAsync); + document.getElementById("reply-all").addEventListener("click", replyAll); + document.getElementById("reply-all-async").addEventListener("click", replyAllAsync); + + function reply() { + // Define attachments. + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + // Create the reply with attachments. + Office.context.mailbox.item.displayReplyForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

    ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply with attachments."); + } + }); + } + + function replyAll() { + // Define attachments. + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + // Create the reply with attachments. + Office.context.mailbox.item.displayReplyAllForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

    ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + }); + } + + function replyAsync() { + // Define attachments. + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + // The async version was introduced in requirement set 1.9. + // It provides a callback when the new appointment form has been created. + Office.context.mailbox.item.displayReplyFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

    ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created reply with attachments."); + } + ); + } + + function replyAllAsync() { + // Define attachments. + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + // The async version was introduced in requirement set 1.9. + // It provides a callback when the new appointment form has been created. + Office.context.mailbox.item.displayReplyAllFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

    ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + ); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to create a reply message and add an inline image attachment and an item attachment.

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/60-sensitivity-label/sensitivity-label.yaml b/samples/outlook/60-sensitivity-label/sensitivity-label.yaml new file mode 100644 index 000000000..6bda2298e --- /dev/null +++ b/samples/outlook/60-sensitivity-label/sensitivity-label.yaml @@ -0,0 +1,94 @@ +order: 2 +id: outlook-sensitivity-labels-sensitivity-label +name: Work with sensitivity labels (Compose) +description: Gets and sets the sensitivity label on a message or appointment in compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.13' +script: + content: |- + document.getElementById("get-sensitivity-label").addEventListener("click", getCurrentSensitivityLabel); + document.getElementById("set-sensitivity-label").addEventListener("click", setSensitivityLabel); + + function getCurrentSensitivityLabel() { + // This snippet gets the current mail item's sensitivity label. + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.mailbox.item.sensitivityLabel.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + + function setSensitivityLabel() { + // This snippet sets the sensitivity label on the current mail item. + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.sensitivityLabelsCatalog.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const catalog = asyncResult.value; + if (catalog.length > 0) { + var id = catalog[0].id; + Office.context.mailbox.item.sensitivityLabel.setAsync(id, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.status); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + else { + console.log("Catalog list is empty"); + } + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the sensitivity label on a message or appointment being composed. To learn more about the sensitivity label API, see Manage the sensitivity label of your message or appointment in compose mode.

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml b/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml new file mode 100644 index 000000000..4467e3f77 --- /dev/null +++ b/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml @@ -0,0 +1,77 @@ +order: 1 +id: outlook-sensitivity-labels-sensitivity-labels-catalog +name: Work with the sensitivity labels catalog +description: Determines if sensitivity labels are enabled on the mailbox and retrieves all available labels from the catalog. +host: OUTLOOK +api_set: + Mailbox: '1.13' +script: + content: |- + document.getElementById("get-sensitivity-labels-enabled").addEventListener("click", getSensitivityLabelsCatalogIsEnabled); + document.getElementById("get-sensitivity-labels-catalog").addEventListener("click", getSensitivityLabelsCatalog); + + function getSensitivityLabelsCatalogIsEnabled() { + // This snippet determines if the sensitivity labels catalog is enabled on the current mailbox. + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + + function getSensitivityLabelsCatalog() { + // This snippet gets all available sensitivity labels from the catalog. + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.sensitivityLabelsCatalog.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const catalog = asyncResult.value; + console.log("Sensitivity Labels Catalog:"); + console.log(JSON.stringify(catalog)); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to determine if sensitivity labels are enabled on the mailbox and retrieves all available labels from the catalog. To learn more about the sensitivity label API, see Manage the sensitivity label of your message or appointment in compose mode.

    +

    Required mode: Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml b/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml new file mode 100644 index 000000000..2a937c32d --- /dev/null +++ b/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml @@ -0,0 +1,60 @@ +id: outlook-delegates-and-shared-folders-get-shared-properties +name: Identify a shared folder or shared mailbox context +description: Identifies whether the current mail item is in a shared folder or shared mailbox by getting its properties. +host: OUTLOOK +api_set: + Mailbox: '1.13' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to identify if the current mail item is in a shared folder or shared mailbox. This is done + by getting the item's shared properties.

    +

    Required mode: Compose, Read

    +

    Note: If you're testing this in Message Compose mode in Outlook on web or on Windows (new or classic), you + must meet certain conditions to call the getSharedPropertiesAsync method. To learn more, see Implement shared folders and shared mailbox scenarios in an Outlook add-in.

    +
    +
    +

    Try it out on a message or appointment from a shared folder or shared mailbox.

    + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml b/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml new file mode 100644 index 000000000..efdf1f74d --- /dev/null +++ b/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml @@ -0,0 +1,69 @@ +id: outlook-mime-headers-get-internet-headers-message-read +name: Get internet headers +description: Gets internet headers on a message in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.item.getAllInternetHeadersAsync(function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Internet headers received successfully"); + if (asyncResult.value.match(/preferred-fruit:.*/gim)) { + console.log("Sender's preferred fruit: " + asyncResult.value.match(/preferred-fruit:.*/gim)[0].slice(17)); + } else { + console.log("Didn't receive header with sender's preferred fruit"); + } + if (asyncResult.value.match(/preferred-vegetable:.*/gim)) { + console.log( + "Sender's preferred vegetable: " + asyncResult.value.match(/preferred-vegetable:.*/gim)[0].slice(21) + ); + } else { + console.log("Didn't receive header with sender's preferred vegetable"); + } + } else { + console.log("Error getting internet headers: " + JSON.stringify(asyncResult.error)); + } + }); + } + + /* Sample output: + Sender's preferred fruit: orange + Sender's preferred vegetable: broccoli + */ + language: typescript +template: + content: |- +
    +

    This sample shows how to get internet headers on a message in Read mode.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml b/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml new file mode 100644 index 000000000..78c540b7a --- /dev/null +++ b/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml @@ -0,0 +1,100 @@ +id: outlook-mime-headers-manage-custom-internet-headers-message-compose +name: Work with custom internet headers +description: Sets, gets, and removes custom internet headers on a message in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("set-custom-headers").addEventListener("click", setCustomHeaders); + document.getElementById("get-selected-custom-headers").addEventListener("click", getSelectedCustomHeaders); + document.getElementById("remove-selected-custom-headers").addEventListener("click", removeSelectedCustomHeaders); + + // Set custom internet headers. + function setCustomHeaders() { + Office.context.mailbox.item.internetHeaders.setAsync( + { "preferred-fruit": "orange", "preferred-vegetable": "broccoli", "best-vegetable": "spinach" }, + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully set headers"); + } else { + console.log("Error setting headers: " + JSON.stringify(asyncResult.error)); + } + } + + ); + } + + // Get custom internet headers. + function getSelectedCustomHeaders() { + Office.context.mailbox.item.internetHeaders.getAsync( + ["preferred-fruit", "preferred-vegetable", "best-vegetable", "nonexistent-header"], + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected headers: " + JSON.stringify(asyncResult.value)); + } else { + console.log("Error getting selected headers: " + JSON.stringify(asyncResult.error)); + } + } + ); + } + + // Remove custom internet headers. + function removeSelectedCustomHeaders() { + Office.context.mailbox.item.internetHeaders.removeAsync( + ["best-vegetable", "nonexistent-header"], + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully removed selected headers"); + } else { + console.log("Error removing selected headers: " + JSON.stringify(asyncResult.error)); + } + } + ); + } + + /* Sample output: + Successfully set headers + Selected headers: {"best-vegetable":"spinach","preferred-fruit":"orange","preferred-vegetable":"broccoli"} + Successfully removed selected headers + Selected headers: {"preferred-fruit":"orange","preferred-vegetable":"broccoli"} + */ + language: typescript +template: + content: |- +
    +

    This sample shows how to set, get, and remove custom internet headers on a message in Compose mode.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/75-regex-matches/contextual.yaml b/samples/outlook/75-regex-matches/contextual.yaml new file mode 100644 index 000000000..c601055e2 --- /dev/null +++ b/samples/outlook/75-regex-matches/contextual.yaml @@ -0,0 +1,85 @@ +id: outlook-regex-matches-contextual +name: Get regex matches (Item Read, contextual) +description: Gets regex matches when the add-in is opened as a contextual add-in. +host: OUTLOOK +api_set: + Mailbox: '1.6' +script: + content: |- + document.getElementById("getRegExMatches").addEventListener("click", getRegExMatches); + document.getElementById("getRegExMatchesByName").addEventListener("click", getRegExMatchesByName); + document.getElementById("getSelectedRegExMatches").addEventListener("click", getSelectedRegExMatches); + + function getRegExMatches() { + // This API only works when you click on the highlighted word "ScriptLab". + console.log(Office.context.mailbox.item.getRegExMatches()); + } + + function getRegExMatchesByName() { + // This API only works when you click on the highlighted word "ScriptLab". + console.log(Office.context.mailbox.item.getRegExMatchesByName("sampleRegexName")); + } + + function getSelectedRegExMatches() { + const matches = Office.context.mailbox.item.getSelectedRegExMatches(); + if (matches) { + console.log(matches); + } else { + console.error("Open add-in by clicking on a highlighted regex match, for this API to return something useful."); + } + } + + /* This add-in declares extension point manifest rules copied below. + For regex match, try running it on an email that has "ScriptLab" in its content. + Note: The following only applies when your add-in uses an XML manifest. Contextual add-ins aren't supported when a unified app manifest for Microsoft 365 (https://learn.microsoft.com/office/dev/add-ins/develop/unified-manifest-overview) is in use. + + + + + + */ + language: typescript +template: + content: |- +
    +

    This sample shows how to get regex matches.

    +

    Note: Contextual add-ins only support the use of an XML manifest. This feature isn't supported when your + add-in uses a + unified app manifest + for Microsoft 365.

    +

    Required mode: Item Read, contextual add-in

    +
    +
    +

    Tip: Try this out as a contextual 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/80-events/drag-drop-item.yaml b/samples/outlook/80-events/drag-drop-item.yaml new file mode 100644 index 000000000..8496c37ad --- /dev/null +++ b/samples/outlook/80-events/drag-drop-item.yaml @@ -0,0 +1,72 @@ +id: outlook-events-drag-drop-item +name: Drag and drop an item into the task pane +description: Handles the drag-and-drop event when a user drags and drops messages and file attachments into the add-in task pane. +host: OUTLOOK +api_set: + Mailbox: '1.5' +script: + content: | + Office.onReady(() => { + dragAndDropEventHandler(event); + }); + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } + language: typescript +template: + content: |- +
    +

    Drag and drop messages and file attachments into the add-in task pane.

    +

    To learn more about the drag-and-drop feature, see Drag and drop messages and + attachments into the task pane of an Outlook add-in.

    +

    Required mode: Compose or Read

    +

    Supported Outlook clients: Outlook on the web and the new Outlook on Windows

    +
    +
    +

    Try it out

    +
      +
    1. Drag a message or file attachment from your mailbox to the task pane. As you drag the item across the task pane, the event name and the coordinates of your mouse pointer are displayed in the console.
    2. +
    3. Drop the message or file attachment into the task pane. The properties + of the dropped item are displayed in the console.
    4. +
    +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml new file mode 100644 index 000000000..e8c65bb22 --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml @@ -0,0 +1,78 @@ +order: 9 +id: outlook-tokens-and-service-calls-get-icaluid-as-attendee +name: Get an appointment's iCalUId as an attendee (Exchange on-premises only) +description: Uses Exchange Web Services (EWS) in an Exchange on-premises environment to get an appointment's iCalUId value where the user is an attendee. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + const ewsId = Office.context.mailbox.item.itemId; + const request = ` + + + + + AllProperties + + + + + + + `; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(getUID(result.value)); + }); + } + + function getUID(xmlResult) { + const parser = new DOMParser(); + const xmlText = parser.parseFromString(xmlResult, "text/xml"); + return xmlText.getElementsByTagName("t:UID")[0].childNodes[0].nodeValue; + } + language: typescript +template: + content: |- +
    +

    This sample uses Exchange Web Services (EWS) to get an appointment's iCalUId value if the user is an attendee.

    +

    Important: Exchange user identity and callback tokens are only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. Then, use Microsoft Graph to get the iCalUId property. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml new file mode 100644 index 000000000..2ac46bca0 --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml @@ -0,0 +1,82 @@ +order: 8 +id: outlook-tokens-and-service-calls-get-icaluid-as-organizer +name: Get an appointment's iCalUId as the organizer (Exchange on-premises only) +description: Uses Exchange Web Services (EWS) in an Exchange on-premises environment to get an appointment's iCalUId value where the user is the organizer. +host: OUTLOOK +api_set: + Mailbox: '1.3' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.item.saveAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + const ewsId = result.value; + const request = ` + + + + + AllProperties + + + + + + + `; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(getUID(result.value)); + }); + }); + } + + function getUID(xmlResult) { + const parser = new DOMParser(); + const xmlText = parser.parseFromString(xmlResult, "text/xml"); + return xmlText.getElementsByTagName("t:UID")[0].childNodes[0].nodeValue; + } + language: typescript +template: + content: |- +
    +

    This sample uses Exchange Web Services (EWS) to get an appointment's iCalUId value if the user is the organizer.

    +

    Important: Exchange user identity and callback tokens are only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. Then, use Microsoft Graph to get the iCalUId property. +

    +
    + + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml new file mode 100644 index 000000000..d87c66aff --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml @@ -0,0 +1,61 @@ +order: 1 +id: outlook-tokens-and-service-calls-ids-and-urls +name: Endpoint URLs and item IDs in Exchange on-premises environments +description: Retrieves the Exchange Web Services (EWS) endpoint URL and item IDs and converts item IDs for different protocols. +host: OUTLOOK +api_set: + Mailbox: '1.5' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + // Get the EWS URL and EWS item ID. + console.log("EWS URL: " + Office.context.mailbox.ewsUrl); + const ewsId = Office.context.mailbox.item.itemId; + console.log("EWS item ID: " + Office.context.mailbox.item.itemId); + + // Convert the EWS item ID to a REST-formatted ID. + const restId = Office.context.mailbox.convertToRestId(ewsId, Office.MailboxEnums.RestVersion.v2_0); + console.log("REST item ID: " + restId); + + // Convert the REST-formatted ID back to an EWS-formatted ID. + const ewsId2 = Office.context.mailbox.convertToEwsId(restId, Office.MailboxEnums.RestVersion.v2_0); + console.log("EWS ID (from REST ID): " + ewsId2); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to retrieve the EWS endpoint URL and item IDs, and convert item IDs for different protocols.

    +

    Important: Exchange user identity and callback tokens are only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml new file mode 100644 index 000000000..b56e7e86d --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml @@ -0,0 +1,67 @@ +order: 6 +id: outlook-tokens-and-service-calls-make-ews-request-async +name: Get a message using Exchange Web Services (EWS) in Exchange on-premises environments +description: Uses EWS in an Exchange on-premises environment to get a message without any backend code. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + const ewsId = Office.context.mailbox.item.itemId; + const request = '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' IdOnly' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + console.log(result); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get a message using EWS, without any backend code.

    +

    Important: This API is only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. Then, use Microsoft Graph to get the message. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml new file mode 100644 index 000000000..a9d4582cf --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml @@ -0,0 +1,70 @@ +order: 7 +id: outlook-tokens-and-service-calls-send-message-using-make-ews-request-async +name: Send a message using Exchange Web Services (EWS) in Exchange on-premises environments +description: Uses EWS in an Exchange on-premises environment to send a message without any backend code. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + const request = ''+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' Hello, Outlook!'+ + ' This message was sent from a ScriptLab code sample, used from ' + Office.context.mailbox.diagnostics.hostName + ', version ' + Office.context.mailbox.diagnostics.hostVersion + '!'+ + ' '+ + ' ' + Office.context.mailbox.userProfile.emailAddress + ''+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ''; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + console.log(result); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to send a message using EWS, without any back-end code.

    +

    Important: This API is only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. Then, use Microsoft Graph to send the message. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml new file mode 100644 index 000000000..c60954ab4 --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml @@ -0,0 +1,58 @@ +order: 4 +id: outlook-tokens-and-service-calls-user-callback-token +name: Get a callback token in Exchange on-premises environments +description: Gets a callback token to call Outlook services from an add-in's backend service in an Exchange on-premises environment. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.getCallbackTokenAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Token retrieval failed with message: ${result.error.message}`); + return; + } + + console.log(result.value); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get a callback token to call Outlook services from an add-in's backend service.

    +

    Important: Exchange user identity and callback tokens are only supported in Exchange on-premises environments. + Additionally, the Outlook REST v2.0 endpoint has been deprecated. Use + nested app authentication (NAA) + to get an access token instead. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml b/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml new file mode 100644 index 000000000..35efaf934 --- /dev/null +++ b/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml @@ -0,0 +1,57 @@ +order: 3 +id: outlook-tokens-and-service-calls-user-identity-token +name: Get a user identity token in Exchange on-premises environments +description: Gets a user identity token for authentication flows in an Exchange on-premises environment. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.getUserIdentityTokenAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Token retrieval failed with message: ${result.error.message}`) + return; + } + + console.log(result.value); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get a user identity token to use in authentication flows.

    +

    Important: This API is only supported in Exchange on-premises environments. + In Exchange Online environments, use nested app authentication (NAA) + to get an access token. +

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/delay-message-delivery.yaml b/samples/outlook/90-other-item-apis/delay-message-delivery.yaml new file mode 100644 index 000000000..016265921 --- /dev/null +++ b/samples/outlook/90-other-item-apis/delay-message-delivery.yaml @@ -0,0 +1,115 @@ +order: 21 +id: outlook-delay-message-delivery +name: Get and set message delivery (Message Compose) +description: Gets and sets the delivery date and time of a message in compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.13' +script: + content: |- + document.getElementById("get-date").addEventListener("click", getDeliveryDate); + document.getElementById("set-time-five-minutes").addEventListener("click", () => computeDelay("set-time-five-minutes")); + document.getElementById("set-time-fifteen-minutes").addEventListener("click", () => computeDelay("set-time-fifteen-minutes")); + document.getElementById("set-time-thirty-minutes").addEventListener("click", () => computeDelay("set-time-thirty-minutes")); + document.getElementById("set-time-sixty-minutes").addEventListener("click", () => computeDelay("set-time-sixty-minutes")); + document.getElementById("set-time-one-day").addEventListener("click", () => computeDelay("set-time-one-day")); + + let totalDelay = 0; + + function computeDelay(input) { + // This snippet identifies additional delivery delay time in minutes and adds it to the total delivery delay time of a message. + const element = document.getElementById(input) as HTMLInputElement | null; + if (element != null) { + const minutes = Number(element.value); + totalDelay += minutes; + setDeliveryDate(minutes); + } + } + + function getDeliveryDate() { + // This snippet gets the delivery date and time of a message. + Office.context.mailbox.item.delayDeliveryTime.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + const deliveryDate = asyncResult.value; + if (deliveryDate === 0) { + console.log("Your message will be delivered immediately when you select Send."); + } else { + const date = new Date(deliveryDate); + console.log(`Message delivery date and time: ${date.toString()}`); + } + }); + } + + function setDeliveryDate(minutes) { + // This snippet sets the delivery date and time of a message. + const currentTime = new Date().getTime(); + const milliseconds = totalDelay * 60000; + const timeDelay = new Date(currentTime + milliseconds); + Office.context.mailbox.item.delayDeliveryTime.setAsync(timeDelay, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + if (minutes === 1440) { + console.log(`Delayed delivery by an additional one day.`); + } else { + console.log(`Delayed delivery by an additional ${minutes} minutes.`); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample gets and sets the delivery date and time of a message in compose mode. To learn more about this API, see Manage the delivery date and time of a message.

    +

    Required mode: Compose

    +
    +
    +

    Try it out

    +
    + +
    +

    Delay message delivery by:

    + + + + + +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml b/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml new file mode 100644 index 000000000..6366043dc --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml @@ -0,0 +1,114 @@ +order: 13 +id: outlook-other-item-apis-get-add-remove-enhancedlocation-appointment +name: Manage the locations of an appointment +description: Gets, adds, and removes locations on an appointment (enhancedLocation API). +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + document.getElementById("add").addEventListener("click", add); + document.getElementById("remove").addEventListener("click", remove); + + function get() { + Office.context.mailbox.item.enhancedLocation.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to get locations. Error message: ${result.error.message}`); + return; + } + const places = result.value; + if (places && places.length > 0) { + result.value.forEach(function(place) { + console.log(`Location: ${place.displayName} (type: ${place.locationIdentifier.type})`); + if (place.locationIdentifier.type === Office.MailboxEnums.LocationType.Room) { + console.log("Email address: " + place.emailAddress); + } + }); + } else { + console.log("There are no locations."); + } + }); + } + + function add() { + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + Office.context.mailbox.item.enhancedLocation.addAsync(locations, (result) => { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully added locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to add locations. Error message: ${result.error.message}`); + } + }); + } + + function remove() { + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + Office.context.mailbox.item.enhancedLocation.removeAsync(locations, (result) => { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully removed locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to remove locations. Error message: ${result.error.message}`); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get and set the location of an appointment.

    +

    Required modes: Appointment Organizer, Appointment Attendee

    +
    +
    +

    Try it out

    + +

    + Note: Can add or remove locations in Organizer mode only. + + +

    +
    + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml b/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml new file mode 100644 index 000000000..b95c68138 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml @@ -0,0 +1,47 @@ +order: 15 +id: outlook-other-item-apis-get-conversation-id-message +name: Get the conversation ID (Message) +description: Gets the conversation ID of a message. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Conversation ID: ${Office.context.mailbox.item.conversationId}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the conversation ID of a message.

    +

    Required modes: Message Compose, Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-conversation-index.yaml b/samples/outlook/90-other-item-apis/get-conversation-index.yaml new file mode 100644 index 000000000..9966ed3f1 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-conversation-index.yaml @@ -0,0 +1,61 @@ +order: 27 +id: outlook-get-conversation-index +name: Get the position of a message in a conversation (Message Compose) +description: Retrieves the Base64-encoded position of the current message in a conversation thread. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("get-conversation-index").addEventListener("click", getConversationIndex); + + function getConversationIndex() { + // This snippet returns the Base64-encoded position of the current message in a conversation thread (PR_CONVERSATION_INDEX). + // The API call is supported on a message being composed and isn't supported on read items or appointments. + Office.context.mailbox.item.getConversationIndexAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + const conversationIndex = result.value; + if (conversationIndex) { + console.log("Position in the conversation thread: " + conversationIndex); + } else { + console.log("The current message doesn't belong to a conversation thread."); + } + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the Base64-encoded position of the current message in a conversation thread.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml b/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml new file mode 100644 index 000000000..172ec5713 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml @@ -0,0 +1,47 @@ +order: 16 +id: outlook-other-item-apis-get-date-time-created-read +name: Get the creation date and time (Read) +description: Gets the creation date and time of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Creation date and time: ${Office.context.mailbox.item.dateTimeCreated}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the creation date and time of an item in Read mode.

    +

    Required modes: Appointment Attendee, Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml b/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml new file mode 100644 index 000000000..0ec907837 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml @@ -0,0 +1,47 @@ +order: 17 +id: outlook-other-item-apis-get-date-time-modified-read +name: Get the last-modified date and time (Read) +description: Gets the last-modified date and time of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Date and time item last modified: ${Office.context.mailbox.item.dateTimeModified}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the last-modified date and time of an item in Read mode.

    +

    Required modes: Appointment Attendee, Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml b/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml new file mode 100644 index 000000000..0d9622fa0 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml @@ -0,0 +1,68 @@ +order: 18 +id: outlook-other-item-apis-get-diagnostic-information +name: Get mailbox diagnostic information +description: Gets a mailbox's diagnostic information. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-diagnostics").addEventListener("click", getDiagnostics); + + function getDiagnostics() { + // This function gets a mailbox's diagnostic information, such as Outlook client and version, and logs it to the console. + const diagnostics = Office.context.mailbox.diagnostics; + console.log(`Client application: ${diagnostics.hostName}`); + console.log(`Client version: ${diagnostics.hostVersion}`); + + switch (diagnostics.OWAView) { + case undefined: + console.log("Current view (Outlook on the web only): Not applicable. An Outlook desktop client is in use."); + break; + case Office.MailboxEnums.OWAView.OneColumnNarrow: + console.log("Current view (Outlook on the web only): Viewed from an older generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.OneColumn: + console.log("Current view (Outlook on the web only): Viewed from a newer generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.TwoColumns: + console.log("Current view (Outlook on the web only): Viewed from a tablet"); + break; + case Office.MailboxEnums.OWAView.ThreeColumns: + console.log("Current view (Outlook on the web only): Viewed from a desktop computer"); + break; + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get a mailbox's diagnostic information.

    +

    Required mode: Compose, Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-eml-format.yaml b/samples/outlook/90-other-item-apis/get-eml-format.yaml new file mode 100644 index 000000000..03c7207ed --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-eml-format.yaml @@ -0,0 +1,54 @@ +order: 25 +id: outlook-get-eml-format +name: Get the Base64-encoded EML format of a message (Message Read) +description: Gets the Base64-encoded EML format of a message in read mode. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("get-eml-format").addEventListener("click", getEmlFormat); + + function getEmlFormat() { + Office.context.mailbox.item.getAsFileAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Error encountered during processing: ${asyncResult.error.message}`); + return; + } + + console.log(asyncResult.value); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the Base64-encoded EML format of a message in read mode.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-end-read.yaml b/samples/outlook/90-other-item-apis/get-end-read.yaml new file mode 100644 index 000000000..2a94acc22 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-end-read.yaml @@ -0,0 +1,58 @@ +order: 9 +id: outlook-other-item-apis-get-end-read +name: Get the end date and time (Read) +description: Gets the end date and time of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-utc").addEventListener("click", getUtc); + document.getElementById("get-local").addEventListener("click", getLocal); + + function getUtc() { + const time = Office.context.mailbox.item.end; + console.log(`Appointment ends (UTC): ${time.toUTCString()}`); + } + + function getLocal() { + const time = Office.context.mailbox.item.end; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment ends (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the end date and time of an item in Read mode.

    +

    Required modes: Appointment Attendee, Message Read (meeting request)

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-in-reply-to.yaml b/samples/outlook/90-other-item-apis/get-in-reply-to.yaml new file mode 100644 index 000000000..70f961e5e --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-in-reply-to.yaml @@ -0,0 +1,54 @@ +order: 26 +id: outlook-get-in-reply-to +name: Get the ID of the message being replied to (Message Compose) +description: Retrieves the ID of the message being replied to by the current message. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("get-in-reply-to").addEventListener("click", getInReplyTo); + + function getInReplyTo() { + // This snippet gets the ID of the message being replied to by the current message (PR_IN_REPLY_TO_ID). + // The API call is supported on messages being composed and isn't supported on read items. + const inReplyTo = Office.context.mailbox.item.inReplyTo; + if (inReplyTo) { + console.log("ID of the message being replied to: " + inReplyTo); + } else { + console.log("No InReplyTo property available for this message"); + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the ID of the message being replied to by the current message.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml b/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml new file mode 100644 index 000000000..aa5c12ad2 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml @@ -0,0 +1,47 @@ +order: 4 +id: outlook-other-item-apis-get-internet-message-id-read +name: Get the internet message ID (Message Read) +description: Gets the internet message ID of a message in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Internet message ID: ${Office.context.mailbox.item.internetMessageId}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the internet message ID of a message in Read mode.

    +

    Required mode: Message Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-item-class-async.yaml b/samples/outlook/90-other-item-apis/get-item-class-async.yaml new file mode 100644 index 000000000..a812e22ca --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-item-class-async.yaml @@ -0,0 +1,56 @@ +order: 28 +id: outlook-get-item-class-async +name: Get item class (Message Compose) +description: Retrieves the item class property of the message being composed. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("get-item-class-async").addEventListener("click", getItemClassAsync); + + function getItemClassAsync() { + // This snippet returns the Exchange Web Services item class property (PR_MESSAGE_CLASS) of the current message. + // The API call is only supported on a message being composed. + Office.context.mailbox.item.getItemClassAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log("Item class of the current message: " + asyncResult.value); + }); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the Exchange Web Services (EWS) item class of the current message being composed.

    +

    Required mode: Message Compose

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-item-class-read.yaml b/samples/outlook/90-other-item-apis/get-item-class-read.yaml new file mode 100644 index 000000000..fb319fb09 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-item-class-read.yaml @@ -0,0 +1,47 @@ +order: 5 +id: outlook-other-item-apis-get-item-class-read +name: Get the item class (Read) +description: Gets the item class of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Item class: ${Office.context.mailbox.item.itemClass}`); + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the item class of an item in Read mode.

    +

    Required mode: Read

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-item-type.yaml b/samples/outlook/90-other-item-apis/get-item-type.yaml new file mode 100644 index 000000000..93713bd74 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-item-type.yaml @@ -0,0 +1,54 @@ +order: 6 +id: outlook-other-item-apis-get-item-type +name: Get the item type +description: Gets the item type. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + const itemType = Office.context.mailbox.item.itemType; + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the item type.

    +
    +
    +

    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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml b/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml new file mode 100644 index 000000000..eaf183cf9 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml @@ -0,0 +1,148 @@ +order: 31 +id: outlook-other-item-apis-get-loaded-message-properties +name: Get properties of a loaded message (Message Compose, Message Read) +description: Gets the properties of the currently loaded message. +host: OUTLOOK +api_set: + Mailbox: '1.15' +script: + content: |- + let list; + + Office.onReady((info) => { + if (info.host === Office.HostType.Outlook) { + list = document.getElementById("selected-items"); + + // Register an event handler to identify when messages are selected. + Office.context.mailbox.addHandlerAsync(Office.EventType.SelectedItemsChanged, run, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log("Event handler added."); + }); + + run(); + } + }); + + function run() { + // Clear the list of previously selected messages, if any. + clearList(list); + + // Get the subject line and sender's email address of each selected message and log them to a list in the task pane. + Office.context.mailbox.getSelectedItemsAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + const selectedItems = asyncResult.value; + + getItemInfo(selectedItems); + }); + } + + // Gets the subject line and sender's email address of each selected message. + async function getItemInfo(selectedItems) { + for (const item of selectedItems) { + addToList(item.subject); + await getSenderEmailAddress(item); + } + } + + // Gets the sender's email address of each selected message. + async function getSenderEmailAddress(item) { + const itemId = item.itemId; + await new Promise((resolve) => { + Office.context.mailbox.loadItemByIdAsync(itemId, (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + const loadedItem = result.value; + const sender = loadedItem.from.emailAddress; + appendToListItem(sender); + + // Unload the current message before processing another selected message. + loadedItem.unloadAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + resolve(); + }); + }); + }); + } + + // Clears the list in the task pane. + function clearList(list) { + while (list.firstChild) { + list.removeChild(list.firstChild); + } + } + + // Adds an item to a list in the task pane. + function addToList(item) { + const listItem = document.createElement("li"); + listItem.textContent = item; + list.appendChild(listItem); + } + + // Appends data to the last item of the list in the task pane. + function appendToListItem(data) { + const listItem = list.lastChild; + listItem.textContent += ` (${data})`; + } + language: typescript +template: + content: |- +
    +

    This sample shows how to get the properties of the currently loaded message.

    +

    Required mode: Message Compose, Message Read

    +
    +
    +

    Try it out

    +
      +
    1. +

      Turn on the Reading Pane in Outlook. For guidance, see Use + and configure the Reading Pane to preview messages.

      +
    2. +
    3. +

      Select a message from your mailbox. To select multiple messages, hold Ctrl (Windows) while + selecting each message. You can select a maximum of 100 messages at a time.

      +
    4. +
    +

    The subject and email address of the sender are automatically logged to the "Selected messages" section of the + task pane.

    +

    To learn more about the item multi-select feature, see Activate + your Outlook add-in on multiple messages.

    +

    Selected messages

    +
      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/90-other-item-apis/get-location-read.yaml b/samples/outlook/90-other-item-apis/get-location-read.yaml new file mode 100644 index 000000000..e476e5644 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-location-read.yaml @@ -0,0 +1,47 @@ +order: 11 +id: outlook-other-item-apis-get-location-read +name: Get the location (Read) +description: Gets the location of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Appointment location: ${Office.context.mailbox.item.location}`); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get the location of an item in Read mode.

      +

      Required modes: Appointment Attendee, Message Read (meeting request)

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-message-properties.yaml b/samples/outlook/90-other-item-apis/get-message-properties.yaml new file mode 100644 index 000000000..bae101012 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-message-properties.yaml @@ -0,0 +1,76 @@ +order: 23 +id: outlook-other-item-apis-get-message-properties +name: Get properties of selected messages (Message Compose, Message Read) +description: Gets the properties of multiple selected messages. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + Office.onReady(() => { + // Registers an event handler to identify when messages are selected. + Office.context.mailbox.addHandlerAsync(Office.EventType.SelectedItemsChanged, getMessageProperties, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log("Event handler added for the SelectedItemsChanged event."); + }); + }); + + function getMessageProperties() { + // Retrieves the selected messages' properties and logs them to the console. + Office.context.mailbox.getSelectedItemsAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + asyncResult.value.forEach((message) => { + console.log(`Item ID: ${message.itemId}`); + console.log(`Conversation ID: ${message.conversationId}`); + console.log(`Internet message ID: ${message.internetMessageId}`); + console.log(`Subject: ${message.subject}`); + console.log(`Item type: ${message.itemType}`); + console.log(`Item mode: ${message.itemMode}`); + console.log(`Has attachment: ${message.hasAttachment}`); + }); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get the properties of multiple selected messages.

      +

      Required mode: Message Compose, Message Read

      +
      +
      +

      Try it out

      +
        +
      1. Turn on the Reading Pane in Outlook. For guidance, see Use and configure the Reading Pane to preview messages.

      2. +
      3. Hold Ctrl (Windows) or Cmd (Mac) while selecting multiple messages from your mailbox. You can select a maximum of 100 messages at a time.

      4. +
      +

      The properties of the selected messages are automatically logged to the console.

      +

      To learn more about the item multi-select feature, see Activate your Outlook add-in on multiple messages.

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml b/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml new file mode 100644 index 000000000..cb2e43aa0 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml @@ -0,0 +1,47 @@ +order: 14 +id: outlook-other-item-apis-get-normalized-subject-read +name: Get the normalized subject (Read) +description: Gets the normalized subject of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Normalized subject: ${Office.context.mailbox.item.normalizedSubject}`); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get the normalized subject of an item in Read mode.

      +

      Required modes: Appointment Attendee, Message Read

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml b/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml new file mode 100644 index 000000000..3b63f5e14 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml @@ -0,0 +1,95 @@ +order: 10 +id: outlook-other-item-apis-get-set-end-appointment-organizer +name: Get and set the end date and time (Appointment Organizer) +description: Gets and sets the end date and time of an appointment in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-utc").addEventListener("click", getUtc); + document.getElementById("get-local").addEventListener("click", getLocal); + document.getElementById("set").addEventListener("click", set); + + function getUtc() { + Office.context.mailbox.item.end.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + console.log(`Appointment ends (UTC): ${time.toUTCString()}`); + }); + } + + function getLocal() { + Office.context.mailbox.item.end.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment ends (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + }); + } + + function set() { + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Get start date failed with message ${result.error.message}`); + return; + } + + const end = result.value; // Set end to current start date and time. + end.setDate(end.getDate() + 1); // Set end as 1 day later than start date. + Office.context.mailbox.item.end.setAsync(end, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Set end date failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set end date and time to ${end}`); + }); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get and set the end date and time of an appointment in Compose mode.

      +

      Required mode: Appointment Organizer

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml b/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml new file mode 100644 index 000000000..0602dd47c --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml @@ -0,0 +1,68 @@ +order: 12 +id: outlook-other-item-apis-get-set-location-appointment-organizer +name: Get and set the location (Appointment Organizer) +description: Gets and sets the location of an appointment in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + document.getElementById("set").addEventListener("click", set); + + function get() { + Office.context.mailbox.item.location.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Appointment location: ${result.value}`); + }); + } + + function set() { + const location = "my office"; + Office.context.mailbox.item.location.setAsync(location, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set location to ${location}`); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get and set the location of an appointment in Compose mode.

      +

      Required mode: Appointment Organizer

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml b/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml new file mode 100644 index 000000000..532504b1a --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml @@ -0,0 +1,72 @@ +order: 24 +id: outlook-other-item-apis-get-set-sensitivity-level +name: Get and set the sensitivity level (Appointment Organizer) +description: Gets and sets the sensitivity level of an appointment being composed. +host: OUTLOOK +api_set: + Mailbox: '1.14' +script: + content: |- + document.getElementById("getSensitivity").addEventListener("click", getSensitivity); + document.getElementById("setSensitivityPrivate").addEventListener("click", setSensitivityPrivate); + + function getSensitivity() { + Office.context.mailbox.item.sensitivity.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Sensitivity: " + asyncResult.value); + } else { + console.log("Failed to get sensitivity: " + JSON.stringify(asyncResult.error)); + } + }); + } + + function setSensitivityPrivate() { + Office.context.mailbox.item.sensitivity.setAsync( + Office.MailboxEnums.AppointmentSensitivityType.Private, + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set appointment sensitivity: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Successfully set appointment sensitivity."); + } + } + ); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get and set the sensitivity level of an appointment being composed. +

      + Required mode: Appointment Organizer +

      +

      +
      +
      + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml b/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml new file mode 100644 index 000000000..b956d94e0 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml @@ -0,0 +1,88 @@ +order: 8 +id: outlook-other-item-apis-get-set-start-appointment-organizer +name: Get and set the start date and time (Appointment Organizer) +description: Gets and sets the start date and time of an appointment in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-utc").addEventListener("click", getUtc); + document.getElementById("get-local").addEventListener("click", getLocal); + document.getElementById("set").addEventListener("click", set); + + function getUtc() { + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + console.log(`Appointment starts (UTC): ${time.toUTCString()}`); + }); + } + + function getLocal() { + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment starts (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + }); + } + + function set() { + const start = new Date(); // Represents current date and time. + start.setDate(start.getDate() + 2); // Add 2 days to current date. + Office.context.mailbox.item.start.setAsync(start, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set start date and time to ${start}`); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get and set the start date and time of an appointment in Compose mode.

      +

      Required mode: Appointment Organizer

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml b/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml new file mode 100644 index 000000000..7a78c2b10 --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml @@ -0,0 +1,68 @@ +order: 2 +id: outlook-other-item-apis-get-set-subject-compose +name: Get and set the subject (Compose) +description: Gets and sets the subject of an item in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + document.getElementById("set").addEventListener("click", set); + + function get() { + Office.context.mailbox.item.subject.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Subject: ${result.value}`); + }); + } + + function set() { + let subject = "Hello World!"; + Office.context.mailbox.item.subject.setAsync(subject, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set subject to ${subject}`); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to set and get the subject of an item in Compose mode.

      +

      Required mode: Compose

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-start-read.yaml b/samples/outlook/90-other-item-apis/get-start-read.yaml new file mode 100644 index 000000000..076caa4ba --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-start-read.yaml @@ -0,0 +1,58 @@ +order: 7 +id: outlook-other-item-apis-get-start-read +name: Get the start date and time (Read) +description: Gets the start date and time of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get-utc").addEventListener("click", getUtc); + document.getElementById("get-local").addEventListener("click", getLocal); + + function getUtc() { + const time = Office.context.mailbox.item.start; + console.log(`Appointment starts (UTC): ${time.toUTCString()}`); + } + + function getLocal() { + const time = Office.context.mailbox.item.start; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment starts (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get the start date and time of an item in Read mode.

      +

      Required modes: Appointment Attendee, Message Read (meeting request)

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/get-subject-read.yaml b/samples/outlook/90-other-item-apis/get-subject-read.yaml new file mode 100644 index 000000000..446e6fc0a --- /dev/null +++ b/samples/outlook/90-other-item-apis/get-subject-read.yaml @@ -0,0 +1,47 @@ +order: 1 +id: outlook-other-item-apis-get-subject-read +name: Get the subject (Read) +description: Gets the subject of an item in Read mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("get").addEventListener("click", get); + + function get() { + console.log(`Subject: ${Office.context.mailbox.item.subject}`); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get the subject of an item in Read mode.

      +

      Required mode: Read

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/item-id-compose.yaml b/samples/outlook/90-other-item-apis/item-id-compose.yaml new file mode 100644 index 000000000..f277cc15d --- /dev/null +++ b/samples/outlook/90-other-item-apis/item-id-compose.yaml @@ -0,0 +1,55 @@ +order: 29 +id: outlook-other-item-apis-item-id-compose +name: Get an item ID in compose mode +description: Gets an item ID in compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.8' +script: + content: |- + document.getElementById("run").addEventListener("click", run); + + function run() { + Office.context.mailbox.item.getItemIdAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`getItemIdAsync failed with message: ${result.error.message}`); + return; + } + + console.log(result.value); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get an item ID in compose mode.

      +

      Required mode: Compose

      +
      +
      +

      Try it out

      +

      Before you can get the item ID, you must first save the mail item.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/send-async.yaml b/samples/outlook/90-other-item-apis/send-async.yaml new file mode 100644 index 000000000..84360408c --- /dev/null +++ b/samples/outlook/90-other-item-apis/send-async.yaml @@ -0,0 +1,53 @@ +order: 30 +id: outlook-send-async +name: Send the current message or appointment (Compose) +description: Sends the current message or appointment. +host: OUTLOOK +api_set: + Mailbox: '1.15' +script: + content: |- + document.getElementById("send-async").addEventListener("click", sendAsync); + + function sendAsync() { + // This snippet sends the current message or appointment being composed. + Office.context.mailbox.item.sendAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to programmatically send the current message or appointment being composed.

      +

      Required mode: Compose

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/session-data-apis.yaml b/samples/outlook/90-other-item-apis/session-data-apis.yaml new file mode 100644 index 000000000..1a38250ca --- /dev/null +++ b/samples/outlook/90-other-item-apis/session-data-apis.yaml @@ -0,0 +1,113 @@ +order: 20 +id: outlook-other-item-apis-session-data-apis +name: Work with session data APIs (Compose) +description: Sets, gets, gets all, removes, and clears session data in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.11' +script: + content: |- + document.getElementById("setSessionData").addEventListener("click", setSessionData); + document.getElementById("getSessionData").addEventListener("click", getSessionData); + document.getElementById("getAllSessionData").addEventListener("click", getAllSessionData); + document.getElementById("removeSessionData").addEventListener("click", removeSessionData); + document.getElementById("clearSessionData").addEventListener("click", clearSessionData); + function setSessionData() { + Office.context.mailbox.item.sessionData.setAsync( + "Date", + "7/24/2020", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.setAsync succeeded"); + } else { + console.log("Failed to set sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); + } + function getSessionData() { + Office.context.mailbox.item.sessionData.getAsync( + "Date", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData value is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); + } + function getAllSessionData() { + Office.context.mailbox.item.sessionData.getAllAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get all sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); + } + function removeSessionData() { + Office.context.mailbox.item.sessionData.removeAsync( + "Date", + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.removeAsync succeeded"); + } else { + console.log("Failed to remove sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + } + ); + } + function clearSessionData() { + Office.context.mailbox.item.sessionData.clearAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.clearAsync succeeded"); + } else { + console.log("Failed to clear sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to set, get, get all, remove, and clear session data in compose mode. +

      + Required mode: Compose +

      +

      +
      +
      + + + + + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/90-other-item-apis/set-selected-data.yaml b/samples/outlook/90-other-item-apis/set-selected-data.yaml new file mode 100644 index 000000000..8336180c8 --- /dev/null +++ b/samples/outlook/90-other-item-apis/set-selected-data.yaml @@ -0,0 +1,54 @@ +order: 3 +id: outlook-item-body-set-selected-data +name: Replace selected text in item body or subject (Compose) +description: Replaces the selected text in the item body or subject in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.1' +script: + content: |- + document.getElementById("set-selected-data").addEventListener("click", setSelectedData); + + function setSelectedData() { + Office.context.mailbox.item.setSelectedDataAsync("Replaced", function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected text has been updated successfully."); + } else { + console.error(asyncResult.error); + } + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to replace the selected text in the item body or subject/title.

      +

      Required mode: Compose

      +
      +
      +

      Try it out

      +

      Select text in the item body or subject then push the Replace selected text 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml b/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml new file mode 100644 index 000000000..f11357527 --- /dev/null +++ b/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml @@ -0,0 +1,143 @@ +order: 19 +id: outlook-other-item-apis-work-with-client-signatures +name: Work with client signatures (Compose) +description: Checks if the client signature is enabled, disables the client signature, gets the compose type, and sets a signature in Compose mode. +host: OUTLOOK +api_set: + Mailbox: '1.10' +script: + content: |- + document.getElementById("isClientSignatureEnabled").addEventListener("click", isClientSignatureEnabled); + document.getElementById("disableClientSignature").addEventListener("click", disableClientSignature); + document.getElementById("getComposeType").addEventListener("click", getComposeType); + document.getElementById("setSignature").addEventListener("click", setSignature); + document.getElementById("setSignatureWithInlineImage").addEventListener("click", setSignatureWithInlineImage); + + function isClientSignatureEnabled() { + // Check if the client signature is currently enabled. + Office.context.mailbox.item.isClientSignatureEnabledAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("isClientSignatureEnabledAsync succeeded with result: " + asyncResult.value); + } else { + console.error(asyncResult.error); + } + }); + } + + function disableClientSignature() { + // Disable the client signature. + Office.context.mailbox.item.disableClientSignatureAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("disableClientSignatureAsync succeeded"); + } else { + console.error(asyncResult.error); + } + }); + } + + function getComposeType() { + // Get the compose type of the current message. + Office.context.mailbox.item.getComposeTypeAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log( + "getComposeTypeAsync succeeded with composeType: " + + asyncResult.value.composeType + + " and coercionType: " + + asyncResult.value.coercionType + ); + } else { + console.error(asyncResult.error); + } + }); + } + + function setSignature() { + // Set the signature for the current item. + const signature = (document.getElementById("signature") as HTMLInputElement).value; + console.log(`Setting signature to "${signature}".`); + Office.context.mailbox.item.body.setSignatureAsync(signature, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("setSignatureAsync succeeded"); + } else { + console.error(asyncResult.error); + } + }); + } + + function setSignatureWithInlineImage() { + // Set the signature for the current item with inline image. + const modIcon1Base64 = "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDRDMxMDg1MjBCNDZFMTExODE2MkM1RUI2M0M4MDYxRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTUxQjgyRjQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTUxQjgyRTQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQxMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNEMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+uC/WfAAAAehJREFUeNpilCzfwEAEkAbiECA2A2J1IOaHin8E4ptAfBaIVwLxU0IGMRKw0B6IW4DYhoE4cASIK6E0VsCEQ1wUiNcB8QESLGOAqj0MxBuhZhBloS4QnwHiQAbygR/UDF1CFupCXSjHQDmQg5qli8tCUBBsQUoQ1AD8UDNFsVk4n0o+w+bT+egWglKjNymmeGhLkqLcG2oHAwtUoIuQDj5OVgZPLUmwRe5aEmAxqYqNpFgKssOcCeplM0KqdST5GfpDDRm0JfkYrj3/SE7QguyQY4ImYYLgCtAS10kHGMw6dzNsv/qC7OwCClJXYlR++v6b4er3j5QmIFcmaNlIL6AOslCIjhYKMTHQGTBBqxh6gXcgC6/R0cKbIAv30dHCfaAKGJTxHxJSqS3Fz9DkowNmywpyMcgA8fF7b8D8VWcfM6w8+4gYC+VB+RCk8hSh0gaUD4/dewvlvUWRe/z+GzGWgex4BGtiOAHxXhoHpzMoSGHZAhSPW2lo2VZYWkHOh4nEtLrIAE+hZmNUwK+B2BOIv1PRsu9QM1/jatNcBtVZ0IREKXgENesyoVYbzNIdFFi2A5tl+NqlL6BB4QBNzsSCU1A9nlAzMAALAQMOQl0qB23qWwKxIlIrDBQ394H4OBCvISYqAAIMACVibHDqsO7zAAAAAElFTkSuQmCC"; + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + modIcon1Base64, + "myImage.png", + { isInline: true }, + function(result) { + if (result.status == Office.AsyncResultStatus.Succeeded) { + const signature = (document.getElementById("signature") as HTMLInputElement).value + ""; + console.log(`Setting signature to "${signature}".`); + Office.context.mailbox.item.body.setSignatureAsync( + signature, + { coercionType: "html" }, + function(asyncResult) { + console.log(`setSignatureAsync: ${asyncResult.status}`); + } + ); + } else { + console.error(`addFileAttachmentFromBase64Async: ${result.error}`); + } + } + ); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to check if the client signature is enabled, disable the client signature, get the compose + type, and set the signature. +

      + Required mode: Compose +

      +

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml b/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml new file mode 100644 index 000000000..275967e00 --- /dev/null +++ b/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml @@ -0,0 +1,69 @@ +order: 1 +id: outlook-get-set-isalldayevent +name: Get and set the isAllDayEvent property (Appointment Organizer) +description: Gets and sets the isAllDayEvent property of an appointment being composed. +host: OUTLOOK +api_set: + Mailbox: preview +script: + content: |- + document.getElementById("getIsAllDayEvent").addEventListener("click", getIsAllDayEvent); + document.getElementById("setIsAllDayEventTrue").addEventListener("click", setIsAllDayEventTrue); + + function getIsAllDayEvent() { + Office.context.mailbox.item.isAllDayEvent.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Is this an all-day event? " + asyncResult.value); + } else { + console.log("Failed to get if this is an all-day event. Error: " + JSON.stringify(asyncResult.error)); + } + }); + } + + function setIsAllDayEventTrue() { + Office.context.mailbox.item.isAllDayEvent.setAsync(true, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set all-day event: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Appointment set to all-day event."); + } + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to get and set the isAllDayEvent property of an appointment being composed. +

      + Required mode: Appointment Organizer +

      +

      +
      +
      + + +
      + 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/beta/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml b/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml new file mode 100644 index 000000000..3763ab1c4 --- /dev/null +++ b/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml @@ -0,0 +1,86 @@ +order: 3 +id: outlook-set-displayed-body-subject +name: Temporarily set the body or subject displayed in a message (Message Read) +description: Temporarily sets the content displayed in the body or subject of a message in read mode. +host: OUTLOOK +api_set: + Mailbox: preview +script: + content: |- + document.getElementById("set-body").addEventListener("click", setDisplayedBody); + document.getElementById("set-subject").addEventListener("click", setDisplayedSubject); + + function setDisplayedBody() { + // This snippet temporarily sets the content displayed in the body of a message in read mode. + // The set content will remain visible until the user switches to a different message in the Reading Pane or closes the window of the current message. + const bodyText = (document.getElementById("body-text-field") as HTMLInputElement).value; + Office.context.mailbox.item.display.body.setAsync(bodyText, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the body."); + }); + } + + function setDisplayedSubject() { + // This snippet temporarily sets the content displayed in the subject field of a message in read mode. + // The set content will remain visible until the user switches to a different message in the Reading Pane or closes the window of the current message. + const subjectText = (document.getElementById("subject-text-field") as HTMLInputElement).value; + Office.context.mailbox.item.display.subject.setAsync(subjectText, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the subject field."); + }); + } + language: typescript +template: + content: |- +
      +

      This sample shows how to temporarily set the content displayed in the body or subject of a + message in read mode.

      +

      Required mode: Message Read

      +
      +
      +

      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; + margin-top: 20px; + min-width: 80px; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/beta/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/outlook/default.yaml b/samples/outlook/default.yaml index 87bd34444..7ccf69f33 100644 --- a/samples/outlook/default.yaml +++ b/samples/outlook/default.yaml @@ -5,38 +5,36 @@ author: OfficeDev host: OUTLOOK api_set: null script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { - OfficeHelpers.UI.notify(`Hello ${Office.context.mailbox.userProfile.displayName}`); + const userProfile = Office.context.mailbox.userProfile; + console.log(`Hello ${userProfile.displayName}`); } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ - language: css -libraries: | - # Office.js - https://unpkg.com/@microsoft/office-js@1.1.1-private.1/dist/office.js - - # CSS Libraries - 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 + content: |- + section.samples { + margin-top: 20px; + } - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - jquery@3.1.1 + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/basics/basic-api-call-js.yaml b/samples/powerpoint/basics/basic-api-call-js.yaml new file mode 100644 index 000000000..5f421f9bb --- /dev/null +++ b/samples/powerpoint/basics/basic-api-call-js.yaml @@ -0,0 +1,67 @@ +order: 2 +id: powerpoint-basics-basic-api-call-js +name: Basic API call (JavaScript) +description: Performs a basic PowerPoint API call using JavaScript. +host: POWERPOINT +api_set: + PowerPointApi: '1.4' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); + + function run() { + // This function gets the collection of shapes on the first slide, + // and adds a text box to the collection, while specifying its text, + // location, and size. Then it names the text box. + return PowerPoint.run(function(context) { + const shapes = context.presentation.slides.getItemAt(0).shapes; + const textbox = shapes.addTextBox("Hello!", { + left: 100, + top: 300, + height: 300, + width: 450 + }); + textbox.name = "Textbox"; + + return 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 executes a code snippet that adds a text box to the first slide in the presentation. +
      + + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/basics/basic-api-call-ts.yaml b/samples/powerpoint/basics/basic-api-call-ts.yaml new file mode 100644 index 000000000..0761647c6 --- /dev/null +++ b/samples/powerpoint/basics/basic-api-call-ts.yaml @@ -0,0 +1,67 @@ +order: 1 +id: powerpoint-basics-basic-api-call-ts +name: Basic API call (TypeScript) +description: Performs a basic PowerPoint API call using TypeScript. +host: POWERPOINT +api_set: + PowerPointApi: '1.4' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); + + const run: Function = async () => { + // This function gets the collection of shapes on the first slide, + // and adds a text box to the collection, while specifying its text, + // location, and size. Then it names the text box. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const shapeOptions: PowerPoint.ShapeAddOptions = { + left: 100, + top: 300, + height: 300, + width: 450 + }; + const textbox: PowerPoint.Shape = shapes.addTextBox("Hello!", shapeOptions); + + await context.sync(); + }); + } + + /** Default helper for invoking an action and handling errors. */ + const tryCatch: (callback: Function) => void = async (callback: Function) => { + 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 executes a code snippet that adds a text box to the first slide in the presentation. +
      + + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/basics/basic-common-api-call.yaml b/samples/powerpoint/basics/basic-common-api-call.yaml index b5dc7098d..0f9d08860 100644 --- a/samples/powerpoint/basics/basic-common-api-call.yaml +++ b/samples/powerpoint/basics/basic-common-api-call.yaml @@ -1,19 +1,19 @@ -order: 1000 +order: 3 id: powerpoint-basics-basic-common-api-call name: Basic API call (Office 2013) description: Executes a basic PowerPoint API call using the "common API" syntax (compatible with Office 2013). author: OfficeDev host: POWERPOINT api_set: - Selection: 1.1 + Selection: '1.1' script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); + console.error(asyncResult.error.message); } else { console.log(`The selected data is "${asyncResult.value}".`); } @@ -21,27 +21,27 @@ script: } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/basics/get-slide-metadata.yaml b/samples/powerpoint/basics/get-slide-metadata.yaml deleted file mode 100644 index da08aa538..000000000 --- a/samples/powerpoint/basics/get-slide-metadata.yaml +++ /dev/null @@ -1,84 +0,0 @@ -id: powerpoint-basics-get-slide-metadata -name: Get slide metadata -description: 'Gets the title, index, and ID of the selected slide(s).' -author: OfficeDev -host: POWERPOINT -api_set: {} -script: - content: |- - $("#get-slide-metadata").click(getSlideMetadata); - - function getSlideMetadata() { - Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideRange, - function (asyncResult) { - if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); - } else { - console.log(JSON.stringify(asyncResult.value, null, 4)); - } - } - ); - } - language: typescript -template: - content: |+ -

      Demonstrates how to get slide metadata.

      -

      Select one or more slides and click Get slide metadata to get the ID, title, and index of the slide(s).

      - - - - language: html -style: - content: |- - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #b7472a; - border: #b7472a; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #8e3720; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - - language: css -libraries: | - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 \ No newline at end of file diff --git a/samples/powerpoint/default.yaml b/samples/powerpoint/default.yaml index 3fa9b929b..556474193 100644 --- a/samples/powerpoint/default.yaml +++ b/samples/powerpoint/default.yaml @@ -5,13 +5,13 @@ author: OfficeDev host: POWERPOINT api_set: {} script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); + console.error(asyncResult.error.message); } else { console.log(`The selected data is "${asyncResult.value}".`); } @@ -19,27 +19,27 @@ script: } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/document/create-presentation.yaml b/samples/powerpoint/document/create-presentation.yaml new file mode 100644 index 000000000..fedd25925 --- /dev/null +++ b/samples/powerpoint/document/create-presentation.yaml @@ -0,0 +1,79 @@ +id: powerpoint-create-presentation +name: Create presentation +description: Creates a new, empty presentation and creates a new presentation by copying an existing one. +author: OfficeDev +host: POWERPOINT +api_set: + PowerPointApi: '1.1' +script: + content: |- + document.getElementById("create-new-blank-presentation").addEventListener("click", () => tryCatch(createBlankPresentation)); + document.getElementById("file").addEventListener("change", () => tryCatch(createPresentationFromExisting)); + + function createBlankPresentation() { + PowerPoint.createPresentation(); + } + + function createPresentationFromExisting() { + const myFile = document.getElementById("file") as HTMLInputElement; + const reader = new FileReader(); + + reader.onload = (event) => { + // Remove the metadata before the Base64-encoded string. + const startIndex = reader.result.toString().indexOf("base64,"); + const copyBase64 = reader.result.toString().substr(startIndex + 7); + + PowerPoint.createPresentation(copyBase64); + }; + + // 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 presentation and how to create a new presentation by copying an existing one.

      +
      +
      +

      Try it out

      +

      Create empty presentation

      +

      +

      Copy existing presentation

      +

      Select a PowerPoint presentation to copy and open in a new instance of PowerPoint.

      +
      + +
      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml b/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml new file mode 100644 index 000000000..d5125be3a --- /dev/null +++ b/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml @@ -0,0 +1,67 @@ +id: powerpoint-hyperlinks-manage-hyperlinks +name: Get hyperlinks +description: Gets the hyperlinks found in a slide. +host: POWERPOINT +api_set: + PowerPointApi: '1.6' +script: + content: |- + document.getElementById("get-hyperlinks").addEventListener("click", () => tryCatch(getHyperlinks)); + + async function getHyperlinks() { + // Gets the hyperlinks found in the first selected slide. + await PowerPoint.run(async (context) => { + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + const hyperlinks: PowerPoint.HyperlinkCollection = slide.hyperlinks.load("address,screenTip"); + const hyperlinksCount = hyperlinks.getCount(); + await context.sync(); + + console.log(`${hyperlinksCount.value} hyperlinks found in first selected slide:`); + for (let link of hyperlinks.items) { + console.log(`Address: "${link.address}" (Screen tip: "${link.screenTip}")`); + } + }); + } + + /** 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: |- +
      +

      Demonstrates how to get the hyperlinks located in a slide.

      +
      +
      +

      Try it out

      +

      First, add at least one hyperlink to a slide then select at least one slide.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/basics/insert-image.yaml b/samples/powerpoint/images/insert-image.yaml similarity index 88% rename from samples/powerpoint/basics/insert-image.yaml rename to samples/powerpoint/images/insert-image.yaml index af77e72c7..a1debdc9e 100644 --- a/samples/powerpoint/basics/insert-image.yaml +++ b/samples/powerpoint/images/insert-image.yaml @@ -1,3 +1,4 @@ +order: 1 id: powerpoint-basics-insert-image name: Insert Image description: Inserts an image to the current slide. @@ -5,8 +6,8 @@ author: OfficeDev host: POWERPOINT api_set: {} script: - content: | - $('#insert').click(run); + content: |- + document.getElementById('insert').addEventListener("click", run); function run() { Office.context.document.setSelectedDataAsync(getImageAsBase64String(), { @@ -31,59 +32,29 @@ script: language: typescript template: content: |- -

      Insert an image into the current slide.

      - +
      +

      Insert an image into the current slide.

      +
      language: html style: content: |- - body { - margin: 0; - padding: 10px; + section.samples { + margin-top: 20px; } - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #b7472a; - border: #b7472a; + section.samples .ms-Button, section.setup .ms-Button { + display: block; + margin-bottom: 5px; + margin-left: 20px; + min-width: 80px; } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #8e3720; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } language: css -libraries: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/images/insert-svg.yaml b/samples/powerpoint/images/insert-svg.yaml new file mode 100644 index 000000000..563929e69 --- /dev/null +++ b/samples/powerpoint/images/insert-svg.yaml @@ -0,0 +1,64 @@ +order: 2 +id: powerpoint-basics-insert-svg +name: Insert SVG +description: Inserts an SVG image using an XML string. +author: OfficeDev +host: POWERPOINT +api_set: {} +script: + content: |- + document.getElementById('insert').addEventListener("click", newImage); + + function newImage() { + Office.context.document.setSelectedDataAsync(getImageAsBase64String(), { + coercionType: Office.CoercionType.XmlSvg, + imageLeft: 50, + imageTop: 50, + imageWidth: 400 + }, + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(asyncResult.error.message); + } + }); + } + + function getImageAsBase64String() { + // A production add-in code could get an image from an + // online source and pass it to a library function that + // converts to base 64. + const svg = " SVG Logo SVG "; + return svg; + } + language: typescript +template: + content: |- +
      +

      This sample shows how to insert an SVG image using an XML string as the source.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/scenarios/searches-wikipedia-api.yaml b/samples/powerpoint/scenarios/searches-wikipedia-api.yaml new file mode 100644 index 000000000..41e403296 --- /dev/null +++ b/samples/powerpoint/scenarios/searches-wikipedia-api.yaml @@ -0,0 +1,251 @@ +order: 1 +id: powerpoint-scenarios-searches-wikipedia-api +name: Search Wikipedia +description: Searches Wikipedia based on the selected text in the presentation. +author: cakriwut +host: POWERPOINT +api_set: {} +script: + content: |- + /* + * Copyright (c) Riwut Libinuko. All rights reserved. Licensed under the MIT license. + */ + + declare let moment: any; + + document.getElementById("search").addEventListener("click", run); + + async function run() { + Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, {}, getSelectedText); + } + + /* Extract selected text and call SearchWiki. */ + function getSelectedText(result) { + const resultElement = document.getElementById("result"); + if (resultElement) { + resultElement.innerHTML = ""; + const listElement = document.createElement("ul"); + listElement.className = "ms-List"; + listElement.id = "ms-List"; // Ensure the list has an ID for later reference + resultElement.appendChild(listElement); + } + + if (result.status === Office.AsyncResultStatus.Succeeded) { + searchWiki(result.value); + } else { + console.error(result.error.message); + } + } + + /* Searching Wiki. */ + function searchWiki(pattern) { + const url = build_wiki_search_url(http://github.com/pattern); + + fetch(url) + .then((response) => response.json()) + .then((data) => { + data.query.search.forEach((val) => { + const date = moment(val.timestamp).format("YYYY-MM-DD hh:mm A"); + const listItem = build_list_item(val.title, val.pageid, val.snippet, date); + const listElement = document.getElementById("ms-List"); + if (listElement) { + const tempDiv = document.createElement("div"); + tempDiv.innerHTML = listItem; + const listItemNode = tempDiv.firstElementChild; + if (listItemNode) { + listElement.appendChild(listItemNode); + } + } + }); + + return data.query; + }) + .then((data) => { + const listItems = document.querySelectorAll(".ms-ListItem"); + listItems.forEach((item) => { + const link = item.querySelector(".listItem-link a"); + if (!link || link.innerHTML.length === 0) { + const pageId = item instanceof HTMLElement ? item.dataset.pageid : undefined; + if (pageId) { + getWikiLink(pageId, item); + } + } + }); + }) + .catch((error) => console.error("Error fetching Wikipedia data:", error)); + } + + // Search for Wiki Page link based on the given pageId. + // Update itemHTML from the returned result. + function getWikiLink(pageid, itemHTML) { + const pageinfo = build_wiki_pageinfo(pageid); + fetch(pageinfo) + .then((response) => response.json()) + .then((data) => { + const itemUrl = data.query.pages[pageid].fullurl; + const images = data.query.pages[pageid].images; + const titleElement = itemHTML.querySelector(".listItem-link"); + const title = titleElement ? titleElement.innerHTML : ""; + + if (titleElement && itemUrl) { + titleElement.innerHTML = `${title}`; + } + + if (images && images.length > 0) { + const imageElement = itemHTML.querySelector(".ms-ListItem-image"); + if (imageElement) { + imageElement.setAttribute("data-image", images[0].title); + } + } + }) + .then(() => { + getWikiImages(pageid, itemHTML); + }) + .catch((error) => console.error("Error fetching Wiki link:", error)); + } + + // Search for Wiki image based on the given pageId, first image. + // Update itemHTML from the returned result. + function getWikiImages(pageid, itemHTML) { + const pageInfo = build_wiki_image_search(pageid); + fetch(pageInfo) + .then((response) => response.json()) + .then(async (data) => { + const pageData = data.query.pages[pageid]; + if (pageData && pageData.original && pageData.original.source) { + const originalImage = pageData.original.source; + const imageElement = itemHTML.querySelector(".ms-ListItem-image"); + + if (originalImage && imageElement) { + const imgElement = document.createElement("img"); + imgElement.width = 70; // Set the width to 70px. + imgElement.src = originalImage; + imageElement.appendChild(imgElement); + return true; + } + } else { + const imageElement = itemHTML.querySelector(".ms-ListItem-image"); + const img = imageElement ? imageElement.dataset.image : undefined; + if (img) { + const pageInfoResult = await fetch(build_wiki_file_search(img)); + return pageInfoResult.json(); + } + } + }) + .then((data) => { + if (data && data.query) { + const key = Object.keys(data.query.pages)[0]; + const page = data.query.pages[key]; + if (page && page.thumbnail && page.thumbnail.source) { + const thumbnail = page.thumbnail.source; + const imageElement = itemHTML.querySelector(".ms-ListItem-image"); + + if (thumbnail && imageElement) { + const imgElement = document.createElement("img"); + imgElement.width = 70; // Set the width to 70px. + imgElement.src = thumbnail; + imageElement.appendChild(imgElement); + } + } + } + }) + .catch((error) => console.error("Error fetching Wiki images:", error)); + } + + /* Wikipedia API query */ + function wiki_base(pattern) { + const base_url = "https://en.wikipedia.org/w/api.php"; + const base_query = "?origin=*&action=query&format=json&prop="; + return base_url + base_query + pattern; + } + + /* Wikipedia Search Query pattern */ + function build_wiki_search_url(http://github.com/pattern) { + const qry = "pageimages&list=search&srsearch="; + return wiki_base(qry + pattern); + } + + /* Wikipedia Image Query pattern */ + function build_wiki_image_search(pattern) { + const qry = "pageimages&piprop=original&pilicense=any&pageids="; + return wiki_base(qry + pattern); + } + + /* Wikipedia File Query pattern */ + function build_wiki_file_search(pattern) { + const qry = "pageimages|pageterms&pilicense=any&titles="; + return wiki_base(qry + pattern); + } + + /* Wikipedia Page Info Query pattern */ + function build_wiki_pageinfo(pattern) { + const qry = "info|images&inprop=url&pageids="; + return wiki_base(qry + pattern); + } + + /* Render */ + function build_list_item(title, pageid, summary, ts) { + return ` +
    • +
      + ${title} + ${summary} +
      +
      +
      + +
      +
      + +
      +
      +
    • `; + } + language: typescript +template: + content: |- +
      +

      Search Wikipedia

      +
      +
      +

      This sample shows how to query external API (Wikipedia) with the text currently selected in the presentation.

      +
      +
      +

      Try it out

      +

      Select any text in the presentation and press Search to see related Wikipedia entries.

      +

      The search result will be provided by Wikipedia API.

      +
        +
      1. Click Search button:

        + +
      2. +
      +
      +
      +

      Result

      +
      +
      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css + + https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js diff --git a/samples/powerpoint/shapes/add-modify-tables.yaml b/samples/powerpoint/shapes/add-modify-tables.yaml new file mode 100644 index 000000000..c9da7247f --- /dev/null +++ b/samples/powerpoint/shapes/add-modify-tables.yaml @@ -0,0 +1,417 @@ +order: 4 +id: powerpoint-shapes-add-modify-tables +name: Add and modify tables +description: Shows how to add and modify tables in a presentation. +host: POWERPOINT +api_set: + PowerPointApi: '1.8' +script: + content: | + document.getElementById("add-basic-table").addEventListener("click", () => tryCatch(addBasicTable)); + document.getElementById("table-width-height").addEventListener("click", () => tryCatch(tableWidthHeight)); + document + .getElementById("table-column-widths-row-heights") + .addEventListener("click", () => tryCatch(tableColumnWidthsRowHeights)); + document.getElementById("table-values").addEventListener("click", () => tryCatch(tableValues)); + document.getElementById("table-merge-areas").addEventListener("click", () => tryCatch(tableMergeAreas)); + document.getElementById("table-cell-fill-font").addEventListener("click", () => tryCatch(tableCellFillFont)); + document.getElementById("table-borders").addEventListener("click", () => tryCatch(tableBorders)); + document.getElementById("table-indent-margin").addEventListener("click", () => tryCatch(tableIndentMargin)); + document.getElementById("table-cell-alignment").addEventListener("click", () => tryCatch(tableCellAlignment)); + document.getElementById("table-text-runs").addEventListener("click", () => tryCatch(tableTextRuns)); + document.getElementById("table-from-shape").addEventListener("click", () => tryCatch(getTableFromShape)); + document.getElementById("update-table-values").addEventListener("click", () => tryCatch(updateTableValues)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function addBasicTable() { + // Adds a basic table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a simple table, specifying the row and column count. + shapes.addTable(3, 4); + await context.sync(); + }); + } + + async function tableWidthHeight() { + // Specifies the width and height of a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the width and height. + shapes.addTable(3, 4, { + width: 600, + height: 400 + }); + await context.sync(); + }); + } + + async function tableColumnWidthsRowHeights() { + // Specifies the column widths and row heights of a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); + } + + async function tableValues() { + // Specifies a table's values. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying cell values. + const shape = shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ] + }); + await context.sync(); + }); + } + + async function tableMergeAreas() { + // Specifies the merge areas of a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); + } + + async function tableCellFillFont() { + // Specifies the font formatting and fill colors of the cells in a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); + } + + async function tableBorders() { + // Specifies a table's borders. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); + } + + async function tableIndentMargin() { + // Specifying the indents for a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the indent level for cells. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }], + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }], + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }] + ] + }); + await context.sync(); + }); + } + + async function tableCellAlignment() { + // Specifies the horizontal and vertical alignments of the cells in a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying horizontal and vertical alignment. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + horizontalAlignment: PowerPoint.ParagraphHorizontalAlignment.justify, + verticalAlignment: PowerPoint.TextVerticalAlignment.middle + } + }); + await context.sync(); + }); + } + + async function tableTextRuns() { + // Specifies the text runs of the cells in a table. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying text runs. + shapes.addTable(3, 4, { + specificCellProperties: [ + [ + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } } + ], + [ + { text: "Bold text", font: { bold: true } }, + { + textRuns: [ + { text: "Text runs with " }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.double } }, + { text: " and plain text" } + ] + }, + { text: "Italicized text", font: { italic: true } }, + { text: "Plain text" } + ], + [ + { text: "Bold text", font: { bold: true } }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.dotted } }, + { + font: { bold: true }, + textRuns: [ + { text: "Text runs with " }, + { text: "italicized text", font: { italic: true } }, + { text: " and (inherited) bold text" } + ] + }, + { text: "Italicized text", font: { italic: true } } + ] + ] + }); + await context.sync(); + }); + } + + async function getTableFromShape() { + // Gets the table from a shape. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + + if (shapeCount.value > 0) { + const shape = shapes.getItemAt(0); + shape.load("type"); + await context.sync(); + + // The shape type can indicate whether the shape is a table. + const isTable = shape.type === PowerPoint.ShapeType.table; + + if (isTable) { + // Get the Table object for the Shape which is a table. + const table = shape.getTable(); + table.load(); + await context.sync(); + + // Get the Table row and column count. + console.log("Table RowCount: " + table.rowCount + " and columnCount: " + table.columnCount); + } else console.log("Selected shape isn't table."); + } else console.log("No shape selected."); + }); + } + + async function updateTableValues() { + // Updates a table's values. + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table (which is a type of Shape). + const shape = shapes.addTable(4, 3); + let table = shape.getTable(); + table.load(); + await context.sync(); + + // Update values in the table. + for (let rowIndex = 0; rowIndex < table.rowCount; rowIndex++) { + for (let columnIndex = 0; columnIndex < table.columnCount; columnIndex++) { + const cell = table.getCellOrNullObject(rowIndex, columnIndex); + cell.text = generateRandomString(); + } + } + + await context.sync(); + }); + } + + function generateRandomString(length: number = 5): string { + // Generates a random string. + const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + + while (result.length < length) { + const randomIndex = Math.floor(Math.random() * characters.length); + result += characters.charAt(randomIndex); + } + + return result; + } + + async function setup() { + await PowerPoint.run(async (context) => { + // Adds a new slide with some content. + const slideCountResult = context.presentation.slides.getCount(); + context.presentation.slides.add(); + await context.sync(); + + const newSlide = context.presentation.slides.getItemAt(slideCountResult.value); + newSlide.load("id"); + newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon); + await context.sync(); + + console.log(`Added slide - ID: ${newSlide.id}`); + + // Switch to the new slide. + context.presentation.setSelectedSlides([newSlide.id]); + 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 and modify tables.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + 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 diff --git a/samples/powerpoint/shapes/binding-to-shapes.yaml b/samples/powerpoint/shapes/binding-to-shapes.yaml new file mode 100644 index 000000000..7eec3ed7b --- /dev/null +++ b/samples/powerpoint/shapes/binding-to-shapes.yaml @@ -0,0 +1,370 @@ +order: 5 +id: powerpoint-shapes-binding-to-shapes +name: Binding to shapes +description: Shows how to create binding references for images and work with z-order. +host: POWERPOINT +api_set: + PowerPointApi: '1.8' +script: + content: | + document + .getElementById("insert-image-and-create-binding") + .addEventListener("click", () => tryCatch(insertImageWithBinding)); + document.getElementById("replace-binding1").addEventListener("click", () => + tryCatch(() => { + replaceBinding(1); + }) + ); + document.getElementById("replace-binding2").addEventListener("click", () => + tryCatch(() => { + replaceBinding(2); + }) + ); + document.getElementById("replace-binding3").addEventListener("click", () => + tryCatch(() => { + replaceBinding(3); + }) + ); + document.getElementById("load-bindings").addEventListener("click", () => tryCatch(loadBindings)); + document.getElementById("bring-to-front").addEventListener("click", () => tryCatch(bringToFront)); + document.getElementById("bring-forward").addEventListener("click", () => tryCatch(bringForward)); + document.getElementById("send-backward").addEventListener("click", () => tryCatch(sendBackward)); + document.getElementById("send-to-back").addEventListener("click", () => tryCatch(sendToBack)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + const flowerImage = getImageAsBase64String(); + + const greenery1 = returnGreenery1AsBase64(); + + const greenery2 = returnGreenery2AsBase64(); + + const greenery3 = returnGreenery3AsBase64(); + + async function insertImageWithBinding() { + // Inserts an image with binding. + await PowerPoint.run(async (context) => { + const bindingId = (document.getElementById("temp-binding-id") as HTMLInputElement).value; + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const myShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle, { + top: 100, + left: 30, + width: 200, + height: 200 + }); + + myShape.fill.setImage(flowerImage); + context.presentation.bindings.add(myShape, PowerPoint.BindingType.shape, bindingId); + await context.sync(); + + const bindingsDropdown = document.getElementById("bindings-dropdown") as HTMLSelectElement; + + const option = new Option(`Binding ${bindingId}`, bindingId); + + // When a binding ID already exists, the binding is updated to refer to the new shape + // so select the existing item rather than add a new one. + const foundIndex = findDropdownItem(bindingsDropdown, option.text); + if (foundIndex < 0) { + bindingsDropdown.add(option); + bindingsDropdown.selectedIndex = bindingsDropdown.options.length - 1; + } else { + bindingsDropdown.selectedIndex = foundIndex; + } + }); + } + + async function replaceBinding(greenery) { + // Update image in binding with selected replacement image. + await PowerPoint.run(async (context) => { + if (greenery === 1) + context.presentation.bindings + .getItem((document.getElementById("bindings-dropdown") as HTMLSelectElement).value) + .getShape() + .fill.setImage(greenery1); + else if (greenery === 2) + context.presentation.bindings + .getItem((document.getElementById("bindings-dropdown") as HTMLSelectElement).value) + .getShape() + .fill.setImage(greenery2); + else + context.presentation.bindings + .getItem((document.getElementById("bindings-dropdown") as HTMLSelectElement).value) + .getShape() + .fill.setImage(greenery3); + + await context.sync(); + }); + } + + async function getShapeForBindingId(bindingId: string): Promise { + // Gets shape associated with binding ID. + return PowerPoint.run(async (context) => { + const binding = context.presentation.bindings.getItem(bindingId); + const shape = binding.getShape(); + return shape; + }); + } + + async function loadBindings() { + // Loads bindings. + await PowerPoint.run(async (context) => { + const bindings = context.presentation.bindings; + bindings.load("items"); + await context.sync(); + + const bindingCount = bindings.items.length; + if (bindingCount === 0) { + console.log(`There are no bindings.`); + } else if (bindingCount === 1) { + console.log("There's 1 binding."); + } else { + console.log(`There are ${bindingCount} bindings.`); + } + + bindings.items.forEach((binding) => { + getShapeForBindingId(binding.id).then((shape) => { + if (shape) { + console.log(`Binding ID: ${binding.id} refers to shape ID ${shape.id}`); + } else { + console.log(`Binding ID: ${binding.id} doesn't refers to shape.`); + } + }); + }); + + populateBindingsDropdown(bindings.items); + }); + } + + function findDropdownItem(dropdown: HTMLSelectElement, text: string): number { + // Finds dropdown items. + for (let index = 0; index < dropdown.options.length; ++index) { + if (dropdown.options[index].text === text) { + return index; + } + } + + return -1; + } + + async function populateBindingsDropdown(bindings: PowerPoint.Binding[]) { + // Populates bindings dropdown list. + const bindingsDropdown = document.getElementById("bindings-dropdown") as HTMLSelectElement; + bindingsDropdown.options.length = 0; + bindings.forEach((binding) => { + const option = new Option(`Binding ${binding.id}`, binding.id); + bindingsDropdown.add(option); + }); + + bindingsDropdown.selectedIndex = 0; + } + + function bringToFront() { + // Brings the shape to the front. + changeZOrder(PowerPoint.ShapeZOrder.bringToFront); + } + + function bringForward() { + // Brings the shape forward. + changeZOrder(PowerPoint.ShapeZOrder.bringForward); + } + + function sendBackward() { + // Sends the shape backward. + changeZOrder(PowerPoint.ShapeZOrder.sendBackward); + } + + function sendToBack() { + // Sends the shape to the back. + changeZOrder(PowerPoint.ShapeZOrder.sendToBack); + } + + async function changeZOrder(operation: PowerPoint.ShapeZOrder) { + // Changes the z-order position of the selected shapes. + return PowerPoint.run(async (context) => { + const selectedShapes = context.presentation.getSelectedShapes(); + selectedShapes.load(); + await context.sync(); + + if (selectedShapes.items.length === 0) { + console.log("No shapes are selected."); + } else { + let direction = 1; // Start with bottom-most (lowest number). + + // Start with top-most when sending to back or bringing forward. + + switch (operation) { + case PowerPoint.ShapeZOrder.bringForward: + + case PowerPoint.ShapeZOrder.sendToBack: + direction = -1; // Reverse direction. + + break; + } + + // Change the z-order position for each of the selected shapes, + + // starting with the bottom-most when bringing to front or sending backward, + + // or top-most when sending to back or bringing forward, + + // so the selected shapes retain their relative z-order positions after they're changed. + + selectedShapes.items + .sort((a, b) => (a.zOrderPosition - b.zOrderPosition) * direction) + .forEach((shape) => { + try { + const originalZOrderPosition = shape.zOrderPosition; + shape.setZOrder(operation); + + console.log(`Changed z-order of shape ${shape.id}.`); + } catch (err) { + console.log(`Unable to change z-order of shape ${shape.id}. ${err.message}`); + } + }); + + await context.sync(); + } + }); + } + + function logSelectedShapesZOrder(selectedShapes: PowerPoint.ShapeScopedCollection) { + // Logs the z-order position of the selected shapes. + console.log(`Selected shapes:`); + + selectedShapes.items.forEach((shape, index) => { + console.log(` [${index}] shape ID ${shape.id}, z-order position: ${shape.zOrderPosition}`); + }); + } + + function getImageAsBase64String() { + // A production add-in code could get an image from an + + // online source and pass it to a library function that + + // converts to Base64. + + return "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"; + } + + function returnGreenery1AsBase64() { + return "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"; + } + + function returnGreenery2AsBase64() { + return "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCACmAPgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD6S1C4jjBeIBdxO4glQRnIyfTkH15z2rhdZaeeX94GMLEYBAXeQc8H0B6nsc+oraW4e62s2QjfN+9O7bjts6cZ9TxWVf2jzb40SQscoGYknnPAJPtjjjIHFfhOMqL5nnybkjlzo8JRI58STEnzFcZBY8+2ck5xwckdQK5fxL5ul3TKJXWRGwHZsq56BZD0344Vu2AG7EdzJZG30whpnmZF2YZPmYDBJPGAcjtnGTXEeJmgubZ4DEgErrE4OAG+Yg5Ixxn37V83zXqWezOaSsjide8Vp5chuLO6hJGGV4HV1OPuk445B9a8a8Z+Ibe5uWKFosjkHcOfcdz15969qurXWNVikuzqt+GlJaNFunGEJ+VVG4cAYAGM8VwXitdY02PdHq1+qPzuaYtwT0G7vz296+pyqWGpVbR323/4AoOCkcf4F0+81rwv4w0o20zxvZjUIGMRCCaFsjGR1K+ldX8PvGj6paRR21rLNsQSGONydowRuYsdqj/abA5rk9K1q/8ACfiWy1xrm4vLiGTLpLKWEkRHzx8k8Fc5/Cu41PSLbQPGcEWnxRjw1q8S6jpsUfEO0gbwyjALBsck554xXr5pGFTm543UveXqklJfdZ+iZ2VVGpS519n9TrtL086lebHKurjdtZMwjrgAYHm9Opwvs1dGNHijFlMoXPR5COoAzyemOvAwMnpUemWZuLSF2dFIUnYB8xOASP1HJ6GrctlcztjzEjhQqzRq/BYHPJ9CR296/NK1VzlvZL+vmecrnE+PPDsMc3mQS4kgUFJExnPTAP5e2M9q81utQitTvMZiSZxhVztVx1UH6YI56Eele2eNr2I6CXEaW2yPDNjJZsdefqPzNeFeK9Im0vSIrhn81bnmSJj8r++OxzkAjkYFfX5HU9tBUqr62R0Qs3ZlG7KzW9xMWBQHCheOe/Pb/wCtXA6qF884GOcYBziuhvNQe3s1jgk/0Jj8rv8AeU45V/f0PQ/ywbiFH+YHp1Pev0fBwlTvf5HbTXK9T0qO6834L+H5WTzUtdT2sDycbyOPzru7NbCLQEnuHPIC8sSAxHQgd/oO5715loZbVPg1eWsLxRyW995oeZ9qrgqxJPau2+HniiOwkjXSbj7bq5G46vcpiO1z1FtG2ct/00YZ5+UCvh80wrftJXtyzk36Oz9Fv/kmTjoc3JO9lYvTeDU0yQtd25m1t08yDTiBssflBWSfg5k5JWHtwW7CtLwx8N4YozvgEkpJL7sMXbvyeuc5z3yK9E8NaDDb2QBZTI5LvO/3mYkE7iepJ55JOeK2bXSCY9kcOZ9xA3HG7jpg/iRz379vja+b1JRcIuyR5TnKVktjz298GLaXNuyQxx4OdzDKjnAUg9Rkjg9simaj4Ig02ACCGOUHG3auxj64ZcEDjpgiu1a0kkvVaWMmQNgjGQoGQM57k7uPQDntST7Lqdh5gVY0wSzcA9uPYcc1yLG1o8q5tOo03Y8q1azbT8gTz274KMJh5gK9stGNwOOuVxXIaL4dn8TeO9C063azdpL5GYLNwVVtzYBAPQHjFeleML1YHmZ1+Z+gRfuj+ft071zvwXiN18XbC5ZmaGxt7m7cEZ2BYyAee+TX1uBryWHqVbJNRevyO3DLmqRT7kkkCav8RPFWoW5mmR9QkUbrhY1+X5ONq7iPlPRgfpXUrpvlWZljWKNo13YhgXA5HUnJPbqTXOfDTzpdOkmW2Mr3DySqWV1DbiWDdD/e/Wu7McsenOzBY5HXcc/NsbHPLc8fSvEzCtONZ009I2X3aHHWm5TlIgtbh0jMTRSzyNITypzknPX8ffjGKz9eRUt3kjVWEqbmWQ9Dj6dsYyfUe+dmBIXdnzukikZsSHJwRwScdNuP0rF8Vs0sZG5Elwyn5sNn8B0wo65ry6dnWt5i3PMbXQ4PGfjrQtFnmlC3VwkRuo1zIqL85Djo6ADAJOV9+lb3hedde8Ra1rG1U+1XkkqEIGO0OQoG4kdFHT34ql4ImNhrXiHXmKJ/YWkXM6t0fzpR5UfHflux7Ctb4a2ot9GtlmJEm3aSRzn6nHf3r6/MKkoYdq+yS++7f4cp11Hy0IruehWytBanDEAkbip2hue5GPfis+5bbeSbxvGAzM75boOh61oPskhyWIGcEnGfz59fWs6SaNmLH94WDHPUnIOK+DhdttnC2c7qluF1TR48FnN3HjeMgDdnp36UVX1PUTB4ghkiz5tlbyXO9hk5CYA9M5YUV7P1KtioRcHsuvmz0MPVVKGvU+sNGDupBP7xDnC5b5l6dzxjPtUl7ctGVQbllwpyTuLdwAffaB9aj+H2pxXSWkd4Bbl2AYu3yg55JH074r6j8ReGNB/4QKaK5itjGtuTHN8oO7HGGr72eTfWaNWtz8rh07/5GtBOrZQPjq7tFMDTs7ENF5bR5wvr6cdOh9ya8715Ymu7P92wXzhkIxBHXqfbnGfQcV6P4ijurB7owK58psNI3yRhj/ec9CRz16iuFHh68vdTe4uxNcpGrBorQ7MMVYBhvHzYAyFwBnvzXxSw86UuaeiRyz0aRlaFO8thZo6oV8heSST+OM84HfHSsDxVoSSwtKdhYEZP3iEHcYHXIA6nqa6uz2KPJDbXjXEZA2ggZAOCPqCOoOc81V1kKbZvKYyyAgAKfmz2xwPfntg/WualUlSq6aMwWx4H4vtorZcxrl9uNpOAp68nJ/yBWx4X87xn8O7vw9uKavoDf2npMrfeki/5axL3I69PUVL4w0iSCaGWOFSHjJE75bJz/Ah4A9CcnvxXFWesXnhXXrHW7Jt91ay7ss2TIOjKx7gjIxX6RQX1rDKMH7y1T81+j2fkz0KE1F2ez3PaPhv4jjvtMjnmn/dyIuEPGDn+L8e3T2711t/rkNsxJI82Y/KFBLHr0AGT3+me1eN63bt4f8W2us6Mh/4RvX4/ttuxGIrWX/lojHouDk8+456V22gwR3E6zTOZoZFwXwQW7YI/hTjgdT1PYD4bH4GEJ+2v7r6df8Pqnuc1Wm6MnFl+8tG1iBbq6z5DPvMasMSAYyFODk9eRxzjPevOvHUKahaMFk5QHdngexHseuPY17XKsS2iW8J3qUG3PIXJ4/8A1e3JxXj3jzSDGrEzYBLfP/Du64P+yT+Xb3vKKt68U9LPQmN7nkVwhthLhRh12ski5Vl9x9e/UYrBuYN8bG0l8snrBM3P/AW6EfXBrotZJyMqVJPAIwT7+lc3dvtUhRxX7JhnzRuenTNaxuprH4b6xAwdN8/fv8ozTvh34nNlcRrkK/Tf/Fj8P8aq6bA934E1xskrDIpA9Mqa5HSppIZEZAXx/dGaJ4WniadanLq/0R01oKcEmfbfgjxxD5IMjDbt2Lux16fQd+Rk12b+Koy8XlAvPKcLDFkksew9f8+lfGmh+MZLUxrJcuFH8EHLAem48D8M16V4X8dxSATT7VXGCCxBb2LZyfpwPavyXMOG50ZOotV5HhyoygfRNlKI4pnRXY/cc/eBA4OM/iffNY1/bRyWxZwRubIZew7g9+w7+tcj4c8d5RAkwdZC20qwBXBGTzjg8fju9K6+e8t3gVTOHuCPuk5wOv4jPPHrXydXD1MNUfMrXJ1POvEulylZS8zhGG0ZOeR6hun59qofDYLpmhfEbxArxM1jpJsY+CDvlOMgj6djW54zkCWDNFIjbiQBkZPtnjOe5z6VjaM0+k/BOUK3lzeI9dWL5Mg+VF1xwTj5T69a+swk3LDNPq0vxu/wTOzC6Scn0TZ0fgKSO30SzgR5ZdqAB40c44GAcfT/APXXQag7yK+yJlU4B3rgNnovPPX+RNS+HdCQWm1pN+QrATMSRyOm4/X6cVHfQJa3cbbfLCAA7F6dB2+vSvlqlSFStKSPLt1M3VbC4s1SUPM77CxdV3mQgcDHfnj25xkcVxs+qQ3Fqs0ccltvj81o7gfvFJGPp04yM5zXpVxaRyRl9xXIPyyNn04HbsePevK/HUZjmSOJlCzOI4o84cO5xxk/MC3VePUEHk92XtV5qnPfv+jNov7PcoBobb4ZanLNELufxPqyW8aLIUHk243uwK543sB0HTmtvw/o/kRpssZAQMgJfvnPOCQy8/lUuvaXFaeKtP8ADaMlxa+FrNLEygYD3LfPM+RyDuIHPpzXYwoLC0RiAEbAXjHH8vyrux+McIKEPta9dn8On+FK50YqfLJU19lW/wA/xKZka2tZAwunlEY2xtKpDOTjlsAjA54HasowXEMIZ4wFWPkSBjn9a6fyopWjDp87NubPA6cf14qHxIQli8ildqr1OOMfzr52Fb3lFLc4W3Y88RfP8Ma9e+RFFOby2tUlLsPkJLuOSf7oorUsbJZtH0GzDKTeSTapKGHbPlpn8AT+NFfQTxcaD5X/AF0/Q6qj5bRtsv8Agnu3ijUH8EeLtWsjj7E8gu7XgkMkoyFUDrgkjgfjS/8ACW6vqzJaXE1wGP8AzDvOxs4GTK3IiB4IHLeu3rXJaj8R1uvhp4F1S5PlTSS3GkXVzGu2bCAlE34yAQOg5ParXh7xLaNbwLHCsMOVflQg6Y3fNjIJPcn+lfS5xUjH34q72+7T9CLuEtHo9fv1/A9AsdQ1C20ibT7iW2eGQAPGsIAUj+7u6nrljknkHtVS5tdg3BvMRhyy/Nkc8ZJAPQdOmKLDUlucqTHiVc5buM8DJ56jHA/hBq8l8JYWOwbhySgG89xj1PbAr4KrWdZuVR6nS5OSSbvbY8/u0jjmkSSKYqd6o8T7WDHknGDgYxlQPmJXoRmqljp4jgGFMcy58xoiAWJz0Ykkg5H1BP0rs7zTzeRSS7N6vuTaMkKckkjt1OB69eKx7qxl04eUJGLkHcQRk852Z/MjvngdeMfayfuX1MeVo8q8daXcGB1LhsAHD9euBgDt7Hp/LyHVbGWOWRUygRM5bqT6Z7V9GeJbWB7JmQBkwQX6HPU/p+PAr5/1yc3GoPp9rG15MWP7uFdzMfXjt9ePevv8hrSnDlS2Ki9bI1fhff2viWx1LwFqcxjtdRbzdOuCQRb3a8jH1wD9R71a8IeKZNL1K50fVm+z39tKbeePb3HcZ9eoJyfauRtNIS0uVnuLlbi7ikEsdlp77trqcjfMPlUZHRcnjtXfeMbaD4kaWvjnRYGi8Qaeiw6xpMWS0ijo69yMZORyemQRXp5hh6Upu/wz69p7J+ktm9rpa6s73FV6fL9pben/AADvxcrfBI13K2SHkON2cZwD64/IHJrI8Y6RbpaI+VJY7Sw6cgZ9MnP/AOqsTwZ4wttQsYXikVnYbQQMDGeAB257DuO/UdB4hkM1phox5rLld3Qc98dsZ9uCcnOa+G9lUw2IUdrM8tb2PF9f0ovIViCs0jYKKMgnvkVxuqeHmViFDRjrhuVx7H/GvW9a0+XT5llZVDSD5g3y5I6nJPUjn/A1mzxxvZSiePYSSAxHb144PWv0TB5hKEYuOqOqFRx2Oe+G2gvd+DfF2+IERBTzyv3W/OuBsdAku9MSd9zKBnbyB+WMV7l8FrXzrHxtZH50MUbBT34Ydqw/A/heK+0OMhF27BvYIMg5OMFuaupmv1aviHLo4fjE9DEVOSjTl3ueMSRtasU6YHarNrqlzaHKMxXrjPH5V3HjzwS2mzFyD0zn+9XAywSQyhWUgD1r6jDYiljaSnHVMiEo1Fc9M8EeOBaN5cz9Bt5PB/yc/nXqMWvwXVmxBXy8DZC3TP1HK/UYz718x2d00JGD09RXXaJ4slgCoZCSOMMf0z27V83mWSRqz9rS0Zz1KOt4npHibVbprGVYGMwwQttI2JD0+6cASdMdm9uK7i+0l7KbwF4ZuAEfS9M+13Ebpz50x6EYIzjd715L4fmbxb4w0HTACYpbtDKFPGxSGY447Ka9r8NawfFPj7xJqRjNwj3f2aEljnbGAuAOnUtXyeZQeEpKFrWTb9X7q/DmE17PDyfV2X6npVrawW1jiMFXZOdi4HoPSsS7tpb28DO29QR1XOW4PBH0GT+Hqa6lbciHbHCFBJ3f7I57+vIrJuI4lWVgSkjFlJzwevcewP8ASvzWnNptnnSWxz+uSpJaiRlZV2lRznI9x6Ak/nXCeEbZb3x2+saqANI8MxNql6WYfMVB8pOeG3OevXI+lbXjjxCNJtnNxu8lAdvGDn1OPXngdwfYHC1e0bw/4L0rwqqN/bHiCRNX1dmbd5UCn/R4mx0z1OOhHvivqsvpOFNt7S0+X2n8l+LR04ZLmdWW0df8vxKXg+3lvLi61OSYrNeTPdSrewlW3Oxb/WJkEc9TivRyzSzwRmF4X3HAcY5HcHofqKh0XRRaWygrswMH6ke3HvmpLZVtbtTJhYA5VcdCxH8zivIxmJWJqymlsckpObuyxDFtluFkQMoIjQ7cEHrkep/xri/iNqJt9NFtGSs0hEYCjIJJwMV3moLvtN7HBByGXjPT/CvP7WUeJPiTpti8fnWdoXv7hiwRESIFtxY9sgVOXx56vtGrqOr+RpTh7Scaa6kllsXxTqUMXzx6ZbxWCKTz8iDP/jxNFch4bttVS9u72S+0pHvZnmZ2vl53MT2+tFezi8I/a6STVkvuR0TTcm+W52954bn0z9nLVZ7XVbPWoLDX0vi9iXXyozgOrAgMpy2cHtVLw54iWK1EnmRW4kXPOBkH5sY5J9sVr+BtettA8US6ZqageHvEsf8AZ95HIpURuwwj/wB0cnHc89eK8+1jw/N4I8T6v4Vmllh+wSBIZZOJLmE8o5f3BxtUYyOa+wxNNVuaM3u+ZPydk/uf5jqRjUpQqxVraP8AQ9Bt/iVGsslu5MYUgFSpJweeV7Y6jJH413ug+L7fVJPnnkJRzmPfjGf4m24ycgj0GAOlfLeuRyaY5ljwIuSQgwBjvt7djz78Vb8K/ElbFkDsY3XOw5yTyOOeO2c+przsTkntqPtMMZKLteJ9p6fdqAVilRMDq4HPQHHr1H58elYOuXES+fGPmYfKpRskrgDHt256kc149ovxOD/ZwPmmchQu45kJ6Y7nvnoOtb83iG71qXy4P3Y2l8pKrFRnHzEZAGfqTk8AHNfCVMFXoy99WXmW53Wxm67dGdpoIbt0tZpAhiiAM0jkbiIx93JAyxJAHXnIFYDeA1n0p914NMikIZbU5MMp9JJANzMeuSCv04rp5tJaxMUskQmmi3N5xLETBsZ6912g44G3PTHO3dpFLphZZFCsMNjkD8R69c5r6GhmTw3IobdfMwabTUXbzPCZrFdJuZ7chCy/ICjDZ74I7cdvzrM8J67qPhbxLHrdiN6xBkmhc4W5TPzo3oPfsemTXbeJNHae5dAnlozZ3HClgT2HXHv9ay9N0G2uNVazvdQj0oOmFuJImaIEdAwXJVffBx1NfcU8VSnTbkrqS230+R00nJNWev3E3i7wukUUXjrwZEZNDuGzfafGpaSzl/jJQfqB1HPTNdD4e1m0vdPhluLgSCRMOI2yT04B9s8npxjp1y9Jt/EvwqjuPEtpa/2h4Xe4FpeNC4e1uD2+ccK2D8p/OjXvh681mvjHwCG1HRJCWutN/wCWlo/VgF7Y7p+XFeZjMG5KMKj0+zL/ANtk+62T6+p1ThHEr2lP4luv1R0E1guuzOG3SYTcpAxxg7eT+ePQVzuradComOdrDgoCTx2OO/5VteC/FNte6YvmkB2ycsfmz7j1HU+mABVPxM8bW00qbtrEhQRnBzx684weK8bCyqUa7oy0toeeZfwgZUvvGEMcarMbaP5l+Xuw6f8A1qb8I7F5LFbSS53EM0TR2ikngn70rDA4P8IbpTPgfKs+u+Kgy4b7EnIPHDf/AF66X4A2afZ5kU5UTyEnklRubGQAMfn6V2ZvP2UsQ7f8+/8A0lno4r/daXqzptW+GRuYXZVw6qSGjJY/i7fN/IV4p42+GL2wyYwjDgkDnqeSOua+x2sIGiVN5IkU4kc9TjAxyR+nFcN4x8N295FIYlMkuCSQM5GD+nPWvmMtzuvhqq97Q4E5Qdz4b1Pw/caexd0O09xWRvlikDYIxzu9PrX0X4u8KW0ry7EVNg6EcKf88fhXl+oeHlhMjCPYy8gjr1x/Ov2PAZxDFU05LU7qdZNalz4M3htvEGpazICyaXp0sw4/iYbRz9M16/8AAy1uG0BbrzCHdjKUIPUnceo9eK8q8OacNO+FfiO+WLZLqF3FYI443KCMjB9ye1ew/DS6k0jR4YCFhTIYOq4P14Gccj9K+S4iqKpCo4fzKPyirv8AGTJxrtThFep6lDcShmDysoi5jC5GcdOvTp/kVk+JtWjsrYSNMu/oq5GOCcZ/8d6HuKW+8R29tZSyeYjumGDOuC3Hf9DznvXmcFpqfxT1u4s9MnEGlwnffalKcRWqdxyeWK5X/gIPSvz/AAuEdWTnN8sY6tv+uv3vY82nCVVqENWaejTW3iTVpfEmvJHF4R0NC05uF/d3VznCQg9zuwTjoR+NZXhdr7WvE97q+vo0Wr30nnsrfdCHhBGw4KAYAIJBxU19NF4zksdM0eJrXwZo5ZbCBjzdSDhp5D1Ytk4+uetbljoZ02yKKpe0z5gic4Ct/ejbrGTxyOD3HNezXq06NJ0tm1ZLsuz83vL5LodNecIR9hB7bvu/8jrr+d1hMQKBsfKoPCqO57etZhidLRpH3SWxOZI26Ef3h6MOoP4VZ021S4vjHJNHNHGqsZVB5yAcEeo747g+lb13ZotpkbZIwcbR34r46U/YSUepxpPc4HXtdNhp81tPLh4wG3g8SqRww9iP1rnNEkkHgu6uQpGoeJpzZROT92yjOZGHpubAzUfiTR7/AMTa3beHtMcC+u3KWbOQBzktG3oOpB7H61PI7TeLmtLaMtpmjwJptr5ZBBCf6xuv8T5P4V9fQpU6NDnju/e+7b75a/8AbrOml+7hKqvRfr+Ba0jwXZxPs+zxnC43FRRXXxSxx2v7uNk4xuK96K8GWJrzk3zM5dOp534qsZLy0naSIpgFjlgGj5zggAYOc9TWn8Qb/wD4Tn4daP4/tyF1jQyNM1iNT8zxZAV8n6hs/wC0fSpNSuxPayBV3Ow68ArjqO5H88isr4feIrbSPFNxpGpMraJ4ii/s+6VskK5BET/N9cH61+lwcqlK6jdw1S7r7S+a/Gx6OFlG7py2lp/kzldVgGp2G9Xznn5DgHjr6t2O49K8f16J7W9keCQ+SrYMh6A+nufavXh4Q1jwtf3ui6q01nHaTNDC20Ge+UZCeUO4IPLnhc9zxXLeKfB808XnNGqqMiO3iO5Yh6Z/iOOrHk4/CvbyzEU8PPkc04vb0/r7upVO9GThM57wv4m2z7JWIUjDO335B6E9l4+6OvevoLwZ4xtwlq6orKq5dI1A+XgN+hzjnoK+WLi1ks3P94HGa7PwP4mkiuIoZWZYywzgZOO/6ZrbO8ohjaftI9C61JS95H13qEkeoW8UkO5ZkO5CHwEPrk/5PfjrkaW8CXaJNGwixgKp481eoHoCCCB2+YDOKx/CWvedpyM7GUoq7F29uMc+vQZHc8VbuHjt73zmLtuUyqkbbCCqlgc9iD65+8w71+OxoypuVB/0zhRc8RWMUswxhNoJZlHXPufyrznWJ4bVGeTAdeOTwfQgd/17V6FqmhvdwCV5juJ6F2BwcnsR6jtXH6roiWU/yqN4Y75cMXVR2UknGeuRg4B5r38qqxSUZSuVvqchYm71GOS2up57WykbzPsseWklxnBCEgD/AHn/AABr2f4POnhnVBPPqE2l6CYW/wBFtovPSRtp2mQHBJyOX4IxwMCuE07RYbX94F2ljhiBlm57nqfwrstMsXNs6eYyAHO08DPGBtHfv+Q7V72KzGNuW149ioTcJqUNLHaeIPg74a8bzvq/h5Rp3iAjfPYyNiOYjrlB7/xDnpkV8+ePF1Dwvr8+kajBLbTBTKsUxyNvs38Q68g8/U17RP4li06Bbl7addRjA8t7R8M7dsHrnp7ZPoKw/F/jbR/iVpsGj+P9LSKVWYRa5ZKd8eTwsmO46bk4OT1wTXBgpyqVnVmrx7Xu1/h727fK59BiJ4LEU4xhZT72t955x8DGSfxR4kKcZsBkdvv10vwOE1pd3i+YgK3cq4Rd2P3hzlj8owPTJqbwP8JNQ+HOuajqK6jb6zol3Zlba8jf5mGc4YDj8RWV8H9R2alfRqGike7lKKWAOd7euTjr1wOayzWpDESxDovmjaH4JnDjIOnhqakurPpW0tNkDeeSXBwMNn0zyfoDxVW5sx5joELFsFscleCAD39CKdY3Ei2ayySKrYCgAEMRzx3PQ/pXPajrht0iaKQiUDBC88HlvqOhPcZ+tfnEYTnKyPMbSscB8RtMWCe4l2eSyk7VHJ49vTp16+1eL6rcK1pIJAqGQZzjKdyOvT8fTrXr/jLxRZXaSPI6R+XlmDMG3Z4GO2OM5HBwa8VtbC98d64WtM29hG+JL0j7q9cL/eJ//XX6zkVB0sO6lfRLq+nl5l0qbqy5Yo2vE7Jovw+8BaSCRJcTSX8qHgjJJHX6innx1baLDhp986EY345PYY9c/wA+1afxEtvC/iDXdKl1bXnsBYwCI2Fim6R04AACg44HtUiaz4d8KxRf8Ih4O82+O7/TtZOWA45AyWOcg9RSbp1aUOanKUpOTf2VrJv4n5W2TPRxNCLn+8mkkkh2g2mseNzJearO3hvw1boZZNUul2N5Y6hFPPIJGTxyevStG61uHxfbQeG/Ddo+leDoDkZ4mv2H/LWU9TnGcHk4BPYVy9xeeIfFuoCLxFqck1lcDyZbaNRHDCrHCvtHGVYK2Tk8GvVPBOhta2jLLCLW5gPkyIRyHBww6HIzkCvHx044SHtHa62Ufhj566yl57LotTgq1YU4clDru+v/AAxqeHNAjsrUEAhFGNgGBkckfQ8kfUjtWg/k312beMHeE3YQDaAe/wDPirU1sYIgGjHLbQG7n39Oav6fEp3TIv7x/lDMMZUcDPtgV8DWruTdR7nAo3KNjZw6Y2VAZIx8+SOhPB/POan8QTY04HKoT3Hc+p9D9K0pdKUxyYG0x4JYjnkZOR/T0xXmfjnXW0K0meRyqbfuk8r6fge1Th6bxVZRjrL8y3eCtYy/BVzNZ6/4s8VTPGw0DT3SHPBNxN8keO2Rk+9XvAPh6OLRolkCtKRlnbkknk8/U1yi6tHpXw00K3lBjuPFGpvqMpJzmCL5YwfxrutM1yBRCIQdg6hUPTt2r6vMo1IUlCK8v/AdP/Sub7zesuSMKT6K/wA3/wACxuyW3l28iJtQkbQR0zRVSXWQsAzC6hmxudcKKK+bhGouhz6HBm1nALpqMXJ3tm1nIYkHodvPXOfeuQ17wcJEknk1O2R1BP8AqLgFeSc/c4IwK9cn09WtVhMZcovlswAO7jAP5Y49sVzes2D31uV3M3l5BI7HPckAD6ntX6bhcw5Z+6rGqduhB8Sbm48YfDvw342sp1vL3RwbDVSgK7VOAXO7ng7Tn/aNZ9tp/wDa2mJ5z7d/DSYOAD2H8RGe3HTpVz4ZXNpo3iXUvDOqypLo3iSE2zIVOxZsfISTgcgleOM4rnNEuH8CeIb3wzqpma6s5fKt2IIeSIn5WU8/eB6DvnntUYilKmnCh9n3o6a8req/7dk38mjsxP7yEcRHfZ+pz3iXwRHyGi8tdxAcD8hgfTgCud0jwnNY3QI3IBkGRO3Yj364JH0r3qOAaiESRljCjGAM7MdUGOrepHTpnOcTt4JRoBNDAqwspVSTkKen44746/Wrp5/Uo0/ZVNznjVlaxyvhiafTJIgrB4VTa6lfvZxtGc9MZ9+Peu1Yyahc29vAFdnJXYoAxlG68cY49utZv2BrCExviMgH5GXBJ7Ag98Y49+lc6+oMD9n2hvOyzkE5KA4A9gSGOPQLzgnPguCxVV1F0M+tztD4ogubLZEm1wiooPVW44Pft0qN7d5riHzFJYLlnwBnA9OR39z+tcZcatBaEyQt5DDttycj6/qOB0xg1Y03xTIt3EZJA25c/K2Vb/dPQ/zGeaqGBqU489Jf5hZ2N42JS6LNGQoyqFTzn65yBz0/DtXQWVykeFdCgAABaP5T6A8cnGeB1qn4eFvqsbyNGhDBcFjwQOjE++cn6n0roDokIjVk5KHzgFODkDk46Z98VzVq6b5J3utPIaGLpiyyGWUF1YFWUH5gD2HYdeg9evrm+JNFgaxb5QkAUlccEkDp15/DHXriunawuSpOWfIAYK4H0AOOnIqlrmlvJZHfL95vkG9hz+BHtxXDTrtTi+bYGtDz/wCHGvN/wg3ifTHcs9pd7ol3fdVkPQdAMqeleZfDzWLiz169YMQ32xsgjJPz9z269cjr0711WgbdJ8R+KtOUnMlqsgxISG2k+pOOvrXidh4gOjahqnmHA80s2ffFfo1DArESxDpq/Oov70e1V/e4Kmu1z6lj+Ji2+mHzpTuwAqORtUkcH9T+A5rzjxb8X7m9uI7O0SRrliFSONSXYZI49xxz3FcBpmkeIvG+1j5llp27d50oO5h6qvvwcnjNdpYanpXhGC6u4EOpasihHmJBdOxdj/CB7VnhckwmGqar2k+y2XqzihhGlzVHZE1p4bN9YTaj4tuVs7Qcrbxybc7fvFj6Medo79643xt8WhLZyaZ4aT7FbRjHnqu0snfYO3r+dZXiW51fxQ4mvZJGhHMcKjCKB6D175rjLiF4ZjkYIr63D4GE5KddqTW0V8K+XU7oVIQjy0tPzO1+HEKyXqytmaaR8l2OSTkc5Pfr1r3y406JbeFyoiKAFiBnHYken8FfNPgnVF03V4wXYRHpjrj0r3zSvEls6RtuIAA5xkbh27elfI8SUaqrqcdrHjYmL57msmlW5ikZ0YIcgLjI24/nzipbfxOltqaLDcurbY2kztXdKFXdjIOeR375pkuqutozyPGtu53BkJHygZI79cfrXi2u+JbmPxFF5isG3E8n5hk9K+awOAnmLnFmFOm53PqDS9WbWuXjaZ1JLKZMZ9xgA5+voK6TTJt2yGQDao3JIDgSr/THcdvyriPhff77KNXTer4OVHOAMHJ/z1rrNWjSO6INyIRKwaJt2EWXp83oGGFz2IB5xXw+IppV5ULWtt6mkU92a+rXghtmlXG0/eBOOB/P69q8Y8VR/wDCc+LNH8P2oDvfXKxMrDOI+rk+23PtXW6x4txpEyudlwmY5InwCpBIIPv1ri/CmonRPC3iLxoyf8TC/b+x9ELjLIzcSyKfYZH4V6mVYSdJuq9JLRer2+7f0RpSiq1VX2Wr+Ra1SGDxR42uV0t2ttC0YjTrCKJyFWOPhj+LZ/Kumh0Q/aE2TySQAZ+diaoeD/DAsbK3aIu+4Dfu/qa6G9ka0kZI8sRjLHpWWMxPtKvJTei0X9dzCpOVWTnLqZd5a7pFUljEGJCDofeiriokzs28ZHyj5uKK5PaNaGXLcis5FlieS4j/AHg5I5A/HkdwaytQUOTHMGYYwrNxnvkL2/LvST6g6XM0BVzHgtHJjPA7fUcZ9cA8CqVzdC4ynnSBt24PCoc9OmchfyJNfY06U+a/Q3OM8W2D3DtKWZZ4gHWUdmBzkHrngen1rZ8ZOfiD4Bj8eafGg8TaMPs2oKudzIv3ioHOWB3A54+YA81HeW8V4xZ4pZf4T5lxjOfZV4x9e1J4U8QReAvEDGeGL+xb8C3v1VWYqv8ADJlmP3STkccZr6GznSioa1Iapd11j/28vxsduFqRi3Tm/dl/Vyn4E1430cUp2PGRlAF3Aj0A6EAZ9gepr1i1vWt4oR5YkRDvIzz16EnvyTx/jXi2vaT/AMKq8e3Fs7k6NeZuLKRBiMJ18sMBxt6j2IwO9dbZeN4UtpJifIjIJIkJJAPVj19u56+pIr53MMI6klVoRvCS0/y9Vszlq05UJuD6Gr4zuEnaRCrrBGgnmaF8MUBACg54LMygEdz7Vwlzb3Cym5mRAXCZSBSETaAoVPoAO/OPXk9Gswke3RwztK32y4VzkoMHyEII64LOR6uvpW5NaWepWwhB24A3rkD6fpj/ACaqnV+oxjSauuottDxTXmlWVyrsB/F1z37du3vVLRvEMVvIVlw6MCHjboQQRx2BGeDxXWeIdD8u4mMcnmq/LN/9c+o546c5rz3VNMa1laaI5kyFGDnk9/wwT+Vff4KVLEU1FnVCz0PavCmrXFj9nN4QtvkbLhcFHPYAgnaehKnBHIxXsOnzQTYjRh5iruYsSA/+f/Za+W/h/qz2EzKHMRIwV/hf/eU5DenI717BYau8ssYtUSC4bANqGPlXB9ImYnY/J+RiVbHBB4r4/Nss/eP2e5m0k9D04Si3uVzJujkUqUc8Z/z275NUdbvI44LgSxjLIcBT05/Cuf0zxJBrDv8AwPGvlyJINrqc4ClT0OeoPpVrU7h1t23sSqD5XQZPtn1/nXxzoyhNRktfxM2zxvTmx8WDAyOkVzaSp8y9eN3B79Km0/4beGvDdw3iLVk82VhvVJvmVCPlG1P4mPYVUSXHxX0iUBlSQvHkjAJKH/PWt/Xbtry+0qxKK7Lex/u5FJ3Abj2NfdY2daMaUacnFSguazs7K59BhpqGClUau47XC8sta8cLHFZW0uj6YW+ZE5uJ146kfdx3Udu9dvov7P8Ab6fYQKytHtUSfKMjdjk8jnPGQeK9a+HekWsYjZoFRiPnzkYwBjB4/XB4FdTrtxHp0bBAmxm/1ZGOB0+n4V8v/bFdUvZ0fcj2X9ankNzr/vKkj5K8ZfD7+zlMEcAZGGdinIjXJ5Xj7vfB5H8vN7/4byXEhMaBQUzjsfTFfSeq3cGrahsCB1ViPLLY2nt3/wA9Ks6f4LL2rOIlQyH5VULjjr+mOPeuqjxDXwy1epyKTi/dPijXvCc+gTq4BZvywa0tI8Ym38lZQMqeh4Ir3r4m/DiMJKTGxHVf69f/AKwrwPVvAtzFGZY424z82OT7H/PrX6Dl+a4bNqKVd6nXGcaitPc7e58ZLdaYpYkxqVQEdASf8ARXL3NvHrPiCGSN9yZGWPauRlvXsdySrn+Fh6j0rW8H3kk+oLEHJbPyle49a7Y5dDBU5VKOmj/EpUuRNo+sPhpaRHSolUjeF68jB/ya6LXo1vbaSJzGyhNhkx07f5/Gsb4buINPBlAUNH1Hcn1/X8qt+I5vItJpUmCFV5B/i/z69a/A8ReeLlrrc4JNWPH/ABpbat4mvfsOiq97rTr5MtqnLXIHSVPVgAA46nGa6m/0ZbjWdH0CzBNh4XgW3kdH4kumAMrYxzg8Z+tUPhtcvpmt+J/HFyjeTodkY7UEcSXMowNp7nGf++q6j4X6TLFpv2m53SX1wxlmLA5LMck/ma+sx1eWGoKOnuq3/b0lr90dP+3jpl+7w6X2p7+i/wA3+R1Nk728CIpUKONxXHNQapbyiEkIJdxwpPQj1rZuoo8CPGEHJA6mqmp3ywWckYVVwvrXw9N8z5kjhkraM51ZorWARsMHufeiuT1/W5nuWtrCJrm7cDbCoz+PsKK+hpYCVSPO2lfu0vzFGM5q8UZuqeKlvLOa3juN1sZF3iNsh5FOAR7Lnao6Hk1Rj8QIkuyZzwvyqTgN249vb1rx2x8VNEFXeAANuD/n/OalbxE7h2aTBbO3vg+or9fWScq5eh3uiz1K51+ONW2uFgGDy20EdOe5P0rA1fxJHf27RH942cYfgEeyj+teevq7nJfMkmMZPPFQreTOQQQid8tgV6FHLIwab3Rao9T1yLWU+IvgmbwxeSkaxpiiXTp+jMi9APden+6favOdB8UPpRc6pGC9uxjW0lbImlB6MP8AnmDyfU4HeqMF/LYXUN3DdGO4hYOjQgkgj3OKs+PrEeKLWPxJpsZDD5LmAdY364+h6g/hWkcDTozcWvcm7+kv8pfgz0ElWioy3X5HYaJ44e8uHLTySTSOZXdz99zyW/z07dK1r3xe8UztFIgMgGApwAO2Rjr19OMda8GsNRmAGGOO1dTpOpsuGdjIpOSpPWuevk9KM+dI45UEnc9MfxfBJbNE5yGzuWTnnnv3rmtUu4m8vBJkQuWXGODjBJ7kYOR2BFZLO10ZphkEH5QwzuYngfXgn6D3qMwSGMbQSRzjq31qKODp0HeOlyVBIv2N6tvJnGVBBGPY/rXomjat/aFsI8HDclPb1z6Z/M/jXl0FjMuGCMFc8Ljgdx+fp7Gur0fzrVkkKnK8FQcE/wD16yx1GE43T1JnFHr5vRqsC/2tcSrJCgWLVVXdLGf7syjmaPr/ALQ7Ejiq19r97oLGy1iNYnuE82CaOTfBdJnh436MvHQ8joQKo6LdvPGyMpKkE7cdf8Pr7flo3llJbaXLZy2o1fRJDuk0643LhyceZC//ACykGeCODwCDk18RKFKcuSvv3/r+vTcx0lpP7/8AM84W/E/xJ0fy1G4XCqCgAJGD2FbesXptPH9qgG4LdKdpB5xu9KzNP8FyW/jTTL3Q7ttb01bpWeKUhLy0APSWP+IAH7y5H0ql49W5ufHTPaiAeSyyvJcyiOONckbmJ7DI9T6A171elTqShTi9ORr8fwPZpRf1OpA+uvB+spb6DI+1TIcAMBxj655+vfFYPifxnDdRvFHdsZ2XCY6Ajt1rxaLxQZ7aRBq2o3QVQpksokgiLY6LvLO3PcgZ9BWRb6pi6UibUcbtoWSSHnJ5ywH67a+Ep5RPW8lp0PFTko2PXfC9idRuhLKHk2scjd2zjH0z/OvWYoRa2qROFcqpIUsePWvKfCFpcw2sbxNtRhuKtc7iBnOASnr6110muC8jJkeOJQrBQzsz5zjlgQMcZ4Ar5zGRc6jSlovUmLUTn/Fzw3khEwLxJksobAbB+7keuQO9cM3gR7qKTKrs2lsqep6nPHf+lM8d+Jl07UXjt5YxGMPuIwWYH+8SeoPTjnFdD4M8UwatarhtjdGAOfzHb/PHSvSUMRhcPGrT2ZnZ7nz144+HyxGTyo/LIyxLHNcn4W02eDUIYVBE4b/RyTgM2f8AVk9s9vQ/Wvr7xr4bgFuJfs4eKdSxKoMjjr7e/wD+uvE77weGvRGF2xKfkwOevQH8q+6yviP22HdKsdUarS5ZHqnw+1Y6joEbbY0kK4K4+ZWHUEfhjFUviZNPYaeWQi4UKeF4IHtn09DWJperSaUX1YgFoMf2hCgACk8LcAeh6Pjo3PRqbdanB8QPEmi6JDOwS9ulWVccBAdzHH0Br5H6m4Yz2yX7vV+i3f3I5+RzkoLrsSazp9zo3w+8F+EmSRLrUpX1nUEc8jJygYHHqvHtXo/huH7FBCoOAF6YxmubOqReJfiTrN+37y3tSLKAk8KsYwf1JrtDPFHAihQhGMEdCK8zM8ROoo05KzfvP1lr+Gi+RtimpVmltHRfItuVWIySZGEyCR056V5p4u8SuZ1tLaN5764IjijTksfSt/xp4wTSoRFkTzSfKqJ95mPQAetYcOm3HhWMtcxLJ4su1yHJyNNhYdP98j8qrA4aMbVai06ef/AXU5FH2jbfwrf/AC9SsLJvCkclpaTibXLpcX94ORAD/wAskPr6mitSx0xLPTUGAzjJLE8se5NFdMsW3J8oTqSk9NF0R8cSWz8tgkD071FukcFiTle1djrHhm88NazJo2oxhZY+UkUfLMh6OvqD+lNm8OKybo+V/vD/AD/niv6Hji6bSd9Hsz3JT5XaRzEMzYOVDYHG7sf89qsW8gkceYST0HtVq/0nyX8tF5Xhv97v+XSqZhaHJIx71unGa0HdSNy3gheMBxnjgDk/5+taej6gfD140xgWaxmTy7i3JzvTPr2I6iuThuHjc88n14q+upkgCR047/e/lXNOi5JxeqZmlKLuiX4geEV8P3UWrae/2jR70B45FGAM/wAvQ+hrPsFHlgxqWJ9BnPOMCuy8GeILCW2n0DUm3aZeN+7kmA2wSHvjsp6H865690W48Aa1Lb3edu4paSHBAyOWPuAcD657VxxqThfD1PiWz/mX+a6/edNT3488fmXrW223KQbsrDnc0Yz85+99cY2/8BNbViFLBjjAXBHrxk9avaJptpdWCxRsFJGFUHkn0/8A10+50iSNpDFhsDaWByB/u/4/XHv4s8TGc3F6HmOabLejpbP5gmAB68diPT/OT+Jroo9MUou9RHlc+aBkY65BxjmuFWSVZ8FcnJ25PB/z6+1bOg+Jvsk0sUwx95coe+TXBiKFSUXKDuQ4s7HTMQuAznAJw4bkjt+VdPHqkrqYiEZivygAA9+hzz/9evOZtTRlkm83a8gGZExtz6FR79xg/WpV8WmyMUN4giwCY2RwUcD+64yD+HI714NfAVK3vJXJcXug1ppNJ8ZaTcxSCKQXKHcV6jdjrnjgmuC+Ld+0PiliCfvocDvjBrU17XUvtUs8SZEdwjLn/eH4j9a5n4ygy+JCiYO/DdRgYOK+twOHcZ0lU35X+h6+FX+zzi/IbZ+Lro2/lrKWDnJzzj346VraPr08UsRlGUAxkccf5NVvB3gS41UxkZZH/jOFB+mQT+gr04fCC4XT/MyCPuqAd2fr0/KuPG43LsNJ0pNXZ5snBaI2NC+ISJEiicLui58tR3HOc1tT+JY9Q0uSKGV1YM37tWzgZ7fSvNovhpfwyGRN5ijcfNyCPoK7HSvB8lsN0kZaRT5oLDKkAE/59a+FxdDARfNRnd+hzSSWx5p4xa7lk81p3fZ68nnt+X862Phx4juI5IgqkTAYjUEkOOoX69cfl6V3HiTwDLPbkgrKXIdlbq7ZyfzrhDpFzpkrAqIfKcAqvDjn27/yr2aWNw2NwjoWRopJxsz3+z1yPW9I3bhOhAIxxx3z6D2964XUYI7W4ZP9ZHncVUj5f8+lYFn4pmhtXlikLToN80aKMzKOrjH8Y7juOeoOcS48cPLc7yFXeMkA8Y/yK+ZoZTWhOXs1eJk02dTd3H2a1F3byx21xESqmVeoP3lYH7ykcEHOazvA+h2Ok2XiD4iWMpsotIhltRpzHesU7pndE+c7ME8HkZrntY8XRLZMqyb5JAQkZ4JPp6HtXrGvDS/hf8FbDQb+wiv9S1UGS6s/uGeaQZYNjoEXA49K9F+1wtFUWnerJRt3j9rfpbr0vvuejl1N80qktIxV/n0PH/A/xBh0zToEvJl8ybMrO5AO5jk9/WvS/Cev6143nePRNMmvGAx57ApCmO5Y8VwVrq9vZ/Z4tN8D6Pazk4Ek5MhGPrXeRTeK9btoLe81H7NYYO+zsU8lG6dccmt8wpYVzdaUFFu71kn9yjf80cNSNCLu5N37f8E22gsfBV1NcTXcHiDxouDFEg3W2n5ON5PRnGat6ZYPHA9zeM11cytullc8ux6ms2z0WPT2URKqqSQxx610drfRpbESlcDnrwMd6+Qxdfniow2/r7l5GDn7S0UrJbL+t2UdTnRWBiQEAdPSiqfi/wARad4d0Z72aRUDLlf9qiunBZdisXT56NJyS0IcZN6I8et5bHxhpsei6w4hli403Un5Ns5/gb1Q8D2rDtob/SL+ax1a3e1voGMaRuvDHu6noVAOcjuQO1cjYeIFA2u/yntmvTNG1K2+JelQaBqF0sOtWyn+ydSYn/v0/qDjj/6wr9yxeGlQi6iXu9fL+8v/AG5fNa3v60E5pU579H+n+Rnz+HYjbKYwWU9ATyPx965fXNCjjJEZygUHI/U/n0rfstSvtPv5dH1aJ7S8RijqwICgcbh6g9j/AFrSuvs2oRiONPlRTkgnP6/jxXnUq9XDyXM7rv0sYpypytI8cvbOS1kVgCQfWkD7gDwvrmuy1fRA75VSvyrgAcHjNc7LpTEkgDGK+ppYiNRHdGaZRjG0nBLfWu9tLpfH/hw6ReOTq1ombWXPzTIvRc/3l7eoriTbGE4f8do6Ulvez2d3HPbuYJY2DI4PIP1p16Ma8VZ6rVPs/wCtzWEuV3Rq+H/FUuiM2n3fEqHa7EZDD0+nH9Old/ZeLbW8RR91ifmJOT7j689/8K888Z2y+IbFddtECXS4F3GnQN/eHsf51y+n6nIHXMhRRyWHUD/GvNq5fTxa52rS6+plVw8W+aJ69fzJMQEYES5Cn/ZHUfj0/OsjU4xGhZSV2g//AKv8+9c7ZeImc5cYA4UddoHQf596vXesLcKFJwSOuegrGGFnSaj0MFBxdixb+Imij8qRmZc8gdfrTH13AePYs9s7Bmt2JAPuMcqR6jmudlcsxIGB6jvURuHUfMD9T0r0FhoXukaqCNk28txewyWTteRq4YQt/ro+e4/iHuPxFWfiq7HxFA5J5cfd6/ernLa92XUbozIyuGDKenNbXxTud2pRSg5+YtknrzRKm1Xp+j/Q7aS9yaPoL4LWVteQRL9leRkVWI3AAfUL/U17u2nQQWDqH+yhzuMSDBB/p+ea+XvhD8QItMgt4MPJcNtVLaAbmlbPQKK9pfxdNqswWeQB2+VrO3cZA775eiE4xtUMeeor8FzvBYl4ybatG+7PAs4t3Ra1y4s7EIEy3nZYxrySeegFcx/wkn2MzxuA0sZAADbl4IOGPrjjAzjPPpWjc6abyyD7o4oHLb4I8+X7A8lm/wCBE1ysNh5oeNYifJydyDj8vxrkoQopNN3YrXOjuvG8EsLFtqzLn5dwz7c14rrPi8wX7q2WjdskcEk9xnv2/Wk8W3Eti0zR7gg4bBHToP8APpXl11qbTXQGSZM8gniv0HJcjpWdXdP8DenS5tT2PTrxZ445oX/fJtMTg4weoP1Fcz4qgNt/xMrdRHFJJ5U8Y+7DKQTkD+64yR6HIq74FaZEV5Iy8ePu5/zzW14surOGFo2RZrWeLyLiEDEhBPBH+0rcqfb3qoT+qY32KV0yV7suXoct8K7I+JviBbtdJ5tjpZ+2XDOBtbb9xSPQtj8q6DxJ46PjrxjeXskm63tCbW3Vj0wfnb2yeOewqjq+jXHwe8IT6O88cmv6xLmSaI8pFj5foQvJ9zXKS3axxW6M3mSBQFuAP3i+zf3l+vIrveHp4+s8VDWNuWD8vtS+b09EeniF7OiqC3er/Q9m8A6Supaik0qiSNMEE9PrxXqtzHbwxq0blcHqRwB0rzv4QFpIEW4UI5AKgcqw9Qe4rvtdG2QRqMqR27V+U5pKTxjpN7Hz8k1dsxNW1OCBpOT8gDcDjNcbe+K7cJcfaZdkBBLBW7exrY8S/wCj6fOwO1QM46ljXzZ468RSvNJbxsVVjk819NkOULMZWvZLqXRpuctC18RviFP4rvVtonZdOtxtjQnkgetFcCXIUH+9RX7hhcJSwlJUaKtFHuRgoKyO6ia15b+zrVmxnlTj+da+l+LLyz2PYw2ljtOQ8Nuu8Y75OeaKKurTi1qjlcpW3O+s/EMHxVFro/iGAnVT8tprFqAsqH/bHQj/ADiuC1n7b4H1+50eeZLp1wwlQYDL2yD0PFFFfMRpQp4uWHirQ5b26Xv07ei0OiP72g5T1adiBNWe5uMnLAqpww4HyjNXYLFdQLv935STnv3/AKUUVvVXIrx0OV6bDLjRY5EZsAevNcrqunLaSkZ+bGeKKK3wlSTlZs0ptkWi6v8A2bd5ZPMt5V8uWI/xqev41j+MNIXw9rMkUTboWIYA9cEZGaKK9ZaV426p3+Vj0YawZWtpiU+vcmr8UhMQDEnP8qKK1kjJkijg49aVnIQNxjmiisiSpHIpmBIKnP3l/wAK2fiSfNa3bplF5/Ciipl/Fh8zppbSF8H+JJNP2Q2qGESDbLKpxLMvdS/UL/sjHvmvc/BviqWG1t440CxkFkwACuOv/wCqiiviuI6FOULuJ5OISudlpHic3MGxkP8ArGUtweOOQPxro57WOOIZXMrp8xzx04/IGiivyPFwVOaUdLtnCzxf4hxBoriQAKrMW2gYA7AD04xXi9qF+3FyoIRhnIzkZoor9g4f/wBzkd9D4Wz1vw9rLadaGRE2wKA2xTznoOa0PClpaeL/AIhwi6jJtNNhfUGizjzChG1fpuIJ9cUUV87ioKn7erDSSi9fuDDRUsRFPucR8QtYm8WeKdTvpiR9lkMMeTyMdT+JrndBna41ONXwSTtA7UUV9lh4RhhOSKslFW+43rNynNvufT/gfTf7P0yB1clWXdtB4U+orY1K6ngM5mYM0fPy9KKK/CKr9pXk5a6/qeLueeePvEH/ABLGfa3IOfevl/Vbpr3UJZG6s5oor9l4Qpxjh5NLqd+CS1ZVdt02AMAcUUUV9+3Y9M//2Q=="; + } + + function returnGreenery3AsBase64() { + return "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAClAPgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyK8u0g0Oa5Ma3EiruyT92vP7e3u/EGoQy3KTeSDuiDD5GPtWx4m0e60i9W3tp1kS8B3qx5A+ldJpGr2mg6fG2r/uUWPbFx0I9K/Ik38J5G5j64baK2S1ubme1u2XaERT8xPTArJk8J+MLcqlpeubaMkJL5nykegNdFodzH4k1y41q9c+RbDEG5M4HrSTa99kf/iY3Jt9NugZoVfnJzweOhPpSpvluoq7GkramB4b8GxNrnlakJ7q7f5iwb5A3v61qeIF13Rrq7l0+RZ7MgAeX8wQjtjtXQXttGLOLV7abf5abnZehHrWJ4a8R/btTvJHka1sLtlCq4+844yK0TbfvE36F/TdKb4hWkVy16qvbLma0VsNx6e3tT7rQdHtrSextRLZToRMJ1BL8Dn5qztQ0a68I3z3lrOArEu2w8nPtVXTfiAb+6e08lprqU+VtEeAB6k+1azd3t6/10KT6Mo22taZpr3Ecl+5u4jxkbd5ptw2r/EF47m0K2BtmCxyEZ3Y68mu2u/AXhq4uGmZhczkgFHfaF/D61SjXULPW1Q28cdkqeUI4TwpHeocuW7hv1Fa25yl74A1zT5Yr7T7pHEi7JRIQCCeTuHvWJPpniXTLi4ii0yVXmIVL5BgZPXHpmvUYitpdztNKi+bjcJZPTofrVTUNX1C2uJoRLGbe4HmlSvKbfu4PYc81pTqyWjQWRn+HPh/bWOmpfXC293qEYLMz/eU57Hvg1d8M+JpIDqFhZxzSSykh5c5UknHfqOaraJPdWFu2qPILm2kzF5UXIQA5x/8AXqwdfjuPLuoLN2kY4eOJcfL3NYVH7RNX1X9fIEzd8TeDfDfhpLfVRp4vY5OZFb5grAfMcdDXK2r6D4p0qez09Bp2oHcUcJt+b+E5/pXY6JNbvPFJMHXTlV9kLAuQSMZIPXArjNQ0/VNV1DULfTtImvo2jHkS2w8sIeoLfQc0Qm6tm/i/rU1l7yujNuLTxl4fhjl+zwyTwRgefG5+YdifU1d0ywufF1ukfih0ljDiVbXJzIexOOuM9BT7Xwf4mv4guoasWuEjDQ2obCZHQv64rnFbX9I8V6XZ6nfLa3ETEB9oBZWP3iT1H8hXTGzbatdGVrHU6z8HtDuLeWPTrOQS3EeAnmMfIYkfMfYVs6F8FNJNqjXOo3W+GD/WKwRGVQdxOBkk4rVh1GTSL+2vxdidB+7dI2BDMBwK2LHxHpLx3UrPlnRgwkjK84OQAevNcrrVIRXO76msbNnmFz4c1V7K01/w1cKbiF2hktGJw6KcDn1x1z61T8N/Eb7Bqt3Y+IoJrS5uZQ4VwdsfrgntWXDq9x4J8Wiz1Vrmw09ybiIgkoVYcHA65rttL1rRfGNwIJdOS7SPc63nl5Df7OTXXUi4xftIky+I3NF8Zabd3V/BbqpiQbkKKAGYjBb0/Csvxt8Ol1jwdNDotsI9SWXzVnDBTIeeSfes1vEOmaFdCzjni05TceW7eWCQp7MPpWxe6nGmow31rqkctkIwixEY+pz3+lefapRlzQ9S07qzPLPDHjYaEZbjUJns9Tsdtp9nznzDznjsRXqOhT3Gq6Al7p14sbXD+Y7XLBgG6t9P6VV8SfDvSPHfhnGmJCL0OZftm3vnPJ6nPvXCaPZ3nhTwpd2epebbusmZFkc4MfBDL7N0zn8K65ezrxcoL3luv8iUmtj0PxTLBrsb6cNKtLjVpIiYZ4lEkm4Dt2AzisDwD45tvDvh270uaOW31ZSUlgc4Z3Jxx61nxafcw3nh7XNIlDxkrFceU+QMnPOOnpXb+Nvh9Z+PIhqFo40/VoOfOUY34/vev1qVGMaahPbv29TS7exev4F8J+GZbrSbZBMLcmRTJgnIySayfhDdWPiXwlPol5agIWJlR8lZcntWdrWlaoPBWp2C6pa3t8sfzuzkFABkg/ljHvWh8I9abxJ4QnggFrY3MC+VGo65x1rk5G6U+6Za3R5v4t8DXnw18a2us6chOiiYJGztuETE8g+1Fem6d4skEMui+LtOSURsQhcZVz2+porT20qqSqLVaXutQt1Tsee2Baa6S/1eSbZI2Fk5+Var22nnWr+R5ppZ7BXIhWRuoFek6Z4c0fxjP9mW/eJUX/U4wKr+Ivhzp2nXEKvfSiz3bdsXG0+tZKo23rqcvJ5nOSeObbSLVLCC1a3b7kzsMgLS6lc2niq3e3s1822giDgkYy/0rqZfBXh+TSYilyjiI4lZzlj7+9WvDl5oOiEx2tt51t3mK7dremauEqa01XmUopPVnHr4d1m6tfOEk+kaGiqDHKSC+Ov4VPfvJp94sGniLUw8XCwqP3bf0rr9U/4qiVrMXsmWQv5URyFX+6aw4tRg8J7V0vSpZih+aSRSd+OvIpuTkrx1X4/NA4L7I7wpp13FdC41R1hlmjKCCVgQw9az9QvBqGtzaZYwrbNaqXfy8DcewzU134r0nV4421RZILx2IYwoSIwOgqlFov8AZdrHeXyTRtdzea/lZJEZ6Z/ChztHayJs0VrIa7pN0zjRjPDN1nL5A55JqXxJo+v3jLLp4k+zsfOGJANo9CK3dKu0eK4t9PkaSzlyGWXOFHqc1TvrLU9FeS9RfMjZRHhJMjB9K6KbTXMo77kbIyLjwpP4nth5t3BaXkW3cucnH9TVzQfDrWqztc64t6WgMIdlJ8oZ+7z0NVJfFcHhtTcXFnPmRskqd24DjGcce1UZdQl03TrdzaSTG9maZ4lB3qhPAPbgVV5KOg0+pr6R4M1DRLOeSz1VZ9O3ebJEnzSKB169Pwq7p3xD0e4Wfz7wRSBhFFbyJjdnkvntjpTdJmufN80xtpukjEnzsGnfjpn0Oe9Ynizwbod48Y0Uta3c4LxlzkKfQj1NKLjLSejYdNC7r+r399D5uj6hCTDgm1U4Jy2CPzNdxa2fiPRPCo1eC5jguHbNyik7FyOAfbArgNH8D/2Ldxard/8AExuON77dqqemcf1r1DQrk6tDLaTSSW1pKCzI7gjjgHPpntWcqsYS5Yq6e/z7ehrTai9TD8MXeoMj6hdT2N8sBId43+baw6Y4/wDrVQ8WaP4Z8e2EsVxEYLyIYjm80s8fuP8ACqVh8L76+1PUZdFnjSIgbZHmIWNiemP4hjP0zXM+K/B2v+EIhLYwNeySKVnlhyShz0HpWkaMoTXLK3X1JlzR0II/hBq9pbpHFqjbHcCJt5G057iu31Pwl4h0jwjc6pqGqR3iQRqiRImD6An3rG074sW1xaWtpLby6bcllVndS65GMlu/PtXX6rrS+PNDOh6c8lxcyttRwNkQYDjnuB1NNyqSqxjOOjKppN6FbQ7628Z+GBp+p6e0moKrQpBNHwVwdpHHv/OuCb4feL/CcNra6DqMdzbWu6bBGw7m5KnP3uOn0rXPi3U/h3c2WleINN8uRF+S9jfesw9V7Ee3UV6Umr2msabDc2UsM0kwAJxxx0X+lQ51KCtFXT+Yt9GfPGom31HxTZx6z+71AlUn2yYUn39DivYU8M6FcaGunF0twfnDRPlmUd8e1UvGXw40zxvD5szJp+uA486FSQ7c4Vh+FcvoNjqnh7S/sut6LqMmJTDFepk/J0ADD1IrSUlWgpQeq6Ak0zoJNIn8FWqXWk+I1n0+V8fY9nzO2cAY710kV4keo6jpWrQw3EuoQRrHJLFvXY6YIHpj+leZwapbai91HZW88c1hKkkVpneZArHeWPXP6V7JY6hZeMNNhvYAYpli4EvXGPu/mCK52qlNdm+ponbRHjEE2o/B6+1a2dLq/wDDhY+TcRp8hf1J9hmtv4V+ILnUtZu9Qub9ork7SlnJwGQjgkfSuli1KHxNNNoOohxbypt+zwnbkcnJNefyeE9X+G+q6nrcDrPoxXy457n55cdh7HsK3jUWJpyg9Jfn/wAEPNGzr1rZ6Z4rk07TZZJLnUGAl3niIN94CtG6+C9lpup21roer3dlI8ZlmRG3YA7/AIms7w7Y23iG90281uV7XULljPbzAgK6j+A10HjjTb3SNWi1zTb6Tzci3uIt+d6HgbfpXK+eD5Yu3fzsaLqzG8FDUb34hNDqdr9sTTlMSzSDAwOjH3OaK5/V/wDhJ/Buprq9hd3d7pN1P5kwZNxX+8T7UVtKhzqLhLp0Gnbc6aHTL5J5IobyO2k37HnUj5gTxWjIb2yY6RK/24FSXn64XuaxP+EZi0+0nsJ7iRLoks0jN1966Lw34asp7JFudQecuCqSB8E/7Nc0ZRqSv0OLZ6laaLTZdGMmnzZdP3eT0c1gaR45tJ9OudJe1MFy8gy6rwwH8quW+hRaVfTXKzswtpCfsp4Ufh3q3qFvbXEcV7bWEXnOcuF4IPrXRzRacXuxF+W/sfC9qmoQzGViuHVRyOOla/w18YWU+nahqE9n5lvPKdkUgGVwK8t1bWZTatZTtBFHISTgHeGHQfjXV29m+rWUMNgYrP7PGPNQKRlsc4zSknD4d3/TKi7O6O3nutG1Lz762hiESnzDGoHUdcD1qzfppuqwJJHqQltFw/kcK4BPAGa81ttJtdFs5YG1F/PkBJQ5PX3rTg0WF1gia5RXSMbctgmsHUqQXJa663/rQ1VSRPq88+J9Pg0B47jdhI4stuHuaqw6bqdtYYvJF82H5/szNhgPTmtmfVWivomunla7k+UvGcgADuKr3HgTVdQtItfjlM1lLL5YkmJztzg49vQ1UKcpu9Ja+fRByqfwnM3Gs3WtxpZDSUjtEAnlL9flPABHqf0FXvDOuxMs8eox4nwRG2PlxnAUe/vXd6Rp+m+FbWa2a3EDSy5RJGJ/hGSWI7/Wuf8AEEmm2sc907WxsgzApGwLrjqB61pJyU+Waat/V/QicHBamBL9g0KVpbu/i+y3bZZmfcQfYfWs3S7/AEy61aS9imkuLC2GxJWBChyOT7kflVXSvAOneONReeAS2dkhztLFkY+nPfp9K7iG2tvDw+wiyIYA4UAeVjHVfb1NVKcKaS79exCXcytJm024u7mC3v5VnuGL+XIcqR1P0/CqEXi/UpZrvTEhdZ1YRxQmPgAnly3cd8Vpaz4dNvp41vTorayuACcE5Uc4GKXwRY332B7ueIXE0jkbSQrAeo9BmkkpLTW+w0tS94k0zXvAttaX+mqL+0khG6HnMh/iPHv6Vh6J8T7HRYbBrxxOl0PMmwWZ489MgnGT0+ldXPZ6hf6fcl7oIYYd8NsCQevP557Vyml+P9MkeW08S6VFEzYjWVrcKq47nA/lXS3zJT5ddtPK36Gs9UpF61+Inhm91oyvawzIpBHmRgD3x74p/wAQfFbQyaRq2gWZitrAYnEClRgnPOPbjNdFoFl4B1MZYWDSK+VKgFWXsMVP4e1m0fWNZ0i3trW2t7xClsrplDyeMD2rKHJeUpS0XTvf/hhwXuu7K0q6Z8VPDiC+05poJPnDjgxMeAyt2xXndn4H8X+DNQ1S20loLyxkyLf7QxDEDBzjGM9u1T+Iv+Ei+G+o2tve24m8P2nIe0GzcpPG7rzmu8tdR0rxfDbX9jq62d5aNjZJLwxPUEdx2z7Um5UV7usX37/oRvozgvCPjx0szBrFrc2uo+YQH8ptpIOM5+oP5V0Vx4z1DSPEGlWerX8rWFx++WWWLhlyQML61H4s1jV7lbLSbaa2jjzJctNwIyi8EknkqSDx7Vr6xoVp4m8LWDTAzajZxh43Byv0GO1aziqclJppv8H/AMN9xduXRbnl/wARv7W+H/jC78RadCn9m6iSqK3Pl5Oce2eSPat7wfq9rd29vrb6hK15M+HtITxkdAFqx4ktJvF3gu6sLkRWkyMGW4JJVNvJYjv6fjXBrpviS4ktX00Wl89nKkix2i7A6qP7vcnvVxnDE01GTV72ZD3uex+L7mIaBHqunW4tdUuflVCwEme5Hp9KpeGtIPiTwfc6Tr0stp9oOFDHlQDwR6muD8T69c6/qGmxXA+xTRNuuEVcKjMfu/gK9zZrW1022R1juAANgQdFI4PrivLqqVOKu7S7msbNnhGm+E7zTdXbS5dW+1QWsmVK9YsnjOeh6dK77xt4CvrnQ4tQttYeC7gXzFRpMRyn2HYmvO/HFjJoviy7jt9OnS4ncTWuyTchHfP416Fquq6t4p8GW6C1mt9QtGVmtnX7wHBAHpXRWnKMlUVnf+tfIuNldWM7QviPrOl6XBo2saUtshRgZWX74Pv0xRUOu+LrrxRpCaNbRyW+pFVH2dkADAdcZ6UVx1I05tOclB9rmsVpuaHjS2tnvLZvtShpnAwjZOD61WsvAZt7iIpqzR7W3JlsAH6Vylr4aXTZDPc30koj5UAEgnsM1e1wyavZwTWNlPYzxn95vfg+9bxjBXSeh5rZ02laXNPql0L25SSeR8K+fvVPrNkPDocXF5GY3HRQSy+3tWBa+ErvU9IhNs8gu428wy7yu36VWm0bxLNdGCfUkmhkwHL4z+dVFU7Xe/QDa8I2lh4oaWKSIxW9vKGDsASR9fWn+NLXUJtRI0iWLehHynglfp3rastO0rTbODTY79LOUrkyZGZG7mqd7e2OlJcQRpDqN667A+SWjPr9azu4puNkW9rGPLHcXdzD/bLpFKhC7Y0xk9hRqfgi4vL1JrW6khlI+UMSNy+gHtXTa3p8tzo9nc3DtBOqKTOCMjH9ayrqxudd0q0vrPW7i78t2VGY5we4I7VtSVk7rUTVtDnvEGj63ZyWKW2qfu5hgysuGz6e2a7vQ/Ev9kG20+QzSyRRJERkskY/l9a5DxDrx17VdK0mGCSO5s2UEbfv45ZnPf2FPNtfWV8979sSO32bZYmOFyfT86eIXNLkQ07bHe6jr58RHy50QW8CFGCkb2PTI9qwR8LtH1Oyju472SA4Dy2xPzH6eprGOrmwnM0J89rkhSpyAB7etSeIvGVtfWsGlWMvl3O8PtiT5gCehIqYc0G2tfJlKb66nQ3+pxaNDa2mlWL2qRAERwrnzTjnJOfTP1rK1zx6lvFZDULJjK7s0TRRgkHGAAfQ9+tdpN4hkv8AybGVIVtbWLZG6xhee/H1qhLZ6dZRWmoRRrcSwg+ZAy71iXPzH6GknRlVclJpX6r/ACv+RpKMJdbHnul6LrWqy/bNbvHi0uNt8VqvAyeQMdfSun17xTeeDbB/M0221FpwET94AYhjg8dc1f8AFesefJaeXpgvYJIzgA7QuenTqOeKydB+DmpyW763cyHzQC9tbTsXHsQenHH8qpqcJNzVv68jOUJLRFXwRY+JPFmqRS3kg0ixZCu0KXd1z90Z/Cr2r+I5/C3iCzt9Q08XulRSbHIh3lTk4OCM59KreGviXF4Sne28RabdRagkxKyjO1k9V54PtW9r2pS+IrnSNR02HLOVZzJyHZGG0fj3roptyTptWb1Vu68/QunZxcUatlovgjWLO61eKzWK7T5VgjTY27acEr6d68216z8ReEo7XxImksLZZfON2j7mVem0jpjHtXqniWG4lsrLUJPsrXmooIs26YCLnJUg96o6dqupXuh6hFcRvLpd6TbpJJwEiUbS2PTHf1qeaNLDxdRX53p6bfqW4+7ykVt4y0690G0fVYopjexAquzc0iN1DD9frXnGv6XoNh4juRott9lgjjEkhecMzknoq5qxqraBbeObbR7HNnZsqIbi4fK7VB6DsMfjxTPjLp2l6hpFrquiWjpcWcgVbi3X/XL2+uMZz9a2cFRnKlJ25tF5f8H8iH7qt1Nvxj8PIfGPgqymsYo7K+tIi4fG6SQYztbngZ/KuQ+Fnj7xJYXP2F7c6hbWvySSEZ2JnAwfQeld78MfGEXibw4cTx2180fkSoeCPVgBXntjNqHwv8TaxaSsLrSyvntIqANtbkEKefUY9qI3lF0Xq195L6SR6V4z0q41rw9fiwt7WS8nhOV37SvpkDoev51y3wxtUXSxdR2zWUhBidlcswYdSCeldVo0en6tpIu4rpktbgBpWztOR6n6EdK5JNIl+G/xAmgtbxItLkjWdba6kyG3dVHXnOTj0rijJSpzg/l8imr2ZyT6LE3xIl0ptRmksZZRO285Ikbk17PcvZ+F5YY7hTeM5Ah2naOe/wCFcX4s0q7hE3iTRbqG7ubkiKa1WNS6KBwyjHSt7wbfXHizw/8A2XqNpNNJDGWS5jj+dGB4JPbFOqpVlCUVdvRevcuMWmYPxHa60bxjoestILiwcBFQxgCPnJHuOa7G+0PUbq+HiLT7lGCwhWiL5ye3FYEFjH4+0SfS728U3cTZj1B1+SPHAXHYGsTwrpV5Nql3okGox3McSmOZw5KBPVT3rGpd0k5dNH/SNVEr2jTfEPWJL5kg03UYG2hA2Ayg9PrRVi4+Fc/9tJdeG74tFbLukuZDtTeP4Qe496K55qFSzjLTz6fmacrZ0PjfSdPTSWu4bsCDPy7fX6UL4YOs6PZpbXS7Aozu6k4rkNZ8NTQTxC9uJrm1Bz5ScKamuBrAsoJ9IJS2J+Vw+Bx2Ndkope61Z9TzDuYNMudJtcXJljVF2iSM8fiKw7q2iheUyXiyBjuzu5B+lQ6V4p8WSMtpcWgeNvlMhGR+dKPDAn1oy3aSOqsGaO3Odw71jLlUeVLRdR27Ghq3gTTtUe1nN+ilkDfIfu+3NP07w5/YM0ggjgmn24Ekp9en41avdFfxLbSf2XGzJbyYUFgrJ7Gq+seELjVLPyJNRjs5Y9oKs/OR9Kak5ytBFcttTPa41DUX+wPD9pjMgV9r/dHQ/hWRe6RqHha4lOiFouCZFY5Vl9frUt5oWraJPGtpdM2xivmxnIY49a6HwlJqs809xqsBlgGyJSwKgc9Sf0rWDfwX94SV3qR+GNKhtNOS/vkD6g6sxYZ3hCec+9Q61d6ZNYlmkVraH5WOzDMO2R61JqnjOzl1W6tp7V1nhPChceZx61hRTR6pPPcz6ZNFbmPakIILSHPLfShrTRibvoRm6tjdW3lXiTWkI89S+MKegU+wp/h+80pvFrLtt7zOZJIolOFbgj5u4J7UyfwhHe6dvNtFa2yLuYZPzDPQmtDwkumw2s8lpbLGFBi8yMZwwOR+dWmnES0ZPc6zcW01yw3BxJwqICNufX1qLU/F9taae8LADzx5UaPJt257sfQc1XuPFV3FZ+Rf2Kw7p9wZkwQnue1Yt3q+mXVxcWhjUXcsY8pDHvVmP3SPY+tKFNvToSz2bwZqtnfeBdKs7iKJp0BDSDAlxkkYbuMUstzepbpDFqZEatkwQsVcA8YXjBB61wtlqqWGl2sE1nNdSRKEdOcRn0rotN8TLcRK05ls9NtgC7SjcRJn5QPesfrM4txqLmjtZ/1+J0xqtOzPQ/D3gTw9q1jE+pSQXc7vsZJf+WRHQMT1J55qz420HQn8MDTtHVLa5s3CSNG2FBY9s+x4q/p/w2vtf8L2OtaeJEMqh5YCu1yueCB0OcdDUtzYwvoU9vLH5M5bkqnBwc89wfavoo4WUKka9CyjZadbdv8AgndGCeqPOrRH1bWJGjiJhtrYFY2YY80JjI74zisPWdQj+0WWkRyyNYIEgZUOC0gJBjH48mur1SM6Ori3k843SBUkj5Vfxrk/E+laMgtYjLdXFzEfNVbbp5x5BLdOOnFa1JKo+ajH3lttpd79ip02ldFT4rfC+01nwxdahpnlyazpreYPsfO5cAFPfA/zzXJfBnxLaapbRaNewCOe0LPunJAKjtg/Wu18BnWYtT1Cy0y4+xwkqJI2YyGIkfe9s9MVzelaPpsvxF1HSr9h/aayMD8wRW5zkV5c0/Yv2stb9NfyOFwV02yhqfhW1+Hvj2HUIJpY9JvkdttqwbyX/uEdlPY1r+N9H0Dxd4Ra4jsZ4NStU8wXqxkAKOznuOn0zVf4rCHw5rejR6ZBFbzzo4dWfKEAgA5PTvVvxvKNJ+GEzQ6jPbuyJKQD8kj7hwT37+3FZKcI14Ts5XVr7fh/wR3im0kVfCEt7daLDYXNtb+QItpZP3ZYep9x6io/iJcaZaWlvpVprFteXUMf2mZZUO+M9MLkZLHP6VN8ObzUNTitvEM0ltcT3MJt3WU4Rsew+7Xn3i3Ur7T/AIoQ6jfaUJIAE2hTuVkHAbOOvXrWlGSUp01a9n01J53y6Hpfhm9g8P8Aw+e/FqJ72SPy4XkIyzsTjA7YqJ/EE/gf4cNDKPJ1K7Vk3ox3EtyST7c/nVbUraHxnpOnzabJNaRwz4MY6M2OMiqnjyK08Q2llp7Xjrd2mRKEXOM/TpXnc2qT6O4Ju1zX8LeGpdI0RZ1naITp5khBUkAjjr271yXgQyf8Jgscl8YrBy+G2hGnjJ5HHqa6GHSLix8GT/2hLPNp0UZUyq204xwPauL8C+DtVdZtajnL2VvGzRI3JOB0FY01zRqTTs3t5+hqtj1C/it7fV7fR1e4j0xUaWQR/dz2GfSik8Alda0C6TUiVe5H+sc7So749KK8eXJF8snqjeKTRwuq2eqa5a/ZlvAghGX7titXT7e50xtMt44DeWceCVJ4b1OKzro6nawPcT25E92fL+Q4Kg+1WNCS40lpr2a5dXhYRrA+cn3r3nXg4d7HlpaHe6mtvqNnMmlSLajcAYTwVJ61IdOv9PXzUt0LRw4YIfvViaVZXN0Wubg+Wbnpk4zUuu+MBos7xTsRbvEYt2c4OK8/m9s02uvQ10WrE0LxMdL0e+uPJMVzLLu8iMdB061Nqs8F9pUlxcoIw8e/IPIftzWb4c8OXOveGPku4IHlZmR3PzYHQYqvd/De9huYBf60l0/UWyEgH0PvXZByb122sS02V9H1bVdGsLmXymuDM48sZz5WOMketXm8VXAtVDX/ANrhcqrCRcDfntWVp73ek3F5ZSAkS5MW7gg96saT4TsLK/ivdSui7KS6WiggFvrWqkmkk7WJVzQ8W3VpZalGsqLBLLGWW5Azz6c1mWWtwm2+z3SSO6vlZE+9jHOMdq19Tk0670uK7vRLOwTIQrwoz0FXbCGwkay+zskZZN5O0Ej059fak6ib+ILXZw114rDrLZadplxezS/IBISQh7nFWmsn8MeF7e3BdLh8u7IgJ3Z+bn0rqtWH/COwKNMs1WZw0hdupP8AjWt/ZzCC1h1Ha9zc228E4wR14P405VfdQ7XTPOtd1q61jQo1MDG3XCkSc7x059TTBY2fhKW0htIRIFwWmb5mz15/ljtW3rPhORtZ0jTlt5zLeyrIrjIXap647itvUnj8L3E9qdPivrmB8/ugShJ+v1xWU6raim3r+mwlFsyG1bV9UW5itICHlHnFHTdsjPAf3PFXvCXh/WdW8SQnV7S5umJWZC0ey2SMdW9z0Fdj4KMkdzNcXmnhr+cBYo0GIrVF52n1yT39BXe6bptzqttJq2qavb2+mhgmwHJSPnqB0Gc9eT6V3LCS+Ockl17/ANWOuFDaU2dvovjSLT9Kt4oJHe4jg8tkiBI9Cfr25Nc7rlw9lYXd4zovyjYpIJx6n6Vp6DYaStzayy+fc2jtgsW25X1AHXtxVrxQmmyXcNpAuYSplLKmzKZ4B/GvrsE6OLbdKV3t6fI700locJ4ju7TUPB1na2tnidG2Eqm3cM5yRXK6hdjQ9PZbjQZIiw+W7iJLKe2M12mveGr7TxFf2+CqjExPIjHrj05ANef/ABG8Z6pql5pvhq1SO2k8o3K3UbH97H247HIINcWKSwcOeS5lsZVZpRucT4D1W38J+KNS1KSa4bTb1fLyyHJkzzux/Dkdf8Kb460PTb/4m6dLM7Wd1dxrcLdwvgsegH1GK2PB+pWuq6TcQa7AkEFgHR2xtkULltwPv05rn9P0OT4gyHUbeOaS3t28uxM8gDhQeMelfOp0XF1IycXtZ/5rocPuSWjsc/4xXUh8T9LtLiBdTtbeEGNZP4xk7ifxxV74l6rB/Yken6naPF9skWOGVekJzkkjvgU/xdcaz4e8Ux6tqGn7WbZB9oMhaPYowV6dTnk+tRfFKOHxNF4amg1K2ihkumzEzDKDb95j19sGhx/fUuboum2wOLTY/wAIwv4auJNP3K9qke23ZkIWY93+vtXHeK57rQvG82pGUtaFFUQ3JaWOSQfwcce/tXrxsrK6htNMvriOGaQfup24BA75HY1wmqi48Q+Ibvw/KLc22lQ+ZEbaTeC5HEjA+3GO1GHqTqz9r9nVE2shnw01C+vdTnSGIGGRjMqRtxGevQ9qyfC3iO60nxLqq6laXGLljmTZkhgf5Vv33iO38IeGsRxxW14yhEaDjc56nB7Vd8FWt3FdwXklw0kbqpwTu3N3zntzWEuVc8nHfT7hJ7Im8S6ta+IfBmoJZtdTyoo/d7doD5H6Yrl/CXjBrDwhf2FuJLLUI4yx3j7474/Ct/x/LNqHiHTtLsolW5nYzXBjIGRnjdjtXZM+h6dFZQX+nx3N1KAEjEYLHA6k1nBU6VPl6PVG1+hzEfjNL3wPFHaeV50MXzkodw9qKzfChGk+Pp7TUIfKVHOIyOMduPpRXOqVKDfNrc2jLQ7O2OjHW5PtXmxZXzYQ5zyKsNFBrk63fljy4zuAcY31xd2N2swXNxeKh+5HET61YvYrmC6htjO/lfe+RulazpuNk46eiORVXa5saxe395aeWLOZrVHLLJGuQv41b8M/D+fxTEdR1ZlktY/ljt1OJCB3Ydq5Z/Ht5oulzae88hQzYO1f4fY10fhbxhFFHcRYnSdW3RsG5ZSOhrNUYUr77de41ODep02raTbS6TKdKjNtdRDCDbgHH9a4vUV1G3SyuLuJ4bmN1AmXvzXpeg65pXiDRpIpWlgudxVmIxtPtWXeeEX17ULOG2kmuoUHmSsvIGOmawaqQaT1vrpsXKnzaoybfUdHudXIurWRp5By54x71JqtgHaULDGCVwspcZ/D3rd1vR9O0RY5ZEZmOXfkZHpiuWWK+1uOTFuQGbckzDlQO5xTVSVWTjCPNbt+olTbDR/Dd3e+F4JxZLcGKR0IkyWdAe1O0yG1bVhHHbyWjOC26bhEAPr2Fdydfu/B3hrTIlktRGY2BLgF5Djr+NYmltpF6gm1UBobxhvcMMpg5Hy/w5r05YXnqRgqkfP+rfI09nFPVnN6yb7V799OssTRpLsSeAfKCevPevR9a1HQ4LHTrdtMkuZIIw7ySfIikDB6e46iuW1t7bS9ZbTrRTZxlA8Mjtzn6dOlZfiHWNRvhYzXGpCR03I0aR7AV4xntzUQdGFOVOzk7+i+SJ54Qvpc9Jk03VfEV3ZaxI0NqkMflRSBQoWLOQqen1rjPFk1rot0TAPtROXmkAGQM9feud0n4hahDa6hoANxMskYOnxPJ8ozwcH0B5+lY2ta7qFlpcS3keZGIQSr/GB1/DIrrxGJkrQo+4vL/MJ1217uh2+u+KotZ0jR72PbFaxBkmtYCBkgfKx/HHX3qj4evP7cnuoo2kFjIifaUB2qpDZP6DH415zo+vJZ3fm29k5sZ4AotwC3myZOWA9R/SvV/A1nHFpsr2rCQjKzKQd8XTO9T715eJi+d1Z633f9amKk5u5614QZtWtZJAwaBYmEYB9Ack/pVKLxHHDdp9oJeYnOxV3M+0fKAPqayPDs8mgaZcBWKWepFkjjBJZMHkA++OlVNS04xaZ/aolmhuo3ZYoWOXLOuN2fQDHFepl0/qGDljIO/Nol+L/DY9BPlhdnpEnivS76zd7mOSBXIjNvKOdu3nAHHPvXzd41s9Z0XxZDrFjALmS3b7P5X3iY2HUD6d/euvs43+zqkmoLmTjzC2SGAGevepvHyRT+E7W7068xqLb4nAIZ9pHGMenOT2yKeCxbxylQqq3Pr6Nf5+pkvfTizxXxxrLeM9K1F9EjFvEu0TtzmZkHIC4zgdM+1dN4DvLZPCNm9pc/LFhJHJ27iepx2x61T8N6o/gfQZWuZIHsYN5S9ZdrlCOVI6nnjms3SbFZrW21PyxHLcXJngs48gLH3OO/19q8yceeHs7Wino++hx25Xc3/EniK+8WStoVhBBPp9uwa5nkZSzEjIX26fjWjq/gzwpeaNFpMcE6anNjyVj5cv6+w68muFi1B7H4k3V6bWO0ivIANgwRKwbBYD171a1W4g8HeLZ9Xmu5vKNussP7zLgn7w/SuyDlCUY0G3aOi7otTaL2veFr7wxdeG7nU0N1HazfvJUbKmM4Azjoc1mNHLpXxknlgsInTUkDK8D9VIxkjp26VpWXi/UvGV1brd2s50eMBogThJH/ANr2ArtLvwRaeLdNiltvK0/WLEboZEP3wOik9wK0c4RXJblk1bTa/wDX4mi5Z6I8n+NNhFez6dBbQeXezSb/AC2GD6AfiTXQaDq0mkaGLfVLKWC6iQiRYcZAA6j8BVTxXc3PiDxLptzc2YeK3hEQmtyf3cgPJPrzWp471qODw5bwTIIDdsYGv0AdORyfUHFYzhNRhh5brqTyNNs5HSNKbxLpOoeJLG6kbU0kLQgn5ig6Kw9MV1mheKZJvCkF7qc0XnqWZHlAyCP4RVbwZ4UbR9CvW05m1Ozn+WNlOw49fYVlaRaW2vfD2/01oBJqNrMzRg8upzwB3NFZxu4yVkmvuEr7nQ+BPsfiWK61HWFEt4zH5uV49M0Vk+D9el0zRWshGJLqN9siOuGjz1+tFcE6lSMmo/kaIpah4T1LULiA7Fd1/ePIrfdxRp2tX+i3FwlzYvcs5+Rz0x9a0tE1CS2026llLbJXLBCeSKLCMeI9PuomdrYxyAxFj1HpXRGpZ6HJa+iMCBv+Egvbi4uWFsjsBHGBnkV1OgaZb6deSXl1MXtdu3d0OfpVAW6y20KpC1vcW8nzEj5SPWuj0XQ4vENzepJIpWJBJ8v3SfeuWpUcnccY3djrPDk2mS+HZJxJslkYlQP4jmuz021a20fMDtZLOhwTwCPrXD+GNITT9KP9oBLe1Us6EdSfaqGreLpLjQWMEksO1/LFuxz8vrXVRxLwcJxi9ZLa2339Tu5vZx8ywniTTbHVkuLu3bVLeJ/9IgST5mXuA3Y10/iHx1HcaVZXuhRRWdgyj5FwZD7H6V5PJbC0hY2gZ5JuWz933rE07ULzT5LqAgm2fkxZxt9CPrTVSc6fs56LfY5XVm7pnZeIPFen3yLAZQxUh5Ni7gh9j25rlNZvtVt7ZTbdHIAU4zs9T7VkaJdiP7RCzfPNIX8gLkgfWraalbX17PFdF1lUDynTOFq4xUZXuYNt6s1X1R/FCRyzXyzTWaCFRGTgcdSOvtTtUml1Cy8t2+zrHy5yc5Hb/wCvWM4fwxrdlqcjKkJOyVVH3ge5FagMt/rDTXBjW3mG1Yn4z6EUTpqMuZ9Qvcx73U7oHTzbxsbm3Ytb/J+8cj+7ngj2rqdRsZ9Q0+GRnV2C/LbfxK5HcfSszXNEuhe2+bhVggPnoI8Hp2B96ytFvL1559VSAZS4/eOWO4r0ZQOhpuKqRUXug20ZrafFbw3f2WGfyprKJnTABDE9ua7XwZby6Ldw6urNJCkam8jDDE4zg9e4zmqml+DF8WXzSwyhpGUTMqLzsOMc9h7V6R4c8JpbeH557m5dILUFXgcDLv8Aw8dhXnTdWbUYq9jop023c1vGt3b3P2KfTpHEUI80BEAEp25K47Y46da8f8T6re6rPaR6ne3SvKWaS2V9qxIOi+5NdzZeLb61nSw06zglnWEqXnGVi5ySP0Ga43W213UpYJ55tOtZpBxmLoTwT19Oa9rMJ048tDDy5VFarW3N1+7+tTory+yc4J4o9NFvaaast45aNpZGLEKT97PqMV6L4LuLCOR7R7ERmSEJvjBIAPr7Hj8a80nl1nT9cnjhaC4ghG5wsYUMB1rU0HxPf63Jf+TdjSbhH2iKMBjtXoxJGeteMqNSTUozs1qcsGou474s2MmlE+GUtw4nuBcSO5A8yMYKqD154/Kpbma21vQBJZ3K2t9bgQ/Zf7qjt7V0sngzUPFvhsahc+dNq0CkMXIy2OdwGOoHavOfE12y31x4dggaO9lC+ZcW45d8jIHccda9ivNYy1eHw9eln1+/dG9RX98reJ/ElncNZW8CQvq1pmSJACx5GCCQefoK5Hw1nxPqF3pWv2ssepy8+aW2/u85UYPYV2/xG0ez8JT+G9Wsbby3tmSN/LH3gQO/XOawPidbLBqFp4g0/wAz7fKyKDjKque/8q3oyhGMYQe+z9Dld29TtbeDUNM0t9ItpkuJvKIjPcA9Dx71h+MviL4i0LQ9Ptp7KETPmGVEkPnAAYLccjNa1pPBNpUF/HJJHchB9pUEI2fqePbHavLvDPxBuB8QZV1GaaaK5dhIblVkJIJACt9MciowtOM3KaXuxf8AWg78q0PTvC3iB9QRtO02E6ZZfKxkdMu5Iy3J/nXX+J/BOh6p4dmhur0oqoHhVX3EydiRXmvjbxJcaC2kiGMrbTyHzHQZOz0rq9N1ObUry4X7NJa2rRjypFALE46msqz9natCTS7F0520Mv4dWGpeENeXT9QnaLTphmMuf3bD2NR3X2fwb4m1G/0qGW/geUbHhGVVj1BNd1q/iS2u/Bg0ZrSC+1SZdkAA+ZPc46V5VYXWo+BNSvLTUoGs7V4/MEUhyNw7jPWsIxhU9+pu91/Xc2dklylm7mPiDxXA0jP9q2l7womxVH8K5oqXQZTpenXGuX94siXh3tEBlwo6CisaqnUm/ZLRaEavdmtb6jaa7CmmW8G24T5Fb196tahGnhlGt2iE1ztzgetM0TSZEu4LjT498zP82f4a2PEFlPcxzzLFtmUhckZJ9a4vaxjLVakxg3salhAms2cF+1iEtEiAnz0ZqXQrWJ7ycQIkKshxD03Yp2lTJo3hTyPO8yQkM9vnv6muZ13xIEiEtlNsmTkeo9a6ZOPtVOO9vxZu5Kn6j9b8W2ceoRWV5FIoQ4kdT8q066EE7tNY3kU0aLnym7isO5uv+Eh0tljijaaU4dxyQa5nwlazAXltPDKsiyY84Z6Dtis9JQlKe679Tmk3zG5rks6XKNauY4Ww3qBWfeahbLZM5ilW7VhibGd2O30roNDRpbi4NyoS0hUBUIyWqfUYLM6el9BEq7TgQv39auFSUI6bdieW+pmatcW2n2ov7cj7TcKCCVAIGKiuC9pp0U22K8knUKCg2sp71W1a0u7q4tZ4LcNaxgNIh6fSr0fh24vLeO/EuyHJACnoPaqT59kJpoybuJ9Vjd7eZWlQBHjmXlfwq5canYXlpFaInkvHhBLPwpYDn5u1Z097DpuuXM0conRIxEeecnrmrcV5E4nt2WN7Zl3kk5IyK2ire70Jegf2s/hqOC1uCS1xJjJ5UKe4NbZvLWS1n0uySOaR3xHP/Cn4iuRgmuf7Nazu4VezjJZZerYJ4x9BXc+HNGOgyWZ8kXlvIRmVV+VFPc+vWqnP2UXyvTuC1Z0nw7km8JXMGnyW0smpJgJtORIucEqe/HbtivVvFkVxGyw2iKi3jpPKJAcs3C7fp3Fc1pehxwTG+LsZYyGgl5ypHQA1Y8Rarda6q6wZbj/R4x+5iPyjsBxXVlrpqc8TN6Q1a79n6np0Fyq76EuteFJvDlveXMcao0kCptP3lJPUHt1FeWX2rAeGm8+AFoJGByMk9QD71v68Fv4zbJqDyytCJDG8rHnPQAnj0rkdThuZQtrZ7fssi5f7S52o3TCjvXm1FDEVW4N23ZyzldlLS7uXTpo2+2xrBqChZZGwdqfXtznNXYPDFp4c8X2c6aibldSLKzrgKzDnOOoBrMjubGx01YbtrdXtn2i3QbWmb8f8aW88Y2VzbWkn9jyTOsuDO5+4eg6e34VTpVGnGys79fuX3mSslqeueCtbuTr72gldbeLKKUPzMzfXjb9a4jxfoc3hv4pR3LoSsYzCVXPmOR90+9Mh1LUNUmk/sfUo4YlAWR0TDMe4Hp6ZrrG0dNe0tdYhnluNRsnDAytvHy8kfhW1CKhzUpy0lbbZSXf8tDpi1JcpivdReJtCng1uzit7mOR5NrgBVA6EfSvOdOux4sF9osMMUnkOCJJc7WweCMeldDp/iPU9e8QzXVzpayyJKRtU/u40P+z6+9ad9plnaancNaYjurwGQRqMfOOgPfAq1anLkT5prbokYSV2ea6MYm+Id5ZX0MwFigaKMPuhkYj7zD8a3b7wbpmneG7vU7lEu7u0dpFEbBcE8gj29RWFpXikeEPFerWWuW8P265cMLtAf3gPQKD0AHatfxUbaxht9PhZo4b1jJLK3zAL16V6tSpyNe7/AF1sZ9Sj4Yik1aLS7q+aW53IXmXIKLzwAK7DxJrw0rQ5b6wgRJQwSOISYyfYHqaq+HfCsmjadDd2V7G6FixhdCvGMn6V5lr3io6t4hvWlsy3lENbmOQ7EweW9zXJG9ebafu9ircqueqeD79rPQLm4SKNNQJMsl1dDa6+1Xtd06w8b6Kq3E5uLh1AjvGyQG9BWTLNpuq+HZLm8Z4YZolDnd8zn2rX0kR6N4ctJYrY+UGAhR2+dj2NcMmvjp6NX+ZrGT6nCaxfG3tP7Ba3QXe5Y2KgjcoPbPrRXZeNPBmqeLXi1YQJbahbKG2IQAyjnn3oqo8zivZfP1KlFt3ia/gLSLiK7kjkWRCpLZPAzXQXmpW2li4ikJkn6h8ZUe1SXWrC2lmXcgdlymOCa811jxVe20k0d3GBA78tjoK82L5LKFrvd9zaclTjaJZvtfTUdaaS4j+zx7cZj6H61zMk0sWo+bHB5ySZGD2rVjvdPm8maNg8AbDjPIqhJeef4h8u3VhbdF47VdOMlLme5wyd0U7LXD4cuxJHGUlDElQMgj0qxoGty3d7PNcOYTK2VRR1pNdtLi1kaeECSFfvBh1FZmh3UthrbXxtfMs5Fwm/oprrtzR97oStjvreOW1mjEqcSkmNs/ePvVG0voJ9VntrlAiKCTuPB+lTzfaLq3S7KEGMZUHpiseSyF7tuXkSIzAgI5wfrXFSTUrtGm6LkuowS6glnYXBeGdfnTqFxVDxBY3loyW9vdukEeScn5MH0rIhhayMMdsssStIUe7x2zzita9mF6o06Ul54GDrcA43r2yK6nSf8SBDae5Q0DQZdQuJY45VCMNz7o8l/wAabcaFaxWHmG7ER3FXjH3iQe1a2n6nqN7I1taW/wC9ztjmAwAPerv/AAh9yiNBLG01zgvu28P64+lYyqSXvMEuYl0/Sv7Vt9Ps4oREu3Bc/wAY9a7fQtHudGu7a2DrJZSSC3SOdv8AVE85HtWD4d0XU9N1PSbaSNgZNzq2eiY5rXGrRpqSNfvhVk+WXH3QD2HelSfNNOXw31b2/rsjopw6vQ9n8SCz0nTYbOKNPOkQLIkbZGMfe+tcB4oku9A8PW6QvIi3Hzywgc7MgD+Wa2buSCLQ4NSjlNzGxIVt3r6iuR8Z3sb3lna/aLidioHGMdM4BPavocTLCUsvaw8/ek99vkdtSSUNCpaTacurF4JEC+USDIo3H6iuE1UfaNanitw1wtuWkZYzkRk+nPWtPRZ1ttUuhNazC5yWBxuAHb8K57R7S+sNavp3+5cv+8VepJOfwr5uMXyyb2POlrsY/jrTUfRraC1kaW81SfckZHz4X37Yrp9MtNR0XSrTTJYIpC4VpHk5K/hWB4tsg3irQWnt5I1DZdk6IvQV1izxeGrme71C7EtvGN8XmfMWXsAO/Fd0qi9lCNPVsi12WLDTJtO1K7hmWKDT7mHLqrbXBHceleg/D2/0fRo1tp7gT2hHzKrbigI6HFeDajqGt+MNZgvktRa6NE+7eRtUp6k16JaW1xPYxyWaR2kG4M0luArcdvpWNWkowUqsr27bXNIys7xRc1iTTvCGt6sdOzM+oSBbXC/dz1yPSsjWPCcWh3VtqlxdSi52FndnwN3oc9q79vDtrq+hS6g8mZLRBKCr5Py9efWvJdGv77x1rGpzatibTlOyFJMYB7f/AK660o4mP1hLlT3XW/8AX3GtTZMpeItMtvFtgLoxlpI7gTecVyNo7Z9MUt0+lahYw6lJG7Q2nHmMMbx6D2pPEa3EmpW2kRQyRaSvEpHy+Z7fSofFkbTWlhoNpEQZ2XeYx/q1966pVY1JRjbVL7kcuu5d8Y+ILrT/AAhJcWsBMbqACx5CsPWqOg6Pp8/hOTWLiBYyYzttwM7vqa0/Eui2dj4LmsLm5aKJY/kY9Sw6Vi+C/Dt1r/hi50v7XtVUykinJHtWVNxcbrTUp30RFqngO9i8IJqUF6zhMOLYNuXHoK7a01f+1vBNs9oVku4VUlWGAMdapfDjWF0i1uNH1hdj2oP+s4Dj1Gap+FJP+Em8RXFlbKtlpMZJKjgvz/KuKpKVS6T+F7+TLSS1Oz03xbpzIq3WZJZo9jQQtls4orjb9LbQPiFAbSB0twApkI4J+tFYRqrDK199dbmsZPodLqWVkF1kmSJcgHpVxLG18Tac01zbqCVwQKKK56OsdSI9TzoeH7e1v2SMsIw2dg6VNd3zabfxSwooOMEH0ooqoycpq7MmvdMrW9SudRD5lMa5xtUcVY8Rq+m6HpUUch2H5iMd6KK64fFFErZnUQay+raFGrRiN1AXep6is2y0SK+0bUr2V2aWF9sYPRQKKK7IRTlK66Mta7lLTLzyNRiRkEkQXIjJwM+tVNcjMFxdXETFGfauPQUUVnSbtJGXQ7rwrEmoaDuiX7LcxkM068l8dvau5W3W6m067cneCVKrwCMdKKK4fixUYPZnXSV0jifEd7L/AGp5kbtHs+VQG+6PaqniRWGr6bG8jSFsNuPHNFFViIqnzUoaRWyFWfvW6HpumltQ8IXkTHYIsEFR1rkvE+otqOsy2UUcdqljAG3KNxkJ4/CiitqVOE8DT5l9p/kjSb9xHHax4gvtNvYLaGVVluE2+ft5QD0FZZt3s9Cnd55J5xIZRMx+fdn1ooq6fuxaj/WpwybuW7vXJ9S16z01wEt47YSMV+85I7k1z/xVt47pkmiDQPY7S3zbvOz6+lFFd9PSovRFXbvcvWV/N4phFnu+xWlvGsrQxciQ+nsK7fXdVlm8JqYP9GkchWkBySOlFFeTXk41IxWw47HReGQNR8Ox2DZjDRhWkQ4LA9cjvXlVlbvp3jf+yo5SbWGQyEY+/joDRRU4aUp0J8zvbb8Tol8B1Vzr0t940t7No0EaAue+TXIeJJbrSfGlz5F0wSaZGK46ew9qKK66cnyb9DCR1+vyR69paaVcQJm4XLXH8Q47VxngnTpPCF1cx291JLGGPytwDRRWqX+zW9CutzZEUPj6+vhdxm3+zqFBibk/Ws3TdJPhe8kMNw8qMjEK3BGPeiiuWrJxqRpr4Wti1qdj8NtY/wCEq0eWG+t0kMch2uetFFFeLjJyjXlFPRGkdUf/2Q=="; + } + + async function setup() { + await PowerPoint.run(async (context) => { + // Adds a new slide with some content. + const slideCountResult = context.presentation.slides.getCount(); + context.presentation.slides.add(); + await context.sync(); + + const newSlide = context.presentation.slides.getItemAt(slideCountResult.value); + newSlide.load("id"); + newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon); + await context.sync(); + + console.log(`Added slide - ID: ${newSlide.id}`); + + // Switch to the new slide. + context.presentation.setSelectedSlides([newSlide.id]); + 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 binding references for images.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Insert image with binding

      +

      Try adding a few images. Enter an ID, then select the button. A binding with that ID will be created which refers + to the shape.

      +

      Binding ID: + +

      + +

      Show the bindings in the document

      +

      The console will show the bindings in the document.

      + +

      Update an image using its binding

      +

      Select a binding ID from the dropdown list then pick a replacement picture.

      +

      Choose the binding for the image you want to update:

      + +

      +

      Select the replacement image:

      + + + +

      +

      After adding a few images, try z-Order APIs

      +

      Click on or select the image you want to act on.

      + + + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + 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 diff --git a/samples/powerpoint/shapes/get-set-shapes.yaml b/samples/powerpoint/shapes/get-set-shapes.yaml new file mode 100644 index 000000000..789c72620 --- /dev/null +++ b/samples/powerpoint/shapes/get-set-shapes.yaml @@ -0,0 +1,227 @@ +order: 2 +id: powerpoint-shapes-get-set-shapes +name: Get, set, load, and save shapes +description: Get and set one or more selected shapes. Load and save one or more shapes. +host: POWERPOINT +api_set: + PowerPointApi: '1.5' +script: + content: | + document.getElementById("getSelectedShapes").addEventListener("click", () => tryCatch(getSelectedShapes)); + document.getElementById("setSelectedShapes").addEventListener("click", () => tryCatch(setSelectedShapes)); + document.getElementById("changeFill").addEventListener("click", () => tryCatch(changeFill)); + document.getElementById("saveShapeSelection").addEventListener("click", () => tryCatch(saveShapeSelection)); + document.getElementById("loadShapeSelection").addEventListener("click", () => tryCatch(loadShapeSelection)); + document.getElementById("createShapes").addEventListener("click", () => tryCatch(createShapes)); + document.getElementById("arrangeSelected").addEventListener("click", () => tryCatch(arrangeSelected)); + + async function getSelectedShapes() { + // Gets the shapes you selected on the slide and displays their IDs on the task pane. + await PowerPoint.run(async (context) => { + let finalTable = ""; + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + finalTable += "
      getSelectedShapes.getCount returned:" + shapeCount.value + "
      "; + finalTable += + "
      "; + shapes.load("items"); + await context.sync(); + shapes.items.map((shape, index) => { + finalTable += ""; + }); + finalTable += "
      IndexId
      " + index + "" + shape.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); + } + + async function setSelectedShapes() { + // Selects the first two shapes on slide 1. + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slide1 = context.presentation.slides.getItemAt(0); + slide1.load("shapes/items/type"); + await context.sync(); + + const shapes = slide1.shapes.items.filter((item) => item.type === PowerPoint.ShapeType.geometricShape); + const shape1: PowerPoint.Shape = shapes[0]; + const shape2: PowerPoint.Shape = shapes[1]; + shape1.load("id"); + shape2.load("id"); + await context.sync(); + + console.log(`IDs: ${shape1.id}, ${shape2.id}`); + slide1.setSelectedShapes([shape1.id, shape2.id]); + await context.sync(); + }); + } + + async function changeFill() { + // Changes the selected shapes fill color to red. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); + } + + let savedSlideSelection = []; + let savedShapeSelection = []; + async function saveShapeSelection() { + // Saves which shapes are selected so that they can be reselected later. + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + savedSlideSelection = []; + slides.items.map((slide) => { + savedSlideSelection.push(slide.id); + }); + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + shapes.items.map((shape) => { + savedShapeSelection.push(shape.id); + }); + }); + } + + async function loadShapeSelection() { + // Reselects shapes that were saved previously. + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedSlideSelection[0]); + await context.sync(); + slide1.setSelectedShapes(savedShapeSelection); + await context.sync(); + }); + } + + const slideWidth = 960; + const slideHeight = 540; + function getRandomBetween(a, b) { + return Math.random() * (b - a) + a; + } + + function generateRandomHexColor() { + return `#${Math.random().toString(16).substring(2, 8)}`; + } + + async function createShapes() { + // Creates random shapes on the selected slide. + await PowerPoint.run(async (context) => { + let finalTable = ""; + const currentSlide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + const maxNewShapeWidth = 200; + const maxNewShapeHeight = 200; + const minNewShapeWidth = 50; + const minNewShapeHeight = 50; + for (let i = 0; i < 20; i++) { + const rectangle: PowerPoint.Shape = currentSlide.shapes.addGeometricShape( + PowerPoint.GeometricShapeType.rectangle, + ); + rectangle.height = getRandomBetween(minNewShapeWidth, maxNewShapeWidth); + rectangle.width = getRandomBetween(minNewShapeHeight, maxNewShapeHeight); + rectangle.left = getRandomBetween(0, slideWidth - rectangle.width); + rectangle.top = getRandomBetween(0, slideHeight - rectangle.height); + rectangle.fill.foregroundColor = generateRandomHexColor(); + } + finalTable += "Done
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); + } + + let currentLeft = 0; + let currentTop = 0; + async function arrangeSelected() { + // Arranges the selected shapes in a line from left to right. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 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 get selected shapes, and how to select and change specific shapes.

      +
      +
      +

      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; + } + .content { + padding: 0 18px; + /* display: none; */ + overflow: hidden; + background-color: #f1f1f1; + max-height: 0; + transition: max-height 0.2s ease-out; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/shapes/get-shapes-by-type.yaml b/samples/powerpoint/shapes/get-shapes-by-type.yaml new file mode 100644 index 000000000..7eba070e1 --- /dev/null +++ b/samples/powerpoint/shapes/get-shapes-by-type.yaml @@ -0,0 +1,141 @@ +order: 3 +id: powerpoint-shapes-get-shapes-by-type +name: Select shapes by type +description: Gets shapes in a slide based on their type, such as GeometricShape or Line. +host: POWERPOINT +api_set: + PowerPointApi: '1.4' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("change-lines").addEventListener("click", () => tryCatch(changeLines)); + document.getElementById("change-geometric-shapes").addEventListener("click", () => tryCatch(changeGeometricShapes)); + + async function changeLines() { + // Changes the dash style of every line in the slide. + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); + } + + async function changeGeometricShapes() { + // Changes the transparency of every geometric shape in the slide. + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); + } + + async function setup() { + await PowerPoint.run(async (context) => { + // Create shapes of different types. + const shapes = context.presentation.slides.getItemAt(0).shapes; + + // Create geometric shapes. + shapes.addGeometricShape(PowerPoint.GeometricShapeType.diamond, { + left: 100, + top: 100, + height: 150, + width: 150 + }); + shapes.addGeometricShape(PowerPoint.GeometricShapeType.octagon, { + left: 400, + top: 300, + height: 150, + width: 150 + }); + + // Create lines. + shapes.addLine(PowerPoint.ConnectorType.elbow, { + left: 400, + top: 150, + height: 20, + width: 150 + }); + shapes.addLine(PowerPoint.ConnectorType.curve, { + left: 100, + top: 300, + height: 150, + width: 20 + }); + + 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 select and change shapes based on their types.

      +
      +
      +

      Setup

      +

      Create some shapes in a new, blank presentation.

      +

      + +

      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/shapes/group-ungroup-shapes.yaml b/samples/powerpoint/shapes/group-ungroup-shapes.yaml new file mode 100644 index 000000000..4021254cc --- /dev/null +++ b/samples/powerpoint/shapes/group-ungroup-shapes.yaml @@ -0,0 +1,193 @@ +order: 6 +id: powerpoint-shapes-group-ungroup-shapes +name: Group and ungroup shapes +description: Shows how to create two shapes then group and ungroup them. +author: aafvstam +host: POWERPOINT +api_set: + PowerPointApi: '1.8' +script: + content: | + document.getElementById("group-shapes").addEventListener("click", () => tryCatch(groupShapes)); + document.getElementById("move-group").addEventListener("click", () => tryCatch(moveGroup)); + document.getElementById("ungroup-shapes").addEventListener("click", () => tryCatch(ungroupShapes)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function groupShapes() { + await PowerPoint.run(async (context) => { + // Groups the geometric shapes on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapesToGroup = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.geometricShape); + if (shapesToGroup.length === 0) { + console.warn("No shapes on the current slide, so nothing to group."); + return; + } + + // Group the geometric shapes. + console.log(`Number of shapes to group: ${shapesToGroup.length}`); + const group = shapes.addGroup(shapesToGroup); + group.load("id"); + await context.sync(); + + console.log(`Grouped shapes. Group ID: ${group.id}`); + }); + } + + async function moveGroup() { + await PowerPoint.run(async (context) => { + // Move the first shape group to the top-left of the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapeGroups = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.group); + if (shapeGroups.length === 0) { + console.warn("No shape groups on the current slide, so nothing to move."); + return; + } + + // Move the first grouped shapes. + const firstGroupId = shapeGroups[0].id; + const shapeGroupToMove = shapes.getItem(firstGroupId); + shapeGroupToMove.top = 0; + shapeGroupToMove.left = 0; + await context.sync(); + + console.log(`Moved shape group with group ID: ${firstGroupId}`); + }); + } + + async function ungroupShapes() { + await PowerPoint.run(async (context) => { + // Ungroups the first shape group on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapeGroups = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.group); + if (shapeGroups.length === 0) { + console.warn("No shape groups on the current slide, so nothing to ungroup."); + return; + } + + // Ungroup the first grouped shapes. + const firstGroupId = shapeGroups[0].id; + const shapeGroupToUngroup = shapes.getItem(firstGroupId); + shapeGroupToUngroup.group.ungroup(); + await context.sync(); + + console.log(`Ungrouped shapes with group ID: ${firstGroupId}`); + }); + } + + async function setup() { + await PowerPoint.run(async (context) => { + // Adds a new slide with two shapes. + const slideCountResult = context.presentation.slides.getCount(); + context.presentation.slides.add(); + await context.sync(); + + const newSlide = context.presentation.slides.getItemAt(slideCountResult.value); + newSlide.load("id"); + + // Create two shapes. + const shape1 = newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle); + shape1.left = 100; + shape1.top = 100; + shape1.width = 150; + shape1.height = 100; + shape1.fill.foregroundColor = "darkred"; + + const shape2 = newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.ellipse); + shape2.left = 300; + shape2.top = 100; + shape2.width = 150; + shape2.height = 100; + shape2.fill.foregroundColor = "darkblue"; + + await context.sync(); + + console.log(`Added slide - ID: ${newSlide.id}`); + + // Switch to the new slide. + context.presentation.setSelectedSlides([newSlide.id]); + 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: |- +
      +

      Shows how to group then ungroup shapes.

      +

      Code sample based on community contribution from Maarten van Stam.

      +
      +
      +

      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; + } + .content { + padding: 0 18px; + /* display: none; */ + overflow: hidden; + background-color: #f1f1f1; + max-height: 0; + transition: max-height 0.2s ease-out; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/shapes/shapes.yaml b/samples/powerpoint/shapes/shapes.yaml new file mode 100644 index 000000000..d830e9898 --- /dev/null +++ b/samples/powerpoint/shapes/shapes.yaml @@ -0,0 +1,216 @@ +order: 1 +id: powerpoint-shapes +name: Insert shape, line, and text box +description: Inserts geometric shapes, lines, and text boxes to a slide. +host: POWERPOINT +api_set: + PowerPointApi: '1.4' +script: + content: | + document.getElementById("create-hexagon").addEventListener("click", () => tryCatch(createHexagon)); + document.getElementById("shrink-hexagon").addEventListener("click", () => tryCatch(shrinkHexagon)); + document.getElementById("move-hexagon").addEventListener("click", () => tryCatch(moveHexagon)); + document.getElementById("create-line").addEventListener("click", () => tryCatch(createLine)); + document.getElementById("create-text-box").addEventListener("click", () => tryCatch(createTextBox)); + document.getElementById("create-shape-with-text").addEventListener("click", () => tryCatch(createShapeWithText)); + document.getElementById("remove-all").addEventListener("click", () => tryCatch(removeAll)); + + async function createHexagon() { + // This function gets the collection of shapes on the first slide, + // and adds a hexagon shape to the collection, while specifying its + // location and size. Then it names the shape. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const shapeOptions: PowerPoint.ShapeAddOptions = { + left: 100, + top: 100, + height: 150, + width: 150, + }; + const hexagon: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon, shapeOptions); + hexagon.name = "Hexagon"; + + await context.sync(); + }); + } + + async function shrinkHexagon() { + // This function gets the collection of shapes on the first slide, + // gets the first shape in the collection, and resets its size. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const hexagon: PowerPoint.Shape = shapes.getItemAt(0); + hexagon.height = 50; + hexagon.width = 50; + + await context.sync(); + }); + } + + async function moveHexagon() { + // This function gets the collection of shapes on the first slide, + // gets the first shape in the collection, and resets its location. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const hexagon: PowerPoint.Shape = shapes.getItemAt(0); + hexagon.top = 50; + hexagon.left = 150; + + await context.sync(); + }); + } + + async function createLine() { + // This function gets the collection of shapes on the first slide, + // and adds a line to the collection, while specifying its + // start and end points. Then it names the shape. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + + // For a line, left and top are the coordinates of the start point, + // while height and width are the coordinates of the end point. + const line: PowerPoint.Shape = shapes.addLine(PowerPoint.ConnectorType.straight, { + left: 400, + top: 200, + height: 20, + width: 150, + }); + line.name = "StraightLine"; + + await context.sync(); + }); + } + + async function createTextBox() { + // This function gets the collection of shapes on the first slide, + // and adds a text box to the collection, while specifying its text, + // location, and size. Then it names the text box. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const textbox: PowerPoint.Shape = shapes.addTextBox("Hello!", { + left: 100, + top: 300, + height: 300, + width: 450, + }); + textbox.name = "Textbox"; + + return context.sync(); + }); + } + + async function createShapeWithText() { + // This function gets the collection of shapes on the first slide, + // and adds a brace pair, {}, to the collection, while specifying its + // location and size. Then it names the shape, sets its text and font + // color, and centers it inside the braces. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); + } + + async function removeAll() { + // This function gets the collection of shapes on the first slide, + // and then iterates through them, deleting each one. + await PowerPoint.run(async (context) => { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + const shapes: PowerPoint.ShapeCollection = slide.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, resize, move, and delete shapes.

      +
      +
      +

      Try it out

      +

      Begin by deleting all shapes that are currently on the slide.

      +

      + + +

      +

      Create, shrink, and move a shape.

      +

      + +

      + +

      + +

      + +

      Create other shapes.

      +

      + +

      + +

      + +

      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/slide-management/add-slides.yaml b/samples/powerpoint/slide-management/add-slides.yaml new file mode 100644 index 000000000..e7e5e89cb --- /dev/null +++ b/samples/powerpoint/slide-management/add-slides.yaml @@ -0,0 +1,104 @@ +order: 1 +id: powerpoint-add-slides +name: Add slides to a presentation +description: Adds a slide and optionally specifies the slide master and layout. +host: POWERPOINT +api_set: + PowerPointApi: '1.3' +script: + content: |- + document.getElementById("slide-masters").addEventListener("click", () => tryCatch(logSlideMasters)); + document.getElementById("add-slide").addEventListener("click", () => tryCatch(addSlide)); + + async function addSlide() { + const chosenMaster = (document.getElementById("master-id") as HTMLInputElement).value; + const chosenLayout = (document.getElementById("layout-id") as HTMLInputElement).value; + + await PowerPoint.run(async function(context) { + // Create a new slide using an existing master slide and layout. + const newSlideOptions: PowerPoint.AddSlideOptions = { + slideMasterId: chosenMaster, /* An ID from `Presentation.slideMasters`. */ + layoutId: chosenLayout /* An ID from `SlideMaster.layouts`. */ + }; + context.presentation.slides.add(newSlideOptions); + await context.sync(); + }); + } + + async function logSlideMasters() { + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); + } + + /** 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 slide and optionally to specify the slide master and layout of the slide.

      +
      +
      +

      Try it out

      +

      On the Home ribbon, open the New Slide drop down menu to see the slide masters and slide layouts in the presentation. Be sure there are at least two slide masters. To add a master, see Use + multiple slide masters in one presentation. The page will open in your browser.

      +

      Press Add slide to add a slide with the default layout of the default slide master to the end of the presentation.

      + +

      Press Log slide masters info to log to the console a list of all the slide masters, their child layouts, and the IDs of the masters and the layouts.

      + +

      Copy one of the slide master IDs from the console and enter it in the Master ID text box. (Example: 6147483651#7142061614)

      +

      +

      Copy one of the layout IDs from the console, under the same master you choose above, and enter it in the Layout ID text box. (Example: 2147483651#3142061614)

      +

      +

      Press Add slide again to add a slide with the corresponding master and layout.

      + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/slide-management/export-import-slide.yaml b/samples/powerpoint/slide-management/export-import-slide.yaml new file mode 100644 index 000000000..391895002 --- /dev/null +++ b/samples/powerpoint/slide-management/export-import-slide.yaml @@ -0,0 +1,306 @@ +order: 5 +id: powerpoint-slide-management-export-import-slide +name: Export and import slide +description: Shows how to export and import a slide. +host: POWERPOINT +api_set: + PowerPointApi: '1.8' +script: + content: | + document.getElementById("export-slide-button").addEventListener("click", () => tryCatch(exportSlide)); + document.getElementById("clear-exported-slide-button").addEventListener("click", () => tryCatch(clearExportedSlide)); + document.getElementById("import-slide-button").addEventListener("click", () => tryCatch(importSlide)); + document.getElementById("slide-image-button").addEventListener("click", () => tryCatch(addSlideImageToNewSlide)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function exportSlide() { + // Exports current slide. + await PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const slideBase64DataResult = slide.exportAsBase64(); + const imageBase64DataResult = slide.getImageAsBase64({ height: 300 }); + await context.sync(); + + localStorage.setItem("exportedSlide", slideBase64DataResult.value); + localStorage.setItem("exportedSlideImage", imageBase64DataResult.value); + + updateSlideImage(imageBase64DataResult.value); + + console.log("Slide was exported."); + }); + } + + function clearExportedSlide() { + // Clears exported slide. + localStorage.removeItem("exportedSlide"); + localStorage.removeItem("exportedSlideImage"); + updateSlideImage(""); + console.log("Exported slide was cleared."); + } + + async function importSlide() { + // Imports the slide that was most recently exported. + const slideBase64Data = localStorage.getItem("exportedSlide"); + if (slideBase64Data === null) { + console.warn("Unable to import. You must first export a slide."); + return; + } + + await PowerPoint.run(async (context) => { + const currentSlide = context.presentation.getSelectedSlides().getItemAt(0); + currentSlide.load("id"); + await context.sync(); + + context.presentation.insertSlidesFromBase64(slideBase64Data, { targetSlideId: currentSlide.id }); + }); + } + + async function getSlideImage(options?: PowerPoint.SlideGetImageOptions): Promise { + // Gets slide image. + return PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const imageBase64Result = slide.getImageAsBase64(options); + await context.sync(); + + return imageBase64Result.value; + }); + } + + async function getImageDimensions(base64Data: string): Promise<{ width: number; height: number }> { + // Gets image dimensions. + return new Promise((resolve, reject) => { + const image = new Image(); + image.onerror = () => { + reject(); + }; + image.onload = () => { + resolve({ width: image.width, height: image.height }); + }; + image.src = `data:image/png;base64,${base64Data}`; + }); + } + + async function addSlideWithImage(imageBase64): Promise { + // Adds a new slide including an image. + return PowerPoint.run(async (context) => { + const presentation = context.presentation; + const currentSlide = presentation.getSelectedSlides().getItemAt(0); + const slideCountResult = context.presentation.slides.getCount(); + + currentSlide.layout.load(); + await context.sync(); + + const slideCount = slideCountResult.value; + + console.log(`Adding slide using layout ${currentSlide.layout.id}`); + + // Add a new slide at the end of the presentation. + context.presentation.slides.add({ layoutId: currentSlide.layout.id }); + try { + await context.sync(); + } catch (err) { + console.error(`Unable to add slide (with layout from current slide). ${err}`); + + // Try adding without specifying the layout. + context.presentation.slides.add(); + + try { + await context.sync(); + } catch (err) { + console.error(`Unable to add slide. ${err}`); + throw err; + } + } + + console.log("Slide added"); + + // Get added slide. + const slide = context.presentation.slides.getItemAt(slideCount); + + slide.load(["id"]); + + await context.sync(); + + console.log(`Added slide id: ${slide.id}`); + + // Switch to the new slide. + context.presentation.setSelectedSlides([slide.id]); + try { + await context.sync(); + } catch (err) { + console.error(`Unable to switch to the new slide. ${err}`); + throw err; + } + + console.log("Switched to the added slide."); + + const activeSlide = context.presentation.getSelectedSlides().getItemAt(0); + activeSlide.load(["id"]); + await context.sync(); + + console.log(`Active slide id: ${activeSlide.id}`); + + const imageDimensions = await getImageDimensions(imageBase64); + const shapeAddOptions = { + height: imageDimensions.height, + width: imageDimensions.width + }; + + let shape; + + shape = await addImageToCurrentSlide(imageBase64); + shape.load(["id"]); + await context.sync(); + + // Select the added image. + activeSlide.setSelectedShapes([shape.id]); + await context.sync(); + }); + } + + async function addImageToCurrentSlide( + imageBase64: string, + options?: PowerPoint.ShapeAddOptions + ): Promise { + // Adds an image to the current slide. + const setSelectedDataOptions: Office.SetSelectedDataOptions = { + coercionType: Office.CoercionType.Image + }; + if (options) { + if (options.height) { + setSelectedDataOptions.imageHeight = options.height; + } + if (options.left) { + setSelectedDataOptions.imageLeft = options.left; + } + if (options.top) { + setSelectedDataOptions.imageTop = options.top; + } + if (options.width) { + setSelectedDataOptions.imageWidth = options.width; + } + } + + return new Promise((resolve, reject) => { + Office.context.document.setSelectedDataAsync( + imageBase64, + setSelectedDataOptions, + async (result: Office.AsyncResult) => { + if (result.error) { + console.error(`ERROR in setSelectedDataAsync(): ${result.error}`); + reject(result.error); + } else { + const shape = await PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.shapes.load(); + await context.sync(); + + return slide.shapes.items[slide.shapes.items.length - 1]; + }); + resolve(shape); + } + } + ); + }); + } + + async function addSlideImageToNewSlide() { + // Adds an image of current slide to the new slide. + const imageBase64 = await getSlideImage({ height: 500 }); + + await addSlideWithImage(imageBase64); + } + + function updateSlideImage(imageBase64: string) { + const slideImageElement = document.getElementById("slide-image") as HTMLImageElement; + slideImageElement.src = imageBase64 ? `data:image/png;base64,${imageBase64}` : ""; + } + + async function setup() { + await PowerPoint.run(async (context) => { + // Adds a new slide with some content. + const slideCountResult = context.presentation.slides.getCount(); + context.presentation.slides.add(); + await context.sync(); + + const newSlide = context.presentation.slides.getItemAt(slideCountResult.value); + newSlide.load("id"); + newSlide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon); + await context.sync(); + + console.log(`Added slide - ID: ${newSlide.id}`); + + // Switch to the new slide. + context.presentation.setSelectedSlides([newSlide.id]); + 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 demonstrates how to export and import a slide. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + + + +

      Once a slide has been exported, click the Import slide button to insert into the presentation.

      +

      To add it to a different presentation, open that presentation and select a slide. It will be inserted after the + selected slide.

      +
      +

      Click the following button to capture an image of the current slide and add it to a new slide at the end of the presentation.

      + +
      + 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; + } + + img { + border: 5px solid #555; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + 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 diff --git a/samples/powerpoint/slide-management/get-set-slides.yaml b/samples/powerpoint/slide-management/get-set-slides.yaml new file mode 100644 index 000000000..cbb58a752 --- /dev/null +++ b/samples/powerpoint/slide-management/get-set-slides.yaml @@ -0,0 +1,175 @@ +order: 4 +id: powerpoint-slide-management-get-set-slides +name: Get, set, load, and save slides +description: Get and set one or more selected slides. Load and save one or more slides. +host: POWERPOINT +api_set: + PowerPointApi: '1.5' +script: + content: |- + document.getElementById("getSelectedSlides").addEventListener("click", () => tryCatch(getSelectedSlides)); + document.getElementById("setSelectedSlides").addEventListener("click", () => tryCatch(setSelectedSlides)); + document.getElementById("deleteSlides").addEventListener("click", () => tryCatch(deleteSlides)); + document.getElementById("saveSlideSelection").addEventListener("click", () => tryCatch(saveSlideSelection)); + document.getElementById("loadSlideSelection").addEventListener("click", () => tryCatch(loadSlideSelection)); + + async function getSelectedSlides() { + // Gets the selected slides and displays their IDs on the task pane. + await PowerPoint.run(async (context) => { + let finalTable = ""; + context.presentation.load("slides"); + await context.sync(); + const allSlidesList = {}; + const allSlidesCount = context.presentation.slides.getCount(); + context.presentation.slides.load("items"); + await context.sync(); + let allSlideItems: PowerPoint.Slide[] = context.presentation.slides.items; + allSlideItems.map((slide, index) => { + allSlidesList[slide.id] = `Slide ${index + 1}`; + }); + + const checkbox = document.getElementById("id-check-usenative") as HTMLInputElement; + if (checkbox && checkbox.checked) { + context.presentation.load("tags"); + } + + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + finalTable += "
      getSelectedSlides.getCount returned:" + slideCount.value + "
      "; + finalTable += + "
      "; + slides.items.map((slide, index) => { + finalTable += ""; + }); + finalTable += "
      IndexId
      " + index + " - " + allSlidesList[slide.id] + "" + slide.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = "" + outputSpan.innerHTML += finalTable; + }); + } + async function deleteSlides() { + // Deletes the selected slides. + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + slides.items.map((slide) => { + slide.delete(); + }); + }); + } + + async function setSelectedSlides() { + // Selects slides 2, 4, and 5. + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slide2: PowerPoint.Slide = context.presentation.slides.getItemAt(1); + const slide4: PowerPoint.Slide = context.presentation.slides.getItemAt(3); + const slide5: PowerPoint.Slide = context.presentation.slides.getItemAt(4); + slide2.load("id"); + slide4.load("id"); + slide5.load("id"); + try { + await context.sync(); + } catch (error) { + console.warn("This action requires at least 5 slides in the presentation."); + return; + } + await context.sync(); + context.presentation.setSelectedSlides([slide2.id, slide4.id, slide5.id]); + await context.sync(); + }); + } + + let savedSlideSelection = []; + async function saveSlideSelection() { + // Saves which slides are currently selected so they can be reselected later. + await PowerPoint.run(async (context) => { + let finalTable = ""; + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + await context.sync(); + finalTable += "
      getSelectedSlides.getCount returned:" + slideCount.value + "
      "; + finalTable += + "
      "; + savedSlideSelection = []; + slides.load("items"); + await context.sync(); + slides.items.map((slide, index) => { + finalTable += ""; + savedSlideSelection.push(slide.id); + }); + finalTable += "
      IndexId
      " + index + "" + slide.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = "" + outputSpan.innerHTML += finalTable; + }); + } + + async function loadSlideSelection() { + // Sets selection to the slides that were saved. + await PowerPoint.run(async (context) => { + context.presentation.setSelectedSlides(savedSlideSelection); + 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 selected slides, and how to select specific slides.

      +
      +
      +

      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; + } + .content { + padding: 0 18px; + /* display: none; */ + overflow: hidden; + background-color: #f1f1f1; + max-height: 0; + transition: max-height 0.2s ease-out; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/slide-management/get-slide-metadata.yaml b/samples/powerpoint/slide-management/get-slide-metadata.yaml new file mode 100644 index 000000000..35f71e6be --- /dev/null +++ b/samples/powerpoint/slide-management/get-slide-metadata.yaml @@ -0,0 +1,52 @@ +order: 3 +id: powerpoint-basics-get-slide-metadata +name: Get slide metadata +description: Gets the title, index, and ID of the selected slides. +author: OfficeDev +host: POWERPOINT +api_set: {} +script: + content: |- + document.getElementById("get-slide-metadata").addEventListener("click", getSlideMetadata); + + function getSlideMetadata() { + Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideRange, + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(asyncResult.error.message); + } else { + console.log(JSON.stringify(asyncResult.value, null, 4)); + } + } + ); + } + language: typescript +template: + content: |- +
      +

      Demonstrates how to get slide metadata.

      +

      Select one or more slides and click Get slide metadata to get the ID, title, and index of the slide(s).

      +
      + + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/powerpoint/slide-management/insert-slides.yaml b/samples/powerpoint/slide-management/insert-slides.yaml new file mode 100644 index 000000000..9429814d2 --- /dev/null +++ b/samples/powerpoint/slide-management/insert-slides.yaml @@ -0,0 +1,116 @@ +order: 2 +id: powerpoint-insert-slides +name: Insert slides from other presentation +description: Inserts slides from another PowerPoint file into the current presentation. +host: POWERPOINT +api_set: + PowerPointApi: '1.5' +script: + content: |- + document.getElementById("insert-all-slides").addEventListener("click", () => tryCatch(insertAllSlides)); + document.getElementById("insert-after-target-slide").addEventListener("click", () => tryCatch(insertAfterSelectedSlide)); + document.getElementById("file").addEventListener("change", () => tryCatch(storeFileAsBase64)); + + let chosenFileBase64; + + async function storeFileAsBase64() { + const reader = new FileReader(); + + reader.onload = async (event) => { + // Remove the metadata before the Base64-encoded string. + const startIndex = reader.result.toString().indexOf("base64,"); + const copyBase64 = reader.result.toString().substr(startIndex + 7); + + chosenFileBase64 = copyBase64; + }; + + // Read in the file and store a Base64-encoded copy as the reader.result + // property. This also triggers the onload event. + const myFile = document.getElementById("file") as HTMLInputElement; + reader.readAsDataURL(myFile.files[0]); + } + + async function insertAllSlides() { + await PowerPoint.run(async function(context) { + context.presentation.insertSlidesFromBase64(chosenFileBase64); + await context.sync(); + }); + } + + async function insertAfterSelectedSlide() { + await PowerPoint.run(async function(context) { + // Get the ID of the first selected slide. + const presentation: PowerPoint.Presentation = context.presentation; + const selected: PowerPoint.Slide = presentation.getSelectedSlides().getItemAt(0); + selected.load("id"); + await context.sync(); + + // Insert the other presentation after the selected slide. + const insertOptions: PowerPoint.InsertSlideOptions = { + formatting: PowerPoint.InsertSlideFormatting.useDestinationTheme, + targetSlideId: selected.id + }; + presentation.insertSlidesFromBase64(chosenFileBase64, insertOptions); + 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 slides from another presentation into the current presentation.

      +
      +
      +

      Try it out

      +

      +

        +
      1. Open this add-in in a brand new presentation.
      2. +
      3. Add at least 2 slides to the presentation.
      4. +
      5. Next, select a PowerPoint presentation from which to insert slides.
      6. +
      +
      + +
      +

      +

      Press Insert all slides to insert all the slides at the beginning of the + presentation. Source formatting is used.

      + +

      Select a slide and press Insert after selected slide. Destination formatting is used.

      + +

      To undo an insertion, click anywhere on the presentation and press Ctrl+Z.

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/tags/tags.yaml b/samples/powerpoint/tags/tags.yaml new file mode 100644 index 000000000..b2816d55d --- /dev/null +++ b/samples/powerpoint/tags/tags.yaml @@ -0,0 +1,204 @@ +id: powerpoint-tags +name: Work with tags +description: Use tags to process subsets of slides. +host: POWERPOINT +api_set: + PowerPointApi: '1.3' +script: + content: |- + document.getElementById("add-selected-slide-tag").addEventListener("click", () => tryCatch(addTagToSelectedSlide)); + document.getElementById("delete-slides-by-audience").addEventListener("click", () => tryCatch(deleteSlidesByAudience)); + document.getElementById("add-slide-tags").addEventListener("click", () => tryCatch(addMultipleSlideTags)); + document.getElementById("add-shape-tag").addEventListener("click", () => tryCatch(addShapeTag)); + document.getElementById("add-presentation-tag").addEventListener("click", () => tryCatch(addPresentationTag)); + document.getElementById("delete-presentation-tag").addEventListener("click", () => tryCatch(deletePresentationTag)); + + async function addTagToSelectedSlide() { + await PowerPoint.run(async function(context) { + let selectedSlideIndex = await getSelectedSlideIndex(); + + // Decrement because the getSelectedSlideByIndex method is 1-based, + // but the getItemAt method is 0-based. + selectedSlideIndex = selectedSlideIndex - 1; + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(selectedSlideIndex); + slide.tags.add("CUSTOMER_TYPE", "Premium"); + + await context.sync(); + + const audienceTag: PowerPoint.Tag = slide.tags.getItem("CUSTOMER_TYPE"); + audienceTag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(audienceTag.key) + " with value " + JSON.stringify(audienceTag.value)); + }); + } + + function getSelectedSlideIndex() { + // Wrap a call of one of the Common APIs in a Promise-returning + // function, so that it can be easily called within a run() function + // of an application-specific API. + return new OfficeExtension.Promise(function (resolve, reject) { + Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideRange, function (asyncResult) { + try { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + reject(console.error(asyncResult.error.message)); + } else { + const result = asyncResult.value as any; + resolve(result.slides[0].index); + } + } catch (error) { + reject(console.log(error)); + } + }); + }); + } + + async function deleteSlidesByAudience() { + await PowerPoint.run(async function(context) { + const slides: PowerPoint.SlideCollection = context.presentation.slides; + slides.load("tags/key, tags/value"); + + await context.sync(); + + for (let i = 0; i < slides.items.length; i++) { + let currentSlide = slides.items[i]; + for (let j = 0; j < currentSlide.tags.items.length; j++) { + let currentTag: PowerPoint.Tag = currentSlide.tags.items[j]; + if (currentTag.key === "CUSTOMER_TYPE" && currentTag.value === "Premium") { + currentSlide.delete(); + } + } + } + + await context.sync(); + }); + } + + async function addMultipleSlideTags() { + await PowerPoint.run(async function(context) { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + slide.tags.add("OCEAN", "Indian"); + slide.tags.add("PLANET", "Jupiter"); + slide.tags.add("CONTINENT", "Antarctica"); + + await context.sync(); + + slide.tags.load("key, value"); + + await context.sync(); + + for (let i = 0; i < slide.tags.items.length; i++) { + console.log("Added key " + JSON.stringify(slide.tags.items[i].key) + " with value " + JSON.stringify(slide.tags.items[i].value)); + } + }); + } + + async function addShapeTag() { + await PowerPoint.run(async function(context) { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + const shape: PowerPoint.Shape = slide.shapes.getItemAt(0); + shape.tags.add("MOUNTAIN", "Denali"); + + await context.sync(); + + const myShapeTag: PowerPoint.Tag = shape.tags.getItem("MOUNTAIN"); + myShapeTag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(myShapeTag.key) + " with value " + JSON.stringify(myShapeTag.value)); + }); + } + + async function addPresentationTag() { + await PowerPoint.run(async function (context) { + let presentationTags: PowerPoint.TagCollection = context.presentation.tags; + presentationTags.add("COLOR", "blue"); + + await context.sync(); + + const tag: PowerPoint.Tag = presentationTags.getItem("COLOR"); + tag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(tag.key) + " with value " + JSON.stringify(tag.value)); + }); + } + + async function deletePresentationTag() { + await PowerPoint.run(async function (context) { + let presentationTags: PowerPoint.TagCollection = context.presentation.tags; + + presentationTags.delete("COLOR"); + + await context.sync(); + + console.log(JSON.stringify(presentationTags)); + }); + } + + /** 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: |- +
      +

      These snippets show how to use tags with the presentation and its slides and shapes.

      +
      +

      Try it out

      +

      1. Add several slides to the deck. Add content to each so they are visually distinct in the thumbnail pane.

      +

      2. Select a single slide and press Add tag to tag the slide to be shown only to premium customers.

      + +

      3. Repeat step 2 for another slide.

      +

      4. Press Delete premium customer slides to remove from the presentation slides that should only be shown to premium customers.

      + +

      5. Press Add slide tags to add mulitiple tags to the first slide of the presentation.

      + +

      6. Select the first slide and on the ribbon, navigate Insert > Illustrations > Shapes to add a shape to it. Press Add shape tag.

      + +

      7. Press Add presentation tag.

      + +

      8. Press Delete presentation tag.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/powerpoint/text/get-set-textrange.yaml b/samples/powerpoint/text/get-set-textrange.yaml new file mode 100644 index 000000000..810332baf --- /dev/null +++ b/samples/powerpoint/text/get-set-textrange.yaml @@ -0,0 +1,228 @@ +order: 1 +id: powerpoint-text-get-set-textrange +name: Work with text range selections +description: Get, set, load, and save text range selections. +host: POWERPOINT +api_set: + PowerPointApi: '1.8' +script: + content: | + document.getElementById("getSelectedTextRange").addEventListener("click", () => tryCatch(getSelectedTextRange)); + document.getElementById("setSelectedTextRange").addEventListener("click", () => tryCatch(setSelectedTextRange)); + document.getElementById("changeColor").addEventListener("click", () => tryCatch(changeColor)); + document.getElementById("saveTextSelection").addEventListener("click", () => tryCatch(saveTextSelection)); + document.getElementById("loadTextSelection").addEventListener("click", () => tryCatch(loadTextSelection)); + document + .getElementById("getSelectedTextRangeProperties") + .addEventListener("click", () => tryCatch(getSelectedTextRangeComplexProperties)); + + async function getSelectedTextRange() { + // Gets the selected text range and prints data about the range on the task pane. + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + try { + await context.sync(); + } catch (error) { + console.warn("You must select only one range of text for this action to work."); + return; + } + textRange.load("text"); + textRange.load("start"); + textRange.load("length"); + await context.sync(); + let txtHtml = textRange.text; + txtHtml = txtHtml.replace(/\n/g, "
      "); + txtHtml = txtHtml.replace(/\r/g, "
      "); + txtHtml = txtHtml.replace(/\v/g, "
      "); + let txtExplained = textRange.text; + txtExplained = txtExplained.replace(/\n/g, "NL"); + txtExplained = txtExplained.replace(/\r/g, "CR"); + txtExplained = txtExplained.replace(/\v/g, "VV"); + let finalTable = ""; + finalTable += + ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += "
      IndexId
      Raw" + textRange.text + "
      Html" + txtHtml + "
      Exp" + txtExplained + "
      Start" + textRange.start + "
      Length" + textRange.length + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); + } + + async function setSelectedTextRange() { + // Selects the first 10 characters of the selected shape. + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + if (shapeCount.value !== 1) { + console.warn("You must select only one shape with text in it."); + return; + } + const shape: PowerPoint.Shape = shapes.getItemAt(0); + const textFrame: PowerPoint.TextFrame = shape.textFrame.load("textRange,hasText"); + await context.sync(); + if (textFrame.hasText != true) { + console.warn("You must select only one shape with text in it."); + return; + } + const textRange: PowerPoint.TextRange = textFrame.textRange; + textRange.load("text"); + await context.sync(); + if (textRange.text.length < 10) { + console.warn("You must select only one shape with at least 10 characters in it."); + return; + } + const textRange10 = textRange.getSubstring(0, 10); + textRange10.setSelected(); + await context.sync(); + }); + } + + async function changeColor() { + // Sets the color of the selected text range to green. + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.font.color = "green"; + await context.sync(); + }); + } + + let savedTextSlideSelection = []; + let savedTextShapeSelection = []; + let savedTextTextRangeStart; + let savedTextTextRangeLength; + async function saveTextSelection() { + // Saves the range that is currently selected so it can be reselected later. + await PowerPoint.run(async (context) => { + let finalTable = ""; + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + savedTextSlideSelection = []; + slides.items.map((slide) => { + savedTextSlideSelection.push(slide.id); + }); + + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + shapes.load("items"); + await context.sync(); + savedTextShapeSelection = []; + shapes.items.map((shape) => { + savedTextShapeSelection.push(shape.id); + }); + const savedTextRange: PowerPoint.TextRange = context.presentation.getSelectedTextRangeOrNullObject(); + savedTextRange.load("start,length"); + await context.sync(); + if (savedTextRange.isNullObject) { + console.warn("You must select only one shape with text in it."); + return; + } + savedTextTextRangeStart = savedTextRange.start; + savedTextTextRangeLength = savedTextRange.length; + }); + } + + async function loadTextSelection() { + // Sets the range selection to the range that was saved previously. + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedTextSlideSelection[0]); + const shape1: PowerPoint.Shape = slide1.shapes.getItem(savedTextShapeSelection[0]); + const textRange: PowerPoint.TextRange = shape1.textFrame.textRange.getSubstring( + savedTextTextRangeStart, + savedTextTextRangeLength, + ); + textRange.setSelected(); + await context.sync(); + }); + } + + async function getSelectedTextRangeComplexProperties() { + // Gets navigational (complex) properties of the selected text range. + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.load("font,paragraphFormat/bulletFormat,paragraphFormat/horizontalAlignment"); + await context.sync(); + + console.log("Font properties of selected text range:"); + console.log(`\tallCaps: ${textRange.font.allCaps}`); + console.log(`\tbold: ${textRange.font.bold}`); + console.log(`\tcolor: ${textRange.font.color}`); + console.log(`\tdoubleStrikethrough: ${textRange.font.doubleStrikethrough}`); + console.log(`\titalic: ${textRange.font.italic}`); + console.log(`\tname: ${textRange.font.name}`); + console.log(`\tsize: ${textRange.font.size}`); + console.log(`\tsmallCaps: ${textRange.font.smallCaps}`); + console.log(`\tstrikethrough: ${textRange.font.strikethrough}`); + console.log(`\tsubscript: ${textRange.font.subscript}`); + console.log(`\tsuperscript: ${textRange.font.superscript}`); + console.log(`\tunderline: ${textRange.font.underline}`); + + console.log("Paragraph format properties of selected text range:"); + console.log(`\tbulletFormat.visible: ${textRange.paragraphFormat.bulletFormat.visible}`); + console.log(`\thorizontalAlignment: ${textRange.paragraphFormat.horizontalAlignment}`); + }); + } + + /** 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 selected text, and how to select specific text.

      +
      +
      +

      Try it out

      +

      Before choosing the Get selected text range button, add text to a slide and select some text.

      + + + + + + +

      Output

      + +

      Output from choosing the Get selected text range button is displayed in this section.

      +
      + 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; + } + .content { + padding: 0 18px; + /* display: none; */ + overflow: hidden; + background-color: #f1f1f1; + max-height: 0; + transition: max-height 0.2s ease-out; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/project/basics/basic-common-api-call.yaml b/samples/project/basics/basic-common-api-call.yaml index bf2020493..95a440ed7 100644 --- a/samples/project/basics/basic-common-api-call.yaml +++ b/samples/project/basics/basic-common-api-call.yaml @@ -7,13 +7,13 @@ host: PROJECT api_set: Selection: 1.1 script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); + console.error(asyncResult.error.message); } else { console.log(`The selected data is "${asyncResult.value}".`); } @@ -21,27 +21,17 @@ script: } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ + content: /* Your style goes here */ language: css -libraries: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - 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 \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/project/default.yaml b/samples/project/default.yaml index b37a46135..27aae8d65 100644 --- a/samples/project/default.yaml +++ b/samples/project/default.yaml @@ -5,13 +5,13 @@ author: OfficeDev host: PROJECT api_set: {} script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); + console.error(asyncResult.error.message); } else { console.log(`The selected data is "${asyncResult.value}".`); } @@ -19,27 +19,27 @@ script: } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/web/default.yaml b/samples/web/default.yaml index 2ffbedcb4..dba053526 100644 --- a/samples/web/default.yaml +++ b/samples/web/default.yaml @@ -5,32 +5,32 @@ author: OfficeDev host: WEB api_set: {} script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { - OfficeHelpers.UI.notify("Your code goes here"); + console.log("Your code goes here"); } language: typescript template: - content: | + content: |- language: html style: - content: | - /* Your style goes here */ - language: css -libraries: | - 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 + content: |- + section.samples { + margin-top: 20px; + } - jquery@3.1.1 - @types/jquery \ No newline at end of file + section.samples .ms-Button, section.setup .ms-Button { + display: block; + margin-bottom: 5px; + margin-left: 20px; + min-width: 80px; + } + language: css +libraries: |- + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/01-basics/basic-api-call-es5.yaml b/samples/word/01-basics/basic-api-call-es5.yaml index 7017a89a3..cf3ab1b5b 100644 --- a/samples/word/01-basics/basic-api-call-es5.yaml +++ b/samples/word/01-basics/basic-api-call-es5.yaml @@ -1,14 +1,14 @@ order: 2 -id: word-basic-api-call-es5 +id: word-basics-api-call-es5 name: Basic API call (JavaScript) description: Performs a basic Word API call using plain JavaScript & Promises. author: OfficeDev host: WORD api_set: - WordApi: 1.1 + WordApi: '1.1' script: content: |- - $("#run").click(() => tryCatch(run)); + document.getElementById("run").addEventListener("click", () => tryCatch(run)); function run() { return Word.run(function (context) { @@ -23,70 +23,41 @@ script: }); } - /** Default helper for invoking an action and handling errors. */ + // Default helper for invoking an action and handling errors. function tryCatch(callback) { Promise.resolve() .then(callback) .catch(function (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(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: |- -

      Executes a simple code snippet

      +
      + This sample executes a code snippet that prints the selected text to the console. Make sure to enter and select text before clicking "Print selection". +
      language: html style: content: |- - body { - margin: 0; - padding: 10px; + section.samples { + margin-top: 20px; } - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; + section.samples .ms-Button, section.setup .ms-Button { + display: block; + margin-bottom: 5px; + margin-left: 20px; + min-width: 80px; } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } language: css -libraries: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/01-basics/basic-api-call.yaml b/samples/word/01-basics/basic-api-call.yaml index 960d64e52..468f154e1 100644 --- a/samples/word/01-basics/basic-api-call.yaml +++ b/samples/word/01-basics/basic-api-call.yaml @@ -1,19 +1,19 @@ order: 1 id: word-basics-basic-api-call -name: Basic API call -description: Executes a basic Word API call using TypeScript. +name: Basic API call (TypeScript) +description: Performs a basic Word API call using TypeScript. author: OfficeDev host: WORD api_set: - WordApi: 1.1 + WordApi: '1.1' script: content: |- - $("#run").click(() => tryCatch(run)); + document.getElementById("run").addEventListener("click", () => tryCatch(run)); async function run() { // Gets the current selection and changes the font color to red. await Word.run(async (context) => { - const range = context.document.getSelection(); + const range: Word.Range = context.document.getSelection(); range.font.color = "red"; range.load("text"); @@ -23,71 +23,42 @@ script: }); } - /** Default helper for invoking an action and handling errors. */ + // 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); + // 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: |- -

      Executes a simple code snippet. Make sure to select text before clicking "Run code".

      +
      + This sample executes a code snippet that prints the selected text to the console. Make sure to enter and select text before clicking "Print selection". +
      language: html style: content: |- - body { - margin: 0; - padding: 10px; + section.samples { + margin-top: 20px; } - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; + section.samples .ms-Button, section.setup .ms-Button { + display: block; + margin-bottom: 5px; + margin-left: 20px; + min-width: 80px; } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } language: css -libraries: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/01-basics/basic-common-api-call.yaml b/samples/word/01-basics/basic-common-api-call.yaml index ef2fcd607..a94c13e3b 100644 --- a/samples/word/01-basics/basic-common-api-call.yaml +++ b/samples/word/01-basics/basic-common-api-call.yaml @@ -1,19 +1,19 @@ -order: 1000 +order: 3 id: word-basics-basic-common-api-call name: Basic API call (Office 2013) -description: Executes a basic Word API call using the "common API" syntax (compatible with Office 2013). +description: Performs a basic Word API call using JavaScript with the "common API" syntax (compatible with Office 2013). author: OfficeDev host: WORD api_set: Selection: 1.1 script: - content: | - $("#run").click(run); + content: |- + document.getElementById("run").addEventListener("click", run); function run() { Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, (asyncResult) => { if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.log(asyncResult.error.message); + console.error(asyncResult.error.message); } else { console.log(`The selected data is "${asyncResult.value}".`); } @@ -21,27 +21,30 @@ script: } language: typescript template: - content: | + content: |- +
      + This sample executes a code snippet that prints the selected text to the console. Make sure to enter and select text before clicking "Print selection". +
      language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/01-basics/basic-doc-assembly.yaml b/samples/word/01-basics/basic-doc-assembly.yaml deleted file mode 100644 index a71046013..000000000 --- a/samples/word/01-basics/basic-doc-assembly.yaml +++ /dev/null @@ -1,157 +0,0 @@ -id: word-basics-basic-doc-assembly -name: Basic document assembly -description: Basic document assembly capabilities of the Word JavaScript API. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#insert-header").click(insertHeader); - $("#add-paragraphs").click(addParagraphs); - $("#add-content-controls").click(addContentControls); - $("#change-customer").click(changeCustomer); - $("#add-footer").click(addFooter); - - // Inserts a heading 1 Title. - function insertHeader() { - Word.run(function (context) { - var header = context.document.body.insertText("This is a sample Heading 1 Title!!", "start"); - header.styleBuiltIn = Word.Style.heading1; - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - // Insert a set of paragraphs, a content control and a page break. - function addParagraphs() { - Word.run(function (context) { - var paragraph = context.document.body.insertParagraph("Timeline", "end"); - paragraph.style = "Heading 2"; - var paragraph2 = context.document.body.insertParagraph("The Services shall commence on July 31, 2015, and shall continue through July 29, 2015.", "end"); - paragraph2.style = "Normal"; - var paragraph3 = context.document.body.insertParagraph("Project Costs by Phase", "end"); - paragraph3.style = "Heading 2"; - // Note a content control with the title of "ProjectCosts" is added. Content will be replaced later. - var paragraph4 = context.document.body.insertParagraph("", "end"); - paragraph4.style = "Normal"; - paragraph4.font.highlightColor = "#FFFF00"; - var contentControl = paragraph4.insertContentControl(); - contentControl.title = "ProjectCosts"; - - var paragraph5 = context.document.body.insertParagraph("Project Team", "end"); - paragraph5.style = "Heading 2"; - paragraph5.font.highlightColor = "#FFFFFF"; - - var paragraph6 = context.document.body.insertParagraph("Terms of Work", "end"); - paragraph6.style = "Heading 1"; - - var paragraph7 = context.document.body.insertParagraph("Contractor shall provide the Services and Deliverable(s) as follows:", "end"); - paragraph7.style = "Normal"; - - var paragraph8 = context.document.body.insertParagraph("Out-of-Pocket Expenses / Invoice Procedures", "end"); - paragraph8.style = "Heading 2"; - - var paragraph9 = context.document.body.insertParagraph("Client will be invoiced monthly for the consulting services and T&L expenses. Standard Contractor invoicing is assumed to be acceptable. Invoices are due upon receipt. client will be invoiced all costs associated with out-of-pocket expenses (including, without limitation, costs and expenses associated with meals, lodging, local transportation and any other applicable business expenses) listed on the invoice as a separate line item. Reimbursement for out-of-pocket expenses in connection with performance of this SOW, when authorized and up to the limits set forth in this SOW, shall be in accordance with Client's then-current published policies governing travel and associated business expenses, which information shall be provided by the Client Project Manager.", "end"); - paragraph9.style = "Normal"; - // Insert a page break at the end of the document. - context.document.body.insertBreak("page", "End"); - return context.sync() - .catch(OfficeHelpers.Utilities.log); - }); - } - - // Search the document for instances of the string "Contractor". Change the format of - // each search result, and wrap each search result in a content control. Set the tag and title property on each content control. - function addContentControls() { - Word.run(function (context) { - //we first search for the "Contractor string" - var results = context.document.body.search("Contractor"); - context.load(results); - return context.sync().then(function () { - // Once we have the results, we iterate - for (var i = 0; i < results.items.length; i++) { - results.items[i].font.highlightColor = "#FFFF00"; - results.items[i].font.bold = true; - var cc = results.items[i].insertContentControl(); - cc.tag = "customer"; // This value is used in another part of this sample. - cc.title = "Customer Name"; - } - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - }); - } - - function changeCustomer() { - Word.run(function (context) { - // Get all the tagged content controls. - var contentControls = context.document.contentControls.getByTag("customer"); - context.load(contentControls, { select: 'text', expand: 'font' }); - return context.sync() - .then(function () { - for (var i = 0; i < contentControls.items.length; i++) { - contentControls.items[i].insertText("Fabrikam", "replace"); - } - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - }); - } - - function addFooter() { - Word.run(function (context) { - // Headers and footers live in the section of the document, we need to retrieve them. - var sections = context.document.sections; - context.load(sections, 'body/style'); - return context.sync().then(function () { - // Get the primary footer of the first section and get its body. - var footer = sections.items[0].getFooter("primary"); - footer.insertParagraph("Confidential", "end"); - footer.insertBreak("line", "end"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - }); - } - language: typescript -template: - content: |4 -

      This sample demonstrates how to use the basic document assembly objects by creating sample document, search, create a template, add paragraphs and footers. Just click the buttons in top-down order.

      - - - - - - - - language: html -style: - content: '' - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/01-basics/insert-and-get-pictures.yaml b/samples/word/01-basics/insert-and-get-pictures.yaml deleted file mode 100644 index a4f8b5ce6..000000000 --- a/samples/word/01-basics/insert-and-get-pictures.yaml +++ /dev/null @@ -1,169 +0,0 @@ -id: word-basics-insert-and-get-pictures -name: Inline pictures -description: Shows how to insert and get inline pictures. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#insert").click(insertImage); - $("#get").click(getImage); - - /** - * Setup by adding a dummy paragraph. - */ - async function setup() { - try { - await Word.run(async (context) => { - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add.You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching Online cover page, header, and sidebar. Click Insert and then choose the elements you want from the different Online galleries.", "replace"); - await context.sync(); - }); - } - catch (exception) { - OfficeHelpers.Utilities.log(exception); - } - } - - /** - * Inserts a blank paragraph at the end of the document - * and then an image anchored to it. - */ - async function insertImage() { - try { - await Word.run(async (context) => { - context.document.body.paragraphs.getLast().insertParagraph("", "after").insertInlinePictureFromBase64(base64Image, "end"); - await context.sync(); - console.log("success"); - }); - } - catch (exception) { - OfficeHelpers.Utilities.log(exception); - } - } - - /** - * Get the first image in the document - */ - async function getImage() { - try { - Word.run(async (context) => { - const firstPicture = context.document.body.inlinePictures.getFirst(); - context.load(firstPicture); - await context.sync(); - - const base64 = firstPicture.getBase64ImageSrc(); - await context.sync(); - - console.log(base64.value); - }) - } - catch (exception) { - OfficeHelpers.Utilities.log(exception); - } - } - - const base64Image = - "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"; - language: typescript -template: - content: | -

      This sample demonstrates how to insert and get inline pictures in a document.

      - -
      -

      Click "setup" to insert sample data and between runs to reset the sample.

      - - -
      - -
      -

      Sample snippets to try.

      - - - -
      - language: html -style: - content: | - body { - margin: 0; - padding: 10px; - } - - /* Button customization, including overwriting some Fabric defaults */ - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: | - # Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - # CSS Libraries - 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 - - # NPM libraries - core-js@2.4.1/client/core.min.js - @microsoft/office-js-helpers@.5.0/dist/office.helpers.min.js - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.js - - # IntelliSense: @types/library or node_modules paths or URL to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/01-basics/insert-formatted-text.yaml b/samples/word/01-basics/insert-formatted-text.yaml deleted file mode 100644 index 08f7d0689..000000000 --- a/samples/word/01-basics/insert-formatted-text.yaml +++ /dev/null @@ -1,103 +0,0 @@ -id: word-basics-insert-formatted-text -name: Insert formatted text -description: Shows how to use formatting objects as well as applying pre-built styles. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#run").click(run); - - async function run() { - try { - await Word.run(async (context) => { - // Here we go to insert first sentence. Then we adjust the formatting. - // Note that replace affects the calling object, in this case the entire document body. - // A similar method can also be used at the range level. - var firstSentence = context.document.body.insertText("This is some formatted text!", "replace"); - firstSentence.font.name = "Courier New"; - firstSentence.font.bold = true; - firstSentence.font.size = 18; - - // Second sentence, let's insert it after the previously inserted one. - var secondSentence = context.document.body.insertText("This is other formatted text.", "end"); - secondSentence.font.bold = false; - secondSentence.font.italic = true; - secondSentence.font.name = "Berlin Sans FB"; - secondSentence.font.size = 30; - secondSentence.font.color = "blue"; - - // You can also use pre-exsiting styles. - var lastSentence = context.document.body.insertParagraph("To be or not to be", "end"); - - // Use styleBuiltIn to use an enumeration of existing styles. If your style is custom make sure to use range.style = "name of your style"; - lastSentence.styleBuiltIn = Word.Style.intenseReference; - - await context.sync() - console.log("success"); - }) - } catch (e) { - OfficeHelpers.Utilities.log(e); - } - } - language: typescript -template: - content: |- -

      Shows how to insert basic formatted text and apply built-in styles.

      - - language: html -style: - content: |- - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/01-basics/insert-header.yaml b/samples/word/01-basics/insert-header.yaml deleted file mode 100644 index f76d4b94a..000000000 --- a/samples/word/01-basics/insert-header.yaml +++ /dev/null @@ -1,79 +0,0 @@ -id: word-basics-insert-header -name: Insert header -description: Demonstrates how to insert a header in the document. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#run").click(run); - - function run() { - Word.run(function (context) { - var myHeader = context.document.sections.getFirst() - .getHeader("primary").insertText("This is a header", "start"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      Click to insert a header in the document

      - - language: html -style: - content: |- - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/01-basics/insert-line-and-page-breaks.yaml b/samples/word/01-basics/insert-line-and-page-breaks.yaml deleted file mode 100644 index aa01b0e34..000000000 --- a/samples/word/01-basics/insert-line-and-page-breaks.yaml +++ /dev/null @@ -1,147 +0,0 @@ -id: word-basics-insert-line-and-page-breaks -name: Insert breaks -description: Shows how to insert page and line breaks in a document. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#setup").click(setup); - $("#line").click(insertLineBreak); - $("#page").click(insertPageBreak); - - function insertLineBreak() { - Word.run(function (context) { - var paragraph = context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.line, "after"); - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function insertPageBreak() { - Word.run(function (context) { - var picture = context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.page, "after"); - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching Online cover page, header, and sidebar. Click Insert and then choose the elements you want from the different Online galleries.", "replace"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |4 -

      This sample demonstrates how to insert pagr and line breaks.

      - - -
      -

      Click "setup" to insert sample text and between runs to reset the sample.

      - - -
      - - -
      -

      Sample snippets to try:

      - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/01-basics/search.yaml b/samples/word/01-basics/search.yaml deleted file mode 100644 index f61954902..000000000 --- a/samples/word/01-basics/search.yaml +++ /dev/null @@ -1,160 +0,0 @@ -id: word-basics-search -name: Search -description: Shows basic and advanced search capabilities. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#setup").click(setup); - $("#basic").click(basicSearch); - $("#wildcard").click(wildcardSearch); - - - function basicSearch() { - Word.run(function (context) { - var results = context.document.body.search("Online"); - context.load(results); - return context.sync() - .then(function () { - //lets traverse the search results... and highlight.. - for (var i = 0; i < results.items.length; i++) { - results.items[i].font.highlightColor = "yellow"; - } - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function wildcardSearch() { - Word.run(function (context) { - // check out how wildcard expression are built, also use the second parameter of the search method to include search modes (i.e. we are using wildcards). - var results = context.document.body.search("$*.[0-9][0-9]", { matchWildcards: true }); - context.load(results); - return context.sync() - .then(function () { - //lets traverse the search results... and highlight.. - for (var i = 0; i < results.items.length; i++) { - results.items[i].font.highlightColor = "red"; - results.items[i].font.color = "white"; - } - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video ($10,000.00), you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching Online cover page, header, and sidebar. Click Insert and then choose the Online elements you want from the different Online galleries.", "replace"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |4 -

      This sample demonstrates basic and advanced search capabilities of the API.

      - - -
      -

      Click "setup" to insert sample text and between runs to reset the sample.

      - - -
      - - -
      -

      Sample snippets to try:

      - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/02-paragraphs/get-paragraph-on-insertion-point.yaml b/samples/word/02-paragraphs/get-paragraph-on-insertion-point.yaml deleted file mode 100644 index 7c24205d3..000000000 --- a/samples/word/02-paragraphs/get-paragraph-on-insertion-point.yaml +++ /dev/null @@ -1,162 +0,0 @@ -id: word-paragraphs-get-paragraph-on-insertion-point -name: Get paragraph from insertion point -description: Gets the full paragraph containing the insertion point. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#get-paragraph").click(getParagraph); - $("#get-sentences").click(getSentences); - $("#setup").click(setup); - - - function getParagraph() { - Word.run(function (context) { - // the collection of paragraphs of the current selection returns the full paragraphs contanied on it. - var paragraph = context.document.getSelection().paragraphs.getFirst(); - context.load(paragraph); - return context.sync() - .then(function () { - console.log(paragraph.text); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function getSentences() { - Word.run(function (context) { - // gets the complete sentence (as range) associated with the insertion point. - var sentences = context.document - .getSelection().getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); - context.load(sentences); - return context.sync() - .then(function () { - // expands the range to the end of the paragraph to get all the complete sentences. - var sentecesToTheEndOfParagraph = sentences.items[0].getRange() - .expandTo(context.document.getSelection().paragraphs - .getFirst().getRange("end") /* Expanding the range all the way to the end of the paragraph */).getTextRanges(["."], false); - context.load(sentecesToTheEndOfParagraph); - return context.sync() - .then(function () { - for (var i = 0; i < sentecesToTheEndOfParagraph.items.length; i++) { - console.log("Sentence " + (i + 1) + ":" - + sentecesToTheEndOfParagraph.items[i].text); - } - }); - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries.", "replace"); - return context.sync() - .then(function () { - context.document.body.paragraphs.getFirst().alignment = "left"; - context.document.body.paragraphs.getLast().alignment = "left"; - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      This sample demonstrates how to get the paragraph and paragraph sentences associated with the current insertion point.

      - -
      -

      Click "setup" to reset the sample.

      - - -
      - -
      - - -
      - language: html -style: - content: | - body { - margin: 0; - padding: 10px; - } - - /* Button customization, including overwriting some Fabric defaults */ - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/02-paragraphs/insert-in-different-locations.yaml b/samples/word/02-paragraphs/insert-in-different-locations.yaml deleted file mode 100644 index b8a4ba2b2..000000000 --- a/samples/word/02-paragraphs/insert-in-different-locations.yaml +++ /dev/null @@ -1,206 +0,0 @@ -id: word-basics-insert-in-different-locations -name: Insert locations. -description: Shows how to insert content using the different available locations. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#setup").click(setup); - $("#before").click(before); - $("#start").click(start); - $("#end").click(end); - $("#after").click(after); - $("#replace").click(replace); - - - function before() { - Word.run(function (context) { - // lets insert before the first paragraph. - var range = context.document.body.paragraphs.getFirst().insertParagraph("This is Before", "before"); - range.font.highlightColor = "yellow"; - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function start() { - Word.run(function (context) { - // This button assumes the before was clicked, so we get the next paragraph and insert text at the begining.Note that there are no-valid locations depending on the object. For instance insertParagraph and "before" on a paragrpah object is not a valid combination. - var range = context.document.body.paragraphs.getFirst().getNext().insertText("This is Start", "start"); - range.font.highlightColor = "blue"; - range.font.color = "white"; - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function end() { - Word.run(function (context) { - // Here we go to insert on paragraph - var range = context.document.body.paragraphs.getFirst().getNext().insertText(" This is End", "end"); - range.font.highlightColor = "green"; - range.font.color = "white"; - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function after() { - Word.run(function (context) { - // Here we go to insert on paragraph - var range = context.document.body.paragraphs.getFirst().getNext().insertParagraph("This is After", "after"); - range.font.highlightColor = "red"; - range.font.color = "white"; - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function replace() { - Word.run(function (context) { - // Here we go to insert on paragraph - var range = context.document.body.paragraphs.getLast().insertText("Just replaced the last paragraph!", "replace"); - range.font.highlightColor = "black"; - range.font.color = "white"; - return context.sync() - .then(function () { - console.log("success"); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries.", "replace"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |4 -

      This sample demonstrates a variety of insert locations available in the API.

      - - -
      -

      Click "setup" to insert sample text and between runs to reset the sample.

      - - -
      - - -
      -

      Sample snippets to try. Click buttons top-down.

      - - - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/02-paragraphs/paragraph-properties.yaml b/samples/word/02-paragraphs/paragraph-properties.yaml deleted file mode 100644 index cb7ed7d56..000000000 --- a/samples/word/02-paragraphs/paragraph-properties.yaml +++ /dev/null @@ -1,176 +0,0 @@ -id: word-paragraphs-paragraph-properties -name: Paragraph properties -description: 'Shows how to set indentation, space between paragraphs and other paragraph properties.' -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#indent").click(indent); - $("#spacing").click(spacing); - $("#space-after").click(spaceAfter); - $("#align").click(align); - $("#setup").click(setup); - - function indent() { - Word.run(function (context) { - // Indents the first paragraph - context.document.body.paragraphs. - getFirst().leftIndent = 75; //units = points - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function spacing() { - Word.run(function (context) { - // Adjusts line spacing - context.document.body.paragraphs - .getFirst().lineSpacing = 20; - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function spaceAfter() { - Word.run(function (context) { - //Adjust space between paragraphs - context.document.body.paragraphs - .getFirst().spaceAfter = 20; - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function align() { - Word.run(function (context) { - // Centers last paragraph alignment - context.document.body.paragraphs - .getLast().alignment = "centered"; - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries.", "replace"); - return context.sync() - .then(function () { - context.document.body.paragraphs.getFirst().alignment = "left"; - context.document.body.paragraphs.getLast().alignment = "left"; - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      This sample demonstrates paragraph property usage.

      - - -
      -

      Click "setup" to reset the sample.

      - - -
      - -
      -

      Sample snippets to try. Click buttons top-down.

      - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/03-content-controls/insert-and-change-content-controls.yaml b/samples/word/03-content-controls/insert-and-change-content-controls.yaml deleted file mode 100644 index 9994502fd..000000000 --- a/samples/word/03-content-controls/insert-and-change-content-controls.yaml +++ /dev/null @@ -1,181 +0,0 @@ -id: word-content-controls-insert-and-change-content-controls -name: Content control basics -description: 'Insertion, manipulation and retrieval of content controls.' -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#insert-controls").click(insertContentControls); - $("#change-controls").click(modifyContentControls); - $("#setup").click(setup); - - - function insertContentControls() { - //traverses each paragraph of the document and wraps a content control on each with either a even or odd tags - Word.run(function (context) { - var paragraphs = context.document.body.paragraphs; - context.load(paragraphs); - return context.sync() - .then(function () { - for (var i = 0; i < paragraphs.items.length; i++) { - console.log(paragraphs.items.length); - var contentControl = paragraphs.items[i].insertContentControl(); - //for even we tag "even" - if (i % 2 == 0) - contentControl.tag = "even"; - - else - contentControl.tag = "odd"; - } - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - - function modifyContentControls() { - // I'll add title and colors to odd and even content controls! and change appearance of all. - Word.run(function (context) { - // gets the complete sentence (as range) associated with the insertion point. - var evenContentControls = context.document.contentControls.getByTag("even"); - var oddContentControls = context.document.contentControls.getByTag("odd"); - context.load(evenContentControls); - context.load(oddContentControls); - return context.sync() - .then(function () { - for (var i = 0; i < evenContentControls.items.length; i++) { - //change a few properties and append a paragraph - evenContentControls.items[i].color = "red"; - evenContentControls.items[i].title = "Odd ContentControl #" + (i+1); - evenContentControls.items[i].appearance = "tags"; - evenContentControls.items[i].insertParagraph("This is an odd content control", "end"); - } - - for (var j = 0; j < oddContentControls.items.length; j++) { - //change a few properties and append a paragraph - oddContentControls.items[j].color = "green"; - oddContentControls.items[j].title = "Even ContentControl #" + (j+1); - oddContentControls.items[j].appearance = "tags"; - oddContentControls.items[j].insertHtml("This is an even content control", "end"); - } - return context.sync(); - - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("One more paragraph. ", "start"); - context.document.body.insertParagraph("Inserting another paragraph. ", "start"); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries. ", "replace"); - return context.sync() - .then(function () { - context.document.body.paragraphs.getFirst().alignment = "left"; - context.document.body.paragraphs.getLast().alignment = "left"; - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      This sample demonstrates how to insert and change content control properties.

      - -
      -

      Click "setup" to reset the sample.

      - - -
      - -
      - - -
      - language: html -style: - content: | - body { - margin: 0; - padding: 10px; - } - - /* Button customization, including overwriting some Fabric defaults */ - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/04-range/scroll-to-range.yaml b/samples/word/04-range/scroll-to-range.yaml deleted file mode 100644 index 82bd4692f..000000000 --- a/samples/word/04-range/scroll-to-range.yaml +++ /dev/null @@ -1,149 +0,0 @@ -id: word-basics-scroll-to-range -name: Scroll to range -description: Shows how to scroll to a range with and without selection. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#setup").click(setup); - $("#scroll").click(scroll); - $("#scroll-end").click(scrollEnd); - - function scroll() { - Word.run(function (context) { - //if select is called with no parameters it selects the object. - var paragraph = context.document.body.paragraphs.getLast().select(); - return context.sync() - .then(function () { - console.log("success"); - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function scrollEnd() { - Word.run(function (context) { - // select can be at the start or end of a range, this by definition moves the insertion point without selecting the range. - var paragraph = context.document.body.paragraphs.getLast().select("end"); - return context.sync() - .then(function () { - console.log("success"); - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - var firstSentence = context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - firstSentence.insertBreak(Word.BreakType.page, "after"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching Online cover page, header, and sidebar. Click Insert and then choose the Online elements you want from the different Online galleries.", "replace"); - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |4 -

      This sample demonstrates how to scroll to a range.

      - - -
      -

      Click "setup" to insert sample text and between runs to reset the sample. This appends a paragraph in the second page to demonstrate scrolling of the document.

      - - -
      - - -
      -

      Sample snippets to try:

      - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/04-range/split-words-of-first-paragraph.yaml b/samples/word/04-range/split-words-of-first-paragraph.yaml deleted file mode 100644 index cdcab4830..000000000 --- a/samples/word/04-range/split-words-of-first-paragraph.yaml +++ /dev/null @@ -1,160 +0,0 @@ -id: word-range-split-words-of-first-paragraph -name: Range manipulation -description: 'Show how to split a paragraph into word ranges and then traverses all the ranges to format each word, producing a "karaoke" effect.' -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#setup").click(setup); - $("#highlight").click(highlightWords); - - function highlightWords() { - Word.run(function (context) { - var myPars = context.document.body.paragraphs; - context.load(myPars); - return context.sync() - .then(function () { - var myWords = myPars.items[0].split([" "], true /*used to trim delimiters*/, true /* used to trim spaces */); - context.load(myWords, { expand: 'font' }); - return context.sync() - .then(function () { - return forEach(myWords, function (item, i) { - if (i >= 1) { - myWords.items[i - 1].font.highlightColor = "#FFFFFF"; - } - myWords.items[i].font.highlightColor = "#FFFF00"; - return createTimerPromise(200).then(context.sync); - }) - }) - }) - }) - .catch(OfficeHelpers.Utilities.log); - - function createTimerPromise(ms) { - return new OfficeExtension.Promise(function (resolve) { - setTimeout(resolve, ms); - }) - } - - function forEach(collection, handler) { - var promise = new OfficeExtension.Promise(function (resolve) { resolve(); }); - collection.items.forEach(function (item, index) { - promise = promise.then(function () { - return handler(item, index); - }) - }); - return promise; - } - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching Online cover page, header, and sidebar. Click Insert and then choose the Online elements you want from the different Online galleries.", "replace"); - return context.sync(); - }) - } - language: typescript -template: - content: |4 -

      This sample demonstrates splitting and traversing ranges.

      - - -
      -

      Click "setup" to insert sample text and between runs to reset the sample.

      - - -
      - - -
      -

      Sample snippets to try:

      - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/05-tables/table-cell-access.yaml b/samples/word/05-tables/table-cell-access.yaml deleted file mode 100644 index e6f7e1ab2..000000000 --- a/samples/word/05-tables/table-cell-access.yaml +++ /dev/null @@ -1,131 +0,0 @@ -id: word-tables-table-cell-access -name: Table cell access -description: Shows how to access a specific cell in a table. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#run").click(getTableCell); - $("#setup").click(insertTable); - - - function getTableCell() { - Word.run(function (context) { - var firstCell = context.document.body.tables.getFirst().getCell(0, 0).body; - context.load(firstCell); - return context.sync() - .then(function () { - console.log("First cell text is " + firstCell.text); - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function insertTable() { - Word.run(function (context) { - // We need a 2D array to hold the initial table values - var data = [["Apple", "Orange", "Pineapple"], ["Tokyo", "Beijing", "Seattle"]]; - var table = context.document.body.insertTable(3, 3, "start", data); - table.styleBuiltIn = Word.Style.gridTable5Dark_Accent2; - return context.sync(); - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      Demostrates how to get a cell from a table.

      - - -
      -

      Click "setup" to add a sample table:

      - - -
      - -
      -

      Get contents of first cell, first table:

      - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/06-lists/insert-list.yaml b/samples/word/06-lists/insert-list.yaml deleted file mode 100644 index 72b8bb660..000000000 --- a/samples/word/06-lists/insert-list.yaml +++ /dev/null @@ -1,145 +0,0 @@ -id: word-lists-insert-list -name: List creation -description: Inserts a new list into the document. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#insert-controls").click(insertList); - $("#setup").click(setup); - - function insertList() { - //this example starts a new list stating with the second paragraph. - Word.run(function (context) { - var paragraphs = context.document.body.paragraphs; - paragraphs.load(); - return context.sync() - .then(function () { - var list = paragraphs.items[1].startNewList(); //indicates new list to be started in the second paragraph. - list.load(); - context.sync() - .then(function () { - //to add new items to the list use start/end on the insert location parameter. - list.insertParagraph('New list item on top of the list', 'start'); - var paragraph = list.insertParagraph('New list item at the end of the list (4th level)', 'end'); - paragraph.listItem.level = 4; //sets up list level for the lsit item. - //to add paragraphs outside the list use before/after - list.insertParagraph('New paragraph goes after (not part of the list)', 'after'); - return context.sync(); - }); - }); - }) - .catch(OfficeHelpers.Utilities.log); - } - - function setup() { - Word.run(function (context) { - // lets insert a couple of paragraphs to illustrate the point.. - context.document.body.clear(); - context.document.body.insertParagraph("Themes and styles also help keep your document coordinated. When you click design and choose a new Theme, the pictures, charts, and SmartArt graphics change to match your new theme. When you apply styles, your headings change to match the new theme. ", "start"); - context.document.body.insertParagraph("Save time in Word with new buttons that show up where you need them. To change the way a picture fits in your document, click it and a button for layout options appears next to it. When you work on a table, click where you want to add a row or a column, and then click the plus sign. ", "start"); - context.document.body.insertParagraph("Video provides a powerful way to help you prove your point. When you click Online Video, you can paste in the embed code for the video you want to add. You can also type a keyword to search online for the video that best fits your document.", "start"); - context.document.body.paragraphs.getLast().insertText("To make your document look professionally produced, Word provides header, footer, cover page, and text box designs that complement each other. For example, you can add a matching cover page, header, and sidebar. Click Insert and then choose the elements you want from the different galleries. ", "replace"); - return context.sync() - .then(function () { - context.document.body.paragraphs.getFirst().alignment = "left"; - context.document.body.paragraphs.getLast().alignment = "left"; - return context.sync(); - }) - }) - .catch(OfficeHelpers.Utilities.log); - } - language: typescript -template: - content: |- -

      This sample demonstrates how to insert and change lists.

      - -
      -

      Click "setup" to reset the sample.

      - - -
      - -
      - -
      - language: html -style: - content: | - body { - margin: 0; - padding: 10px; - } - - /* Button customization, including overwriting some Fabric defaults */ - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/07-custom-properties/get-built-in-properties.yaml b/samples/word/07-custom-properties/get-built-in-properties.yaml deleted file mode 100644 index b5756abe3..000000000 --- a/samples/word/07-custom-properties/get-built-in-properties.yaml +++ /dev/null @@ -1,85 +0,0 @@ -id: word-custom-properties-get-built-in-properties -name: Get built-in document properties. -description: Shows how to get built-in document properties. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |+ - $("#run").click(getProperties); - - function getProperties() { - Word.run(function (context) { - var builtInProperties = context.document.properties; - context.load(builtInProperties); - return context.sync() - .then(function () { - console.log(JSON.stringify(builtInProperties, null, 4)); - }); - }) - .catch(OfficeHelpers.Utilities.log); - - } - - language: typescript -template: - content: |4 -

      This sample demonstrates how to set headers.

      - - - language: html -style: - content: |- - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/07-custom-properties/read-write-custom-document-properties.yaml b/samples/word/07-custom-properties/read-write-custom-document-properties.yaml deleted file mode 100644 index 12f672d94..000000000 --- a/samples/word/07-custom-properties/read-write-custom-document-properties.yaml +++ /dev/null @@ -1,143 +0,0 @@ -id: word-basics-read-write-custom-document-properties -name: Read-write custom document properties -description: This sample shows how to add custom document properties of different types and how to read them as well. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: |- - $("#number").click(insertNumericProperty); - $("#string").click(insertStringProperty); - $("#read").click(readCustomDocumentProperties); - - function insertNumericProperty() { - Word.run(function (context) { - context.document.properties.customProperties.add("Numeric Property", 1234); - return context.sync() - .then(function () { - console.log("Property added"); - }) - .catch(OfficeHelpers.Utilities.log); - }) - - } - - function insertStringProperty() { - Word.run(function (context) { - context.document.properties.customProperties.add("String Property", "Hello World!"); - return context.sync() - .then(function () { - console.log("Property added"); - }) - .catch(OfficeHelpers.Utilities.log); - }) - } - - function readCustomDocumentProperties() { - Word.run(function (context) { - var properties = context.document.properties.customProperties; - context.load(properties); - return context.sync() - .then(function () { - for (var i = 0; i < properties.items.length; i++) - console.log("Property Name:" + properties.items[i].key + ";Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].value); - }) - .catch(OfficeHelpers.Utilities.log); - }) - } - language: typescript -template: - content: |4 -

      This sample demonstrates how to insert custom document properties of different data types and how to read them.

      - -
      -

      Sample snippets to try.

      - - - - - -
      - language: html -style: - content: |4 - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #217346; - border: #217346; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #164b2e; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - - #setup.ms-Button, #setup.ms-Button:focus { - background: darkred; - border: darkred; - } - - #setup.ms-Button:hover, #setup.ms-Button:active { - background: red; - } - - #samples-container { - margin-top: 20px; - } - - #samples-container .ms-Button { - display: block; - margin-bottom: 5px; - } - - #samples-container .ms-Button, #setup-container .ms-Button { - margin-left: 20px; - min-width: 80px; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-onadded-event.yaml b/samples/word/10-content-controls/content-control-onadded-event.yaml new file mode 100644 index 000000000..a21f0fbf7 --- /dev/null +++ b/samples/word/10-content-controls/content-control-onadded-event.yaml @@ -0,0 +1,136 @@ +order: 2 +id: word-content-controls-content-control-onadded-event +name: On adding content controls +description: Registers, triggers, and deregisters onAdded event that tracks the addition of content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("register-event-handler").addEventListener("click", () => tryCatch(registerEventHandler)); + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("deregister-event-handler").addEventListener("click", () => tryCatch(deregisterEventHandler)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContext; + + async function registerEventHandler() { + // Registers the onAdded event handler on the document. + await Word.run(async (context) => { + eventContext = context.document.onContentControlAdded.add(contentControlAdded); + await context.sync(); + + console.log("Added event handler for when content controls are added."); + }); + } + + async function contentControlAdded(event: Word.ContentControlAddedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were added:`, event.ids); + }); + } + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function deregisterEventHandler() { + await Word.run(eventContext.context, async (context) => { + eventContext.remove(); + await context.sync(); + }); + + eventContext = null; + console.log("Removed event handler that was tracking when content controls are added."); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onAdded event with content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Register event handler. + + Insert content controls. + + Remove event handler. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-ondatachanged-event.yaml b/samples/word/10-content-controls/content-control-ondatachanged-event.yaml new file mode 100644 index 000000000..9ca1c8006 --- /dev/null +++ b/samples/word/10-content-controls/content-control-ondatachanged-event.yaml @@ -0,0 +1,154 @@ +order: 5 +id: word-content-controls-content-control-ondatachanged-event +name: On changing data in content controls +description: Registers, triggers, and deregisters onDataChanged event that tracks when data is changed in content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function registerEventHandlers() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDataChanged event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDataChanged.add(contentControlDataChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when data is changed in content controls."); + } + }); + } + + async function contentControlDataChanged(event: Word.ContentControlDataChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where data was changed:`, event.ids); + }); + } + + async function deregisterEventHandlers() { + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers that were tracking when data is changed in content controls."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onDataChanged event on content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + 1. Insert content controls. + + 2. Register event handlers. + +

      3. Within a content control, make a change in the text.

      + 4. Remove event handlers. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-ondeleted-event.yaml b/samples/word/10-content-controls/content-control-ondeleted-event.yaml new file mode 100644 index 000000000..cdbf945ff --- /dev/null +++ b/samples/word/10-content-controls/content-control-ondeleted-event.yaml @@ -0,0 +1,174 @@ +order: 7 +id: word-content-controls-content-control-ondeleted-event +name: On deleting content controls +description: Registers, triggers, and deregisters onDeleted event that tracks the removal of content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("delete-content-control").addEventListener("click", () => tryCatch(deleteContentControl)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function registerEventHandlers() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDeleted event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDeleted.add(contentControlDeleted); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when content controls are deleted."); + } + }); + } + + async function contentControlDeleted(event: Word.ContentControlDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were deleted:`, event.ids); + }); + } + + async function deleteContentControl() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("forTesting"); + contentControls.load("items"); + await context.sync(); + + if (contentControls.items.length === 0) { + console.log("There are no content controls in this document."); + } else { + console.log("Control to be deleted:", contentControls.items[0]); + contentControls.items[0].delete(false); + await context.sync(); + } + }); + } + + async function deregisterEventHandlers() { + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers that were tracking when content controls are deleted."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onDeleted event on content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Insert content controls. + + Register event handlers. + + Delete first content control. + + Remove event handlers. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-onentered-event.yaml b/samples/word/10-content-controls/content-control-onentered-event.yaml new file mode 100644 index 000000000..cba1483af --- /dev/null +++ b/samples/word/10-content-controls/content-control-onentered-event.yaml @@ -0,0 +1,154 @@ +order: 3 +id: word-content-controls-content-control-onentered-event +name: On entering content controls +description: Registers, triggers, and deregisters onEntered event that tracks when the cursor is placed within content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function registerEventHandlers() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onEntered event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onEntered.add(contentControlEntered); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is placed in content controls."); + } + }); + } + + async function contentControlEntered(event: Word.ContentControlEnteredEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was entered: ${event.ids[0]}`); + }); + } + + async function deregisterEventHandlers() { + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers that were tracking when the cursor is placed in content controls."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onEntered event on content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + 1. Insert content controls. + + 2. Register event handlers. + +

      3. Place the cursor in a content control.

      + 4. Remove event handlers. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-onexited-event.yaml b/samples/word/10-content-controls/content-control-onexited-event.yaml new file mode 100644 index 000000000..36950eef7 --- /dev/null +++ b/samples/word/10-content-controls/content-control-onexited-event.yaml @@ -0,0 +1,155 @@ +order: 6 +id: word-content-controls-content-control-onexited-event +name: On exiting content controls +description: Registers, triggers, and deregisters onExited event that tracks when the cursor is removed from within content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function registerEventHandlers() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onExited event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onExited.add(contentControlExited); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is removed from within content controls."); + } + }); + } + + async function contentControlExited(event: Word.ContentControlExitedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was exited: ${event.ids[0]}`); + }); + } + + async function deregisterEventHandlers() { + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers that were tracking when the cursor is removed from within content controls."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onExited event on content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + 1. Insert content controls. + + 2. Register event handlers. + +

      3. Place cursor within a content control.

      +

      4. Place cursor in location outside of that content control.

      + 5. Remove event handlers. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml b/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml new file mode 100644 index 000000000..377dc3061 --- /dev/null +++ b/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml @@ -0,0 +1,153 @@ +order: 4 +id: word-content-controls-content-control-onselectionchanged-event +name: On changing selection in content controls +description: Registers, triggers, and deregisters onSelectionChanged event that tracks when selections are changed in content controls. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-content-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + contentControl.tag = "forTesting"; + } + + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function registerEventHandlers() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onSelectionChanged.add(contentControlSelectionChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when selections are changed in content controls."); + } + }); + } + + async function contentControlSelectionChanged(event: Word.ContentControlSelectionChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where selection was changed:`, event.ids); + }); + } + + async function deregisterEventHandlers() { + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers that were tracking when selection is changed in content controls."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to use the onSelectionChanged event on content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + 1. Insert content controls. + + 2. Register event handlers. + +

      3. Select text within a content control.

      + 4. Remove event handlers. + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/get-change-tracking-states.yaml b/samples/word/10-content-controls/get-change-tracking-states.yaml new file mode 100644 index 000000000..6e7804c55 --- /dev/null +++ b/samples/word/10-content-controls/get-change-tracking-states.yaml @@ -0,0 +1,167 @@ +order: 11 +id: word-content-controls-get-change-tracking-states +name: Get change tracking states of content controls +description: Gets change tracking states of content controls. +author: xiruatms +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("turn-on-change-tracking").addEventListener("click", () => tryCatch(turnOnChangeTracking)); + document.getElementById("insert-content-control").addEventListener("click", () => tryCatch(insertContentControlOnLastParagraph)); + document.getElementById("delete-content-control").addEventListener("click", () => tryCatch(deleteFirstContentControl)); + document.getElementById("turn-off-change-tracking").addEventListener("click", () => tryCatch(turnOffChangeTracking)); + document.getElementById("log-change-tracking-states").addEventListener("click", () => tryCatch(logChangeTrackingStates)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function turnOnChangeTracking() { + // Turns on change tracking. + await Word.run(async (context) => { + context.document.changeTrackingMode = Word.ChangeTrackingMode.trackAll; + await context.sync(); + console.log("Turned on change tracking."); + }); + } + + async function insertContentControlOnLastParagraph() { + // Inserts a content control on the last paragraph. + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load(); + paragraphs.getLast().insertContentControl("RichText"); + await context.sync(); + console.log("Inserted content control on last paragraph."); + }); + } + + async function deleteFirstContentControl() { + // Deletes the first content control found in the document body. + await Word.run(async (context) => { + context.document.body + .getContentControls() + .getFirst() + .delete(false); + await context.sync(); + console.log("Deleted the first content control."); + }); + } + + async function turnOffChangeTracking() { + // Turns off change tracking. + await Word.run(async (context) => { + context.document.changeTrackingMode = Word.ChangeTrackingMode.off; + await context.sync(); + console.log("Turned off change tracking."); + }); + } + + async function logChangeTrackingStates() { + // Logs the current change tracking states of the content controls. + await Word.run(async (context) => { + let trackAddedArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.added]; + let trackDeletedArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.deleted]; + let trackNormalArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.normal]; + + let addedContentControls = context.document.body.getContentControls().getByChangeTrackingStates(trackAddedArray); + let deletedContentControls = context.document.body + .getContentControls() + .getByChangeTrackingStates(trackDeletedArray); + let normalContentControls = context.document.body.getContentControls().getByChangeTrackingStates(trackNormalArray); + + addedContentControls.load(); + deletedContentControls.load(); + normalContentControls.load(); + await context.sync(); + + console.log(`Number of content controls in Added state: ${addedContentControls.items.length}`); + console.log(`Number of content controls in Deleted state: ${deletedContentControls.items.length}`); + console.log(`Number of content controls in Normal state: ${normalContentControls.items.length}`); + }); + } + + async function setup() { + // Adds 4 paragraphs then inserts content controls on the first three paragraphs. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + body.paragraphs.load(); + await context.sync(); + body.paragraphs.items[0].insertContentControl("PlainText"); + body.paragraphs.items[1].insertContentControl("PlainText"); + body.paragraphs.items[2].insertContentControl("RichText"); + console.log("Inserted content controls on the first three paragraphs."); + }); + } + + // 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 how to insert and delete control controls then get their change tracking state. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml b/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml new file mode 100644 index 000000000..de1450052 --- /dev/null +++ b/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml @@ -0,0 +1,240 @@ +order: 8 +id: word-content-controls-insert-and-change-checkbox-content-control +name: Manage checkbox content controls +description: Inserts, updates, retrieves, and deletes checkbox content controls. +host: WORD +api_set: + WordApi: '1.7' +script: + content: |- + document.getElementById("insert-controls").addEventListener("click", () => tryCatch(insertCheckboxContentControls)); + document.getElementById("toggle-control").addEventListener("click", () => tryCatch(toggleCheckboxContentControl)); + document.getElementById("change-controls").addEventListener("click", () => tryCatch(toggleCheckboxContentControls)); + document.getElementById("delete-control").addEventListener("click", () => tryCatch(deleteCheckboxContentControl)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertCheckboxContentControls() { + // Traverses each paragraph of the document and places a checkbox content control at the beginning of each. + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just start each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i] + .getRange(Word.RangeLocation.start) + .insertContentControl(Word.ContentControlType.checkBox); + } + console.log("Checkbox content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function toggleCheckboxContentControl() { + // Toggles the isChecked property of the first checkbox content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,checkboxContentControl/isChecked"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,checkboxContentControl/isChecked"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + const isCheckedBefore = selectedContentControl.checkboxContentControl.isChecked; + console.log("isChecked state before:", `id: ${selectedContentControl.id} ... isChecked: ${isCheckedBefore}`); + selectedContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + selectedContentControl.load("id,checkboxContentControl/isChecked"); + await context.sync(); + + console.log( + "isChecked state after:", + `id: ${selectedContentControl.id} ... isChecked: ${selectedContentControl.checkboxContentControl.isChecked}` + ); + }); + } + + async function toggleCheckboxContentControls() { + // Toggles the isChecked property on all checkbox content controls. + await Word.run(async (context) => { + let contentControls = context.document.getContentControls({ + types: [Word.ContentControlType.checkBox] + }); + contentControls.load("items"); + + await context.sync(); + + const length = contentControls.items.length; + console.log(`Number of checkbox content controls: ${length}`); + + if (length <= 0) { + return; + } + + const checkboxContentControls = []; + for (let i = 0; i < length; i++) { + let contentControl = contentControls.items[i]; + contentControl.load("id,checkboxContentControl/isChecked"); + checkboxContentControls.push(contentControl); + } + + await context.sync(); + + console.log("isChecked state before:"); + const updatedCheckboxContentControls = []; + for (let i = 0; i < checkboxContentControls.length; i++) { + const currentCheckboxContentControl = checkboxContentControls[i]; + const isCheckedBefore = currentCheckboxContentControl.checkboxContentControl.isChecked; + console.log(`id: ${currentCheckboxContentControl.id} ... isChecked: ${isCheckedBefore}`); + + currentCheckboxContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + currentCheckboxContentControl.load("id,checkboxContentControl/isChecked"); + updatedCheckboxContentControls.push(currentCheckboxContentControl); + } + + await context.sync(); + + console.log("isChecked state after:"); + for (let i = 0; i < updatedCheckboxContentControls.length; i++) { + const currentCheckboxContentControl = updatedCheckboxContentControls[i]; + console.log( + `id: ${currentCheckboxContentControl.id} ... isChecked: ${currentCheckboxContentControl.checkboxContentControl.isChecked}` + ); + } + }); + } + + async function deleteCheckboxContentControl() { + // Deletes the first checkbox content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete checkbox content control with id: ${selectedContentControl.id}`); + selectedContentControl.delete(false); + await context.sync(); + + console.log("Deleted checkbox content control."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("Task 3", "Start"); + body.insertParagraph("Task 2", "Start"); + body.insertParagraph("Task 1", "Start"); + body.paragraphs.getLast().insertText("Task 4", "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. + if (error.code === Word.ErrorCodes.itemNotFound) { + console.warn("No checkbox content control is currently selected."); + } else { + console.error(error); + } + } + } + language: typescript +template: + content: |- +
      + This sample demonstrates how to insert, change, and delete checkbox content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      + Insert checkbox content controls on each paragraph. + +

      +

      + Modify isChecked property of the first checkbox content control found in your selected content. + +

      +

      + Modify isChecked property of all checkbox content controls. + +

      +

      + Delete the first checkbox content control found in your selected 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml b/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml new file mode 100644 index 000000000..75d803917 --- /dev/null +++ b/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml @@ -0,0 +1,316 @@ +order: 9 +id: word-content-controls-insert-and-change-combo-box-content-control +name: Manage combo box content controls +description: Inserts, updates, and deletes combo box content controls. +host: WORD +api_set: + WordApi: '1.9' +script: + content: |- + document.getElementById("insert-control").addEventListener("click", () => tryCatch(insertComboBoxContentControl)); + document.getElementById("add-item").addEventListener("click", () => tryCatch(addItemToComboBoxContentControl)); + document.getElementById("get-items").addEventListener("click", () => tryCatch(getListFromComboBoxContentControl)); + document.getElementById("delete-item").addEventListener("click", () => tryCatch(deleteItemFromComboBoxContentControl)); + document.getElementById("delete-list").addEventListener("click", () => tryCatch(deleteListFromComboBoxContentControl)); + document.getElementById("delete-control").addEventListener("click", () => tryCatch(deleteComboBoxContentControl)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertComboBoxContentControl() { + // Places a combo box content control at the end of the selection. + await Word.run(async (context) => { + let selection = context.document.getSelection(); + selection.getRange(Word.RangeLocation.end).insertContentControl(Word.ContentControlType.comboBox); + await context.sync(); + + console.log("Combo box content control inserted at the end of the selection."); + }); + } + + async function addItemToComboBoxContentControl() { + // Adds the provided list item to the first combo box content control in the selection. + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.comboBoxContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); + } + + async function getListFromComboBoxContentControl() { + // Gets the list items from the first combo box content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedComboBox: Word.ComboBoxContentControl = selectedContentControl.comboBoxContentControl; + selectedComboBox.listItems.load("items"); + await context.sync(); + + const currentItems: Word.ContentControlListItemCollection = selectedComboBox.listItems; + console.log(`The list from the combo box content control with ID ${selectedContentControl.id}:`, currentItems); + }); + } + + async function deleteItemFromComboBoxContentControl() { + // Deletes the provided list item from the first combo box content control in the selection. + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedComboBox: Word.ComboBoxContentControl = selectedContentControl.comboBoxContentControl; + selectedComboBox.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.comboBoxContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`); + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); + } + + async function deleteListFromComboBoxContentControl() { + // Deletes the list items from first combo box content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete the list from the combo box content control with ID ${selectedContentControl.id}`); + selectedContentControl.comboBoxContentControl.deleteAllListItems(); + await context.sync(); + + console.log("Deleted the list from the combo box content control."); + }); + } + + async function deleteComboBoxContentControl() { + // Deletes the first combo box content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete combo box content control with ID ${selectedContentControl.id}`); + selectedContentControl.delete(false); + await context.sync(); + + console.log("Deleted combo box content control."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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. + if (error.code === Word.ErrorCodes.itemNotFound) { + console.warn("No combo box content control is currently selected."); + } else { + console.error(error); + } + } + } + language: typescript +template: + content: |- +
      + This sample demonstrates how to insert, change, and delete combo box content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      + Insert a combo box content control after selected text. + +

      +

      +

      Add a unique list item to the first combo box content control found in your selected + content. +
      + + + +

      +

      + Get all list items from the first combo box content control found in your selected content. + +

      +

      +

      Delete a list item from the first combo box content control found in your selected + content. +
      + + + +

      +

      + Delete all list items from the first combo box content control found in your selected content. + +

      +

      + Delete the first combo box content control found in your selected 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/insert-and-change-content-controls.yaml b/samples/word/10-content-controls/insert-and-change-content-controls.yaml new file mode 100644 index 000000000..0221fc952 --- /dev/null +++ b/samples/word/10-content-controls/insert-and-change-content-controls.yaml @@ -0,0 +1,143 @@ +order: 1 +id: word-content-controls-insert-and-change-content-controls +name: Content control basics +description: Inserts, updates, and retrieves content controls. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("insert-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("change-controls").addEventListener("click", () => tryCatch(modifyContentControls)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each with either a even or odd tags. + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + // For even, tag "even". + if (i % 2 === 0) { + contentControl.tag = "even"; + } else { + contentControl.tag = "odd"; + } + } + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function modifyContentControls() { + // Adds title and colors to odd and even content controls and changes their appearance. + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + let evenContentControls = context.document.contentControls.getByTag("even"); + let oddContentControls = context.document.contentControls.getByTag("odd"); + evenContentControls.load("length"); + oddContentControls.load("length"); + + await context.sync(); + + for (let i = 0; i < evenContentControls.items.length; i++) { + // Change a few properties and append a paragraph. + evenContentControls.items[i].set({ + color: "red", + title: "Odd ContentControl #" + (i + 1), + appearance: Word.ContentControlAppearance.tags + }); + evenContentControls.items[i].insertParagraph("This is an odd content control", "End"); + } + + for (let j = 0; j < oddContentControls.items.length; j++) { + // Change a few properties and append a paragraph. + oddContentControls.items[j].set({ + color: "green", + title: "Even ContentControl #" + (j + 1), + appearance: "Tags" + }); + oddContentControls.items[j].insertHtml("This is an even content control", "End"); + } + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to insert and change content control properties. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Insert content controls on each paragraph. +

      + Modify content control appearance and 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml b/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml new file mode 100644 index 000000000..c91d99dd9 --- /dev/null +++ b/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml @@ -0,0 +1,318 @@ +order: 10 +id: word-content-controls-insert-and-change-dropdown-list-content-control +name: Manage dropdown list content controls +description: Inserts, updates, and deletes dropdown list content controls. +host: WORD +api_set: + WordApi: '1.9' +script: + content: |- + document.getElementById("insert-control").addEventListener("click", () => tryCatch(insertDropdownListContentControl)); + document.getElementById("add-item").addEventListener("click", () => tryCatch(addItemToDropdownListContentControl)); + document.getElementById("get-items").addEventListener("click", () => tryCatch(getListFromDropdownListContentControl)); + document.getElementById("delete-item").addEventListener("click", () => tryCatch(deleteItemFromDropdownListContentControl)); + document.getElementById("delete-list").addEventListener("click", () => tryCatch(deleteListFromDropdownListContentControl)); + document.getElementById("delete-control").addEventListener("click", () => tryCatch(deleteDropdownListContentControl)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertDropdownListContentControl() { + // Places a dropdown list content control at the end of the selection. + await Word.run(async (context) => { + let selection = context.document.getSelection(); + selection.getRange(Word.RangeLocation.end).insertContentControl(Word.ContentControlType.dropDownList); + await context.sync(); + + console.log("Dropdown list content control inserted at the end of the selection."); + }); + } + + async function addItemToDropdownListContentControl() { + // Adds the provided list item to the first dropdown list content control in the selection. + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.dropDownListContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); + } + + async function getListFromDropdownListContentControl() { + // Gets the list items from the first dropdown list content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedDropdownList: Word.DropDownListContentControl = selectedContentControl.dropDownListContentControl; + selectedDropdownList.listItems.load("items"); + await context.sync(); + + const currentItems: Word.ContentControlListItemCollection = selectedDropdownList.listItems; + console.log(`The list from the dropdown list content control with ID ${selectedContentControl.id}:`, currentItems); + }); + } + + async function deleteItemFromDropdownListContentControl() { + // Deletes the provided list item from the first dropdown list content control in the selection. + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedDropdownList: Word.DropDownListContentControl = selectedContentControl.dropDownListContentControl; + selectedDropdownList.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.dropDownListContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`) + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); + } + + async function deleteListFromDropdownListContentControl() { + // Deletes the list items from first dropdown list content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log( + `About to delete the list from the dropdown list content control with ID ${selectedContentControl.id}` + ); + selectedContentControl.dropDownListContentControl.deleteAllListItems(); + await context.sync(); + + console.log("Deleted the list from the dropdown list content control."); + }); + } + + async function deleteDropdownListContentControl() { + // Deletes the first dropdown list content control found in the selection. + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete dropdown list content control with ID ${selectedContentControl.id}`); + selectedContentControl.delete(false); + await context.sync(); + + console.log("Deleted dropdown list content control."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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. + if (error.code === Word.ErrorCodes.itemNotFound) { + console.warn("No dropdown list content control is currently selected."); + } else { + console.error(error); + } + } + } + language: typescript +template: + content: |- +
      + This sample demonstrates how to insert, change, and delete dropdown list content controls. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      + Insert a dropdown list content control after selected text. + +

      +

      +

      Add a unique list item to the first dropdown list content control found in your selected + content. +
      + + + +

      +

      + Get all list items from the first dropdown list content control found in your selected content. + +

      +

      +

      Delete a list item from the first dropdown list content control found in your selected + content. +
      + + + +

      +

      + Delete all list items from the first dropdown list content control found in your selected content. + +

      +

      + Delete the first dropdown list content control found in your selected 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/15-images/insert-and-get-pictures.yaml b/samples/word/15-images/insert-and-get-pictures.yaml new file mode 100644 index 000000000..1857f2392 --- /dev/null +++ b/samples/word/15-images/insert-and-get-pictures.yaml @@ -0,0 +1,112 @@ +order: 1 +id: word-images-insert-and-get-pictures +name: Use inline pictures +description: Inserts and gets inline pictures. +host: WORD +api_set: + WordApiDesktop: '1.1' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("insert").addEventListener("click", () => tryCatch(insertImage)); + document.getElementById("get").addEventListener("click", () => tryCatch(getImage)); + + async function insertImage() { + // Inserts an image anchored to the last paragraph. + await Word.run(async (context) => { + context.document.body.paragraphs + .getLast() + .insertParagraph("", "After") + .insertInlinePictureFromBase64(base64Image, "End"); + + await context.sync(); + }); + } + + async function getImage() { + // Gets the first image in the document. + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); + } + + async function setup() { + // Sets up by adding a dummy paragraph. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "End" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "End" + ); + }); + } + + // 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); + } + } + + const base64Image = + "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"; + language: typescript +template: + content: |- +
      + This sample demonstrates how to insert and get inline pictures in a document. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/20-lists/insert-list.yaml b/samples/word/20-lists/insert-list.yaml new file mode 100644 index 000000000..801e8ef30 --- /dev/null +++ b/samples/word/20-lists/insert-list.yaml @@ -0,0 +1,113 @@ +order: 1 +id: word-lists-insert-list +name: Create a list +description: Inserts a new list into the document. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("insert-list").addEventListener("click", () => tryCatch(insertList)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertList() { + // This example starts a new list with the second paragraph. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Themes and styles also help keep your document coordinated. When you click design and choose a new Theme, the pictures, charts, and SmartArt graphics change to match your new theme. When you apply styles, your headings change to match the new theme.", + "Start" + ); + body.insertParagraph( + "Save time in Word with new buttons that show up where you need them. To change the way a picture fits in your document, click it and a button for layout options appears next to it. When you work on a table, click where you want to add a row or a column, and then click the plus sign.", + "Start" + ); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to insert and change lists. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/20-lists/manage-list-styles.yaml b/samples/word/20-lists/manage-list-styles.yaml new file mode 100644 index 000000000..b382c43d4 --- /dev/null +++ b/samples/word/20-lists/manage-list-styles.yaml @@ -0,0 +1,110 @@ +order: 2 +id: word-lists-manage-styles +name: Get list styles +description: This sample shows how to get the list styles in the current document. +author: xiruatms +host: WORD +api_set: + WordApiDesktop: '1.1' +script: + content: |- + document.getElementById("count").addEventListener("click", () => tryCatch(getCount)); + document.getElementById("properties").addEventListener("click", () => tryCatch(getProperties)); + + async function getCount() { + // Gets the available list styles stored with the document. + await Word.run(async (context) => { + const styles: Word.StyleCollection = context.document.getStyles(); + const count = styles.getCount(); + + // Load object to log properties and their values in the console. + styles.load(); + await context.sync(); + + for (let i = 0; i <= count.value; i++) { + if (styles.items[i] && styles.items[i].type == "List") { + console.log(`List style name: ${styles.items[i].nameLocal}`, styles.items[i]); + } + } + }); + } + + async function getProperties() { + // Gets the properties of the specified style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); + } + + // 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 list styles in the current document. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/20-lists/organize-list.yaml b/samples/word/20-lists/organize-list.yaml new file mode 100644 index 000000000..9733c5a65 --- /dev/null +++ b/samples/word/20-lists/organize-list.yaml @@ -0,0 +1,141 @@ +order: 2 +id: word-lists-organize-list +name: Organize a list +description: Shows how to create and organize a list. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("insert-list").addEventListener("click", () => tryCatch(insertOrganizeList)); + document.getElementById("get-list-props").addEventListener("click", () => tryCatch(getListProps)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertOrganizeList() { + // Inserts a list starting with the first paragraph then set numbering and bullet types of the list items. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Use the first paragraph to start a new list. + const list: Word.List = paragraphs.items[0].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set numbering for list level 1. + list.setLevelNumbering(0, Word.ListNumbering.arabic); + + // Set bullet type for list level 5. + list.setLevelBullet(4, Word.ListBullet.arrow); + + // Set list level for the last item in this list. + paragraph.listItem.level = 4; + + list.load("levelTypes"); + + await context.sync(); + }); + } + + async function getListProps() { + // Gets information about the first list in the document. + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Create a list then customize the numbering and bullets. You can also organize the list items into multiple levels and change the style, alignment, etc.", + "Start" + ); + }); + } + + // 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 how to create and organize a list. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml b/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml new file mode 100644 index 000000000..ad67db11b --- /dev/null +++ b/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml @@ -0,0 +1,121 @@ +order: 1 +id: word-paragraph-get-paragraph-on-insertion-point +name: Get paragraph from insertion point +description: Gets the full paragraph containing the insertion point. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("get-paragraph").addEventListener("click", () => tryCatch(getParagraph)); + document.getElementById("get-sentences").addEventListener("click", () => tryCatch(getSentences)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function getParagraph() { + await Word.run(async (context) => { + // The collection of paragraphs of the current selection returns the full paragraphs contained in it. + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + paragraph.load("text"); + + await context.sync(); + console.log(paragraph.text); + }); + } + + async function getSentences() { + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + const sentences: Word.RangeCollection = context.document + .getSelection() + .getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); + sentences.load("$none"); + await context.sync(); + + // Expand the range to the end of the paragraph to get all the complete sentences. + const sentencesToTheEndOfParagraph: Word.RangeCollection = sentences.items[0] + .getRange() + .expandTo( + context.document + .getSelection() + .paragraphs.getFirst() + .getRange(Word.RangeLocation.end) + ) + .getTextRanges(["."], false /* Don't trim spaces*/); + sentencesToTheEndOfParagraph.load("text"); + await context.sync(); + + for (let i = 0; i < sentencesToTheEndOfParagraph.items.length; i++) { + console.log(sentencesToTheEndOfParagraph.items[i].text); + } + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to get the paragraph and paragraph sentences associated with the current insertion point. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Select an insertion point in the document.

      +

      + +

      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/get-text.yaml b/samples/word/25-paragraph/get-text.yaml new file mode 100644 index 000000000..af1de9577 --- /dev/null +++ b/samples/word/25-paragraph/get-text.yaml @@ -0,0 +1,101 @@ +order: 9 +id: word-paragraph-get-text +name: Get text +description: Shows how to get paragraph text, including hidden text and text marked for deletion. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.7' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function run() { + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + + const text = paragraph.getText(); + const textIncludingHidden = paragraph.getText({ IncludeHiddenText: true }); + const textIncludingDeleted = paragraph.getText({ IncludeTextMarkedAsDeleted: true }); + + await context.sync(); + + console.log("Text:- " + text.value, "Including hidden text:- " + textIncludingHidden.value, "Including text marked as deleted:- " + textIncludingDeleted.value); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.insertParagraph( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "End" + ); + }); + } + + // 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 how to get paragraph text, including hidden text and text marked for deletion.

      +
        +
      • How to hide selected text (only available on Windows): +
          +
        1. Open the Font dialog (e.g., right-click the text then select Font from the context menu).
        2. +
        3. Turn on the Hidden checkbox.
        4. +
        5. Choose OK.
        6. +
        +
      • +
      • How to Track changes in + Word.
      • +
      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/25-paragraph/get-word-count.yaml b/samples/word/25-paragraph/get-word-count.yaml new file mode 100644 index 000000000..95ea7e97d --- /dev/null +++ b/samples/word/25-paragraph/get-word-count.yaml @@ -0,0 +1,128 @@ +order: 8 +id: word-paragraph-get-word-count +name: Get word count +description: Counts how many times a word or term appears in the document. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("count").addEventListener("click", () => tryCatch(run)); + + async function run() { + // Counts how many times each term appears in the document. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("text"); + await context.sync(); + + // Split up the document text using existing spaces as the delimiter. + let text = []; + paragraphs.items.forEach((item) => { + let paragraph = item.text.trim(); + if (paragraph) { + paragraph.split(" ").forEach((term) => { + let currentTerm = term.trim(); + if (currentTerm) { + text.push(currentTerm); + } + }); + } + }); + + // Determine the list of unique terms. + let makeTextDistinct = new Set(text); + let distinctText = Array.from(makeTextDistinct); + let allSearchResults = []; + + for (let i = 0; i < distinctText.length; i++) { + let results = context.document.body.search(distinctText[i], { matchCase: true, matchWholeWord: true }); + results.load("text"); + + // Map each search term with its results. + let correlatedResults = { + searchTerm: distinctText[i], + hits: results + }; + + allSearchResults.push(correlatedResults); + } + + await context.sync(); + + // Display the count for each search term. + allSearchResults.forEach((result) => { + let length = result.hits.items.length; + + console.log("Search term: " + result.searchTerm + " => Count: " + length); + }); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.insertParagraph( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "End" + ); + }); + } + + // 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 how to get the count for words and terms in the document body. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Get the word/term count. +

      + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/insert-formatted-text.yaml b/samples/word/25-paragraph/insert-formatted-text.yaml new file mode 100644 index 000000000..073882a0e --- /dev/null +++ b/samples/word/25-paragraph/insert-formatted-text.yaml @@ -0,0 +1,113 @@ +order: 4 +id: word-paragraph-insert-formatted-text +name: Insert formatted text +description: Formats text with pre-built and custom styles. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("add-text").addEventListener("click", () => tryCatch(addFormattedText)); + document.getElementById("add-paragraph").addEventListener("click", () => tryCatch(addFormattedParagraph)); + document.getElementById("add-preset").addEventListener("click", () => tryCatch(addPreStyledFormattedText)); + + async function addFormattedText() { + await Word.run(async (context) => { + // Insert the sentence, then adjust the formatting. + // Note that replace affects the calling object, in this case the entire document body. + // A similar method can also be used at the range level. + const sentence: Word.Range = context.document.body.insertText( + "This is some formatted text!", + "Replace" + ); + sentence.font.set({ + name: "Courier New", + bold: true, + size: 18 + }); + + await context.sync(); + }); + } + + async function addFormattedParagraph() { + await Word.run(async (context) => { + // Second sentence, let's insert it as a paragraph after the previously inserted one. + const secondSentence: Word.Paragraph = context.document.body.insertParagraph( + "This is the first text with a custom style.", + "End" + ); + secondSentence.font.set({ + bold: false, + italic: true, + name: "Berlin Sans FB", + color: "blue", + size: 30 + }); + + await context.sync(); + }); + } + + async function addPreStyledFormattedText() { + await Word.run(async (context) => { + const sentence: Word.Paragraph = context.document.body.insertParagraph( + "To be or not to be", + "End" + ); + + // Use styleBuiltIn to use an enumeration of existing styles. If your style is custom make sure to use: range.style = "name of your style"; + sentence.styleBuiltIn = Word.BuiltInStyleName.intenseReference; + + 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 basic formatted text and apply built-in styles. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/insert-header-and-footer.yaml b/samples/word/25-paragraph/insert-header-and-footer.yaml new file mode 100644 index 000000000..7e820b803 --- /dev/null +++ b/samples/word/25-paragraph/insert-header-and-footer.yaml @@ -0,0 +1,190 @@ +order: 5 +id: word-paragraph-insert-header-and-footer +name: Insert headers and footers +description: Inserts headers and footers in the document. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("add-header").addEventListener("click", () => tryCatch(addHeader)); + document.getElementById("add-footer").addEventListener("click", () => tryCatch(addFooter)); + document.getElementById("add-first-page-header").addEventListener("click", () => tryCatch(addFirstPageHeader)); + document.getElementById("add-first-page-footer").addEventListener("click", () => tryCatch(addFirstPageFooter)); + document.getElementById("add-even-pages-header").addEventListener("click", () => tryCatch(addEvenPagesHeader)); + document.getElementById("add-even-pages-footer").addEventListener("click", () => tryCatch(addEvenPagesFooter)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function addHeader() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getHeader(Word.HeaderFooterType.primary) + .insertParagraph("This is a primary header.", "End"); + + await context.sync(); + }); + } + + async function addFooter() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getFooter("Primary") + .insertParagraph("This is a primary footer.", "End"); + + await context.sync(); + }); + } + + async function addFirstPageHeader() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getHeader("FirstPage") + .insertParagraph("This is a first-page header.", "End"); + + await context.sync(); + }); + } + + async function addFirstPageFooter() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getFooter(Word.HeaderFooterType.firstPage) + .insertParagraph("This is a first-page footer.", "End"); + + await context.sync(); + }); + } + + async function addEvenPagesHeader() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getHeader(Word.HeaderFooterType.evenPages) + .insertParagraph("This is an even-pages header.", "End"); + + await context.sync(); + }); + } + + async function addEvenPagesFooter() { + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getFooter("EvenPages") + .insertParagraph("This is an even-pages footer.", "End"); + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + // Set up text in the document body. + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "HeaderFooterType.firstPage applies the header or footer to the first page of the current section. HeaderFooterType.evenPages applies the header or footer to the even pages of the current section. By default, HeaderFooterType.primary applies the header or footer to all pages in the current section. However, if either or both options for FirstPage and EvenPages are set, Primary excludes those pages.", + "Start" + ); + body.insertBreak(Word.BreakType.page, Word.InsertLocation.end); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "End" + ); + body.insertBreak(Word.BreakType.page, Word.InsertLocation.end); + body.insertParagraph( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "End" + ); + + // Clear any headers and footers. + const section: Word.Section = context.document.sections.getFirst(); + + section.getHeader("Primary").clear(); + section.getHeader("FirstPage").clear(); + section.getHeader("EvenPages").clear(); + + section.getFooter("Primary").clear(); + section.getFooter("FirstPage").clear(); + section.getFooter("EvenPages").clear(); + }); + } + + // 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 inserts headers and footers in the document. +
      +
      +

      Set up

      +

      1. Set up sample text. + +

      2. Open the Header & Footer ribbon (refer to Edit your + existing headers and footers for details). +

      +
      +

      Try it out

      +

      Apply to all pages

      + + +
      To see the "Primary" header/footer in the document, turn off the Different First Page and + Different Odd & Even Pages options in the + Header & Footer ribbon.
      +

      Apply to the first page

      + + +
      To see the "FirstPage" header/footer in the document, turn on the Different First Page option in the Header & Footer ribbon then scroll to the first page.
      +

      Apply to all even pages

      + + +
      To see the "EvenPages" header/footer in the document, turn on the Different Odd & Even Pages option in the Header & Footer ribbon then scroll to an even-numbered page.
      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/insert-in-different-locations.yaml b/samples/word/25-paragraph/insert-in-different-locations.yaml new file mode 100644 index 000000000..ad6572d46 --- /dev/null +++ b/samples/word/25-paragraph/insert-in-different-locations.yaml @@ -0,0 +1,156 @@ +order: 3 +id: word-paragraph-insert-in-different-locations +name: Insert content at different locations +description: Inserts content at different document locations. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.2' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("before").addEventListener("click", () => tryCatch(before)); + document.getElementById("start").addEventListener("click", () => tryCatch(start)); + document.getElementById("end").addEventListener("click", () => tryCatch(end)); + document.getElementById("after").addEventListener("click", () => tryCatch(after)); + document.getElementById("replace").addEventListener("click", () => tryCatch(replace)); + + async function before() { + await Word.run(async (context) => { + // Let's insert before the first paragraph. + const range: Word.Paragraph = context.document.body.paragraphs.getFirst().insertParagraph("This is Before", "Before"); + range.font.highlightColor = "yellow"; + + await context.sync(); + }); + } + + async function start() { + await Word.run(async (context) => { + // This button assumes before() ran. + // Get the next paragraph and insert text at the beginning. Note that there are invalid locations depending on the object. For instance, insertParagraph and "before" on a paragraph object is not a valid combination. + const range: Word.Range = context.document.body.paragraphs + .getFirst() + .getNext() + .insertText("This is Start", "Start"); + range.font.highlightColor = "blue"; + range.font.color = "white"; + + await context.sync(); + }); + } + + async function end() { + await Word.run(async (context) => { + // Insert text at the end of a paragraph. + const range: Word.Range = context.document.body.paragraphs + .getFirst() + .getNext() + .insertText(" This is End", "End"); + range.font.highlightColor = "green"; + range.font.color = "white"; + + await context.sync(); + }); + } + + async function after() { + await Word.run(async (context) => { + // Insert a paragraph after an existing one. + const range: Word.Paragraph = context.document.body.paragraphs + .getFirst() + .getNext() + .insertParagraph("This is After", "After"); + range.font.highlightColor = "red"; + range.font.color = "white"; + + await context.sync(); + }); + } + + async function replace() { + await Word.run(async (context) => { + // Replace the last paragraph. + const range: Word.Range = context.document.body.paragraphs.getLast().insertText("Just replaced the last paragraph!", "Replace"); + range.font.highlightColor = "black"; + range.font.color = "white"; + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + }); + } + + 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 a variety of insert locations available in the API. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/insert-line-and-page-breaks.yaml b/samples/word/25-paragraph/insert-line-and-page-breaks.yaml new file mode 100644 index 000000000..140084bfa --- /dev/null +++ b/samples/word/25-paragraph/insert-line-and-page-breaks.yaml @@ -0,0 +1,100 @@ +order: 2 +id: word-paragraph-insert-line-and-page-breaks +name: Insert breaks +description: Inserts page and line breaks in a document. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.2' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("line").addEventListener("click", () => tryCatch(insertLineBreak)); + document.getElementById("page").addEventListener("click", () => tryCatch(insertPageBreak)); + + async function insertLineBreak() { + Word.run(async (context) => { + context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.line, "After"); + + await context.sync(); + console.log("success"); + }); + } + + async function insertPageBreak() { + await Word.run(async (context) => { + context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.page, "After"); + + await context.sync(); + console.log("success"); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + + console.log("success"); + }); + } + + 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 how to insert page and line breaks. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/25-paragraph/onadded-event.yaml b/samples/word/25-paragraph/onadded-event.yaml new file mode 100644 index 000000000..9469153a3 --- /dev/null +++ b/samples/word/25-paragraph/onadded-event.yaml @@ -0,0 +1,120 @@ +order: 10 +id: word-paragraph-onadded-event +name: On adding paragraphs +description: Registers, triggers, and deregisters the onParagraphAdded event that tracks the addition of paragraphs. +host: WORD +api_set: + WordApi: '1.6' +script: + content: |- + document.getElementById("register-event-handler").addEventListener("click", () => tryCatch(registerEventHandler)); + document.getElementById("insert-paragraphs").addEventListener("click", () => tryCatch(insertParagraphs)); + document.getElementById("get-paragraph-by-id").addEventListener("click", () => tryCatch(getParagraphById)); + document.getElementById("deregister-event-handler").addEventListener("click", () => tryCatch(deregisterEventHandler)); + + let eventContext; + + async function registerEventHandler() { + // Registers the onParagraphAdded event handler on the document. + await Word.run(async (context) => { + eventContext = context.document.onParagraphAdded.add(paragraphAdded); + await context.sync(); + + console.log("Added event handler for when paragraphs are added."); + }); + } + + async function paragraphAdded(event: Word.ParagraphAddedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were added:`, event.uniqueLocalIds); + }); + } + + async function getParagraphById() { + await Word.run(async (context) => { + const paragraphId = (document.getElementById("paragraph-id") as HTMLInputElement).value; + const paragraph: Word.Paragraph = context.document.getParagraphByUniqueLocalId(paragraphId); + paragraph.load(); + await paragraph.context.sync(); + + console.log(paragraph); + }); + } + + async function insertParagraphs() { + // Inserts two paragraphs within the document body. + await Word.run(async (context) => { + const paragraphCount = 2; + for (let i = 0; i < paragraphCount; i++) { + context.document.body.insertParagraph(`Paragraph Test ${i + 1}`, "End"); + } + + console.log("Paragraphs inserted: " + paragraphCount); + await context.sync(); + }); + } + + async function deregisterEventHandler() { + await Word.run(eventContext.context, async (context) => { + eventContext.remove(); + await context.sync(); + }); + + eventContext = null; + console.log("Removed event handler that was tracking when paragraphs are added."); + } + + // 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 how to use the onAdded event with paragraphs. +
      +
      +

      Try it out

      + + +

      From the console, copy a paragraph ID and paste it into the following field.
      + + + +

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/25-paragraph/onchanged-event.yaml b/samples/word/25-paragraph/onchanged-event.yaml new file mode 100644 index 000000000..1653214ae --- /dev/null +++ b/samples/word/25-paragraph/onchanged-event.yaml @@ -0,0 +1,121 @@ +order: 11 +id: word-paragraph-onchanged-event +name: On changing content in paragraphs +description: Registers, triggers, and deregisters the onParagraphChanged event that tracks when content is changed in paragraphs. +host: WORD +api_set: + WordApi: '1.6' +script: + content: |- + document.getElementById("register-event-handler").addEventListener("click", () => tryCatch(registerEventHandler)); + document.getElementById("get-paragraph-by-id").addEventListener("click", () => tryCatch(getParagraphById)); + document.getElementById("deregister-event-handler").addEventListener("click", () => tryCatch(deregisterEventHandler)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContext; + + async function registerEventHandler() { + // Registers the onParagraphChanged event handler on the document. + await Word.run(async (context) => { + eventContext = context.document.onParagraphChanged.add(paragraphChanged); + await context.sync(); + + console.log("Added event handler for when content is changed in paragraphs."); + }); + } + + async function paragraphChanged(event: Word.ParagraphChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs where content was changed:`, event.uniqueLocalIds); + }); + } + + async function getParagraphById() { + await Word.run(async (context) => { + const paragraphId = (document.getElementById("paragraph-id") as HTMLInputElement).value; + const paragraph: Word.Paragraph = context.document.getParagraphByUniqueLocalId(paragraphId); + paragraph.load(); + await paragraph.context.sync(); + + console.log(paragraph); + }); + } + + async function deregisterEventHandler() { + await Word.run(eventContext.context, async (context) => { + eventContext.remove(); + await context.sync(); + }); + + eventContext = null; + console.log("Removed event handler that was tracking content changes in paragraphs."); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("Paragraph 1", "End"); + body.insertParagraph("Paragraph 2", "End"); + }); + } + + // 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 how to use the onChanged event with paragraphs. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + +

      +

      Within a paragraph, make a change in the text. Then, from the console, copy the paragraph + ID where content was changed and paste into the following field.
      + + + +

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/25-paragraph/ondeleted-event.yaml b/samples/word/25-paragraph/ondeleted-event.yaml new file mode 100644 index 000000000..248a6de4c --- /dev/null +++ b/samples/word/25-paragraph/ondeleted-event.yaml @@ -0,0 +1,121 @@ +order: 12 +id: word-paragraph-ondeleted-event +name: On deleting paragraphs +description: Registers, triggers, and deregisters the onParagraphDeleted event that tracks the removal of paragraphs. +host: WORD +api_set: + WordApi: '1.6' +script: + content: |- + document.getElementById("register-event-handler").addEventListener("click", () => tryCatch(registerEventHandler)); + document.getElementById("delete-paragraph").addEventListener("click", () => tryCatch(deleteParagraph)); + document.getElementById("deregister-event-handler").addEventListener("click", () => tryCatch(deregisterEventHandler)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContext; + + async function registerEventHandler() { + // Registers the onParagraphDeleted event handler on the document. + await Word.run(async (context) => { + eventContext = context.document.onParagraphDeleted.add(paragraphDeleted); + await context.sync(); + + console.log("Added event handlers for when paragraphs are deleted."); + }); + } + + async function paragraphDeleted(event: Word.ParagraphDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were deleted:`, event.uniqueLocalIds); + }); + } + + async function deleteParagraph() { + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("items"); + await context.sync(); + + if (paragraphs.items.length == 0) { + console.log("There are no paragraphs in this document."); + } else { + console.log("Paragraph to be deleted:", paragraphs.items[0]); + paragraphs.items[0].delete(); + await context.sync(); + } + }); + } + + async function deregisterEventHandler() { + await Word.run(eventContext.context, async (context) => { + eventContext.remove(); + await context.sync(); + }); + + eventContext = null; + console.log("Removed event handler that was tracking when paragraphs are deleted."); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("Paragraph 1", "End"); + body.insertParagraph("Paragraph 2", "End"); + body.insertParagraph("Paragraph 3", "End"); + }); + } + + // 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 how to use the onDeleted event with paragraphs. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/25-paragraph/paragraph-properties.yaml b/samples/word/25-paragraph/paragraph-properties.yaml new file mode 100644 index 000000000..b0cb4b0af --- /dev/null +++ b/samples/word/25-paragraph/paragraph-properties.yaml @@ -0,0 +1,155 @@ +order: 6 +id: word-paragraph-paragraph-properties +name: Paragraph properties +description: Sets indentation, space between paragraphs, and other paragraph properties. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("indent").addEventListener("click", () => tryCatch(indent)); + document.getElementById("spacing").addEventListener("click", () => tryCatch(spacing)); + document.getElementById("space-after").addEventListener("click", () => tryCatch(spaceAfter)); + document.getElementById("line-unit-spacing-after").addEventListener("click", () => tryCatch(spaceAfterInLines)); + document.getElementById("line-unit-spacing-before").addEventListener("click", () => tryCatch(spaceBeforeInLines)); + document.getElementById("align").addEventListener("click", () => tryCatch(align)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function indent() { + await Word.run(async (context) => { + // Indent the first paragraph. + context.document.body.paragraphs.getFirst().leftIndent = 75; //units = points + + return context.sync(); + }); + } + + async function spacing() { + await Word.run(async (context) => { + // Adjust line spacing. + context.document.body.paragraphs.getFirst().lineSpacing = 20; + + await context.sync(); + }); + } + + async function spaceAfter() { + await Word.run(async (context) => { + // Set the space (in points) after the first paragraph. + context.document.body.paragraphs.getFirst().spaceAfter = 20; + + await context.sync(); + }); + } + + async function spaceAfterInLines() { + await Word.run(async (context) => { + // Set the space (in line units) after the first paragraph. + context.document.body.paragraphs.getFirst().lineUnitAfter = 1; + + await context.sync(); + }); + } + + async function spaceBeforeInLines() { + await Word.run(async (context) => { + // Set the space (in line units) before the first paragraph. + context.document.body.paragraphs.getFirst().lineUnitBefore = 1; + + await context.sync(); + }); + } + + async function align() { + await Word.run(async (context) => { + // Center last paragraph alignment. + context.document.body.paragraphs.getLast().alignment = "Centered"; + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + body.paragraphs.getFirst().alignment = "Left"; + body.paragraphs.getLast().alignment = Word.Alignment.left; + }); + } + + // 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 paragraph property usage. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/25-paragraph/search.yaml b/samples/word/25-paragraph/search.yaml new file mode 100644 index 000000000..0dc258279 --- /dev/null +++ b/samples/word/25-paragraph/search.yaml @@ -0,0 +1,118 @@ +order: 7 +id: word-paragraph-search +name: Search +description: Shows basic and advanced search capabilities. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("basic-search").addEventListener("click", () => tryCatch(basicSearch)); + document.getElementById("wildcard-search").addEventListener("click", () => tryCatch(wildcardSearch)); + + async function basicSearch() { + // Does a basic text search and highlights matches in the document. + await Word.run(async (context) => { + const results : Word.RangeCollection = context.document.body.search("extend"); + results.load("length"); + + await context.sync(); + + // Let's traverse the search results and highlight matches. + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.highlightColor = "yellow"; + } + + await context.sync(); + }); + } + + async function wildcardSearch() { + // Does a wildcard search and highlights matches in the document. + await Word.run(async (context) => { + // Construct a wildcard expression and set matchWildcards to true in order to use wildcards. + const results : Word.RangeCollection = context.document.body.search("$*.[0-9][0-9]", { matchWildcards: true }); + results.load("length"); + + await context.sync(); + + // Let's traverse the search results and highlight matches. + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.highlightColor = "red"; + results.items[i].font.color = "white"; + } + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + + await context.sync(); + }); + } + + 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 and advanced search capabilities of the API. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/30-properties/get-built-in-properties.yaml b/samples/word/30-properties/get-built-in-properties.yaml new file mode 100644 index 000000000..0fe8a3dbd --- /dev/null +++ b/samples/word/30-properties/get-built-in-properties.yaml @@ -0,0 +1,64 @@ +order: 1 +id: word-properties-get-built-in-properties +name: Built-in document properties +description: Gets built-in document properties. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(getProperties)); + + async function getProperties() { + await Word.run(async (context) => { + const builtInProperties: Word.DocumentProperties = context.document.properties; + builtInProperties.load("*"); // Let's get all! + + await context.sync(); + console.log(JSON.stringify(builtInProperties, null, 4)); + }); + } + + // 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 how to get the built-in properties of a Word document. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/30-properties/read-write-custom-document-properties.yaml b/samples/word/30-properties/read-write-custom-document-properties.yaml new file mode 100644 index 000000000..b09a55f54 --- /dev/null +++ b/samples/word/30-properties/read-write-custom-document-properties.yaml @@ -0,0 +1,91 @@ +order: 2 +id: word-properties-read-write-custom-document-properties +name: Custom document properties +description: Adds and reads custom document properties of different types. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("number").addEventListener("click", () => tryCatch(insertNumericProperty)); + document.getElementById("string").addEventListener("click", () => tryCatch(insertStringProperty)); + document.getElementById("read").addEventListener("click", () => tryCatch(readCustomDocumentProperties)); + + async function insertNumericProperty() { + await Word.run(async (context) => { + context.document.properties.customProperties.add("Numeric Property", 1234); + + await context.sync(); + console.log("Property added"); + }); + } + + async function insertStringProperty() { + await Word.run(async (context) => { + context.document.properties.customProperties.add("String Property", "Hello World!"); + + await context.sync(); + console.log("Property added"); + }); + } + + async function readCustomDocumentProperties() { + await Word.run(async (context) => { + const properties: Word.CustomPropertyCollection = context.document.properties.customProperties; + properties.load("key,type,value"); + + await context.sync(); + for (let i = 0; i < properties.items.length; i++) + console.log("Property Name:" + properties.items[i].key + "; Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].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 demonstrates how to insert custom document properties of different data types and how to read them. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/35-ranges/compare-location.yaml b/samples/word/35-ranges/compare-location.yaml new file mode 100644 index 000000000..ca1a6bcb4 --- /dev/null +++ b/samples/word/35-ranges/compare-location.yaml @@ -0,0 +1,125 @@ +order: 3 +id: word-ranges-compare-location +name: Compare range locations +description: This sample shows how to compare the locations of two ranges. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("compare").addEventListener("click", () => tryCatch(compareLocations)); + document.getElementById("compare-to-selection").addEventListener("click", () => tryCatch(compareWithSelection)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function compareLocations() { + // Compares the location of one paragraph in relation to another paragraph. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("items"); + + await context.sync(); + + const firstParagraphAsRange: Word.Range = paragraphs.items[0].getRange(); + const secondParagraphAsRange: Word.Range = paragraphs.items[1].getRange(); + + const comparedLocation = firstParagraphAsRange.compareLocationWith(secondParagraphAsRange); + + await context.sync(); + + const locationValue: Word.LocationRelation = comparedLocation.value; + console.log(`Location of the first paragraph in relation to the second paragraph: ${locationValue}`); + }); + } + + async function compareWithSelection() { + // Compares the location of the second paragraph in relation to the cursor's location. + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("items"); + + await context.sync(); + + const secondParagraphAsRange: Word.Range = paragraphs.items[1].getRange(); + const selection: Word.Range = context.document.getSelection(); + + const comparedLocation = secondParagraphAsRange.compareLocationWith(selection); + + await context.sync(); + + const locationValue: Word.LocationRelation = comparedLocation.value; + console.log(`Location of the second paragraph in relation to the cursor's location: ${locationValue}`); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + }); + } + + 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 how to compare locations of ranges. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Compare location of first paragraph with location of second paragraph

      + +

      Compare location of second paragraph with cursor's location

      +

      +

      Move cursor or select text in the document.
      + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/35-ranges/get-pages.yaml b/samples/word/35-ranges/get-pages.yaml new file mode 100644 index 000000000..15f5ca0e4 --- /dev/null +++ b/samples/word/35-ranges/get-pages.yaml @@ -0,0 +1,288 @@ +order: 4 +id: word-ranges-get-pages +name: Work with pages, panes, and windows +description: Shows how to work with pages, panes, and windows. +author: yilin4 +host: WORD +api_set: + WordApiDesktop: '1.2' +script: + content: | + document.getElementById("get-pages-selected-range").addEventListener("click", () => tryCatch(getPagesOfSelectedRange)); + document + .getElementById("get-pages-third-paragraph") + .addEventListener("click", () => tryCatch(getPagesOfThirdParagraph)); + document + .getElementById("get-pages-enclosing-viewport") + .addEventListener("click", () => tryCatch(getPagesEnclosingViewport)); + document.getElementById("get-all-pages").addEventListener("click", () => tryCatch(getAllPages)); + document.getElementById("get-all-panes").addEventListener("click", () => tryCatch(getAllPanes)); + document.getElementById("get-all-windows").addEventListener("click", () => tryCatch(getAllWindows)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function getPagesOfSelectedRange() { + await Word.run(async (context) => { + // Gets pages of the selection. + const pages: Word.PageCollection = context.document.getSelection().pages; + pages.load(); + await context.sync(); + + // Log info for pages included in selection. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index info for page ${i + 1} in the selection: ${pagesIndexes[i].index}`); + console.log("Text of that page in the selection:", pagesText[i].text); + } + }); + } + + async function getPagesOfThirdParagraph() { + await Word.run(async (context) => { + // Gets the pages that contain the third paragraph. + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load(); + await context.sync(); + + const paraThree = paragraphs.items[2]; + const rangeOfParagraph = paraThree.getRange(); + const pages: Word.PageCollection = rangeOfParagraph.pages; + pages.load(); + await context.sync(); + + // Log info for pages in range. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index of page ${i + 1} that contains the third paragraph: ${pagesIndexes[i].index}`); + console.log("Text of that page:", pagesText[i].text); + } + }); + } + + async function getPagesEnclosingViewport() { + await Word.run(async (context) => { + // Gets the pages enclosing the viewport. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get pages enclosing the viewport. + const pages: Word.PageCollection = activePane.pagesEnclosingViewport; + pages.load(); + + await context.sync(); + + // Log the number of pages. + const pageCount = pages.items.length; + console.log(`Number of pages enclosing the viewport: ${pageCount}`); + + // Log index info of these pages. + const pagesIndexes = []; + for (let i = 0; i < pageCount; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + } + }); + } + + async function getAllPages() { + await Word.run(async (context) => { + // Gets the first paragraph of each page. + console.log("Getting first paragraph of each page..."); + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get all pages. + const pages: Word.PageCollection = activePane.pages; + pages.load(); + + await context.sync(); + + // Get page index and paragraphs of each page. + const pagesIndexes = []; + const pagesNumberOfParagraphs = []; + const pagesFirstParagraphText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const paragraphs = page.getRange().paragraphs; + paragraphs.load("items/length"); + pagesNumberOfParagraphs.push(paragraphs); + + const firstParagraph = paragraphs.getFirst(); + firstParagraph.load("text"); + pagesFirstParagraphText.push(firstParagraph); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + console.log(`Number of paragraphs: ${pagesNumberOfParagraphs[i].items.length}`); + console.log("First paragraph's text:", pagesFirstParagraphText[i].text); + } + }); + } + + async function getAllPanes() { + await Word.run(async (context) => { + // Gets all the panes in the active document window. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load("panes/items/length"); + + await context.sync(); + + const panes: Word.PaneCollection = activeWindow.panes; + console.log(`Number of panes in the current document window: ${panes.items.length}`); + }); + } + + async function getAllWindows() { + await Word.run(async (context) => { + // Gets the document windows. + const windows: Word.WindowCollection = context.document.windows; + windows.load("windows/items/length"); + + await context.sync(); + + console.log(`Number of windows for this document: ${windows.items.length}`); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertBreak(Word.BreakType.page, Word.InsertLocation.end); + body.insertParagraph( + "Themes and styles also help keep your document coordinated. When you click design and choose a new Theme, the pictures, charts, and SmartArt graphics change to match your new theme. When you apply styles, your headings change to match the new theme.", + "End" + ); + body.insertText( + "Save time in Word with new buttons that show up where you need them. To change the way a picture fits in your document, click it and a button for layout options appears next to it. When you work on a table, click where you want to add a row or a column, and then click the plus sign.", + "Start" + ); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to work with pages, panes, and windows. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/35-ranges/scroll-to-range.yaml b/samples/word/35-ranges/scroll-to-range.yaml new file mode 100644 index 000000000..b7fd13481 --- /dev/null +++ b/samples/word/35-ranges/scroll-to-range.yaml @@ -0,0 +1,100 @@ +order: 1 +id: word-ranges-scroll-to-range +name: Scroll to a range +description: Scrolls to a range with and without selection. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.2' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("scroll").addEventListener("click", () => tryCatch(scroll)); + document.getElementById("scroll-end").addEventListener("click", () => tryCatch(scrollEnd)); + + async function scroll() { + await Word.run(async (context) => { + // If select is called with no parameters, it selects the object. + context.document.body.paragraphs.getLast().select(); + + await context.sync(); + }); + } + + async function scrollEnd() { + await Word.run(async (context) => { + // Select can be at the start or end of a range; this by definition moves the insertion point without selecting the range. + context.document.body.paragraphs.getLast().select(Word.SelectionMode.end); + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + const firstSentence: Word.Paragraph = body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + firstSentence.insertBreak(Word.BreakType.page, "After"); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to scroll to 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/35-ranges/split-words-of-first-paragraph.yaml b/samples/word/35-ranges/split-words-of-first-paragraph.yaml new file mode 100644 index 000000000..b0db6d9a3 --- /dev/null +++ b/samples/word/35-ranges/split-words-of-first-paragraph.yaml @@ -0,0 +1,100 @@ +order: 2 +id: word-ranges-split-words-of-first-paragraph +name: Split a paragraph into ranges +description: Splits a paragraph into word ranges and then traverses all the ranges to format each word, producing a "karaoke" effect. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("highlight").addEventListener("click", () => tryCatch(highlightWords)); + + async function highlightWords() { + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + const words = paragraph.split([" "], true /* trimDelimiters*/, true /* trimSpaces */); + words.load("text"); + + await context.sync(); + + for (let i = 0; i < words.items.length; i++) { + if (i >= 1) { + words.items[i - 1].font.highlightColor = "#FFFFFF"; + } + words.items[i].font.highlightColor = "#FFFF00"; + + await context.sync(); + await pause(200); + } + }); + } + + function pause(milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + }); + } + + 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 splitting and traversing 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/40-tables/manage-custom-style.yaml b/samples/word/40-tables/manage-custom-style.yaml new file mode 100644 index 000000000..cfd5c0258 --- /dev/null +++ b/samples/word/40-tables/manage-custom-style.yaml @@ -0,0 +1,435 @@ +order: 3 +id: word-tables-manage-custom-style +name: Manage custom table style +description: Shows how to manage primarily margins and alignments of a custom table style in the current document. +host: WORD +api_set: + WordApiDesktop: '1.1' +script: + content: |- + document.getElementById("add-style").addEventListener("click", () => tryCatch(addStyle)); + document.getElementById("apply-style").addEventListener("click", () => tryCatch(applyStyle)); + document.getElementById("show-style-properties").addEventListener("click", () => tryCatch(getTableStyle)); + document.getElementById("set-alignment").addEventListener("click", () => tryCatch(setAlignment)); + document.getElementById("set-allow-break-across-page").addEventListener("click", () => tryCatch(setAllowBreakAcrossPage)); + document.getElementById("set-top-cell-margin").addEventListener("click", () => tryCatch(setTopCellMargin)); + document.getElementById("set-bottom-cell-margin").addEventListener("click", () => tryCatch(setBottomCellMargin)); + document.getElementById("set-left-cell-margin").addEventListener("click", () => tryCatch(setLeftCellMargin)); + document.getElementById("set-right-cell-margin").addEventListener("click", () => tryCatch(setRightCellMargin)); + document.getElementById("set-cell-spacing").addEventListener("click", () => tryCatch(setCellSpacing)); + document.getElementById("delete-style").addEventListener("click", () => tryCatch(deleteStyle)); + document.getElementById("import-styles-from-json").addEventListener("click", () => tryCatch(importStylesFromJson)); + + async function addStyle() { + // Adds a new table style. + const newStyleName = (document.getElementById("new-style-name") as HTMLInputElement).value; + if (newStyleName == "") { + console.warn("Enter a style name to add."); + return; + } + + await Word.run(async (context) => { + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(newStyleName); + style.load(); + await context.sync(); + + if (!style.isNullObject) { + console.warn( + `There's an existing style with the same name '${newStyleName}'! Please provide another style name.` + ); + return; + } + + context.document.addStyle(newStyleName, Word.StyleType.table); + await context.sync(); + + console.log(newStyleName + " has been added to the style list."); + }); + } + + async function applyStyle() { + // Applies the specified style to a new table. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + await Word.run(async (context) => { + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.table) { + console.warn(`The '${styleName}' style isn't a table style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + const data = [ + ["Tokyo", "Beijing", "Seattle"], + ["Apple", "Orange", "Pineapple"] + ]; + const table: Word.Table = body.insertTable(2, 3, "Start", data); + table.style = style.nameLocal; + table.styleFirstColumn = false; + await context.sync(); + + console.log(`'${styleName}' style applied to first table.`, style); + } + }); + } + + async function getTableStyle() { + // Gets the table style properties and displays them in the form. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.load(); + await context.sync(); + + if (tableStyle.isNullObject) { + console.warn(`There's no existing table style with the name '${styleName}'.`); + return; + } + + console.log(tableStyle); + (document.getElementById("alignment") as HTMLInputElement).value = tableStyle.alignment; + (document.getElementById("allow-break-across-page") as HTMLInputElement).value = tableStyle.allowBreakAcrossPage.toString(); + (document.getElementById("top-cell-margin") as HTMLInputElement).value = tableStyle.topCellMargin; + (document.getElementById("bottom-cell-margin") as HTMLInputElement).value = tableStyle.bottomCellMargin; + (document.getElementById("left-cell-margin") as HTMLInputElement).value = tableStyle.leftCellMargin; + (document.getElementById("right-cell-margin") as HTMLInputElement).value = tableStyle.rightCellMargin; + (document.getElementById("cell-spacing") as HTMLInputElement).value = tableStyle.cellSpacing; + }); + } + + async function setAlignment() { + // Sets the table alignment. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const alignment = (document.getElementById("alignment") as HTMLInputElement).value; + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.alignment = alignment as Word.Alignment; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Alignment: " + tableStyle.alignment); + }); + } + + async function setAllowBreakAcrossPage() { + // Sets the allowBreakAcrossPage property. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const allowBreakAcrossPage = (document.getElementById("allow-break-across-page") as HTMLInputElement).value; + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.allowBreakAcrossPage = allowBreakAcrossPage === "true"; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("allowBreakAcrossPage: " + tableStyle.allowBreakAcrossPage); + }); + } + + async function setTopCellMargin() { + // Sets the top cell margin. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const topCellMargin = Number((document.getElementById("top-cell-margin") as HTMLInputElement).value); + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.topCellMargin = topCellMargin; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Top cell margin: " + tableStyle.topCellMargin); + }); + } + + async function setBottomCellMargin() { + // Sets the bottom cell margin. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const bottomCellMargin = Number((document.getElementById("bottom-cell-margin") as HTMLInputElement).value); + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.bottomCellMargin = bottomCellMargin; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Bottom cell margin: " + tableStyle.bottomCellMargin); + }); + } + + async function setLeftCellMargin() { + // Sets the left cell margin. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const leftCellMargin = Number((document.getElementById("left-cell-margin") as HTMLInputElement).value); + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.leftCellMargin = leftCellMargin; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Left cell margin: " + tableStyle.leftCellMargin); + }); + } + + async function setRightCellMargin() { + // Sets the right cell margin. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const rightCellMargin = Number((document.getElementById("right-cell-margin") as HTMLInputElement).value); + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.rightCellMargin = rightCellMargin; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Right cell margin: " + tableStyle.rightCellMargin); + }); + } + + async function setCellSpacing() { + // Sets the cell spacing. + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + await Word.run(async (context) => { + const cellSpacing = Number((document.getElementById("cell-spacing") as HTMLInputElement).value); + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.cellSpacing = cellSpacing; + await context.sync(); + + tableStyle.load(); + await context.sync(); + console.log("Cell spacing: " + tableStyle.cellSpacing); + }); + } + + async function deleteStyle() { + // Deletes the custom style. + const styleName = (document.getElementById("style-name-to-delete") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to delete."); + return; + } + + await Word.run(async (context) => { + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.delete(); + console.log(`Successfully deleted custom style '${styleName}'.`); + } + }); + } + + async function importStylesFromJson() { + // Imports styles from JSON. + await Word.run(async (context) => { + const str = + '{"styles":[{"baseStyle":"Default Paragraph Font","builtIn":false,"inUse":true,"linked":false,"nameLocal":"NewCharStyle","priority":2,"quickStyle":true,"type":"Character","unhideWhenUsed":false,"visibility":false,"paragraphFormat":null,"font":{"name":"DengXian Light","size":16.0,"bold":true,"italic":false,"color":"#F1A983","underline":"None","subscript":false,"superscript":true,"strikeThrough":true,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#FF0000"}},{"baseStyle":"Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewParaStyle","nameLocal":"NewParaStyle","priority":1,"quickStyle":true,"type":"Paragraph","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Centered","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":72.0,"lineSpacing":18.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":72.0,"spaceAfter":30.0,"spaceBefore":30.0,"widowControl":true},"font":{"name":"DengXian","size":14.0,"bold":true,"italic":true,"color":"#8DD873","underline":"Single","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":true,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#00FF00"}},{"baseStyle":"Table Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewTableStyle","nameLocal":"NewTableStyle","priority":100,"type":"Table","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Left","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":0.0,"lineSpacing":12.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":0.0,"spaceAfter":0.0,"spaceBefore":0.0,"widowControl":true},"font":{"name":"DengXian","size":20.0,"bold":false,"italic":true,"color":"#D86DCB","underline":"None","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"tableStyle":{"allowBreakAcrossPage":true,"alignment":"Left","bottomCellMargin":0.0,"leftCellMargin":0.08,"rightCellMargin":0.08,"topCellMargin":0.0,"cellSpacing":0.0},"shading":{"backgroundPatternColor":"#60CAF3"}}]}'; + const styles = context.document.importStylesFromJson(str); + + // If you'd like to set how conflicting styles are handled, use the importedStylesConflictBehavior parameter that was introduced in the Desktop 1.1 requirement set. "Ignore" is the default. + ////const styles = context.document.importStylesFromJson(str, Word.ImportedStylesConflictBehavior.Ignore); + + await context.sync(); + console.log("Styles imported from JSON:", styles); + }); + } + + // Default helper for invoking an action and handling errors. + async function tryCatch(callback) { + try { + await callback(); + } catch (error) { + console.error(error); + } + } + language: typescript +template: + content: |- +
      +

      This sample demonstrates how to manage a custom table style and use Document.importStylesFromJson. +

      +

      Important: Some TableStyle properties are currently in preview. If this snippet doesn't work, try using Word + on a different platform.

      +
      +
      +

      Try it out

      +

      Add a new table style

      +

      Name the style using letters. Can include digits. Examples: NewName, newname1

      +

      + + +

      + +

      Use custom style

      + + +

      + +

      + +

      +
      +

      Update custom style

      + +
      Note: Mixed and Unknown aren't valid when setting.
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      +

      Delete custom style

      + + +
      + +
      +
      +

      Import styles from JSON string

      + +
      + 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; + } + + .margin { + margin-top: 5px; + margin-bottom: 5px; + } + language: css +libraries: |- + https://appsforoffice.microsoft.com/lib/1/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/40-tables/manage-formatting.yaml b/samples/word/40-tables/manage-formatting.yaml new file mode 100644 index 000000000..9929afcd4 --- /dev/null +++ b/samples/word/40-tables/manage-formatting.yaml @@ -0,0 +1,238 @@ +order: 2 +id: word-tables-manage-formatting +name: Table formatting +description: Gets the formatting details of a table, a table row, and a table cell, including borders, alignment, and cell padding. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("get-table-alignment").addEventListener("click", () => tryCatch(getTableAlignment)); + document.getElementById("get-table-border").addEventListener("click", () => tryCatch(getTableBorder)); + document.getElementById("get-table-cell-padding").addEventListener("click", () => tryCatch(getTableCellPadding)); + document.getElementById("get-table-row-alignment").addEventListener("click", () => tryCatch(getTableRowAlignment)); + document.getElementById("get-table-row-border").addEventListener("click", () => tryCatch(getTableRowBorder)); + document.getElementById("get-table-row-cell-padding").addEventListener("click", () => tryCatch(getTableRowCellPadding)); + document.getElementById("get-table-cell-alignment").addEventListener("click", () => tryCatch(getTableCellAlignment)); + document.getElementById("get-table-cell-border").addEventListener("click", () => tryCatch(getTableCellBorder)); + document.getElementById("get-table-cell-cell-padding").addEventListener("click", () => tryCatch(getTableCellCellPadding)); + document.getElementById("setup").addEventListener("click", () => tryCatch(insertTable)); + + async function getTableAlignment() { + // Gets alignment details about the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + firstTable.load(["alignment", "horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table:`, `- Alignment of the table within the containing page column: ${firstTable.alignment}`, `- Horizontal alignment of every cell in the table: ${firstTable.horizontalAlignment}`, `- Vertical alignment of every cell in the table: ${firstTable.verticalAlignment}`); + }); + } + + async function getTableBorder() { + // Gets border details about the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); + } + + async function getTableCellPadding() { + // Gets cell padding details about the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const cellPaddingLocation = Word.CellPaddingLocation.right; + const cellPadding = firstTable.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table: ${cellPadding.value} points` + ); + }); + } + + async function getTableRowAlignment() { + // Gets content alignment details about the first row of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + firstTableRow.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first row:`, `- Horizontal alignment of every cell in the row: ${firstTableRow.horizontalAlignment}`, `- Vertical alignment of every cell in the row: ${firstTableRow.verticalAlignment}`); + }); + } + + async function getTableRowBorder() { + // Gets border details about the first row of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const borderLocation = Word.BorderLocation.bottom; + const border: Word.TableBorder = firstTableRow.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first row:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); + } + + async function getTableRowCellPadding() { + // Gets cell padding details about the first row of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const cellPaddingLocation = Word.CellPaddingLocation.bottom; + const cellPadding = firstTableRow.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table's first row: ${cellPadding.value} points` + ); + }); + } + + async function getTableCellAlignment() { + // Gets content alignment details about the first cell of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); + } + + async function getTableCellBorder() { + // Gets border details about the first of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstCell: Word.TableCell = firstTable.getCell(0, 0); + const borderLocation = "Left"; + const border: Word.TableBorder = firstCell.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first cell:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); + } + + async function getTableCellCellPadding() { + // Gets cell padding details about the first cell of the first table in the document. + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstCell: Word.TableCell = firstTable.getCell(0, 0); + const cellPaddingLocation = "Left"; + const cellPadding = firstCell.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table's first cell: ${cellPadding.value} points` + ); + }); + } + + async function insertTable() { + await Word.run(async (context) => { + // Use a two-dimensional array to hold the initial table values. + const data = [ + ["Tokyo", "Beijing", "Seattle"], + ["Apple", "Orange", "Pineapple"] + ]; + const table = context.document.body.insertTable(2, 3, "Start", data); + table.styleBuiltIn = Word.BuiltInStyleName.gridTable5Dark_Accent2; + table.styleFirstColumn = false; + + 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 various formatting details about a table, a table row, and a table cell, including + borders, alignment, and cell padding. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Table formatting

      +

      + + + +

      +

      Table row formatting

      +

      + + + +

      +

      Table cell formatting

      +

      + + + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/40-tables/table-cell-access.yaml b/samples/word/40-tables/table-cell-access.yaml new file mode 100644 index 000000000..c4389b9d7 --- /dev/null +++ b/samples/word/40-tables/table-cell-access.yaml @@ -0,0 +1,86 @@ +order: 1 +id: word-tables-table-cell-access +name: Create and access a table +description: Creates a table and accesses a specific cell. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(getTableCell)); + document.getElementById("setup").addEventListener("click", () => tryCatch(insertTable)); + + async function getTableCell() { + // Gets the content of the first cell in the first table. + await Word.run(async (context) => { + const firstCell: Word.Body = context.document.body.tables.getFirst().getCell(0, 0).body; + firstCell.load("text"); + + await context.sync(); + console.log("First cell's text is: " + firstCell.text); + }); + } + + async function insertTable() { + await Word.run(async (context) => { + // Use a two-dimensional array to hold the initial table values. + const data = [ + ["Tokyo", "Beijing", "Seattle"], + ["Apple", "Orange", "Pineapple"] + ]; + const table: Word.Table = context.document.body.insertTable(2, 3, "Start", data); + table.styleBuiltIn = Word.BuiltInStyleName.gridTable5Dark_Accent2; + table.styleFirstColumn = false; + + 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 demonstrates how to get a cell from 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/45-shapes/group-ungroup.yaml b/samples/word/45-shapes/group-ungroup.yaml new file mode 100644 index 000000000..f00f561b8 --- /dev/null +++ b/samples/word/45-shapes/group-ungroup.yaml @@ -0,0 +1,269 @@ +order: 3 +id: word-shapes-group-ungroup +name: Group and ungroup shapes +description: Shows how to group and ungroup shapes. +host: WORD +api_set: + WordApiDesktop: '1.2' +script: + content: | + document.getElementById("group-shapes").addEventListener("click", () => tryCatch(groupShapes)); + document.getElementById("move-group").addEventListener("click", () => tryCatch(moveGroup)); + document.getElementById("scale-group").addEventListener("click", () => tryCatch(scaleGroup)); + document.getElementById("change-group-position").addEventListener("click", () => tryCatch(changeGroupPosition)); + document.getElementById("change-group-size").addEventListener("click", () => tryCatch(changeGroupSize)); + document.getElementById("ungroup-shapes").addEventListener("click", () => tryCatch(ungroupShapes)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function groupShapes() { + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); + } + + async function moveGroup() { + await Word.run(async (context) => { + // Moves the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to move the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.moveHorizontally(-10); + firstShapeGroup.moveVertically(50); + + console.log("Moved the first shape group."); + }); + } + + async function scaleGroup() { + await Word.run(async (context) => { + // Scales the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to scale the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.scaleHeight(0.75, Word.ShapeScaleType.currentSize); + firstShapeGroup.scaleWidth(0.5, Word.ShapeScaleType.currentSize, Word.ShapeScaleFrom.scaleFromBottomRight); + + console.log("Scaled the first shape group."); + }); + } + + async function changeGroupPosition() { + await Word.run(async (context) => { + // Changes the position of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to change the position of the first shape group found in document body:", shapeGroup.shapes); + firstShapeGroup.relativeVerticalPosition = Word.RelativeVerticalPosition.insideMargin; + firstShapeGroup.relativeHorizontalPosition = Word.RelativeHorizontalPosition.margin; + + console.log("Changed the position of the first shape group."); + }); + } + + async function changeGroupSize() { + await Word.run(async (context) => { + // Changes the relative size of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log( + "About to change the relative size of the first shape group found in the document body:", + shapeGroup.shapes, + ); + firstShapeGroup.relativeHorizontalSize = Word.RelativeSize.insideMargin; + firstShapeGroup.relativeVerticalSize = Word.RelativeSize.bottomMargin; + firstShapeGroup.heightRelative = 50; + + console.log("Changed the relative size of the first shape group."); + }); + } + + async function ungroupShapes() { + await Word.run(async (context) => { + // Ungroups the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to ungroup the first shape group found in the document body:", shapeGroup.shapes); + shapeGroup.ungroup(); + + console.log("Ungrouped the first shape group."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + const lastParagraph: Word.Paragraph = body.paragraphs.getLast(); + + // Inserts a text box. + const textBoxOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100, + }; + lastParagraph.insertTextBox("placeholder text", textBoxOptions); + + // Inserts a geometric shape. + const geometricShapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + left: 120, + }; + lastParagraph.insertGeometricShape(Word.GeometricShapeType.star24, geometricShapeOptions); + + // Inserts a picture. + const pictureOptions: Word.InsertShapeOptions = { + top: 120, + left: 60, + height: 150, + width: 150, + }; + lastParagraph.insertPictureFromBase64(getPictureBase64(), pictureOptions); + + await context.sync(); + }); + } + + function getPictureBase64(): string { + // Returns Base64-encoded image data for a sample picture. + const pictureBase64 = + "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"; + return pictureBase64; + } + + // 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 how to group and ungroup shapes. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/45-shapes/manage-canvases.yaml b/samples/word/45-shapes/manage-canvases.yaml new file mode 100644 index 000000000..597353a0b --- /dev/null +++ b/samples/word/45-shapes/manage-canvases.yaml @@ -0,0 +1,167 @@ +order: 4 +id: word-shapes-manage-canvases +name: Work with canvases +description: Shows how to work with canvases. +host: WORD +api_set: + WordApiDesktop: '1.2' +script: + content: | + document.getElementById("insert-canvas").addEventListener("click", () => tryCatch(insertCanvas)); + document.getElementById("get-canvases").addEventListener("click", () => tryCatch(getCanvases)); + document.getElementById("get-first-canvas").addEventListener("click", () => tryCatch(getFirstCanvas)); + document.getElementById("move-first-canvas").addEventListener("click", () => tryCatch(moveFirstCanvas)); + document.getElementById("delete-first-canvas").addEventListener("click", () => tryCatch(deleteFirstCanvas)); + + async function insertCanvas() { + await Word.run(async (context) => { + // Inserts a canvas in the document. + const canvasShape: Word.Shape = context.document.getSelection().insertCanvas(); + canvasShape.load(); + await context.sync(); + + canvasShape.select(); + console.log("Inserted canvas:", canvasShape); + + const canvas: Word.Canvas = canvasShape.canvas; + canvas.load("shape,shapes"); + await context.sync(); + + console.log("Canvas object:", canvas); + }); + } + + async function getCanvases() { + await Word.run(async (context) => { + // Gets the canvases found in the document body. + const canvases: Word.ShapeCollection = context.document.body.shapes.getByTypes([Word.ShapeType.canvas]); + canvases.load("items"); + await context.sync(); + + if (canvases.items.length == 0) { + console.log("No canvases found in the document body."); + return; + } + + console.log("Canvases found in the document body:", canvases); + }); + } + + async function getFirstCanvas() { + await Word.run(async (context) => { + // Gets the first canvas found in the document body. + const canvasShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.canvas]) + .getFirstOrNullObject(); + canvasShape.load(); + canvasShape.load("canvas/shapes"); + await context.sync(); + + if (canvasShape.isNullObject) { + console.log("No canvases found in the document body."); + return; + } + + console.log("First canvas found in the document body:", canvasShape); + console.log("Shapes associated with the first canvas:", canvasShape.canvas.shapes); + canvasShape.select(); + }); + } + + async function moveFirstCanvas() { + await Word.run(async (context) => { + // Moves the first canvas found in the document body. + const canvasShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.canvas]) + .getFirstOrNullObject(); + canvasShape.load(); + canvasShape.load("canvas/shapes"); + await context.sync(); + + if (canvasShape.isNullObject) { + console.log("No canvases found in the document body."); + return; + } + + console.log("First canvas found in the document body:", canvasShape); + canvasShape.moveHorizontally(50); + canvasShape.moveVertically(-10); + console.log("Moved the first canvas."); + }); + } + + async function deleteFirstCanvas() { + await Word.run(async (context) => { + // Deletes the first canvas found in the document body. + const canvasShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.canvas]) + .getFirstOrNullObject(); + canvasShape.load(); + canvasShape.load("canvas/shapes"); + await context.sync(); + + if (canvasShape.isNullObject) { + console.log("No canvases found in the document body."); + return; + } + + console.log("First canvas found in the document body:", canvasShape); + canvasShape.delete(); + console.log("Deleted the first canvas."); + }); + } + + // 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 how to work with canvases. A canvas can be useful for organizing several shapes and connecting them. Diagrams and flowcharts are examples where using a canvas could be appropriate. +

      To learn how to add shapes to a drawing canvas using the Word UI, see Add a drawing to a document. Adding shapes to a canvas with the Word APIs is not supported.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/45-shapes/manage-geometric-shapes.yaml b/samples/word/45-shapes/manage-geometric-shapes.yaml new file mode 100644 index 000000000..85f037a1e --- /dev/null +++ b/samples/word/45-shapes/manage-geometric-shapes.yaml @@ -0,0 +1,256 @@ +order: 2 +id: word-shapes-manage-geometric-shapes +name: Manage geometric shapes +description: Shows how to work with geometric shapes. +host: WORD +api_set: + WordApiDesktop: '1.2' +script: + content: | + document.getElementById("insert-heptagon").addEventListener("click", () => tryCatch(insertGeometricShape_Heptagon)); + document.getElementById("insert-moon").addEventListener("click", () => tryCatch(insertGeometricShape_Moon)); + document.getElementById("get-geometric-shapes").addEventListener("click", () => tryCatch(getGeometricShapes)); + document.getElementById("get-moons").addEventListener("click", () => tryCatch(getMoonGeometricShapes)); + document.getElementById("get-first-geometric-shape").addEventListener("click", () => tryCatch(getFirstGeometricShape)); + document.getElementById("get-first-heptagon").addEventListener("click", () => tryCatch(getFirstHeptagon)); + document.getElementById("get-first-moon-fill").addEventListener("click", () => tryCatch(getFirstMoonColorFill)); + document.getElementById("clear-first-moon-fill").addEventListener("click", () => tryCatch(clearFirstMoonColorFill)); + document.getElementById("set-first-moon-fill").addEventListener("click", () => tryCatch(setFirstMoonColorFill)); + + async function insertGeometricShape_Heptagon() { + await Word.run(async (context) => { + // Inserts a heptagon geometric shape at the beginning of the selection. + const selection: Word.Range = context.document.getSelection(); + const shapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + }; + selection.insertGeometricShape(Word.GeometricShapeType.heptagon, shapeOptions); + await context.sync(); + + console.log("Inserted a heptagon."); + }); + } + + async function insertGeometricShape_Moon() { + await Word.run(async (context) => { + // Inserts a moon geometric shape at the beginning of the selection. + const selection: Word.Range = context.document.getSelection(); + const shapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + left: 120, + }; + selection.insertGeometricShape(Word.GeometricShapeType.moon, shapeOptions); + await context.sync(); + + console.log("Inserted a moon."); + }); + } + + async function getGeometricShapes() { + await Word.run(async (context) => { + // Gets the geometric shapes from the document body. + const geometricShapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + ]); + geometricShapes.load(); + await context.sync(); + + console.log("Geometric shapes found in the document body:", geometricShapes); + }); + } + + async function getMoonGeometricShapes() { + await Word.run(async (context) => { + // Gets the moon geometric shapes from the document body. + const moons: Word.ShapeCollection = context.document.body.shapes.getByGeometricTypes([ + Word.GeometricShapeType.moon, + ]); + moons.load(); + await context.sync(); + + console.log("Moons found in the document body:", moons); + }); + } + + async function getFirstGeometricShape() { + await Word.run(async (context) => { + // Gets the first geometric shape found in the document body. + const geometricShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.geometricShape]) + .getFirstOrNullObject(); + geometricShape.load(); + await context.sync(); + + if (geometricShape.isNullObject) { + console.log("No geometric shapes found in the document body."); + return; + } + + console.log( + `First geometric shape found in the document body is of type ${geometricShape.geometricShapeType}:`, + geometricShape, + ); + }); + } + + async function getFirstHeptagon() { + await Word.run(async (context) => { + // Gets the first heptagon found in the document body. + const heptagon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.heptagon]) + .getFirstOrNullObject(); + heptagon.load(); + await context.sync(); + + if (heptagon.isNullObject) { + console.log("No heptagons found in the document body."); + return; + } + + console.log("First heptagon found in the document body:", heptagon); + }); + } + + async function getFirstMoonColorFill() { + await Word.run(async (context) => { + // Gets the color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + const moonFillType = moonFill.type as Word.ShapeFillType; + + console.log("Color fill properties of the first moon found in the document body:"); + console.log(`\tForeground color: ${moonFill.foregroundColor}`); + console.log(`\tBackground color: ${moonFill.backgroundColor}`); + console.log(`\tTransparency: ${moonFill.transparency}`); + console.log(`\tFill type: ${moonFillType}`); + }); + } + + async function clearFirstMoonColorFill() { + await Word.run(async (context) => { + // Clears the color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + console.log("Current fill properties of the first moon found in the document body:", moonFill); + + moonFill.clear(); + moonFill.load(); + await context.sync(); + + console.log("Cleared the color fill properties of the first moon found in the document body:", moonFill); + }); + } + + async function setFirstMoonColorFill() { + await Word.run(async (context) => { + // Sets color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + console.log("Current fill properties of the first moon found in the document body:", moonFill); + + moonFill.setSolidColor("green"); + moonFill.load(); + await context.sync(); + + console.log("Updated color fill properties of the first moon found in the document body:", moonFill); + }); + } + + // 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 how to work with geometric shapes. +
      +
      +

      Try it out

      + + + + + + +

      Work with color fill properties of the first moon

      + + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/45-shapes/manage-shapes-text-boxes.yaml b/samples/word/45-shapes/manage-shapes-text-boxes.yaml new file mode 100644 index 000000000..ef91e7153 --- /dev/null +++ b/samples/word/45-shapes/manage-shapes-text-boxes.yaml @@ -0,0 +1,415 @@ +order: 1 +id: word-shapes-manage-shapes-text-boxes +name: Work with shapes and text boxes +description: Shows how to work with shapes and text boxes. +author: yilin4 +host: WORD +api_set: + WordApiDesktop: '1.2' +script: + content: | + document + .getElementById("insert-text-box-into-current-selection") + .addEventListener("click", () => tryCatch(insertTextBoxIntoCurrentSelection)); + document.getElementById("get-text-boxes-in-main-doc").addEventListener("click", () => tryCatch(getTextBoxesInMainDoc)); + document + .getElementById("get-text-wrap-of-text-box-in-main-doc") + .addEventListener("click", () => tryCatch(getTextWrapOfTextBoxInMainDoc)); + document + .getElementById("set-text-wrap-of-text-box-in-main-doc") + .addEventListener("click", () => tryCatch(setTextWrapPropertiesOfTextBoxInMainDoc)); + document + .getElementById("get-text-frame-of-text-box-in-main-doc") + .addEventListener("click", () => tryCatch(getTextFrameOfTextBoxInMainDoc)); + document + .getElementById("set-text-frame-of-text-box-in-main-doc") + .addEventListener("click", () => tryCatch(setTextFramePropertiesOfTextBoxInMainDoc)); + document.getElementById("set-text-box-properties").addEventListener("click", () => tryCatch(setTextBoxProperties)); + document + .getElementById("get-text-from-text-box-in-main-doc") + .addEventListener("click", () => tryCatch(getTextFromTextBoxInMainDoc)); + document + .getElementById("insert-content-control-into-text-box") + .addEventListener("click", () => tryCatch(insertContentControlIntoTextBox)); + document + .getElementById("get-content-controls-in-text-box") + .addEventListener("click", () => tryCatch(getContentControlsInTextBox)); + document + .getElementById("insert-picture-at-start-of-text-box") + .addEventListener("click", () => tryCatch(insertPictureAtStartOfTextBox)); + document.getElementById("delete-first-text-box").addEventListener("click", () => tryCatch(deleteFirstTextBox)); + document + .getElementById("insert-text-box-in-header-at-first-paragraph") + .addEventListener("click", () => tryCatch(insertTextBoxInHeaderAtFirstParagraph)); + document.getElementById("get-text-boxes-in-header").addEventListener("click", () => tryCatch(getTextBoxesInHeader)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertTextBoxIntoCurrentSelection() { + await Word.run(async (context) => { + // Inserts a text box at the beginning of the selection. + const range: Word.Range = context.document.getSelection(); + const insertShapeOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100 + }; + + const newTextBox: Word.Shape = range.insertTextBox("placeholder text", insertShapeOptions); + await context.sync(); + + console.log("Inserted a text box at the beginning of the current selection."); + }); + } + + async function getTextBoxesInMainDoc() { + await Word.run(async (context) => { + // Gets text boxes in the main document. + const shapes: Word.ShapeCollection = context.document.body.shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the main document: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the main document has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the main document doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the main document."); + } + }); + } + + async function getTextWrapOfTextBoxInMainDoc() { + await Word.run(async (context) => { + // Gets text wrap properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textWrap"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text wrap properties of first text box:", shape.textWrap); + }); + } + + async function setTextWrapPropertiesOfTextBoxInMainDoc() { + await Word.run(async (context) => { + // Sets text wrap properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirstOrNullObject(); + firstShapeWithTextBox.load("textWrap"); + await context.sync(); + + if (firstShapeWithTextBox.isNullObject) { + console.log("No shapes with text boxes found in main document."); + return; + } + + const textWrap: Word.ShapeTextWrap = firstShapeWithTextBox.textWrap; + textWrap.type = Word.ShapeTextWrapType.square; + textWrap.side = Word.ShapeTextWrapSide.both; + + console.log("The first text box's text wrap properties were updated:", textWrap); + }); + } + + async function getTextFrameOfTextBoxInMainDoc() { + await Word.run(async (context) => { + // Gets the text frame of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text frame of first text box:", shape.textFrame); + }); + } + + async function setTextFramePropertiesOfTextBoxInMainDoc() { + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); + } + + async function setTextBoxProperties() { + await Word.run(async (context) => { + // Sets the properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.top = 115; + firstShapeWithTextBox.left = 0; + firstShapeWithTextBox.width = 50; + firstShapeWithTextBox.height = 50; + await context.sync(); + + console.log("The first text box's properties were updated:", firstShapeWithTextBox); + }); + } + + async function getTextFromTextBoxInMainDoc() { + await Word.run(async (context) => { + // Gets text from the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("body/text"); + await context.sync(); + + console.log( + shape.isNullObject + ? "No shapes with text boxes found in the main document." + : `Text in first text box: ${shape.body.text}` + ); + }); + } + + async function insertContentControlIntoTextBox() { + await Word.run(async (context) => { + // Inserts a content control into the first paragraph in the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const firstParagraphInTextBox: Word.Paragraph = firstShapeWithTextBox.body.paragraphs.getFirst(); + const newControl: Word.ContentControl = firstParagraphInTextBox.insertContentControl(); + newControl.load(); + await context.sync(); + + console.log("New content control properties:", newControl); + }); + } + + async function getContentControlsInTextBox() { + await Word.run(async (context) => { + // Gets the content controls in the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const contentControlsInTextBox: Word.ContentControlCollection = firstShapeWithTextBox.body.contentControls; + contentControlsInTextBox.load(); + await context.sync(); + + console.log(`Number of content controls: ${contentControlsInTextBox.items.length}`); + }); + } + + async function insertPictureAtStartOfTextBox() { + await Word.run(async (context) => { + // Inserts a picture at the start of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const startRange: Word.Range = firstShapeWithTextBox.body.getRange(Word.RangeLocation.start); + const newPic: Word.InlinePicture = startRange.insertInlinePictureFromBase64( + getPictureBase64(), + Word.InsertLocation.start + ); + newPic.load(); + await context.sync(); + + console.log("New inline picture properties:", newPic); + }); + } + + async function deleteFirstTextBox() { + await Word.run(async (context) => { + // Deletes the first text box. + context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirst().delete(); + await context.sync(); + + console.log("The first text box in document was deleted."); + }); + } + + async function insertTextBoxInHeaderAtFirstParagraph() { + await Word.run(async (context) => { + // Inserts a text box at the beginning of the first paragraph in the header. + const headerFooterBody: Word.Body = context.document.sections.getFirst().getHeader(Word.HeaderFooterType.primary); + headerFooterBody.load("paragraphs"); + const firstParagraph: Word.Paragraph = headerFooterBody.paragraphs.getFirst(); + const insertShapeOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100 + }; + const newTextBox: Word.Shape = firstParagraph.insertTextBox("placeholder text", insertShapeOptions); + newTextBox.select(); + await context.sync(); + + console.log("Inserted a text box at the beginning of the first paragraph in the header."); + }); + } + + async function getTextBoxesInHeader() { + await Word.run(async (context) => { + // Gets text boxes in the header. + const shapes: Word.ShapeCollection = context.document.sections + .getFirst() + .getHeader(Word.HeaderFooterType.primary).shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the header: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the header has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the header doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the header."); + } + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start", + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace", + ); + }); + } + + function getPictureBase64(): string { + // Returns Base64-encoded image data for a sample picture. + const pictureBase64 = + "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"; + return pictureBase64; + } + + // 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 how to work with shapes and text boxes. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Main document

      + + +

      The following buttons act on the first text box in the main document.

      + + + + + + + + + + +

      Header

      + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-common-patterns/multiple-property-set.yaml b/samples/word/50-common-patterns/multiple-property-set.yaml deleted file mode 100644 index c96d59d0f..000000000 --- a/samples/word/50-common-patterns/multiple-property-set.yaml +++ /dev/null @@ -1,122 +0,0 @@ -id: word-common-patterns-multiple-property-set -name: Multiple Property Set -description: Setting multiple properties at once with the API object set() method. -host: WORD -api_set: - WordApi: 1.4 -script: - content: |- - $("#set-multiple-properties-with-object").click(() => tryCatch(setMultiplePropertiesWithObject)); - $("#copy-properties-from-paragraph").click(() => tryCatch(copyPropertiesFromParagraph)); - - async function setMultiplePropertiesWithObject() { - await Word.run(async (context) => { - const paragraph = context.document.body.paragraphs.getFirst(); - paragraph.set({ - leftIndent: 30, - font: { - bold: true, - color: "red" - } - }); - - await context.sync(); - }); - } - - async function copyPropertiesFromParagraph() { - await Word.run(async (context) => { - const firstParagraph = context.document.body.paragraphs.getFirst(); - const secondParagraph = firstParagraph.getNext(); - firstParagraph.load("text, font/color, font/bold, leftIndent"); - - await context.sync(); - - secondParagraph.set(firstParagraph); - - 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 how to format text using the object.set method of the Word API.

      -

      Be sure that there are at least two paragraphs before you try it out.

      -
      - -
      -

      Try it out

      -

      Set the styling of the first paragraph.

      - -

      Now copy the formatting of the first paragraph to the second.

      - -
      - language: html -style: - content: |- - body { - margin: 0; - padding: 10px; - } - - - /* Button customization, including overwriting some Fabric defaults */ - - .ms-Button, .ms-Button:focus { - background: #2b579a; - border: #2b579a; - } - - .ms-Button > .ms-Button-label, - .ms-Button:focus > .ms-Button-label, - .ms-Button:hover > .ms-Button-label { - color: white; - } - - .ms-Button:hover, .ms-Button:active { - background: #204072; - } - - .ms-Button.is-disabled, .ms-Button:disabled { - background-color: #f4f4f4; - border-color: #f4f4f4; - } - - .ms-Button.is-disabled .ms-Button-label, - .ms-Button:disabled .ms-Button-label { - color: #a6a6a6; - } - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/50-document/compare-documents.yaml b/samples/word/50-document/compare-documents.yaml new file mode 100644 index 000000000..70ee0b554 --- /dev/null +++ b/samples/word/50-document/compare-documents.yaml @@ -0,0 +1,74 @@ +order: 16 +id: word-document-compare-documents +name: Compare documents +description: Compares two documents (the current one and a specified external one). +author: YijunMS +host: WORD +api_set: + WordApiDesktop: '1.1' +script: + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); + + async function run() { + // Compares the current document with a specified external document. + await Word.run(async (context) => { + // Absolute path of an online or local document. + const filePath = (document.getElementById("filePath") as HTMLInputElement).value; + // Options that configure the compare operation. + const options: Word.DocumentCompareOptions = { + compareTarget: Word.CompareTarget.compareTargetCurrent, + detectFormatChanges: false + // Other options you choose... + }; + context.document.compare(filePath, options); + + await context.sync(); + + console.log("Differences shown in the current document."); + }); + } + + // 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 compare two documents: the current one and a specified external one.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/get-external-styles.yaml b/samples/word/50-document/get-external-styles.yaml new file mode 100644 index 000000000..3f7c74914 --- /dev/null +++ b/samples/word/50-document/get-external-styles.yaml @@ -0,0 +1,85 @@ +order: 13 +id: word-document-get-external-styles +name: Get styles from external document +description: This sample shows how to get styles from an external document. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("file").addEventListener("change", getBase64); + document.getElementById("get-external-styles").addEventListener("click", () => tryCatch(getExternalStyles)); + + let externalDocument; + + async function getExternalStyles() { + // Gets style info from another document passed in as a Base64-encoded string. + await Word.run(async (context) => { + const retrievedStyles = context.application.retrieveStylesFromBase64(externalDocument); + await context.sync(); + + console.log("Styles from the other document:", retrievedStyles.value); + }); + } + + function getBase64() { + // Retrieve the file and set up an HTML FileReader element. + const myFile = document.getElementById("file") as HTMLInputElement; + const reader = new FileReader(); + + reader.onload = (event) => { + // Remove the metadata before the Base64-encoded string. + const startIndex = reader.result.toString().indexOf("base64,"); + externalDocument = 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]); + } + + // 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 how to get styles from an external document. +
      +
      +

      Try it out

      +

      Select a Word document to get its style info.

      +
      + +
      +
      +

      Get style info from the selected document.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/insert-external-document.yaml b/samples/word/50-document/insert-external-document.yaml new file mode 100644 index 000000000..005d12d69 --- /dev/null +++ b/samples/word/50-document/insert-external-document.yaml @@ -0,0 +1,124 @@ +order: 3 +id: word-document-insert-external-document +name: Insert an external document +description: Inserts the content (with or without settings) of an external document into the current document. Settings include formatting, change-tracking mode, custom properties, and XML parts. +host: WORD +api_set: + WordApi: '1.7' +script: + content: |- + document.getElementById("file").addEventListener("change", getBase64); + document.getElementById("insert-document").addEventListener("click", () => tryCatch(insertDocument)); + document.getElementById("insert-document-with-settings").addEventListener("click", () => tryCatch(insertDocumentWithSettings)); + + let externalDocument; + + async function insertDocument() { + // Updates the text of the current document with the text from another document passed in as a Base64-encoded string. + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + const externalDoc: Word.DocumentCreated = context.application.createDocument(externalDocument); + await context.sync(); + + if (!Office.context.requirements.isSetSupported("WordApiHiddenDocument", "1.3")) { + console.warn("The WordApiHiddenDocument 1.3 requirement set isn't supported on this client so can't proceed. Try this action on a platform that supports this requirement set."); + return; + } + + const externalDocBody: Word.Body = externalDoc.body; + externalDocBody.load("text"); + await context.sync(); + + // Insert the external document's text at the beginning of the current document's body. + const externalDocBodyText = externalDocBody.text; + const currentDocBody: Word.Body = context.document.body; + currentDocBody.insertText(externalDocBodyText, Word.InsertLocation.start); + await context.sync(); + }); + } + + async function insertDocumentWithSettings() { + // Inserts content (applying selected settings) from another document passed in as a Base64-encoded string. + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + context.document.insertFileFromBase64(externalDocument, "Replace", { + importTheme: true, + importStyles: true, + importParagraphSpacing: true, + importPageColor: true, + importChangeTrackingMode: true, + importCustomProperties: true, + importCustomXmlParts: true, + importDifferentOddEvenPages: true + }); + await context.sync(); + }); + } + + function getBase64() { + // Retrieve the file and set up an HTML FileReader element. + const myFile = document.getElementById("file") as HTMLInputElement; + const reader = new FileReader(); + + reader.onload = (event) => { + // Remove the metadata before the Base64-encoded string. + const startIndex = reader.result.toString().indexOf("base64,"); + externalDocument = 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]); + } + + // 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 the body text from an external document into the current document.

      +
      +
      +

      Try it out

      +

      Select a Word document.

      +
      + +
      +
      +

      Insert the body text from the selected document.

      + +
      +

      Insert the body text with settings applied from the selected document.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/insert-section-breaks.yaml b/samples/word/50-document/insert-section-breaks.yaml new file mode 100644 index 000000000..1ca46f47b --- /dev/null +++ b/samples/word/50-document/insert-section-breaks.yaml @@ -0,0 +1,137 @@ +order: 2 +id: word-document-insert-section-breaks +name: Add a section +description: Shows how to insert section breaks in the document. +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("add-sectionNext").addEventListener("click", () => tryCatch(addNext)); + document.getElementById("add-sectionEven").addEventListener("click", () => tryCatch(addEven)); + document.getElementById("add-sectionOdd").addEventListener("click", () => tryCatch(addOdd)); + document.getElementById("add-sectionContinuous").addEventListener("click", () => tryCatch(addContinuous)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function addNext() { + // Inserts a section break on the next page. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionNext, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section break on next page."); + }); + } + + async function addEven() { + // Inserts a section break on the next even page. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionEven, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section break on next even page."); + }); + } + + async function addOdd() { + // Inserts a section break on the next odd page. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionOdd, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section break on next odd page."); + }); + } + + async function addContinuous() { + // Inserts a section without an associated page break. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionContinuous, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section without an associated page break."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 insert sections in the document. +
      +
      +

      Set up

      + +

      You should also show the formatting marks to see the section indicators. To learn more, refer to Show or hide tab marks in Word

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/manage-annotations.yaml b/samples/word/50-document/manage-annotations.yaml new file mode 100644 index 000000000..344bbc495 --- /dev/null +++ b/samples/word/50-document/manage-annotations.yaml @@ -0,0 +1,361 @@ +order: 15 +id: word-document-manage-annotations +name: Manage annotations +description: Shows how to leverage the Writing Assistance API to manage annotations and use annotation events. +author: cbouzmsft +host: WORD +api_set: + WordApi: '1.8' +script: + content: |- + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("insert-annotations").addEventListener("click", () => tryCatch(insertAnnotations)); + document.getElementById("get-annotations").addEventListener("click", () => tryCatch(getAnnotations)); + document.getElementById("accept-first").addEventListener("click", () => tryCatch(acceptFirst)); + document.getElementById("reject-last").addEventListener("click", () => tryCatch(rejectLast)); + document.getElementById("delete-annotations").addEventListener("click", () => tryCatch(deleteAnnotations)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function registerEventHandlers() { + // Registers event handlers. + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + } + + async function paragraphChanged(args: Word.ParagraphChangedEventArgs) { + await Word.run(async (context) => { + const results = []; + for (let id of args.uniqueLocalIds) { + let para = context.document.getParagraphByUniqueLocalId(id); + para.load("uniqueLocalId"); + + results.push({ para: para, text: para.getText() }); + } + + await context.sync(); + + for (let result of results) { + console.log(`${args.type}: ID ${result.para.uniqueLocalId}:-`, result.text.value); + } + }); + } + + async function insertAnnotations() { + // Adds annotations to the selected paragraph. + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); + } + + async function getAnnotations() { + // Gets annotations found in the selected paragraph. + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); + } + + async function acceptFirst() { + // Accepts the first annotation found in the selected paragraph. + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Accepting ID ${annotation.id}...`); + annotation.critiqueAnnotation.accept(); + + await context.sync(); + break; + } + } + }); + } + + async function rejectLast() { + // Rejects the last annotation found in the selected paragraph. + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = annotations.items.length - 1; i >= 0; i--) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Rejecting ID ${annotation.id}...`); + annotation.critiqueAnnotation.reject(); + + await context.sync(); + break; + } + } + }); + } + + async function deleteAnnotations() { + // Deletes all annotations found in the selected paragraph. + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id"); + + await context.sync(); + + const ids = []; + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + ids.push(annotation.id); + annotation.delete(); + } + + await context.sync(); + + console.log("Annotations deleted:", ids); + }); + } + + async function onClickedHandler(args: Word.AnnotationClickedEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationClicked: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } + + async function onHoveredHandler(args: Word.AnnotationHoveredEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationHovered: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } + + async function onInsertedHandler(args: Word.AnnotationInsertedEventArgs) { + await Word.run(async (context) => { + const annotations = []; + for (let i = 0; i < args.ids.length; i++) { + let annotation: Word.Annotation = context.document.getAnnotationById(args.ids[i]); + annotation.load("id,critiqueAnnotation"); + + annotations.push(annotation); + } + + await context.sync(); + + for (let annotation of annotations) { + console.log(`AnnotationInserted: ID ${annotation.id}:`, annotation.critiqueAnnotation.critique); + } + }); + } + + async function onRemovedHandler(args: Word.AnnotationRemovedEventArgs) { + await Word.run(async (context) => { + for (let id of args.ids) { + console.log(`AnnotationRemoved: ID ${id}`); + } + }); + } + + async function onPopupActionHandler(args: Word.AnnotationPopupActionEventArgs) { + await Word.run(async (context) => { + let message = `AnnotationPopupAction: ID ${args.id} = `; + if (args.action === "Accept") { + message += `Accepted: ${args.critiqueSuggestion}`; + } else { + message += "Rejected"; + } + + console.log(message); + }); + } + + async function deregisterEventHandlers() { + // Deregisters event handlers. + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers."); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.insertParagraph( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "End" + ); + }); + } + + // 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 how to manage annotations and use annotation events.

      +

      Important: You need a Microsoft 365 subscription in order to use Annotation APIs. See GitHub issue 4953 for more information.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/manage-body.yaml b/samples/word/50-document/manage-body.yaml new file mode 100644 index 000000000..0051442b5 --- /dev/null +++ b/samples/word/50-document/manage-body.yaml @@ -0,0 +1,415 @@ +order: 1 +id: word-document-manage-body +name: Manage body +description: Shows how to manage the document body. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.2' +script: + content: |- + document.getElementById("get-font-props").addEventListener("click", () => tryCatch(getFontProperties)); + document.getElementById("get-html").addEventListener("click", () => tryCatch(getHTML)); + document.getElementById("get-ooxml").addEventListener("click", () => tryCatch(getOOXML)); + document.getElementById("get-text").addEventListener("click", () => tryCatch(getText)); + document.getElementById("insert-content-control").addEventListener("click", () => tryCatch(insertContentControl)); + document.getElementById("insert-page-break").addEventListener("click", () => tryCatch(insertPageBreak)); + document.getElementById("file").addEventListener("change", getBase64); + document.getElementById("insert-external-body").addEventListener("click", () => tryCatch(insertExternalBody)); + document.getElementById("insert-html").addEventListener("click", () => tryCatch(insertHTML)); + document.getElementById("insert-image-inline").addEventListener("click", () => tryCatch(insertImageInline)); + document.getElementById("insert-ooxml").addEventListener("click", () => tryCatch(insertOOXML)); + document.getElementById("insert-text").addEventListener("click", () => tryCatch(insertText)); + document.getElementById("select").addEventListener("click", () => tryCatch(select)); + document.getElementById("clear").addEventListener("click", () => tryCatch(clear)); + document.getElementById("insert-paragraph").addEventListener("click", () => tryCatch(insertParagraph)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function getFontProperties() { + // Gets the style and the font size, font name, and font color properties on the body object. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to load font and style information for the document body. + body.load("font/size, font/name, font/color, style"); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + // Show font-related property values on the body object. + const results = + "Font size: " + + body.font.size + + "; Font name: " + + body.font.name + + "; Font color: " + + body.font.color + + "; Body style: " + + body.style; + + console.log(results); + }); + } + + async function getHTML() { + // Gets the HTML that represents the content of the body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to get the HTML contents of the body. + const bodyHTML = body.getHtml(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (HTML): " + bodyHTML.value); + }); + } + + async function getOOXML() { + // Gets the OOXML that represents the content of the body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to get the OOXML contents of the body. + const bodyOOXML = body.getOoxml(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (OOXML): " + bodyOOXML.value); + }); + } + + async function getText() { + // Gets the text content of the body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to load the text in document body. + body.load("text"); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (text): " + body.text); + }); + } + + async function insertContentControl() { + // Creates a content control using the document body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to wrap the body in a content control. + body.insertContentControl(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Wrapped the body in a content control."); + }); + } + + async function insertPageBreak() { + // Inserts a page break at the beginning of the document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert a page break at the start of the document body. + body.insertBreak(Word.BreakType.page, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added a page break at the start of the document body."); + }); + } + + let externalDocument; + + function getBase64() { + // Retrieve the file and set up an HTML FileReader element. + const myFile = document.getElementById("file") as HTMLInputElement; + const reader = new FileReader(); + + reader.onload = (event) => { + // Remove the metadata before the Base64-encoded string. + const startIndex = reader.result.toString().indexOf("base64,"); + externalDocument = 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 insertExternalBody() { + // Inserts the body from the external document at the beginning of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert the Base64-encoded string representation of the body of the selected .docx file at the beginning of the current document. + body.insertFileFromBase64(externalDocument, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added Base64-encoded text to the beginning of the document body."); + }); + } + + async function insertHTML() { + // Inserts the HTML at the beginning of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert HTML at the beginning of the document. + body.insertHtml("This is text inserted with body.insertHtml()", Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("HTML added to the beginning of the document body."); + }); + } + + async function insertImageInline() { + // Inserts an image inline at the beginning of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Base64-encoded image to insert inline. + const base64EncodedImg = + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAANCAIAAAAxEEnAAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACFSURBVDhPtY1BEoQwDMP6/0+XgIMTBAeYoTqso9Rkx1zG+tNj1H94jgGzeNSjteO5vtQQuG2seO0av8LzGbe3anzRoJ4ybm/VeKEerAEbAUpW4aWQCmrGFWykRzGBCnYy2ha3oAIq2MloW9yCCqhgJ6NtcQsqoIKdjLbFLaiACnYyf2fODbrjZcXfr2F4AAAAAElFTkSuQmCC"; + + // Queue a command to insert a Base64-encoded image at the beginning of the current document. + body.insertInlinePictureFromBase64(base64EncodedImg, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added a Base64-encoded image to the beginning of the document body."); + }); + } + + async function insertOOXML() { + // Inserts OOXML at the beginning of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert OOXML at the beginning of the body. + body.insertOoxml( + "This text has formatting directly applied to achieve its font size, color, line spacing, and paragraph spacing.", + Word.InsertLocation.start + ); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added OOXML to the beginning of the document body."); + }); + + // Read "Understand when and how to use Office Open XML in your Word add-in" for guidance on working with OOXML. + // https://learn.microsoft.com/office/dev/add-ins/word/create-better-add-ins-for-word-with-office-open-xml + + // The Word-Add-in-DocumentAssembly sample shows how you can use this API to assemble a document. + // https://github.com/OfficeDev/Word-Add-in-DocumentAssembly + } + + async function insertText() { + // Inserts text at the beginning of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert text at the beginning of the current document. + body.insertText('This is text inserted with body.insertText()', Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Text added to the beginning of the document body."); + }); + } + + async function select() { + // Selects the entire body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to select the document body. + // The Word UI will move to the selected document body. + body.select(); + + console.log("Selected the document body."); + }); + } + + async function clear() { + // Clears out the content from the document body. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to clear the contents of the body. + body.clear(); + + console.log("Cleared the body contents."); + }); + + // The Silly stories add-in sample shows how the clear method can be used to clear the contents of a document. + // https://aka.ms/sillystorywordaddin + } + + async function insertParagraph() { + // Inserts a paragraph at the end of this document. + // Run a batch operation against the Word object model. + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert a paragraph at the end of the current document. + body.insertParagraph("Content of a new paragraph", Word.InsertLocation.end); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Paragraph added at the end of the document body."); + }); + + // The Word-Add-in-DocumentAssembly sample shows how you can use the insertParagraph method to assemble a document. + // https://github.com/OfficeDev/Word-Add-in-DocumentAssembly + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 manage the content of the document body. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + + + + + + +

      Choose a Word document to copy its body into the current document.

      +
      + +
      +
      + + + + + + + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/manage-change-tracking.yaml b/samples/word/50-document/manage-change-tracking.yaml new file mode 100644 index 000000000..e5b647f12 --- /dev/null +++ b/samples/word/50-document/manage-change-tracking.yaml @@ -0,0 +1,146 @@ +order: 4 +id: word-document-manage-change-tracking +name: Track changes +description: This sample shows how to get and set the change tracking mode and get the before and after of reviewed text. +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("get-change-tracking-mode").addEventListener("click", () => tryCatch(getChangeTrackingMode)); + document.getElementById("set-change-tracking-mode").addEventListener("click", () => tryCatch(setChangeTrackingMode)); + document.getElementById("get-reviewed-text").addEventListener("click", () => tryCatch(getReviewedText)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function getChangeTrackingMode() { + // Gets the current change tracking mode. + await Word.run(async (context) => { + const document: Word.Document = context.document; + document.load("changeTrackingMode"); + await context.sync(); + + if (document.changeTrackingMode === Word.ChangeTrackingMode.trackMineOnly) { + console.log("Only my changes are being tracked."); + } else if (document.changeTrackingMode === Word.ChangeTrackingMode.trackAll) { + console.log("Everyone's changes are being tracked."); + } else { + console.log("No changes are being tracked."); + } + }); + } + + async function setChangeTrackingMode() { + // Sets the change tracking mode. + await Word.run(async (context) => { + const mode = (document.querySelector("input[name='mode']:checked") as HTMLInputElement).value; + if (mode === "Track only my changes") { + context.document.changeTrackingMode = Word.ChangeTrackingMode.trackMineOnly; + } else if (mode === "Track everyone's changes") { + context.document.changeTrackingMode = Word.ChangeTrackingMode.trackAll; + } else { + context.document.changeTrackingMode = Word.ChangeTrackingMode.off; + } + + await context.sync(); + + getChangeTrackingMode(); + }); + } + + async function getReviewedText() { + // Gets the reviewed text. + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection(); + const before = range.getReviewedText(Word.ChangeTrackingVersion.original); + const after = range.getReviewedText(Word.ChangeTrackingVersion.current); + + await context.sync(); + + console.log("Reviewed text (before):", before.value, "Reviewed text (after):", after.value); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 basic operations of the Track Changes feature.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Get current change tracking mode

      + +

      Set change tracking mode

      +

      + +
      + +
      + +
      + +

      +

      Get reviewed text

      +

      + + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/manage-comments.yaml b/samples/word/50-document/manage-comments.yaml new file mode 100644 index 000000000..75a4ba5aa --- /dev/null +++ b/samples/word/50-document/manage-comments.yaml @@ -0,0 +1,297 @@ +order: 6 +id: word-document-manage-comments +name: Manage comments +description: This sample shows how to perform basic comments operations, including insert, reply, get, edit, resolve, and delete. +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("insert").addEventListener("click", () => tryCatch(insertComment)); + document.getElementById("edit").addEventListener("click", () => tryCatch(editFirstCommentInSelection)); + document.getElementById("reply").addEventListener("click", () => tryCatch(replyToFirstActiveCommentInSelection)); + document.getElementById("resolve").addEventListener("click", () => tryCatch(toggleResolvedStatusOfFirstCommentInSelection)); + document.getElementById("range").addEventListener("click", () => tryCatch(getFirstCommentRangeInSelection)); + document.getElementById("get-comments-in-selection").addEventListener("click", () => tryCatch(getCommentsInSelection)); + document.getElementById("get-replies-to-first-comment-in-selection").addEventListener("click", () => tryCatch(getRepliesToFirstCommentInSelection)); + document.getElementById("delete").addEventListener("click", () => tryCatch(deleteFirstCommentInSelection)); + document.getElementById("get-comments").addEventListener("click", () => tryCatch(getComments)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertComment() { + // Sets a comment on the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("comment-text") as HTMLInputElement).value; + const comment: Word.Comment = context.document.getSelection().insertComment(text); + + // Load object to log in the console. + comment.load(); + await context.sync(); + + console.log("Comment inserted:", comment); + }); + } + + async function editFirstCommentInSelection() { + // Edits the first active comment in the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("edit-comment-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (!firstActiveComment) { + console.warn("No active comment was found in the selection, so couldn't edit."); + return; + } + + firstActiveComment.content = text; + + // Load object to log in the console. + firstActiveComment.load(); + await context.sync(); + + console.log("Comment content changed:", firstActiveComment); + }); + } + + async function replyToFirstActiveCommentInSelection() { + // Replies to the first active comment in the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); + } + + async function toggleResolvedStatusOfFirstCommentInSelection() { + // Toggles Resolved status of the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document + .getSelection() + .getComments() + .getFirstOrNullObject(); + comment.load("resolved"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to toggle."); + return; + } + + // Toggle resolved status. + // If the comment is active, set as resolved. + // If it's resolved, set resolved to false. + const resolvedBefore = comment.resolved; + console.log(`Comment Resolved status (before): ${resolvedBefore}`); + comment.resolved = !resolvedBefore; + comment.load("resolved"); + await context.sync(); + + console.log(`Comment Resolved status (after): ${comment.resolved}`); + }); + } + + async function getFirstCommentRangeInSelection() { + // Gets the range of the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); + } + + async function getCommentsInSelection() { + // Gets the comments in the selected content. + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("Comments:", comments); + }); + } + + async function getRepliesToFirstCommentInSelection() { + // Gets the replies to the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("replies"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no replies to get."); + return; + } + + const replies: Word.CommentReplyCollection = comment.replies; + console.log("Replies to the first comment:", replies); + }); + } + + async function deleteFirstCommentInSelection() { + // Deletes the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.delete(); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to delete."); + return; + } + + console.log("Comment deleted."); + }); + } + + async function getComments() { + // Gets the comments in the document body. + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.body.getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("All comments:", comments); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 basic operations using comments.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Manage comments in selection

      +

      Select content in document body before proceeding.

      +

      + + + +

      +

      + + + +

      +

      + + + +

      +

      + +

      +

      + +

      +

      + +

      +

      + +

      +

      + +

      +

      Manage comments in document body

      +

      + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-custom-xml-part-ns.yaml b/samples/word/50-document/manage-custom-xml-part-ns.yaml new file mode 100644 index 000000000..c40fe12a7 --- /dev/null +++ b/samples/word/50-document/manage-custom-xml-part-ns.yaml @@ -0,0 +1,306 @@ +order: 10 +id: word-document-manage-custom-xml-part-ns +name: Manage a CustomXmlPart with the namespace +description: This sample shows how to add, query, replace, edit, and delete a custom XML part in a document. +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("add-custom-xml-part").addEventListener("click", () => tryCatch(addCustomXmlPart)); + document.getElementById("query").addEventListener("click", () => tryCatch(query)); + document.getElementById("get-namespace").addEventListener("click", () => tryCatch(getNamespace)); + document.getElementById("get-by-namespace").addEventListener("click", () => tryCatch(getByNamespaceUri)); + document.getElementById("replace-custom-xml-part").addEventListener("click", () => tryCatch(replace)); + document.getElementById("insert-attribute").addEventListener("click", () => tryCatch(insertAttribute)); + document.getElementById("insert-element").addEventListener("click", () => tryCatch(insertElement)); + document.getElementById("delete-custom-xml-part").addEventListener("click", () => tryCatch(deleteCustomXmlPart)); + + async function addCustomXmlPart() { + // Adds a custom XML part. + // If you want to populate the CustomXml.namespaceUri property, you must include the xmlns attribute. + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load(["id", "namespaceUri"]); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log(`Added custom XML part with namespace URI ${customXmlPart.namespaceUri}:`, readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartIdNS", customXmlPart.id); + + await context.sync(); + }); + } + + async function query() { + // Original XML: JuanHongSally + + // Queries a custom XML part for elements matching the search terms. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/contoso:Reviewers"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); + } + + async function getNamespace() { + // Original XML: JuanHongSally + + // Gets the namespace URI from a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + customXmlPart.load("namespaceUri"); + await context.sync(); + + const namespaceUri = customXmlPart.namespaceUri; + console.log(`Namespace URI: ${JSON.stringify(namespaceUri)}`); + } else { + console.warn("Didn't find custom XML part."); + } + }); + } + + async function getByNamespaceUri() { + // Original XML: JuanHongSally + + // Gets the custom XML parts with the specified namespace URI. + await Word.run(async (context) => { + const namespaceUri = "http://schemas.contoso.com/review/1.0"; + console.log(`Specified namespace URI: ${namespaceUri}`); + const scopedCustomXmlParts: Word.CustomXmlPartScopedCollection = + context.document.customXmlParts.getByNamespace(namespaceUri); + scopedCustomXmlParts.load("items"); + await context.sync(); + + console.log(`Number of custom XML parts found with this namespace: ${!scopedCustomXmlParts.items ? 0 : scopedCustomXmlParts.items.length}`); + }); + } + + async function replace() { + // Original XML: JuanHongSally + + // Replaces a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const originalXmlBlob = customXmlPart.getXml(); + await context.sync(); + + let readableXml = addLineBreaksToXML(originalXmlBlob.value); + console.log("Original custom XML part:", readableXml); + + // The setXml method replaces the entire XML part. + customXmlPart.setXml( + "JohnHitomi" + ); + const updatedXmlBlob = customXmlPart.getXml(); + await context.sync(); + + readableXml = addLineBreaksToXML(updatedXmlBlob.value); + console.log("Replaced custom XML part:", readableXml); + } else { + console.warn("Didn't find custom XML part to replace."); + } + }); + } + + async function insertAttribute() { + // Original XML: JuanHongSally + + // Inserts an attribute into a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertAttribute method inserts an attribute with the given name and value into the element identified by the xpath parameter. + customXmlPart.insertAttribute( + "/contoso:Reviewers", + { contoso: "http://schemas.contoso.com/review/1.0" }, + "Nation", + "US" + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted attribute:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert attribute into."); + } + }); + } + + async function insertElement() { + // Original XML: JuanHongSally + + // Inserts an element into a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertElement method inserts the given XML under the parent element identified by the xpath parameter at the provided child position index. + customXmlPart.insertElement( + "/contoso:Reviewers", + "Mark", + { contoso: "http://schemas.contoso.com/review/1.0" }, + 0 + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted element:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert element into."); + } + }); + } + + async function deleteCustomXmlPart() { + // Original XML: JuanHongSally + + // Deletes a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + let customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xmlBlob = customXmlPart.getXml(); + customXmlPart.delete(); + customXmlPart = context.document.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); + + await context.sync(); + + if (customXmlPart.isNullObject) { + console.log(`The XML part with the ID ${xmlPartIDSetting.value} has been deleted.`); + + // Delete the associated setting too. + xmlPartIDSetting.delete(); + + await context.sync(); + } else { + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.error( + `This is strange. The XML part with the id ${xmlPartIDSetting.value} wasn't deleted:`, + readableXml + ); + } + } else { + console.warn("Didn't find custom XML part to delete."); + } + }); + } + + 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 add, query, replace, edit, and delete a custom XML part in a document.

      +

      Note: For your production add-in, make sure to create and host your own XML schema.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-custom-xml-part.yaml b/samples/word/50-document/manage-custom-xml-part.yaml new file mode 100644 index 000000000..630a7587d --- /dev/null +++ b/samples/word/50-document/manage-custom-xml-part.yaml @@ -0,0 +1,214 @@ +order: 11 +id: word-document-manage-custom-xml-part +name: Manage a CustomXmlPart without the namespace +description: This sample shows how to add, query, edit, and delete a custom XML part in a document. +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("add-custom-xml-part").addEventListener("click", () => tryCatch(addCustomXmlPart)); + document.getElementById("query").addEventListener("click", () => tryCatch(query)); + document.getElementById("insert-attribute").addEventListener("click", () => tryCatch(insertAttribute)); + document.getElementById("insert-element").addEventListener("click", () => tryCatch(insertElement)); + document.getElementById("delete-custom-xml-part").addEventListener("click", () => tryCatch(deleteCustomXmlPart)); + + async function addCustomXmlPart() { + // Adds a custom XML part. + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load("id"); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Added custom XML part:", readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); + } + + async function query() { + // Original XML: JuanHongSally + + // Queries a custom XML part for elements matching the search terms. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/Reviewers/Reviewer"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); + } + + async function insertAttribute() { + // Original XML: JuanHongSally + + // Inserts an attribute into a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertAttribute method inserts an attribute with the given name and value into the element identified by the xpath parameter. + customXmlPart.insertAttribute("/Reviewers", { contoso: "http://schemas.contoso.com/review/1.0" }, "Nation", "US"); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted attribute:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert attribute into."); + } + }); + } + + async function insertElement() { + // Original XML: JuanHongSally + + // Inserts an element into a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertElement method inserts the given XML under the parent element identified by the xpath parameter at the provided child position index. + customXmlPart.insertElement( + "/Reviewers", + "Mark", + { contoso: "http://schemas.contoso.com/review/1.0" }, + 0 + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted element:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert element into."); + } + }); + } + + async function deleteCustomXmlPart() { + // Original XML: JuanHongSally + + // Deletes a custom XML part. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + let customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xmlBlob = customXmlPart.getXml(); + customXmlPart.delete(); + customXmlPart = context.document.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); + + await context.sync(); + + if (customXmlPart.isNullObject) { + console.log(`The XML part with the ID ${xmlPartIDSetting.value} has been deleted.`); + + // Delete the associated setting too. + xmlPartIDSetting.delete(); + + await context.sync(); + } else { + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.error(`This is strange. The XML part with the id ${xmlPartIDSetting.value} wasn't deleted:`, readableXml); + } + } else { + console.warn("Didn't find custom XML part to delete."); + } + }); + } + + 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 add, query, edit, and delete a custom XML part in a document.

      +

      Note: For your production add-in, make sure to create and host your own XML schema.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-fields.yaml b/samples/word/50-document/manage-fields.yaml new file mode 100644 index 000000000..b60163bee --- /dev/null +++ b/samples/word/50-document/manage-fields.yaml @@ -0,0 +1,242 @@ +order: 8 +id: word-document-manage-fields +name: Manage fields +description: This sample shows how to perform basic operations on fields, including insert, get, and delete. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-date-field").addEventListener("click", () => tryCatch(rangeInsertDateField)); + document.getElementById("get-first").addEventListener("click", () => tryCatch(getFirstField)); + document.getElementById("get-parent-body").addEventListener("click", () => tryCatch(getParentBodyOfFirstField)); + document.getElementById("get-all").addEventListener("click", () => tryCatch(getAllFields)); + document.getElementById("get-selected-field-and-update").addEventListener("click", () => tryCatch(getSelectedFieldAndUpdate)); + document.getElementById("get-selected-field-and-lock-or-unlock").addEventListener("click", () => tryCatch(getFieldAndLockOrUnlock)); + document.getElementById("delete-first-field").addEventListener("click", () => tryCatch(deleteFirstField)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function rangeInsertDateField() { + // Inserts a Date field before selection. + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection().getRange(); + + const field: Word.Field = range.insertField(Word.InsertLocation.before, Word.FieldType.date, '\\@ "M/d/yyyy h:mm am/pm"', true); + + field.load("result,code"); + await context.sync(); + + if (field.isNullObject) { + console.log("There are no fields in this document."); + } else { + console.log("Code of the field: " + field.code, "Result of the field: " + JSON.stringify(field.result)); + } + }); + } + + async function getFirstField() { + // Gets the first field in the document. + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); + } + + async function getParentBodyOfFirstField() { + // Gets the parent body of the first field in the document. + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load("parentBody/text"); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + const parentBody: Word.Body = field.parentBody; + console.log("Text of first field's parent body: " + JSON.stringify(parentBody.text)); + } + }); + } + + async function getAllFields() { + // Gets all fields in the document body. + await Word.run(async (context) => { + const fields: Word.FieldCollection = context.document.body.fields.load("items"); + + await context.sync(); + + if (fields.items.length === 0) { + console.log("No fields in this document."); + } else { + fields.load(["code", "result"]); + await context.sync(); + + for (let i = 0; i < fields.items.length; i++) { + console.log(`Field ${i + 1}'s code: ${fields.items[i].code}`, `Field ${i + 1}'s result: ${JSON.stringify(fields.items[i].result)}`); + } + } + }); + } + + async function getSelectedFieldAndUpdate() { + // Gets and updates the first field in the selection. + await Word.run(async (context) => { + let field = context.document.getSelection().fields.getFirstOrNullObject(); + field.load(["code", "result", "type", "locked"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("No field in selection."); + } else { + console.log("Before updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + + field.updateResult(); + field.select(); + await context.sync(); + + field.load(["code", "result"]); + await context.sync(); + + console.log("After updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + } + }); + } + + async function getFieldAndLockOrUnlock() { + // Gets the first field in the selection and toggles between setting it to locked or unlocked. + await Word.run(async (context) => { + let field = context.document.getSelection().fields.getFirstOrNullObject(); + field.load(["code", "result", "type", "locked"]); + await context.sync(); + + if (field.isNullObject) { + console.log("The selection has no fields."); + } else { + console.log(`The first field in the selection is currently ${field.locked ? "locked" : "unlocked"}.`); + field.locked = !field.locked; + await context.sync(); + + console.log(`The first field in the selection is now ${field.locked ? "locked" : "unlocked"}.`); + } + }); + } + + async function deleteFirstField() { + // Deletes the first field in the document. + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + field.delete(); + await context.sync(); + + console.log("The first field in the document was deleted."); + } + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + }); + } + + // 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 how to manage fields, which are placeholders for dynamic data in your document. To learn + more about fields, refer to Insert, edit, and view + fields in Word.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Insert fields

      +

      First, select some text.

      +

      +

      Insert a Date field before the selection.
      + +

      +

      Get and update fields

      + + + + +
      +

      +

      Toggle the first field of the selection between locked and unlocked.
      + +

      +

      Delete fields

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-footnotes.yaml b/samples/word/50-document/manage-footnotes.yaml new file mode 100644 index 000000000..20115c5a3 --- /dev/null +++ b/samples/word/50-document/manage-footnotes.yaml @@ -0,0 +1,242 @@ +order: 7 +id: word-document-manage-footnotes +name: Manage footnotes +description: This sample shows how to perform basic footnote operations, including insert, get, and delete. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("insert-footnote").addEventListener("click", () => tryCatch(insertFootnote)); + document.getElementById("get-reference").addEventListener("click", () => tryCatch(getReference)); + document.getElementById("get-footnote-type").addEventListener("click", () => tryCatch(getFootnoteType)); + document.getElementById("get-footnote-body").addEventListener("click", () => tryCatch(getFootnoteBody)); + document.getElementById("get-next-footnote").addEventListener("click", () => tryCatch(getNextFootnote)); + document.getElementById("delete-footnote").addEventListener("click", () => tryCatch(deleteFootnote)); + document.getElementById("get-first-footnote").addEventListener("click", () => tryCatch(getFirstFootnote)); + document.getElementById("get-footnotes-from-body").addEventListener("click", () => tryCatch(getFootnotesFromBody)); + document.getElementById("get-footnotes-from-range").addEventListener("click", () => tryCatch(getFootnotesFromRange)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertFootnote() { + // Sets a footnote on the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("input-footnote") as HTMLInputElement).value; + const footnote: Word.NoteItem = context.document.getSelection().insertFootnote(text); + await context.sync(); + + console.log("Inserted footnote."); + }); + } + async function getReference() { + // Selects the footnote's reference mark in the document body. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/reference"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + const reference: Word.Range = item.reference; + reference.select(); + await context.sync(); + + console.log(`Reference ${referenceNumber} is selected.`); + }); + } + async function getFootnoteType() { + // Gets the referenced note's item type and body type, which are both "Footnote". + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + console.log(`Note type of footnote ${referenceNumber}: ${item.type}`); + + item.body.load("type"); + await context.sync(); + + console.log(`Body type of note: ${item.body.type}`); + }); + } + async function getFootnoteBody() { + // Gets the text of the referenced footnote. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/body"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const footnoteBody: Word.Range = footnotes.items[mark].body.getRange(); + footnoteBody.load("text"); + await context.sync(); + + console.log(`Text of footnote ${referenceNumber}: ${footnoteBody.text}`); + }); + } + async function getNextFootnote() { + // Selects the next footnote in the document body. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/reference"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const reference: Word.Range = footnotes.items[mark].getNext().reference; + reference.select(); + console.log("Selected is the next footnote: " + (mark + 2)); + }); + } + async function deleteFootnote() { + // Deletes this referenced footnote. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + footnotes.items[mark].delete(); + await context.sync(); + + console.log("Footnote deleted."); + }); + } + async function getFirstFootnote() { + // Gets the first footnote in the document body and select its reference mark. + await Word.run(async (context) => { + const reference: Word.Range = context.document.body.footnotes.getFirst().reference; + reference.select(); + console.log("The first footnote is selected."); + }); + } + async function getFootnotesFromBody() { + // Gets the footnotes in the document body. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("length"); + await context.sync(); + + console.log("Number of footnotes in the document body: " + footnotes.items.length); + }); + } + async function getFootnotesFromRange() { + // Gets the footnotes in the selected document range. + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.getSelection().footnotes; + footnotes.load("length"); + await context.sync(); + + console.log("Number of footnotes in the selected range: " + footnotes.items.length); + }); + } + async function setup() { + // Set two paragraphs of sample text. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 basic operations using footnotes.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Insert footnote

      +

      1. Select text in the document.

      +

      + + + +

      +

      3. Repeat steps 1 and 2 as often as you want.

      +

      Manage existing footnote

      +

      + + +

      +

      Note: Ensure the main document body has focus.

      + + + + + +

      Get footnotes

      + + +

      First, select text in the document. + +

      +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-settings.yaml b/samples/word/50-document/manage-settings.yaml new file mode 100644 index 000000000..a14fe7961 --- /dev/null +++ b/samples/word/50-document/manage-settings.yaml @@ -0,0 +1,121 @@ +order: 9 +id: word-document-manage-settings +name: Manage settings +description: This sample shows how to add, edit, get, and delete custom settings on a document. +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("add-edit-setting").addEventListener("click", () => tryCatch(addEditSetting)); + document.getElementById("get-all-settings").addEventListener("click", () => tryCatch(getAllSettings)); + document.getElementById("delete-all-settings").addEventListener("click", () => tryCatch(deleteAllSettings)); + + async function addEditSetting() { + // Adds a new custom setting or + // edits the value of an existing one. + await Word.run(async (context) => { + const key = (document.getElementById("key") as HTMLInputElement).value; + if (key == "") { + console.error("Key shouldn't be empty."); + return; + } + + const value = (document.getElementById("value") as HTMLInputElement).value; + const settings: Word.SettingCollection = context.document.settings; + const setting: Word.Setting = settings.add(key, value); + setting.load(); + await context.sync(); + + console.log("Setting added or edited:", setting); + }); + } + + async function getAllSettings() { + // Gets all custom settings this add-in set on this document. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + settings.load("items"); + await context.sync(); + + if (settings.items.length == 0) { + console.log("There are no settings."); + } else { + console.log("All settings:"); + for (let i = 0; i < settings.items.length; i++) { + console.log(settings.items[i]); + } + } + }); + } + + async function deleteAllSettings() { + // Deletes all custom settings this add-in had set on this document. + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + settings.deleteAll(); + await context.sync(); + console.log("All settings deleted."); + }); + } + + // 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, get, and delete custom settings on a document. Settings created by an add-in + can + only be managed by that add-in.

      +
      +
      +

      Try it out

      +

      Add a new setting, or edit an existing one

      +
      + + +
      +
      + + +
      + +

      Get all settings

      + +

      Delete all 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/manage-styles.yaml b/samples/word/50-document/manage-styles.yaml new file mode 100644 index 000000000..0398d69e9 --- /dev/null +++ b/samples/word/50-document/manage-styles.yaml @@ -0,0 +1,342 @@ +order: 12 +id: word-document-manage-styles +name: Manage styles +description: This sample shows how to perform operations on the styles in the current document and how to add and delete custom styles. +host: WORD +api_set: + WordApiDesktop: '1.1' +script: + content: |- + document.getElementById("count").addEventListener("click", () => tryCatch(getCount)); + document.getElementById("add-style").addEventListener("click", () => tryCatch(addStyle)); + document.getElementById("properties").addEventListener("click", () => tryCatch(getProperties)); + document.getElementById("apply-style").addEventListener("click", () => tryCatch(applyStyle)); + document.getElementById("font-properties").addEventListener("click", () => tryCatch(setFontProperties)); + document.getElementById("paragraph-format").addEventListener("click", () => tryCatch(setParagraphFormat)); + document.getElementById("border-properties").addEventListener("click", () => tryCatch(setBorderProperties)); + document.getElementById("shading-properties").addEventListener("click", () => tryCatch(setShadingProperties)); + document.getElementById("delete-style").addEventListener("click", () => tryCatch(deleteStyle)); + + async function getCount() { + // Gets the number of available styles stored with the document. + await Word.run(async (context) => { + const styles: Word.StyleCollection = context.document.getStyles(); + const count = styles.getCount(); + await context.sync(); + + console.log(`Number of styles: ${count.value}`); + }); + } + + async function addStyle() { + // Adds a new style. + await Word.run(async (context) => { + const newStyleName = (document.getElementById("new-style-name") as HTMLInputElement).value; + if (newStyleName == "") { + console.warn("Enter a style name to add."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(newStyleName); + style.load(); + await context.sync(); + + if (!style.isNullObject) { + console.warn( + `There's an existing style with the same name '${newStyleName}'! Please provide another style name.` + ); + return; + } + + const newStyleType = ((document.getElementById("new-style-type") as HTMLSelectElement).value as unknown) as Word.StyleType; + context.document.addStyle(newStyleName, newStyleType); + await context.sync(); + + console.log(newStyleName + " has been added to the style list."); + }); + } + + async function getProperties() { + // Gets the properties of the specified style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.font.load(); + style.paragraphFormat.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + } + }); + } + + async function applyStyle() { + // Applies the specified style to a paragraph. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.paragraph) { + console.log(`The '${styleName}' style isn't a paragraph style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + const paragraph: Word.Paragraph = body.paragraphs.getFirst(); + paragraph.style = style.nameLocal; + console.log(`'${styleName}' style applied to first paragraph.`); + } + }); + } + + async function setFontProperties() { + // Updates font properties (e.g., color, size) of the specified style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update font properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const font: Word.Font = style.font; + font.color = "#FF0000"; + font.size = 20; + console.log(`Successfully updated font properties of the '${styleName}' style.`); + } + }); + } + + async function setParagraphFormat() { + // Sets certain aspects of the specified style's paragraph format e.g., the left indent size and the alignment. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update its paragraph format."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.paragraphFormat.leftIndent = 30; + style.paragraphFormat.alignment = Word.Alignment.centered; + console.log(`Successfully the paragraph format of the '${styleName}' style.`); + } + }); + } + + async function setBorderProperties() { + // Updates border properties (e.g., type, width, color) of the specified style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); + } + + async function setShadingProperties() { + // Updates shading properties (e.g., texture, pattern colors) of the specified style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update shading properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const shading: Word.Shading = style.shading; + shading.load(); + await context.sync(); + + shading.backgroundPatternColor = "blue"; + shading.foregroundPatternColor = "yellow"; + shading.texture = Word.ShadingTextureType.darkTrellis; + + console.log("Updated shading."); + } + }); + } + + async function deleteStyle() { + // Deletes the custom style. + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to delete."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.delete(); + console.log(`Successfully deleted custom style '${styleName}'.`); + } + }); + } + + // 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 how to manage styles. +
      +
      +

      Try it out

      +

      +

      Get current number of styles

      + +

      +

      Add a custom style

      +
      Give the style an alphanumeric name. Must start with a letter. Examples: NewName, newname1
      +

      + + +

      +

      + + +

      + +

      Use custom style

      + + +

      + +

      + +

      Update custom style

      + + +

      +

      Set font color to red and font size to 20.
      + +

      +

      Set paragraph left indent size to 30 and alignment to center.
      + +

      +

      Set outside border type to dashed, width to pt. 0.25, and color to green.
      + +

      +

      Set texture to DarkTrellis, foreground pattern color to yellow, and background pattern color to blue.
      + +

      Delete custom style

      +

      + + + +

      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/50-document/manage-tracked-changes.yaml b/samples/word/50-document/manage-tracked-changes.yaml new file mode 100644 index 000000000..30307f735 --- /dev/null +++ b/samples/word/50-document/manage-tracked-changes.yaml @@ -0,0 +1,210 @@ +order: 5 +id: word-document-manage-tracked-changes +name: Manage tracked changes +description: This samples shows how to manage tracked changes, including accepting and rejecting changes. +host: WORD +api_set: + WordApi: '1.6' +script: + content: |- + document.getElementById("get-all-tracked-changes").addEventListener("click", () => tryCatch(getAllTrackedChanges)); + document.getElementById("get-first-tracked-change-range").addEventListener("click", () => tryCatch(getFirstTrackedChangeRange)); + document.getElementById("get-next-tracked-change").addEventListener("click", () => tryCatch(getNextTrackedChange)); + document.getElementById("accept-first-tracked-change").addEventListener("click", () => tryCatch(acceptFirstTrackedChange)); + document.getElementById("reject-first-tracked-change").addEventListener("click", () => tryCatch(rejectFirstTrackedChange)); + document.getElementById("accept-all-tracked-changes").addEventListener("click", () => tryCatch(acceptAllTrackedChanges)); + document.getElementById("reject-all-tracked-changes").addEventListener("click", () => tryCatch(rejectAllTrackedChanges)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function getAllTrackedChanges() { + // Gets all tracked changes. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.load(); + await context.sync(); + + console.log(trackedChanges); + }); + } + + async function getFirstTrackedChangeRange() { + // Gets the range of the first tracked change. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const range: Word.Range = trackedChange.getRange(); + range.load(); + await context.sync(); + + console.log("range.text: " + range.text); + }); + } + + async function getNextTrackedChange() { + // Gets the next (second) tracked change. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + await context.sync(); + + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const nextTrackedChange: Word.TrackedChange = trackedChange.getNext(); + await context.sync(); + + nextTrackedChange.load(["author", "date", "text", "type"]); + await context.sync(); + + console.log(nextTrackedChange); + }); + } + + async function acceptFirstTrackedChange() { + // Accepts the first tracked change. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + trackedChange.load(); + await context.sync(); + + console.log("First tracked change:", trackedChange); + trackedChange.accept(); + console.log("Accepted the first tracked change."); + }); + } + + async function rejectFirstTrackedChange() { + // Rejects the first tracked change. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + trackedChange.load(); + await context.sync(); + + console.log("First tracked change:", trackedChange); + trackedChange.reject(); + console.log("Rejected the first tracked change."); + }); + } + + async function acceptAllTrackedChanges() { + // Accepts all tracked changes. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.acceptAll(); + console.log("Accepted all tracked changes."); + }); + } + + async function rejectAllTrackedChanges() { + // Rejects all tracked changes. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.rejectAll(); + console.log("Rejected all tracked changes."); + }); + } + + async function setup() { + // Updates the text and sets the font color to red. + await Word.run(async (context) => { + context.document.changeTrackingMode = Word.ChangeTrackingMode.off; + + context.document.body.insertText("AAA BBB CCC DDD EEE FFF", "Replace"); + + context.document.changeTrackingMode = Word.ChangeTrackingMode.trackAll; + context.document.body + .search("BBB") + .getFirst() + .insertText("WWW", "Replace"); + context.document.body + .search("DDD ") + .getFirst() + .delete(); + context.document.body + .search("FFF") + .getFirst() + .insertText("XXX ", "Start"); + }); + } + + // 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 manage tracked changes. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + + + + + +
      +
      +

      First, choose the Add sample text button. + +

      +

      First, choose the Add sample text 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/50-document/save-close.yaml b/samples/word/50-document/save-close.yaml new file mode 100644 index 000000000..5f8f691dc --- /dev/null +++ b/samples/word/50-document/save-close.yaml @@ -0,0 +1,137 @@ +order: 14 +id: word-document-save-close +name: Manage document save and close +description: Shows how to manage saving and closing document. +host: WORD +api_set: + WordApi: '1.5' +script: + content: |- + document.getElementById("save-no-prompt").addEventListener("click", () => tryCatch(saveNoPrompt)); + document.getElementById("save-after-prompt").addEventListener("click", () => tryCatch(saveAfterPrompt)); + document.getElementById("close-after-save").addEventListener("click", () => tryCatch(closeAfterSave)); + document.getElementById("close-no-save").addEventListener("click", () => tryCatch(closeWithoutSave)); + document.getElementById("save").addEventListener("click", () => tryCatch(save)); + document.getElementById("close").addEventListener("click", () => tryCatch(close)); + + async function saveNoPrompt() { + // Saves the document with the provided file name + // if it hasn't been saved before. + await Word.run(async (context) => { + const text = (document.getElementById("fileName-text") as HTMLInputElement).value; + context.document.save(Word.SaveBehavior.save, text); + await context.sync(); + }); + } + + async function saveAfterPrompt() { + // If the document hasn't been saved before, prompts + // user with options for if or how they want to save. + await Word.run(async (context) => { + context.document.save(Word.SaveBehavior.prompt); + await context.sync(); + }); + } + + async function closeAfterSave() { + // Closes the document after saving. + await Word.run(async (context) => { + context.document.close(Word.CloseBehavior.save); + }); + } + + async function closeWithoutSave() { + // Closes the document without saving any changes. + await Word.run(async (context) => { + context.document.close(Word.CloseBehavior.skipSave); + await context.sync(); + }); + } + + async function save() { + // Saves the document with default behavior + // for current state of the document. + await Word.run(async (context) => { + context.document.save(); + await context.sync(); + }); + } + + async function close() { + // Closes the document with default behavior + // for current state of the document. + await Word.run(async (context) => { + context.document.close(); + }); + } + + // 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 options for saving and closing the current document.

      +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/90-scenarios/correlated-objects-pattern.yaml b/samples/word/90-scenarios/correlated-objects-pattern.yaml new file mode 100644 index 000000000..32b972033 --- /dev/null +++ b/samples/word/90-scenarios/correlated-objects-pattern.yaml @@ -0,0 +1,166 @@ +order: 3 +id: word-scenarios-correlated-objects-pattern +name: Correlated objects pattern +description: Shows the performance benefits of avoiding `context.sync` calls in a loop. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.4' +script: + content: |- + document.getElementById("replace-placeholders").addEventListener("click", () => tryCatch(replacePlaceholders)); + document.getElementById("replace-placeholders-slow").addEventListener("click", () => tryCatch(replacePlaceholdersSlow)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + document.getElementById("add-lots-of-text").addEventListener("click", () => tryCatch(addLotsOfText)); + const jobMapping = [ + { job: "{Coordinator}", person: "Sally" }, + { job: "{Deputy}", person: "Bob" }, + { job: "{Manager}", person: "Kim" } + ]; + async function replacePlaceholders() { + Word.run(async (context) => { + const startTime = Date.now(); + let count = 0; + + // Find the locations of all the placeholder strings. + const allSearchResults = []; + for (let i = 0; i < jobMapping.length; i++) { + let options = Word.SearchOptions.newObject(context); + options.matchWildcards = false; + let searchResults = context.document.body.search(jobMapping[i].job, options); + searchResults.load('items'); + let correlatedSearchResult = { + rangesMatchingJob: searchResults, + personAssignedToJob: jobMapping[i].person + } + allSearchResults.push(correlatedSearchResult); + } + + // Sync to load those locations in the add-in. + await context.sync() + + // Replace the placeholder text at the known locations. + for (let i = 0; i < allSearchResults.length; i++) { + let correlatedObject = allSearchResults[i]; + + for (let j = 0; j < correlatedObject.rangesMatchingJob.items.length; j++) { + let targetRange = correlatedObject.rangesMatchingJob.items[j]; + let name = correlatedObject.personAssignedToJob; + targetRange.insertText(name, Word.InsertLocation.replace); + count++; + } + } + + await context.sync(); + console.log(`Replacing ${count} placeholders with the correlated objects pattern took ${Date.now() - startTime} milliseconds.`); + console.log() + }); + } + async function replacePlaceholdersSlow() { + Word.run(async (context) => { + const startTime = Date.now(); + let count = 0; + + // The context.sync calls in the loops will degrade performance. + for (let i = 0; i < jobMapping.length; i++) { + let options = Word.SearchOptions.newObject(context); + options.matchWildcards = false; + let searchResults = context.document.body.search(jobMapping[i].job, options); + searchResults.load('items'); + + await context.sync(); + + for (let j = 0; j < searchResults.items.length; j++) { + searchResults.items[j].insertText(jobMapping[i].person, Word.InsertLocation.replace); + count++; + await context.sync(); + } + } + console.log(`Replacing ${count} placeholders with in-loop sync statements took ${Date.now() - startTime} milliseconds.`); + }); + } + async function setup(timesToAddText: number = 1) { + await Word.run(async (context) => { + console.log("Setup beginning..."); + const body: Word.Body = context.document.body; + body.clear(); + while (timesToAddText > 0) { + body.insertParagraph( + "This defines the roles of {Coordinator}, {Deputy}, {Manager}.", + Word.InsertLocation.end + ); + body.insertParagraph( + "{Coordinator}: Oversees daily operations and ensures projects run smoothly by coordinating between different teams and resources.", + Word.InsertLocation.end + ); + body.insertParagraph( + "{Deputy}: Assists and supports senior management, often stepping in to make decisions or manage tasks in {Manager}'s absence.", + Word.InsertLocation.end + ); + body.insertParagraph( + "{Manager}: Leads the team, setting goals, planning strategies, and making decisions to achieve organizational objectives.", + Word.InsertLocation.end + ); + timesToAddText--; + } + await context.sync(); + console.log("Setup complete."); + }); + } + async function addLotsOfText() { + // Add the setup text 100 times. + setup(100); + } + // 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 the performance optimization gained from the correlated objects pattern. For more information, see Avoid using the context.sync method in loops.

      +
      +
      +

      Setup

      +

      Use Setup to create a basic text block with some placeholders. Use More text to create a longer text block to better see performance distinctions.

      + +
      +
      +

      Replace placeholder text

      + + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/90-scenarios/doc-assembly.yaml b/samples/word/90-scenarios/doc-assembly.yaml new file mode 100644 index 000000000..186206ba1 --- /dev/null +++ b/samples/word/90-scenarios/doc-assembly.yaml @@ -0,0 +1,171 @@ +order: 1 +id: word-scenarios-doc-assembly +name: Document assembly +description: Composes different parts of a Word document. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.1' +script: + content: |- + document.getElementById("insert-header").addEventListener("click", () => tryCatch(insertHeader)); + document.getElementById("add-paragraphs").addEventListener("click", () => tryCatch(addParagraphs)); + document.getElementById("add-content-controls").addEventListener("click", () => tryCatch(addContentControls)); + document.getElementById("change-customer").addEventListener("click", () => tryCatch(changeCustomer)); + document.getElementById("add-footer").addEventListener("click", () => tryCatch(addFooter)); + + async function insertHeader() { + await Word.run(async (context) => { + const header: Word.Range = context.document.body.insertText("This is a sample Heading 1 Title!!\n", + "Start" /*this means at the beginning of the body */); + header.styleBuiltIn = Word.BuiltInStyleName.heading1; + + await context.sync(); + }); + } + + async function addParagraphs() { + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.insertParagraph("Timeline", "End"); + paragraph.styleBuiltIn = "Heading2"; + const paragraph2: Word.Paragraph = context.document.body.insertParagraph("The Services shall commence on July 31, 2015, and shall continue through July 29, 2015.", "End"); + paragraph2.styleBuiltIn = "Normal"; + const paragraph3: Word.Paragraph = context.document.body.insertParagraph("Project Costs by Phase", "End"); + paragraph3.styleBuiltIn = "Heading2"; + // Note a content control with the title of "ProjectCosts" is added. Content will be replaced later. + const paragraph4: Word.Paragraph = context.document.body.insertParagraph("", "End"); + paragraph4.styleBuiltIn = "Normal"; + paragraph4.font.highlightColor = "#FFFF00"; + const contentControl: Word.ContentControl = paragraph4.insertContentControl(); + contentControl.title = "ProjectCosts"; + const paragraph5: Word.Paragraph = context.document.body.insertParagraph("Project Team", "End"); + paragraph5.styleBuiltIn = "Heading2"; + paragraph5.font.highlightColor = "#FFFFFF"; + const paragraph6: Word.Paragraph = context.document.body.insertParagraph("Terms of Work", "End"); + paragraph6.styleBuiltIn = "Heading1"; + const paragraph7: Word.Paragraph = context.document.body.insertParagraph("Contractor shall provide the Services and Deliverable(s) as follows:", "End"); + paragraph7.styleBuiltIn = "Normal"; + const paragraph8: Word.Paragraph = context.document.body.insertParagraph("Out-of-Pocket Expenses / Invoice Procedures", "End"); + paragraph8.styleBuiltIn = "Heading2"; + const paragraph9 : Word.Paragraph= context.document.body.insertParagraph("Client will be invoiced monthly for the consulting services and T&L expenses. Standard Contractor invoicing is assumed to be acceptable. Invoices are due upon receipt. client will be invoiced all costs associated with out-of-pocket expenses (including, without limitation, costs and expenses associated with meals, lodging, local transportation and any other applicable business expenses) listed on the invoice as a separate line item. Reimbursement for out-of-pocket expenses in connection with performance of this SOW, when authorized and up to the limits set forth in this SOW, shall be in accordance with Client's then-current published policies governing travel and associated business expenses, which information shall be provided by the Client Project Manager.", "End"); + paragraph9.styleBuiltIn = "Normal"; + // Insert a page break at the end of the document. + context.document.body.insertBreak("Page", "End"); + + await context.sync(); + }); + } + + async function addContentControls() { + // Simulates creation of a template. First searches the document for instances of the string "Contractor", + // then changes the format of each search result, + // then wraps each search result within a content control, + // finally sets a tag and title property on each content control. + await Word.run(async (context) => { + const results: Word.RangeCollection = context.document.body.search("Contractor"); + results.load("font/bold"); + + // Check to make sure these content controls haven't been added yet. + const customerContentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("customer"); + customerContentControls.load("text"); + await context.sync(); + + if (customerContentControls.items.length === 0) { + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.bold = true; + let cc: Word.ContentControl = results.items[i].insertContentControl(); + cc.tag = "customer"; // This value is used in the next step of this sample. + cc.title = "Customer Name " + i; + } + } + await context.sync(); + }); + } + + async function changeCustomer() { + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("customer"); + contentControls.load("text"); + + await context.sync(); + + for (let i = 0; i < contentControls.items.length; i++) { + contentControls.items[i].insertText("Fabrikam", "Replace"); + } + + await context.sync(); + }); + } + + async function addFooter() { + await Word.run(async (context) => { + context.document.sections.getFirst() + .getFooter("Primary").insertParagraph("Confidential", "End"); + + 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 demonstrates how to use the basic document assembly objects. It creates a sample document, searches for text, + creates a template, and adds paragraphs and footers. +
      +
      +

      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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/90-scenarios/multiple-property-set.yaml b/samples/word/90-scenarios/multiple-property-set.yaml new file mode 100644 index 000000000..bbd154569 --- /dev/null +++ b/samples/word/90-scenarios/multiple-property-set.yaml @@ -0,0 +1,112 @@ +order: 2 +id: word-scenarios-multiple-property-set +name: Set multiple properties at once +description: Sets multiple properties at once with the API object set() method. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.3' +script: + content: |- + document.getElementById("set-multiple-properties-with-object").addEventListener("click", () => tryCatch(setMultiplePropertiesWithObject)); + document.getElementById("copy-properties-from-paragraph").addEventListener("click", () => tryCatch(copyPropertiesFromParagraph)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function setMultiplePropertiesWithObject() { + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + paragraph.set({ + leftIndent: 30, + font: { + bold: true, + color: "red" + } + }); + + await context.sync(); + }); + } + + async function copyPropertiesFromParagraph() { + await Word.run(async (context) => { + const firstParagraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + const secondParagraph: Word.Paragraph = firstParagraph.getNext(); + firstParagraph.load("text, font/color, font/bold, leftIndent"); + + await context.sync(); + + secondParagraph.set(firstParagraph); + + await context.sync(); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 format text using the object.set method.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      Set the styling of the first paragraph.

      + +

      Now copy the formatting of the first paragraph to the second.

      + +
      + 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/samples/word/99-fabric/fabric-insert-form-data.yaml b/samples/word/99-fabric/fabric-insert-form-data.yaml deleted file mode 100644 index 448fa0702..000000000 --- a/samples/word/99-fabric/fabric-insert-form-data.yaml +++ /dev/null @@ -1,211 +0,0 @@ -id: word-fabric-insert-form-data -name: Fabric JS - Using form data -description: Takes form data entered in the task pane and pushes it into the document. This is meant to show the use of common Fabric elements. -author: OfficeDev -host: WORD -api_set: - WordApi: 1.1 -script: - content: | - $("#run").click(run); - $("#clear").click(clear); - $('#tgl-fruit-vege').click(switchLabels); - - initializeUI(); - - let acceptCheckBox; - - async function switchLabels() { - if ($('#tgl-fruit-vege').children('label').hasClass('is-selected')) { - $('#lbl-title').text('Favorite vegetable'); - $('#lbl-snack').text('Is this vegetable eaten as a snack?'); - } - else { - $('#lbl-title').text('Favorite fruit'); - $('#lbl-snack').text('Is this fruit eaten as a snack?'); - } - } - - async function run() { - if (acceptCheckBox.getValue()) { - $('#error-message').hide(); - try { - await Word.run(async (context) => { - const strName = `Name: ${$('#fruit-name').val()}`; - const strColor = `Color: ${$('#color').val()}`; - - let strEatenSnack = 'Eaten as a snack: '; - const eatSnack = $('.ms-RadioButton-field'); - eatSnack.each(function () { - var _this = $(this); - if (_this.hasClass('is-checked')) { - strEatenSnack = strEatenSnack + (_this.siblings('input').val()); - } - }); - - const strAdditionalComments = 'Additional Comments: ' + $('#txtAdditionalComments').val(); - const strAcceptedTC = 'Terms and conditions accepted: ' + acceptCheckBox.getValue(); - - const body = context.document.body; - body.insertParagraph(strName, Word.InsertLocation.end); - body.insertParagraph(strColor, Word.InsertLocation.end); - body.insertParagraph(strEatenSnack, Word.InsertLocation.end); - body.insertParagraph(strAdditionalComments, Word.InsertLocation.end); - body.insertParagraph(strAcceptedTC, Word.InsertLocation.end); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - else { - $('#error-message').show(); - } - } - - async function clear() { - try { - $('#fruit-name').val(''); - $('#color').siblings('ul.ms-Dropdown-items').children('.is-selected').removeClass('is-selected'); - $('#color').siblings('.ms-Dropdown-title').text('Black'); - $('#color').val('Black'); - $(':input').not(':button, :submit, :reset, :hidden, :checkbox, :radio').val(''); - $('#choicefieldgroup-no').removeClass('is-checked'); - $('#choicefieldgroup-yes').addClass('is-checked'); - acceptCheckBox.unCheck(); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } - } - - async function initializeUI() { - const textFieldElements = document.querySelectorAll(".ms-TextField"); - for (let i = 0; i < textFieldElements.length; i++) { - new fabric['TextField'](textFieldElements[i]); - } - - const dropdownHTMLElements = document.querySelectorAll('.ms-Dropdown'); - for (let i = 0; i < dropdownHTMLElements.length; ++i) { - new fabric['Dropdown'](dropdownHTMLElements[i]); - } - - const checkBoxElements = document.querySelectorAll(".ms-CheckBox"); - acceptCheckBox = new fabric['CheckBox'](checkBoxElements[0]); - - const choiceFieldGroupElements = document.querySelectorAll(".ms-ChoiceFieldGroup"); - for (let i = 0; i < choiceFieldGroupElements.length; i++) { - new fabric['ChoiceFieldGroup'](choiceFieldGroupElements[i]); - } - - const toggleElements = document.querySelectorAll(".ms-Toggle"); - for (let i = 0; i < toggleElements.length; i++) { - new fabric['Toggle'](toggleElements[i]); - } - - $('#error-message').hide(); - } - - - // To avoid compile errors for the undeclared "fabric" object, declare it to the type-system here. - declare var fabric; - language: typescript -template: - content: |- -
      - Fruit or Vegetable? - - -
      -

      Favorite fruit

      -
      - - -
      -
      - - - -
      -
      -
      - -
      -
        -
      • - - -
      • -
      • - - -
      • -
      -
      -

      -

      - - -
      -
      - - -
      -
      -
      -
      - -
      -
      - Please accept the terms and conditions. -
      -
      -
      -

      -
      - - - language: html -style: - content: '' - language: css -libraries: |- - // Office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.js - - // NPM libraries - jquery@3.1.1 - office-ui-fabric-js@1.4.0/dist/js/fabric.min.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 - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.min.js - core-js@2.4.1/client/core.min.js - - // IntelliSense: Use dt~library_name for DefinitelyTyped or URLs to d.ts files - @types/office-js - @types/jquery - @types/core-js - @microsoft/office-js-helpers@0.7.4/dist/office.helpers.d.ts \ No newline at end of file diff --git a/samples/word/99-preview-apis/close-document-window.yaml b/samples/word/99-preview-apis/close-document-window.yaml new file mode 100644 index 000000000..7908cc0e5 --- /dev/null +++ b/samples/word/99-preview-apis/close-document-window.yaml @@ -0,0 +1,61 @@ +id: word-close-document-window +name: Close document window +description: Shows how to close document window. +host: WORD +api_set: + WordApi: '1.10' +script: + content: | + document.getElementById("close-with-save-prompt").addEventListener("click", () => tryCatch(closeWithSavePrompt)); + + async function closeWithSavePrompt() { + await Word.run(async (context) => { + // Closes the document window, prompting to save if this is a new document. + const window: Word.Window = context.document.activeWindow; + const closeOptions: Word.WindowCloseOptions = { saveChanges: Word.SaveConfiguration.promptToSaveChanges }; + console.log("About to close the document window..."); + window.close(closeOptions); + }); + } + + // 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 how to close the document window. +
      +
      +

      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/beta/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/99-preview-apis/insert-and-change-content-controls.yaml b/samples/word/99-preview-apis/insert-and-change-content-controls.yaml new file mode 100644 index 000000000..c4f5761e8 --- /dev/null +++ b/samples/word/99-preview-apis/insert-and-change-content-controls.yaml @@ -0,0 +1,201 @@ +id: word-insert-and-change-content-controls +name: Content control basics +description: Inserts, updates, and retrieves content controls. +author: OfficeDev +host: WORD +api_set: + WordApi: '1.10' +script: + content: | + document.getElementById("insert-controls").addEventListener("click", () => tryCatch(insertContentControls)); + document.getElementById("change-controls").addEventListener("click", () => tryCatch(modifyContentControls)); + document.getElementById("set-state").addEventListener("click", () => tryCatch(setState)); + document.getElementById("reset-state").addEventListener("click", () => tryCatch(resetState)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + async function insertContentControls() { + // Traverses each paragraph of the document and wraps a content control on each with either a even or odd tags. + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + // For even, tag "even". + if (i % 2 === 0) { + contentControl.tag = "even"; + } else { + contentControl.tag = "odd"; + } + } + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); + } + + async function modifyContentControls() { + // Adds title and colors to odd and even content controls and changes their appearance. + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + let evenContentControls = context.document.contentControls.getByTag("even"); + let oddContentControls = context.document.contentControls.getByTag("odd"); + evenContentControls.load("length"); + oddContentControls.load("length"); + + await context.sync(); + + for (let i = 0; i < evenContentControls.items.length; i++) { + // Change a few properties and append a paragraph. + evenContentControls.items[i].set({ + color: "red", + title: "Odd ContentControl #" + (i + 1), + appearance: Word.ContentControlAppearance.tags + }); + evenContentControls.items[i].insertParagraph("This is an odd content control", "End"); + } + + for (let j = 0; j < oddContentControls.items.length; j++) { + // Change a few properties and append a paragraph. + oddContentControls.items[j].set({ + color: "green", + title: "Even ContentControl #" + (j + 1), + appearance: "Tags" + }); + oddContentControls.items[j].insertHtml("This is an even content control", "End"); + } + + await context.sync(); + }); + } + + async function setState() { + // Sets the state of the first content control. + await Word.run(async (context) => { + const state = ((document.getElementById("state-to-set") as HTMLSelectElement) + .value as unknown) as Word.ContentControlState; + let firstContentControl = context.document.contentControls.getFirstOrNullObject(); + await context.sync(); + + if (firstContentControl.isNullObject) { + console.warn("There are no content controls in this document."); + return; + } + + firstContentControl.setState(state); + firstContentControl.load("id"); + await context.sync(); + + console.log(`Set state of first content control with ID ${firstContentControl.id} to ${state}.`); + }); + } + + async function resetState() { + // Resets the state of the first content control. + await Word.run(async (context) => { + let firstContentControl = context.document.contentControls.getFirstOrNullObject(); + await context.sync(); + + if (firstContentControl.isNullObject) { + console.warn("There are no content controls in this document."); + return; + } + + firstContentControl.resetState(); + firstContentControl.load("id"); + await context.sync(); + + console.log(`Reset state of first content control with ID: ${firstContentControl.id}`); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph("One more paragraph.", "Start"); + body.insertParagraph("Inserting another paragraph.", "Start"); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 demonstrates how to insert content controls and change their properties. +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      + Insert content controls on each paragraph. + +

      + Modify content control appearance and content. + +

      Preview features

      + Set state of first content control. +
      + + + +

      + Reset state of first content control. + +

      + 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/beta/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/99-preview-apis/manage-comments.yaml b/samples/word/99-preview-apis/manage-comments.yaml new file mode 100644 index 000000000..8935b24d3 --- /dev/null +++ b/samples/word/99-preview-apis/manage-comments.yaml @@ -0,0 +1,362 @@ +id: word-manage-comments +name: Manage comments +description: This sample shows how to perform operations on comments (including insert, reply, get, edit, resolve, and delete) and use comment events. +host: WORD +api_set: + WordApi: '1.10' +script: + content: |- + document.getElementById("register-event-handlers").addEventListener("click", () => tryCatch(registerEventHandlers)); + document.getElementById("insert").addEventListener("click", () => tryCatch(insertComment)); + document.getElementById("edit").addEventListener("click", () => tryCatch(editFirstCommentInSelection)); + document.getElementById("reply").addEventListener("click", () => tryCatch(replyToFirstActiveCommentInSelection)); + document.getElementById("resolve").addEventListener("click", () => tryCatch(toggleResolvedStatusOfFirstCommentInSelection)); + document.getElementById("range").addEventListener("click", () => tryCatch(getFirstCommentRangeInSelection)); + document.getElementById("get-comments-in-selection").addEventListener("click", () => tryCatch(getCommentsInSelection)); + document.getElementById("get-replies-to-first-comment-in-selection").addEventListener("click", () => tryCatch(getRepliesToFirstCommentInSelection)); + document.getElementById("delete").addEventListener("click", () => tryCatch(deleteFirstCommentInSelection)); + document.getElementById("get-comments").addEventListener("click", () => tryCatch(getComments)); + document.getElementById("deregister-event-handlers").addEventListener("click", () => tryCatch(deregisterEventHandlers)); + document.getElementById("setup").addEventListener("click", () => tryCatch(setup)); + + let eventContexts = []; + + async function registerEventHandlers() { + // Registers event handlers. + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + } + + async function insertComment() { + // Sets a comment on the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("comment-text") as HTMLInputElement).value; + const comment: Word.Comment = context.document.getSelection().insertComment(text); + + // Load object to log in the console. + comment.load(); + await context.sync(); + + console.log("Comment inserted:", comment); + }); + } + + async function editFirstCommentInSelection() { + // Edits the first active comment in the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("edit-comment-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (!firstActiveComment) { + console.warn("No active comment was found in the selection, so couldn't edit."); + return; + } + + firstActiveComment.content = text; + + // Load object to log in the console. + firstActiveComment.load(); + await context.sync(); + + console.log("Comment content changed:", firstActiveComment); + }); + } + + async function replyToFirstActiveCommentInSelection() { + // Replies to the first active comment in the selected content. + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); + } + + async function toggleResolvedStatusOfFirstCommentInSelection() { + // Toggles Resolved status of the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document + .getSelection() + .getComments() + .getFirstOrNullObject(); + comment.load("resolved"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to toggle."); + return; + } + + // Toggle resolved status. + // If the comment is active, set as resolved. + // If it's resolved, set resolved to false. + const resolvedBefore = comment.resolved; + console.log(`Comment Resolved status (before): ${resolvedBefore}`); + comment.resolved = !resolvedBefore; + comment.load("resolved"); + await context.sync(); + + console.log(`Comment Resolved status (after): ${comment.resolved}`); + }); + } + + async function getFirstCommentRangeInSelection() { + // Gets the range of the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); + } + + async function getCommentsInSelection() { + // Gets the comments in the selected content. + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("Comments:", comments); + }); + } + + async function getRepliesToFirstCommentInSelection() { + // Gets the replies to the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("replies"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no replies to get."); + return; + } + + const replies: Word.CommentReplyCollection = comment.replies; + console.log("Replies to the first comment:", replies); + }); + } + + async function deleteFirstCommentInSelection() { + // Deletes the first comment in the selected content. + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.delete(); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to delete."); + return; + } + + console.log("Comment deleted."); + }); + } + + async function getComments() { + // Gets the comments in the document body. + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.body.getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("All comments:", comments); + }); + } + + async function deregisterEventHandlers() { + // Deregisters event handlers. + await Word.run(async (context) => { + for (let i = 0; i < eventContexts.length; i++) { + await Word.run(eventContexts[i].context, async (context) => { + eventContexts[i].remove(); + }); + } + + await context.sync(); + + eventContexts = []; + console.log("Removed event handlers."); + }); + } + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } + + async function onChangedHandler(event: Word.CommentEventArgs) { + await Word.run(async (context) => { + console.log( + `${event.type} event detected. ${event.changeType} change made. Event source: ${event.source}. Comment info:`, event.commentDetails + ); + }); + } + + async function setup() { + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "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 operations on comments and how to use comment events.

      +

      Important: Comment events APIs are currently in preview. If this snippet doesn't work, try using + Word + on a different platform.

      +
      +
      +

      Set up

      + +
      +
      +

      Try it out

      +

      + +

      +

      Manage comments in selection

      +

      Select content in document body before proceeding.

      +

      + + + +

      +

      + + + +

      +

      + + + +

      +

      + +

      +

      + +

      +

      + +

      +

      + +

      +

      + +

      +

      Manage comments in document body

      +

      + +

      +

      + +

      +
      + 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/beta/hosted/office.js + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js-preview/index.d.ts + + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css \ No newline at end of file diff --git a/samples/word/default.yaml b/samples/word/default.yaml index 5168945d5..d6e45d828 100644 --- a/samples/word/default.yaml +++ b/samples/word/default.yaml @@ -1,56 +1,57 @@ id: word-word-default name: Blank snippet -description: Create a new snippet from a blank template. +description: Creates a new snippet from a blank template. author: OfficeDev host: WORD api_set: - WordApi: 1.1 + WordApi: '1.1' script: - content: | - $("#run").click(() => tryCatch(run)); + content: |- + document.getElementById("run").addEventListener("click", () => tryCatch(run)); async function run() { await Word.run(async (context) => { + const body = context.document.body; - OfficeHelpers.UI.notify("Your code goes here"); + console.log("Your code goes here"); await context.sync(); }); } - /** Default helper for invoking an action and handling errors. */ + // 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); + // 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: | + content: |- language: html style: - content: | - /* Your style goes here */ + 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: | +libraries: |- https://appsforoffice.microsoft.com/lib/1/hosted/office.js - https://appsforoffice.microsoft.com/lib/1/hosted/office.d.ts - - 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 + https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/master/types/office-js/index.d.ts - jquery@3.1.1 - @types/jquery \ No newline at end of file + https://unpkg.com/office-ui-fabric-core@11.1.0/dist/css/fabric.min.css + https://unpkg.com/office-ui-fabric-js@1.5.0/dist/css/fabric.components.min.css diff --git a/snippet-extractor-metadata/excel.xlsx b/snippet-extractor-metadata/excel.xlsx index 51b47f6db..60920aee9 100644 Binary files a/snippet-extractor-metadata/excel.xlsx and b/snippet-extractor-metadata/excel.xlsx differ diff --git a/snippet-extractor-metadata/outlook.xlsx b/snippet-extractor-metadata/outlook.xlsx new file mode 100644 index 000000000..769da162a Binary files /dev/null and b/snippet-extractor-metadata/outlook.xlsx differ diff --git a/snippet-extractor-metadata/powerpoint.xlsx b/snippet-extractor-metadata/powerpoint.xlsx new file mode 100644 index 000000000..27d2f9dba Binary files /dev/null and b/snippet-extractor-metadata/powerpoint.xlsx differ diff --git a/snippet-extractor-metadata/word.xlsx b/snippet-extractor-metadata/word.xlsx new file mode 100644 index 000000000..8ec0f93ba Binary files /dev/null and b/snippet-extractor-metadata/word.xlsx differ diff --git a/snippet-extractor-output/excel.yaml b/snippet-extractor-output/excel.yaml deleted file mode 100644 index 09c74bb48..000000000 --- a/snippet-extractor-output/excel.yaml +++ /dev/null @@ -1,2050 +0,0 @@ -Excel.Binding.onDataChanged: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const salesTable = sheet.tables.getItem("SalesTable"); - const dataRange = salesTable.getDataBodyRange(); - const salesByQuarterBinding = context.workbook.bindings.add(dataRange, "range", "SalesByQuarter"); - salesByQuarterBinding.onDataChanged.add(onSalesDataChanged); - - OfficeHelpers.UI.notify("The handler is registered.", "Change the value in one of the data cells and watch this message banner. (Be sure to complete the edit by pressing Enter or clicking in another cell.)"); - - await context.sync(); - }); -Excel.NamedItemCollection.add: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - const headerRange = sheet.getRange("A1:E1"); - sheet.names.add("ExpensesHeader", headerRange); - const namedItems = sheet.names.load("name, type"); - - await context.sync(); - - let namedItemsList = `This workbook contains ${namedItems.items.length} named item(s):`; - for (let i = 0; i < namedItems.items.length; i++) { - namedItemsList += JSON.stringify(namedItems.items[i]); - } - OfficeHelpers.UI.notify(namedItemsList); - - await context.sync(); - }); - - |- - try { - await Excel.run(async (context) => { - - await OfficeHelpers.ExcelUtilities.forceCreateSheet(context.workbook, "Sample"); - - const sheet = context.workbook.worksheets.getItem("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.names.add("TotalAmount", "=SUM(ExpensesTable[AMOUNT])"); - - sheet.getRange("D11").values = [["=TotalAmount"]]; - - if (Office.context.requirements.isSetSupported("ExcelApi", 1.2)) { - sheet.getUsedRange().format.autofitColumns(); - sheet.getUsedRange().format.autofitRows(); - } - - sheet.activate(); - - await context.sync(); - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } -Excel.NamedItem.delete: - - |- - try { - await Excel.run(async (context) => { - - const sheet = context.workbook.worksheets.getItem("Sample"); - - sheet.names.getItem("TotalAmount").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])"]]; - - await context.sync(); - - }); - } - catch (error) { - OfficeHelpers.UI.notify(error); - OfficeHelpers.Utilities.log(error); - } -Excel.NamedItem.formula: - - |- - 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) { - OfficeHelpers.UI.notify(`There is no named item with the name "MyRange".`); - } 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(); - - OfficeHelpers.UI.notify(`Just updated the named item "${myNamedItem.name}" -- it's now located here: ${myNamedItem.formula}`); - } - }); -Excel.SettingCollection.onSettingsChanged: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.onSettingsChanged.add(onChangedSetting); - OfficeHelpers.UI.notify("Handler registered", ""); - - await context.sync(); - }); -Excel.SettingCollection.add: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - settings.onSettingsChanged.add(onChangedSetting); - OfficeHelpers.UI.notify("Handler registered", ""); - - await context.sync(); - }); -Excel.Setting.delete: - - |- - 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) { - OfficeHelpers.UI.notify("The setting has been deleted"); - } else { - OfficeHelpers.UI.notify("The setting was not deleted"); - } - - await context.sync(); - }); -Excel.Setting.getItemOrNullObject: - - |- - 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) { - OfficeHelpers.UI.notify("The setting has been deleted"); - } else { - OfficeHelpers.UI.notify("The setting was not deleted"); - } - - await context.sync(); - }); -Excel.Range.getUsedRangeOrNullObject: - - |- - 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) { - OfficeHelpers.UI.notify("Need Data to Make Chart", "To create a meaningful chart, 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(); - }); -Excel.Range.getIntersectionOrNullObject: - - |- - 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 method for how to - // test this code path. - reportMissingData("Asian"); - } else { - createContinentChart(sheet, "Asian", asianContestRange, "A9", "F24"); - } - - if (europeanContestRange.isNullObject) { - // See the declaration of this method for how to - // test this code path. - reportMissingData("European"); - } else { - createContinentChart(sheet, "European", europeanContestRange, "A25", "F40"); - } - - await context.sync(); - }); -Excel.Range.getUsedRange: - - |- - 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 method for how to - // test this code path. - reportMissingData("Asian"); - } else { - createContinentChart(sheet, "Asian", asianContestRange, "A9", "F24"); - } - - if (europeanContestRange.isNullObject) { - // See the declaration of this method for how to - // test this code path. - reportMissingData("European"); - } else { - createContinentChart(sheet, "European", europeanContestRange, "A25", "F40"); - } - - await context.sync(); - }); -Excel.CustomXmlPartCollection.set: - - |- - 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(); - }); - - |- - 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(); - }); -Excel.CustomXmlPart.add: - - |- - 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(); - }); -Excel.CustomXmlPart.getItem: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - - await context.sync(); - - 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(); - }); -Excel.CustomXmlPart.getXml: - - |- - 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(); - }); -Excel.CustomXmlPart.id: - - |- - 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(); - }); -Excel.CustomXmlPartCollection.setXml: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - - await context.sync(); - - 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(); - }); -Excel.CustomXmlPartCollection.delete: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - - await context.sync(); - - 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(); - }); -Excel.CustomXmlPartScopedCollection.getItemOrNullObject: - - |- - await Excel.run(async (context) => { - const settings = context.workbook.settings; - const xmlPartIDSetting = settings.getItem("ContosoReviewXmlPartId").load("value"); - - await context.sync(); - - 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(); - }); -Excel.CustomXmlPartScopedCollection.getByNamespace: - - |- - 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 { - OfficeHelpers.UI.notify(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. - There should be exactly 1.`); - } - - await context.sync(); - }); -Excel.Worksheet.getCount: - - |- - 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 { - OfficeHelpers.UI.notify(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. - There should be exactly 1.`); - } - - await context.sync(); - }); -Excel.Worksheet.getOnlyItem: - - |- - 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 { - OfficeHelpers.UI.notify(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. - There should be exactly 1.`); - } - - await context.sync(); - }); -Excel.WorksheetCollection.getPrevious: - - |- - 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); - OfficeHelpers.UI.notify("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(); - }); -Excel.WorksheetCollection.getNext: - - |- - 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); - OfficeHelpers.UI.notify(`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(); - }); -Excel.ConditionalFormatCollection.getFirst: - - |- - 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); - OfficeHelpers.UI.notify(`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(); - }); -Excel.ConditionalFormat.getLast: - - |- - 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); - OfficeHelpers.UI.notify(`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(); - }); -Excel.ColorScaleConditionalFormat.add: - - |- - 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(); - }); -Excel.ConditionalFormat.colorScale: - - |- - 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(); - }); -Excel.PresetCriteriaConditionalFormat.criteria: - - |- - 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(); - }); -Excel.ConditionalPresetCriteriaRule.preset: - - |- - 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(); - }); -Excel.ConditionalFormat.rule: - - |- - 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(); - }); - - |- - 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(); - }); -Excel.DataBarConditionalFormat.criterion: - - |- - 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(); - }); -Excel.ConditionalFormat.dataBar: - - |- - 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(); - }); -Excel.IconSetConditionalFormat.barDirection: - - |- - 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(); - }); -Excel.IconSetConditionalFormat.iconSet: - - |- - 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 this method does below, 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(); - }); -Excel.ConditionalIconCriterion.style: - - |- - 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 this method does below, 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(); - }); -Excel.ConditionalIconCriterion.criteria: - - |- - 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 this method does below, 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(); - }); -Excel.ConditionalIconCriterion.type: - - |- - 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 this method does below, 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(); - }); -Excel.ConditionalFormat.operator: - - |- - 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 this method does below, 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(); - }); - - |- - 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(); - }); -Excel.TextConditionalFormat.formula: - - |- - 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 this method does below, 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(); - }); -Excel.TextConditionalFormat.textComparison: - - |- - 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(); - }); -Excel.ConditionalTextComparisonRule.format: - - |- - 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(); - }); -Excel.ConditionalTextComparisonRule.rule: - - |- - 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(); - }); -Excel.CellValueConditionalFormat.text: - - |- - 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(); - }); -Excel.CellValueConditionalFormat.cellValue: - - |- - 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(); - }); -Excel.ConditionalCellValueRule.format: - - |- - 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(); - }); -Excel.ConditionalCellValueRule.rule: - - |- - 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(); - }); -Excel.ConditionalFormat.formula1: - - |- - 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(); - }); -Excel.CustomConditionalFormat.operator: - - |- - 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(); - }); -Excel.CustomConditionalFormat.custom: - - |- - 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(); - }); -Excel.ConditionalFormatRule.format: - - |- - 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(); - }); -Excel.ConditionalFormatCollection.formula: - - |- - 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(); - }); -Excel.ConditionalFormat.type: - - |- - 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(); - - $("#conditional-formats li").remove(); - if (cfRangePairs.length > 0) { - cfRangePairs.forEach(item => { - let $p = $("

      ").text( - `${item.cf.type}`) - let $li = $(`
    • `); - $li.append($p); - $("#conditional-formats").append($li); - $(".conditional-formats").show()[0].scrollIntoView(); - }) - } - else { - OfficeHelpers.UI.notify("None to display", "No conditional formats in workbook", "warning"); - } - }); -Excel.ConditionalFormatCollection.getItemAt: - - |- - 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(); - - $("#conditional-formats li").remove(); - if (cfRangePairs.length > 0) { - cfRangePairs.forEach(item => { - let $p = $("

      ").text( - `${item.cf.type}`) - let $li = $(`
    • `); - $li.append($p); - $("#conditional-formats").append($li); - $(".conditional-formats").show()[0].scrollIntoView(); - }) - } - else { - OfficeHelpers.UI.notify("None to display", "No conditional formats in workbook", "warning"); - } - }); -Excel.Range.getRange: - - |- - 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(); - - $("#conditional-formats li").remove(); - if (cfRangePairs.length > 0) { - cfRangePairs.forEach(item => { - let $p = $("

      ").text( - `${item.cf.type}`) - let $li = $(`
    • `); - $li.append($p); - $("#conditional-formats").append($li); - $(".conditional-formats").show()[0].scrollIntoView(); - }) - } - else { - OfficeHelpers.UI.notify("None to display", "No conditional formats in workbook", "warning"); - } - }); -Excel.RangeHyperlink.clearAll: - - |- - 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(); - }); -Excel.RangeHyperlink.hyperlink: - - |- - 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(); - - OfficeHelpers.UI.notify("Created a hyperlink to a URL for each of the products in the first table."); - }); -Excel.RangeHyperlink.address: - - |- - 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(); - - OfficeHelpers.UI.notify("Created a hyperlink to a URL for each of the products in the first table."); - }); -Excel.RangeHyperlink.screenTip: - - |- - 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(); - - OfficeHelpers.UI.notify("Created a hyperlink to a URL for each of the products in the first table."); - }); -Excel.RangeFormat.textToDisplay: - - |- - 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(); - - OfficeHelpers.UI.notify("Created a hyperlink to a URL for each of the products in the first table."); - }); -Excel.WorksheetFreezePanes.documentReference: - - |- - 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(); - - OfficeHelpers.UI.notify("Created a hyperlink to a location in this workbook for each of the products in the second table."); - }); -Excel.WorksheetFreezePanes.textOrientation: - - |- - 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(); - }); -Excel.WorksheetFreezePanes.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(); - }); -Excel.WorksheetFreezePanes.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(); - }); -Excel.WorksheetFreezePanes.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(); - }); -Excel.Worksheet.getLocationOrNullObject: - - |- - 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) { - OfficeHelpers.UI.notify(`The worksheet does not contain a frozen pane.`); - } else { - OfficeHelpers.UI.notify(`The address of the frozen range (cells that are frozen in the top-and-left-most pane) is "${frozenRange.address}"`); - } - }); -Excel.Worksheet.unfreeze: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - sheet.freezePanes.unfreeze(); - - await context.sync(); - }); -Excel.ChartTrendlineCollection.gridlines: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getActiveWorksheet(); - sheet.gridlines = true; - - await context.sync(); - }); -Excel.ChartTrendline.tabColor: - - |- - await Excel.run(async (context) => { - const activeSheet = context.workbook.worksheets.getActiveWorksheet(); - activeSheet.tabColor = "#FF0000"; - - await context.sync(); - }); -Excel.ChartTrendlineFormat.add: - - |- - 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(); - }); -Excel.ChartTrendlineFormat.type: - - |- - 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); - }); -Excel.ChartSeriesCollection.line: - - |- - 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. - // In this example, it's #4472c4 which is blue. - 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); - }); -Excel.ChartSeries.line: - - |- - 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); - }); -Excel.ChartAxis.delete: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - let series = seriesCollection.getItemAt(0); - - // Delete the first series. - series.delete(); - - await context.sync(); - }); -Excel.ChartAxis.setValues: - - |- - await Excel.run(async (context) => { - const sheet = context.workbook.worksheets.getItem("Sample"); - - let seriesCollection = sheet.charts.getItemAt(0).series; - - // Add new series. - let series = seriesCollection.add("New Product"); - let values = sheet.getRange("E2:E7"); - - // Set the vertical values for the series. - series.setValues(values); - seriesCollection.load("count"); - - await context.sync(); - - OfficeHelpers.UI.notify("Number of series = " + seriesCollection.count); - }); -Excel.ChartFormatString.displayUnit: - - |- - 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(); - - OfficeHelpers.UI.notify("The vertical axis display unit is: " + valueAxis.displayUnit); - }); -Excel.ChartFill.showDisplayUnitLabel: - - |- - 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(); - }); -Excel.DocumentProperties.font: - - |- - 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(); - }); -Excel.Style.setSolidColor: - - |- - 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(); - - OfficeHelpers.UI.notify("Successfully set chart point color to red (for the third item in series 1)."); - }); -Excel.StyleCollection.properties: - - |- - 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(); - - OfficeHelpers.UI.notify("Set the following document properties: title, subject, keywords, comments, category, manager, company."); - }); -Excel.StyleCollection.style: - - |- - 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(); - }); -Excel.Style.getItem: - - |- - 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.orientation = 38; - newStyle.addIndent = true; - newStyle.includeProtection = true; - newStyle.shrinkToFit = true; - newStyle.locked = false; - - await context.sync(); - - OfficeHelpers.UI.notify("Successfully added a new style with diagonal orientation to the Home tab ribbon."); - }); -Excel.Style.add: - - |- - 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.orientation = 38; - newStyle.addIndent = true; - newStyle.includeProtection = true; - newStyle.shrinkToFit = true; - newStyle.locked = false; - - await context.sync(); - - OfficeHelpers.UI.notify("Successfully added a new style with diagonal orientation to the Home tab ribbon."); - }); -Excel.Style.font: - - |- - 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); - }); -Excel.Style.delete: - - |- - 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(); - - OfficeHelpers.UI.notify("Successfully deleted the diagonal orientation style from the Home tab ribbon."); - }); -Excel.TableDataChangedEvent.horizontalAlignment: - - |- - await Excel.run(async (context) => { - let style = context.workbook.styles.getItem("Diagonal Orientation Style"); - style.load("orientation, horizontalAlignment, addIndent, readingOrder, wrapText, includeProtection, shrinkToFit, locked"); - - await context.sync(); - - console.log("Orientation: " + style.orientation); - console.log("Horizontal alignment: " + style.horizontalAlignment); - console.log("Add indent: " + style.addIndent); - 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); - }); -Excel.TableDataChangedEvent.fill: - - |- - 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(); - }); -Excel.TableSelectionChangedEvent.address: - - |- - 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); - }); - } -Excel.WorksheetAddedEvent.onDataChanged: - - |- - await Excel.run(async (context) => { - let table = context.workbook.tables.getItemAt(0); - table.onDataChanged.add(onDataChange); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the onDataChanged event", - "Try changing a cell value in the table, and watch the console output."); - }); -Excel.WorksheetDataChangedEvent.onSelectionChanged: - - |- - await Excel.run(async (context) => { - let table = context.workbook.tables.getItemAt(0); - table.onSelectionChanged.add(onSelectionChange); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for table onSelectionChanged event", - "Try changing a range selection in the table, and watch the console output."); - }); -Excel.WorksheetAddedEvent.onAdded: - - |- - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets; - sheet.onAdded.add(onWorksheetAdd); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnAdded event", - "Try adding a worksheet, and watch the console output."); - }); -Excel.WorksheetDeactivatedEvent.onDataChanged: - - |- - await Excel.run(async (context) => { - let sheet = context.workbook.worksheets.getItem("Sample"); - sheet.onDataChanged.add(onDataChange); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the onDataChanged event."); - }); -Excel.WorksheetActivatedEvent.worksheetId: - - |- - 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); - }); - } -Excel.ChartSeries.onDeactivated: - - |- - await Excel.run(async (context) => { - let sheets = context.workbook.worksheets; - sheets.onDeactivated.add(onDeactivate); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnDeactivate event", - "Try selecting a different worksheet, and watch the console output."); - }); -Excel.ChartSeries.onActivated: - - |- - await Excel.run(async (context) => { - let sheets = context.workbook.worksheets; - sheets.onActivated.add(onActivate); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the OnActivate event", - "Try selecting a different worksheet, and watch the console output."); - }); -Excel.ChartSeries.markerStyle: - - |- - 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(); - }); -Excel.ChartSeries.markerSize: - - |- - 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(); - }); -Excel.TableSelectionChangedEvent.markerForegroundColor: - - |- - 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(); - }); -Excel.TableSelectionChangedEvent.markerBackgroundColor: - - |- - 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(); - }); -Excel.TableSelectionChangedEvent.onDataChanged: - - |- - await Excel.run(async (context) => { - let tables = context.workbook.tables; - tables.onDataChanged.add(onDataChange); - - await context.sync(); - - OfficeHelpers.UI.notify("A handler has been registered for the table collection onDataChanged event", - "Try changing cell values in the tables, and watch the console output."); - }); -Excel.TableSelectionChangedEvent.worksheetId: - - |- - async function onDataChange(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 onDataChanged event has been triggered. Data changed address : " + event.address); - console.log("Table Id : " + event.tableId); - console.log("Worksheet Id : " + worksheet.name); - }); - } -Excel.TableSelectionChangedEvent.tableId: - - |- - async function onDataChange(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 onDataChanged event has been triggered. Data changed address : " + event.address); - console.log("Table Id : " + event.tableId); - console.log("Worksheet Id : " + worksheet.name); - }); - } diff --git a/snippet-extractor-output/snippets.yaml b/snippet-extractor-output/snippets.yaml new file mode 100644 index 000000000..91d9201bb --- /dev/null +++ b/snippet-extractor-output/snippets.yaml @@ -0,0 +1,30868 @@ +Excel.AggregationFunction:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml + + + 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(); + }); + } +Excel.Application#decimalSeparator:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info.yaml + + + 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(); + }); +Excel.Application#calculate:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/performance-optimization.yaml + + + await Excel.run(async (context) => { + context.application.calculate(Excel.CalculationType.full); + }); +Excel.Application#suspendScreenUpdatingUntilNextSync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/performance-optimization.yaml + + + 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`); + }); +Excel.ArrowheadLength:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.ArrowheadStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.ArrowheadWidth:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.AutoFillType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-auto-fill.yaml + + + 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(); + }); +Excel.AutoFilter#apply:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.AutoFilter#clearColumnCriteria:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.AutoFilter#reapply:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.AutoFilter#remove:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.Binding#onDataChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/data-changed.yaml + + + 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(); + }); +Excel.BindingType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-disable-events.yaml + + + 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(); + }); +Excel.BorderLineStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.BuiltInStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.CalculationMode:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-calculation.yaml + + + 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); + }); +Excel.CalculationType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-calculation.yaml + + + await Excel.run(async (context) => { + context.application.calculate(Excel.CalculationType.recalculate); + await context.sync(); + }); +Excel.CardLayoutSection:type: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-attribution.yaml + + + function makeProductEntity(productID: number, productName: string, product?: + any) { + const entity: Excel.EntityCellValue = { + type: Excel.CellValueType.entity, + text: productName, + properties: { /* Excel.EntityPropertyType */ + "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: { /* Excel.EntityViewLayouts */ + card: { /* Excel.EntityCardLayout */ + title: { property: "Product Name" }, + sections: [ /* Excel.CardLayoutSection */ + { + 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; + } +Excel.CellBorder:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.CellControl:type: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.CellControlType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.CellPropertiesFill#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.CellPropertiesFillLoadOptions#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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}`); + }); +Excel.CellPropertiesFont#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.CellPropertiesFontLoadOptions#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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}`); + }); +Excel.CellPropertiesLoadOptions#address:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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}`); + }); +Excel.CellValueConditionalFormat#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.CellValueConditionalFormat#rule:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.CellValueType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-error-values.yaml + + + // 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(); + }); +Excel.Chart#getDataTableOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.Chart#onActivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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}.`); + }); + } +Excel.Chart#onDeactivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + } +Excel.ChartAxis#displayUnit:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-axis.yaml + + + 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); + }); +Excel.ChartAxis#showDisplayUnitLabel:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-axis.yaml + + + 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(); + }); +Excel.ChartCollection#onActivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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}.`); + }); + } +Excel.ChartCollection#onDeactivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml + + + 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."); + }); + } +Excel.ChartDataLabel:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-labels.yaml + + + // This function styles substrings within data label text using font + formatting. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.load("points"); + await context.sync(); + + series.points.load("items"); + await context.sync(); + + // Style a substring in the first data label. + let searchString = "sports"; + let dataLabel = series.points.getItemAt(dataLabelInfo[0].index).dataLabel.load("text"); + await context.sync(); + let substringStart = dataLabel.text.indexOf(searchString); + let subLabel = dataLabel.getSubstring(substringStart, searchString.length); + subLabel.font.size = 13; + subLabel.font.bold = true; + + // Style a substring in the second data label. + searchString = "'Titanic'"; + dataLabel = series.points.getItemAt(dataLabelInfo[1].index).dataLabel.load("text"); + await context.sync(); + + substringStart = dataLabel.text.indexOf(searchString); + subLabel = dataLabel.getSubstring(substringStart, searchString.length); + subLabel.font.name = "Calibri"; + subLabel.font.size = 13; + subLabel.font.italic = true; + subLabel.font.color = "blue"; + await context.sync(); + }); +Excel.ChartDataTable#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTable#showHorizontalBorder:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTable#showLegendKey:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTable#showOutlineBorder:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTable#showVerticalBorder:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTable#visible:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTableFormat#border:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartDataTableFormat#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml + + + // 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(); + }); +Excel.ChartFill#setSolidColor:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-point.yaml + + + 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(); + }); +Excel.ChartLeaderLines:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code changes the format of leader lines. It adjusts color, + weight, and line style. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + const lineFormat = dataLabels.leaderLines.format; + + // Set leader line formatting properties. + lineFormat.line.color = "blue"; + lineFormat.line.weight = 2; + lineFormat.line.lineStyle = Excel.ChartLineStyle.dot; + + await context.sync(); + }); +Excel.ChartLeaderLinesFormat:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code changes the format of leader lines. It adjusts color, + weight, and line style. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + const lineFormat = dataLabels.leaderLines.format; + + // Set leader line formatting properties. + lineFormat.line.color = "blue"; + lineFormat.line.weight = 2; + lineFormat.line.lineStyle = Excel.ChartLineStyle.dot; + + await context.sync(); + }); +Excel.ChartLegendFormat#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-legend.yaml + + + 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(); + }); +Excel.ChartPoint:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-labels.yaml + + + // This function adds data labels to specific chart points + + // and sets their text and position. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.points.load("dataLabel"); + await context.sync(); + + // Define properties for data label positioning and shape. + const labelProperties = [ + { + top: 70, + geometricShapeType: Excel.GeometricShapeType.rectangle + }, + { + top: 200, + geometricShapeType: Excel.GeometricShapeType.rectangle + } + ]; + + // Add data labels to specific chart points and set their text and properties. + for (let i = 0; i < dataLabelInfo.length; i++) { + const point = series.points.getItemAt(dataLabelInfo[i].index); + point.hasDataLabel = true; + + const dataLabel = point.dataLabel; + dataLabel.text = dataLabelInfo[i].news; + dataLabel.set(labelProperties[i]); + } + await context.sync(); + }); +Excel.ChartPointsCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-labels.yaml + + + // This function adds data labels to specific chart points + + // and sets their text and position. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + await context.sync(); + + const series = chart.series.getItemAt(0); + series.points.load("dataLabel"); + await context.sync(); + + // Define properties for data label positioning and shape. + const labelProperties = [ + { + top: 70, + geometricShapeType: Excel.GeometricShapeType.rectangle + }, + { + top: 200, + geometricShapeType: Excel.GeometricShapeType.rectangle + } + ]; + + // Add data labels to specific chart points and set their text and properties. + for (let i = 0; i < dataLabelInfo.length; i++) { + const point = series.points.getItemAt(dataLabelInfo[i].index); + point.hasDataLabel = true; + + const dataLabel = point.dataLabel; + dataLabel.text = dataLabelInfo[i].news; + dataLabel.set(labelProperties[i]); + } + await context.sync(); + }); +Excel.ChartSeries#getDimensionValues:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-bubble-chart.yaml + + + 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}`); + }); +Excel.ChartSeries#setBubbleSizes:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-bubble-chart.yaml + + + 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(); + }); +Excel.ChartSeries#getDimensionDataSourceString:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-source.yaml + + + // 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); + }); +Excel.ChartSeries#getDimensionDataSourceType:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-source.yaml + + + // 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); + }); +Excel.ChartSeries:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code adds data labels to the chart and positions them to + demonstrate leader lines. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + + // Enable data labels for the series. Leader lines are enabled by default. + series.hasDataLabels = true; + series.points.load("items"); + await context.sync(); + + // Load the top position for each data label. + series.points.items.forEach((point) => point.dataLabel.load("top")); + await context.sync(); + + // Move some data labels to create distance from their chart points. + const point1 = series.points.items[1]; + const point2 = series.points.items[2]; + point1.dataLabel.top -= 50; + point2.dataLabel.top += 50; + + // Format the data labels. + series.dataLabels.geometricShapeType = Excel.GeometricShapeType.rectangle; + series.dataLabels.showCategoryName = true; + series.dataLabels.format.border.weight = 1; + + await context.sync(); + }); +Excel.ChartSeries#hasDataLabels:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code adds data labels to the chart and positions them to + demonstrate leader lines. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + + // Enable data labels for the series. Leader lines are enabled by default. + series.hasDataLabels = true; + series.points.load("items"); + await context.sync(); + + // Load the top position for each data label. + series.points.items.forEach((point) => point.dataLabel.load("top")); + await context.sync(); + + // Move some data labels to create distance from their chart points. + const point1 = series.points.items[1]; + const point2 = series.points.items[2]; + point1.dataLabel.top -= 50; + point2.dataLabel.top += 50; + + // Format the data labels. + series.dataLabels.geometricShapeType = Excel.GeometricShapeType.rectangle; + series.dataLabels.showCategoryName = true; + series.dataLabels.format.border.weight = 1; + + await context.sync(); + }); +Excel.ChartSeries#points:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code adds data labels to the chart and positions them to + demonstrate leader lines. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + + // Enable data labels for the series. Leader lines are enabled by default. + series.hasDataLabels = true; + series.points.load("items"); + await context.sync(); + + // Load the top position for each data label. + series.points.items.forEach((point) => point.dataLabel.load("top")); + await context.sync(); + + // Move some data labels to create distance from their chart points. + const point1 = series.points.items[1]; + const point2 = series.points.items[2]; + point1.dataLabel.top -= 50; + point2.dataLabel.top += 50; + + // Format the data labels. + series.dataLabels.geometricShapeType = Excel.GeometricShapeType.rectangle; + series.dataLabels.showCategoryName = true; + series.dataLabels.format.border.weight = 1; + + await context.sync(); + }); +Excel.ChartSeries#showLeaderLines:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml + + + // The following code disables leader lines for chart data labels. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem(sheetName); + const chart = sheet.charts.getItemAt(0); + const series = chart.series.getItemAt(0); + const dataLabels = series.dataLabels; + + // Disable leader lines. + dataLabels.showLeaderLines = false; + + await context.sync(); + }); +Excel.ChartSeries#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series.yaml + + + 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(); + }); +Excel.ChartSeries#setValues:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series.yaml + + + 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(); + }); +Excel.ChartSeries#markerBackgroundColor:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-markers.yaml + + + 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(); + }); +Excel.ChartSeries#markerForegroundColor:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-markers.yaml + + + 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(); + }); +Excel.ChartSeries#markerSize:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-markers.yaml + + + 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(); + }); +Excel.ChartSeries#markerStyle:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-markers.yaml + + + 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(); + }); +Excel.ChartSeriesBy:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-source.yaml + + + 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(); + }); +Excel.ChartSeriesDimension:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-bubble-chart.yaml + + + 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}`); + }); +Excel.ChartTitle#getSubstring:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-title-format.yaml + + + 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(); + }); +Excel.ChartTitle#textOrientation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-title-format.yaml + + + 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(); + }); +Excel.ChartTrendline#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-trendlines.yaml + + + 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); + }); +Excel.ChartTrendlineCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-trendlines.yaml + + + 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(); + }); +Excel.ChartTrendlineFormat#line:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-trendlines.yaml + + + 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); + }); +Excel.ChartType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-create-several-charts.yaml + + + 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(); + }); +Excel.CheckboxCellControl:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.ClearApplyTo:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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 removes 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(); + }); +Excel.CloseBehavior:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-save-and-close.yaml + + + await Excel.run(async (context) => { + context.workbook.close(Excel.CloseBehavior.skipSave); + }); +Excel.ColorScaleConditionalFormat#criteria:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.Comment#content:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-basics.yaml + + + 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(); + }); +Excel.Comment#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-basics.yaml + + + await Excel.run(async (context) => { + context.workbook.comments.getItemByCell("Comments!A2").delete(); + await context.sync(); + }); +Excel.Comment#load:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-basics.yaml + + + 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(); + }); +Excel.Comment#resolved:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-resolution.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Comments"); + sheet.comments.getItemAt(0).resolved = true; + await context.sync(); + }); +Excel.CommentCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-basics.yaml + + + 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(); + }); +Excel.CommentCollection#onAdded:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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}`); + }); + } +Excel.CommentCollection#onChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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}`); + }); + } +Excel.CommentCollection#onDeleted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml + + + 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}`); + }); + } +Excel.CommentReply#content:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-replies.yaml + + + 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(); + }); +Excel.CommentReply#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-replies.yaml + + + 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(); + }); +Excel.CommentReplyCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-replies.yaml + + + 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(); + }); +Excel.CommentRichContent#mentions:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-mentions.yaml + + + 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(); + }); +Excel.ConditionalCellValueRule#formula1:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalCellValueRule#operator:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalDataBarDirection:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#cellValue:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#colorScale:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#custom:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#dataBar:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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."); + } + }); +Excel.ConditionalFormat#iconSet:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#preset:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#textComparison:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormat#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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."); + } + }); +Excel.ConditionalFormatCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormatCollection#clearAll:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Sample"); + const range = sheet.getRange(); + range.conditionalFormats.clearAll(); + + await context.sync(); + + document.querySelectorAll(".conditional-formats").forEach(element => { + element.style.display = "none"; + }); + }); +Excel.ConditionalFormatCollection#getItemAt:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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."); + } + }); +Excel.ConditionalFormatColorCriterionType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormatIconRuleType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormatPresetCriterion:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml + + + 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(); + }); +Excel.ConditionalFormatRule#formula:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalFormatType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml + + + 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(); + }); +Excel.ConditionalIconCriterion#formula:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalIconCriterion#operator:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalIconCriterion#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalIconCriterionOperator:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalPresetCriteriaRule#criterion:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalTextComparisonRule#text:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConditionalTextOperator:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.ConnectorType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.ContentType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-mentions.yaml + + + 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(); + }); +Excel.CultureInfo#datetimeFormat:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info-date-time.yaml + + + 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(); + }); +Excel.CustomConditionalFormat#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.CustomPropertyCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/custom-properties.yaml + + + await Excel.run(async (context) => { + // Get the key/value pair from the task pane. + const userKey = document.getElementById("key").textContent; + const userValue = document.getElementById("value").textContent; + + // 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}.`); + }); +Excel.CustomXmlPart#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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) { + document.getElementById("display-xml").textContent = `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}` + document.getElementById("display-xml").textContent = strangeMessage; + } + + await context.sync(); + } + }); +Excel.CustomXmlPart#getXml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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); + document.getElementById("display-xml").textContent = readableXml; + + // Store the XML part's ID in a setting. + const settings = context.workbook.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Excel.CustomXmlPart#id:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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); + document.getElementById("display-xml").textContent = readableXml; + + // Store the XML part's ID in a setting. + const settings = context.workbook.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Excel.CustomXmlPart#setXml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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); + document.getElementById("display-xml").textContent = readableXml; + await context.sync(); + } + }); +Excel.CustomXmlPartCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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); + document.getElementById("display-xml").textContent = readableXml; + + // Store the XML part's ID in a setting. + const settings = context.workbook.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Excel.CustomXmlPartCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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); + document.getElementById("display-xml").textContent = readableXml; + await context.sync(); + } + }); +Excel.CustomXmlPartCollection#getByNamespace:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml + + + await Excel.run(async (context) => { + document.getElementById("display-xml").textContent = ""; + 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<"); + + document.getElementById("display-xml").textContent = `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(); + }); +Excel.CustomXmlPartScopedCollection#getItemOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml + + + 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) { + document.getElementById("display-xml").textContent = `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}` + document.getElementById("display-xml").textContent = strangeMessage; + } + + await context.sync(); + } + }); +Excel.CustomXmlPartScopedCollection#getCount:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml + + + await Excel.run(async (context) => { + document.getElementById("display-xml").textContent = ""; + 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<"); + + document.getElementById("display-xml").textContent = `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(); + }); +Excel.CustomXmlPartScopedCollection#getOnlyItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml + + + await Excel.run(async (context) => { + document.getElementById("display-xml").textContent = ""; + 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<"); + + document.getElementById("display-xml").textContent = `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(); + }); +Excel.DataBarConditionalFormat#barDirection:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.DataPivotHierarchy#showAs:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-calculations.yaml + + + 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(); + }); +Excel.DataPivotHierarchy#name:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + 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(); + }); +Excel.DataValidationErrorAlert:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidation#errorAlert:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidation#prompt:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidation#rule:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidationOperator:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidationRule#list:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DataValidationRule#wholeNumber:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml + + + 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(); + }); +Excel.DateFilterCondition:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.DeleteShiftDirection:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml + + + // 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); + }); +Excel.DocumentProperties#custom:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/custom-properties.yaml + + + 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}`); + }); + }); +Excel.DoubleCellValue#numberFormat:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-formatted-number.yaml + + + // This function creates a double 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.double, + basicValue: 12.34, + numberFormat: "$* #,##0.00" + } + ] + ]; + + await context.sync(); + }); +Excel.DoubleCellValue#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-formatted-number.yaml + + + // This function creates a double 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.double, + basicValue: 32889.0, + numberFormat: "m/d/yyyy" + } + ] + ]; + await context.sync(); + }); +Excel.DynamicFilterCriteria:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/filter-data.yaml + + + 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(); + }); +Excel.EntityCardLayout:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-attribution.yaml + + + function makeProductEntity(productID: number, productName: string, product?: + any) { + const entity: Excel.EntityCellValue = { + type: Excel.CellValueType.entity, + text: productName, + properties: { /* Excel.EntityPropertyType */ + "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: { /* Excel.EntityViewLayouts */ + card: { /* Excel.EntityCardLayout */ + title: { property: "Product Name" }, + sections: [ /* Excel.CardLayoutSection */ + { + 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; + } +Excel.EntityCompactLayoutIcons:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-icons.yaml + + + 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; + } +Excel.EntityPropertyType:type: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-attribution.yaml + + + function makeProductEntity(productID: number, productName: string, product?: + any) { + const entity: Excel.EntityCellValue = { + type: Excel.CellValueType.entity, + text: productName, + properties: { /* Excel.EntityPropertyType */ + "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: { /* Excel.EntityViewLayouts */ + card: { /* Excel.EntityCardLayout */ + title: { property: "Product Name" }, + sections: [ /* Excel.CardLayoutSection */ + { + 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; + } +Excel.EntityViewLayouts:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-attribution.yaml + + + function makeProductEntity(productID: number, productName: string, product?: + any) { + const entity: Excel.EntityCellValue = { + type: Excel.CellValueType.entity, + text: productName, + properties: { /* Excel.EntityPropertyType */ + "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: { /* Excel.EntityViewLayouts */ + card: { /* Excel.EntityCardLayout */ + title: { property: "Product Name" }, + sections: [ /* Excel.CardLayoutSection */ + { + 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; + } +Excel.ErrorCellValue:type: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-error-values.yaml + + + // 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(); + }); +Excel.ErrorCellValueType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-error-values.yaml + + + // 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(); + }); +Excel.FillPattern:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.FilterCriteria#filterOn:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.FilterDatetimeSpecificity:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.Functions:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-built-in-functions.yaml + + + await Excel.run(async (context) => { + // This function uses VLOOKUP to find data in the "Wrench" row on the worksheet. + let range = context.workbook.worksheets.getItem("Sample").getRange("A1:D4"); + + // Get the value in the second column in the "Wrench" row. + let unitSoldInNov = context.workbook.functions.vlookup("Wrench", range, 2, false); + unitSoldInNov.load("value"); + + await context.sync(); + console.log(" Number of wrenches sold in November = " + unitSoldInNov.value); + }); +Excel.Functions#vlookup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-built-in-functions.yaml + + + await Excel.run(async (context) => { + // This function uses VLOOKUP to find data in the "Wrench" row on the worksheet. + let range = context.workbook.worksheets.getItem("Sample").getRange("A1:D4"); + + // Get the value in the second column in the "Wrench" row. + let unitSoldInNov = context.workbook.functions.vlookup("Wrench", range, 2, false); + unitSoldInNov.load("value"); + + await context.sync(); + console.log(" Number of wrenches sold in November = " + unitSoldInNov.value); + }); +Excel.Functions#sum:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-built-in-functions.yaml + + + await Excel.run(async (context) => { + // This function uses VLOOKUP to find data in the "Wrench" row + // on the worksheet, and then it uses SUM to combine the values. + let range = context.workbook.worksheets.getItem("Sample").getRange("A1:D4"); + + // Get the values in the second, third, and fourth columns in the "Wrench" row, + // and combine those values with SUM. + let sumOfTwoLookups = context.workbook.functions.sum( + context.workbook.functions.vlookup("Wrench", range, 2, false), + context.workbook.functions.vlookup("Wrench", range, 3, false), + context.workbook.functions.vlookup("Wrench", range, 4, false) + ); + sumOfTwoLookups.load("value"); + + await context.sync(); + console.log(" Number of wrenches sold in November, December, and January = " + sumOfTwoLookups.value); + }); +Excel.GeometricShapeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml + + + 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(); + }); +Excel.GroupOption:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/outline.yaml + + + 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(); + }); +Excel.HorizontalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-merged-ranges.yaml + + + 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(); + }); +Excel.IconSet:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.IconSetConditionalFormat#criteria:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.IconSetConditionalFormat#style:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.Image#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml + + + 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(); + }); +Excel.InsertShiftDirection:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/insert-delete-clear-range.yaml + + + 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(); + }); +Excel.KeyboardDirection:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-get-range-edge.yaml + + + 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(); + }); +Excel.LabelFilterCondition:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.Line#connectBeginShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.Line#connectEndShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.Line#disconnectBeginShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.Line#disconnectEndShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.NamedItem:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/create-and-remove-named-item.yaml + + + await Excel.run(async (context) => { + // Log all the named items in the active worksheet. + 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++) { + const namedItem : Excel.NamedItem = namedItems.items[i]; + console.log(JSON.stringify(namedItem)) + "\n"; + } + + await context.sync(); + }); +Excel.NamedItem#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/create-and-remove-named-item.yaml + + + 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(); + }); +Excel.NamedItem#formula:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/update-named-item.yaml + + + 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}`); + } + }); +Excel.NamedItemCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/create-and-remove-named-item.yaml + + + 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(); + }); +Excel.Note:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function changes the height and width of the first note. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.height = 200; + note.width = 400; + await context.sync(); + }); +Excel.Note#content:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function changes the content in the first note. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.content = "Changing the content of the first note."; + await context.sync(); + }); +Excel.Note#height:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function changes the height and width of the first note. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.height = 200; + note.width = 400; + await context.sync(); + }); +Excel.Note#visible:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function sets the note on cell A1 to visible. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const firstNote = sheet.notes.getItem("A1"); + + firstNote.load(); + await context.sync(); + + firstNote.visible = true; + }); +Excel.Note#width:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function changes the height and width of the first note. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.height = 200; + note.width = 400; + await context.sync(); + }); +Excel.Note#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function deletes the note from cell A2. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItem("A2"); + note.delete(); + + await context.sync(); + }); +Excel.NoteCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function adds a note to the selected cell. + + await Excel.run(async (context) => { + const selectedRange = context.workbook.getSelectedRange(); + + // Note that an InvalidArgument error is thrown if multiple cells are selected. + context.workbook.notes.add(selectedRange, "The first note."); + await context.sync(); + }); +Excel.NoteCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function adds a note to the selected cell. + + await Excel.run(async (context) => { + const selectedRange = context.workbook.getSelectedRange(); + + // Note that an InvalidArgument error is thrown if multiple cells are selected. + context.workbook.notes.add(selectedRange, "The first note."); + await context.sync(); + }); +Excel.NoteCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function sets the note on cell A1 to visible. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const firstNote = sheet.notes.getItem("A1"); + + firstNote.load(); + await context.sync(); + + firstNote.visible = true; + }); +Excel.NoteCollection#getItemAt:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml + + + // This function changes the content in the first note. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Notes"); + const note = sheet.notes.getItemAt(0); + note.content = "Changing the content of the first note."; + await context.sync(); + }); +Excel.NumberFormatInfo#numberDecimalSeparator:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info.yaml + + + // 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(); + }); +Excel.NumberFormatInfo#numberGroupSeparator:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info.yaml + + + 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(); + }); +Excel.PageBreakCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.horizontalPageBreaks.add("A21:E21"); + await context.sync(); + }); +Excel.PageLayout#centerHorizontally:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.centerHorizontally = true; + farmSheet.pageLayout.centerVertically = true; + await context.sync(); + }); +Excel.PageLayout#centerVertically:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.centerHorizontally = true; + farmSheet.pageLayout.centerVertically = true; + await context.sync(); + }); +Excel.PageLayout#orientation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.orientation = Excel.PageOrientation.landscape; + await context.sync(); + }); +Excel.PageLayout#setPrintArea:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.setPrintArea("A1:D41"); + await context.sync(); + }); +Excel.PageLayout#setPrintTitleRows:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.setPrintTitleRows("$1:$1"); + await context.sync(); + }); +Excel.PageLayout#zoom:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.zoom = { scale: 200 }; + await context.sync(); + }); +Excel.PageOrientation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml + + + await Excel.run(async (context) => { + const farmSheet = context.workbook.worksheets.getItem("Print"); + farmSheet.pageLayout.orientation = Excel.PageOrientation.landscape; + await context.sync(); + }); +Excel.PictureFormat:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml + + + 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); + }); +Excel.PivotField#clearAllFilters:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotFilters#dateFilter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotFilters#labelFilter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotFilters#manualFilter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotFilters#valueFilter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotHierarchy#fields:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.PivotLayout#getDataBodyRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml + + + 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(); + }); +Excel.PivotLayout#altTextDescription:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#displayBlankLineAfterEachItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#emptyCellText:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#fillEmptyCells:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#layoutType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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); + }); +Excel.PivotLayout#preserveFormatting:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#repeatAllItemLabels:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#showColumnGrandTotals:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#showFieldHeaders:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotLayout#showRowGrandTotals:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml + + + 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(); + }); +Excel.PivotTable#columnHierarchies:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + 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(); + }); +Excel.PivotTable#dataHierarchies:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + 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(); + }); +Excel.PivotTable#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + await Excel.run(async (context) => { + context.workbook.worksheets.getItem("Pivot").pivotTables.getItem("Farm Sales").delete(); + + await context.sync(); + }); +Excel.PivotTable#layout:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + 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); + }); +Excel.PivotTable#getDataSourceString:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-source-data.yaml + + + // 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); + }); +Excel.PivotTable#getDataSourceType:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-source-data.yaml + + + // 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); + }); +Excel.PivotTable#filterHierarchies:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml + + + 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(); + } + }); + } +Excel.PivotTable#refresh:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-refresh.yaml + + + // 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(); + }); +Excel.PivotTableCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml + + + 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(); + }); +Excel.PivotTableCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-refresh.yaml + + + // 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(); + }); +Excel.PresetCriteriaConditionalFormat#rule:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.Range#clearOrResetContents:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Remove all content from the Analysis column. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Clear all the data from the second column. + range.clearOrResetContents(); + await context.sync(); + }); +Excel.Range#control:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.Range#values:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Change the value of the checkbox in B3. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + const range = sheet.getRange("B3"); + + range.values = [["TRUE"]]; + await context.sync(); + }); +Excel.Range#valuesAsJson:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-formatted-number.yaml + + + // This function creates a double 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.double, + basicValue: 32889.0, + numberFormat: "m/d/yyyy" + } + ] + ]; + await context.sync(); + }); +Excel.Range#getDirectDependents:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-direct-dependents.yaml + + + 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(); + }); +Excel.Range#sort:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml + + + 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(); + }); + } +Excel.Range#getMergedAreasOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-merged-ranges.yaml + + + 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(); + }); +Excel.Range#merge:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-merged-ranges.yaml + + + 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(); + }); +Excel.Range#group:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/outline.yaml + + + 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(); + }); +Excel.Range#ungroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/outline.yaml + + + 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(); + }); +Excel.Range#getPivotTables:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-get-pivottables.yaml + + + 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}`); + }); + }); +Excel.Range#getDirectPrecedents:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/precedents.yaml + + + 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(); + }); +Excel.Range#getPrecedents:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/precedents.yaml + + + 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(); + }); +Excel.Range#getSpecialCells:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-areas.yaml + + + 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(); + }); +Excel.Range#autoFill:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-auto-fill.yaml + + + 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(); + }); +Excel.Range#getCellProperties:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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}`); + }); +Excel.Range#setCellProperties:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.Range#copyFrom:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-copyfrom.yaml + + + 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(); + }); +Excel.Range#moveTo:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-copyfrom.yaml + + + 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(); + }); +Excel.Range#getDependents:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-dependents.yaml + + + // 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(); + }); +Excel.Range#getSpillingToRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/dynamic-arrays.yaml + + + 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}.`); + }); +Excel.Range#find:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-find.yaml + + + 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 searchText = (document.getElementById("searchText") as HTMLTextAreaElement).value; + const foundRange = searchRange.find(searchText, { + completeMatch: isCompleteMatchToggle, + matchCase: isMatchCaseToggle, + searchDirection: searchDirectionToggle + }); + + foundRange.load("address"); + await context.sync(); + + + console.log(foundRange.address); + }); +Excel.Range#findOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-find.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Sample"); + const table = sheet.tables.getItem("ExpensesTable"); + const searchRange = table.getRange(); + const searchText = (document.getElementById("searchText") as HTMLTextAreaElement).value; + const foundRange = searchRange.findOrNullObject(searchText, { + 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); + } + }); +Excel.Range#getExtendedRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-get-range-edge.yaml + + + 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(); + }); +Excel.Range#getRangeEdge:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-get-range-edge.yaml + + + 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(); + }); +Excel.Range#hyperlink:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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(); + }); +Excel.Range#getIntersectionOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-relationships.yaml + + + 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(); + }); +Excel.Range#getUsedRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-relationships.yaml + + + 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(); + }); +Excel.Range#removeDuplicates:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-remove-duplicates.yaml + + + 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."); + }); +Excel.Range#style:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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(); + }); +Excel.Range#getUsedRangeOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/used-range.yaml + + + 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(); + }); +Excel.Range#set:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/multiple-property-set.yaml + + + 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(); + }); +Excel.RangeAreas#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-areas.yaml + + + 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(); + }); +Excel.RangeCopyType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-copyfrom.yaml + + + 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(); + }); +Excel.RangeFormat#textOrientation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-text-orientation.yaml + + + 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(); + }); +Excel.RangeHyperlink#address:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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(); + }); +Excel.RangeHyperlink#documentReference:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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(); + }); +Excel.RangeHyperlink#screenTip:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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(); + }); +Excel.RangeHyperlink#textToDisplay:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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(); + }); +Excel.RangeUnderlineStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml + + + 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 removes 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(); + }); +Excel.ReadingOrder:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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); + }); +Excel.RemoveDuplicatesResult#uniqueRemaining:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-remove-duplicates.yaml + + + 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."); + }); +Excel.Runtime#enableEvents:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-disable-events.yaml + + + 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(); + }); +Excel.SaveBehavior:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-save-and-close.yaml + + + await Excel.run(async (context) => { + context.workbook.save(Excel.SaveBehavior.prompt); + }); +Excel.SearchDirection:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-find.yaml + + + searchDirectionToggle = searchDirectionToggle === + Excel.SearchDirection.forward ? Excel.SearchDirection.backwards : + Excel.SearchDirection.forward; + + console.log("Search direction = " + searchDirectionToggle); +Excel.SettableCellProperties#style:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml + + + 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(); + }); +Excel.Setting#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/create-get-change-delete-settings.yaml + + + 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(); + }); +Excel.SettingCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + await Excel.run(async (context) => { + const settings = context.workbook.settings; + settings.onSettingsChanged.add(onChangedSetting); + + await context.sync(); + console.log("Settings changed handler registered."); + }); +Excel.SettingCollection#onSettingsChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + await Excel.run(async (context) => { + const settings = context.workbook.settings; + settings.onSettingsChanged.add(onChangedSetting); + + await context.sync(); + console.log("Settings changed handler registered."); + }); +Excel.SettingCollection#getItemOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/create-get-change-delete-settings.yaml + + + 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(); + }); +Excel.Shape#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml + + + 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(); + }); +Excel.Shape#fill:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml + + + 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(); + }); +Excel.Shape#rotation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml + + + 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(); + }); +Excel.Shape#group:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-groups.yaml + + + 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(); + }); +Excel.Shape#getAsImage:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml + + + 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); + }); +Excel.Shape#incrementRotation:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Shapes"); + const shape = sheet.shapes.getItem("Image"); + shape.incrementRotation(180); + await context.sync(); + }); +Excel.Shape#line:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.Shape#incrementLeft:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Shapes"); + const shape = sheet.shapes.getItem("Square") + shape.incrementLeft(-25); + await context.sync(); + }); +Excel.Shape#incrementTop:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Shapes"); + const shape = sheet.shapes.getItem("Pentagon") + shape.incrementTop(25); + await context.sync(); + }); +Excel.Shape#lockAspectRatio:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + 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(); + }); +Excel.Shape#scaleHeight:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + 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(); + }); +Excel.Shape#setZOrder:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + 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(); + }); +Excel.ShapeAutoSize:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-textboxes.yaml + + + 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(); + }); +Excel.ShapeCollection#addGeometricShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml + + + 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(); + }); +Excel.ShapeCollection#addGroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-groups.yaml + + + 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(); + }); +Excel.ShapeCollection#addImage:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml + + + const myFile = document.getElementById("selectedFile") as HTMLInputElement; + + 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]); +Excel.ShapeCollection#addLine:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml + + + 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(); + }); +Excel.ShapeCollection#addTextBox:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-textboxes.yaml + + + 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(); + }); +Excel.ShapeGroup#ungroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-groups.yaml + + + 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(); + }); +Excel.ShapeScaleType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + 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(); + }); +Excel.ShapeTextHorizontalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-textboxes.yaml + + + 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(); + }); +Excel.ShapeZOrder:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml + + + 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(); + }); +Excel.SheetVisibility:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-visibility.yaml + + + 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"); + } + }); +Excel.ShowAsCalculation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-calculations.yaml + + + 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(); + }); +Excel.ShowAsRule#baseItem:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-calculations.yaml + + + 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(); + }); +Excel.Slicer#clearFilters:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + await Excel.run(async (context) => { + const slicer = context.workbook.slicers.getItem("Fruit Slicer"); + slicer.clearFilters(); + await context.sync(); + }); +Excel.Slicer#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + sheet.slicers.getItemAt(0).delete(); + await context.sync(); + }); +Excel.Slicer#selectItems:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + await Excel.run(async (context) => { + const slicer = context.workbook.slicers.getItem("Fruit Slicer"); + slicer.selectItems(["Lemon", "Lime", "Orange"]); + await context.sync(); + }); +Excel.Slicer#style:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + await Excel.run(async (context) => { + const slicer = context.workbook.slicers.getItem("Fruit Slicer"); + slicer.style = "SlicerStyleLight6"; + await context.sync(); + }); +Excel.SlicerCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + 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(); + }); +Excel.SlicerCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + 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(); + }); +Excel.SortOn:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml + + + 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(); + }); + } +Excel.SortOrientation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml + + + 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(); + }); + } +CustomFunctions.StreamingInvocation#setResult:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/streaming-function.yaml + + + /** @CustomFunction + * @description Increments the cell with a given amount at a specified interval in milliseconds. + * @param {number} amount - The amount to add to the cell value on each increment. + * @param {number} interval - The time in milliseconds to wait before the next increment on the cell. + * @param {CustomFunctions.StreamingInvocation} invocation - Parameter to send results to Excel + * or respond to the user canceling the function. + * @returns An incrementing value. + */ + function increment(amount: number, interval: number, invocation: + CustomFunctions.StreamingInvocation): void { + let result = 0; + const timer = setInterval(() => { + result += amount; + invocation.setResult(result); + }, interval); + + invocation.onCanceled = () => { + clearInterval(timer); + } + } +Excel.Style#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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."); + }); +Excel.Style#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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); + }); +Excel.Style#horizontalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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(); + }); +Excel.Style#load:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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); + }); +Excel.StyleCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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."); + }); +Excel.StyleCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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."); + }); +Excel.Table#onChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-table-changed.yaml + + + 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"); + }); +Excel.Table#onSelectionChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-table-changed.yaml + + + 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"); + }); +Excel.Table#resize:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/resize-table.yaml + + + 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(); + }); +Excel.TableChangedEventArgs#details:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/data-change-event-details.yaml + + + 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})`); + }); + } +Excel.TableChangedEventArgs#tableId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-tablecollection-changed.yaml + + + 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); + }); + } +Excel.TableChangedEventArgs#worksheetId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-tablecollection-changed.yaml + + + 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); + }); + } +Excel.TableCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.TableCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Remove checkboxes from the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the checkboxes back to boolean values. + range.control = { + type: Excel.CellControlType.empty + }; + await context.sync(); + }); +Excel.TableCollection#onChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-tablecollection-changed.yaml + + + 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"); + }); +Excel.TableColumn#getDataBodyRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.TableColumnCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Add checkboxes to the table. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Change the boolean values to checkboxes. + range.control = { + type: Excel.CellControlType.checkbox + }; + await context.sync(); + }); +Excel.TableColumnCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml + + + // Remove all content from the Analysis column. + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Get the second column in the table, without the header. + const range = sheet.tables.getItem("FruitTable").columns.getItem("Analysis").getDataBodyRange(); + + // Clear all the data from the second column. + range.clearOrResetContents(); + await context.sync(); + }); +Excel.TableSelectionChangedEventArgs#address:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-table-changed.yaml + + + 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); + }); + } +Excel.TextConditionalFormat#format:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.TextConditionalFormat#rule:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml + + + 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(); + }); +Excel.TextFrame#deleteText:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-textboxes.yaml + + + await Excel.run(async (context) => { + const shapes = context.workbook.worksheets.getItem("Shapes").shapes; + const textbox = shapes.getItem("Textbox"); + textbox.textFrame.deleteText(); + await context.sync(); + }); +Excel.ValueFilterCondition:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml + + + 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(); + }); +Excel.VerticalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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(); + }); +Excel.WebImageCellValue#address:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-web-image.yaml + + + // 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"); + }); +Excel.WebImageCellValue#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-web-image.yaml + + + // 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 = (document.getElementById("url") as HTMLInputElement).value; + const imageAltText = (document.getElementById("alt-text") as HTMLInputElement).value; + 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(); + }); +Excel.Workbook#properties:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/properties.yaml + + + 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."); + }); +Excel.Workbook#onActivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-activated.yaml + + + 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."); + }); + } + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-activated.yaml + + + 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."); + }); +Excel.Workbook#pivotTables:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-get-pivottables.yaml + + + 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}`); + }); + }); +Excel.Workbook#getSelectedRanges:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-areas.yaml + + + await Excel.run(async (context) => { + + const selectedRanges = context.workbook.getSelectedRanges(); + selectedRanges.format.fill.color = "lightblue"; + + await context.sync(); + }) +Excel.Workbook#styles:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml + + + 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."); + }); +Excel.Workbook#getActiveShapeOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-get-active.yaml + + + // This method gets the active shape and displays it as an image in the task + pane. + + await Excel.run(async (context) => { + // Get the currently active shape, if any. + const activeShape = context.workbook.getActiveShapeOrNullObject(); + + if (activeShape) { + // Convert the active shape to an image. + const shapeImage = activeShape.getAsImage(Excel.PictureFormat.png); + await context.sync(); + + // Display the image in the task pane. + const imageContainer = document.getElementById("image"); + imageContainer.innerHTML = ''; // Clear the container before adding a new image. + const imageElement = document.createElement("img"); + imageElement.src = "data:image/png;base64," + shapeImage.value; + imageContainer.appendChild(imageElement); + } else { + console.log("No active shape"); + } + }); +Excel.Workbook#getActiveCell:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-get-active-cell.yaml + + + 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); + }); +Excel.Workbook#insertWorksheetsFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml + + + // Retrieve the file and set up an HTML FileReader element. + + const myFile = document.getElementById("file") as HTMLInputElement; + + 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]); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml + + + 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(); + }); +Excel.Workbook#close:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-save-and-close.yaml + + + await Excel.run(async (context) => { + context.workbook.close(Excel.CloseBehavior.save); + }); +Excel.Workbook#save:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-save-and-close.yaml + + + await Excel.run(async (context) => { + context.workbook.save(Excel.SaveBehavior.save); + }); +Excel.WorkbookProtection#protect:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/data-protection.yaml + + + 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); + } + }); +Excel.WorkbookProtection#unprotect:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/data-protection.yaml + + + let password = await passwordHandler(); + + passwordHelper(password); + + await Excel.run(async (context) => { + let workbook = context.workbook; + workbook.protection.unprotect(password); + }); +Excel.WorkbookRangeAreas#areas:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/precedents.yaml + + + 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(); + }); +Excel.Worksheet#customProperties:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/custom-properties.yaml + + + 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}`); + }); + }); +Excel.Worksheet#onColumnSorted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml + + + 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(); + }); + }); + }); +Excel.Worksheet#onRowSorted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml + + + 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(); + }); + }); + }); +Excel.Worksheet#onSingleClicked:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-worksheet-single-click.yaml + + + 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(); + }); +Excel.Worksheet#onFormulaChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-formula-changed.yaml + + + 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-formula-changed.yaml + + + 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}.` + ); + }); + } +Excel.Worksheet#onChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml + + + 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."); + }); +Excel.Worksheet#onProtectionChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml + + + // 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."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml + + + 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 + "."); + }); + } +Excel.Worksheet#showOutlineLevels:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/outline.yaml + + + 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(); + }); +Excel.Worksheet#slicers:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml + + + 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(); + }); +Excel.Worksheet#pivotTables:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-get-pivottables.yaml + + + 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}`); + }); + }); +Excel.Worksheet#getRanges:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-areas.yaml + + + 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(); + }) +Excel.Worksheet#autoFilter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml + + + // 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(); + }); +Excel.Worksheet#copy:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-copy.yaml + + + 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 + "'") + }); +Excel.Worksheet#findAllOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-find-all.yaml + + + 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" + } + }); +Excel.Worksheet#showGridlines:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/gridlines.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + sheet.showGridlines = true; + + await context.sync(); + }); +Excel.Worksheet#getNext:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml + + + 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(); + }); +Excel.Worksheet#getPrevious:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml + + + 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(); + }); +Excel.Worksheet#tabColor:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/tab-color.yaml + + + await Excel.run(async (context) => { + const activeSheet = context.workbook.worksheets.getActiveWorksheet(); + activeSheet.tabColor = "#FF0000"; + + await context.sync(); + }); +Excel.WorksheetAddedEventArgs#worksheetId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + 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 + ); + }); + } +Excel.WorksheetChangedEventArgs#changeDirectionState:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml + + + 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); + } + }); + } + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml + + + // 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); + }); +Excel.WorksheetChangedEventArgs#triggerSource:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml + + + 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); + } + }); + } +Excel.WorksheetCollection#onActivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + 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."); + }); +Excel.WorksheetCollection#onAdded:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + 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."); + }); +Excel.WorksheetCollection#onDeactivated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml + + + 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."); + }); +Excel.WorksheetCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml + + + 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(); + }); +Excel.WorksheetCollection#getLast:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml + + + 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(); + }); +Excel.WorksheetCustomPropertyCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/custom-properties.yaml + + + await Excel.run(async (context) => { + // Get the key/value pair from the task pane. + const userKey = document.getElementById("key").textContent; + const userValue = document.getElementById("value").textContent; + + // 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}.`); + }); +Excel.WorksheetFreezePanes#freezeAt:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml + + + 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(); + }); +Excel.WorksheetFreezePanes#freezeColumns:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml + + + 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(); + }); +Excel.WorksheetFreezePanes#freezeRows:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml + + + 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(); + }); +Excel.WorksheetFreezePanes#getLocationOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml + + + 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}"`); + } + }); +Excel.WorksheetFreezePanes#unfreeze:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml + + + await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getItem("Sample"); + sheet.freezePanes.unfreeze(); + + await context.sync(); + }); +Excel.WorksheetPositionType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml + + + 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(); + }); +Excel.WorksheetProtection#protect:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/data-protection.yaml + + + 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); + } + }); +Excel.WorksheetProtection#unprotect:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/data-protection.yaml + + + let password = await passwordHandler(); + + passwordHelper(password); + + await Excel.run(async (context) => { + let activeSheet = context.workbook.worksheets.getActiveWorksheet(); + activeSheet.protection.unprotect(password); + }); +Excel.WorksheetProtectionChangedEventArgs#isProtected:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml + + + 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 + "."); + }); + } +Excel.WorksheetProtectionChangedEventArgs#source:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml + + + 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 + "."); + }); + } +Excel.WorksheetProtectionChangedEventArgs#worksheetId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml + + + 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 + "."); + }); + } +Excel.WorksheetSingleClickedEventArgs#address:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-worksheet-single-click.yaml + + + 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(); + }); +Office.AppointmentCompose#addFileAttachmentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + const attachmentUrl = (document.getElementById("attachmentUrl") as + HTMLInputElement).value; + + Office.context.mailbox.item.addFileAttachmentAsync( + attachmentUrl, + getFileName(attachmentUrl), + { isInline: false }, + (result) => { + console.log(result); + } + ); +Office.AppointmentCompose#addFileAttachmentFromBase64Async:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + const base64String = + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsSAAALEgHS3X78AAACRUlEQVRYw82XzXHbMBCFP2F8tzsQc8Ixyh0zoiuIXIGdCsxUYKqC0B04FdiuwMoM7mGOOIXqQGoAymXhgSX+itJM9kIRFLAP+3YXD5Pdbscx5oxaAIW8Ztr6l2PWmQwF4IyaieP53qdfAqQ8CwBn1JU4vpWhrbxXQA5MZfynANmcDIAzKgcy4FKGXsVJFf3nLgKyBQptfT4KQMRz2N0fcbxqmRMDWXflx0VPnrdArq0vekQ1Dv0UeHZGNebHhwjU8AzwKM43RyZnbAf58Q6ghudeWd0Aus0+5EcMIIRi3beua0D3Nm39BEAx3i7HTK4DEBJn5YxKOnaRA5+ErpMBWMpzDvx1RuXCcxOISlufAjfC7zgAsqsvUvMAD0ApPaEtGi9AIlUzKgJo60tt/SyKRkzLrAXERluf7W1gOICWaMyB386oooOWsIHvXbSoHuUSFovtHqicUVnH3EJoeT0aQEf5/XBGlc6otIOWBXAtPeZkAIJ9Bt6cUU9tZautX2nrk3MACHYr1ZKProKRtDw4o8pzAPjWo+NtpXTTvoteDDg8noDAcwbcRedAkGdFXyk2GEDcegVAFp2gyVDHjRQ4o6q2smoqtR5Hd+qMqtoALCWUUymr1m43QMZfOaMK4C0SrMsDANJ2E5FNcbdbjHC+ENl+H0myJFbLtaq4Rt8dyPBYRQV1E40nMv9rl7xrOw3DGb+Whcqu3i/OM6CUOWvgRlufNmnLYy4m77uJI7AXtdNcTDrU71LEyv7v01/N/ovL6bmu5/8A1tNWZldH0W4AAAAASUVORK5CYII="; + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + base64String, + "logo.png", + { isInline: false }, + (result) => { + console.log(result); + } + ); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Set the signature for the current item with inline image. + + const modIcon1Base64 = + "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDRDMxMDg1MjBCNDZFMTExODE2MkM1RUI2M0M4MDYxRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTUxQjgyRjQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTUxQjgyRTQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQxMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNEMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+uC/WfAAAAehJREFUeNpilCzfwEAEkAbiECA2A2J1IOaHin8E4ptAfBaIVwLxU0IGMRKw0B6IW4DYhoE4cASIK6E0VsCEQ1wUiNcB8QESLGOAqj0MxBuhZhBloS4QnwHiQAbygR/UDF1CFupCXSjHQDmQg5qli8tCUBBsQUoQ1AD8UDNFsVk4n0o+w+bT+egWglKjNymmeGhLkqLcG2oHAwtUoIuQDj5OVgZPLUmwRe5aEmAxqYqNpFgKssOcCeplM0KqdST5GfpDDRm0JfkYrj3/SE7QguyQY4ImYYLgCtAS10kHGMw6dzNsv/qC7OwCClJXYlR++v6b4er3j5QmIFcmaNlIL6AOslCIjhYKMTHQGTBBqxh6gXcgC6/R0cKbIAv30dHCfaAKGJTxHxJSqS3Fz9DkowNmywpyMcgA8fF7b8D8VWcfM6w8+4gYC+VB+RCk8hSh0gaUD4/dewvlvUWRe/z+GzGWgex4BGtiOAHxXhoHpzMoSGHZAhSPW2lo2VZYWkHOh4nEtLrIAE+hZmNUwK+B2BOIv1PRsu9QM1/jatNcBtVZ0IREKXgENesyoVYbzNIdFFi2A5tl+NqlL6BB4QBNzsSCU1A9nlAzMAALAQMOQl0qB23qWwKxIlIrDBQ394H4OBCvISYqAAIMACVibHDqsO7zAAAAAElFTkSuQmCC"; + + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + modIcon1Base64, + "myImage.png", + { isInline: true }, + function(result) { + if (result.status == Office.AsyncResultStatus.Succeeded) { + const signature = (document.getElementById("signature") as HTMLInputElement).value + ""; + console.log(`Setting signature to "${signature}".`); + Office.context.mailbox.item.body.setSignatureAsync( + signature, + { coercionType: "html" }, + function(asyncResult) { + console.log(`setSignatureAsync: ${asyncResult.status}`); + } + ); + } else { + console.error(`addFileAttachmentFromBase64Async: ${result.error}`); + } + } + ); +Office.AppointmentCompose#categories:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + // Note: In order for you to successfully add a category, + + // it must be in the mailbox categories master list. + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#close:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close.yaml + + + Office.context.mailbox.item.close(); +Office.AppointmentCompose#disableClientSignatureAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Disable the client signature. + + Office.context.mailbox.item.disableClientSignatureAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("disableClientSignatureAsync succeeded"); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#end:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml + + + Office.context.mailbox.item.end.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment ends (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml + + + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Get start date failed with message ${result.error.message}`); + return; + } + + const end = result.value; // Set end to current start date and time. + end.setDate(end.getDate() + 1); // Set end as 1 day later than start date. + Office.context.mailbox.item.end.setAsync(end, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Set end date failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set end date and time to ${end}`); + }); + }); +Office.AppointmentCompose#enhancedLocation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + Office.context.mailbox.item.enhancedLocation.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to get locations. Error message: ${result.error.message}`); + return; + } + const places = result.value; + if (places && places.length > 0) { + result.value.forEach(function(place) { + console.log(`Location: ${place.displayName} (type: ${place.locationIdentifier.type})`); + if (place.locationIdentifier.type === Office.MailboxEnums.LocationType.Room) { + console.log("Email address: " + place.emailAddress); + } + }); + } else { + console.log("There are no locations."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + + Office.context.mailbox.item.enhancedLocation.addAsync(locations, (result) => + { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully added locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to add locations. Error message: ${result.error.message}`); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + + Office.context.mailbox.item.enhancedLocation.removeAsync(locations, (result) + => { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully removed locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to remove locations. Error message: ${result.error.message}`); + } + }); +Office.AppointmentCompose#getAttachmentContentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + + + // Gets the attachments of the current message or appointment in compose + mode. The getAttachmentsAsync call can only be used in compose mode. + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + if (result.value.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + for (let i = 0; i < result.value.length; i++) { + // Log the attachment type and its contents to the console. + Office.context.mailbox.item.getAttachmentContentAsync(result.value[i].id, handleAttachmentsCallback); + } + }); +Office.AppointmentCompose#getAttachmentsAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + if (result.value.length > 0) { + for (let i = 0; i < result.value.length; i++) { + const attachment = result.value[i]; + let attachmentType; + switch (attachment.attachmentType) { + case Office.MailboxEnums.AttachmentType.Cloud: + attachmentType = "Attachment is stored in a cloud location"; + break; + case Office.MailboxEnums.AttachmentType.File: + attachmentType = "Attachment is a file"; + break; + case Office.MailboxEnums.AttachmentType.Item: + attachmentType = "Attachment is an Exchange item"; + break; + } + console.log( + "ID: " + + attachment.id + + "\n" + + "Type: " + + attachmentType + + "\n" + + "Name: " + + attachment.name + + "\n" + + "Size: " + + attachment.size + + "\n" + + "isInline: " + + attachment.isInline + ); + } + } else { + console.log("No attachments on this message."); + } + }); +Office.AppointmentCompose#getItemIdAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/item-id-compose.yaml + + + Office.context.mailbox.item.getItemIdAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`getItemIdAsync failed with message: ${result.error.message}`); + return; + } + + console.log(result.value); + }); +Office.AppointmentCompose#getSelectedDataAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-selected-data.yaml + + + Office.context.mailbox.item.getSelectedDataAsync(Office.CoercionType.Text, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const text = asyncResult.value.data; + const prop = asyncResult.value.sourceProperty; + console.log("Selected text in " + prop + ": " + text); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#getSharedPropertiesAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + + + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); +Office.AppointmentCompose#isAllDayEvent:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + + + Office.context.mailbox.item.isAllDayEvent.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Is this an all-day event? " + asyncResult.value); + } else { + console.log("Failed to get if this is an all-day event. Error: " + JSON.stringify(asyncResult.error)); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + + + Office.context.mailbox.item.isAllDayEvent.setAsync(true, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set all-day event: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Appointment set to all-day event."); + } + }); +Office.AppointmentCompose#isClientSignatureEnabledAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Check if the client signature is currently enabled. + + Office.context.mailbox.item.isClientSignatureEnabledAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("isClientSignatureEnabledAsync succeeded with result: " + asyncResult.value); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#itemType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.AppointmentCompose#loadCustomPropertiesAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + Office.context.mailbox.item.loadCustomPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`loadCustomPropertiesAsync failed with message ${result.error.message}`); + return; + } + + customProps = result.value; + console.log("Loaded the CustomProperties object."); + }); +Office.AppointmentCompose#location:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + + + Office.context.mailbox.item.location.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Appointment location: ${result.value}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + + + const location = "my office"; + + Office.context.mailbox.item.location.setAsync(location, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set location to ${location}`); + }); +Office.AppointmentCompose#notificationMessages:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a progress indicator to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a persistent information notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Replaces a notification message of a given key with another message. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Removes a notification message from the current mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.removeAsync(id, + handleResult); +Office.AppointmentCompose#optionalAttendees:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + + + Office.context.mailbox.item.optionalAttendees.getAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOptionalAttendees = asyncResult.value; + for (let i = 0; i < apptOptionalAttendees.length; i++) { + console.log( + "Optional attendees: " + + apptOptionalAttendees[i].displayName + + " (" + + apptOptionalAttendees[i].emailAddress + + ") - response: " + + apptOptionalAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + + + const email = (document.getElementById("emailOptional") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.optionalAttendees.setAsync(emailArray, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting optional attendees field."); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#organizer:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml + + + Office.context.mailbox.item.organizer.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOrganizer = asyncResult.value; + console.log("Organizer: " + apptOrganizer.displayName + " (" + apptOrganizer.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#recurrence:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + Office.context.mailbox.item.recurrence.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const recurrence = asyncResult.value; + if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(`Recurrence pattern: ${JSON.stringify(recurrence)}`); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.AppointmentCompose#removeAttachmentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.removeAttachmentAsync( + (document.getElementById("attachmentId") as HTMLInputElement).value, + (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(`Attachment removed successfully.`); + } + ); +Office.AppointmentCompose#requiredAttendees:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + + + Office.context.mailbox.item.requiredAttendees.getAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptRequiredAttendees = asyncResult.value; + for (let i = 0; i < apptRequiredAttendees.length; i++) { + console.log( + "Required attendees: " + + apptRequiredAttendees[i].displayName + + " (" + + apptRequiredAttendees[i].emailAddress + + ") - response: " + + apptRequiredAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + + + const email = (document.getElementById("emailRequired") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.requiredAttendees.setAsync(emailArray, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting required attendees field."); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#saveAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/save.yaml + + + Office.context.mailbox.item.saveAsync(function (result) { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`saveAsync succeeded, itemId is ${result.value}`); + } + else { + console.error(`saveAsync failed with message ${result.error.message}`); + } + }); +Office.AppointmentCompose#sendAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/send-async.yaml + + + // This snippet sends the current message or appointment being composed. + + Office.context.mailbox.item.sendAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + }); +Office.AppointmentCompose#sensitivity:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + + + Office.context.mailbox.item.sensitivity.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Sensitivity: " + asyncResult.value); + } else { + console.log("Failed to get sensitivity: " + JSON.stringify(asyncResult.error)); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + + + Office.context.mailbox.item.sensitivity.setAsync( + Office.MailboxEnums.AppointmentSensitivityType.Private, + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set appointment sensitivity: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Successfully set appointment sensitivity."); + } + } + ); +Office.AppointmentCompose#sensitivityLabel:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + + + // This snippet gets the current mail item's sensitivity label. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.mailbox.item.sensitivityLabel.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.AppointmentCompose#seriesId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml + + + const seriesId = Office.context.mailbox.item.seriesId; + + + if (seriesId === undefined) { + console.log("This is a message that's not a meeting request."); + } else if (seriesId === null) { + console.log("This is a single appointment, a parent series, or a meeting request for a series or single meeting."); + } else { + console.log("This is an instance belonging to series with ID " + seriesId); + } +Office.AppointmentCompose#sessionData:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.getAllAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get all sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.AppointmentCompose#setSelectedDataAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/set-selected-data.yaml + + + Office.context.mailbox.item.setSelectedDataAsync("Replaced", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected text has been updated successfully."); + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentCompose#start:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + + + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment starts (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + + + const start = new Date(); // Represents current date and time. + + start.setDate(start.getDate() + 2); // Add 2 days to current date. + + Office.context.mailbox.item.start.setAsync(start, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set start date and time to ${start}`); + }); +Office.AppointmentCompose#subject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + + + Office.context.mailbox.item.subject.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Subject: ${result.value}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + + + let subject = "Hello World!"; + + Office.context.mailbox.item.subject.setAsync(subject, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set subject to ${subject}`); + }); +Office.AppointmentForm:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-appointment.yaml + + + const start = new Date(); + + const end = new Date(); + + end.setHours(start.getHours() + 1); + + + // The async version is only available starting with requirement set 1.9, + + // and provides a callback when the new appointment form has been created. + + Office.context.mailbox.displayNewAppointmentFormAsync( + { + requiredAttendees: ["bob@contoso.com"], + optionalAttendees: ["sam@contoso.com"], + start: start, + end: end, + location: "Home", + subject: "meeting", + resources: ["projector@contoso.com"], + body: "Hello World!" + }, + function(asyncResult) { + console.log(JSON.stringify(asyncResult)); + } + ); +Office.AppointmentRead#attachments:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml + + + const item = Office.context.mailbox.item; + + + if (item.attachments.length > 0) { + for (let i = 0; i < item.attachments.length; i++) { + const attachment = item.attachments[i]; + console.log(`${i+1}. Name: ${attachment.name}`); + console.log(`ID: ${attachment.id}`); + console.log(`Type: ${attachment.attachmentType}`); + console.log(`Inline content: ${attachment.isInline}`); + console.log(`Size: ${attachment.size}`); + } + } else { + console.log("This mail item doesn't contain any attachments."); + } +Office.AppointmentRead#categories:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + // Note: In order for you to successfully add a category, + + // it must be in the mailbox categories master list. + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.AppointmentRead#dateTimeCreated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml + + + console.log(`Creation date and time: + ${Office.context.mailbox.item.dateTimeCreated}`); +Office.AppointmentRead#dateTimeModified:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml + + + console.log(`Date and time item last modified: + ${Office.context.mailbox.item.dateTimeModified}`); +Office.AppointmentRead#displayReplyAllForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyAllForm("This is a reply ALL with + some bold text."); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // Create the reply with attachments. + + Office.context.mailbox.item.displayReplyAllForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + }); +Office.AppointmentRead#displayReplyAllFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyAllFormAsync("This is a reply ALL + with some bold text.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyAllFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + ); +Office.AppointmentRead#displayReplyForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyForm("This is a reply with some + text in italics."); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // Create the reply with attachments. + + Office.context.mailbox.item.displayReplyForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply with attachments."); + } + }); +Office.AppointmentRead#displayReplyFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyFormAsync("This is a reply with + some text in italics.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created reply with attachments."); + } + ); +Office.AppointmentRead#end:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-end-read.yaml + + + const time = Office.context.mailbox.item.end; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment ends (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.AppointmentRead#enhancedLocation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + Office.context.mailbox.item.enhancedLocation.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to get locations. Error message: ${result.error.message}`); + return; + } + const places = result.value; + if (places && places.length > 0) { + result.value.forEach(function(place) { + console.log(`Location: ${place.displayName} (type: ${place.locationIdentifier.type})`); + if (place.locationIdentifier.type === Office.MailboxEnums.LocationType.Room) { + console.log("Email address: " + place.emailAddress); + } + }); + } else { + console.log("There are no locations."); + } + }); +Office.AppointmentRead#getAttachmentContentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + + + // Gets the attachments of the current message or appointment in read mode. + The item.attachments call can only be used in read mode. + + const item = Office.context.mailbox.item; + + const attachments = item.attachments; + + if (attachments.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + + for (let i = 0; i < attachments.length; i++) { + // Log the attachment type and its contents to the console. + item.getAttachmentContentAsync(attachments[i].id, handleAttachmentsCallback); + } +Office.AppointmentRead#getRegExMatches:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + // This API only works when you click on the highlighted word "ScriptLab". + + console.log(Office.context.mailbox.item.getRegExMatches()); +Office.AppointmentRead#getRegExMatchesByName:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + // This API only works when you click on the highlighted word "ScriptLab". + + console.log(Office.context.mailbox.item.getRegExMatchesByName("sampleRegexName")); +Office.AppointmentRead#getSelectedRegExMatches:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + const matches = Office.context.mailbox.item.getSelectedRegExMatches(); + + if (matches) { + console.log(matches); + } else { + console.error("Open add-in by clicking on a highlighted regex match, for this API to return something useful."); + } +Office.AppointmentRead#getSharedPropertiesAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + + + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); +Office.AppointmentRead#itemClass:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-read.yaml + + + console.log(`Item class: ${Office.context.mailbox.item.itemClass}`); +Office.AppointmentRead#itemType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.AppointmentRead#loadCustomPropertiesAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + Office.context.mailbox.item.loadCustomPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`loadCustomPropertiesAsync failed with message ${result.error.message}`); + return; + } + + customProps = result.value; + console.log("Loaded the CustomProperties object."); + }); +Office.AppointmentRead#location:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-location-read.yaml + + + console.log(`Appointment location: + ${Office.context.mailbox.item.location}`); +Office.AppointmentRead#normalizedSubject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml + + + console.log(`Normalized subject: + ${Office.context.mailbox.item.normalizedSubject}`); +Office.AppointmentRead#notificationMessages:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a progress indicator to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a persistent information notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Replaces a notification message of a given key with another message. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Removes a notification message from the current mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.removeAsync(id, + handleResult); +Office.AppointmentRead#optionalAttendees:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml + + + const apptOptionalAttendees = Office.context.mailbox.item.optionalAttendees; + + console.log("Optional attendees:"); + + for (let i = 0; i < apptOptionalAttendees.length; i++) { + console.log( + apptOptionalAttendees[i].displayName + + " (" + + apptOptionalAttendees[i].emailAddress + + ") - response: " + + apptOptionalAttendees[i].appointmentResponse + ); + } +Office.AppointmentRead#organizer:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml + + + const apptOrganizer = Office.context.mailbox.item.organizer; + + console.log("Organizer: " + apptOrganizer.displayName + " (" + + apptOrganizer.emailAddress + ")"); +Office.AppointmentRead#recurrence:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-recurrence-read.yaml + + + const recurrence = Office.context.mailbox.item.recurrence; + + + if (recurrence === undefined) { + console.log("This item is a message but not a meeting request."); + } else if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(JSON.stringify(recurrence)); + } +Office.AppointmentRead#requiredAttendees:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml + + + const apptRequiredAttendees = Office.context.mailbox.item.requiredAttendees; + + console.log("Required attendees:"); + + for (let i = 0; i < apptRequiredAttendees.length; i++) { + console.log( + apptRequiredAttendees[i].displayName + + " (" + + apptRequiredAttendees[i].emailAddress + + ") - response: " + + apptRequiredAttendees[i].appointmentResponse + ); + } +Office.AppointmentRead#seriesId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml + + + const seriesId = Office.context.mailbox.item.seriesId; + + + if (seriesId === undefined) { + console.log("This is a message that's not a meeting request."); + } else if (seriesId === null) { + console.log("This is a single appointment, a parent series, or a meeting request for a series or single meeting."); + } else { + console.log("This is an instance belonging to series with ID " + seriesId); + } +Office.AppointmentRead#start:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml + + + const time = Office.context.mailbox.item.start; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment starts (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.AppointmentRead#subject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-subject-read.yaml + + + console.log(`Subject: ${Office.context.mailbox.item.subject}`); +Office.AttachmentDetails:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml + + + const item = Office.context.mailbox.item; + + + if (item.attachments.length > 0) { + for (let i = 0; i < item.attachments.length; i++) { + const attachment = item.attachments[i]; + console.log(`${i+1}. Name: ${attachment.name}`); + console.log(`ID: ${attachment.id}`); + console.log(`Type: ${attachment.attachmentType}`); + console.log(`Inline content: ${attachment.isInline}`); + console.log(`Size: ${attachment.size}`); + } + } else { + console.log("This mail item doesn't contain any attachments."); + } +Office.AttachmentDetailsCompose:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + if (result.value.length > 0) { + for (let i = 0; i < result.value.length; i++) { + const attachment = result.value[i]; + let attachmentType; + switch (attachment.attachmentType) { + case Office.MailboxEnums.AttachmentType.Cloud: + attachmentType = "Attachment is stored in a cloud location"; + break; + case Office.MailboxEnums.AttachmentType.File: + attachmentType = "Attachment is a file"; + break; + case Office.MailboxEnums.AttachmentType.Item: + attachmentType = "Attachment is an Exchange item"; + break; + } + console.log( + "ID: " + + attachment.id + + "\n" + + "Type: " + + attachmentType + + "\n" + + "Name: " + + attachment.name + + "\n" + + "Size: " + + attachment.size + + "\n" + + "isInline: " + + attachment.isInline + ); + } + } else { + console.log("No attachments on this message."); + } + }); +Office.Body:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/add-inline-base64-image.yaml + + + // Get the current body of the message or appointment. + + Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, + (bodyResult) => { + if (bodyResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to get body: ${bodyResult.error.message}`); + return; + } + + // Add the Base64-encoded image to the end of the body. + const options = { isInline: true, asyncContext: bodyResult.value }; + Office.context.mailbox.item.addFileAttachmentFromBase64Async(base64String, "sample.png", options, (attachResult) => { + if (attachResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to attach file: ${attachResult.error.message}`); + return; + } + + let body = attachResult.asyncContext; + body += ''; + + Office.context.mailbox.item.body.setAsync(body, { coercionType: Office.CoercionType.Html }, (setResult) => { + if (setResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to set body: ${setResult.error.message}`); + return; + } + + console.log("Inline Base64-encoded image added to the end of the body."); + }); + }); + }); +Office.Body#appendOnSendAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/append-text-on-send.yaml + + + // This snippet appends text to the end of the message or appointment's body + once it's sent. + + const text = (document.getElementById("text-field") as + HTMLInputElement).value; + + + // It's recommended to call getTypeAsync and pass its returned value to the + options.coercionType parameter of the appendOnSendAsync call. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.appendOnSendAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" will be appended to the body once the message or appointment is sent. Send the mail item to test this feature.`); + }); + }); +Office.Body#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/add-inline-base64-image.yaml + + + // Get the current body of the message or appointment. + + Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, + (bodyResult) => { + if (bodyResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to get body: ${bodyResult.error.message}`); + return; + } + + // Add the Base64-encoded image to the end of the body. + const options = { isInline: true, asyncContext: bodyResult.value }; + Office.context.mailbox.item.addFileAttachmentFromBase64Async(base64String, "sample.png", options, (attachResult) => { + if (attachResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to attach file: ${attachResult.error.message}`); + return; + } + + let body = attachResult.asyncContext; + body += ''; + + Office.context.mailbox.item.body.setAsync(body, { coercionType: Office.CoercionType.Html }, (setResult) => { + if (setResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to set body: ${setResult.error.message}`); + return; + } + + console.log("Inline Base64-encoded image added to the end of the body."); + }); + }); + }); +Office.Body#getTypeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-body-format.yaml + + + // Get the mail item's body format (plain text or HTML) and log it to the + console. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log("Body format: " + asyncResult.value); + }); +Office.Body#prependAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-to-item-body.yaml + + + /* This snippet adds text to the beginning of the message or appointment's + body. + + When prepending a link in HTML markup to the body, you can disable the online link preview by setting the anchor tag's id attribute to "LPNoLP". For example, 'Click here!'. + */ + + const text = (document.getElementById("text-field") as + HTMLInputElement).value; + + + // It's recommended to call getTypeAsync and pass its returned value to the + options.coercionType parameter of the prependAsync call. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.prependAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" prepended to the body.`); + }); + }); +Office.Body#prependOnSendAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-on-send.yaml + + + // This snippet prepends text to the beginning of the message or + appointment's body once it's sent. + + const text = (document.getElementById("text-field") as + HTMLInputElement).value; + + + // It's recommended to call getTypeAsync and pass its returned value to the + options.coercionType parameter of the prependOnSendAsync call. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.prependOnSendAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" will be prepended to the body once the message or appointment is sent. Send the mail item to test this feature.`); + }); + }); +Office.Body#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/add-inline-base64-image.yaml + + + // Get the current body of the message or appointment. + + Office.context.mailbox.item.body.getAsync(Office.CoercionType.Html, + (bodyResult) => { + if (bodyResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to get body: ${bodyResult.error.message}`); + return; + } + + // Add the Base64-encoded image to the end of the body. + const options = { isInline: true, asyncContext: bodyResult.value }; + Office.context.mailbox.item.addFileAttachmentFromBase64Async(base64String, "sample.png", options, (attachResult) => { + if (attachResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to attach file: ${attachResult.error.message}`); + return; + } + + let body = attachResult.asyncContext; + body += ''; + + Office.context.mailbox.item.body.setAsync(body, { coercionType: Office.CoercionType.Html }, (setResult) => { + if (setResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Failed to set body: ${setResult.error.message}`); + return; + } + + console.log("Inline Base64-encoded image added to the end of the body."); + }); + }); + }); +Office.Body#setSelectedDataAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/replace-selected-text.yaml + + + /* This snippet replaces selected text in a message or appointment's body + with specified text. + + If you want to use a link in HTML markup as a value of the setSelectedDataAsync call's data parameter, you can disable online link preview by setting the anchor tag's id attribute to "LPNoLP". For example, 'Click here!'. + */ + + const text = (document.getElementById("text-field") as + HTMLInputElement).value; + + + // It's recommended to call getTypeAsync and pass its returned value to the + options.coercionType parameter of the prependAsync call. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.setSelectedDataAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`Replaced selected text with "${text}".`); + }); + }); +Office.Body#setSignatureAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Set the signature for the current item with inline image. + + const modIcon1Base64 = + "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDRDMxMDg1MjBCNDZFMTExODE2MkM1RUI2M0M4MDYxRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTUxQjgyRjQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTUxQjgyRTQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQxMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNEMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+uC/WfAAAAehJREFUeNpilCzfwEAEkAbiECA2A2J1IOaHin8E4ptAfBaIVwLxU0IGMRKw0B6IW4DYhoE4cASIK6E0VsCEQ1wUiNcB8QESLGOAqj0MxBuhZhBloS4QnwHiQAbygR/UDF1CFupCXSjHQDmQg5qli8tCUBBsQUoQ1AD8UDNFsVk4n0o+w+bT+egWglKjNymmeGhLkqLcG2oHAwtUoIuQDj5OVgZPLUmwRe5aEmAxqYqNpFgKssOcCeplM0KqdST5GfpDDRm0JfkYrj3/SE7QguyQY4ImYYLgCtAS10kHGMw6dzNsv/qC7OwCClJXYlR++v6b4er3j5QmIFcmaNlIL6AOslCIjhYKMTHQGTBBqxh6gXcgC6/R0cKbIAv30dHCfaAKGJTxHxJSqS3Fz9DkowNmywpyMcgA8fF7b8D8VWcfM6w8+4gYC+VB+RCk8hSh0gaUD4/dewvlvUWRe/z+GzGWgex4BGtiOAHxXhoHpzMoSGHZAhSPW2lo2VZYWkHOh4nEtLrIAE+hZmNUwK+B2BOIv1PRsu9QM1/jatNcBtVZ0IREKXgENesyoVYbzNIdFFi2A5tl+NqlL6BB4QBNzsSCU1A9nlAzMAALAQMOQl0qB23qWwKxIlIrDBQ394H4OBCvISYqAAIMACVibHDqsO7zAAAAAElFTkSuQmCC"; + + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + modIcon1Base64, + "myImage.png", + { isInline: true }, + function(result) { + if (result.status == Office.AsyncResultStatus.Succeeded) { + const signature = (document.getElementById("signature") as HTMLInputElement).value + ""; + console.log(`Setting signature to "${signature}".`); + Office.context.mailbox.item.body.setSignatureAsync( + signature, + { coercionType: "html" }, + function(asyncResult) { + console.log(`setSignatureAsync: ${asyncResult.status}`); + } + ); + } else { + console.error(`addFileAttachmentFromBase64Async: ${result.error}`); + } + } + ); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Set the signature for the current item. + + const signature = (document.getElementById("signature") as + HTMLInputElement).value; + + console.log(`Setting signature to "${signature}".`); + + Office.context.mailbox.item.body.setSignatureAsync(signature, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("setSignatureAsync succeeded"); + } else { + console.error(asyncResult.error); + } + }); +Office.Categories#addAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + // Note: In order for you to successfully add a category, + + // it must be in the mailbox categories master list. + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.Categories#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.Categories#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.CoercionTypeOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/append-text-on-send.yaml + + + // This snippet appends text to the end of the message or appointment's body + once it's sent. + + const text = (document.getElementById("text-field") as + HTMLInputElement).value; + + + // It's recommended to call getTypeAsync and pass its returned value to the + options.coercionType parameter of the appendOnSendAsync call. + + Office.context.mailbox.item.body.getTypeAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + const bodyFormat = asyncResult.value; + Office.context.mailbox.item.body.appendOnSendAsync(text, { coercionType: bodyFormat }, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log(`"${text}" will be appended to the body once the message or appointment is sent. Send the mail item to test this feature.`); + }); + }); +Office.CustomProperties#get:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + const propertyName = (document.getElementById("get-property-name") as + HTMLInputElement).value; + + const propertyValue = customProps.get(propertyName); + + console.log(`The value of custom property "${propertyName}" is + "${propertyValue}".`); +Office.CustomProperties#getAll:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + let allCustomProps; + + if (Office.context.requirements.isSetSupported("Mailbox", "1.9")) { + allCustomProps = customProps.getAll(); + } else { + allCustomProps = customProps["rawData"]; + } + + + console.log(allCustomProps); +Office.CustomProperties#remove:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + const propertyName = (document.getElementById("remove-property-name") as + HTMLInputElement).value; + + customProps.remove(propertyName); + + console.log(`Custom property "${propertyName}" removed.`); +Office.CustomProperties#saveAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + customProps.saveAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`saveAsync failed with message ${result.error.message}`); + return; + } + + console.log(`Custom properties saved with status: ${result.status}`); + }); +Office.CustomProperties#set:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + const propertyName = (document.getElementById("set-property-name") as + HTMLInputElement).value; + + const propertyValue = (document.getElementById("property-value") as + HTMLInputElement).value; + + customProps.set(propertyName, propertyValue); + + console.log(`Custom property "${propertyName}" set to value + "${propertyValue}".`); +Office.DelayDeliveryTime#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/delay-message-delivery.yaml + + + // This snippet gets the delivery date and time of a message. + + Office.context.mailbox.item.delayDeliveryTime.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + const deliveryDate = asyncResult.value; + if (deliveryDate === 0) { + console.log("Your message will be delivered immediately when you select Send."); + } else { + const date = new Date(deliveryDate); + console.log(`Message delivery date and time: ${date.toString()}`); + } + }); +Office.DelayDeliveryTime#setAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/delay-message-delivery.yaml + + + function setDeliveryDate(minutes) { + // This snippet sets the delivery date and time of a message. + const currentTime = new Date().getTime(); + const milliseconds = totalDelay * 60000; + const timeDelay = new Date(currentTime + milliseconds); + Office.context.mailbox.item.delayDeliveryTime.setAsync(timeDelay, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + if (minutes === 1440) { + console.log(`Delayed delivery by an additional one day.`); + } else { + console.log(`Delayed delivery by an additional ${minutes} minutes.`); + } + }); + } +Office.Diagnostics:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml + + + // This function gets a mailbox's diagnostic information, such as Outlook + client and version, and logs it to the console. + + const diagnostics = Office.context.mailbox.diagnostics; + + console.log(`Client application: ${diagnostics.hostName}`); + + console.log(`Client version: ${diagnostics.hostVersion}`); + + + switch (diagnostics.OWAView) { + case undefined: + console.log("Current view (Outlook on the web only): Not applicable. An Outlook desktop client is in use."); + break; + case Office.MailboxEnums.OWAView.OneColumnNarrow: + console.log("Current view (Outlook on the web only): Viewed from an older generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.OneColumn: + console.log("Current view (Outlook on the web only): Viewed from a newer generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.TwoColumns: + console.log("Current view (Outlook on the web only): Viewed from a tablet"); + break; + case Office.MailboxEnums.OWAView.ThreeColumns: + console.log("Current view (Outlook on the web only): Viewed from a desktop computer"); + break; + } +Office.Display#body:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + + + // This snippet temporarily sets the content displayed in the body of a + message in read mode. + + // The set content will remain visible until the user switches to a + different message in the Reading Pane or closes the window of the current + message. + + const bodyText = (document.getElementById("body-text-field") as + HTMLInputElement).value; + + Office.context.mailbox.item.display.body.setAsync(bodyText, (asyncResult) => + { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the body."); + }); +Office.Display#subject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + + + // This snippet temporarily sets the content displayed in the subject field + of a message in read mode. + + // The set content will remain visible until the user switches to a + different message in the Reading Pane or closes the window of the current + message. + + const subjectText = (document.getElementById("subject-text-field") as + HTMLInputElement).value; + + Office.context.mailbox.item.display.subject.setAsync(subjectText, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the subject field."); + }); +Office.DisplayedBody#setAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + + + // This snippet temporarily sets the content displayed in the body of a + message in read mode. + + // The set content will remain visible until the user switches to a + different message in the Reading Pane or closes the window of the current + message. + + const bodyText = (document.getElementById("body-text-field") as + HTMLInputElement).value; + + Office.context.mailbox.item.display.body.setAsync(bodyText, (asyncResult) => + { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the body."); + }); +Office.DisplayedSubject#setAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + + + // This snippet temporarily sets the content displayed in the subject field + of a message in read mode. + + // The set content will remain visible until the user switches to a + different message in the Reading Pane or closes the window of the current + message. + + const subjectText = (document.getElementById("subject-text-field") as + HTMLInputElement).value; + + Office.context.mailbox.item.display.subject.setAsync(subjectText, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the subject field."); + }); +Office.DragAndDropEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } +Office.DragoverEventData:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } +Office.DropEventData:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } +Office.DroppedItems:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } +Office.DroppedItemDetails:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml + + + function dragAndDropEventHandler(event) { + Office.context.mailbox.addHandlerAsync(Office.EventType.DragAndDropEvent, (event) => { + console.log(`Event type: ${event.type}`); + + const eventData = event.dragAndDropEventData; + console.log(`x-coordinate: ${eventData.pageX}, y-coordinate: ${eventData.pageY}`); + + if (eventData.type == "drop") { + console.log("Items dropped into task pane."); + const files = eventData.dataTransfer.files; + files.forEach((file) => { + const content = file.fileContent; + const name = file.name; + const fileType = file.type; + console.log(`File name: ${name}`); + console.log(`File type: ${fileType}`); + console.log(`Contents: ${content.text().then((text) => { console.log(text); })}`); + }); + } + }); + } +Office.EnhancedLocation#addAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + + Office.context.mailbox.item.enhancedLocation.addAsync(locations, (result) => + { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully added locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to add locations. Error message: ${result.error.message}`); + } + }); +Office.EnhancedLocation#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + Office.context.mailbox.item.enhancedLocation.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to get locations. Error message: ${result.error.message}`); + return; + } + const places = result.value; + if (places && places.length > 0) { + result.value.forEach(function(place) { + console.log(`Location: ${place.displayName} (type: ${place.locationIdentifier.type})`); + if (place.locationIdentifier.type === Office.MailboxEnums.LocationType.Room) { + console.log("Email address: " + place.emailAddress); + } + }); + } else { + console.log("There are no locations."); + } + }); +Office.EnhancedLocation#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + + Office.context.mailbox.item.enhancedLocation.removeAsync(locations, (result) + => { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully removed locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to remove locations. Error message: ${result.error.message}`); + } + }); +Office.From#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml + + + Office.context.mailbox.item.from.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgFrom = asyncResult.value; + console.log("Message from: " + msgFrom.displayName + " (" + msgFrom.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); +Office.InternetHeaders#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + + + Office.context.mailbox.item.internetHeaders.getAsync( + ["preferred-fruit", "preferred-vegetable", "best-vegetable", "nonexistent-header"], + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected headers: " + JSON.stringify(asyncResult.value)); + } else { + console.log("Error getting selected headers: " + JSON.stringify(asyncResult.error)); + } + } + ); +Office.InternetHeaders#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + + + Office.context.mailbox.item.internetHeaders.removeAsync( + ["best-vegetable", "nonexistent-header"], + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully removed selected headers"); + } else { + console.log("Error removing selected headers: " + JSON.stringify(asyncResult.error)); + } + } + ); +Office.InternetHeaders#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + + + Office.context.mailbox.item.internetHeaders.setAsync( + { "preferred-fruit": "orange", "preferred-vegetable": "broccoli", "best-vegetable": "spinach" }, + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully set headers"); + } else { + console.log("Error setting headers: " + JSON.stringify(asyncResult.error)); + } + } + + ); +Office.IsAllDayEvent#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + + + Office.context.mailbox.item.isAllDayEvent.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Is this an all-day event? " + asyncResult.value); + } else { + console.log("Failed to get if this is an all-day event. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.IsAllDayEvent#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml + + + Office.context.mailbox.item.isAllDayEvent.setAsync(true, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set all-day event: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Appointment set to all-day event."); + } + }); +Office.Item:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.LocalClientTime:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml + + + const time = Office.context.mailbox.item.start; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment starts (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.Location#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + + + Office.context.mailbox.item.location.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Appointment location: ${result.value}`); + }); +Office.Location#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml + + + const location = "my office"; + + Office.context.mailbox.item.location.setAsync(location, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set location to ${location}`); + }); +Office.Mailbox#convertToEwsId:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + + + // Get the EWS URL and EWS item ID. + + console.log("EWS URL: " + Office.context.mailbox.ewsUrl); + + const ewsId = Office.context.mailbox.item.itemId; + + console.log("EWS item ID: " + Office.context.mailbox.item.itemId); + + + // Convert the EWS item ID to a REST-formatted ID. + + const restId = Office.context.mailbox.convertToRestId(ewsId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("REST item ID: " + restId); + + + // Convert the REST-formatted ID back to an EWS-formatted ID. + + const ewsId2 = Office.context.mailbox.convertToEwsId(restId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("EWS ID (from REST ID): " + ewsId2); +Office.Mailbox#convertToLocalClientTime:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml + + + const time = Office.context.mailbox.item.start; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment starts (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.Mailbox#convertToRestId:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + + + // Get the EWS URL and EWS item ID. + + console.log("EWS URL: " + Office.context.mailbox.ewsUrl); + + const ewsId = Office.context.mailbox.item.itemId; + + console.log("EWS item ID: " + Office.context.mailbox.item.itemId); + + + // Convert the EWS item ID to a REST-formatted ID. + + const restId = Office.context.mailbox.convertToRestId(ewsId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("REST item ID: " + restId); + + + // Convert the REST-formatted ID back to an EWS-formatted ID. + + const ewsId2 = Office.context.mailbox.convertToEwsId(restId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("EWS ID (from REST ID): " + ewsId2); +Office.Mailbox#diagnostics:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml + + + // This function gets a mailbox's diagnostic information, such as Outlook + client and version, and logs it to the console. + + const diagnostics = Office.context.mailbox.diagnostics; + + console.log(`Client application: ${diagnostics.hostName}`); + + console.log(`Client version: ${diagnostics.hostVersion}`); + + + switch (diagnostics.OWAView) { + case undefined: + console.log("Current view (Outlook on the web only): Not applicable. An Outlook desktop client is in use."); + break; + case Office.MailboxEnums.OWAView.OneColumnNarrow: + console.log("Current view (Outlook on the web only): Viewed from an older generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.OneColumn: + console.log("Current view (Outlook on the web only): Viewed from a newer generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.TwoColumns: + console.log("Current view (Outlook on the web only): Viewed from a tablet"); + break; + case Office.MailboxEnums.OWAView.ThreeColumns: + console.log("Current view (Outlook on the web only): Viewed from a desktop computer"); + break; + } +Office.Mailbox#displayAppointmentForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-appointment.yaml + + + const itemId = (document.getElementById("itemId") as + HTMLInputElement).value; + + Office.context.mailbox.displayAppointmentForm(itemId); +Office.Mailbox#displayAppointmentFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-appointment.yaml + + + const itemId = (document.getElementById("itemId") as + HTMLInputElement).value; + + + // The async version will return error 9049 if the item is not found. + + // The async version is only available starting with requirement set 1.9. + + Office.context.mailbox.displayAppointmentFormAsync(itemId, + function(asyncResult) { + console.log("Result: " + JSON.stringify(asyncResult)); + }); +Office.Mailbox#displayMessageForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-message.yaml + + + const itemId = (document.getElementById("itemId") as + HTMLInputElement).value; + + Office.context.mailbox.displayMessageForm(itemId); +Office.Mailbox#displayMessageFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-message.yaml + + + const itemId = (document.getElementById("itemId") as + HTMLInputElement).value; + + + // The async version will return error 9049 if the item is not found. + + // The async version is only available starting with requirement set 1.9. + + Office.context.mailbox.displayMessageFormAsync(itemId, function + (asyncResult) { + console.log("Result: " + JSON.stringify(asyncResult)); + }); +Office.Mailbox#displayNewAppointmentForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-appointment.yaml + + + const start = new Date(); + + const end = new Date(); + + end.setHours(start.getHours() + 1); + + + Office.context.mailbox.displayNewAppointmentForm({ + requiredAttendees: ["bob@contoso.com"], + optionalAttendees: ["sam@contoso.com"], + start: start, + end: end, + location: "Home", + subject: "meeting", + resources: ["projector@contoso.com"], + body: "Hello World!" + }); +Office.Mailbox#displayNewAppointmentFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-appointment.yaml + + + const start = new Date(); + + const end = new Date(); + + end.setHours(start.getHours() + 1); + + + // The async version is only available starting with requirement set 1.9, + + // and provides a callback when the new appointment form has been created. + + Office.context.mailbox.displayNewAppointmentFormAsync( + { + requiredAttendees: ["bob@contoso.com"], + optionalAttendees: ["sam@contoso.com"], + start: start, + end: end, + location: "Home", + subject: "meeting", + resources: ["projector@contoso.com"], + body: "Hello World!" + }, + function(asyncResult) { + console.log(JSON.stringify(asyncResult)); + } + ); +Office.Mailbox#displayNewMessageForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-message.yaml + + + Office.context.mailbox.displayNewMessageForm({ + toRecipients: Office.context.mailbox.item.to, // Copies the To line from current item + ccRecipients: ["sam@contoso.com"], + subject: "Outlook add-ins are cool!", + htmlBody: 'Hello World!
      ', + attachments: [ + { + type: "file", + name: "image.png", + url: "https://i.imgur.com/9S36xvA.jpg", + isInline: true + } + ] + }); +Office.Mailbox#displayNewMessageFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-message.yaml + + + // The async version is only available starting with requirement set 1.9, + + // and provides a callback when the new message form has been created. + + Office.context.mailbox.displayNewMessageFormAsync( + { + toRecipients: Office.context.mailbox.item.to, // Copies the To line from current item + ccRecipients: ["sam@contoso.com"], + subject: "Outlook add-ins are cool!", + htmlBody: 'Hello World!
      ', + attachments: [ + { + type: "file", + name: "image.png", + url: "https://i.imgur.com/9S36xvA.jpg", + isInline: true + } + ] + }, + (asyncResult) => { + console.log(JSON.stringify(asyncResult)); + } + ); +Office.Mailbox#ewsUrl:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + + + // Get the EWS URL and EWS item ID. + + console.log("EWS URL: " + Office.context.mailbox.ewsUrl); + + const ewsId = Office.context.mailbox.item.itemId; + + console.log("EWS item ID: " + Office.context.mailbox.item.itemId); + + + // Convert the EWS item ID to a REST-formatted ID. + + const restId = Office.context.mailbox.convertToRestId(ewsId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("REST item ID: " + restId); + + + // Convert the REST-formatted ID back to an EWS-formatted ID. + + const ewsId2 = Office.context.mailbox.convertToEwsId(restId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("EWS ID (from REST ID): " + ewsId2); +Office.Mailbox#getCallbackTokenAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml + + + Office.context.mailbox.getCallbackTokenAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Token retrieval failed with message: ${result.error.message}`); + return; + } + + console.log(result.value); + }); +Office.Mailbox#getSelectedItemsAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-message-properties.yaml + + + // Retrieves the selected messages' properties and logs them to the console. + + Office.context.mailbox.getSelectedItemsAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + asyncResult.value.forEach((message) => { + console.log(`Item ID: ${message.itemId}`); + console.log(`Conversation ID: ${message.conversationId}`); + console.log(`Internet message ID: ${message.internetMessageId}`); + console.log(`Subject: ${message.subject}`); + console.log(`Item type: ${message.itemType}`); + console.log(`Item mode: ${message.itemMode}`); + console.log(`Has attachment: ${message.hasAttachment}`); + }); + }); +Office.Mailbox#getUserIdentityTokenAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml + + + Office.context.mailbox.getUserIdentityTokenAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Token retrieval failed with message: ${result.error.message}`) + return; + } + + console.log(result.value); + }); +Office.Mailbox#loadItemByIdAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml + + + async function getSenderEmailAddress(item) { + const itemId = item.itemId; + await new Promise((resolve) => { + Office.context.mailbox.loadItemByIdAsync(itemId, (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + const loadedItem = result.value; + const sender = loadedItem.from.emailAddress; + appendToListItem(sender); + + // Unload the current message before processing another selected message. + loadedItem.unloadAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + resolve(); + }); + }); + }); + } +Office.Mailbox#makeEwsRequestAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml + + + const ewsId = Office.context.mailbox.item.itemId; + + const request = ` + + + + + AllProperties + + + + + + + `; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(getUID(result.value)); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml + + + const request = ''+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' Hello, Outlook!'+ + ' This message was sent from a ScriptLab code sample, used from ' + Office.context.mailbox.diagnostics.hostName + ', version ' + Office.context.mailbox.diagnostics.hostVersion + '!'+ + ' '+ + ' ' + Office.context.mailbox.userProfile.emailAddress + ''+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ''; + + Office.context.mailbox.makeEwsRequestAsync(request, (result) => { + console.log(result); + }); +Office.Mailbox#masterCategories:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Master categories:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories in the master list."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + const masterCategoriesToAdd = [ + { + displayName: "TestCategory", + color: Office.MailboxEnums.CategoryColor.Preset0 + } + ]; + + + Office.context.mailbox.masterCategories.addAsync(masterCategoriesToAdd, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully added categories to master list"); + } else { + console.log("masterCategories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + const masterCategoriesToRemove = ["TestCategory"]; + + + Office.context.mailbox.masterCategories.removeAsync(masterCategoriesToRemove, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully removed categories from master list"); + } else { + console.log("masterCategories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); +Office.MailboxEnums.ActionType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational message with actions to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + + const itemId = Office.context.mailbox.item.itemId; + + const details = { + type: Office.MailboxEnums.ItemNotificationMessageType.InsightMessage, + message: "This is an insight notification with id = " + id, + icon: "PG.Icon.16", + actions: [ + { + actionText: "Open insight", + actionType: Office.MailboxEnums.ActionType.ShowTaskPane, + // Identify whether the current mail item is in read or compose mode to set the appropriate commandId value. + commandId: (itemId == undefined ? "PG.HelpCommand.Compose" : "PG.HelpCommand.Read"), + contextData: { a: "aValue", b: "bValue" } + } + ] + }; + + + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); +Office.MailboxEnums.AppointmentSensitivityType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + + + Office.context.mailbox.item.sensitivity.setAsync( + Office.MailboxEnums.AppointmentSensitivityType.Private, + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set appointment sensitivity: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Successfully set appointment sensitivity."); + } + } + ); +Office.MailboxEnums.AttachmentContentFormat:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + + + function handleAttachmentsCallback(result) { + // Identifies whether the attachment is a Base64-encoded string, .eml file, .icalendar file, or a URL. + switch (result.value.format) { + case Office.MailboxEnums.AttachmentContentFormat.Base64: + // Handle file attachment. + console.log("Attachment is a Base64-encoded string."); + break; + case Office.MailboxEnums.AttachmentContentFormat.Eml: + // Handle email item attachment. + console.log("Attachment is a message."); + break; + case Office.MailboxEnums.AttachmentContentFormat.ICalendar: + // Handle .icalender attachment. + console.log("Attachment is a calendar item."); + break; + case Office.MailboxEnums.AttachmentContentFormat.Url: + // Handle cloud attachment. + console.log("Attachment is a cloud attachment."); + break; + default: + // Handle attachment formats that aren't supported. + } + + console.log(result.value.content); + } +Office.MailboxEnums.AttachmentType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + if (result.value.length > 0) { + for (let i = 0; i < result.value.length; i++) { + const attachment = result.value[i]; + let attachmentType; + switch (attachment.attachmentType) { + case Office.MailboxEnums.AttachmentType.Cloud: + attachmentType = "Attachment is stored in a cloud location"; + break; + case Office.MailboxEnums.AttachmentType.File: + attachmentType = "Attachment is a file"; + break; + case Office.MailboxEnums.AttachmentType.Item: + attachmentType = "Attachment is an Exchange item"; + break; + } + console.log( + "ID: " + + attachment.id + + "\n" + + "Type: " + + attachmentType + + "\n" + + "Name: " + + attachment.name + + "\n" + + "Size: " + + attachment.size + + "\n" + + "isInline: " + + attachment.isInline + ); + } + } else { + console.log("No attachments on this message."); + } + }); +Office.MailboxEnums.CategoryColor:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + const masterCategoriesToAdd = [ + { + displayName: "TestCategory", + color: Office.MailboxEnums.CategoryColor.Preset0 + } + ]; + + + Office.context.mailbox.masterCategories.addAsync(masterCategoriesToAdd, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully added categories to master list"); + } else { + console.log("masterCategories.addAsync call failed with error: " + asyncResult.error.message); + } + }); +Office.MailboxEnums.ComposeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Get the compose type of the current message. + + Office.context.mailbox.item.getComposeTypeAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log( + "getComposeTypeAsync succeeded with composeType: " + + asyncResult.value.composeType + + " and coercionType: " + + asyncResult.value.coercionType + ); + } else { + console.error(asyncResult.error); + } + }); +Office.MailboxEnums.Days:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.MailboxEnums.ItemNotificationMessageType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an error notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ErrorMessage, + message: "Error notification message with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); +Office.MailboxEnums.ItemType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.MailboxEnums.LocationType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml + + + const locations = [ + { + id: "Contoso", + type: Office.MailboxEnums.LocationType.Custom + }, + { + id: "room500@test.com", + type: Office.MailboxEnums.LocationType.Room + } + ]; + + Office.context.mailbox.item.enhancedLocation.addAsync(locations, (result) => + { + if (result.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully added locations ${JSON.stringify(locations)}`); + } else { + console.error(`Failed to add locations. Error message: ${result.error.message}`); + } + }); +Office.MailboxEnums.Month:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.MailboxEnums.OWAView:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml + + + // This function gets a mailbox's diagnostic information, such as Outlook + client and version, and logs it to the console. + + const diagnostics = Office.context.mailbox.diagnostics; + + console.log(`Client application: ${diagnostics.hostName}`); + + console.log(`Client version: ${diagnostics.hostVersion}`); + + + switch (diagnostics.OWAView) { + case undefined: + console.log("Current view (Outlook on the web only): Not applicable. An Outlook desktop client is in use."); + break; + case Office.MailboxEnums.OWAView.OneColumnNarrow: + console.log("Current view (Outlook on the web only): Viewed from an older generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.OneColumn: + console.log("Current view (Outlook on the web only): Viewed from a newer generation mobile phone"); + break; + case Office.MailboxEnums.OWAView.TwoColumns: + console.log("Current view (Outlook on the web only): Viewed from a tablet"); + break; + case Office.MailboxEnums.OWAView.ThreeColumns: + console.log("Current view (Outlook on the web only): Viewed from a desktop computer"); + break; + } +Office.MailboxEnums.RecipientType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml + + + const msgTo = Office.context.mailbox.item.to; + + const distributionLists = []; + + const externalRecipients = []; + + const internalRecipients = []; + + const otherRecipients = []; + + for (let i = 0; i < msgTo.length; i++) { + switch (msgTo[i].recipientType) { + case Office.MailboxEnums.RecipientType.DistributionList: + distributionLists.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.ExternalUser: + externalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.User: + internalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.Other: + otherRecipients.push(msgTo[i]); + } + } + + + if (distributionLists.length > 0) { + console.log("Distribution Lists:"); + distributionLists.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (externalRecipients.length > 0) { + console.log("External Recipients:"); + externalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (internalRecipients.length > 0) { + console.log("Internal Recipients:"); + internalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (otherRecipients.length > 0) { + console.log("Other Recipients:"); + otherRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } +Office.MailboxEnums.RecurrenceTimeZone:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.MailboxEnums.RecurrenceType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.MailboxEnums.ResponseType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml + + + function organizeByResponse(attendees) { + const accepted = []; + const declined = []; + const noResponse = []; + const tentative = []; + attendees.forEach(attendee => { + switch (attendee.appointmentResponse) { + case Office.MailboxEnums.ResponseType.Accepted: + accepted.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Declined: + declined.push(attendee); + break; + case Office.MailboxEnums.ResponseType.None: + noResponse.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Tentative: + tentative.push(attendee); + break; + case Office.MailboxEnums.ResponseType.Organizer: + console.log(`Organizer: ${attendee.displayName}, ${attendee.emailAddress}`); + break; + } + }); + + // List attendees by their response. + console.log("Accepted: "); + printAttendees(accepted); + console.log("Declined: "); + printAttendees(declined); + console.log("Tentative: "); + printAttendees(tentative); + console.log("No response: "); + printAttendees(noResponse); + } +Office.MailboxEnums.RestVersion:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml + + + // Get the EWS URL and EWS item ID. + + console.log("EWS URL: " + Office.context.mailbox.ewsUrl); + + const ewsId = Office.context.mailbox.item.itemId; + + console.log("EWS item ID: " + Office.context.mailbox.item.itemId); + + + // Convert the EWS item ID to a REST-formatted ID. + + const restId = Office.context.mailbox.convertToRestId(ewsId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("REST item ID: " + restId); + + + // Convert the REST-formatted ID back to an EWS-formatted ID. + + const ewsId2 = Office.context.mailbox.convertToEwsId(restId, + Office.MailboxEnums.RestVersion.v2_0); + + console.log("EWS ID (from REST ID): " + ewsId2); +Office.MailboxEnums.SourceProperty:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-selected-data.yaml + + + Office.context.mailbox.item.getSelectedDataAsync(Office.CoercionType.Text, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const text = asyncResult.value.data; + const prop = asyncResult.value.sourceProperty; + console.log("Selected text in " + prop + ": " + text); + } else { + console.error(asyncResult.error); + } + }); +Office.MailboxEnums.WeekNumber:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.MasterCategories#addAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + const masterCategoriesToAdd = [ + { + displayName: "TestCategory", + color: Office.MailboxEnums.CategoryColor.Preset0 + } + ]; + + + Office.context.mailbox.masterCategories.addAsync(masterCategoriesToAdd, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully added categories to master list"); + } else { + console.log("masterCategories.addAsync call failed with error: " + asyncResult.error.message); + } + }); +Office.MasterCategories#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Master categories:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories in the master list."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.MasterCategories#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml + + + const masterCategoriesToRemove = ["TestCategory"]; + + + Office.context.mailbox.masterCategories.removeAsync(masterCategoriesToRemove, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Successfully removed categories from master list"); + } else { + console.log("masterCategories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); +Office.MessageCompose:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + const attachmentUrl = (document.getElementById("attachmentUrl") as + HTMLInputElement).value; + + Office.context.mailbox.item.addFileAttachmentAsync( + attachmentUrl, + getFileName(attachmentUrl), + { isInline: false }, + (result) => { + console.log(result); + } + ); +Office.MessageCompose#addFileAttachmentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + const attachmentUrl = (document.getElementById("attachmentUrl") as + HTMLInputElement).value; + + Office.context.mailbox.item.addFileAttachmentAsync( + attachmentUrl, + getFileName(attachmentUrl), + { isInline: false }, + (result) => { + console.log(result); + } + ); +Office.MessageCompose#addFileAttachmentFromBase64Async:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + const base64String = + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsSAAALEgHS3X78AAACRUlEQVRYw82XzXHbMBCFP2F8tzsQc8Ixyh0zoiuIXIGdCsxUYKqC0B04FdiuwMoM7mGOOIXqQGoAymXhgSX+itJM9kIRFLAP+3YXD5Pdbscx5oxaAIW8Ztr6l2PWmQwF4IyaieP53qdfAqQ8CwBn1JU4vpWhrbxXQA5MZfynANmcDIAzKgcy4FKGXsVJFf3nLgKyBQptfT4KQMRz2N0fcbxqmRMDWXflx0VPnrdArq0vekQ1Dv0UeHZGNebHhwjU8AzwKM43RyZnbAf58Q6ghudeWd0Aus0+5EcMIIRi3beua0D3Nm39BEAx3i7HTK4DEBJn5YxKOnaRA5+ErpMBWMpzDvx1RuXCcxOISlufAjfC7zgAsqsvUvMAD0ApPaEtGi9AIlUzKgJo60tt/SyKRkzLrAXERluf7W1gOICWaMyB386oooOWsIHvXbSoHuUSFovtHqicUVnH3EJoeT0aQEf5/XBGlc6otIOWBXAtPeZkAIJ9Bt6cUU9tZautX2nrk3MACHYr1ZKProKRtDw4o8pzAPjWo+NtpXTTvoteDDg8noDAcwbcRedAkGdFXyk2GEDcegVAFp2gyVDHjRQ4o6q2smoqtR5Hd+qMqtoALCWUUymr1m43QMZfOaMK4C0SrMsDANJ2E5FNcbdbjHC+ENl+H0myJFbLtaq4Rt8dyPBYRQV1E40nMv9rl7xrOw3DGb+Whcqu3i/OM6CUOWvgRlufNmnLYy4m77uJI7AXtdNcTDrU71LEyv7v01/N/ovL6bmu5/8A1tNWZldH0W4AAAAASUVORK5CYII="; + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + base64String, + "logo.png", + { isInline: false }, + (result) => { + console.log(result); + } + ); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Set the signature for the current item with inline image. + + const modIcon1Base64 = + "iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDRDMxMDg1MjBCNDZFMTExODE2MkM1RUI2M0M4MDYxRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTUxQjgyRjQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTUxQjgyRTQ2MEQxMUUxODlFMkQwNTYzQ0YwMTUxMiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQxMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNEMzEwODUyMEI0NkUxMTE4MTYyQzVFQjYzQzgwNjFEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+uC/WfAAAAehJREFUeNpilCzfwEAEkAbiECA2A2J1IOaHin8E4ptAfBaIVwLxU0IGMRKw0B6IW4DYhoE4cASIK6E0VsCEQ1wUiNcB8QESLGOAqj0MxBuhZhBloS4QnwHiQAbygR/UDF1CFupCXSjHQDmQg5qli8tCUBBsQUoQ1AD8UDNFsVk4n0o+w+bT+egWglKjNymmeGhLkqLcG2oHAwtUoIuQDj5OVgZPLUmwRe5aEmAxqYqNpFgKssOcCeplM0KqdST5GfpDDRm0JfkYrj3/SE7QguyQY4ImYYLgCtAS10kHGMw6dzNsv/qC7OwCClJXYlR++v6b4er3j5QmIFcmaNlIL6AOslCIjhYKMTHQGTBBqxh6gXcgC6/R0cKbIAv30dHCfaAKGJTxHxJSqS3Fz9DkowNmywpyMcgA8fF7b8D8VWcfM6w8+4gYC+VB+RCk8hSh0gaUD4/dewvlvUWRe/z+GzGWgex4BGtiOAHxXhoHpzMoSGHZAhSPW2lo2VZYWkHOh4nEtLrIAE+hZmNUwK+B2BOIv1PRsu9QM1/jatNcBtVZ0IREKXgENesyoVYbzNIdFFi2A5tl+NqlL6BB4QBNzsSCU1A9nlAzMAALAQMOQl0qB23qWwKxIlIrDBQ394H4OBCvISYqAAIMACVibHDqsO7zAAAAAElFTkSuQmCC"; + + Office.context.mailbox.item.addFileAttachmentFromBase64Async( + modIcon1Base64, + "myImage.png", + { isInline: true }, + function(result) { + if (result.status == Office.AsyncResultStatus.Succeeded) { + const signature = (document.getElementById("signature") as HTMLInputElement).value + ""; + console.log(`Setting signature to "${signature}".`); + Office.context.mailbox.item.body.setSignatureAsync( + signature, + { coercionType: "html" }, + function(asyncResult) { + console.log(`setSignatureAsync: ${asyncResult.status}`); + } + ); + } else { + console.error(`addFileAttachmentFromBase64Async: ${result.error}`); + } + } + ); +Office.MessageCompose#bcc:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + + + Office.context.mailbox.item.bcc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgBcc = asyncResult.value; + console.log("Message being blind-copied to:"); + for (let i = 0; i < msgBcc.length; i++) { + console.log(msgBcc[i].displayName + " (" + msgBcc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + + + const email = (document.getElementById("emailBcc") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.bcc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Bcc field."); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#categories:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + // Note: In order for you to successfully add a category, + + // it must be in the mailbox categories master list. + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#cc:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + + + Office.context.mailbox.item.cc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgCc = asyncResult.value; + console.log("Message being copied to:"); + for (let i = 0; i < msgCc.length; i++) { + console.log(msgCc[i].displayName + " (" + msgCc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + + + const email = (document.getElementById("emailCc") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.cc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Cc field."); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#close:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close.yaml + + + Office.context.mailbox.item.close(); +Office.MessageCompose#closeAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close-async.yaml + + + // This snippet closes the current message being composed and discards any + unsaved changes when the optional property, discardItem, is set to true. + + // The API call works on a new message being composed, a reply, or an + existing draft. + + // When discardItem is set to false or isn't defined on a new message with + unsaved changes, the user is prompted to save a draft, discard the changes, + or cancel the close operation. + + Office.context.mailbox.item.closeAsync( + { discardItem: true }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + }); +Office.MessageCompose#conversationId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml + + + console.log(`Conversation ID: + ${Office.context.mailbox.item.conversationId}`); +Office.MessageCompose#delayDeliveryTime:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/delay-message-delivery.yaml + + + function setDeliveryDate(minutes) { + // This snippet sets the delivery date and time of a message. + const currentTime = new Date().getTime(); + const milliseconds = totalDelay * 60000; + const timeDelay = new Date(currentTime + milliseconds); + Office.context.mailbox.item.delayDeliveryTime.setAsync(timeDelay, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + if (minutes === 1440) { + console.log(`Delayed delivery by an additional one day.`); + } else { + console.log(`Delayed delivery by an additional ${minutes} minutes.`); + } + }); + } +Office.MessageCompose#disableClientSignatureAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Disable the client signature. + + Office.context.mailbox.item.disableClientSignatureAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("disableClientSignatureAsync succeeded"); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#from:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml + + + Office.context.mailbox.item.from.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgFrom = asyncResult.value; + console.log("Message from: " + msgFrom.displayName + " (" + msgFrom.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#getAttachmentContentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + + + // Gets the attachments of the current message or appointment in compose + mode. The getAttachmentsAsync call can only be used in compose mode. + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + if (result.value.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + for (let i = 0; i < result.value.length; i++) { + // Log the attachment type and its contents to the console. + Office.context.mailbox.item.getAttachmentContentAsync(result.value[i].id, handleAttachmentsCallback); + } + }); +Office.MessageCompose#getAttachmentsAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.getAttachmentsAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + if (result.value.length > 0) { + for (let i = 0; i < result.value.length; i++) { + const attachment = result.value[i]; + let attachmentType; + switch (attachment.attachmentType) { + case Office.MailboxEnums.AttachmentType.Cloud: + attachmentType = "Attachment is stored in a cloud location"; + break; + case Office.MailboxEnums.AttachmentType.File: + attachmentType = "Attachment is a file"; + break; + case Office.MailboxEnums.AttachmentType.Item: + attachmentType = "Attachment is an Exchange item"; + break; + } + console.log( + "ID: " + + attachment.id + + "\n" + + "Type: " + + attachmentType + + "\n" + + "Name: " + + attachment.name + + "\n" + + "Size: " + + attachment.size + + "\n" + + "isInline: " + + attachment.isInline + ); + } + } else { + console.log("No attachments on this message."); + } + }); +Office.MessageCompose#getComposeTypeAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Get the compose type of the current message. + + Office.context.mailbox.item.getComposeTypeAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log( + "getComposeTypeAsync succeeded with composeType: " + + asyncResult.value.composeType + + " and coercionType: " + + asyncResult.value.coercionType + ); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#getConversationIndexAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-index.yaml + + + // This snippet returns the Base64-encoded position of the current message + in a conversation thread (PR_CONVERSATION_INDEX). + + // The API call is supported on a message being composed and isn't supported + on read items or appointments. + + Office.context.mailbox.item.getConversationIndexAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.log(result.error.message); + return; + } + + const conversationIndex = result.value; + if (conversationIndex) { + console.log("Position in the conversation thread: " + conversationIndex); + } else { + console.log("The current message doesn't belong to a conversation thread."); + } + }); +Office.MessageCompose#getItemClassAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-async.yaml + + + // This snippet returns the Exchange Web Services item class property + (PR_MESSAGE_CLASS) of the current message. + + // The API call is only supported on a message being composed. + + Office.context.mailbox.item.getItemClassAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + + console.log("Item class of the current message: " + asyncResult.value); + }); +Office.MessageCompose#getItemIdAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/item-id-compose.yaml + + + Office.context.mailbox.item.getItemIdAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`getItemIdAsync failed with message: ${result.error.message}`); + return; + } + + console.log(result.value); + }); +Office.MessageCompose#getSelectedDataAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-selected-data.yaml + + + Office.context.mailbox.item.getSelectedDataAsync(Office.CoercionType.Text, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const text = asyncResult.value.data; + const prop = asyncResult.value.sourceProperty; + console.log("Selected text in " + prop + ": " + text); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#getSharedPropertiesAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + + + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); +Office.MessageCompose#inReplyTo:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-in-reply-to.yaml + + + // This snippet gets the ID of the message being replied to by the current + message (PR_IN_REPLY_TO_ID). + + // The API call is supported on messages being composed and isn't supported + on read items. + + const inReplyTo = Office.context.mailbox.item.inReplyTo; + + if (inReplyTo) { + console.log("ID of the message being replied to: " + inReplyTo); + } else { + console.log("No InReplyTo property available for this message"); + } +Office.MessageCompose#internetHeaders:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml + + + Office.context.mailbox.item.internetHeaders.getAsync( + ["preferred-fruit", "preferred-vegetable", "best-vegetable", "nonexistent-header"], + function (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected headers: " + JSON.stringify(asyncResult.value)); + } else { + console.log("Error getting selected headers: " + JSON.stringify(asyncResult.error)); + } + } + ); +Office.MessageCompose#isClientSignatureEnabledAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml + + + // Check if the client signature is currently enabled. + + Office.context.mailbox.item.isClientSignatureEnabledAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("isClientSignatureEnabledAsync succeeded with result: " + asyncResult.value); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#itemType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.MessageCompose#loadCustomPropertiesAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + Office.context.mailbox.item.loadCustomPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`loadCustomPropertiesAsync failed with message ${result.error.message}`); + return; + } + + customProps = result.value; + console.log("Loaded the CustomProperties object."); + }); +Office.MessageCompose#notificationMessages:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a progress indicator to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a persistent information notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Replaces a notification message of a given key with another message. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Removes a notification message from the current mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.removeAsync(id, + handleResult); +Office.MessageCompose#removeAttachmentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml + + + Office.context.mailbox.item.removeAttachmentAsync( + (document.getElementById("attachmentId") as HTMLInputElement).value, + (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(result.error.message); + return; + } + + console.log(`Attachment removed successfully.`); + } + ); +Office.MessageCompose#sendAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/send-async.yaml + + + // This snippet sends the current message or appointment being composed. + + Office.context.mailbox.item.sendAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Action failed with error: " + asyncResult.error.message); + return; + } + }); +Office.MessageCompose#sensitivityLabel:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + + + // This snippet gets the current mail item's sensitivity label. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.mailbox.item.sensitivityLabel.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.MessageCompose#seriesId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml + + + const seriesId = Office.context.mailbox.item.seriesId; + + + if (seriesId === undefined) { + console.log("This is a message that's not a meeting request."); + } else if (seriesId === null) { + console.log("This is a single appointment, a parent series, or a meeting request for a series or single meeting."); + } else { + console.log("This is an instance belonging to series with ID " + seriesId); + } +Office.MessageCompose#sessionData:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.getAllAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get all sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.MessageCompose#setSelectedDataAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/set-selected-data.yaml + + + Office.context.mailbox.item.setSelectedDataAsync("Replaced", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Selected text has been updated successfully."); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageCompose#subject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + + + Office.context.mailbox.item.subject.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Subject: ${result.value}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml + + + let subject = "Hello World!"; + + Office.context.mailbox.item.subject.setAsync(subject, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set subject to ${subject}`); + }); +Office.MessageCompose#to:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + + + Office.context.mailbox.item.to.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgTo = asyncResult.value; + console.log("Message being sent to:"); + for (let i = 0; i < msgTo.length; i++) { + console.log(msgTo[i].displayName + " (" + msgTo[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + + + const email = (document.getElementById("emailTo") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.to.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting To field."); + } else { + console.error(asyncResult.error); + } + }); +Office.MessageRead:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml + + + const item = Office.context.mailbox.item; + + + if (item.attachments.length > 0) { + for (let i = 0; i < item.attachments.length; i++) { + const attachment = item.attachments[i]; + console.log(`${i+1}. Name: ${attachment.name}`); + console.log(`ID: ${attachment.id}`); + console.log(`Type: ${attachment.attachmentType}`); + console.log(`Inline content: ${attachment.isInline}`); + console.log(`Size: ${attachment.size}`); + } + } else { + console.log("This mail item doesn't contain any attachments."); + } +Office.MessageRead#attachments:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml + + + const item = Office.context.mailbox.item; + + + if (item.attachments.length > 0) { + for (let i = 0; i < item.attachments.length; i++) { + const attachment = item.attachments[i]; + console.log(`${i+1}. Name: ${attachment.name}`); + console.log(`ID: ${attachment.id}`); + console.log(`Type: ${attachment.attachmentType}`); + console.log(`Inline content: ${attachment.isInline}`); + console.log(`Size: ${attachment.size}`); + } + } else { + console.log("This mail item doesn't contain any attachments."); + } +Office.MessageRead#categories:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + console.log("Categories assigned to this item:"); + console.log(JSON.stringify(categories)); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + // Note: In order for you to successfully add a category, + + // it must be in the mailbox categories master list. + + + Office.context.mailbox.masterCategories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const masterCategories = asyncResult.value; + if (masterCategories && masterCategories.length > 0) { + // Grab the first category from the master list. + const categoryToAdd = [masterCategories[0].displayName]; + Office.context.mailbox.item.categories.addAsync(categoryToAdd, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully assigned category '${categoryToAdd}' to item.`); + } else { + console.log("categories.addAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories in the master list on this mailbox. You can add categories using Office.context.mailbox.masterCategories.addAsync."); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml + + + Office.context.mailbox.item.categories.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const categories = asyncResult.value; + if (categories && categories.length > 0) { + // Grab the first category assigned to this item. + const categoryToRemove = [categories[0].displayName]; + Office.context.mailbox.item.categories.removeAsync(categoryToRemove, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(`Successfully unassigned category '${categoryToRemove}' from this item.`); + } else { + console.log("categories.removeAsync call failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("There are no categories assigned to this item."); + } + } else { + console.error(asyncResult.error); + } + }); +Office.MessageRead#cc:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml + + + const msgCc = Office.context.mailbox.item.cc; + + console.log("Message copied to:"); + + for (let i = 0; i < msgCc.length; i++) { + console.log(msgCc[i].displayName + " (" + msgCc[i].emailAddress + ")"); + } +Office.MessageRead#conversationId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml + + + console.log(`Conversation ID: + ${Office.context.mailbox.item.conversationId}`); +Office.MessageRead#dateTimeCreated:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml + + + console.log(`Creation date and time: + ${Office.context.mailbox.item.dateTimeCreated}`); +Office.MessageRead#dateTimeModified:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml + + + console.log(`Date and time item last modified: + ${Office.context.mailbox.item.dateTimeModified}`); +Office.MessageRead#display:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml + + + // This snippet temporarily sets the content displayed in the body of a + message in read mode. + + // The set content will remain visible until the user switches to a + different message in the Reading Pane or closes the window of the current + message. + + const bodyText = (document.getElementById("body-text-field") as + HTMLInputElement).value; + + Office.context.mailbox.item.display.body.setAsync(bodyText, (asyncResult) => + { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Action failed with error: ${asyncResult.error.message}`); + return; + } + + console.log("Temporarily set the content displayed in the body."); + }); +Office.MessageRead#displayReplyAllForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyAllForm("This is a reply ALL with + some bold text."); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // Create the reply with attachments. + + Office.context.mailbox.item.displayReplyAllForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + }); +Office.MessageRead#displayReplyAllFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyAllFormAsync("This is a reply ALL + with some bold text.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyAllFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created a reply-all form with attachments."); + } + ); +Office.MessageRead#displayReplyForm:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyForm("This is a reply with some + text in italics."); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // Create the reply with attachments. + + Office.context.mailbox.item.displayReplyForm({ + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment], + callback: (result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + console.log("Created a reply with attachments."); + } + }); +Office.MessageRead#displayReplyFormAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml + + + Office.context.mailbox.item.displayReplyFormAsync("This is a reply with + some text in italics.", function( + asyncResult + ) { + console.log(JSON.stringify(asyncResult)); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMTM0A1t6AAAF3klEQVR4Xt2aMcolRRSFdQUuwSW4AAMzU8ENzAIMDA1NzHUBgqmZkbG4ADGVQRgGZBBElAERRPg9eC+PQ73qc6u66lZ3v48bzH+7uqr6VN/T1f3mjafT8Pr7b37+8G3En99+5akTcAqB/n7+48uP3vvp3TdvgT//+uE7P3woBwv07+s/Xn32jKXhwKF/Xr3wpgdxpEC/ffnp8/ffKkQpAg3QDDr6Ocs5RiCzm0ILEQca02qB7u2mPQ4xpnUCabtBWDWFdbfYmBYJ1HLZN6PBP3794uOiAcdKY0oXKLQbFE71jkBS33FrjClRoNBuXjx7J/QUNNCdZBtTikAtdtO1+JBA34Z5xjRfIG03I/YBTYVMScY0U6DQbsbXGdevF2C6Mc0RKLQbHEUbbz0MZNKPuYnGNCpQaDdY0iQTDR9zU4xpSCB9t+PQ719/7k3T0P49bkw7BQrtZnBajTS+uIwYU7dA4ZzynrhMWF/3sc+YOgQK7WaiNQpCh9bRu36tAmm7wT2MovOmaUAaPY3G6DKmWCBtNzaYN80EJjIuDUejMSmBUC/abnCrL3Di8IEwErhAvUGrCxRa4C+ffLDAicMVmhW42K2VLgUK67zlFXwcqL9GmltseUXlDirOvMXIbqKdHc/vieGTIJoE6rL93djNWwy9OHwqRCyQqM+J6LpeFj4bIhZoTWVdWCCLBbvkY93HwqdCdJg0AheQ/XRf9mivhk+C6BMIscawUdR5m0MRPjzRLZAFZMo2pnBHlhE+NhELJGa5YNO42Jh8VCIWCBnMEu8WRf4WC147sAxYjGLcjPDxiCaBDMxS+MKCF1cUdXbF+UhEh0CGqDjksz9CZ++2fRiiWyCgKw532QJjEhMYCR+A2COQoStuwcYyw5i8a2K/QIZ+Ei/YWM41Ju+UGBUI6Bses4eIqf6Nzkc+43N4j8QEgQxdcZApe2OJdRp/R/G+iGkCGbriFmws9TqF4b0QkwUC4SNmwcYSu419xuTnE/MFMrCSRT9FZG8s9xmTn0xkCQSKfu4Di5y9sew1Jj+NOFIgC1hG9q+y7b+s+QnE8QJZYJ0n/g+rKvoBYuFNibMIZJG9sYQx6Y8n3o44l0AILDKWOtW/xf/g8RbE6QSygGVkbyyrxuTHiJMKZLHgjbcY0bPEqQWySN1YFmN5lriAQBZJxlSM4lniMgIhMjaWxRCeJa4kkAWcdaIxFZ17lrieQBazNpZFt54lriqQBXZ9g8ZUdOhZ4toCIWxj6UP2U/TmWSJRoDU/9V1YIIDdcONr9L64dond2P19T8QjmDSDdUYhTJHpcR7z90Am/bVBx6NtFLcIv+pXAzfgo71qaFAmWx9linjYl9UWIJN4zD3454527ncD+DP7g5nBgyI8S5xCIIMHzbCbKjwowrPESQXyVD48aHXcWCDc7dm/Wxk8qKcymfZN2gJ+mfqDDODhPJUDLmTrAeotiFaBLJI2IwYP5KnZ2IaeByrC2xEVgdCFeCfIqzgexVNT0T9Ab30VqAgEwneCjIrj/j01CVFTFuKrQF0gQ/wCaQHJJ1Yc9+ypYcKawgXqrwJKIEPfmRMrjrv11BhTZh4LZGAdhDFNqTju0FN70TW1ZTdVWgUCoTFh1JGK46481U9YU70fITsEMrQxjVQc9+OpTnRNhXZTpVsgI5zKjorjHjzVjK6pkWXbKZCBm1kYU2/F8bmeakDXVJfdVBkSCGB+wpi6lo5P9FSEvpF77abKqECGNqbGiuNTPLWNrikc2mE3VeYIZOj1DCuOG3uqhq6pEbupMlMgA7PfMiY9e27pqTvEGozbTZX5AgFtTFsVx208ReiammI3VVIEMrQxYbWLS+KjnvofXVMT7aZKokCGKIqi4viQp3pOTyJdIAO3wJYx3SqOk/hT1FSS3VRZJBDQxlQUkaipPLupsk4gQxuTjmy7qbJaIEM4SzXW2E2VYwQyhDHdYqXdVDlSIKCNabHdVDlYIOPemA6xmyqnEMgwYzrQbio8Pf0HxndUxitiwgUAAAAASUVORK5CYII=", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created reply with attachments."); + } + ); +Office.MessageRead#end:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-end-read.yaml + + + const time = Office.context.mailbox.item.end; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment ends (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.MessageRead#from:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml + + + const msgFrom = Office.context.mailbox.item.from; + + console.log("Message received from: " + msgFrom.displayName + " (" + + msgFrom.emailAddress + ")"); +Office.MessageRead#getAllInternetHeadersAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml + + + Office.context.mailbox.item.getAllInternetHeadersAsync(function + (asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Internet headers received successfully"); + if (asyncResult.value.match(/preferred-fruit:.*/gim)) { + console.log("Sender's preferred fruit: " + asyncResult.value.match(/preferred-fruit:.*/gim)[0].slice(17)); + } else { + console.log("Didn't receive header with sender's preferred fruit"); + } + if (asyncResult.value.match(/preferred-vegetable:.*/gim)) { + console.log( + "Sender's preferred vegetable: " + asyncResult.value.match(/preferred-vegetable:.*/gim)[0].slice(21) + ); + } else { + console.log("Didn't receive header with sender's preferred vegetable"); + } + } else { + console.log("Error getting internet headers: " + JSON.stringify(asyncResult.error)); + } + }); +Office.MessageRead#getAsFileAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-eml-format.yaml + + + Office.context.mailbox.item.getAsFileAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(`Error encountered during processing: ${asyncResult.error.message}`); + return; + } + + console.log(asyncResult.value); + }); +Office.MessageRead#getAttachmentContentAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml + + + // Gets the attachments of the current message or appointment in read mode. + The item.attachments call can only be used in read mode. + + const item = Office.context.mailbox.item; + + const attachments = item.attachments; + + if (attachments.length <= 0) { + console.log("Mail item has no attachments."); + return; + } + + + for (let i = 0; i < attachments.length; i++) { + // Log the attachment type and its contents to the console. + item.getAttachmentContentAsync(attachments[i].id, handleAttachmentsCallback); + } +Office.MessageRead#getRegExMatches:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + // This API only works when you click on the highlighted word "ScriptLab". + + console.log(Office.context.mailbox.item.getRegExMatches()); +Office.MessageRead#getRegExMatchesByName:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + // This API only works when you click on the highlighted word "ScriptLab". + + console.log(Office.context.mailbox.item.getRegExMatchesByName("sampleRegexName")); +Office.MessageRead#getSelectedRegExMatches:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml + + + const matches = Office.context.mailbox.item.getSelectedRegExMatches(); + + if (matches) { + console.log(matches); + } else { + console.error("Open add-in by clicking on a highlighted regex match, for this API to return something useful."); + } +Office.MessageRead#getSharedPropertiesAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + + + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); +Office.MessageRead#internetMessageId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml + + + console.log(`Internet message ID: + ${Office.context.mailbox.item.internetMessageId}`); +Office.MessageRead#itemClass:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-read.yaml + + + console.log(`Item class: ${Office.context.mailbox.item.itemClass}`); +Office.MessageRead#itemType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml + + + const itemType = Office.context.mailbox.item.itemType; + + switch (itemType) { + case Office.MailboxEnums.ItemType.Appointment: + console.log(`Current item is an ${itemType}.`); + break; + case Office.MailboxEnums.ItemType.Message: + console.log(`Current item is a ${itemType}. A message could be an email, meeting request, meeting response, or meeting cancellation.`); + break; + } +Office.MessageRead#loadCustomPropertiesAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml + + + Office.context.mailbox.item.loadCustomPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error(`loadCustomPropertiesAsync failed with message ${result.error.message}`); + return; + } + + customProps = result.value; + console.log("Loaded the CustomProperties object."); + }); +Office.MessageRead#location:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-location-read.yaml + + + console.log(`Appointment location: + ${Office.context.mailbox.item.location}`); +Office.MessageRead#normalizedSubject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml + + + console.log(`Normalized subject: + ${Office.context.mailbox.item.normalizedSubject}`); +Office.MessageRead#notificationMessages:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a progress indicator to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a persistent information notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Replaces a notification message of a given key with another message. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Removes a notification message from the current mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.removeAsync(id, + handleResult); +Office.MessageRead#recurrence:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-recurrence-read.yaml + + + const recurrence = Office.context.mailbox.item.recurrence; + + + if (recurrence === undefined) { + console.log("This item is a message but not a meeting request."); + } else if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(JSON.stringify(recurrence)); + } +Office.MessageRead#sender:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml + + + const msgSender = Office.context.mailbox.item.sender; + + console.log("Sender: " + msgSender.displayName + " (" + + msgSender.emailAddress + ")"); +Office.MessageRead#seriesId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml + + + const seriesId = Office.context.mailbox.item.seriesId; + + + if (seriesId === undefined) { + console.log("This is a message that's not a meeting request."); + } else if (seriesId === null) { + console.log("This is a single appointment, a parent series, or a meeting request for a series or single meeting."); + } else { + console.log("This is an instance belonging to series with ID " + seriesId); + } +Office.MessageRead#start:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml + + + const time = Office.context.mailbox.item.start; + + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + + console.log(`Appointment starts (local): ${localTime.month + + 1}/${localTime.date}/${localTime.year}, + ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); +Office.MessageRead#subject:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-subject-read.yaml + + + console.log(`Subject: ${Office.context.mailbox.item.subject}`); +Office.MessageRead#to:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml + + + const msgTo = Office.context.mailbox.item.to; + + const distributionLists = []; + + const externalRecipients = []; + + const internalRecipients = []; + + const otherRecipients = []; + + for (let i = 0; i < msgTo.length; i++) { + switch (msgTo[i].recipientType) { + case Office.MailboxEnums.RecipientType.DistributionList: + distributionLists.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.ExternalUser: + externalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.User: + internalRecipients.push(msgTo[i]); + break; + case Office.MailboxEnums.RecipientType.Other: + otherRecipients.push(msgTo[i]); + } + } + + + if (distributionLists.length > 0) { + console.log("Distribution Lists:"); + distributionLists.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (externalRecipients.length > 0) { + console.log("External Recipients:"); + externalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (internalRecipients.length > 0) { + console.log("Internal Recipients:"); + internalRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } + + + if (otherRecipients.length > 0) { + console.log("Other Recipients:"); + otherRecipients.forEach((recipient) => console.log(`${recipient.displayName}, ${recipient.emailAddress}`)); + } +Office.NotificationMessageAction:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational message with actions to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + + const itemId = Office.context.mailbox.item.itemId; + + const details = { + type: Office.MailboxEnums.ItemNotificationMessageType.InsightMessage, + message: "This is an insight notification with id = " + id, + icon: "PG.Icon.16", + actions: [ + { + actionText: "Open insight", + actionType: Office.MailboxEnums.ActionType.ShowTaskPane, + // Identify whether the current mail item is in read or compose mode to set the appropriate commandId value. + commandId: (itemId == undefined ? "PG.HelpCommand.Compose" : "PG.HelpCommand.Read"), + contextData: { a: "aValue", b: "bValue" } + } + ] + }; + + + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); +Office.NotificationMessageDetails:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); +Office.NotificationMessages#addAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a progress indicator to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ProgressIndicator, + message: "Progress indicator with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an informational notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Non-persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: false + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds a persistent information notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Persistent informational notification message with id = " + id, + icon: "PG.Icon.16", + persistent: true + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Adds an error notification to the mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + const details = + { + type: Office.MailboxEnums.ItemNotificationMessageType.ErrorMessage, + message: "Error notification message with id = " + id + }; + Office.context.mailbox.item.notificationMessages.addAsync(id, details, + handleResult); +Office.NotificationMessages#getAllAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Gets all the notification messages and their keys for the current mail + item. + + Office.context.mailbox.item.notificationMessages.getAllAsync((asyncResult) + => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + console.log(asyncResult.value); + }); +Office.NotificationMessages#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Removes a notification message from the current mail item. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.removeAsync(id, + handleResult); +Office.NotificationMessages#replaceAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml + + + // Replaces a notification message of a given key with another message. + + const id = (document.getElementById("notificationId") as + HTMLInputElement).value; + + Office.context.mailbox.item.notificationMessages.replaceAsync( + id, + { + type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage, + message: "Notification message with id = " + id + " has been replaced with an informational message.", + icon: "icon2", + persistent: false + }, + handleResult); +Office.Organizer#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml + + + Office.context.mailbox.item.organizer.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOrganizer = asyncResult.value; + console.log("Organizer: " + apptOrganizer.displayName + " (" + apptOrganizer.emailAddress + ")"); + } else { + console.error(asyncResult.error); + } + }); +Office.Recipients#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + + + Office.context.mailbox.item.bcc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgBcc = asyncResult.value; + console.log("Message being blind-copied to:"); + for (let i = 0; i < msgBcc.length; i++) { + console.log(msgBcc[i].displayName + " (" + msgBcc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + + + Office.context.mailbox.item.cc.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgCc = asyncResult.value; + console.log("Message being copied to:"); + for (let i = 0; i < msgCc.length; i++) { + console.log(msgCc[i].displayName + " (" + msgCc[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + + + Office.context.mailbox.item.optionalAttendees.getAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptOptionalAttendees = asyncResult.value; + for (let i = 0; i < apptOptionalAttendees.length; i++) { + console.log( + "Optional attendees: " + + apptOptionalAttendees[i].displayName + + " (" + + apptOptionalAttendees[i].emailAddress + + ") - response: " + + apptOptionalAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + + + Office.context.mailbox.item.requiredAttendees.getAsync(function(asyncResult) + { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const apptRequiredAttendees = asyncResult.value; + for (let i = 0; i < apptRequiredAttendees.length; i++) { + console.log( + "Required attendees: " + + apptRequiredAttendees[i].displayName + + " (" + + apptRequiredAttendees[i].emailAddress + + ") - response: " + + apptRequiredAttendees[i].appointmentResponse + ); + } + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + + + Office.context.mailbox.item.to.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const msgTo = asyncResult.value; + console.log("Message being sent to:"); + for (let i = 0; i < msgTo.length; i++) { + console.log(msgTo[i].displayName + " (" + msgTo[i].emailAddress + ")"); + } + } else { + console.error(asyncResult.error); + } + }); +Office.Recipients#setAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml + + + const email = (document.getElementById("emailBcc") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.bcc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Bcc field."); + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml + + + const email = (document.getElementById("emailCc") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.cc.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting Cc field."); + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml + + + const email = (document.getElementById("emailOptional") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.optionalAttendees.setAsync(emailArray, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting optional attendees field."); + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml + + + const email = (document.getElementById("emailRequired") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.requiredAttendees.setAsync(emailArray, + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting required attendees field."); + } else { + console.error(asyncResult.error); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml + + + const email = (document.getElementById("emailTo") as + HTMLInputElement).value; + + const emailArray = [email]; + + Office.context.mailbox.item.to.setAsync(emailArray, function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Succeeded in setting To field."); + } else { + console.error(asyncResult.error); + } + }); +Office.Recurrence#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + Office.context.mailbox.item.recurrence.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const recurrence = asyncResult.value; + if (recurrence === null) { + console.log("This is a single appointment."); + } else { + console.log(`Recurrence pattern: ${JSON.stringify(recurrence)}`); + } + } else { + console.error(asyncResult.error); + } + }); +Office.Recurrence#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml + + + // Important: Can only set the recurrence pattern of an appointment series. + + + const currentDate = new Date(); + + let seriesTimeObject: Office.SeriesTime; + + // Set series start date to tomorrow. + + seriesTimeObject.setStartDate(currentDate.getFullYear(), + currentDate.getMonth(), currentDate.getDay() + 1); + + // Set series end date to one year from now. + + seriesTimeObject.setEndDate(currentDate.getFullYear() + 1, + currentDate.getMonth() + 1, currentDate.getDay()); + + // Set start time to 1:30 PM. + + seriesTimeObject.setStartTime(13, 30); + + // Set duration to 30 minutes. + + seriesTimeObject.setDuration(30); + + + const pattern: Office.Recurrence = { + seriesTime: seriesTimeObject, + recurrenceType: Office.MailboxEnums.RecurrenceType.Yearly, + recurrenceProperties: { + interval: 1, + dayOfWeek: Office.MailboxEnums.Days.Tue, + weekNumber: Office.MailboxEnums.WeekNumber.Second, + month: Office.MailboxEnums.Month.Sep + }, + recurrenceTimeZone: { name: Office.MailboxEnums.RecurrenceTimeZone.PacificStandardTime } + }; + + + Office.context.mailbox.item.recurrence.setAsync(pattern, (asyncResult) => { + if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Failed to set recurrence. Error: ${asyncResult.error.message}`); + return; + } + console.log(`Succeeded in setting recurrence pattern ${JSON.stringify(pattern)}`); + }); +Office.ReplyFormAttachment:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created reply with attachments."); + } + ); +Office.ReplyFormData:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml + + + // Define attachments. + + const base64Attachment = { + base64file: + "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", + inLine: true, + name: "script_lab.png", + type: Office.MailboxEnums.AttachmentType.Base64 + }; + + const fileAttachment = { + inLine: true, + name: "dog.jpg", + type: Office.MailboxEnums.AttachmentType.File, + url: "https://i.imgur.com/9S36xvA.jpg" + }; + + const itemAttachment = { + itemId: Office.context.mailbox.item.itemId, + name: "test_email.msg", + type: Office.MailboxEnums.AttachmentType.Item + }; + + + // The async version was introduced in requirement set 1.9. + + // It provides a callback when the new appointment form has been created. + + Office.context.mailbox.item.displayReplyFormAsync( + { + htmlBody: + "This is a reply with an inline Base64-encoded attachment, an inline image, and an item attachment.

      ", + attachments: [base64Attachment, fileAttachment, itemAttachment] + }, + (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.error(`Action failed with message ${asyncResult.error.message}`); + return; + } + + console.log("Created reply with attachments."); + } + ); +Office.RoamingSettings#get:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml + + + const settingName = (document.getElementById("settingName") as + HTMLInputElement).value; + + const settingValue = Office.context.roamingSettings.get(settingName); + + (document.getElementById("settingValue") as HTMLInputElement).value = + settingValue; + + console.log(`The value of setting "${settingName}" is "${settingValue}".`); +Office.RoamingSettings#remove:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml + + + // Remove the specified setting from the mailbox. + + const settingName = (document.getElementById("settingName") as + HTMLInputElement).value; + + Office.context.roamingSettings.remove(settingName); + + console.log(`The "${settingName}" setting has been removed.`); +Office.RoamingSettings#saveAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml + + + // Save settings in the mailbox to make it available in future sessions. + + Office.context.roamingSettings.saveAsync(function(result) { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + } else { + console.log(`Settings saved with status: ${result.status}`); + } + }); +Office.RoamingSettings#set:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml + + + const settingName = (document.getElementById("settingName") as + HTMLInputElement).value; + + const settingValue = (document.getElementById("settingValue") as + HTMLInputElement).value; + + Office.context.roamingSettings.set(settingName, settingValue); + + console.log(`Setting "${settingName}" set to value "${settingValue}".`); +Office.SelectedItemDetails:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-message-properties.yaml + + + // Retrieves the selected messages' properties and logs them to the console. + + Office.context.mailbox.getSelectedItemsAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log(asyncResult.error.message); + return; + } + + asyncResult.value.forEach((message) => { + console.log(`Item ID: ${message.itemId}`); + console.log(`Conversation ID: ${message.conversationId}`); + console.log(`Internet message ID: ${message.internetMessageId}`); + console.log(`Subject: ${message.subject}`); + console.log(`Item type: ${message.itemType}`); + console.log(`Item mode: ${message.itemMode}`); + console.log(`Has attachment: ${message.hasAttachment}`); + }); + }); +Office.Sensitivity#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + + + Office.context.mailbox.item.sensitivity.getAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("Sensitivity: " + asyncResult.value); + } else { + console.log("Failed to get sensitivity: " + JSON.stringify(asyncResult.error)); + } + }); +Office.Sensitivity#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml + + + Office.context.mailbox.item.sensitivity.setAsync( + Office.MailboxEnums.AppointmentSensitivityType.Private, + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Failed) { + console.log("Failed to set appointment sensitivity: " + JSON.stringify(asyncResult.error)); + } else { + console.log("Successfully set appointment sensitivity."); + } + } + ); +Office.SensitivityLabel#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + + + // This snippet gets the current mail item's sensitivity label. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.mailbox.item.sensitivityLabel.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.SensitivityLabel#setAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml + + + // This snippet sets the sensitivity label on the current mail item. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.sensitivityLabelsCatalog.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const catalog = asyncResult.value; + if (catalog.length > 0) { + var id = catalog[0].id; + Office.context.mailbox.item.sensitivityLabel.setAsync(id, (asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.status); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } + else { + console.log("Catalog list is empty"); + } + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.SensitivityLabelsCatalog#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml + + + // This snippet gets all available sensitivity labels from the catalog. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded && asyncResult.value == true) { + Office.context.sensitivityLabelsCatalog.getAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + const catalog = asyncResult.value; + console.log("Sensitivity Labels Catalog:"); + console.log(JSON.stringify(catalog)); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.SensitivityLabelsCatalog#getIsEnabledAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml + + + // This snippet determines if the sensitivity labels catalog is enabled on + the current mailbox. + + Office.context.sensitivityLabelsCatalog.getIsEnabledAsync((asyncResult) => { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log(asyncResult.value); + } else { + console.log("Action failed with error: " + asyncResult.error.message); + } + }); +Office.SessionData#clearAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.clearAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.clearAsync succeeded"); + } else { + console.log("Failed to clear sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.SessionData#getAllAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.getAllAsync(function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get all sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.SessionData#getAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.getAsync( + "Date", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("The sessionData value is " + JSON.stringify(asyncResult.value)); + } else { + console.log("Failed to get sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.SessionData#removeAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.removeAsync( + "Date", + function callback(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.removeAsync succeeded"); + } else { + console.log("Failed to remove sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + } + ); +Office.SessionData#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml + + + Office.context.mailbox.item.sessionData.setAsync( + "Date", + "7/24/2020", + function(asyncResult) { + if (asyncResult.status === Office.AsyncResultStatus.Succeeded) { + console.log("sessionData.setAsync succeeded"); + } else { + console.log("Failed to set sessionData. Error: " + JSON.stringify(asyncResult.error)); + } + }); +Office.SharedProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml + + + Office.context.mailbox.item.getSharedPropertiesAsync((result) => { + if (result.status === Office.AsyncResultStatus.Failed) { + console.error("The current folder or mailbox isn't shared."); + return; + } + const sharedProperties = result.value; + console.log(`Owner: ${sharedProperties.owner}`); + console.log(`Permissions: ${sharedProperties.delegatePermissions}`); + console.log(`Target mailbox: ${sharedProperties.targetMailbox}`); + }); +Office.Time#getAsync:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + + + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + + const time = result.value; + const localTime = Office.context.mailbox.convertToLocalClientTime(time); + console.log(`Appointment starts (local): ${localTime.month + 1}/${localTime.date}/${localTime.year}, ${localTime.hours}:${localTime.minutes}:${localTime.seconds}`); + }); +Office.Time#setAsync:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml + + + const start = new Date(); // Represents current date and time. + + start.setDate(start.getDate() + 2); // Add 2 days to current date. + + Office.context.mailbox.item.start.setAsync(start, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Action failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set start date and time to ${start}`); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml + + + Office.context.mailbox.item.start.getAsync((result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Get start date failed with message ${result.error.message}`); + return; + } + + const end = result.value; // Set end to current start date and time. + end.setDate(end.getDate() + 1); // Set end as 1 day later than start date. + Office.context.mailbox.item.end.setAsync(end, (result) => { + if (result.status !== Office.AsyncResultStatus.Succeeded) { + console.error(`Set end date failed with message ${result.error.message}`); + return; + } + console.log(`Successfully set end date and time to ${end}`); + }); + }); +PowerPoint.AddSlideOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + const chosenMaster = (document.getElementById("master-id") as + HTMLInputElement).value; + + const chosenLayout = (document.getElementById("layout-id") as + HTMLInputElement).value; + + + await PowerPoint.run(async function(context) { + // Create a new slide using an existing master slide and layout. + const newSlideOptions: PowerPoint.AddSlideOptions = { + slideMasterId: chosenMaster, /* An ID from `Presentation.slideMasters`. */ + layoutId: chosenLayout /* An ID from `SlideMaster.layouts`. */ + }; + context.presentation.slides.add(newSlideOptions); + await context.sync(); + }); +PowerPoint.Binding:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function getShapeForBindingId(bindingId: string): + Promise { + // Gets shape associated with binding ID. + return PowerPoint.run(async (context) => { + const binding = context.presentation.bindings.getItem(bindingId); + const shape = binding.getShape(); + return shape; + }); + } +PowerPoint.Binding#getShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function getShapeForBindingId(bindingId: string): + Promise { + // Gets shape associated with binding ID. + return PowerPoint.run(async (context) => { + const binding = context.presentation.bindings.getItem(bindingId); + const shape = binding.getShape(); + return shape; + }); + } +PowerPoint.BindingCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Loads bindings. + + await PowerPoint.run(async (context) => { + const bindings = context.presentation.bindings; + bindings.load("items"); + await context.sync(); + + const bindingCount = bindings.items.length; + if (bindingCount === 0) { + console.log(`There are no bindings.`); + } else if (bindingCount === 1) { + console.log("There's 1 binding."); + } else { + console.log(`There are ${bindingCount} bindings.`); + } + + bindings.items.forEach((binding) => { + getShapeForBindingId(binding.id).then((shape) => { + if (shape) { + console.log(`Binding ID: ${binding.id} refers to shape ID ${shape.id}`); + } else { + console.log(`Binding ID: ${binding.id} doesn't refers to shape.`); + } + }); + }); + + populateBindingsDropdown(bindings.items); + }); +PowerPoint.BindingCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Inserts an image with binding. + + await PowerPoint.run(async (context) => { + const bindingId = (document.getElementById("temp-binding-id") as HTMLInputElement).value; + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const myShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle, { + top: 100, + left: 30, + width: 200, + height: 200 + }); + + myShape.fill.setImage(flowerImage); + context.presentation.bindings.add(myShape, PowerPoint.BindingType.shape, bindingId); + await context.sync(); + + const bindingsDropdown = document.getElementById("bindings-dropdown") as HTMLSelectElement; + + const option = new Option(`Binding ${bindingId}`, bindingId); + + // When a binding ID already exists, the binding is updated to refer to the new shape + // so select the existing item rather than add a new one. + const foundIndex = findDropdownItem(bindingsDropdown, option.text); + if (foundIndex < 0) { + bindingsDropdown.add(option); + bindingsDropdown.selectedIndex = bindingsDropdown.options.length - 1; + } else { + bindingsDropdown.selectedIndex = foundIndex; + } + }); +PowerPoint.BindingCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function getShapeForBindingId(bindingId: string): + Promise { + // Gets shape associated with binding ID. + return PowerPoint.run(async (context) => { + const binding = context.presentation.bindings.getItem(bindingId); + const shape = binding.getShape(); + return shape; + }); + } +PowerPoint.BindingType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Inserts an image with binding. + + await PowerPoint.run(async (context) => { + const bindingId = (document.getElementById("temp-binding-id") as HTMLInputElement).value; + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const myShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle, { + top: 100, + left: 30, + width: 200, + height: 200 + }); + + myShape.fill.setImage(flowerImage); + context.presentation.bindings.add(myShape, PowerPoint.BindingType.shape, bindingId); + await context.sync(); + + const bindingsDropdown = document.getElementById("bindings-dropdown") as HTMLSelectElement; + + const option = new Option(`Binding ${bindingId}`, bindingId); + + // When a binding ID already exists, the binding is updated to refer to the new shape + // so select the existing item rather than add a new one. + const foundIndex = findDropdownItem(bindingsDropdown, option.text); + if (foundIndex < 0) { + bindingsDropdown.add(option); + bindingsDropdown.selectedIndex = bindingsDropdown.options.length - 1; + } else { + bindingsDropdown.selectedIndex = foundIndex; + } + }); +PowerPoint.BorderProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.BorderProperties#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.BorderProperties#dashStyle:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.BorderProperties#weight:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.BulletFormat:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Gets navigational (complex) properties of the selected text range. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.load("font,paragraphFormat/bulletFormat,paragraphFormat/horizontalAlignment"); + await context.sync(); + + console.log("Font properties of selected text range:"); + console.log(`\tallCaps: ${textRange.font.allCaps}`); + console.log(`\tbold: ${textRange.font.bold}`); + console.log(`\tcolor: ${textRange.font.color}`); + console.log(`\tdoubleStrikethrough: ${textRange.font.doubleStrikethrough}`); + console.log(`\titalic: ${textRange.font.italic}`); + console.log(`\tname: ${textRange.font.name}`); + console.log(`\tsize: ${textRange.font.size}`); + console.log(`\tsmallCaps: ${textRange.font.smallCaps}`); + console.log(`\tstrikethrough: ${textRange.font.strikethrough}`); + console.log(`\tsubscript: ${textRange.font.subscript}`); + console.log(`\tsuperscript: ${textRange.font.superscript}`); + console.log(`\tunderline: ${textRange.font.underline}`); + + console.log("Paragraph format properties of selected text range:"); + console.log(`\tbulletFormat.visible: ${textRange.paragraphFormat.bulletFormat.visible}`); + console.log(`\thorizontalAlignment: ${textRange.paragraphFormat.horizontalAlignment}`); + }); +PowerPoint.ConnectorType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a line to the collection, while specifying its + + // start and end points. Then it names the shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + + // For a line, left and top are the coordinates of the start point, + // while height and width are the coordinates of the end point. + const line: PowerPoint.Shape = shapes.addLine(PowerPoint.ConnectorType.straight, { + left: 400, + top: 200, + height: 20, + width: 150, + }); + line.name = "StraightLine"; + + await context.sync(); + }); +PowerPoint.FillProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FillProperties#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#doubleStrikethrough:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#name:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#strikethrough:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#subscript:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.FontProperties#superscript:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.GeometricShapeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a hexagon shape to the collection, while specifying its + + // location and size. Then it names the shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const shapeOptions: PowerPoint.ShapeAddOptions = { + left: 100, + top: 100, + height: 150, + width: 150, + }; + const hexagon: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon, shapeOptions); + hexagon.name = "Hexagon"; + + await context.sync(); + }); +PowerPoint.Hyperlink:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml + + + // Gets the hyperlinks found in the first selected slide. + + await PowerPoint.run(async (context) => { + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + const hyperlinks: PowerPoint.HyperlinkCollection = slide.hyperlinks.load("address,screenTip"); + const hyperlinksCount = hyperlinks.getCount(); + await context.sync(); + + console.log(`${hyperlinksCount.value} hyperlinks found in first selected slide:`); + for (let link of hyperlinks.items) { + console.log(`Address: "${link.address}" (Screen tip: "${link.screenTip}")`); + } + }); +PowerPoint.HyperlinkCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml + + + // Gets the hyperlinks found in the first selected slide. + + await PowerPoint.run(async (context) => { + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + const hyperlinks: PowerPoint.HyperlinkCollection = slide.hyperlinks.load("address,screenTip"); + const hyperlinksCount = hyperlinks.getCount(); + await context.sync(); + + console.log(`${hyperlinksCount.value} hyperlinks found in first selected slide:`); + for (let link of hyperlinks.items) { + console.log(`Address: "${link.address}" (Screen tip: "${link.screenTip}")`); + } + }); +PowerPoint.InsertSlideFormatting:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml + + + await PowerPoint.run(async function(context) { + // Get the ID of the first selected slide. + const presentation: PowerPoint.Presentation = context.presentation; + const selected: PowerPoint.Slide = presentation.getSelectedSlides().getItemAt(0); + selected.load("id"); + await context.sync(); + + // Insert the other presentation after the selected slide. + const insertOptions: PowerPoint.InsertSlideOptions = { + formatting: PowerPoint.InsertSlideFormatting.useDestinationTheme, + targetSlideId: selected.id + }; + presentation.insertSlidesFromBase64(chosenFileBase64, insertOptions); + await context.sync(); + }); +PowerPoint.InsertSlideOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml + + + await PowerPoint.run(async function(context) { + // Get the ID of the first selected slide. + const presentation: PowerPoint.Presentation = context.presentation; + const selected: PowerPoint.Slide = presentation.getSelectedSlides().getItemAt(0); + selected.load("id"); + await context.sync(); + + // Insert the other presentation after the selected slide. + const insertOptions: PowerPoint.InsertSlideOptions = { + formatting: PowerPoint.InsertSlideFormatting.useDestinationTheme, + targetSlideId: selected.id + }; + presentation.insertSlidesFromBase64(chosenFileBase64, insertOptions); + await context.sync(); + }); +PowerPoint.ParagraphFormat:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Gets navigational (complex) properties of the selected text range. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.load("font,paragraphFormat/bulletFormat,paragraphFormat/horizontalAlignment"); + await context.sync(); + + console.log("Font properties of selected text range:"); + console.log(`\tallCaps: ${textRange.font.allCaps}`); + console.log(`\tbold: ${textRange.font.bold}`); + console.log(`\tcolor: ${textRange.font.color}`); + console.log(`\tdoubleStrikethrough: ${textRange.font.doubleStrikethrough}`); + console.log(`\titalic: ${textRange.font.italic}`); + console.log(`\tname: ${textRange.font.name}`); + console.log(`\tsize: ${textRange.font.size}`); + console.log(`\tsmallCaps: ${textRange.font.smallCaps}`); + console.log(`\tstrikethrough: ${textRange.font.strikethrough}`); + console.log(`\tsubscript: ${textRange.font.subscript}`); + console.log(`\tsuperscript: ${textRange.font.superscript}`); + console.log(`\tunderline: ${textRange.font.underline}`); + + console.log("Paragraph format properties of selected text range:"); + console.log(`\tbulletFormat.visible: ${textRange.paragraphFormat.bulletFormat.visible}`); + console.log(`\thorizontalAlignment: ${textRange.paragraphFormat.horizontalAlignment}`); + }); +PowerPoint.ParagraphHorizontalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the horizontal and vertical alignments of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying horizontal and vertical alignment. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + horizontalAlignment: PowerPoint.ParagraphHorizontalAlignment.justify, + verticalAlignment: PowerPoint.TextVerticalAlignment.middle + } + }); + await context.sync(); + }); +PowerPoint.Presentation:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml + + + await PowerPoint.run(async function(context) { + // Get the ID of the first selected slide. + const presentation: PowerPoint.Presentation = context.presentation; + const selected: PowerPoint.Slide = presentation.getSelectedSlides().getItemAt(0); + selected.load("id"); + await context.sync(); + + // Insert the other presentation after the selected slide. + const insertOptions: PowerPoint.InsertSlideOptions = { + formatting: PowerPoint.InsertSlideFormatting.useDestinationTheme, + targetSlideId: selected.id + }; + presentation.insertSlidesFromBase64(chosenFileBase64, insertOptions); + await context.sync(); + }); +PowerPoint.Presentation#getSelectedShapes:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Arranges the selected shapes in a line from left to right. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 0; + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Gets the shapes you selected on the slide and displays their IDs on the + task pane. + + await PowerPoint.run(async (context) => { + let finalTable = ""; + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + finalTable += "
      getSelectedShapes.getCount returned:" + shapeCount.value + "
      "; + finalTable += + "
      "; + shapes.load("items"); + await context.sync(); + shapes.items.map((shape, index) => { + finalTable += ""; + }); + finalTable += "
      IndexId
      " + index + "" + shape.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Saves which shapes are selected so that they can be reselected later. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + savedSlideSelection = []; + slides.items.map((slide) => { + savedSlideSelection.push(slide.id); + }); + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + shapes.items.map((shape) => { + savedShapeSelection.push(shape.id); + }); + }); +PowerPoint.Presentation#getSelectedSlides:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Gets the selected slides and displays their IDs on the task pane. + + await PowerPoint.run(async (context) => { + let finalTable = ""; + context.presentation.load("slides"); + await context.sync(); + const allSlidesList = {}; + const allSlidesCount = context.presentation.slides.getCount(); + context.presentation.slides.load("items"); + await context.sync(); + let allSlideItems: PowerPoint.Slide[] = context.presentation.slides.items; + allSlideItems.map((slide, index) => { + allSlidesList[slide.id] = `Slide ${index + 1}`; + }); + + const checkbox = document.getElementById("id-check-usenative") as HTMLInputElement; + if (checkbox && checkbox.checked) { + context.presentation.load("tags"); + } + + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + finalTable += "
      getSelectedSlides.getCount returned:" + slideCount.value + "
      "; + finalTable += + "
      "; + slides.items.map((slide, index) => { + finalTable += ""; + }); + finalTable += "
      IndexId
      " + index + " - " + allSlidesList[slide.id] + "" + slide.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = "" + outputSpan.innerHTML += finalTable; + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Saves which slides are currently selected so they can be reselected + later. + + await PowerPoint.run(async (context) => { + let finalTable = ""; + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + await context.sync(); + finalTable += "
      getSelectedSlides.getCount returned:" + slideCount.value + "
      "; + finalTable += + "
      "; + savedSlideSelection = []; + slides.load("items"); + await context.sync(); + slides.items.map((slide, index) => { + finalTable += ""; + savedSlideSelection.push(slide.id); + }); + finalTable += "
      IndexId
      " + index + "" + slide.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = "" + outputSpan.innerHTML += finalTable; + }); +PowerPoint.Presentation#getSelectedTextRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Gets the selected text range and prints data about the range on the task + pane. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + try { + await context.sync(); + } catch (error) { + console.warn("You must select only one range of text for this action to work."); + return; + } + textRange.load("text"); + textRange.load("start"); + textRange.load("length"); + await context.sync(); + let txtHtml = textRange.text; + txtHtml = txtHtml.replace(/\n/g, "
      "); + txtHtml = txtHtml.replace(/\r/g, "
      "); + txtHtml = txtHtml.replace(/\v/g, "
      "); + let txtExplained = textRange.text; + txtExplained = txtExplained.replace(/\n/g, "NL"); + txtExplained = txtExplained.replace(/\r/g, "CR"); + txtExplained = txtExplained.replace(/\v/g, "VV"); + let finalTable = ""; + finalTable += + ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += ""; + finalTable += "
      IndexId
      Raw" + textRange.text + "
      Html" + txtHtml + "
      Exp" + txtExplained + "
      Start" + textRange.start + "
      Length" + textRange.length + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Sets the range selection to the range that was saved previously. + + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedTextSlideSelection[0]); + const shape1: PowerPoint.Shape = slide1.shapes.getItem(savedTextShapeSelection[0]); + const textRange: PowerPoint.TextRange = shape1.textFrame.textRange.getSubstring( + savedTextTextRangeStart, + savedTextTextRangeLength, + ); + textRange.setSelected(); + await context.sync(); + }); +PowerPoint.Presentation#insertSlidesFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml + + + await PowerPoint.run(async function(context) { + // Get the ID of the first selected slide. + const presentation: PowerPoint.Presentation = context.presentation; + const selected: PowerPoint.Slide = presentation.getSelectedSlides().getItemAt(0); + selected.load("id"); + await context.sync(); + + // Insert the other presentation after the selected slide. + const insertOptions: PowerPoint.InsertSlideOptions = { + formatting: PowerPoint.InsertSlideFormatting.useDestinationTheme, + targetSlideId: selected.id + }; + presentation.insertSlidesFromBase64(chosenFileBase64, insertOptions); + await context.sync(); + }); +PowerPoint.Presentation#setSelectedSlides:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Sets selection to the slides that were saved. + + await PowerPoint.run(async (context) => { + context.presentation.setSelectedSlides(savedSlideSelection); + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Selects slides 2, 4, and 5. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slide2: PowerPoint.Slide = context.presentation.slides.getItemAt(1); + const slide4: PowerPoint.Slide = context.presentation.slides.getItemAt(3); + const slide5: PowerPoint.Slide = context.presentation.slides.getItemAt(4); + slide2.load("id"); + slide4.load("id"); + slide5.load("id"); + try { + await context.sync(); + } catch (error) { + console.warn("This action requires at least 5 slides in the presentation."); + return; + } + await context.sync(); + context.presentation.setSelectedSlides([slide2.id, slide4.id, slide5.id]); + await context.sync(); + }); +PowerPoint.Presentation#bindings:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Loads bindings. + + await PowerPoint.run(async (context) => { + const bindings = context.presentation.bindings; + bindings.load("items"); + await context.sync(); + + const bindingCount = bindings.items.length; + if (bindingCount === 0) { + console.log(`There are no bindings.`); + } else if (bindingCount === 1) { + console.log("There's 1 binding."); + } else { + console.log(`There are ${bindingCount} bindings.`); + } + + bindings.items.forEach((binding) => { + getShapeForBindingId(binding.id).then((shape) => { + if (shape) { + console.log(`Binding ID: ${binding.id} refers to shape ID ${shape.id}`); + } else { + console.log(`Binding ID: ${binding.id} doesn't refers to shape.`); + } + }); + }); + + populateBindingsDropdown(bindings.items); + }); +PowerPoint.Shape:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.Shape#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and then iterates through them, deleting each one. + + await PowerPoint.run(async (context) => { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + const shapes: PowerPoint.ShapeCollection = slide.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(); + }); +PowerPoint.Shape#getTable:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Gets the table from a shape. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + + if (shapeCount.value > 0) { + const shape = shapes.getItemAt(0); + shape.load("type"); + await context.sync(); + + // The shape type can indicate whether the shape is a table. + const isTable = shape.type === PowerPoint.ShapeType.table; + + if (isTable) { + // Get the Table object for the Shape which is a table. + const table = shape.getTable(); + table.load(); + await context.sync(); + + // Get the Table row and column count. + console.log("Table RowCount: " + table.rowCount + " and columnCount: " + table.columnCount); + } else console.log("Selected shape isn't table."); + } else console.log("No shape selected."); + }); +PowerPoint.Shape#setZOrder:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function changeZOrder(operation: PowerPoint.ShapeZOrder) { + // Changes the z-order position of the selected shapes. + return PowerPoint.run(async (context) => { + const selectedShapes = context.presentation.getSelectedShapes(); + selectedShapes.load(); + await context.sync(); + + if (selectedShapes.items.length === 0) { + console.log("No shapes are selected."); + } else { + let direction = 1; // Start with bottom-most (lowest number). + + // Start with top-most when sending to back or bringing forward. + + switch (operation) { + case PowerPoint.ShapeZOrder.bringForward: + + case PowerPoint.ShapeZOrder.sendToBack: + direction = -1; // Reverse direction. + + break; + } + + // Change the z-order position for each of the selected shapes, + + // starting with the bottom-most when bringing to front or sending backward, + + // or top-most when sending to back or bringing forward, + + // so the selected shapes retain their relative z-order positions after they're changed. + + selectedShapes.items + .sort((a, b) => (a.zOrderPosition - b.zOrderPosition) * direction) + .forEach((shape) => { + try { + const originalZOrderPosition = shape.zOrderPosition; + shape.setZOrder(operation); + + console.log(`Changed z-order of shape ${shape.id}.`); + } catch (err) { + console.log(`Unable to change z-order of shape ${shape.id}. ${err.message}`); + } + }); + + await context.sync(); + } + }); + } +PowerPoint.Shape#fill:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Changes the selected shapes fill color to red. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); +PowerPoint.Shape#group:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml + + + await PowerPoint.run(async (context) => { + // Ungroups the first shape group on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapeGroups = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.group); + if (shapeGroups.length === 0) { + console.warn("No shape groups on the current slide, so nothing to ungroup."); + return; + } + + // Ungroup the first grouped shapes. + const firstGroupId = shapeGroups[0].id; + const shapeGroupToUngroup = shapes.getItem(firstGroupId); + shapeGroupToUngroup.group.ungroup(); + await context.sync(); + + console.log(`Ungrouped shapes with group ID: ${firstGroupId}`); + }); +PowerPoint.Shape#height:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Arranges the selected shapes in a line from left to right. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 0; + }); +PowerPoint.Shape#left:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Arranges the selected shapes in a line from left to right. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 0; + }); +PowerPoint.Shape#top:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Arranges the selected shapes in a line from left to right. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 0; + }); +PowerPoint.Shape#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.Shape#width:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Arranges the selected shapes in a line from left to right. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + let maxHeight = 0; + shapes.items.map((shape) => { + shape.load("width,height"); + }); + await context.sync(); + shapes.items.map((shape) => { + shape.left = currentLeft; + shape.top = currentTop; + currentLeft += shape.width; + if (shape.height > maxHeight) maxHeight = shape.height; + }); + await context.sync(); + currentLeft = 0; + if (currentTop > slideHeight - 200) currentTop = 0; + }); +PowerPoint.Shape#zOrderPosition:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function changeZOrder(operation: PowerPoint.ShapeZOrder) { + // Changes the z-order position of the selected shapes. + return PowerPoint.run(async (context) => { + const selectedShapes = context.presentation.getSelectedShapes(); + selectedShapes.load(); + await context.sync(); + + if (selectedShapes.items.length === 0) { + console.log("No shapes are selected."); + } else { + let direction = 1; // Start with bottom-most (lowest number). + + // Start with top-most when sending to back or bringing forward. + + switch (operation) { + case PowerPoint.ShapeZOrder.bringForward: + + case PowerPoint.ShapeZOrder.sendToBack: + direction = -1; // Reverse direction. + + break; + } + + // Change the z-order position for each of the selected shapes, + + // starting with the bottom-most when bringing to front or sending backward, + + // or top-most when sending to back or bringing forward, + + // so the selected shapes retain their relative z-order positions after they're changed. + + selectedShapes.items + .sort((a, b) => (a.zOrderPosition - b.zOrderPosition) * direction) + .forEach((shape) => { + try { + const originalZOrderPosition = shape.zOrderPosition; + shape.setZOrder(operation); + + console.log(`Changed z-order of shape ${shape.id}.`); + } catch (err) { + console.log(`Unable to change z-order of shape ${shape.id}. ${err.message}`); + } + }); + + await context.sync(); + } + }); + } +PowerPoint.ShapeAddOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a hexagon shape to the collection, while specifying its + + // location and size. Then it names the shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const shapeOptions: PowerPoint.ShapeAddOptions = { + left: 100, + top: 100, + height: 150, + width: 150, + }; + const hexagon: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon, shapeOptions); + hexagon.name = "Hexagon"; + + await context.sync(); + }); +PowerPoint.ShapeAutoSize:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a brace pair, {}, to the collection, while specifying its + + // location and size. Then it names the shape, sets its text and font + + // color, and centers it inside the braces. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); +PowerPoint.ShapeCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.ShapeCollection#addGeometricShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a hexagon shape to the collection, while specifying its + + // location and size. Then it names the shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const shapeOptions: PowerPoint.ShapeAddOptions = { + left: 100, + top: 100, + height: 150, + width: 150, + }; + const hexagon: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.hexagon, shapeOptions); + hexagon.name = "Hexagon"; + + await context.sync(); + }); +PowerPoint.ShapeCollection#addGroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml + + + await PowerPoint.run(async (context) => { + // Groups the geometric shapes on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapesToGroup = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.geometricShape); + if (shapesToGroup.length === 0) { + console.warn("No shapes on the current slide, so nothing to group."); + return; + } + + // Group the geometric shapes. + console.log(`Number of shapes to group: ${shapesToGroup.length}`); + const group = shapes.addGroup(shapesToGroup); + group.load("id"); + await context.sync(); + + console.log(`Grouped shapes. Group ID: ${group.id}`); + }); +PowerPoint.ShapeCollection#addLine:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a line to the collection, while specifying its + + // start and end points. Then it names the shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + + // For a line, left and top are the coordinates of the start point, + // while height and width are the coordinates of the end point. + const line: PowerPoint.Shape = shapes.addLine(PowerPoint.ConnectorType.straight, { + left: 400, + top: 200, + height: 20, + width: 150, + }); + line.name = "StraightLine"; + + await context.sync(); + }); +PowerPoint.ShapeCollection#addTable:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Adds a basic table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a simple table, specifying the row and column count. + shapes.addTable(3, 4); + await context.sync(); + }); +PowerPoint.ShapeCollection#addTextBox:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a text box to the collection, while specifying its text, + + // location, and size. Then it names the text box. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const textbox: PowerPoint.Shape = shapes.addTextBox("Hello!", { + left: 100, + top: 300, + height: 300, + width: 450, + }); + textbox.name = "Textbox"; + + return context.sync(); + }); +PowerPoint.ShapeCollection#getCount:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Gets the table from a shape. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + + if (shapeCount.value > 0) { + const shape = shapes.getItemAt(0); + shape.load("type"); + await context.sync(); + + // The shape type can indicate whether the shape is a table. + const isTable = shape.type === PowerPoint.ShapeType.table; + + if (isTable) { + // Get the Table object for the Shape which is a table. + const table = shape.getTable(); + table.load(); + await context.sync(); + + // Get the Table row and column count. + console.log("Table RowCount: " + table.rowCount + " and columnCount: " + table.columnCount); + } else console.log("Selected shape isn't table."); + } else console.log("No shape selected."); + }); +PowerPoint.ShapeCollection#getItemAt:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function(context) { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + const shape: PowerPoint.Shape = slide.shapes.getItemAt(0); + shape.tags.add("MOUNTAIN", "Denali"); + + await context.sync(); + + const myShapeTag: PowerPoint.Tag = shape.tags.getItem("MOUNTAIN"); + myShapeTag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(myShapeTag.key) + " with value " + JSON.stringify(myShapeTag.value)); + }); +PowerPoint.ShapeCollection#load:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.ShapeFill:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.ShapeFill#setImage:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Inserts an image with binding. + + await PowerPoint.run(async (context) => { + const bindingId = (document.getElementById("temp-binding-id") as HTMLInputElement).value; + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const myShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle, { + top: 100, + left: 30, + width: 200, + height: 200 + }); + + myShape.fill.setImage(flowerImage); + context.presentation.bindings.add(myShape, PowerPoint.BindingType.shape, bindingId); + await context.sync(); + + const bindingsDropdown = document.getElementById("bindings-dropdown") as HTMLSelectElement; + + const option = new Option(`Binding ${bindingId}`, bindingId); + + // When a binding ID already exists, the binding is updated to refer to the new shape + // so select the existing item rather than add a new one. + const foundIndex = findDropdownItem(bindingsDropdown, option.text); + if (foundIndex < 0) { + bindingsDropdown.add(option); + bindingsDropdown.selectedIndex = bindingsDropdown.options.length - 1; + } else { + bindingsDropdown.selectedIndex = foundIndex; + } + }); +PowerPoint.ShapeFill#setSolidColor:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Changes the selected shapes fill color to red. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); +PowerPoint.ShapeFill#foregroundColor:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Creates random shapes on the selected slide. + + await PowerPoint.run(async (context) => { + let finalTable = ""; + const currentSlide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + const maxNewShapeWidth = 200; + const maxNewShapeHeight = 200; + const minNewShapeWidth = 50; + const minNewShapeHeight = 50; + for (let i = 0; i < 20; i++) { + const rectangle: PowerPoint.Shape = currentSlide.shapes.addGeometricShape( + PowerPoint.GeometricShapeType.rectangle, + ); + rectangle.height = getRandomBetween(minNewShapeWidth, maxNewShapeWidth); + rectangle.width = getRandomBetween(minNewShapeHeight, maxNewShapeHeight); + rectangle.left = getRandomBetween(0, slideWidth - rectangle.width); + rectangle.top = getRandomBetween(0, slideHeight - rectangle.height); + rectangle.fill.foregroundColor = generateRandomHexColor(); + } + finalTable += "Done
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); +PowerPoint.ShapeFill#transparency:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the transparency of every geometric shape in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the shape transparency to be halfway transparent. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.geometricShape) { + shape.fill.transparency = 0.5; + } + }); + await context.sync(); + }); +PowerPoint.ShapeFill#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Changes the selected shapes fill color to red. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); +PowerPoint.ShapeFillType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Changes the selected shapes fill color to red. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); +PowerPoint.ShapeFont:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Gets navigational (complex) properties of the selected text range. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.load("font,paragraphFormat/bulletFormat,paragraphFormat/horizontalAlignment"); + await context.sync(); + + console.log("Font properties of selected text range:"); + console.log(`\tallCaps: ${textRange.font.allCaps}`); + console.log(`\tbold: ${textRange.font.bold}`); + console.log(`\tcolor: ${textRange.font.color}`); + console.log(`\tdoubleStrikethrough: ${textRange.font.doubleStrikethrough}`); + console.log(`\titalic: ${textRange.font.italic}`); + console.log(`\tname: ${textRange.font.name}`); + console.log(`\tsize: ${textRange.font.size}`); + console.log(`\tsmallCaps: ${textRange.font.smallCaps}`); + console.log(`\tstrikethrough: ${textRange.font.strikethrough}`); + console.log(`\tsubscript: ${textRange.font.subscript}`); + console.log(`\tsuperscript: ${textRange.font.superscript}`); + console.log(`\tunderline: ${textRange.font.underline}`); + + console.log("Paragraph format properties of selected text range:"); + console.log(`\tbulletFormat.visible: ${textRange.paragraphFormat.bulletFormat.visible}`); + console.log(`\thorizontalAlignment: ${textRange.paragraphFormat.horizontalAlignment}`); + }); +PowerPoint.ShapeFont#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Sets the color of the selected text range to green. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.font.color = "green"; + await context.sync(); + }); +PowerPoint.ShapeFont#underline:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a brace pair, {}, to the collection, while specifying its + + // location and size. Then it names the shape, sets its text and font + + // color, and centers it inside the braces. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); +PowerPoint.ShapeFontUnderlineStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a brace pair, {}, to the collection, while specifying its + + // location and size. Then it names the shape, sets its text and font + + // color, and centers it inside the braces. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); +PowerPoint.ShapeGroup:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml + + + await PowerPoint.run(async (context) => { + // Ungroups the first shape group on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapeGroups = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.group); + if (shapeGroups.length === 0) { + console.warn("No shape groups on the current slide, so nothing to ungroup."); + return; + } + + // Ungroup the first grouped shapes. + const firstGroupId = shapeGroups[0].id; + const shapeGroupToUngroup = shapes.getItem(firstGroupId); + shapeGroupToUngroup.group.ungroup(); + await context.sync(); + + console.log(`Ungrouped shapes with group ID: ${firstGroupId}`); + }); +PowerPoint.ShapeGroup#ungroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml + + + await PowerPoint.run(async (context) => { + // Ungroups the first shape group on the current slide. + + // Get the shapes on the current slide. + context.presentation.load("slides"); + const slide: PowerPoint.Slide = context.presentation.getSelectedSlides().getItemAt(0); + slide.load("shapes/items/type,shapes/items/id"); + await context.sync(); + + const shapes: PowerPoint.ShapeCollection = slide.shapes; + const shapeGroups = shapes.items.filter((item) => item.type === PowerPoint.ShapeType.group); + if (shapeGroups.length === 0) { + console.warn("No shape groups on the current slide, so nothing to ungroup."); + return; + } + + // Ungroup the first grouped shapes. + const firstGroupId = shapeGroups[0].id; + const shapeGroupToUngroup = shapes.getItem(firstGroupId); + shapeGroupToUngroup.group.ungroup(); + await context.sync(); + + console.log(`Ungrouped shapes with group ID: ${firstGroupId}`); + }); +PowerPoint.ShapeLineDashStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the dash style of every line in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); +PowerPoint.ShapeLineFormat:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the dash style of every line in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); +PowerPoint.ShapeLineFormat#dashStyle:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the dash style of every line in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); +PowerPoint.ShapeScopedCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Changes the selected shapes fill color to red. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items/fill/type"); + await context.sync(); + shapes.items.map((shape) => { + const shapeFillType = shape.fill.type as PowerPoint.ShapeFillType; + console.log(`Shape ID ${shape.id} original fill type: ${shapeFillType}`); + shape.fill.setSolidColor("red"); + }); + await context.sync(); + }); +PowerPoint.ShapeScopedCollection#getCount:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Gets the shapes you selected on the slide and displays their IDs on the + task pane. + + await PowerPoint.run(async (context) => { + let finalTable = ""; + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + finalTable += "
      getSelectedShapes.getCount returned:" + shapeCount.value + "
      "; + finalTable += + "
      "; + shapes.load("items"); + await context.sync(); + shapes.items.map((shape, index) => { + finalTable += ""; + }); + finalTable += "
      IndexId
      " + index + "" + shape.id + "
      "; + const outputSpan = document.getElementById("outputSpan"); + outputSpan.innerHTML = ""; + outputSpan.innerHTML += finalTable; + }); +PowerPoint.ShapeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the dash style of every line in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); +PowerPoint.ShapeZOrder:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + // Sends the shape to the back. + + changeZOrder(PowerPoint.ShapeZOrder.sendToBack); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml + + + async function changeZOrder(operation: PowerPoint.ShapeZOrder) { + // Changes the z-order position of the selected shapes. + return PowerPoint.run(async (context) => { + const selectedShapes = context.presentation.getSelectedShapes(); + selectedShapes.load(); + await context.sync(); + + if (selectedShapes.items.length === 0) { + console.log("No shapes are selected."); + } else { + let direction = 1; // Start with bottom-most (lowest number). + + // Start with top-most when sending to back or bringing forward. + + switch (operation) { + case PowerPoint.ShapeZOrder.bringForward: + + case PowerPoint.ShapeZOrder.sendToBack: + direction = -1; // Reverse direction. + + break; + } + + // Change the z-order position for each of the selected shapes, + + // starting with the bottom-most when bringing to front or sending backward, + + // or top-most when sending to back or bringing forward, + + // so the selected shapes retain their relative z-order positions after they're changed. + + selectedShapes.items + .sort((a, b) => (a.zOrderPosition - b.zOrderPosition) * direction) + .forEach((shape) => { + try { + const originalZOrderPosition = shape.zOrderPosition; + shape.setZOrder(operation); + + console.log(`Changed z-order of shape ${shape.id}.`); + } catch (err) { + console.log(`Unable to change z-order of shape ${shape.id}. ${err.message}`); + } + }); + + await context.sync(); + } + }); + } +PowerPoint.Slide:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Reselects shapes that were saved previously. + + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedSlideSelection[0]); + await context.sync(); + slide1.setSelectedShapes(savedShapeSelection); + await context.sync(); + }); +PowerPoint.Slide#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Deletes the selected slides. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + slides.items.map((slide) => { + slide.delete(); + }); + }); +PowerPoint.Slide#exportAsBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml + + + // Exports current slide. + + await PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const slideBase64DataResult = slide.exportAsBase64(); + const imageBase64DataResult = slide.getImageAsBase64({ height: 300 }); + await context.sync(); + + localStorage.setItem("exportedSlide", slideBase64DataResult.value); + localStorage.setItem("exportedSlideImage", imageBase64DataResult.value); + + updateSlideImage(imageBase64DataResult.value); + + console.log("Slide was exported."); + }); +PowerPoint.Slide#getImageAsBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml + + + // Exports current slide. + + await PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const slideBase64DataResult = slide.exportAsBase64(); + const imageBase64DataResult = slide.getImageAsBase64({ height: 300 }); + await context.sync(); + + localStorage.setItem("exportedSlide", slideBase64DataResult.value); + localStorage.setItem("exportedSlideImage", imageBase64DataResult.value); + + updateSlideImage(imageBase64DataResult.value); + + console.log("Slide was exported."); + }); +PowerPoint.Slide#setSelectedShapes:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Reselects shapes that were saved previously. + + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedSlideSelection[0]); + await context.sync(); + slide1.setSelectedShapes(savedShapeSelection); + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Selects the first two shapes on slide 1. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slide1 = context.presentation.slides.getItemAt(0); + slide1.load("shapes/items/type"); + await context.sync(); + + const shapes = slide1.shapes.items.filter((item) => item.type === PowerPoint.ShapeType.geometricShape); + const shape1: PowerPoint.Shape = shapes[0]; + const shape2: PowerPoint.Shape = shapes[1]; + shape1.load("id"); + shape2.load("id"); + await context.sync(); + + console.log(`IDs: ${shape1.id}, ${shape2.id}`); + slide1.setSelectedShapes([shape1.id, shape2.id]); + await context.sync(); + }); +PowerPoint.SlideCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + const chosenMaster = (document.getElementById("master-id") as + HTMLInputElement).value; + + const chosenLayout = (document.getElementById("layout-id") as + HTMLInputElement).value; + + + await PowerPoint.run(async function(context) { + // Create a new slide using an existing master slide and layout. + const newSlideOptions: PowerPoint.AddSlideOptions = { + slideMasterId: chosenMaster, /* An ID from `Presentation.slideMasters`. */ + layoutId: chosenLayout /* An ID from `SlideMaster.layouts`. */ + }; + context.presentation.slides.add(newSlideOptions); + await context.sync(); + }); +PowerPoint.SlideCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + const chosenMaster = (document.getElementById("master-id") as + HTMLInputElement).value; + + const chosenLayout = (document.getElementById("layout-id") as + HTMLInputElement).value; + + + await PowerPoint.run(async function(context) { + // Create a new slide using an existing master slide and layout. + const newSlideOptions: PowerPoint.AddSlideOptions = { + slideMasterId: chosenMaster, /* An ID from `Presentation.slideMasters`. */ + layoutId: chosenLayout /* An ID from `SlideMaster.layouts`. */ + }; + context.presentation.slides.add(newSlideOptions); + await context.sync(); + }); +PowerPoint.SlideCollection#getItemAt:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml + + + // Selects slides 2, 4, and 5. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slide2: PowerPoint.Slide = context.presentation.slides.getItemAt(1); + const slide4: PowerPoint.Slide = context.presentation.slides.getItemAt(3); + const slide5: PowerPoint.Slide = context.presentation.slides.getItemAt(4); + slide2.load("id"); + slide4.load("id"); + slide5.load("id"); + try { + await context.sync(); + } catch (error) { + console.warn("This action requires at least 5 slides in the presentation."); + return; + } + await context.sync(); + context.presentation.setSelectedSlides([slide2.id, slide4.id, slide5.id]); + await context.sync(); + }); +PowerPoint.SlideGetImageOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml + + + // Exports current slide. + + await PowerPoint.run(async (context) => { + const slide = context.presentation.getSelectedSlides().getItemAt(0); + const slideBase64DataResult = slide.exportAsBase64(); + const imageBase64DataResult = slide.getImageAsBase64({ height: 300 }); + await context.sync(); + + localStorage.setItem("exportedSlide", slideBase64DataResult.value); + localStorage.setItem("exportedSlideImage", imageBase64DataResult.value); + + updateSlideImage(imageBase64DataResult.value); + + console.log("Slide was exported."); + }); +PowerPoint.SlideLayout:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideLayout#id:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideLayoutCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideLayoutCollection#load:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.ShapeLineStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml + + + // Changes the dash style of every line in the slide. + + await PowerPoint.run(async (context) => { + // Get the type of shape for every shape in the collection. + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + shapes.load("type"); + await context.sync(); + + // Change the dash style for shapes of the type `line`. + shapes.items.forEach((shape) => { + if (shape.type === PowerPoint.ShapeType.line) { + shape.lineFormat.style = PowerPoint.ShapeLineStyle.thickThin; + shape.lineFormat.dashStyle = PowerPoint.ShapeLineDashStyle.dashDot; + } + }); + await context.sync(); + }); +PowerPoint.SlideMaster:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideMaster#id:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideMasterCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideMasterCollection#load:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml + + + await PowerPoint.run(async function(context) { + // Load information about all the slide masters and associated layouts. + const slideMasters: PowerPoint.SlideMasterCollection = context.presentation.slideMasters.load("id, name, layouts/items/name, layouts/items/id"); + await context.sync(); + + // Log the name and ID of each slide master. + for (let i = 0; i < slideMasters.items.length; i++) { + console.log("Master name: " + slideMasters.items[i].name); + console.log("Master ID: " + slideMasters.items[i].id); + + // Log the name and ID of each slide layout in the slide master. + const layoutsInMaster: PowerPoint.SlideLayoutCollection = slideMasters.items[i].layouts; + for (let j = 0; j < layoutsInMaster.items.length; j++) { + console.log(" Layout name: " + layoutsInMaster.items[j].name + " Layout ID: " + layoutsInMaster.items[j].id); + } + } + }); +PowerPoint.SlideScopedCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml + + + // Saves which shapes are selected so that they can be reselected later. + + await PowerPoint.run(async (context) => { + context.presentation.load("slides"); + await context.sync(); + const slides: PowerPoint.SlideScopedCollection = context.presentation.getSelectedSlides(); + const slideCount = slides.getCount(); + slides.load("items"); + await context.sync(); + savedSlideSelection = []; + slides.items.map((slide) => { + savedSlideSelection.push(slide.id); + }); + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + shapes.load("items"); + await context.sync(); + shapes.items.map((shape) => { + savedShapeSelection.push(shape.id); + }); + }); +PowerPoint.Table:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Updates a table's values. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table (which is a type of Shape). + const shape = shapes.addTable(4, 3); + let table = shape.getTable(); + table.load(); + await context.sync(); + + // Update values in the table. + for (let rowIndex = 0; rowIndex < table.rowCount; rowIndex++) { + for (let columnIndex = 0; columnIndex < table.columnCount; columnIndex++) { + const cell = table.getCellOrNullObject(rowIndex, columnIndex); + cell.text = generateRandomString(); + } + } + + await context.sync(); + }); +PowerPoint.Table#getCellOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Updates a table's values. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table (which is a type of Shape). + const shape = shapes.addTable(4, 3); + let table = shape.getTable(); + table.load(); + await context.sync(); + + // Update values in the table. + for (let rowIndex = 0; rowIndex < table.rowCount; rowIndex++) { + for (let columnIndex = 0; columnIndex < table.columnCount; columnIndex++) { + const cell = table.getCellOrNullObject(rowIndex, columnIndex); + cell.text = generateRandomString(); + } + } + + await context.sync(); + }); +PowerPoint.TableAddOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the width and height of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the width and height. + shapes.addTable(3, 4, { + width: 600, + height: 400 + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#columns:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#height:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the width and height of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the width and height. + shapes.addTable(3, 4, { + width: 600, + height: 400 + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#mergedAreas:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#rows:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#specificCellProperties:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#uniformCellProperties:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#values:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's values. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying cell values. + const shape = shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ] + }); + await context.sync(); + }); +PowerPoint.TableAddOptions#width:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the width and height of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the width and height. + shapes.addTable(3, 4, { + width: 600, + height: 400 + }); + await context.sync(); + }); +PowerPoint.TableCell:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Updates a table's values. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table (which is a type of Shape). + const shape = shapes.addTable(4, 3); + let table = shape.getTable(); + table.load(); + await context.sync(); + + // Update values in the table. + for (let rowIndex = 0; rowIndex < table.rowCount; rowIndex++) { + for (let columnIndex = 0; columnIndex < table.columnCount; columnIndex++) { + const cell = table.getCellOrNullObject(rowIndex, columnIndex); + cell.text = generateRandomString(); + } + } + + await context.sync(); + }); +PowerPoint.TableCell#text:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Updates a table's values. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table (which is a type of Shape). + const shape = shapes.addTable(4, 3); + let table = shape.getTable(); + table.load(); + await context.sync(); + + // Update values in the table. + for (let rowIndex = 0; rowIndex < table.rowCount; rowIndex++) { + for (let columnIndex = 0; columnIndex < table.columnCount; columnIndex++) { + const cell = table.getCellOrNullObject(rowIndex, columnIndex); + cell.text = generateRandomString(); + } + } + + await context.sync(); + }); +PowerPoint.TableCellBorders:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellBorders#bottom:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellBorders#left:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellBorders#right:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellBorders#top:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#borders:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies a table's borders. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying border styles. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + borders: { + left: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + right: { color: "blue", dashStyle: PowerPoint.ShapeLineDashStyle.solid, weight: 4 }, + top: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 }, + bottom: { color: "red", dashStyle: PowerPoint.ShapeLineDashStyle.longDashDotDot, weight: 2 } + } + } + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#fill:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the font formatting and fill colors of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying font formatting and fill colors. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [ + { fill: { color: "red" }, font: { color: "yellow", name: "Calibri" } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", name: "Coolvetica" } }, + { fill: { color: "red" }, font: { color: "yellow", italic: true } }, + { fill: { color: "red" }, font: { color: "#9966cc", strikethrough: true } } + ], + [ + { fill: { color: "#fbceb1" }, font: { color: "yellow", doubleStrikethrough: true } }, + { fill: { color: "red" }, font: { color: "yellow", subscript: true } }, + { fill: { color: "#0048ba" }, font: { color: "yellow", superscript: true } }, + { fill: { color: "red" }, font: { color: "yellow" } } + ], + [ + { fill: { color: "red" }, font: { color: "#b0bf1a" } }, + { fill: { color: "#9966cc" }, font: { color: "yellow" } }, + { fill: { color: "#b0bf1a" }, font: { color: "yellow" } }, + { fill: { color: "red" }, font: { color: "#fbceb1" } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#horizontalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the horizontal and vertical alignments of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying horizontal and vertical alignment. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + horizontalAlignment: PowerPoint.ParagraphHorizontalAlignment.justify, + verticalAlignment: PowerPoint.TextVerticalAlignment.middle + } + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#indentLevel:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifying the indents for a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying the indent level for cells. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + specificCellProperties: [ + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }], + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }], + [{ indentLevel: 0 }, { indentLevel: 1 }, { indentLevel: 2 }, { indentLevel: 3 }] + ] + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#textRuns:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the text runs of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying text runs. + shapes.addTable(3, 4, { + specificCellProperties: [ + [ + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } } + ], + [ + { text: "Bold text", font: { bold: true } }, + { + textRuns: [ + { text: "Text runs with " }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.double } }, + { text: " and plain text" } + ] + }, + { text: "Italicized text", font: { italic: true } }, + { text: "Plain text" } + ], + [ + { text: "Bold text", font: { bold: true } }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.dotted } }, + { + font: { bold: true }, + textRuns: [ + { text: "Text runs with " }, + { text: "italicized text", font: { italic: true } }, + { text: " and (inherited) bold text" } + ] + }, + { text: "Italicized text", font: { italic: true } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TableCellProperties#verticalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the horizontal and vertical alignments of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying horizontal and vertical alignment. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "GGG", "HHHH"], + ["1", "12", "123", "1234"] + ], + uniformCellProperties: { + horizontalAlignment: PowerPoint.ParagraphHorizontalAlignment.justify, + verticalAlignment: PowerPoint.TextVerticalAlignment.middle + } + }); + await context.sync(); + }); +PowerPoint.TableColumnProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.TableColumnProperties#columnWidth:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.TableMergedAreaProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableMergedAreaProperties#columnCount:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableMergedAreaProperties#columnIndex:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableMergedAreaProperties#rowCount:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableMergedAreaProperties#rowIndex:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the merge areas of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying one 2x2 merged area. + shapes.addTable(3, 4, { + values: [ + ["A", "BB", "CCC", "DDDD"], + ["E", "FF", "", "HHHH"], + ["1", "", "", "1234"] + ], + mergedAreas: [{ rowIndex: 1, columnIndex: 1, rowCount: 2, columnCount: 2 }] + }); + await context.sync(); + }); +PowerPoint.TableRowProperties:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.TableRowProperties#rowHeight:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the column widths and row heights of a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying column widths and row heights. + shapes.addTable(3, 4, { + columns: [{ columnWidth: 100 }, { columnWidth: 200 }, { columnWidth: 100 }, { columnWidth: 200 }], + rows: [{ rowHeight: 60 }, { rowHeight: 120 }, { rowHeight: 180 }] + }); + await context.sync(); + }); +PowerPoint.Tag:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function (context) { + let presentationTags: PowerPoint.TagCollection = context.presentation.tags; + presentationTags.add("COLOR", "blue"); + + await context.sync(); + + const tag: PowerPoint.Tag = presentationTags.getItem("COLOR"); + tag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(tag.key) + " with value " + JSON.stringify(tag.value)); + }); +PowerPoint.TagCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function(context) { + let selectedSlideIndex = await getSelectedSlideIndex(); + + // Decrement because the getSelectedSlideByIndex method is 1-based, + // but the getItemAt method is 0-based. + selectedSlideIndex = selectedSlideIndex - 1; + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(selectedSlideIndex); + slide.tags.add("CUSTOMER_TYPE", "Premium"); + + await context.sync(); + + const audienceTag: PowerPoint.Tag = slide.tags.getItem("CUSTOMER_TYPE"); + audienceTag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(audienceTag.key) + " with value " + JSON.stringify(audienceTag.value)); + }); +PowerPoint.TagCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function(context) { + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(0); + slide.tags.add("OCEAN", "Indian"); + slide.tags.add("PLANET", "Jupiter"); + slide.tags.add("CONTINENT", "Antarctica"); + + await context.sync(); + + slide.tags.load("key, value"); + + await context.sync(); + + for (let i = 0; i < slide.tags.items.length; i++) { + console.log("Added key " + JSON.stringify(slide.tags.items[i].key) + " with value " + JSON.stringify(slide.tags.items[i].value)); + } + }); +PowerPoint.TagCollection#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function (context) { + let presentationTags: PowerPoint.TagCollection = context.presentation.tags; + + presentationTags.delete("COLOR"); + + await context.sync(); + + console.log(JSON.stringify(presentationTags)); + }); +PowerPoint.TagCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml + + + await PowerPoint.run(async function(context) { + let selectedSlideIndex = await getSelectedSlideIndex(); + + // Decrement because the getSelectedSlideByIndex method is 1-based, + // but the getItemAt method is 0-based. + selectedSlideIndex = selectedSlideIndex - 1; + const slide: PowerPoint.Slide = context.presentation.slides.getItemAt(selectedSlideIndex); + slide.tags.add("CUSTOMER_TYPE", "Premium"); + + await context.sync(); + + const audienceTag: PowerPoint.Tag = slide.tags.getItem("CUSTOMER_TYPE"); + audienceTag.load("key, value"); + + await context.sync(); + + console.log("Added key " + JSON.stringify(audienceTag.key) + " with value " + JSON.stringify(audienceTag.value)); + }); +PowerPoint.TextFrame:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Selects the first 10 characters of the selected shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + if (shapeCount.value !== 1) { + console.warn("You must select only one shape with text in it."); + return; + } + const shape: PowerPoint.Shape = shapes.getItemAt(0); + const textFrame: PowerPoint.TextFrame = shape.textFrame.load("textRange,hasText"); + await context.sync(); + if (textFrame.hasText != true) { + console.warn("You must select only one shape with text in it."); + return; + } + const textRange: PowerPoint.TextRange = textFrame.textRange; + textRange.load("text"); + await context.sync(); + if (textRange.text.length < 10) { + console.warn("You must select only one shape with at least 10 characters in it."); + return; + } + const textRange10 = textRange.getSubstring(0, 10); + textRange10.setSelected(); + await context.sync(); + }); +PowerPoint.TextFrame#autoSizeSetting:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a brace pair, {}, to the collection, while specifying its + + // location and size. Then it names the shape, sets its text and font + + // color, and centers it inside the braces. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); +PowerPoint.TextRange:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Sets the color of the selected text range to green. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.font.color = "green"; + await context.sync(); + }); +PowerPoint.TextRange#setSelected:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Selects the first 10 characters of the selected shape. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeScopedCollection = context.presentation.getSelectedShapes(); + const shapeCount = shapes.getCount(); + await context.sync(); + if (shapeCount.value !== 1) { + console.warn("You must select only one shape with text in it."); + return; + } + const shape: PowerPoint.Shape = shapes.getItemAt(0); + const textFrame: PowerPoint.TextFrame = shape.textFrame.load("textRange,hasText"); + await context.sync(); + if (textFrame.hasText != true) { + console.warn("You must select only one shape with text in it."); + return; + } + const textRange: PowerPoint.TextRange = textFrame.textRange; + textRange.load("text"); + await context.sync(); + if (textRange.text.length < 10) { + console.warn("You must select only one shape with at least 10 characters in it."); + return; + } + const textRange10 = textRange.getSubstring(0, 10); + textRange10.setSelected(); + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Sets the range selection to the range that was saved previously. + + await PowerPoint.run(async (context) => { + const slide1: PowerPoint.Slide = context.presentation.slides.getItem(savedTextSlideSelection[0]); + const shape1: PowerPoint.Shape = slide1.shapes.getItem(savedTextShapeSelection[0]); + const textRange: PowerPoint.TextRange = shape1.textFrame.textRange.getSubstring( + savedTextTextRangeStart, + savedTextTextRangeLength, + ); + textRange.setSelected(); + await context.sync(); + }); +PowerPoint.TextRange#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Sets the color of the selected text range to green. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.font.color = "green"; + await context.sync(); + }); +PowerPoint.TextRange#paragraphFormat:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml + + + // Gets navigational (complex) properties of the selected text range. + + await PowerPoint.run(async (context) => { + const textRange: PowerPoint.TextRange = context.presentation.getSelectedTextRange(); + textRange.load("font,paragraphFormat/bulletFormat,paragraphFormat/horizontalAlignment"); + await context.sync(); + + console.log("Font properties of selected text range:"); + console.log(`\tallCaps: ${textRange.font.allCaps}`); + console.log(`\tbold: ${textRange.font.bold}`); + console.log(`\tcolor: ${textRange.font.color}`); + console.log(`\tdoubleStrikethrough: ${textRange.font.doubleStrikethrough}`); + console.log(`\titalic: ${textRange.font.italic}`); + console.log(`\tname: ${textRange.font.name}`); + console.log(`\tsize: ${textRange.font.size}`); + console.log(`\tsmallCaps: ${textRange.font.smallCaps}`); + console.log(`\tstrikethrough: ${textRange.font.strikethrough}`); + console.log(`\tsubscript: ${textRange.font.subscript}`); + console.log(`\tsuperscript: ${textRange.font.superscript}`); + console.log(`\tunderline: ${textRange.font.underline}`); + + console.log("Paragraph format properties of selected text range:"); + console.log(`\tbulletFormat.visible: ${textRange.paragraphFormat.bulletFormat.visible}`); + console.log(`\thorizontalAlignment: ${textRange.paragraphFormat.horizontalAlignment}`); + }); +PowerPoint.TextRun:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml + + + // Specifies the text runs of the cells in a table. + + await PowerPoint.run(async (context) => { + const shapes = context.presentation.getSelectedSlides().getItemAt(0).shapes; + + // Add a table, specifying text runs. + shapes.addTable(3, 4, { + specificCellProperties: [ + [ + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } }, + { text: "Title text", font: { bold: true } } + ], + [ + { text: "Bold text", font: { bold: true } }, + { + textRuns: [ + { text: "Text runs with " }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.double } }, + { text: " and plain text" } + ] + }, + { text: "Italicized text", font: { italic: true } }, + { text: "Plain text" } + ], + [ + { text: "Bold text", font: { bold: true } }, + { text: "Underlined text", font: { underline: PowerPoint.ShapeFontUnderlineStyle.dotted } }, + { + font: { bold: true }, + textRuns: [ + { text: "Text runs with " }, + { text: "italicized text", font: { italic: true } }, + { text: " and (inherited) bold text" } + ] + }, + { text: "Italicized text", font: { italic: true } } + ] + ] + }); + await context.sync(); + }); +PowerPoint.TextVerticalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml + + + // This function gets the collection of shapes on the first slide, + + // and adds a brace pair, {}, to the collection, while specifying its + + // location and size. Then it names the shape, sets its text and font + + // color, and centers it inside the braces. + + await PowerPoint.run(async (context) => { + const shapes: PowerPoint.ShapeCollection = context.presentation.slides.getItemAt(0).shapes; + const braces: PowerPoint.Shape = shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair, { + left: 100, + top: 400, + height: 50, + width: 150, + }); + braces.name = "Braces"; + braces.textFrame.textRange.text = "Shape text"; + braces.textFrame.textRange.font.color = "purple"; + braces.textFrame.textRange.font.underline = PowerPoint.ShapeFontUnderlineStyle.heavy; + braces.textFrame.verticalAlignment = PowerPoint.TextVerticalAlignment.middleCentered; + braces.textFrame.autoSizeSetting = PowerPoint.ShapeAutoSize.autoSizeShapeToFitText; + + return context.sync(); + }); +Word.Alignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + body.paragraphs + .getLast() + .insertText( + "Use add-in commands to extend the Word UI and launch task panes that run JavaScript that interacts with the content in a Word document. Any code that you can run in a browser can run in a Word add-in. Add-ins that interact with content in a Word document create requests to act on Word objects and synchronize object state.", + "Replace" + ); + body.paragraphs.getFirst().alignment = "Left"; + body.paragraphs.getLast().alignment = Word.Alignment.left; + }); +Word.Annotation:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Accepts the first annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Accepting ID ${annotation.id}...`); + annotation.critiqueAnnotation.accept(); + + await context.sync(); + break; + } + } + }); +Word.Annotation#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Deletes all annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id"); + + await context.sync(); + + const ids = []; + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + ids.push(annotation.id); + annotation.delete(); + } + + await context.sync(); + + console.log("Annotations deleted:", ids); + }); +Word.Annotation#critiqueAnnotation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Gets annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); +Word.Annotation#id:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Accepts the first annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Accepting ID ${annotation.id}...`); + annotation.critiqueAnnotation.accept(); + + await context.sync(); + break; + } + } + }); +Word.Annotation#state:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Rejects the last annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = annotations.items.length - 1; i >= 0; i--) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Rejecting ID ${annotation.id}...`); + annotation.critiqueAnnotation.reject(); + + await context.sync(); + break; + } + } + }); +Word.AnnotationClickedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onClickedHandler(args: Word.AnnotationClickedEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationClicked: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } +Word.AnnotationCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Gets annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); +Word.AnnotationHoveredEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onHoveredHandler(args: Word.AnnotationHoveredEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationHovered: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } +Word.AnnotationInsertedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onInsertedHandler(args: Word.AnnotationInsertedEventArgs) { + await Word.run(async (context) => { + const annotations = []; + for (let i = 0; i < args.ids.length; i++) { + let annotation: Word.Annotation = context.document.getAnnotationById(args.ids[i]); + annotation.load("id,critiqueAnnotation"); + + annotations.push(annotation); + } + + await context.sync(); + + for (let annotation of annotations) { + console.log(`AnnotationInserted: ID ${annotation.id}:`, annotation.critiqueAnnotation.critique); + } + }); + } +Word.AnnotationPopupActionEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onPopupActionHandler(args: + Word.AnnotationPopupActionEventArgs) { + await Word.run(async (context) => { + let message = `AnnotationPopupAction: ID ${args.id} = `; + if (args.action === "Accept") { + message += `Accepted: ${args.critiqueSuggestion}`; + } else { + message += "Rejected"; + } + + console.log(message); + }); + } +Word.AnnotationRemovedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onRemovedHandler(args: Word.AnnotationRemovedEventArgs) { + await Word.run(async (context) => { + for (let id of args.ids) { + console.log(`AnnotationRemoved: ID ${id}`); + } + }); + } +Word.AnnotationSet:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Adds annotations to the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); +Word.AnnotationState:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Accepts the first annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Accepting ID ${annotation.id}...`); + annotation.critiqueAnnotation.accept(); + + await context.sync(); + break; + } + } + }); +Word.Application:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + + + // Updates the text of the current document with the text from another + document passed in as a Base64-encoded string. + + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + const externalDoc: Word.DocumentCreated = context.application.createDocument(externalDocument); + await context.sync(); + + if (!Office.context.requirements.isSetSupported("WordApiHiddenDocument", "1.3")) { + console.warn("The WordApiHiddenDocument 1.3 requirement set isn't supported on this client so can't proceed. Try this action on a platform that supports this requirement set."); + return; + } + + const externalDocBody: Word.Body = externalDoc.body; + externalDocBody.load("text"); + await context.sync(); + + // Insert the external document's text at the beginning of the current document's body. + const externalDocBodyText = externalDocBody.text; + const currentDocBody: Word.Body = context.document.body; + currentDocBody.insertText(externalDocBodyText, Word.InsertLocation.start); + await context.sync(); + }); +Word.Application#createDocument:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + + + // Updates the text of the current document with the text from another + document passed in as a Base64-encoded string. + + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + const externalDoc: Word.DocumentCreated = context.application.createDocument(externalDocument); + await context.sync(); + + if (!Office.context.requirements.isSetSupported("WordApiHiddenDocument", "1.3")) { + console.warn("The WordApiHiddenDocument 1.3 requirement set isn't supported on this client so can't proceed. Try this action on a platform that supports this requirement set."); + return; + } + + const externalDocBody: Word.Body = externalDoc.body; + externalDocBody.load("text"); + await context.sync(); + + // Insert the external document's text at the beginning of the current document's body. + const externalDocBodyText = externalDocBody.text; + const currentDocBody: Word.Body = context.document.body; + currentDocBody.insertText(externalDocBodyText, Word.InsertLocation.start); + await context.sync(); + }); +Word.Application#retrieveStylesFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/get-external-styles.yaml + + + // Gets style info from another document passed in as a Base64-encoded + string. + + await Word.run(async (context) => { + const retrievedStyles = context.application.retrieveStylesFromBase64(externalDocument); + await context.sync(); + + console.log("Styles from the other document:", retrievedStyles.value); + }); +Word.Body#clear:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Clears out the content from the document body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to clear the contents of the body. + body.clear(); + + console.log("Cleared the body contents."); + }); + + + // The Silly stories add-in sample shows how the clear method can be used to + clear the contents of a document. + + // https://aka.ms/sillystorywordaddin +Word.Body#getComments:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the comments in the document body. + + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.body.getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("All comments:", comments); + }); +Word.Body#getHtml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Gets the HTML that represents the content of the body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to get the HTML contents of the body. + const bodyHTML = body.getHtml(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (HTML): " + bodyHTML.value); + }); +Word.Body#getOoxml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Gets the OOXML that represents the content of the body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to get the OOXML contents of the body. + const bodyOOXML = body.getOoxml(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (OOXML): " + bodyOOXML.value); + }); +Word.Body#getTrackedChanges:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets all tracked changes. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.load(); + await context.sync(); + + console.log(trackedChanges); + }); +Word.Body#insertBreak:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts a page break at the beginning of the document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert a page break at the start of the document body. + body.insertBreak(Word.BreakType.page, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added a page break at the start of the document body."); + }); +Word.Body#insertContentControl:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Creates a content control using the document body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to wrap the body in a content control. + body.insertContentControl(); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Wrapped the body in a content control."); + }); +Word.Body#insertFileFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts the body from the external document at the beginning of this + document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert the Base64-encoded string representation of the body of the selected .docx file at the beginning of the current document. + body.insertFileFromBase64(externalDocument, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added Base64-encoded text to the beginning of the document body."); + }); +Word.Body#insertHtml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts the HTML at the beginning of this document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert HTML at the beginning of the document. + body.insertHtml("This is text inserted with body.insertHtml()", Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("HTML added to the beginning of the document body."); + }); +Word.Body#insertInlinePictureFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts an image inline at the beginning of this document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Base64-encoded image to insert inline. + const base64EncodedImg = + "iVBORw0KGgoAAAANSUhEUgAAAB4AAAANCAIAAAAxEEnAAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACFSURBVDhPtY1BEoQwDMP6/0+XgIMTBAeYoTqso9Rkx1zG+tNj1H94jgGzeNSjteO5vtQQuG2seO0av8LzGbe3anzRoJ4ybm/VeKEerAEbAUpW4aWQCmrGFWykRzGBCnYy2ha3oAIq2MloW9yCCqhgJ6NtcQsqoIKdjLbFLaiACnYyf2fODbrjZcXfr2F4AAAAAElFTkSuQmCC"; + + // Queue a command to insert a Base64-encoded image at the beginning of the current document. + body.insertInlinePictureFromBase64(base64EncodedImg, Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added a Base64-encoded image to the beginning of the document body."); + }); +Word.Body#insertOoxml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts OOXML at the beginning of this document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert OOXML at the beginning of the body. + body.insertOoxml( + "This text has formatting directly applied to achieve its font size, color, line spacing, and paragraph spacing.", + Word.InsertLocation.start + ); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Added OOXML to the beginning of the document body."); + }); + + + // Read "Understand when and how to use Office Open XML in your Word add-in" + for guidance on working with OOXML. + + // + https://learn.microsoft.com/office/dev/add-ins/word/create-better-add-ins-for-word-with-office-open-xml + + + // The Word-Add-in-DocumentAssembly sample shows how you can use this API to + assemble a document. + + // https://github.com/OfficeDev/Word-Add-in-DocumentAssembly +Word.Body#insertParagraph:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-formatted-text.yaml + + + await Word.run(async (context) => { + // Second sentence, let's insert it as a paragraph after the previously inserted one. + const secondSentence: Word.Paragraph = context.document.body.insertParagraph( + "This is the first text with a custom style.", + "End" + ); + secondSentence.font.set({ + bold: false, + italic: true, + name: "Berlin Sans FB", + color: "blue", + size: 30 + }); + + await context.sync(); + }); +Word.Body#insertTable:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + + + await Word.run(async (context) => { + // Use a two-dimensional array to hold the initial table values. + const data = [ + ["Tokyo", "Beijing", "Seattle"], + ["Apple", "Orange", "Pineapple"] + ]; + const table: Word.Table = context.document.body.insertTable(2, 3, "Start", data); + table.styleBuiltIn = Word.BuiltInStyleName.gridTable5Dark_Accent2; + table.styleFirstColumn = false; + + await context.sync(); + }); +Word.Body#insertText:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Inserts text at the beginning of this document. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to insert text at the beginning of the current document. + body.insertText('This is text inserted with body.insertText()', Word.InsertLocation.start); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Text added to the beginning of the document body."); + }); +Word.Body#search:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/search.yaml + + + // Does a basic text search and highlights matches in the document. + + await Word.run(async (context) => { + const results : Word.RangeCollection = context.document.body.search("extend"); + results.load("length"); + + await context.sync(); + + // Let's traverse the search results and highlight matches. + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.highlightColor = "yellow"; + } + + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/search.yaml + + + // Does a wildcard search and highlights matches in the document. + + await Word.run(async (context) => { + // Construct a wildcard expression and set matchWildcards to true in order to use wildcards. + const results : Word.RangeCollection = context.document.body.search("$*.[0-9][0-9]", { matchWildcards: true }); + results.load("length"); + + await context.sync(); + + // Let's traverse the search results and highlight matches. + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.highlightColor = "red"; + results.items[i].font.color = "white"; + } + + await context.sync(); + }); +Word.Body#select:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Selects the entire body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to select the document body. + // The Word UI will move to the selected document body. + body.select(); + + console.log("Selected the document body."); + }); +Word.Body#fields:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets all fields in the document body. + + await Word.run(async (context) => { + const fields: Word.FieldCollection = context.document.body.fields.load("items"); + + await context.sync(); + + if (fields.items.length === 0) { + console.log("No fields in this document."); + } else { + fields.load(["code", "result"]); + await context.sync(); + + for (let i = 0; i < fields.items.length; i++) { + console.log(`Field ${i + 1}'s code: ${fields.items[i].code}`, `Field ${i + 1}'s result: ${JSON.stringify(fields.items[i].result)}`); + } + } + }); +Word.Body#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Gets the style and the font size, font name, and font color properties on + the body object. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to load font and style information for the document body. + body.load("font/size, font/name, font/color, style"); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + // Show font-related property values on the body object. + const results = + "Font size: " + + body.font.size + + "; Font name: " + + body.font.name + + "; Font color: " + + body.font.color + + "; Body style: " + + body.style; + + console.log(results); + }); +Word.Body#footnotes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the footnotes in the document body. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("length"); + await context.sync(); + + console.log("Number of footnotes in the document body: " + footnotes.items.length); + }); +Word.Body#inlinePictures:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Gets the first image in the document. + + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); +Word.Body#lists:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Gets information about the first list in the document. + + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); +Word.Body#onCommentAdded:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.Body#onCommentChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onChangedHandler(event: Word.CommentEventArgs) { + await Word.run(async (context) => { + console.log( + `${event.type} event detected. ${event.changeType} change made. Event source: ${event.source}. Comment info:`, event.commentDetails + ); + }); + } +Word.Body#onCommentDeleted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.Body#onCommentDeselected:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.Body#onCommentSelected:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.Body#paragraphs:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-word-count.yaml + + + // Counts how many times each term appears in the document. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("text"); + await context.sync(); + + // Split up the document text using existing spaces as the delimiter. + let text = []; + paragraphs.items.forEach((item) => { + let paragraph = item.text.trim(); + if (paragraph) { + paragraph.split(" ").forEach((term) => { + let currentTerm = term.trim(); + if (currentTerm) { + text.push(currentTerm); + } + }); + } + }); + + // Determine the list of unique terms. + let makeTextDistinct = new Set(text); + let distinctText = Array.from(makeTextDistinct); + let allSearchResults = []; + + for (let i = 0; i < distinctText.length; i++) { + let results = context.document.body.search(distinctText[i], { matchCase: true, matchWholeWord: true }); + results.load("text"); + + // Map each search term with its results. + let correlatedResults = { + searchTerm: distinctText[i], + hits: results + }; + + allSearchResults.push(correlatedResults); + } + + await context.sync(); + + // Display the count for each search term. + allSearchResults.forEach((result) => { + let length = result.hits.items.length; + + console.log("Search term: " + result.searchTerm + " => Count: " + length); + }); + }); +Word.Body#shapes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text boxes in the main document. + const shapes: Word.ShapeCollection = context.document.body.shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the main document: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the main document has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the main document doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the main document."); + } + }); +Word.Body#tables:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + + + // Gets the content of the first cell in the first table. + + await Word.run(async (context) => { + const firstCell: Word.Body = context.document.body.tables.getFirst().getCell(0, 0).body; + firstCell.load("text"); + + await context.sync(); + console.log("First cell's text is: " + firstCell.text); + }); +Word.Body#text:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml + + + // Gets the text content of the body. + + // Run a batch operation against the Word object model. + + await Word.run(async (context) => { + // Create a proxy object for the document body. + const body: Word.Body = context.document.body; + + // Queue a command to load the text in document body. + body.load("text"); + + // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. + await context.sync(); + + console.log("Body contents (text): " + body.text); + }); +Word.Body#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the referenced note's item type and body type, which are both + "Footnote". + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + console.log(`Note type of footnote ${referenceNumber}: ${item.type}`); + + item.body.load("type"); + await context.sync(); + + console.log(`Body type of note: ${item.body.type}`); + }); +Word.BodyType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the referenced note's item type and body type, which are both + "Footnote". + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + console.log(`Note type of footnote ${referenceNumber}: ${item.type}`); + + item.body.load("type"); + await context.sync(); + + console.log(`Body type of note: ${item.body.type}`); + }); +Word.Border:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BorderCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BorderCollection#outsideBorderColor:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BorderCollection#outsideBorderType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BorderCollection#outsideBorderWidth:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BorderLocation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.BorderType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first of the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstCell: Word.TableCell = firstTable.getCell(0, 0); + const borderLocation = "Left"; + const border: Word.TableBorder = firstCell.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first cell:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.BorderWidth:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.BreakType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-line-and-page-breaks.yaml + + + await Word.run(async (context) => { + context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.page, "After"); + + await context.sync(); + console.log("success"); + }); +Word.BuiltInStyleName:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-formatted-text.yaml + + + await Word.run(async (context) => { + const sentence: Word.Paragraph = context.document.body.insertParagraph( + "To be or not to be", + "End" + ); + + // Use styleBuiltIn to use an enumeration of existing styles. If your style is custom make sure to use: range.style = "name of your style"; + sentence.styleBuiltIn = Word.BuiltInStyleName.intenseReference; + + await context.sync(); + }); +Word.Canvas:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-canvases.yaml + + + await Word.run(async (context) => { + // Inserts a canvas in the document. + const canvasShape: Word.Shape = context.document.getSelection().insertCanvas(); + canvasShape.load(); + await context.sync(); + + canvasShape.select(); + console.log("Inserted canvas:", canvasShape); + + const canvas: Word.Canvas = canvasShape.canvas; + canvas.load("shape,shapes"); + await context.sync(); + + console.log("Canvas object:", canvas); + }); +Word.Canvas#shapes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-canvases.yaml + + + await Word.run(async (context) => { + // Gets the first canvas found in the document body. + const canvasShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.canvas]) + .getFirstOrNullObject(); + canvasShape.load(); + canvasShape.load("canvas/shapes"); + await context.sync(); + + if (canvasShape.isNullObject) { + console.log("No canvases found in the document body."); + return; + } + + console.log("First canvas found in the document body:", canvasShape); + console.log("Shapes associated with the first canvas:", canvasShape.canvas.shapes); + canvasShape.select(); + }); +Word.CellPaddingLocation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets cell padding details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const cellPaddingLocation = Word.CellPaddingLocation.right; + const cellPadding = firstTable.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table: ${cellPadding.value} points` + ); + }); +Word.ChangeTrackingMode:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + + + // Gets the current change tracking mode. + + await Word.run(async (context) => { + const document: Word.Document = context.document; + document.load("changeTrackingMode"); + await context.sync(); + + if (document.changeTrackingMode === Word.ChangeTrackingMode.trackMineOnly) { + console.log("Only my changes are being tracked."); + } else if (document.changeTrackingMode === Word.ChangeTrackingMode.trackAll) { + console.log("Everyone's changes are being tracked."); + } else { + console.log("No changes are being tracked."); + } + }); +Word.ChangeTrackingState:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/get-change-tracking-states.yaml + + + // Logs the current change tracking states of the content controls. + + await Word.run(async (context) => { + let trackAddedArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.added]; + let trackDeletedArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.deleted]; + let trackNormalArray: Word.ChangeTrackingState[] = [Word.ChangeTrackingState.normal]; + + let addedContentControls = context.document.body.getContentControls().getByChangeTrackingStates(trackAddedArray); + let deletedContentControls = context.document.body + .getContentControls() + .getByChangeTrackingStates(trackDeletedArray); + let normalContentControls = context.document.body.getContentControls().getByChangeTrackingStates(trackNormalArray); + + addedContentControls.load(); + deletedContentControls.load(); + normalContentControls.load(); + await context.sync(); + + console.log(`Number of content controls in Added state: ${addedContentControls.items.length}`); + console.log(`Number of content controls in Deleted state: ${deletedContentControls.items.length}`); + console.log(`Number of content controls in Normal state: ${normalContentControls.items.length}`); + }); +Word.ChangeTrackingVersion:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + + + // Gets the reviewed text. + + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection(); + const before = range.getReviewedText(Word.ChangeTrackingVersion.original); + const after = range.getReviewedText(Word.ChangeTrackingVersion.current); + + await context.sync(); + + console.log("Reviewed text (before):", before.value, "Reviewed text (after):", after.value); + }); +Word.CheckboxContentControl:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property on all checkbox content controls. + + await Word.run(async (context) => { + let contentControls = context.document.getContentControls({ + types: [Word.ContentControlType.checkBox] + }); + contentControls.load("items"); + + await context.sync(); + + const length = contentControls.items.length; + console.log(`Number of checkbox content controls: ${length}`); + + if (length <= 0) { + return; + } + + const checkboxContentControls = []; + for (let i = 0; i < length; i++) { + let contentControl = contentControls.items[i]; + contentControl.load("id,checkboxContentControl/isChecked"); + checkboxContentControls.push(contentControl); + } + + await context.sync(); + + console.log("isChecked state before:"); + const updatedCheckboxContentControls = []; + for (let i = 0; i < checkboxContentControls.length; i++) { + const currentCheckboxContentControl = checkboxContentControls[i]; + const isCheckedBefore = currentCheckboxContentControl.checkboxContentControl.isChecked; + console.log(`id: ${currentCheckboxContentControl.id} ... isChecked: ${isCheckedBefore}`); + + currentCheckboxContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + currentCheckboxContentControl.load("id,checkboxContentControl/isChecked"); + updatedCheckboxContentControls.push(currentCheckboxContentControl); + } + + await context.sync(); + + console.log("isChecked state after:"); + for (let i = 0; i < updatedCheckboxContentControls.length; i++) { + const currentCheckboxContentControl = updatedCheckboxContentControls[i]; + console.log( + `id: ${currentCheckboxContentControl.id} ... isChecked: ${currentCheckboxContentControl.checkboxContentControl.isChecked}` + ); + } + }); +Word.CloseBehavior:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml + + + // Closes the document after saving. + + await Word.run(async (context) => { + context.document.close(Word.CloseBehavior.save); + }); +Word.ComboBoxContentControl:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Places a combo box content control at the end of the selection. + + await Word.run(async (context) => { + let selection = context.document.getSelection(); + selection.getRange(Word.RangeLocation.end).insertContentControl(Word.ContentControlType.comboBox); + await context.sync(); + + console.log("Combo box content control inserted at the end of the selection."); + }); +Word.ComboBoxContentControl#addListItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Adds the provided list item to the first combo box content control in the + selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.comboBoxContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ComboBoxContentControl#deleteAllListItems:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Deletes the list items from first combo box content control found in the + selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete the list from the combo box content control with ID ${selectedContentControl.id}`); + selectedContentControl.comboBoxContentControl.deleteAllListItems(); + await context.sync(); + + console.log("Deleted the list from the combo box content control."); + }); +Word.ComboBoxContentControl#listItems:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Deletes the provided list item from the first combo box content control + in the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedComboBox: Word.ComboBoxContentControl = selectedContentControl.comboBoxContentControl; + selectedComboBox.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.comboBoxContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`); + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.Comment:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Sets a comment on the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("comment-text") as HTMLInputElement).value; + const comment: Word.Comment = context.document.getSelection().insertComment(text); + + // Load object to log in the console. + comment.load(); + await context.sync(); + + console.log("Comment inserted:", comment); + }); +Word.Comment#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Deletes the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.delete(); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to delete."); + return; + } + + console.log("Comment deleted."); + }); +Word.Comment#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the range of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); +Word.Comment#reply:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Replies to the first active comment in the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); +Word.Comment#content:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Edits the first active comment in the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("edit-comment-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (!firstActiveComment) { + console.warn("No active comment was found in the selection, so couldn't edit."); + return; + } + + firstActiveComment.content = text; + + // Load object to log in the console. + firstActiveComment.load(); + await context.sync(); + + console.log("Comment content changed:", firstActiveComment); + }); +Word.Comment#contentRange:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the range of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); +Word.Comment#replies:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the replies to the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("replies"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no replies to get."); + return; + } + + const replies: Word.CommentReplyCollection = comment.replies; + console.log("Replies to the first comment:", replies); + }); +Word.Comment#resolved:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Toggles Resolved status of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document + .getSelection() + .getComments() + .getFirstOrNullObject(); + comment.load("resolved"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so nothing to toggle."); + return; + } + + // Toggle resolved status. + // If the comment is active, set as resolved. + // If it's resolved, set resolved to false. + const resolvedBefore = comment.resolved; + console.log(`Comment Resolved status (before): ${resolvedBefore}`); + comment.resolved = !resolvedBefore; + comment.load("resolved"); + await context.sync(); + + console.log(`Comment Resolved status (after): ${comment.resolved}`); + }); +Word.CommentChangeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onChangedHandler(event: Word.CommentEventArgs) { + await Word.run(async (context) => { + console.log( + `${event.type} event detected. ${event.changeType} change made. Event source: ${event.source}. Comment info:`, event.commentDetails + ); + }); + } +Word.CommentCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Replies to the first active comment in the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); +Word.CommentCollection#getFirstOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the range of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); +Word.CommentCollection#items:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Replies to the first active comment in the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); +Word.CommentContentRange:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the range of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); +Word.CommentDetail:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.CommentEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onChangedHandler(event: Word.CommentEventArgs) { + await Word.run(async (context) => { + console.log( + `${event.type} event detected. ${event.changeType} change made. Event source: ${event.source}. Comment info:`, event.commentDetails + ); + }); + } +Word.CommentReply:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Replies to the first active comment in the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("reply-text") as HTMLInputElement).value; + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + comments.load("items"); + await context.sync(); + + const firstActiveComment: Word.Comment = comments.items.find((item) => item.resolved !== true); + if (firstActiveComment) { + const reply: Word.CommentReply = firstActiveComment.reply(text); + console.log("Reply added."); + } else { + console.warn("No active comment was found in the selection, so couldn't reply."); + } + }); +Word.CommentReplyCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the replies to the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("replies"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no replies to get."); + return; + } + + const replies: Word.CommentReplyCollection = comment.replies; + console.log("Replies to the first comment:", replies); + }); +Word.CompareTarget:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/compare-documents.yaml + + + // Compares the current document with a specified external document. + + await Word.run(async (context) => { + // Absolute path of an online or local document. + const filePath = (document.getElementById("filePath") as HTMLInputElement).value; + // Options that configure the compare operation. + const options: Word.DocumentCompareOptions = { + compareTarget: Word.CompareTarget.compareTargetCurrent, + detectFormatChanges: false + // Other options you choose... + }; + context.document.compare(filePath, options); + + await context.sync(); + + console.log("Differences shown in the current document."); + }); +Word.ContentControl#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("forTesting"); + contentControls.load("items"); + await context.sync(); + + if (contentControls.items.length === 0) { + console.log("There are no content controls in this document."); + } else { + console.log("Control to be deleted:", contentControls.items[0]); + contentControls.items[0].delete(false); + await context.sync(); + } + }); +Word.ContentControl#resetState:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/insert-and-change-content-controls.yaml + + + // Resets the state of the first content control. + + await Word.run(async (context) => { + let firstContentControl = context.document.contentControls.getFirstOrNullObject(); + await context.sync(); + + if (firstContentControl.isNullObject) { + console.warn("There are no content controls in this document."); + return; + } + + firstContentControl.resetState(); + firstContentControl.load("id"); + await context.sync(); + + console.log(`Reset state of first content control with ID: ${firstContentControl.id}`); + }); +Word.ContentControl#set:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml + + + // Adds title and colors to odd and even content controls and changes their + appearance. + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + let evenContentControls = context.document.contentControls.getByTag("even"); + let oddContentControls = context.document.contentControls.getByTag("odd"); + evenContentControls.load("length"); + oddContentControls.load("length"); + + await context.sync(); + + for (let i = 0; i < evenContentControls.items.length; i++) { + // Change a few properties and append a paragraph. + evenContentControls.items[i].set({ + color: "red", + title: "Odd ContentControl #" + (i + 1), + appearance: Word.ContentControlAppearance.tags + }); + evenContentControls.items[i].insertParagraph("This is an odd content control", "End"); + } + + for (let j = 0; j < oddContentControls.items.length; j++) { + // Change a few properties and append a paragraph. + oddContentControls.items[j].set({ + color: "green", + title: "Even ContentControl #" + (j + 1), + appearance: "Tags" + }); + oddContentControls.items[j].insertHtml("This is an even content control", "End"); + } + + await context.sync(); + }); +Word.ContentControl#setState:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/insert-and-change-content-controls.yaml + + + // Sets the state of the first content control. + + await Word.run(async (context) => { + const state = ((document.getElementById("state-to-set") as HTMLSelectElement) + .value as unknown) as Word.ContentControlState; + let firstContentControl = context.document.contentControls.getFirstOrNullObject(); + await context.sync(); + + if (firstContentControl.isNullObject) { + console.warn("There are no content controls in this document."); + return; + } + + firstContentControl.setState(state); + firstContentControl.load("id"); + await context.sync(); + + console.log(`Set state of first content control with ID ${firstContentControl.id} to ${state}.`); + }); +Word.ContentControl#checkboxContentControl:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property of the first checkbox content control + found in the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,checkboxContentControl/isChecked"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,checkboxContentControl/isChecked"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + const isCheckedBefore = selectedContentControl.checkboxContentControl.isChecked; + console.log("isChecked state before:", `id: ${selectedContentControl.id} ... isChecked: ${isCheckedBefore}`); + selectedContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + selectedContentControl.load("id,checkboxContentControl/isChecked"); + await context.sync(); + + console.log( + "isChecked state after:", + `id: ${selectedContentControl.id} ... isChecked: ${selectedContentControl.checkboxContentControl.isChecked}` + ); + }); +Word.ContentControl#comboBoxContentControl:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Adds the provided list item to the first combo box content control in the + selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.comboBoxContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ContentControl#dropDownListContentControl:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Adds the provided list item to the first dropdown list content control in + the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.dropDownListContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ContentControl#onDataChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDataChanged event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDataChanged.add(contentControlDataChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when data is changed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + + + async function contentControlDataChanged(event: + Word.ContentControlDataChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where data was changed:`, event.ids); + }); + } +Word.ContentControl#onDeleted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDeleted event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDeleted.add(contentControlDeleted); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when content controls are deleted."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + async function contentControlDeleted(event: + Word.ContentControlDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were deleted:`, event.ids); + }); + } +Word.ContentControl#onEntered:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onEntered event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onEntered.add(contentControlEntered); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is placed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml + + + async function contentControlEntered(event: + Word.ContentControlEnteredEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was entered: ${event.ids[0]}`); + }); + } +Word.ContentControl#onExited:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onExited event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onExited.add(contentControlExited); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is removed from within content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml + + + async function contentControlExited(event: + Word.ContentControlExitedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was exited: ${event.ids[0]}`); + }); + } +Word.ContentControl#onSelectionChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onSelectionChanged.add(contentControlSelectionChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when selections are changed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + + + async function contentControlSelectionChanged(event: + Word.ContentControlSelectionChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where selection was changed:`, event.ids); + }); + } +Word.ContentControl#tag:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml + + + // Traverses each paragraph of the document and wraps a content control on + each with either a even or odd tags. + + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + // For even, tag "even". + if (i % 2 === 0) { + contentControl.tag = "even"; + } else { + contentControl.tag = "odd"; + } + } + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); +Word.ContentControlAddedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml + + + // Registers the onAdded event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onContentControlAdded.add(contentControlAdded); + await context.sync(); + + console.log("Added event handler for when content controls are added."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml + + + async function contentControlAdded(event: Word.ContentControlAddedEventArgs) + { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were added:`, event.ids); + }); + } +Word.ContentControlAppearance:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml + + + // Adds title and colors to odd and even content controls and changes their + appearance. + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + let evenContentControls = context.document.contentControls.getByTag("even"); + let oddContentControls = context.document.contentControls.getByTag("odd"); + evenContentControls.load("length"); + oddContentControls.load("length"); + + await context.sync(); + + for (let i = 0; i < evenContentControls.items.length; i++) { + // Change a few properties and append a paragraph. + evenContentControls.items[i].set({ + color: "red", + title: "Odd ContentControl #" + (i + 1), + appearance: Word.ContentControlAppearance.tags + }); + evenContentControls.items[i].insertParagraph("This is an odd content control", "End"); + } + + for (let j = 0; j < oddContentControls.items.length; j++) { + // Change a few properties and append a paragraph. + oddContentControls.items[j].set({ + color: "green", + title: "Even ContentControl #" + (j + 1), + appearance: "Tags" + }); + oddContentControls.items[j].insertHtml("This is an even content control", "End"); + } + + await context.sync(); + }); +Word.ContentControlCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("customer"); + contentControls.load("text"); + + await context.sync(); + + for (let i = 0; i < contentControls.items.length; i++) { + contentControls.items[i].insertText("Fabrikam", "Replace"); + } + + await context.sync(); + }); +Word.ContentControlCollection#getByTag:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("customer"); + contentControls.load("text"); + + await context.sync(); + + for (let i = 0; i < contentControls.items.length; i++) { + contentControls.items[i].insertText("Fabrikam", "Replace"); + } + + await context.sync(); + }); +Word.ContentControlCollection#getFirstOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property of the first checkbox content control + found in the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,checkboxContentControl/isChecked"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,checkboxContentControl/isChecked"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + const isCheckedBefore = selectedContentControl.checkboxContentControl.isChecked; + console.log("isChecked state before:", `id: ${selectedContentControl.id} ... isChecked: ${isCheckedBefore}`); + selectedContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + selectedContentControl.load("id,checkboxContentControl/isChecked"); + await context.sync(); + + console.log( + "isChecked state after:", + `id: ${selectedContentControl.id} ... isChecked: ${selectedContentControl.checkboxContentControl.isChecked}` + ); + }); +Word.ContentControlDataChangedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDataChanged event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDataChanged.add(contentControlDataChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when data is changed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml + + + async function contentControlDataChanged(event: + Word.ContentControlDataChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where data was changed:`, event.ids); + }); + } +Word.ContentControlDeletedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onDeleted event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onDeleted.add(contentControlDeleted); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when content controls are deleted."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + async function contentControlDeleted(event: + Word.ContentControlDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were deleted:`, event.ids); + }); + } +Word.ContentControlEnteredEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onEntered event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onEntered.add(contentControlEntered); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is placed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml + + + async function contentControlEntered(event: + Word.ContentControlEnteredEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was entered: ${event.ids[0]}`); + }); + } +Word.ContentControlExitedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + // Register the onExited event handler on each content control. + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onExited.add(contentControlExited); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when the cursor is removed from within content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml + + + async function contentControlExited(event: + Word.ContentControlExitedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. ID of content control that was exited: ${event.ids[0]}`); + }); + } +Word.ContentControlListItem:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Deletes the provided list item from the first dropdown list content + control in the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedDropdownList: Word.DropDownListContentControl = selectedContentControl.dropDownListContentControl; + selectedDropdownList.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.dropDownListContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`) + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ContentControlListItem#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Deletes the provided list item from the first combo box content control + in the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedComboBox: Word.ComboBoxContentControl = selectedContentControl.comboBoxContentControl; + selectedComboBox.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.comboBoxContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`); + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ContentControlListItem#displayText:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Deletes the provided list item from the first dropdown list content + control in the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedDropdownList: Word.DropDownListContentControl = selectedContentControl.dropDownListContentControl; + selectedDropdownList.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.dropDownListContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`) + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ContentControlListItemCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml + + + // Gets the list items from the first combo box content control found in the + selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.comboBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,comboBoxContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,comboBoxContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.comboBox) { + console.warn("No combo box content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedComboBox: Word.ComboBoxContentControl = selectedContentControl.comboBoxContentControl; + selectedComboBox.listItems.load("items"); + await context.sync(); + + const currentItems: Word.ContentControlListItemCollection = selectedComboBox.listItems; + console.log(`The list from the combo box content control with ID ${selectedContentControl.id}:`, currentItems); + }); +Word.ContentControlOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property of the first checkbox content control + found in the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,checkboxContentControl/isChecked"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,checkboxContentControl/isChecked"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + const isCheckedBefore = selectedContentControl.checkboxContentControl.isChecked; + console.log("isChecked state before:", `id: ${selectedContentControl.id} ... isChecked: ${isCheckedBefore}`); + selectedContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + selectedContentControl.load("id,checkboxContentControl/isChecked"); + await context.sync(); + + console.log( + "isChecked state after:", + `id: ${selectedContentControl.id} ... isChecked: ${selectedContentControl.checkboxContentControl.isChecked}` + ); + }); +Word.ContentControlSelectionChangedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + + + await Word.run(async (context) => { + const contentControls: Word.ContentControlCollection = context.document.contentControls; + contentControls.load("items"); + await context.sync(); + + if (contentControls.items.length === 0) { + console.log("There aren't any content controls in this document so can't register event handlers."); + } else { + for (let i = 0; i < contentControls.items.length; i++) { + eventContexts[i] = contentControls.items[i].onSelectionChanged.add(contentControlSelectionChanged); + contentControls.items[i].track(); + } + + await context.sync(); + + console.log("Added event handlers for when selections are changed in content controls."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml + + + async function contentControlSelectionChanged(event: + Word.ContentControlSelectionChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls where selection was changed:`, event.ids); + }); + } +Word.ContentControlState:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/insert-and-change-content-controls.yaml + + + // Sets the state of the first content control. + + await Word.run(async (context) => { + const state = ((document.getElementById("state-to-set") as HTMLSelectElement) + .value as unknown) as Word.ContentControlState; + let firstContentControl = context.document.contentControls.getFirstOrNullObject(); + await context.sync(); + + if (firstContentControl.isNullObject) { + console.warn("There are no content controls in this document."); + return; + } + + firstContentControl.setState(state); + firstContentControl.load("id"); + await context.sync(); + + console.log(`Set state of first content control with ID ${firstContentControl.id} to ${state}.`); + }); +Word.ContentControlType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Traverses each paragraph of the document and places a checkbox content + control at the beginning of each. + + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just start each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i] + .getRange(Word.RangeLocation.start) + .insertContentControl(Word.ContentControlType.checkBox); + } + console.log("Checkbox content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); +Word.Critique:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Adds annotations to the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); +Word.CritiqueAnnotation:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Gets annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); +Word.CritiqueAnnotation#accept:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Accepts the first annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Accepting ID ${annotation.id}...`); + annotation.critiqueAnnotation.accept(); + + await context.sync(); + break; + } + } + }); +Word.CritiqueAnnotation#reject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Rejects the last annotation found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + for (let i = annotations.items.length - 1; i >= 0; i--) { + const annotation: Word.Annotation = annotations.items[i]; + + if (annotation.state === Word.AnnotationState.created) { + console.log(`Rejecting ID ${annotation.id}...`); + annotation.critiqueAnnotation.reject(); + + await context.sync(); + break; + } + } + }); +Word.CritiqueAnnotation#critique:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Gets annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); +Word.CritiqueColorScheme:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Adds annotations to the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); +Word.CritiquePopupOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Adds annotations to the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); +Word.CustomProperty:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + const properties: Word.CustomPropertyCollection = context.document.properties.customProperties; + properties.load("key,type,value"); + + await context.sync(); + for (let i = 0; i < properties.items.length; i++) + console.log("Property Name:" + properties.items[i].key + "; Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].value); + }); +Word.CustomPropertyCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + const properties: Word.CustomPropertyCollection = context.document.properties.customProperties; + properties.load("key,type,value"); + + await context.sync(); + for (let i = 0; i < properties.items.length; i++) + console.log("Property Name:" + properties.items[i].key + "; Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].value); + }); +Word.CustomPropertyCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + context.document.properties.customProperties.add("Numeric Property", 1234); + + await context.sync(); + console.log("Property added"); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + context.document.properties.customProperties.add("String Property", "Hello World!"); + + await context.sync(); + console.log("Property added"); + }); +Word.CustomPropertyCollection#items:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + const properties: Word.CustomPropertyCollection = context.document.properties.customProperties; + properties.load("key,type,value"); + + await context.sync(); + for (let i = 0; i < properties.items.length; i++) + console.log("Property Name:" + properties.items[i].key + "; Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].value); + }); +Word.CustomXmlPart:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Adds a custom XML part. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load("id"); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Added custom XML part:", readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Word.CustomXmlPart#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Original XML: + JuanHongSally + + + // Deletes a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + let customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xmlBlob = customXmlPart.getXml(); + customXmlPart.delete(); + customXmlPart = context.document.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); + + await context.sync(); + + if (customXmlPart.isNullObject) { + console.log(`The XML part with the ID ${xmlPartIDSetting.value} has been deleted.`); + + // Delete the associated setting too. + xmlPartIDSetting.delete(); + + await context.sync(); + } else { + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.error(`This is strange. The XML part with the id ${xmlPartIDSetting.value} wasn't deleted:`, readableXml); + } + } else { + console.warn("Didn't find custom XML part to delete."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Deletes a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + let customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xmlBlob = customXmlPart.getXml(); + customXmlPart.delete(); + customXmlPart = context.document.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value); + + await context.sync(); + + if (customXmlPart.isNullObject) { + console.log(`The XML part with the ID ${xmlPartIDSetting.value} has been deleted.`); + + // Delete the associated setting too. + xmlPartIDSetting.delete(); + + await context.sync(); + } else { + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.error( + `This is strange. The XML part with the id ${xmlPartIDSetting.value} wasn't deleted:`, + readableXml + ); + } + } else { + console.warn("Didn't find custom XML part to delete."); + } + }); +Word.CustomXmlPart#getXml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Adds a custom XML part. + + // If you want to populate the CustomXml.namespaceUri property, you must + include the xmlns attribute. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load(["id", "namespaceUri"]); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log(`Added custom XML part with namespace URI ${customXmlPart.namespaceUri}:`, readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartIdNS", customXmlPart.id); + + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Adds a custom XML part. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load("id"); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Added custom XML part:", readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Word.CustomXmlPart#insertAttribute:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Inserts an attribute into a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertAttribute method inserts an attribute with the given name and value into the element identified by the xpath parameter. + customXmlPart.insertAttribute( + "/contoso:Reviewers", + { contoso: "http://schemas.contoso.com/review/1.0" }, + "Nation", + "US" + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted attribute:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert attribute into."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Original XML: + JuanHongSally + + + // Inserts an attribute into a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertAttribute method inserts an attribute with the given name and value into the element identified by the xpath parameter. + customXmlPart.insertAttribute("/Reviewers", { contoso: "http://schemas.contoso.com/review/1.0" }, "Nation", "US"); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted attribute:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert attribute into."); + } + }); +Word.CustomXmlPart#insertElement:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Inserts an element into a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertElement method inserts the given XML under the parent element identified by the xpath parameter at the provided child position index. + customXmlPart.insertElement( + "/contoso:Reviewers", + "Mark", + { contoso: "http://schemas.contoso.com/review/1.0" }, + 0 + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted element:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert element into."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Original XML: + JuanHongSally + + + // Inserts an element into a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + + // The insertElement method inserts the given XML under the parent element identified by the xpath parameter at the provided child position index. + customXmlPart.insertElement( + "/Reviewers", + "Mark", + { contoso: "http://schemas.contoso.com/review/1.0" }, + 0 + ); + const xmlBlob = customXmlPart.getXml(); + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Successfully inserted element:", readableXml); + } else { + console.warn("Didn't find custom XML part to insert element into."); + } + }); +Word.CustomXmlPart#query:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Queries a custom XML part for elements matching the search terms. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/contoso:Reviewers"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Original XML: + JuanHongSally + + + // Queries a custom XML part for elements matching the search terms. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/Reviewers/Reviewer"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); +Word.CustomXmlPart#setXml:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Replaces a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const originalXmlBlob = customXmlPart.getXml(); + await context.sync(); + + let readableXml = addLineBreaksToXML(originalXmlBlob.value); + console.log("Original custom XML part:", readableXml); + + // The setXml method replaces the entire XML part. + customXmlPart.setXml( + "JohnHitomi" + ); + const updatedXmlBlob = customXmlPart.getXml(); + await context.sync(); + + readableXml = addLineBreaksToXML(updatedXmlBlob.value); + console.log("Replaced custom XML part:", readableXml); + } else { + console.warn("Didn't find custom XML part to replace."); + } + }); +Word.CustomXmlPart#id:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Adds a custom XML part. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load("id"); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Added custom XML part:", readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Word.CustomXmlPart#namespaceUri:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Gets the namespace URI from a custom XML part. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + customXmlPart.load("namespaceUri"); + await context.sync(); + + const namespaceUri = customXmlPart.namespaceUri; + console.log(`Namespace URI: ${JSON.stringify(namespaceUri)}`); + } else { + console.warn("Didn't find custom XML part."); + } + }); +Word.CustomXmlPartCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Adds a custom XML part. + + // If you want to populate the CustomXml.namespaceUri property, you must + include the xmlns attribute. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load(["id", "namespaceUri"]); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log(`Added custom XML part with namespace URI ${customXmlPart.namespaceUri}:`, readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartIdNS", customXmlPart.id); + + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Adds a custom XML part. + + await Word.run(async (context) => { + const originalXml = + "JuanHongSally"; + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.add(originalXml); + customXmlPart.load("id"); + const xmlBlob = customXmlPart.getXml(); + + await context.sync(); + + const readableXml = addLineBreaksToXML(xmlBlob.value); + console.log("Added custom XML part:", readableXml); + + // Store the XML part's ID in a setting so the ID is available to other functions. + const settings: Word.SettingCollection = context.document.settings; + settings.add("ContosoReviewXmlPartId", customXmlPart.id); + + await context.sync(); + }); +Word.CustomXmlPartCollection#getByNamespace:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Gets the custom XML parts with the specified namespace URI. + + await Word.run(async (context) => { + const namespaceUri = "http://schemas.contoso.com/review/1.0"; + console.log(`Specified namespace URI: ${namespaceUri}`); + const scopedCustomXmlParts: Word.CustomXmlPartScopedCollection = + context.document.customXmlParts.getByNamespace(namespaceUri); + scopedCustomXmlParts.load("items"); + await context.sync(); + + console.log(`Number of custom XML parts found with this namespace: ${!scopedCustomXmlParts.items ? 0 : scopedCustomXmlParts.items.length}`); + }); +Word.CustomXmlPartCollection#getItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Queries a custom XML part for elements matching the search terms. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartIdNS").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/contoso:Reviewers"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml + + + // Original XML: + JuanHongSally + + + // Queries a custom XML part for elements matching the search terms. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + const xmlPartIDSetting: Word.Setting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value"); + + await context.sync(); + + if (xmlPartIDSetting.value) { + const customXmlPart: Word.CustomXmlPart = context.document.customXmlParts.getItem(xmlPartIDSetting.value); + const xpathToQueryFor = "/Reviewers/Reviewer"; + const clientResult = customXmlPart.query(xpathToQueryFor, { + contoso: "http://schemas.contoso.com/review/1.0" + }); + + await context.sync(); + + console.log(`Queried custom XML part for ${xpathToQueryFor} and found ${clientResult.value.length} matches:`); + for (let i = 0; i < clientResult.value.length; i++) { + console.log(clientResult.value[i]); + } + } else { + console.warn("Didn't find custom XML part to query."); + } + }); +Word.CustomXmlPartScopedCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml + + + // Original XML: JuanHongSally + + + // Gets the custom XML parts with the specified namespace URI. + + await Word.run(async (context) => { + const namespaceUri = "http://schemas.contoso.com/review/1.0"; + console.log(`Specified namespace URI: ${namespaceUri}`); + const scopedCustomXmlParts: Word.CustomXmlPartScopedCollection = + context.document.customXmlParts.getByNamespace(namespaceUri); + scopedCustomXmlParts.load("items"); + await context.sync(); + + console.log(`Number of custom XML parts found with this namespace: ${!scopedCustomXmlParts.items ? 0 : scopedCustomXmlParts.items.length}`); + }); +Word.Document:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + + + // Gets the current change tracking mode. + + await Word.run(async (context) => { + const document: Word.Document = context.document; + document.load("changeTrackingMode"); + await context.sync(); + + if (document.changeTrackingMode === Word.ChangeTrackingMode.trackMineOnly) { + console.log("Only my changes are being tracked."); + } else if (document.changeTrackingMode === Word.ChangeTrackingMode.trackAll) { + console.log("Everyone's changes are being tracked."); + } else { + console.log("No changes are being tracked."); + } + }); +Word.Document#addStyle:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Adds a new style. + + await Word.run(async (context) => { + const newStyleName = (document.getElementById("new-style-name") as HTMLInputElement).value; + if (newStyleName == "") { + console.warn("Enter a style name to add."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(newStyleName); + style.load(); + await context.sync(); + + if (!style.isNullObject) { + console.warn( + `There's an existing style with the same name '${newStyleName}'! Please provide another style name.` + ); + return; + } + + const newStyleType = ((document.getElementById("new-style-type") as HTMLSelectElement).value as unknown) as Word.StyleType; + context.document.addStyle(newStyleName, newStyleType); + await context.sync(); + + console.log(newStyleName + " has been added to the style list."); + }); +Word.Document#close:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml + + + // Closes the document with default behavior + + // for current state of the document. + + await Word.run(async (context) => { + context.document.close(); + }); +Word.Document#compare:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/compare-documents.yaml + + + // Compares the current document with a specified external document. + + await Word.run(async (context) => { + // Absolute path of an online or local document. + const filePath = (document.getElementById("filePath") as HTMLInputElement).value; + // Options that configure the compare operation. + const options: Word.DocumentCompareOptions = { + compareTarget: Word.CompareTarget.compareTargetCurrent, + detectFormatChanges: false + // Other options you choose... + }; + context.document.compare(filePath, options); + + await context.sync(); + + console.log("Differences shown in the current document."); + }); +Word.Document#getContentControls:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property on all checkbox content controls. + + await Word.run(async (context) => { + let contentControls = context.document.getContentControls({ + types: [Word.ContentControlType.checkBox] + }); + contentControls.load("items"); + + await context.sync(); + + const length = contentControls.items.length; + console.log(`Number of checkbox content controls: ${length}`); + + if (length <= 0) { + return; + } + + const checkboxContentControls = []; + for (let i = 0; i < length; i++) { + let contentControl = contentControls.items[i]; + contentControl.load("id,checkboxContentControl/isChecked"); + checkboxContentControls.push(contentControl); + } + + await context.sync(); + + console.log("isChecked state before:"); + const updatedCheckboxContentControls = []; + for (let i = 0; i < checkboxContentControls.length; i++) { + const currentCheckboxContentControl = checkboxContentControls[i]; + const isCheckedBefore = currentCheckboxContentControl.checkboxContentControl.isChecked; + console.log(`id: ${currentCheckboxContentControl.id} ... isChecked: ${isCheckedBefore}`); + + currentCheckboxContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + currentCheckboxContentControl.load("id,checkboxContentControl/isChecked"); + updatedCheckboxContentControls.push(currentCheckboxContentControl); + } + + await context.sync(); + + console.log("isChecked state after:"); + for (let i = 0; i < updatedCheckboxContentControls.length; i++) { + const currentCheckboxContentControl = updatedCheckboxContentControls[i]; + console.log( + `id: ${currentCheckboxContentControl.id} ... isChecked: ${currentCheckboxContentControl.checkboxContentControl.isChecked}` + ); + } + }); +Word.Document#getParagraphByUniqueLocalId:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + + + await Word.run(async (context) => { + const paragraphId = (document.getElementById("paragraph-id") as HTMLInputElement).value; + const paragraph: Word.Paragraph = context.document.getParagraphByUniqueLocalId(paragraphId); + paragraph.load(); + await paragraph.context.sync(); + + console.log(paragraph); + }); +Word.Document#getStyles:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Gets the number of available styles stored with the document. + + await Word.run(async (context) => { + const styles: Word.StyleCollection = context.document.getStyles(); + const count = styles.getCount(); + await context.sync(); + + console.log(`Number of styles: ${count.value}`); + }); +Word.Document#importStylesFromJson:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml + + + // Imports styles from JSON. + + await Word.run(async (context) => { + const str = + '{"styles":[{"baseStyle":"Default Paragraph Font","builtIn":false,"inUse":true,"linked":false,"nameLocal":"NewCharStyle","priority":2,"quickStyle":true,"type":"Character","unhideWhenUsed":false,"visibility":false,"paragraphFormat":null,"font":{"name":"DengXian Light","size":16.0,"bold":true,"italic":false,"color":"#F1A983","underline":"None","subscript":false,"superscript":true,"strikeThrough":true,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#FF0000"}},{"baseStyle":"Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewParaStyle","nameLocal":"NewParaStyle","priority":1,"quickStyle":true,"type":"Paragraph","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Centered","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":72.0,"lineSpacing":18.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":72.0,"spaceAfter":30.0,"spaceBefore":30.0,"widowControl":true},"font":{"name":"DengXian","size":14.0,"bold":true,"italic":true,"color":"#8DD873","underline":"Single","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":true,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#00FF00"}},{"baseStyle":"Table Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewTableStyle","nameLocal":"NewTableStyle","priority":100,"type":"Table","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Left","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":0.0,"lineSpacing":12.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":0.0,"spaceAfter":0.0,"spaceBefore":0.0,"widowControl":true},"font":{"name":"DengXian","size":20.0,"bold":false,"italic":true,"color":"#D86DCB","underline":"None","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"tableStyle":{"allowBreakAcrossPage":true,"alignment":"Left","bottomCellMargin":0.0,"leftCellMargin":0.08,"rightCellMargin":0.08,"topCellMargin":0.0,"cellSpacing":0.0},"shading":{"backgroundPatternColor":"#60CAF3"}}]}'; + const styles = context.document.importStylesFromJson(str); + + // If you'd like to set how conflicting styles are handled, use the importedStylesConflictBehavior parameter that was introduced in the Desktop 1.1 requirement set. "Ignore" is the default. + ////const styles = context.document.importStylesFromJson(str, Word.ImportedStylesConflictBehavior.Ignore); + + await context.sync(); + console.log("Styles imported from JSON:", styles); + }); +Word.Document#insertFileFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + + + // Inserts content (applying selected settings) from another document passed + in as a Base64-encoded string. + + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + context.document.insertFileFromBase64(externalDocument, "Replace", { + importTheme: true, + importStyles: true, + importParagraphSpacing: true, + importPageColor: true, + importChangeTrackingMode: true, + importCustomProperties: true, + importCustomXmlParts: true, + importDifferentOddEvenPages: true + }); + await context.sync(); + }); +Word.Document#save:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml + + + // Saves the document with default behavior + + // for current state of the document. + + await Word.run(async (context) => { + context.document.save(); + await context.sync(); + }); +Word.Document#activeWindow:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the first paragraph of each page. + console.log("Getting first paragraph of each page..."); + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get all pages. + const pages: Word.PageCollection = activePane.pages; + pages.load(); + + await context.sync(); + + // Get page index and paragraphs of each page. + const pagesIndexes = []; + const pagesNumberOfParagraphs = []; + const pagesFirstParagraphText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const paragraphs = page.getRange().paragraphs; + paragraphs.load("items/length"); + pagesNumberOfParagraphs.push(paragraphs); + + const firstParagraph = paragraphs.getFirst(); + firstParagraph.load("text"); + pagesFirstParagraphText.push(firstParagraph); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + console.log(`Number of paragraphs: ${pagesNumberOfParagraphs[i].items.length}`); + console.log("First paragraph's text:", pagesFirstParagraphText[i].text); + } + }); +Word.Document#changeTrackingMode:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + + + // Gets the current change tracking mode. + + await Word.run(async (context) => { + const document: Word.Document = context.document; + document.load("changeTrackingMode"); + await context.sync(); + + if (document.changeTrackingMode === Word.ChangeTrackingMode.trackMineOnly) { + console.log("Only my changes are being tracked."); + } else if (document.changeTrackingMode === Word.ChangeTrackingMode.trackAll) { + console.log("Everyone's changes are being tracked."); + } else { + console.log("No changes are being tracked."); + } + }); +Word.Document#onAnnotationClicked:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onClickedHandler(args: Word.AnnotationClickedEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationClicked: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } +Word.Document#onAnnotationHovered:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onHoveredHandler(args: Word.AnnotationHoveredEventArgs) { + await Word.run(async (context) => { + const annotation: Word.Annotation = context.document.getAnnotationById(args.id); + annotation.load("critiqueAnnotation"); + + await context.sync(); + + console.log(`AnnotationHovered: ID ${args.id}:`, annotation.critiqueAnnotation.critique); + }); + } +Word.Document#onAnnotationInserted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onInsertedHandler(args: Word.AnnotationInsertedEventArgs) { + await Word.run(async (context) => { + const annotations = []; + for (let i = 0; i < args.ids.length; i++) { + let annotation: Word.Annotation = context.document.getAnnotationById(args.ids[i]); + annotation.load("id,critiqueAnnotation"); + + annotations.push(annotation); + } + + await context.sync(); + + for (let annotation of annotations) { + console.log(`AnnotationInserted: ID ${annotation.id}:`, annotation.critiqueAnnotation.critique); + } + }); + } +Word.Document#onAnnotationPopupAction:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onPopupActionHandler(args: + Word.AnnotationPopupActionEventArgs) { + await Word.run(async (context) => { + let message = `AnnotationPopupAction: ID ${args.id} = `; + if (args.action === "Accept") { + message += `Accepted: ${args.critiqueSuggestion}`; + } else { + message += "Rejected"; + } + + console.log(message); + }); + } +Word.Document#onAnnotationRemoved:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function onRemovedHandler(args: Word.AnnotationRemovedEventArgs) { + await Word.run(async (context) => { + for (let id of args.ids) { + console.log(`AnnotationRemoved: ID ${id}`); + } + }); + } +Word.Document#onContentControlAdded:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml + + + // Registers the onAdded event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onContentControlAdded.add(contentControlAdded); + await context.sync(); + + console.log("Added event handler for when content controls are added."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml + + + async function contentControlAdded(event: Word.ContentControlAddedEventArgs) + { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were added:`, event.ids); + }); + } +Word.Document#onParagraphAdded:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + + + // Registers the onParagraphAdded event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphAdded.add(paragraphAdded); + await context.sync(); + + console.log("Added event handler for when paragraphs are added."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + + + async function paragraphAdded(event: Word.ParagraphAddedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were added:`, event.uniqueLocalIds); + }); + } +Word.Document#onParagraphChanged:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml + + + // Registers the onParagraphChanged event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphChanged.add(paragraphChanged); + await context.sync(); + + console.log("Added event handler for when content is changed in paragraphs."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml + + + async function paragraphChanged(event: Word.ParagraphChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs where content was changed:`, event.uniqueLocalIds); + }); + } +Word.Document#onParagraphDeleted:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml + + + // Registers the onParagraphDeleted event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphDeleted.add(paragraphDeleted); + await context.sync(); + + console.log("Added event handlers for when paragraphs are deleted."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml + + + async function paragraphDeleted(event: Word.ParagraphDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were deleted:`, event.uniqueLocalIds); + }); + } +Word.Document#properties:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/get-built-in-properties.yaml + + + await Word.run(async (context) => { + const builtInProperties: Word.DocumentProperties = context.document.properties; + builtInProperties.load("*"); // Let's get all! + + await context.sync(); + console.log(JSON.stringify(builtInProperties, null, 4)); + }); +Word.Document#settings:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Gets all custom settings this add-in set on this document. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + settings.load("items"); + await context.sync(); + + if (settings.items.length == 0) { + console.log("There are no settings."); + } else { + console.log("All settings:"); + for (let i = 0; i < settings.items.length; i++) { + console.log(settings.items[i]); + } + } + }); +Word.Document#windows:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the document windows. + const windows: Word.WindowCollection = context.document.windows; + windows.load("windows/items/length"); + + await context.sync(); + + console.log(`Number of windows for this document: ${windows.items.length}`); + }); +Word.DocumentCompareOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/compare-documents.yaml + + + // Compares the current document with a specified external document. + + await Word.run(async (context) => { + // Absolute path of an online or local document. + const filePath = (document.getElementById("filePath") as HTMLInputElement).value; + // Options that configure the compare operation. + const options: Word.DocumentCompareOptions = { + compareTarget: Word.CompareTarget.compareTargetCurrent, + detectFormatChanges: false + // Other options you choose... + }; + context.document.compare(filePath, options); + + await context.sync(); + + console.log("Differences shown in the current document."); + }); +Word.DocumentCreated:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + + + // Updates the text of the current document with the text from another + document passed in as a Base64-encoded string. + + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + const externalDoc: Word.DocumentCreated = context.application.createDocument(externalDocument); + await context.sync(); + + if (!Office.context.requirements.isSetSupported("WordApiHiddenDocument", "1.3")) { + console.warn("The WordApiHiddenDocument 1.3 requirement set isn't supported on this client so can't proceed. Try this action on a platform that supports this requirement set."); + return; + } + + const externalDocBody: Word.Body = externalDoc.body; + externalDocBody.load("text"); + await context.sync(); + + // Insert the external document's text at the beginning of the current document's body. + const externalDocBodyText = externalDocBody.text; + const currentDocBody: Word.Body = context.document.body; + currentDocBody.insertText(externalDocBodyText, Word.InsertLocation.start); + await context.sync(); + }); +Word.DocumentProperties:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/get-built-in-properties.yaml + + + await Word.run(async (context) => { + const builtInProperties: Word.DocumentProperties = context.document.properties; + builtInProperties.load("*"); // Let's get all! + + await context.sync(); + console.log(JSON.stringify(builtInProperties, null, 4)); + }); +Word.DocumentPropertyType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml + + + await Word.run(async (context) => { + const properties: Word.CustomPropertyCollection = context.document.properties.customProperties; + properties.load("key,type,value"); + + await context.sync(); + for (let i = 0; i < properties.items.length; i++) + console.log("Property Name:" + properties.items[i].key + "; Type=" + properties.items[i].type + "; Property Value=" + properties.items[i].value); + }); +Word.DropDownListContentControl:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Places a dropdown list content control at the end of the selection. + + await Word.run(async (context) => { + let selection = context.document.getSelection(); + selection.getRange(Word.RangeLocation.end).insertContentControl(Word.ContentControlType.dropDownList); + await context.sync(); + + console.log("Dropdown list content control inserted at the end of the selection."); + }); +Word.DropDownListContentControl#addListItem:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Adds the provided list item to the first dropdown list content control in + the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-add") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + selectedContentControl.dropDownListContentControl.addListItem(listItemText); + await context.sync(); + + console.log(`List item added to control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.DropDownListContentControl#deleteAllListItems:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Deletes the list items from first dropdown list content control found in + the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log( + `About to delete the list from the dropdown list content control with ID ${selectedContentControl.id}` + ); + selectedContentControl.dropDownListContentControl.deleteAllListItems(); + await context.sync(); + + console.log("Deleted the list from the dropdown list content control."); + }); +Word.DropDownListContentControl#listItems:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Deletes the provided list item from the first dropdown list content + control in the selection. + + await Word.run(async (context) => { + const listItemText = (document.getElementById("item-to-delete") as HTMLInputElement).value.trim(); + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.dropDownList] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,dropDownListContentControl"); + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,dropDownListContentControl"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.dropDownList) { + console.warn("No dropdown list content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + let selectedDropdownList: Word.DropDownListContentControl = selectedContentControl.dropDownListContentControl; + selectedDropdownList.listItems.load("items/*"); + await context.sync(); + + let listItems: Word.ContentControlListItemCollection = selectedContentControl.dropDownListContentControl.listItems; + let itemToDelete: Word.ContentControlListItem = listItems.items.find((item) => item.displayText === listItemText); + if (!itemToDelete) { + console.warn(`List item doesn't exist in control with ID ${selectedContentControl.id}: ${listItemText}`) + return; + } + + itemToDelete.delete(); + await context.sync(); + + console.log(`List item deleted from control with ID ${selectedContentControl.id}: ${listItemText}`); + }); +Word.ErrorCodes:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + 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. + if (error.code === Word.ErrorCodes.itemNotFound) { + console.warn("No checkbox content control is currently selected."); + } else { + console.error(error); + } + } + } +Word.EventSource:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.track(); + await context.sync(); + + eventContexts[0] = body.onCommentAdded.add(onEventHandler); + eventContexts[1] = body.onCommentChanged.add(onChangedHandler); + eventContexts[2] = body.onCommentDeleted.add(onEventHandler); + eventContexts[3] = body.onCommentDeselected.add(onEventHandler); + eventContexts[4] = body.onCommentSelected.add(onEventHandler); + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml + + + async function onEventHandler(event: Word.CommentEventArgs) { + // Handler for all events except onCommentChanged. + await Word.run(async (context) => { + console.log(`${event.type} event detected. Event source: ${event.source}. Comment info:`, event.commentDetails); + }); + } +Word.EventType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml + + + async function contentControlDeleted(event: + Word.ContentControlDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.eventType} event detected. IDs of content controls that were deleted:`, event.ids); + }); + } +Word.Field:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.Field#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Deletes the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + field.delete(); + await context.sync(); + + console.log("The first field in the document was deleted."); + } + }); +Word.Field#select:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets and updates the first field in the selection. + + await Word.run(async (context) => { + let field = context.document.getSelection().fields.getFirstOrNullObject(); + field.load(["code", "result", "type", "locked"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("No field in selection."); + } else { + console.log("Before updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + + field.updateResult(); + field.select(); + await context.sync(); + + field.load(["code", "result"]); + await context.sync(); + + console.log("After updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + } + }); +Word.Field#updateResult:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets and updates the first field in the selection. + + await Word.run(async (context) => { + let field = context.document.getSelection().fields.getFirstOrNullObject(); + field.load(["code", "result", "type", "locked"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("No field in selection."); + } else { + console.log("Before updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + + field.updateResult(); + field.select(); + await context.sync(); + + field.load(["code", "result"]); + await context.sync(); + + console.log("After updating:", "Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result)); + } + }); +Word.Field#code:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.Field#kind:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.Field#locked:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the selection and toggles between setting it to + locked or unlocked. + + await Word.run(async (context) => { + let field = context.document.getSelection().fields.getFirstOrNullObject(); + field.load(["code", "result", "type", "locked"]); + await context.sync(); + + if (field.isNullObject) { + console.log("The selection has no fields."); + } else { + console.log(`The first field in the selection is currently ${field.locked ? "locked" : "unlocked"}.`); + field.locked = !field.locked; + await context.sync(); + + console.log(`The first field in the selection is now ${field.locked ? "locked" : "unlocked"}.`); + } + }); +Word.Field#parentBody:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the parent body of the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load("parentBody/text"); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + const parentBody: Word.Body = field.parentBody; + console.log("Text of first field's parent body: " + JSON.stringify(parentBody.text)); + } + }); +Word.Field#result:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.Field#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.FieldCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets all fields in the document body. + + await Word.run(async (context) => { + const fields: Word.FieldCollection = context.document.body.fields.load("items"); + + await context.sync(); + + if (fields.items.length === 0) { + console.log("No fields in this document."); + } else { + fields.load(["code", "result"]); + await context.sync(); + + for (let i = 0; i < fields.items.length; i++) { + console.log(`Field ${i + 1}'s code: ${fields.items[i].code}`, `Field ${i + 1}'s result: ${JSON.stringify(fields.items[i].result)}`); + } + } + }); +Word.FieldCollection#getFirstOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.FieldCollection#items:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets all fields in the document body. + + await Word.run(async (context) => { + const fields: Word.FieldCollection = context.document.body.fields.load("items"); + + await context.sync(); + + if (fields.items.length === 0) { + console.log("No fields in this document."); + } else { + fields.load(["code", "result"]); + await context.sync(); + + for (let i = 0; i < fields.items.length; i++) { + console.log(`Field ${i + 1}'s code: ${fields.items[i].code}`, `Field ${i + 1}'s result: ${JSON.stringify(fields.items[i].result)}`); + } + } + }); +Word.FieldKind:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Gets the first field in the document. + + await Word.run(async (context) => { + const field: Word.Field = context.document.body.fields.getFirstOrNullObject(); + field.load(["code", "result", "locked", "type", "data", "kind"]); + + await context.sync(); + + if (field.isNullObject) { + console.log("This document has no fields."); + } else { + console.log("Code of first field: " + field.code, "Result of first field: " + JSON.stringify(field.result), "Type of first field: " + field.type, "Is the first field locked? " + field.locked, "Kind of the first field: " + field.kind); + } + }); +Word.FieldType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Inserts a Date field before selection. + + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection().getRange(); + + const field: Word.Field = range.insertField(Word.InsertLocation.before, Word.FieldType.date, '\\@ "M/d/yyyy h:mm am/pm"', true); + + field.load("result,code"); + await context.sync(); + + if (field.isNullObject) { + console.log("There are no fields in this document."); + } else { + console.log("Code of the field: " + field.code, "Result of the field: " + JSON.stringify(field.result)); + } + }); +Word.GeometricShapeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Inserts a heptagon geometric shape at the beginning of the selection. + const selection: Word.Range = context.document.getSelection(); + const shapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + }; + selection.insertGeometricShape(Word.GeometricShapeType.heptagon, shapeOptions); + await context.sync(); + + console.log("Inserted a heptagon."); + }); +Word.GetTextOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-text.yaml + + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + + const text = paragraph.getText(); + const textIncludingHidden = paragraph.getText({ IncludeHiddenText: true }); + const textIncludingDeleted = paragraph.getText({ IncludeTextMarkedAsDeleted: true }); + + await context.sync(); + + console.log("Text:- " + text.value, "Including hidden text:- " + textIncludingHidden.value, "Including text marked as deleted:- " + textIncludingDeleted.value); + }); +Word.HeaderFooterType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-header-and-footer.yaml + + + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getHeader(Word.HeaderFooterType.primary) + .insertParagraph("This is a primary header.", "End"); + + await context.sync(); + }); +Word.ImageFormat:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Gets the first image in the document. + + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); +Word.ImportedStylesConflictBehavior:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml + + + // Imports styles from JSON. + + await Word.run(async (context) => { + const str = + '{"styles":[{"baseStyle":"Default Paragraph Font","builtIn":false,"inUse":true,"linked":false,"nameLocal":"NewCharStyle","priority":2,"quickStyle":true,"type":"Character","unhideWhenUsed":false,"visibility":false,"paragraphFormat":null,"font":{"name":"DengXian Light","size":16.0,"bold":true,"italic":false,"color":"#F1A983","underline":"None","subscript":false,"superscript":true,"strikeThrough":true,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#FF0000"}},{"baseStyle":"Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewParaStyle","nameLocal":"NewParaStyle","priority":1,"quickStyle":true,"type":"Paragraph","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Centered","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":72.0,"lineSpacing":18.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":72.0,"spaceAfter":30.0,"spaceBefore":30.0,"widowControl":true},"font":{"name":"DengXian","size":14.0,"bold":true,"italic":true,"color":"#8DD873","underline":"Single","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":true,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#00FF00"}},{"baseStyle":"Table Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewTableStyle","nameLocal":"NewTableStyle","priority":100,"type":"Table","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Left","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":0.0,"lineSpacing":12.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":0.0,"spaceAfter":0.0,"spaceBefore":0.0,"widowControl":true},"font":{"name":"DengXian","size":20.0,"bold":false,"italic":true,"color":"#D86DCB","underline":"None","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"tableStyle":{"allowBreakAcrossPage":true,"alignment":"Left","bottomCellMargin":0.0,"leftCellMargin":0.08,"rightCellMargin":0.08,"topCellMargin":0.0,"cellSpacing":0.0},"shading":{"backgroundPatternColor":"#60CAF3"}}]}'; + const styles = context.document.importStylesFromJson(str); + + // If you'd like to set how conflicting styles are handled, use the importedStylesConflictBehavior parameter that was introduced in the Desktop 1.1 requirement set. "Ignore" is the default. + ////const styles = context.document.importStylesFromJson(str, Word.ImportedStylesConflictBehavior.Ignore); + + await context.sync(); + console.log("Styles imported from JSON:", styles); + }); +Word.InlinePicture#getBase64ImageSrc:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Gets the first image in the document. + + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); +Word.InlinePicture:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Inserts an image anchored to the last paragraph. + + await Word.run(async (context) => { + context.document.body.paragraphs + .getLast() + .insertParagraph("", "After") + .insertInlinePictureFromBase64(base64Image, "End"); + + await context.sync(); + }); +Word.InlinePicture#imageFormat:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Gets the first image in the document. + + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); +Word.InlinePictureCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Gets the first image in the document. + + await Word.run(async (context) => { + const firstPicture: Word.InlinePicture = context.document.body.inlinePictures.getFirst(); + firstPicture.load("width, height, imageFormat"); + + await context.sync(); + console.log(`Image dimensions: ${firstPicture.width} x ${firstPicture.height}`, `Image format: ${firstPicture.imageFormat}`); + // Get the image encoded as Base64. + const base64 = firstPicture.getBase64ImageSrc(); + + await context.sync(); + console.log(base64.value); + }); +Word.InsertFileOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml + + + // Inserts content (applying selected settings) from another document passed + in as a Base64-encoded string. + + await Word.run(async (context) => { + // Use the Base64-encoded string representation of the selected .docx file. + context.document.insertFileFromBase64(externalDocument, "Replace", { + importTheme: true, + importStyles: true, + importParagraphSpacing: true, + importPageColor: true, + importChangeTrackingMode: true, + importCustomProperties: true, + importCustomXmlParts: true, + importDifferentOddEvenPages: true + }); + await context.sync(); + }); +Word.InsertLocation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-section-breaks.yaml + + + // Inserts a section without an associated page break. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionContinuous, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section without an associated page break."); + }); +Word.InsertShapeOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a text box at the beginning of the selection. + const range: Word.Range = context.document.getSelection(); + const insertShapeOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100 + }; + + const newTextBox: Word.Shape = range.insertTextBox("placeholder text", insertShapeOptions); + await context.sync(); + + console.log("Inserted a text box at the beginning of the current selection."); + }); +Word.List:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.List#insertParagraph:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.List#setLevelBullet:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Inserts a list starting with the first paragraph then set numbering and + bullet types of the list items. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Use the first paragraph to start a new list. + const list: Word.List = paragraphs.items[0].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set numbering for list level 1. + list.setLevelNumbering(0, Word.ListNumbering.arabic); + + // Set bullet type for list level 5. + list.setLevelBullet(4, Word.ListBullet.arrow); + + // Set list level for the last item in this list. + paragraph.listItem.level = 4; + + list.load("levelTypes"); + + await context.sync(); + }); +Word.List#setLevelNumbering:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Inserts a list starting with the first paragraph then set numbering and + bullet types of the list items. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Use the first paragraph to start a new list. + const list: Word.List = paragraphs.items[0].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set numbering for list level 1. + list.setLevelNumbering(0, Word.ListNumbering.arabic); + + // Set bullet type for list level 5. + list.setLevelBullet(4, Word.ListBullet.arrow); + + // Set list level for the last item in this list. + paragraph.listItem.level = 4; + + list.load("levelTypes"); + + await context.sync(); + }); +Word.List#levelExistences:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Gets information about the first list in the document. + + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); +Word.List#levelTypes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Gets information about the first list in the document. + + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); +Word.ListBuiltInNumberStyle:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.ListBullet:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Inserts a list starting with the first paragraph then set numbering and + bullet types of the list items. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Use the first paragraph to start a new list. + const list: Word.List = paragraphs.items[0].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set numbering for list level 1. + list.setLevelNumbering(0, Word.ListNumbering.arabic); + + // Set bullet type for list level 5. + list.setLevelBullet(4, Word.ListBullet.arrow); + + // Set list level for the last item in this list. + paragraph.listItem.level = 4; + + list.load("levelTypes"); + + await context.sync(); + }); +Word.ListCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Gets information about the first list in the document. + + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); +Word.ListItem:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.ListItem#level:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.ListLevel:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.ListLevelCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.ListLevelType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Gets information about the first list in the document. + + await Word.run(async (context) => { + const lists: Word.ListCollection = context.document.body.lists; + lists.load("items"); + + await context.sync(); + + if (lists.items.length === 0) { + console.warn("There are no lists in this document."); + return; + } + + // Get the first list. + const list: Word.List = lists.getFirst(); + list.load("levelTypes,levelExistences"); + + await context.sync(); + + const levelTypes = list.levelTypes; + console.log("Level types of the first list:"); + for (let i = 0; i < levelTypes.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelTypes[i]}`); + } + + const levelExistences = list.levelExistences; + console.log("Level existences of the first list:"); + for (let i = 0; i < levelExistences.length; i++) { + console.log(`- Level ${i + 1} (index ${i}): ${levelExistences[i]}`); + } + }); +Word.ListNumbering:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml + + + // Inserts a list starting with the first paragraph then set numbering and + bullet types of the list items. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Use the first paragraph to start a new list. + const list: Word.List = paragraphs.items[0].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set numbering for list level 1. + list.setLevelNumbering(0, Word.ListNumbering.arabic); + + // Set bullet type for list level 5. + list.setLevelBullet(4, Word.ListBullet.arrow); + + // Set list level for the last item in this list. + paragraph.listItem.level = 4; + + list.load("levelTypes"); + + await context.sync(); + }); +Word.ListTemplate:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.LocationRelation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/compare-location.yaml + + + // Compares the location of one paragraph in relation to another paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("items"); + + await context.sync(); + + const firstParagraphAsRange: Word.Range = paragraphs.items[0].getRange(); + const secondParagraphAsRange: Word.Range = paragraphs.items[1].getRange(); + + const comparedLocation = firstParagraphAsRange.compareLocationWith(secondParagraphAsRange); + + await context.sync(); + + const locationValue: Word.LocationRelation = comparedLocation.value; + console.log(`Location of the first paragraph in relation to the second paragraph: ${locationValue}`); + }); +Word.NoteItem:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the text of the referenced footnote. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/body"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const footnoteBody: Word.Range = footnotes.items[mark].body.getRange(); + footnoteBody.load("text"); + await context.sync(); + + console.log(`Text of footnote ${referenceNumber}: ${footnoteBody.text}`); + }); +Word.NoteItem#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Deletes this referenced footnote. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + footnotes.items[mark].delete(); + await context.sync(); + + console.log("Footnote deleted."); + }); +Word.NoteItem#getNext:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Selects the next footnote in the document body. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/reference"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const reference: Word.Range = footnotes.items[mark].getNext().reference; + reference.select(); + console.log("Selected is the next footnote: " + (mark + 2)); + }); +Word.NoteItem#body:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the text of the referenced footnote. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/body"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const footnoteBody: Word.Range = footnotes.items[mark].body.getRange(); + footnoteBody.load("text"); + await context.sync(); + + console.log(`Text of footnote ${referenceNumber}: ${footnoteBody.text}`); + }); +Word.NoteItem#reference:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Selects the footnote's reference mark in the document body. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items/reference"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + const reference: Word.Range = item.reference; + reference.select(); + await context.sync(); + + console.log(`Reference ${referenceNumber} is selected.`); + }); +Word.NoteItem#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the referenced note's item type and body type, which are both + "Footnote". + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + console.log(`Note type of footnote ${referenceNumber}: ${item.type}`); + + item.body.load("type"); + await context.sync(); + + console.log(`Body type of note: ${item.body.type}`); + }); +Word.NoteItemCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the first footnote in the document body and select its reference + mark. + + await Word.run(async (context) => { + const reference: Word.Range = context.document.body.footnotes.getFirst().reference; + reference.select(); + console.log("The first footnote is selected."); + }); +Word.NoteItemCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the first footnote in the document body and select its reference + mark. + + await Word.run(async (context) => { + const reference: Word.Range = context.document.body.footnotes.getFirst().reference; + reference.select(); + console.log("The first footnote is selected."); + }); +Word.NoteItemType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the referenced note's item type and body type, which are both + "Footnote". + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.body.footnotes; + footnotes.load("items"); + await context.sync(); + + const referenceNumber = (document.getElementById("input-reference") as HTMLInputElement).value; + const mark = (referenceNumber as number) - 1; + const item: Word.NoteItem = footnotes.items[mark]; + console.log(`Note type of footnote ${referenceNumber}: ${item.type}`); + + item.body.load("type"); + await context.sync(); + + console.log(`Body type of note: ${item.body.type}`); + }); +Word.OutlineLevel:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml + + + // Imports styles from JSON. + + await Word.run(async (context) => { + const str = + '{"styles":[{"baseStyle":"Default Paragraph Font","builtIn":false,"inUse":true,"linked":false,"nameLocal":"NewCharStyle","priority":2,"quickStyle":true,"type":"Character","unhideWhenUsed":false,"visibility":false,"paragraphFormat":null,"font":{"name":"DengXian Light","size":16.0,"bold":true,"italic":false,"color":"#F1A983","underline":"None","subscript":false,"superscript":true,"strikeThrough":true,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#FF0000"}},{"baseStyle":"Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewParaStyle","nameLocal":"NewParaStyle","priority":1,"quickStyle":true,"type":"Paragraph","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Centered","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":72.0,"lineSpacing":18.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":72.0,"spaceAfter":30.0,"spaceBefore":30.0,"widowControl":true},"font":{"name":"DengXian","size":14.0,"bold":true,"italic":true,"color":"#8DD873","underline":"Single","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":true,"highlightColor":null,"hidden":false},"shading":{"backgroundPatternColor":"#00FF00"}},{"baseStyle":"Table Normal","builtIn":false,"inUse":true,"linked":false,"nextParagraphStyle":"NewTableStyle","nameLocal":"NewTableStyle","priority":100,"type":"Table","unhideWhenUsed":false,"visibility":false,"paragraphFormat":{"alignment":"Left","firstLineIndent":0.0,"keepTogether":false,"keepWithNext":false,"leftIndent":0.0,"lineSpacing":12.0,"lineUnitAfter":0.0,"lineUnitBefore":0.0,"mirrorIndents":false,"outlineLevel":"OutlineLevelBodyText","rightIndent":0.0,"spaceAfter":0.0,"spaceBefore":0.0,"widowControl":true},"font":{"name":"DengXian","size":20.0,"bold":false,"italic":true,"color":"#D86DCB","underline":"None","subscript":false,"superscript":false,"strikeThrough":false,"doubleStrikeThrough":false,"highlightColor":null,"hidden":false},"tableStyle":{"allowBreakAcrossPage":true,"alignment":"Left","bottomCellMargin":0.0,"leftCellMargin":0.08,"rightCellMargin":0.08,"topCellMargin":0.0,"cellSpacing":0.0},"shading":{"backgroundPatternColor":"#60CAF3"}}]}'; + const styles = context.document.importStylesFromJson(str); + + // If you'd like to set how conflicting styles are handled, use the importedStylesConflictBehavior parameter that was introduced in the Desktop 1.1 requirement set. "Ignore" is the default. + ////const styles = context.document.importStylesFromJson(str, Word.ImportedStylesConflictBehavior.Ignore); + + await context.sync(); + console.log("Styles imported from JSON:", styles); + }); +Word.Page:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets pages of the selection. + const pages: Word.PageCollection = context.document.getSelection().pages; + pages.load(); + await context.sync(); + + // Log info for pages included in selection. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index info for page ${i + 1} in the selection: ${pagesIndexes[i].index}`); + console.log("Text of that page in the selection:", pagesText[i].text); + } + }); +Word.Page#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets pages of the selection. + const pages: Word.PageCollection = context.document.getSelection().pages; + pages.load(); + await context.sync(); + + // Log info for pages included in selection. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index info for page ${i + 1} in the selection: ${pagesIndexes[i].index}`); + console.log("Text of that page in the selection:", pagesText[i].text); + } + }); +Word.Page#index:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the pages that contain the third paragraph. + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load(); + await context.sync(); + + const paraThree = paragraphs.items[2]; + const rangeOfParagraph = paraThree.getRange(); + const pages: Word.PageCollection = rangeOfParagraph.pages; + pages.load(); + await context.sync(); + + // Log info for pages in range. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index of page ${i + 1} that contains the third paragraph: ${pagesIndexes[i].index}`); + console.log("Text of that page:", pagesText[i].text); + } + }); +Word.PageCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets pages of the selection. + const pages: Word.PageCollection = context.document.getSelection().pages; + pages.load(); + await context.sync(); + + // Log info for pages included in selection. + console.log(pages); + const pagesIndexes = []; + const pagesText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const range = page.getRange(); + range.load("text"); + pagesText.push(range); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Index info for page ${i + 1} in the selection: ${pagesIndexes[i].index}`); + console.log("Text of that page in the selection:", pagesText[i].text); + } + }); +Word.Pane:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the first paragraph of each page. + console.log("Getting first paragraph of each page..."); + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get all pages. + const pages: Word.PageCollection = activePane.pages; + pages.load(); + + await context.sync(); + + // Get page index and paragraphs of each page. + const pagesIndexes = []; + const pagesNumberOfParagraphs = []; + const pagesFirstParagraphText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const paragraphs = page.getRange().paragraphs; + paragraphs.load("items/length"); + pagesNumberOfParagraphs.push(paragraphs); + + const firstParagraph = paragraphs.getFirst(); + firstParagraph.load("text"); + pagesFirstParagraphText.push(firstParagraph); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + console.log(`Number of paragraphs: ${pagesNumberOfParagraphs[i].items.length}`); + console.log("First paragraph's text:", pagesFirstParagraphText[i].text); + } + }); +Word.Pane#pages:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the first paragraph of each page. + console.log("Getting first paragraph of each page..."); + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get all pages. + const pages: Word.PageCollection = activePane.pages; + pages.load(); + + await context.sync(); + + // Get page index and paragraphs of each page. + const pagesIndexes = []; + const pagesNumberOfParagraphs = []; + const pagesFirstParagraphText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const paragraphs = page.getRange().paragraphs; + paragraphs.load("items/length"); + pagesNumberOfParagraphs.push(paragraphs); + + const firstParagraph = paragraphs.getFirst(); + firstParagraph.load("text"); + pagesFirstParagraphText.push(firstParagraph); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + console.log(`Number of paragraphs: ${pagesNumberOfParagraphs[i].items.length}`); + console.log("First paragraph's text:", pagesFirstParagraphText[i].text); + } + }); +Word.Pane#pagesEnclosingViewport:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the pages enclosing the viewport. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get pages enclosing the viewport. + const pages: Word.PageCollection = activePane.pagesEnclosingViewport; + pages.load(); + + await context.sync(); + + // Log the number of pages. + const pageCount = pages.items.length; + console.log(`Number of pages enclosing the viewport: ${pageCount}`); + + // Log index info of these pages. + const pagesIndexes = []; + for (let i = 0; i < pageCount; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + } + }); +Word.PaneCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets all the panes in the active document window. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load("panes/items/length"); + + await context.sync(); + + const panes: Word.PaneCollection = activeWindow.panes; + console.log(`Number of panes in the current document window: ${panes.items.length}`); + }); +Word.Paragraph:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // The collection of paragraphs of the current selection returns the full paragraphs contained in it. + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + paragraph.load("text"); + + await context.sync(); + console.log(paragraph.text); + }); +Word.Paragraph#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + const sentences: Word.RangeCollection = context.document + .getSelection() + .getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); + sentences.load("$none"); + await context.sync(); + + // Expand the range to the end of the paragraph to get all the complete sentences. + const sentencesToTheEndOfParagraph: Word.RangeCollection = sentences.items[0] + .getRange() + .expandTo( + context.document + .getSelection() + .paragraphs.getFirst() + .getRange(Word.RangeLocation.end) + ) + .getTextRanges(["."], false /* Don't trim spaces*/); + sentencesToTheEndOfParagraph.load("text"); + await context.sync(); + + for (let i = 0; i < sentencesToTheEndOfParagraph.items.length; i++) { + console.log(sentencesToTheEndOfParagraph.items[i].text); + } + }); +Word.Paragraph#insertAnnotations:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Adds annotations to the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const options: Word.CritiquePopupOptions = { + brandingTextResourceId: "PG.TabLabel", + subtitleResourceId: "PG.HelpCommand.TipTitle", + titleResourceId: "PG.HelpCommand.Label", + suggestions: ["suggestion 1", "suggestion 2", "suggestion 3"] + }; + const critique1: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.red, + start: 1, + length: 3, + popupOptions: options + }; + const critique2: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.green, + start: 6, + length: 1, + popupOptions: options + }; + const critique3: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.blue, + start: 10, + length: 3, + popupOptions: options + }; + const critique4: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.lavender, + start: 14, + length: 3, + popupOptions: options + }; + const critique5: Word.Critique = { + colorScheme: Word.CritiqueColorScheme.berry, + start: 18, + length: 10, + popupOptions: options + }; + const annotationSet: Word.AnnotationSet = { + critiques: [critique1, critique2, critique3, critique4, critique5] + }; + + const annotationIds = paragraph.insertAnnotations(annotationSet); + + await context.sync(); + + console.log("Annotations inserted:", annotationIds.value); + }); +Word.Paragraph#insertBreak:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-line-and-page-breaks.yaml + + + Word.run(async (context) => { + context.document.body.paragraphs.getFirst().insertBreak(Word.BreakType.line, "After"); + + await context.sync(); + console.log("success"); + }); +Word.Paragraph#insertContentControl:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml + + + // Traverses each paragraph of the document and wraps a content control on + each with either a even or odd tags. + + await Word.run(async (context) => { + let paragraphs = context.document.body.paragraphs; + paragraphs.load("$none"); // Don't need any properties; just wrap each paragraph with a content control. + + await context.sync(); + + for (let i = 0; i < paragraphs.items.length; i++) { + let contentControl = paragraphs.items[i].insertContentControl(); + // For even, tag "even". + if (i % 2 === 0) { + contentControl.tag = "even"; + } else { + contentControl.tag = "odd"; + } + } + console.log("Content controls inserted: " + paragraphs.items.length); + + await context.sync(); + }); +Word.Paragraph#insertGeometricShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.clear(); + const lastParagraph: Word.Paragraph = body.paragraphs.getLast(); + + // Inserts a text box. + const textBoxOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100, + }; + lastParagraph.insertTextBox("placeholder text", textBoxOptions); + + // Inserts a geometric shape. + const geometricShapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + left: 120, + }; + lastParagraph.insertGeometricShape(Word.GeometricShapeType.star24, geometricShapeOptions); + + // Inserts a picture. + const pictureOptions: Word.InsertShapeOptions = { + top: 120, + left: 60, + height: 150, + width: 150, + }; + lastParagraph.insertPictureFromBase64(getPictureBase64(), pictureOptions); + + await context.sync(); + }); +Word.Paragraph#insertText:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-in-different-locations.yaml + + + await Word.run(async (context) => { + // Replace the last paragraph. + const range: Word.Range = context.document.body.paragraphs.getLast().insertText("Just replaced the last paragraph!", "Replace"); + range.font.highlightColor = "black"; + range.font.color = "white"; + + await context.sync(); + }); +Word.Paragraph#insertTextBox:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a text box at the beginning of the first paragraph in the header. + const headerFooterBody: Word.Body = context.document.sections.getFirst().getHeader(Word.HeaderFooterType.primary); + headerFooterBody.load("paragraphs"); + const firstParagraph: Word.Paragraph = headerFooterBody.paragraphs.getFirst(); + const insertShapeOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100 + }; + const newTextBox: Word.Shape = firstParagraph.insertTextBox("placeholder text", insertShapeOptions); + newTextBox.select(); + await context.sync(); + + console.log("Inserted a text box at the beginning of the first paragraph in the header."); + }); +Word.Paragraph#select:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/scroll-to-range.yaml + + + await Word.run(async (context) => { + // If select is called with no parameters, it selects the object. + context.document.body.paragraphs.getLast().select(); + + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/scroll-to-range.yaml + + + await Word.run(async (context) => { + // Select can be at the start or end of a range; this by definition moves the insertion point without selecting the range. + context.document.body.paragraphs.getLast().select(Word.SelectionMode.end); + + await context.sync(); + }); +Word.Paragraph#set:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/multiple-property-set.yaml + + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + paragraph.set({ + leftIndent: 30, + font: { + bold: true, + color: "red" + } + }); + + await context.sync(); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/multiple-property-set.yaml + + + await Word.run(async (context) => { + const firstParagraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + const secondParagraph: Word.Paragraph = firstParagraph.getNext(); + firstParagraph.load("text, font/color, font/bold, leftIndent"); + + await context.sync(); + + secondParagraph.set(firstParagraph); + + await context.sync(); + }); +Word.Paragraph#split:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/split-words-of-first-paragraph.yaml + + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.paragraphs.getFirst(); + const words = paragraph.split([" "], true /* trimDelimiters*/, true /* trimSpaces */); + words.load("text"); + + await context.sync(); + + for (let i = 0; i < words.items.length; i++) { + if (i >= 1) { + words.items[i - 1].font.highlightColor = "#FFFFFF"; + } + words.items[i].font.highlightColor = "#FFFF00"; + + await context.sync(); + await pause(200); + } + }); +Word.Paragraph#startNewList:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.Paragraph#alignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Center last paragraph alignment. + context.document.body.paragraphs.getLast().alignment = "Centered"; + + await context.sync(); + }); +Word.Paragraph#leftIndent:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Indent the first paragraph. + context.document.body.paragraphs.getFirst().leftIndent = 75; //units = points + + return context.sync(); + }); +Word.Paragraph#lineSpacing:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Adjust line spacing. + context.document.body.paragraphs.getFirst().lineSpacing = 20; + + await context.sync(); + }); +Word.Paragraph#lineUnitAfter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Set the space (in line units) after the first paragraph. + context.document.body.paragraphs.getFirst().lineUnitAfter = 1; + + await context.sync(); + }); +Word.Paragraph#lineUnitBefore:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Set the space (in line units) before the first paragraph. + context.document.body.paragraphs.getFirst().lineUnitBefore = 1; + + await context.sync(); + }); +Word.Paragraph#spaceAfter:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml + + + await Word.run(async (context) => { + // Set the space (in points) after the first paragraph. + context.document.body.paragraphs.getFirst().spaceAfter = 20; + + await context.sync(); + }); +Word.Paragraph#style:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Applies the specified style to a paragraph. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.paragraph) { + console.log(`The '${styleName}' style isn't a paragraph style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + const paragraph: Word.Paragraph = body.paragraphs.getFirst(); + paragraph.style = style.nameLocal; + console.log(`'${styleName}' style applied to first paragraph.`); + } + }); +Word.Paragraph#styleBuiltIn:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.body.insertParagraph("Timeline", "End"); + paragraph.styleBuiltIn = "Heading2"; + const paragraph2: Word.Paragraph = context.document.body.insertParagraph("The Services shall commence on July 31, 2015, and shall continue through July 29, 2015.", "End"); + paragraph2.styleBuiltIn = "Normal"; + const paragraph3: Word.Paragraph = context.document.body.insertParagraph("Project Costs by Phase", "End"); + paragraph3.styleBuiltIn = "Heading2"; + // Note a content control with the title of "ProjectCosts" is added. Content will be replaced later. + const paragraph4: Word.Paragraph = context.document.body.insertParagraph("", "End"); + paragraph4.styleBuiltIn = "Normal"; + paragraph4.font.highlightColor = "#FFFF00"; + const contentControl: Word.ContentControl = paragraph4.insertContentControl(); + contentControl.title = "ProjectCosts"; + const paragraph5: Word.Paragraph = context.document.body.insertParagraph("Project Team", "End"); + paragraph5.styleBuiltIn = "Heading2"; + paragraph5.font.highlightColor = "#FFFFFF"; + const paragraph6: Word.Paragraph = context.document.body.insertParagraph("Terms of Work", "End"); + paragraph6.styleBuiltIn = "Heading1"; + const paragraph7: Word.Paragraph = context.document.body.insertParagraph("Contractor shall provide the Services and Deliverable(s) as follows:", "End"); + paragraph7.styleBuiltIn = "Normal"; + const paragraph8: Word.Paragraph = context.document.body.insertParagraph("Out-of-Pocket Expenses / Invoice Procedures", "End"); + paragraph8.styleBuiltIn = "Heading2"; + const paragraph9 : Word.Paragraph= context.document.body.insertParagraph("Client will be invoiced monthly for the consulting services and T&L expenses. Standard Contractor invoicing is assumed to be acceptable. Invoices are due upon receipt. client will be invoiced all costs associated with out-of-pocket expenses (including, without limitation, costs and expenses associated with meals, lodging, local transportation and any other applicable business expenses) listed on the invoice as a separate line item. Reimbursement for out-of-pocket expenses in connection with performance of this SOW, when authorized and up to the limits set forth in this SOW, shall be in accordance with Client's then-current published policies governing travel and associated business expenses, which information shall be provided by the Client Project Manager.", "End"); + paragraph9.styleBuiltIn = "Normal"; + // Insert a page break at the end of the document. + context.document.body.insertBreak("Page", "End"); + + await context.sync(); + }); +Word.Paragraph#text:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // The collection of paragraphs of the current selection returns the full paragraphs contained in it. + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + paragraph.load("text"); + + await context.sync(); + console.log(paragraph.text); + }); +Word.Paragraph#uniqueLocalId:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Registers event handlers. + + await Word.run(async (context) => { + eventContexts[0] = context.document.onParagraphAdded.add(paragraphChanged); + eventContexts[1] = context.document.onParagraphChanged.add(paragraphChanged); + + eventContexts[2] = context.document.onAnnotationClicked.add(onClickedHandler); + eventContexts[3] = context.document.onAnnotationHovered.add(onHoveredHandler); + eventContexts[4] = context.document.onAnnotationInserted.add(onInsertedHandler); + eventContexts[5] = context.document.onAnnotationRemoved.add(onRemovedHandler); + eventContexts[6] = context.document.onAnnotationPopupAction.add(onPopupActionHandler); + + await context.sync(); + + console.log("Event handlers registered."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + async function paragraphChanged(args: Word.ParagraphChangedEventArgs) { + await Word.run(async (context) => { + const results = []; + for (let id of args.uniqueLocalIds) { + let para = context.document.getParagraphByUniqueLocalId(id); + para.load("uniqueLocalId"); + + results.push({ para: para, text: para.getText() }); + } + + await context.sync(); + + for (let result of results) { + console.log(`${args.type}: ID ${result.para.uniqueLocalId}:-`, result.text.value); + } + }); + } +Word.ParagraphAddedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + + + // Registers the onParagraphAdded event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphAdded.add(paragraphAdded); + await context.sync(); + + console.log("Added event handler for when paragraphs are added."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml + + + async function paragraphAdded(event: Word.ParagraphAddedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were added:`, event.uniqueLocalIds); + }); + } +Word.ParagraphChangedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml + + + // Registers the onParagraphChanged event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphChanged.add(paragraphChanged); + await context.sync(); + + console.log("Added event handler for when content is changed in paragraphs."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml + + + async function paragraphChanged(event: Word.ParagraphChangedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs where content was changed:`, event.uniqueLocalIds); + }); + } +Word.ParagraphCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Inserts an image anchored to the last paragraph. + + await Word.run(async (context) => { + context.document.body.paragraphs + .getLast() + .insertParagraph("", "After") + .insertInlinePictureFromBase64(base64Image, "End"); + + await context.sync(); + }); +Word.ParagraphCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml + + + // Gets annotations found in the selected paragraph. + + await Word.run(async (context) => { + const paragraph: Word.Paragraph = context.document.getSelection().paragraphs.getFirst(); + const annotations: Word.AnnotationCollection = paragraph.getAnnotations(); + annotations.load("id,state,critiqueAnnotation"); + + await context.sync(); + + console.log("Annotations found:"); + + for (let i = 0; i < annotations.items.length; i++) { + const annotation: Word.Annotation = annotations.items[i]; + + console.log(`ID ${annotation.id} - state '${annotation.state}':`, annotation.critiqueAnnotation.critique); + } + }); +Word.ParagraphCollection#getLast:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml + + + // Inserts an image anchored to the last paragraph. + + await Word.run(async (context) => { + context.document.body.paragraphs + .getLast() + .insertParagraph("", "After") + .insertInlinePictureFromBase64(base64Image, "End"); + + await context.sync(); + }); +Word.ParagraphCollection#items:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml + + + // This example starts a new list with the second paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("$none"); + + await context.sync(); + + // Start new list using the second paragraph. + const list: Word.List = paragraphs.items[1].startNewList(); + list.load("$none"); + + await context.sync(); + + // To add new items to the list, use Start or End on the insertLocation parameter. + list.insertParagraph("New list item at the start of the list", "Start"); + const paragraph: Word.Paragraph = list.insertParagraph("New list item at the end of the list (set to list level 5)", "End"); + + // Set up list level for the list item. + paragraph.listItem.level = 4; + + // To add paragraphs outside the list, use Before or After. + list.insertParagraph("New paragraph goes after (not part of the list)", "After"); + + await context.sync(); + }); +Word.ParagraphDeletedEventArgs:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml + + + // Registers the onParagraphDeleted event handler on the document. + + await Word.run(async (context) => { + eventContext = context.document.onParagraphDeleted.add(paragraphDeleted); + await context.sync(); + + console.log("Added event handlers for when paragraphs are deleted."); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml + + + async function paragraphDeleted(event: Word.ParagraphDeletedEventArgs) { + await Word.run(async (context) => { + console.log(`${event.type} event detected. IDs of paragraphs that were deleted:`, event.uniqueLocalIds); + }); + } +Word.ParagraphFormat:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Sets certain aspects of the specified style's paragraph format e.g., the + left indent size and the alignment. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update its paragraph format."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.paragraphFormat.leftIndent = 30; + style.paragraphFormat.alignment = Word.Alignment.centered; + console.log(`Successfully the paragraph format of the '${styleName}' style.`); + } + }); +Word.ParagraphFormat#alignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Sets certain aspects of the specified style's paragraph format e.g., the + left indent size and the alignment. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update its paragraph format."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.paragraphFormat.leftIndent = 30; + style.paragraphFormat.alignment = Word.Alignment.centered; + console.log(`Successfully the paragraph format of the '${styleName}' style.`); + } + }); +Word.ParagraphFormat#leftIndent:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Sets certain aspects of the specified style's paragraph format e.g., the + left indent size and the alignment. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update its paragraph format."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.paragraphFormat.leftIndent = 30; + style.paragraphFormat.alignment = Word.Alignment.centered; + console.log(`Successfully the paragraph format of the '${styleName}' style.`); + } + }); +Word.Range:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the range of the first comment in the selected content. + + await Word.run(async (context) => { + const comment: Word.Comment = context.document.getSelection().getComments().getFirstOrNullObject(); + comment.load("contentRange"); + const range: Word.Range = comment.getRange(); + range.load("text"); + await context.sync(); + + if (comment.isNullObject) { + console.warn("No comments in the selection, so no range to get."); + return; + } + + console.log(`Comment location: ${range.text}`); + const contentRange: Word.CommentContentRange = comment.contentRange; + console.log("Comment content range:", contentRange); + }); +Word.Range#compareLocationWith:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/compare-location.yaml + + + // Compares the location of one paragraph in relation to another paragraph. + + await Word.run(async (context) => { + const paragraphs: Word.ParagraphCollection = context.document.body.paragraphs; + paragraphs.load("items"); + + await context.sync(); + + const firstParagraphAsRange: Word.Range = paragraphs.items[0].getRange(); + const secondParagraphAsRange: Word.Range = paragraphs.items[1].getRange(); + + const comparedLocation = firstParagraphAsRange.compareLocationWith(secondParagraphAsRange); + + await context.sync(); + + const locationValue: Word.LocationRelation = comparedLocation.value; + console.log(`Location of the first paragraph in relation to the second paragraph: ${locationValue}`); + }); +Word.Range#expandTo:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + const sentences: Word.RangeCollection = context.document + .getSelection() + .getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); + sentences.load("$none"); + await context.sync(); + + // Expand the range to the end of the paragraph to get all the complete sentences. + const sentencesToTheEndOfParagraph: Word.RangeCollection = sentences.items[0] + .getRange() + .expandTo( + context.document + .getSelection() + .paragraphs.getFirst() + .getRange(Word.RangeLocation.end) + ) + .getTextRanges(["."], false /* Don't trim spaces*/); + sentencesToTheEndOfParagraph.load("text"); + await context.sync(); + + for (let i = 0; i < sentencesToTheEndOfParagraph.items.length; i++) { + console.log(sentencesToTheEndOfParagraph.items[i].text); + } + }); +Word.Range#getComments:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Gets the comments in the selected content. + + await Word.run(async (context) => { + const comments: Word.CommentCollection = context.document.getSelection().getComments(); + + // Load objects to log in the console. + comments.load(); + await context.sync(); + + console.log("Comments:", comments); + }); +Word.Range#getContentControls:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Deletes the first checkbox content control found in the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + console.log(`About to delete checkbox content control with id: ${selectedContentControl.id}`); + selectedContentControl.delete(false); + await context.sync(); + + console.log("Deleted checkbox content control."); + }); +Word.Range#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml + + + // Places a dropdown list content control at the end of the selection. + + await Word.run(async (context) => { + let selection = context.document.getSelection(); + selection.getRange(Word.RangeLocation.end).insertContentControl(Word.ContentControlType.dropDownList); + await context.sync(); + + console.log("Dropdown list content control inserted at the end of the selection."); + }); +Word.Range#getReviewedText:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml + + + // Gets the reviewed text. + + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection(); + const before = range.getReviewedText(Word.ChangeTrackingVersion.original); + const after = range.getReviewedText(Word.ChangeTrackingVersion.current); + + await context.sync(); + + console.log("Reviewed text (before):", before.value, "Reviewed text (after):", after.value); + }); +Word.Range#getTextRanges:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + const sentences: Word.RangeCollection = context.document + .getSelection() + .getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); + sentences.load("$none"); + await context.sync(); + + // Expand the range to the end of the paragraph to get all the complete sentences. + const sentencesToTheEndOfParagraph: Word.RangeCollection = sentences.items[0] + .getRange() + .expandTo( + context.document + .getSelection() + .paragraphs.getFirst() + .getRange(Word.RangeLocation.end) + ) + .getTextRanges(["."], false /* Don't trim spaces*/); + sentencesToTheEndOfParagraph.load("text"); + await context.sync(); + + for (let i = 0; i < sentencesToTheEndOfParagraph.items.length; i++) { + console.log(sentencesToTheEndOfParagraph.items[i].text); + } + }); +Word.Range#insertComment:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml + + + // Sets a comment on the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("comment-text") as HTMLInputElement).value; + const comment: Word.Comment = context.document.getSelection().insertComment(text); + + // Load object to log in the console. + comment.load(); + await context.sync(); + + console.log("Comment inserted:", comment); + }); +Word.Range#insertContentControl:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + + + // Simulates creation of a template. First searches the document for + instances of the string "Contractor", + + // then changes the format of each search result, + + // then wraps each search result within a content control, + + // finally sets a tag and title property on each content control. + + await Word.run(async (context) => { + const results: Word.RangeCollection = context.document.body.search("Contractor"); + results.load("font/bold"); + + // Check to make sure these content controls haven't been added yet. + const customerContentControls: Word.ContentControlCollection = context.document.contentControls.getByTag("customer"); + customerContentControls.load("text"); + await context.sync(); + + if (customerContentControls.items.length === 0) { + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.bold = true; + let cc: Word.ContentControl = results.items[i].insertContentControl(); + cc.tag = "customer"; // This value is used in the next step of this sample. + cc.title = "Customer Name " + i; + } + } + await context.sync(); + }); +Word.Range#insertField:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml + + + // Inserts a Date field before selection. + + await Word.run(async (context) => { + const range: Word.Range = context.document.getSelection().getRange(); + + const field: Word.Field = range.insertField(Word.InsertLocation.before, Word.FieldType.date, '\\@ "M/d/yyyy h:mm am/pm"', true); + + field.load("result,code"); + await context.sync(); + + if (field.isNullObject) { + console.log("There are no fields in this document."); + } else { + console.log("Code of the field: " + field.code, "Result of the field: " + JSON.stringify(field.result)); + } + }); +Word.Range#insertFootnote:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Sets a footnote on the selected content. + + await Word.run(async (context) => { + const text = (document.getElementById("input-footnote") as HTMLInputElement).value; + const footnote: Word.NoteItem = context.document.getSelection().insertFootnote(text); + await context.sync(); + + console.log("Inserted footnote."); + }); +Word.Range#insertInlinePictureFromBase64:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a picture at the start of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const startRange: Word.Range = firstShapeWithTextBox.body.getRange(Word.RangeLocation.start); + const newPic: Word.InlinePicture = startRange.insertInlinePictureFromBase64( + getPictureBase64(), + Word.InsertLocation.start + ); + newPic.load(); + await context.sync(); + + console.log("New inline picture properties:", newPic); + }); + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + // Returns Base64-encoded image data for a sample picture. + + const pictureBase64 = + "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"; + return pictureBase64; +Word.Range#insertGeometricShape:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Inserts a moon geometric shape at the beginning of the selection. + const selection: Word.Range = context.document.getSelection(); + const shapeOptions: Word.InsertShapeOptions = { + height: 120, + width: 120, + left: 120, + }; + selection.insertGeometricShape(Word.GeometricShapeType.moon, shapeOptions); + await context.sync(); + + console.log("Inserted a moon."); + }); +Word.Range#insertTextBox:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a text box at the beginning of the selection. + const range: Word.Range = context.document.getSelection(); + const insertShapeOptions: Word.InsertShapeOptions = { + top: 0, + left: 0, + height: 100, + width: 100 + }; + + const newTextBox: Word.Shape = range.insertTextBox("placeholder text", insertShapeOptions); + await context.sync(); + + console.log("Inserted a text box at the beginning of the current selection."); + }); +Word.Range#footnotes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml + + + // Gets the footnotes in the selected document range. + + await Word.run(async (context) => { + const footnotes: Word.NoteItemCollection = context.document.getSelection().footnotes; + footnotes.load("length"); + await context.sync(); + + console.log("Number of footnotes in the selected range: " + footnotes.items.length); + }); +Word.Range#parentContentControl:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml + + + // Toggles the isChecked property of the first checkbox content control + found in the selection. + + await Word.run(async (context) => { + const selectedRange: Word.Range = context.document.getSelection(); + let selectedContentControl = selectedRange + .getContentControls({ + types: [Word.ContentControlType.checkBox] + }) + .getFirstOrNullObject(); + selectedContentControl.load("id,checkboxContentControl/isChecked"); + + await context.sync(); + + if (selectedContentControl.isNullObject) { + const parentContentControl: Word.ContentControl = selectedRange.parentContentControl; + parentContentControl.load("id,type,checkboxContentControl/isChecked"); + await context.sync(); + + if (parentContentControl.isNullObject || parentContentControl.type !== Word.ContentControlType.checkBox) { + console.warn("No checkbox content control is currently selected."); + return; + } else { + selectedContentControl = parentContentControl; + } + } + + const isCheckedBefore = selectedContentControl.checkboxContentControl.isChecked; + console.log("isChecked state before:", `id: ${selectedContentControl.id} ... isChecked: ${isCheckedBefore}`); + selectedContentControl.checkboxContentControl.isChecked = !isCheckedBefore; + selectedContentControl.load("id,checkboxContentControl/isChecked"); + await context.sync(); + + console.log( + "isChecked state after:", + `id: ${selectedContentControl.id} ... isChecked: ${selectedContentControl.checkboxContentControl.isChecked}` + ); + }); +Word.Range#styleBuiltIn:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml + + + await Word.run(async (context) => { + const header: Word.Range = context.document.body.insertText("This is a sample Heading 1 Title!!\n", + "Start" /*this means at the beginning of the body */); + header.styleBuiltIn = Word.BuiltInStyleName.heading1; + + await context.sync(); + }); +Word.RangeCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/search.yaml + + + // Does a basic text search and highlights matches in the document. + + await Word.run(async (context) => { + const results : Word.RangeCollection = context.document.body.search("extend"); + results.load("length"); + + await context.sync(); + + // Let's traverse the search results and highlight matches. + for (let i = 0; i < results.items.length; i++) { + results.items[i].font.highlightColor = "yellow"; + } + + await context.sync(); + }); +Word.RangeLocation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml + + + await Word.run(async (context) => { + // Get the complete sentence (as range) associated with the insertion point. + const sentences: Word.RangeCollection = context.document + .getSelection() + .getTextRanges(["."] /* Using the "." as delimiter */, false /*means without trimming spaces*/); + sentences.load("$none"); + await context.sync(); + + // Expand the range to the end of the paragraph to get all the complete sentences. + const sentencesToTheEndOfParagraph: Word.RangeCollection = sentences.items[0] + .getRange() + .expandTo( + context.document + .getSelection() + .paragraphs.getFirst() + .getRange(Word.RangeLocation.end) + ) + .getTextRanges(["."], false /* Don't trim spaces*/); + sentencesToTheEndOfParagraph.load("text"); + await context.sync(); + + for (let i = 0; i < sentencesToTheEndOfParagraph.items.length; i++) { + console.log(sentencesToTheEndOfParagraph.items[i].text); + } + }); +Word.RelativeHorizontalPosition:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the position of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to change the position of the first shape group found in document body:", shapeGroup.shapes); + firstShapeGroup.relativeVerticalPosition = Word.RelativeVerticalPosition.insideMargin; + firstShapeGroup.relativeHorizontalPosition = Word.RelativeHorizontalPosition.margin; + + console.log("Changed the position of the first shape group."); + }); +Word.RelativeSize:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the relative size of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log( + "About to change the relative size of the first shape group found in the document body:", + shapeGroup.shapes, + ); + firstShapeGroup.relativeHorizontalSize = Word.RelativeSize.insideMargin; + firstShapeGroup.relativeVerticalSize = Word.RelativeSize.bottomMargin; + firstShapeGroup.heightRelative = 50; + + console.log("Changed the relative size of the first shape group."); + }); +Word.RelativeVerticalPosition:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the position of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to change the position of the first shape group found in document body:", shapeGroup.shapes); + firstShapeGroup.relativeVerticalPosition = Word.RelativeVerticalPosition.insideMargin; + firstShapeGroup.relativeHorizontalPosition = Word.RelativeHorizontalPosition.margin; + + console.log("Changed the position of the first shape group."); + }); +Word.SaveBehavior:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml + + + // If the document hasn't been saved before, prompts + + // user with options for if or how they want to save. + + await Word.run(async (context) => { + context.document.save(Word.SaveBehavior.prompt); + await context.sync(); + }); +Word.SaveConfiguration:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/close-document-window.yaml + + + await Word.run(async (context) => { + // Closes the document window, prompting to save if this is a new document. + const window: Word.Window = context.document.activeWindow; + const closeOptions: Word.WindowCloseOptions = { saveChanges: Word.SaveConfiguration.promptToSaveChanges }; + console.log("About to close the document window..."); + window.close(closeOptions); + }); +Word.Section#getFooter:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-header-and-footer.yaml + + + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getFooter("Primary") + .insertParagraph("This is a primary footer.", "End"); + + await context.sync(); + }); +Word.Section#getHeader:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-header-and-footer.yaml + + + await Word.run(async (context) => { + context.document.sections + .getFirst() + .getHeader(Word.HeaderFooterType.primary) + .insertParagraph("This is a primary header.", "End"); + + await context.sync(); + }); +Word.Section:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-section-breaks.yaml + + + // Inserts a section break on the next page. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionNext, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section break on next page."); + }); +Word.SectionCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-section-breaks.yaml + + + // Inserts a section break on the next even page. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + body.insertBreak(Word.BreakType.sectionEven, Word.InsertLocation.end); + + await context.sync(); + + console.log("Inserted section break on next even page."); + }); +Word.SelectionMode:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/scroll-to-range.yaml + + + await Word.run(async (context) => { + // Select can be at the start or end of a range; this by definition moves the insertion point without selecting the range. + context.document.body.paragraphs.getLast().select(Word.SelectionMode.end); + + await context.sync(); + }); +Word.Setting:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Adds a new custom setting or + + // edits the value of an existing one. + + await Word.run(async (context) => { + const key = (document.getElementById("key") as HTMLInputElement).value; + if (key == "") { + console.error("Key shouldn't be empty."); + return; + } + + const value = (document.getElementById("value") as HTMLInputElement).value; + const settings: Word.SettingCollection = context.document.settings; + const setting: Word.Setting = settings.add(key, value); + setting.load(); + await context.sync(); + + console.log("Setting added or edited:", setting); + }); +Word.Setting#key:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Adds a new custom setting or + + // edits the value of an existing one. + + await Word.run(async (context) => { + const key = (document.getElementById("key") as HTMLInputElement).value; + if (key == "") { + console.error("Key shouldn't be empty."); + return; + } + + const value = (document.getElementById("value") as HTMLInputElement).value; + const settings: Word.SettingCollection = context.document.settings; + const setting: Word.Setting = settings.add(key, value); + setting.load(); + await context.sync(); + + console.log("Setting added or edited:", setting); + }); +Word.Setting#value:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Adds a new custom setting or + + // edits the value of an existing one. + + await Word.run(async (context) => { + const key = (document.getElementById("key") as HTMLInputElement).value; + if (key == "") { + console.error("Key shouldn't be empty."); + return; + } + + const value = (document.getElementById("value") as HTMLInputElement).value; + const settings: Word.SettingCollection = context.document.settings; + const setting: Word.Setting = settings.add(key, value); + setting.load(); + await context.sync(); + + console.log("Setting added or edited:", setting); + }); +Word.SettingCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Deletes all custom settings this add-in had set on this document. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + settings.deleteAll(); + await context.sync(); + console.log("All settings deleted."); + }); +Word.SettingCollection#add:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Adds a new custom setting or + + // edits the value of an existing one. + + await Word.run(async (context) => { + const key = (document.getElementById("key") as HTMLInputElement).value; + if (key == "") { + console.error("Key shouldn't be empty."); + return; + } + + const value = (document.getElementById("value") as HTMLInputElement).value; + const settings: Word.SettingCollection = context.document.settings; + const setting: Word.Setting = settings.add(key, value); + setting.load(); + await context.sync(); + + console.log("Setting added or edited:", setting); + }); +Word.SettingCollection#items:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml + + + // Gets all custom settings this add-in set on this document. + + await Word.run(async (context) => { + const settings: Word.SettingCollection = context.document.settings; + settings.load("items"); + await context.sync(); + + if (settings.items.length == 0) { + console.log("There are no settings."); + } else { + console.log("All settings:"); + for (let i = 0; i < settings.items.length; i++) { + console.log(settings.items[i]); + } + } + }); +Word.Shading:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates shading properties (e.g., texture, pattern colors) of the + specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update shading properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const shading: Word.Shading = style.shading; + shading.load(); + await context.sync(); + + shading.backgroundPatternColor = "blue"; + shading.foregroundPatternColor = "yellow"; + shading.texture = Word.ShadingTextureType.darkTrellis; + + console.log("Updated shading."); + } + }); +Word.ShadingTextureType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates shading properties (e.g., texture, pattern colors) of the + specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update shading properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const shading: Word.Shading = style.shading; + shading.load(); + await context.sync(); + + shading.backgroundPatternColor = "blue"; + shading.foregroundPatternColor = "yellow"; + shading.texture = Word.ShadingTextureType.darkTrellis; + + console.log("Updated shading."); + } + }); +Word.Shape:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets the properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.top = 115; + firstShapeWithTextBox.left = 0; + firstShapeWithTextBox.width = 50; + firstShapeWithTextBox.height = 50; + await context.sync(); + + console.log("The first text box's properties were updated:", firstShapeWithTextBox); + }); +Word.Shape#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Deletes the first text box. + context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirst().delete(); + await context.sync(); + + console.log("The first text box in document was deleted."); + }); +Word.Shape#group:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); +Word.Shape#moveHorizontally:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Moves the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to move the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.moveHorizontally(-10); + firstShapeGroup.moveVertically(50); + + console.log("Moved the first shape group."); + }); +Word.Shape#moveVertically:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Moves the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to move the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.moveHorizontally(-10); + firstShapeGroup.moveVertically(50); + + console.log("Moved the first shape group."); + }); +Word.Shape#scaleHeight:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Scales the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to scale the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.scaleHeight(0.75, Word.ShapeScaleType.currentSize); + firstShapeGroup.scaleWidth(0.5, Word.ShapeScaleType.currentSize, Word.ShapeScaleFrom.scaleFromBottomRight); + + console.log("Scaled the first shape group."); + }); +Word.Shape#scaleWidth:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Scales the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to scale the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.scaleHeight(0.75, Word.ShapeScaleType.currentSize); + firstShapeGroup.scaleWidth(0.5, Word.ShapeScaleType.currentSize, Word.ShapeScaleFrom.scaleFromBottomRight); + + console.log("Scaled the first shape group."); + }); +Word.Shape#select:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); +Word.Shape#body:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a content control into the first paragraph in the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const firstParagraphInTextBox: Word.Paragraph = firstShapeWithTextBox.body.paragraphs.getFirst(); + const newControl: Word.ContentControl = firstParagraphInTextBox.insertContentControl(); + newControl.load(); + await context.sync(); + + console.log("New content control properties:", newControl); + }); +Word.Shape#canvas:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-canvases.yaml + + + await Word.run(async (context) => { + // Inserts a canvas in the document. + const canvasShape: Word.Shape = context.document.getSelection().insertCanvas(); + canvasShape.load(); + await context.sync(); + + canvasShape.select(); + console.log("Inserted canvas:", canvasShape); + + const canvas: Word.Canvas = canvasShape.canvas; + canvas.load("shape,shapes"); + await context.sync(); + + console.log("Canvas object:", canvas); + }); +Word.Shape#fill:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Gets the color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + const moonFillType = moonFill.type as Word.ShapeFillType; + + console.log("Color fill properties of the first moon found in the document body:"); + console.log(`\tForeground color: ${moonFill.foregroundColor}`); + console.log(`\tBackground color: ${moonFill.backgroundColor}`); + console.log(`\tTransparency: ${moonFill.transparency}`); + console.log(`\tFill type: ${moonFillType}`); + }); +Word.Shape#geometricShapeType:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Gets the first geometric shape found in the document body. + const geometricShape: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.geometricShape]) + .getFirstOrNullObject(); + geometricShape.load(); + await context.sync(); + + if (geometricShape.isNullObject) { + console.log("No geometric shapes found in the document body."); + return; + } + + console.log( + `First geometric shape found in the document body is of type ${geometricShape.geometricShapeType}:`, + geometricShape, + ); + }); +Word.Shape#heightRelative:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the relative size of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log( + "About to change the relative size of the first shape group found in the document body:", + shapeGroup.shapes, + ); + firstShapeGroup.relativeHorizontalSize = Word.RelativeSize.insideMargin; + firstShapeGroup.relativeVerticalSize = Word.RelativeSize.bottomMargin; + firstShapeGroup.heightRelative = 50; + + console.log("Changed the relative size of the first shape group."); + }); +Word.Shape#relativeHorizontalPosition:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the position of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to change the position of the first shape group found in document body:", shapeGroup.shapes); + firstShapeGroup.relativeVerticalPosition = Word.RelativeVerticalPosition.insideMargin; + firstShapeGroup.relativeHorizontalPosition = Word.RelativeHorizontalPosition.margin; + + console.log("Changed the position of the first shape group."); + }); +Word.Shape#relativeHorizontalSize:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the relative size of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log( + "About to change the relative size of the first shape group found in the document body:", + shapeGroup.shapes, + ); + firstShapeGroup.relativeHorizontalSize = Word.RelativeSize.insideMargin; + firstShapeGroup.relativeVerticalSize = Word.RelativeSize.bottomMargin; + firstShapeGroup.heightRelative = 50; + + console.log("Changed the relative size of the first shape group."); + }); +Word.Shape#relativeVerticalPosition:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the position of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to change the position of the first shape group found in document body:", shapeGroup.shapes); + firstShapeGroup.relativeVerticalPosition = Word.RelativeVerticalPosition.insideMargin; + firstShapeGroup.relativeHorizontalPosition = Word.RelativeHorizontalPosition.margin; + + console.log("Changed the position of the first shape group."); + }); +Word.Shape#relativeVerticalSize:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Changes the relative size of the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log( + "About to change the relative size of the first shape group found in the document body:", + shapeGroup.shapes, + ); + firstShapeGroup.relativeHorizontalSize = Word.RelativeSize.insideMargin; + firstShapeGroup.relativeVerticalSize = Word.RelativeSize.bottomMargin; + firstShapeGroup.heightRelative = 50; + + console.log("Changed the relative size of the first shape group."); + }); +Word.Shape#shapeGroup:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); +Word.Shape#textFrame:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets the text frame of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text frame of first text box:", shape.textFrame); + }); +Word.Shape#textWrap:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text wrap properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textWrap"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text wrap properties of first text box:", shape.textWrap); + }); +Word.Shape#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text boxes in the main document. + const shapes: Word.ShapeCollection = context.document.body.shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the main document: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the main document has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the main document doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the main document."); + } + }); +Word.ShapeAutoSize:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.ShapeCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text boxes in the main document. + const shapes: Word.ShapeCollection = context.document.body.shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the main document: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the main document has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the main document doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the main document."); + } + }); +Word.ShapeCollection#getByGeometricTypes:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Gets the moon geometric shapes from the document body. + const moons: Word.ShapeCollection = context.document.body.shapes.getByGeometricTypes([ + Word.GeometricShapeType.moon, + ]); + moons.load(); + await context.sync(); + + console.log("Moons found in the document body:", moons); + }); +Word.ShapeCollection#getByTypes:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets the properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.top = 115; + firstShapeWithTextBox.left = 0; + firstShapeWithTextBox.width = 50; + firstShapeWithTextBox.height = 50; + await context.sync(); + + console.log("The first text box's properties were updated:", firstShapeWithTextBox); + }); +Word.ShapeCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Inserts a content control into the first paragraph in the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirst(); + firstShapeWithTextBox.load("type/body"); + await context.sync(); + + const firstParagraphInTextBox: Word.Paragraph = firstShapeWithTextBox.body.paragraphs.getFirst(); + const newControl: Word.ContentControl = firstParagraphInTextBox.insertContentControl(); + newControl.load(); + await context.sync(); + + console.log("New content control properties:", newControl); + }); +Word.ShapeCollection#getFirstOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text from the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("body/text"); + await context.sync(); + + console.log( + shape.isNullObject + ? "No shapes with text boxes found in the main document." + : `Text in first text box: ${shape.body.text}` + ); + }); +Word.ShapeCollection#group:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); +Word.ShapeFill:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Gets the color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + const moonFillType = moonFill.type as Word.ShapeFillType; + + console.log("Color fill properties of the first moon found in the document body:"); + console.log(`\tForeground color: ${moonFill.foregroundColor}`); + console.log(`\tBackground color: ${moonFill.backgroundColor}`); + console.log(`\tTransparency: ${moonFill.transparency}`); + console.log(`\tFill type: ${moonFillType}`); + }); +Word.ShapeFill#clear:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Sets color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + console.log("Current fill properties of the first moon found in the document body:", moonFill); + + moonFill.setSolidColor("green"); + moonFill.load(); + await context.sync(); + + console.log("Updated color fill properties of the first moon found in the document body:", moonFill); + }); +Word.ShapeFill#setSolidColor:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Sets color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + console.log("Current fill properties of the first moon found in the document body:", moonFill); + + moonFill.setSolidColor("green"); + moonFill.load(); + await context.sync(); + + console.log("Updated color fill properties of the first moon found in the document body:", moonFill); + }); +Word.ShapeFillType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml + + + await Word.run(async (context) => { + // Gets the color fill properties of the first moon found in the document body. + const moon: Word.Shape = context.document.body.shapes + .getByGeometricTypes([Word.GeometricShapeType.moon]) + .getFirstOrNullObject(); + moon.load("fill"); + await context.sync(); + + if (moon.isNullObject) { + console.log("No moons found in the document body."); + return; + } + + const moonFill: Word.ShapeFill = moon.fill; + const moonFillType = moonFill.type as Word.ShapeFillType; + + console.log("Color fill properties of the first moon found in the document body:"); + console.log(`\tForeground color: ${moonFill.foregroundColor}`); + console.log(`\tBackground color: ${moonFill.backgroundColor}`); + console.log(`\tTransparency: ${moonFill.transparency}`); + console.log(`\tFill type: ${moonFillType}`); + }); +Word.ShapeGroup:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Groups the shapes (including text boxes and pictures) found in the document body. + const shapes: Word.ShapeCollection = context.document.body.shapes.getByTypes([ + Word.ShapeType.geometricShape, + Word.ShapeType.textBox, + Word.ShapeType.picture, + ]); + shapes.load("items"); + await context.sync(); + + const numShapes = shapes.items.length; + if (numShapes === 0) { + console.log("No shapes found in the document body."); + return; + } + + console.log(`Number of shapes to group: ${numShapes}`); + + const groupedShape: Word.Shape = shapes.group(); + groupedShape.load("shapeGroup/shapes"); + await context.sync(); + + const shapeGroup: Word.ShapeGroup = groupedShape.shapeGroup; + console.log("Shapes grouped:", shapeGroup.shapes); + groupedShape.select(); + }); +Word.ShapeGroup#ungroup:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Ungroups the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to ungroup the first shape group found in the document body:", shapeGroup.shapes); + shapeGroup.ungroup(); + + console.log("Ungrouped the first shape group."); + }); +Word.ShapeGroup#shapes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Moves the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to move the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.moveHorizontally(-10); + firstShapeGroup.moveVertically(50); + + console.log("Moved the first shape group."); + }); +Word.ShapeScaleFrom:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Scales the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to scale the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.scaleHeight(0.75, Word.ShapeScaleType.currentSize); + firstShapeGroup.scaleWidth(0.5, Word.ShapeScaleType.currentSize, Word.ShapeScaleFrom.scaleFromBottomRight); + + console.log("Scaled the first shape group."); + }); +Word.ShapeScaleType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml + + + await Word.run(async (context) => { + // Scales the first set of grouped shapes (including text boxes) found in the document body. + const firstShapeGroup: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.group]) + .getFirstOrNullObject(); + firstShapeGroup.load("shapeGroup/shapes"); + await context.sync(); + + if (firstShapeGroup.isNullObject) { + console.log("No shape groups found in the document body."); + return; + } + + let shapeGroup: Word.ShapeGroup = firstShapeGroup.shapeGroup; + console.log("About to scale the first shape group found in the document body:", shapeGroup.shapes); + firstShapeGroup.scaleHeight(0.75, Word.ShapeScaleType.currentSize); + firstShapeGroup.scaleWidth(0.5, Word.ShapeScaleType.currentSize, Word.ShapeScaleFrom.scaleFromBottomRight); + + console.log("Scaled the first shape group."); + }); +Word.ShapeTextOrientation:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.ShapeTextVerticalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.ShapeTextWrap:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text wrap properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textWrap"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text wrap properties of first text box:", shape.textWrap); + }); +Word.ShapeTextWrap#side:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text wrap properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirstOrNullObject(); + firstShapeWithTextBox.load("textWrap"); + await context.sync(); + + if (firstShapeWithTextBox.isNullObject) { + console.log("No shapes with text boxes found in main document."); + return; + } + + const textWrap: Word.ShapeTextWrap = firstShapeWithTextBox.textWrap; + textWrap.type = Word.ShapeTextWrapType.square; + textWrap.side = Word.ShapeTextWrapSide.both; + + console.log("The first text box's text wrap properties were updated:", textWrap); + }); +Word.ShapeTextWrap#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text wrap properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirstOrNullObject(); + firstShapeWithTextBox.load("textWrap"); + await context.sync(); + + if (firstShapeWithTextBox.isNullObject) { + console.log("No shapes with text boxes found in main document."); + return; + } + + const textWrap: Word.ShapeTextWrap = firstShapeWithTextBox.textWrap; + textWrap.type = Word.ShapeTextWrapType.square; + textWrap.side = Word.ShapeTextWrapSide.both; + + console.log("The first text box's text wrap properties were updated:", textWrap); + }); +Word.ShapeTextWrapSide:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text wrap properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirstOrNullObject(); + firstShapeWithTextBox.load("textWrap"); + await context.sync(); + + if (firstShapeWithTextBox.isNullObject) { + console.log("No shapes with text boxes found in main document."); + return; + } + + const textWrap: Word.ShapeTextWrap = firstShapeWithTextBox.textWrap; + textWrap.type = Word.ShapeTextWrapType.square; + textWrap.side = Word.ShapeTextWrapSide.both; + + console.log("The first text box's text wrap properties were updated:", textWrap); + }); +Word.ShapeTextWrapType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text wrap properties of the first text box. + const firstShapeWithTextBox: Word.Shape = context.document.body.shapes + .getByTypes([Word.ShapeType.textBox]) + .getFirstOrNullObject(); + firstShapeWithTextBox.load("textWrap"); + await context.sync(); + + if (firstShapeWithTextBox.isNullObject) { + console.log("No shapes with text boxes found in main document."); + return; + } + + const textWrap: Word.ShapeTextWrap = firstShapeWithTextBox.textWrap; + textWrap.type = Word.ShapeTextWrapType.square; + textWrap.side = Word.ShapeTextWrapSide.both; + + console.log("The first text box's text wrap properties were updated:", textWrap); + }); +Word.ShapeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets text boxes in the main document. + const shapes: Word.ShapeCollection = context.document.body.shapes; + shapes.load(); + await context.sync(); + + if (shapes.items.length > 0) { + console.log(`Number of shapes found in the main document: ${shapes.items.length}`); + shapes.items.forEach(function (shape, index) { + if (shape.type === Word.ShapeType.textBox) { + console.log(`Shape ${index} in the main document has a text box. Properties:`, shape); + } else { + console.log(`Shape ${index} in the main document doesn't have a text box.`); + } + }); + } else { + console.log("No shapes found in the main document."); + } + }); +Word.Style:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Applies the specified style to a paragraph. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.paragraph) { + console.log(`The '${styleName}' style isn't a paragraph style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + const paragraph: Word.Paragraph = body.paragraphs.getFirst(); + paragraph.style = style.nameLocal; + console.log(`'${styleName}' style applied to first paragraph.`); + } + }); +Word.Style#delete:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Deletes the custom style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to delete."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.delete(); + console.log(`Successfully deleted custom style '${styleName}'.`); + } + }); +Word.Style#borders:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates border properties (e.g., type, width, color) of the specified + style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update border properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const borders: Word.BorderCollection = style.borders; + borders.load("items"); + await context.sync(); + + borders.outsideBorderType = Word.BorderType.dashed; + borders.outsideBorderWidth = Word.BorderWidth.pt025; + borders.outsideBorderColor = "green"; + console.log("Updated outside borders."); + } + }); +Word.Style#font:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates font properties (e.g., color, size) of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update font properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const font: Word.Font = style.font; + font.color = "#FF0000"; + font.size = 20; + console.log(`Successfully updated font properties of the '${styleName}' style.`); + } + }); +Word.Style#listTemplate:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.Style#nameLocal:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Applies the specified style to a paragraph. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.paragraph) { + console.log(`The '${styleName}' style isn't a paragraph style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + const paragraph: Word.Paragraph = body.paragraphs.getFirst(); + paragraph.style = style.nameLocal; + console.log(`'${styleName}' style applied to first paragraph.`); + } + }); +Word.Style#paragraphFormat:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Sets certain aspects of the specified style's paragraph format e.g., the + left indent size and the alignment. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update its paragraph format."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + style.paragraphFormat.leftIndent = 30; + style.paragraphFormat.alignment = Word.Alignment.centered; + console.log(`Successfully the paragraph format of the '${styleName}' style.`); + } + }); +Word.Style#shading:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Updates shading properties (e.g., texture, pattern colors) of the + specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to update shading properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else { + const shading: Word.Shading = style.shading; + shading.load(); + await context.sync(); + + shading.backgroundPatternColor = "blue"; + shading.foregroundPatternColor = "yellow"; + shading.texture = Word.ShadingTextureType.darkTrellis; + + console.log("Updated shading."); + } + }); +Word.StyleCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Gets the number of available styles stored with the document. + + await Word.run(async (context) => { + const styles: Word.StyleCollection = context.document.getStyles(); + const count = styles.getCount(); + await context.sync(); + + console.log(`Number of styles: ${count.value}`); + }); +Word.StyleCollection#getByNameOrNullObject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Adds a new style. + + await Word.run(async (context) => { + const newStyleName = (document.getElementById("new-style-name") as HTMLInputElement).value; + if (newStyleName == "") { + console.warn("Enter a style name to add."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(newStyleName); + style.load(); + await context.sync(); + + if (!style.isNullObject) { + console.warn( + `There's an existing style with the same name '${newStyleName}'! Please provide another style name.` + ); + return; + } + + const newStyleType = ((document.getElementById("new-style-type") as HTMLSelectElement).value as unknown) as Word.StyleType; + context.document.addStyle(newStyleName, newStyleType); + await context.sync(); + + console.log(newStyleName + " has been added to the style list."); + }); +Word.StyleCollection#getCount:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Gets the number of available styles stored with the document. + + await Word.run(async (context) => { + const styles: Word.StyleCollection = context.document.getStyles(); + const count = styles.getCount(); + await context.sync(); + + console.log(`Number of styles: ${count.value}`); + }); +Word.StyleType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml + + + // Applies the specified style to a paragraph. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to apply."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load(); + await context.sync(); + + if (style.isNullObject) { + console.warn(`There's no existing style with the name '${styleName}'.`); + } else if (style.type != Word.StyleType.paragraph) { + console.log(`The '${styleName}' style isn't a paragraph style.`); + } else { + const body: Word.Body = context.document.body; + body.clear(); + body.insertParagraph( + "Do you want to create a solution that extends the functionality of Word? You can use the Office Add-ins platform to extend Word clients running on the web, on a Windows desktop, or on a Mac.", + "Start" + ); + const paragraph: Word.Paragraph = body.paragraphs.getFirst(); + paragraph.style = style.nameLocal; + console.log(`'${styleName}' style applied to first paragraph.`); + } + }); +Word.Table#getBorder:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.Table#getCell:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + + + // Gets the content of the first cell in the first table. + + await Word.run(async (context) => { + const firstCell: Word.Body = context.document.body.tables.getFirst().getCell(0, 0).body; + firstCell.load("text"); + + await context.sync(); + console.log("First cell's text is: " + firstCell.text); + }); +Word.Table#getCellPadding:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets cell padding details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const cellPaddingLocation = Word.CellPaddingLocation.right; + const cellPadding = firstTable.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table: ${cellPadding.value} points` + ); + }); +Word.Table#alignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets alignment details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + firstTable.load(["alignment", "horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table:`, `- Alignment of the table within the containing page column: ${firstTable.alignment}`, `- Horizontal alignment of every cell in the table: ${firstTable.horizontalAlignment}`, `- Vertical alignment of every cell in the table: ${firstTable.verticalAlignment}`); + }); +Word.Table#horizontalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets alignment details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + firstTable.load(["alignment", "horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table:`, `- Alignment of the table within the containing page column: ${firstTable.alignment}`, `- Horizontal alignment of every cell in the table: ${firstTable.horizontalAlignment}`, `- Vertical alignment of every cell in the table: ${firstTable.verticalAlignment}`); + }); +Word.Table#rows:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first row of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + firstTableRow.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first row:`, `- Horizontal alignment of every cell in the row: ${firstTableRow.horizontalAlignment}`, `- Vertical alignment of every cell in the row: ${firstTableRow.verticalAlignment}`); + }); +Word.Table#verticalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets alignment details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + firstTable.load(["alignment", "horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table:`, `- Alignment of the table within the containing page column: ${firstTable.alignment}`, `- Horizontal alignment of every cell in the table: ${firstTable.horizontalAlignment}`, `- Vertical alignment of every cell in the table: ${firstTable.verticalAlignment}`); + }); +Word.Table:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + + + await Word.run(async (context) => { + // Use a two-dimensional array to hold the initial table values. + const data = [ + ["Tokyo", "Beijing", "Seattle"], + ["Apple", "Orange", "Pineapple"] + ]; + const table: Word.Table = context.document.body.insertTable(2, 3, "Start", data); + table.styleBuiltIn = Word.BuiltInStyleName.gridTable5Dark_Accent2; + table.styleFirstColumn = false; + + await context.sync(); + }); +Word.TableBorder:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableBorder#color:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableBorder#type:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableBorder#width:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const borderLocation = Word.BorderLocation.top; + const border: Word.TableBorder = firstTable.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableCell:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableCell#getBorder:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first of the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstCell: Word.TableCell = firstTable.getCell(0, 0); + const borderLocation = "Left"; + const border: Word.TableBorder = firstCell.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first cell:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableCell#getCellPadding:member(2): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets cell padding details about the first cell of the first table in the + document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstCell: Word.TableCell = firstTable.getCell(0, 0); + const cellPaddingLocation = "Left"; + const cellPadding = firstCell.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table's first cell: ${cellPadding.value} points` + ); + }); +Word.TableCell#horizontalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableCell#verticalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableCellCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets alignment details about the first table in the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + firstTable.load(["alignment", "horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table:`, `- Alignment of the table within the containing page column: ${firstTable.alignment}`, `- Horizontal alignment of every cell in the table: ${firstTable.horizontalAlignment}`, `- Vertical alignment of every cell in the table: ${firstTable.verticalAlignment}`); + }); +Word.TableCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml + + + // Gets the content of the first cell in the first table. + + await Word.run(async (context) => { + const firstCell: Word.Body = context.document.body.tables.getFirst().getCell(0, 0).body; + firstCell.load("text"); + + await context.sync(); + console.log("First cell's text is: " + firstCell.text); + }); +Word.TableRow:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableRow#getBorder:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first row of the first table in the + document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const borderLocation = Word.BorderLocation.bottom; + const border: Word.TableBorder = firstTableRow.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first row:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableRow#getCellPadding:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets cell padding details about the first row of the first table in the + document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const cellPaddingLocation = Word.CellPaddingLocation.bottom; + const cellPadding = firstTableRow.getCellPadding(cellPaddingLocation); + await context.sync(); + + console.log( + `Cell padding details about the ${cellPaddingLocation} border of the first table's first row: ${cellPadding.value} points` + ); + }); +Word.TableRow#cells:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first cell of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const firstCell: Word.TableCell = firstTableRow.cells.getFirst(); + firstCell.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first cell:`, `- Horizontal alignment of the cell's content: ${firstCell.horizontalAlignment}`, `- Vertical alignment of the cell's content: ${firstCell.verticalAlignment}`); + }); +Word.TableRowCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first row of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + firstTableRow.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first row:`, `- Horizontal alignment of every cell in the row: ${firstTableRow.horizontalAlignment}`, `- Vertical alignment of every cell in the row: ${firstTableRow.verticalAlignment}`); + }); +Word.TableRowCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets border details about the first row of the first table in the + document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + const borderLocation = Word.BorderLocation.bottom; + const border: Word.TableBorder = firstTableRow.getBorder(borderLocation); + border.load(["type", "color", "width"]); + await context.sync(); + + console.log(`Details about the ${borderLocation} border of the first table's first row:`, `- Color: ${border.color}`, `- Type: ${border.type}`, `- Width: ${border.width} points`); + }); +Word.TableStyle:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml + + + // Gets the table style properties and displays them in the form. + + const styleName = (document.getElementById("style-name") as + HTMLInputElement).value; + + if (styleName == "") { + console.warn("Please input a table style name."); + return; + } + + + await Word.run(async (context) => { + const tableStyle: Word.TableStyle = context.document.getStyles().getByName(styleName).tableStyle; + tableStyle.load(); + await context.sync(); + + if (tableStyle.isNullObject) { + console.warn(`There's no existing table style with the name '${styleName}'.`); + return; + } + + console.log(tableStyle); + (document.getElementById("alignment") as HTMLInputElement).value = tableStyle.alignment; + (document.getElementById("allow-break-across-page") as HTMLInputElement).value = tableStyle.allowBreakAcrossPage.toString(); + (document.getElementById("top-cell-margin") as HTMLInputElement).value = tableStyle.topCellMargin; + (document.getElementById("bottom-cell-margin") as HTMLInputElement).value = tableStyle.bottomCellMargin; + (document.getElementById("left-cell-margin") as HTMLInputElement).value = tableStyle.leftCellMargin; + (document.getElementById("right-cell-margin") as HTMLInputElement).value = tableStyle.rightCellMargin; + (document.getElementById("cell-spacing") as HTMLInputElement).value = tableStyle.cellSpacing; + }); +Word.TextFrame:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Gets the text frame of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + console.log("Text frame of first text box:", shape.textFrame); + }); +Word.TextFrame#autoSizeSetting:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.TextFrame#orientation:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.TextFrame#verticalAlignment:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml + + + await Word.run(async (context) => { + // Sets text frame properties of the first text box in the main document. + const shape: Word.Shape = context.document.body.shapes.getByTypes([Word.ShapeType.textBox]).getFirstOrNullObject(); + shape.load("textFrame"); + await context.sync(); + + if (shape.isNullObject) { + console.log("No shapes with text boxes found in the main document."); + return; + } + + const textFrame: Word.TextFrame = shape.textFrame; + textFrame.verticalAlignment = Word.ShapeTextVerticalAlignment.bottom; + textFrame.orientation = Word.ShapeTextOrientation.vertical270; + textFrame.autoSizeSetting = Word.ShapeAutoSize.shapeToFitText; + + console.log("The first text box's text frame properties were updated:", textFrame); + }); +Word.TrackedChange:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the next (second) tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + await context.sync(); + + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const nextTrackedChange: Word.TrackedChange = trackedChange.getNext(); + await context.sync(); + + nextTrackedChange.load(["author", "date", "text", "type"]); + await context.sync(); + + console.log(nextTrackedChange); + }); +Word.TrackedChange#accept:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Accepts the first tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + trackedChange.load(); + await context.sync(); + + console.log("First tracked change:", trackedChange); + trackedChange.accept(); + console.log("Accepted the first tracked change."); + }); +Word.TrackedChange#getNext:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the next (second) tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + await context.sync(); + + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const nextTrackedChange: Word.TrackedChange = trackedChange.getNext(); + await context.sync(); + + nextTrackedChange.load(["author", "date", "text", "type"]); + await context.sync(); + + console.log(nextTrackedChange); + }); +Word.TrackedChange#getRange:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the range of the first tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const range: Word.Range = trackedChange.getRange(); + range.load(); + await context.sync(); + + console.log("range.text: " + range.text); + }); +Word.TrackedChange#reject:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Rejects the first tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + trackedChange.load(); + await context.sync(); + + console.log("First tracked change:", trackedChange); + trackedChange.reject(); + console.log("Rejected the first tracked change."); + }); +Word.TrackedChangeCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the range of the first tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const range: Word.Range = trackedChange.getRange(); + range.load(); + await context.sync(); + + console.log("range.text: " + range.text); + }); +Word.TrackedChangeCollection#acceptAll:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Accepts all tracked changes. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.acceptAll(); + console.log("Accepted all tracked changes."); + }); +Word.TrackedChangeCollection#getFirst:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the range of the first tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const range: Word.Range = trackedChange.getRange(); + range.load(); + await context.sync(); + + console.log("range.text: " + range.text); + }); +Word.TrackedChangeCollection#rejectAll:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Rejects all tracked changes. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + trackedChanges.rejectAll(); + console.log("Rejected all tracked changes."); + }); +Word.TrackedChangeType:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml + + + // Gets the next (second) tracked change. + + await Word.run(async (context) => { + const body: Word.Body = context.document.body; + const trackedChanges: Word.TrackedChangeCollection = body.getTrackedChanges(); + await context.sync(); + + const trackedChange: Word.TrackedChange = trackedChanges.getFirst(); + await context.sync(); + + const nextTrackedChange: Word.TrackedChange = trackedChange.getNext(); + await context.sync(); + + nextTrackedChange.load(["author", "date", "text", "type"]); + await context.sync(); + + console.log(nextTrackedChange); + }); +Word.TrailingCharacter:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml + + + // Gets the properties of the specified style. + + await Word.run(async (context) => { + const styleName = (document.getElementById("style-name-to-use") as HTMLInputElement).value; + if (styleName == "") { + console.warn("Enter a style name to get properties."); + return; + } + + const style: Word.Style = context.document.getStyles().getByNameOrNullObject(styleName); + style.load("type"); + await context.sync(); + + if (style.isNullObject || style.type != Word.StyleType.list) { + console.warn(`There's no existing style with the name '${styleName}'. Or this isn't a list style.`); + } else { + // Load objects to log properties and their values in the console. + style.load(); + style.listTemplate.load(); + await context.sync(); + + console.log(`Properties of the '${styleName}' style:`, style); + + const listLevels = style.listTemplate.listLevels; + listLevels.load("items"); + await context.sync(); + + console.log(`List levels of the '${styleName}' style:`, listLevels); + } + }); +Word.VerticalAlignment:enum: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml + + + // Gets content alignment details about the first row of the first table in + the document. + + await Word.run(async (context) => { + const firstTable: Word.Table = context.document.body.tables.getFirst(); + const firstTableRow: Word.TableRow = firstTable.rows.getFirst(); + firstTableRow.load(["horizontalAlignment", "verticalAlignment"]); + await context.sync(); + + console.log(`Details about the alignment of the first table's first row:`, `- Horizontal alignment of every cell in the row: ${firstTableRow.horizontalAlignment}`, `- Vertical alignment of every cell in the row: ${firstTableRow.verticalAlignment}`); + }); +Word.Window:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the first paragraph of each page. + console.log("Getting first paragraph of each page..."); + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get all pages. + const pages: Word.PageCollection = activePane.pages; + pages.load(); + + await context.sync(); + + // Get page index and paragraphs of each page. + const pagesIndexes = []; + const pagesNumberOfParagraphs = []; + const pagesFirstParagraphText = []; + for (let i = 0; i < pages.items.length; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + + const paragraphs = page.getRange().paragraphs; + paragraphs.load("items/length"); + pagesNumberOfParagraphs.push(paragraphs); + + const firstParagraph = paragraphs.getFirst(); + firstParagraph.load("text"); + pagesFirstParagraphText.push(firstParagraph); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + console.log(`Number of paragraphs: ${pagesNumberOfParagraphs[i].items.length}`); + console.log("First paragraph's text:", pagesFirstParagraphText[i].text); + } + }); +Word.Window#close:member(1): + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/close-document-window.yaml + + + await Word.run(async (context) => { + // Closes the document window, prompting to save if this is a new document. + const window: Word.Window = context.document.activeWindow; + const closeOptions: Word.WindowCloseOptions = { saveChanges: Word.SaveConfiguration.promptToSaveChanges }; + console.log("About to close the document window..."); + window.close(closeOptions); + }); +Word.Window#activePane:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the pages enclosing the viewport. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load(); + + // Get the active pane. + const activePane: Word.Pane = activeWindow.activePane; + activePane.load(); + + // Get pages enclosing the viewport. + const pages: Word.PageCollection = activePane.pagesEnclosingViewport; + pages.load(); + + await context.sync(); + + // Log the number of pages. + const pageCount = pages.items.length; + console.log(`Number of pages enclosing the viewport: ${pageCount}`); + + // Log index info of these pages. + const pagesIndexes = []; + for (let i = 0; i < pageCount; i++) { + const page = pages.items[i]; + page.load("index"); + pagesIndexes.push(page); + } + + await context.sync(); + + for (let i = 0; i < pagesIndexes.length; i++) { + console.log(`Page index: ${pagesIndexes[i].index}`); + } + }); +Word.Window#panes:member: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets all the panes in the active document window. + + // Get the active window. + const activeWindow: Word.Window = context.document.activeWindow; + activeWindow.load("panes/items/length"); + + await context.sync(); + + const panes: Word.PaneCollection = activeWindow.panes; + console.log(`Number of panes in the current document window: ${panes.items.length}`); + }); +Word.WindowCloseOptions:interface: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/close-document-window.yaml + + + await Word.run(async (context) => { + // Closes the document window, prompting to save if this is a new document. + const window: Word.Window = context.document.activeWindow; + const closeOptions: Word.WindowCloseOptions = { saveChanges: Word.SaveConfiguration.promptToSaveChanges }; + console.log("About to close the document window..."); + window.close(closeOptions); + }); +Word.WindowCollection:class: + - >- + // Link to full sample: + https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml + + + await Word.run(async (context) => { + // Gets the document windows. + const windows: Word.WindowCollection = context.document.windows; + windows.load("windows/items/length"); + + await context.sync(); + + console.log(`Number of windows for this document: ${windows.items.length}`); + }); diff --git a/tsconfig.json b/tsconfig.json index 0fd566d63..a3ff66e69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { - "target": "es6", + "target": "es2018", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, + "esModuleInterop": true, "removeComments": false, "noImplicitAny": false, "noEmitOnError": true, @@ -17,8 +18,10 @@ "rootDir": "config", "lib": [ "dom", - "es2015" + "es2018" ], - "pretty": true + "pretty": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true } } \ No newline at end of file diff --git a/tslint.json b/tslint.json index 14a66dce9..1bec78163 100644 --- a/tslint.json +++ b/tslint.json @@ -33,7 +33,6 @@ "no-eval": true, "no-trailing-whitespace": true, "no-unused-expression": true, - "no-use-before-declare": true, "one-line": [ true, "check-open-brace", diff --git a/view-prod/excel.json b/view-prod/excel.json new file mode 100644 index 000000000..38e8b6628 --- /dev/null +++ b/view-prod/excel.json @@ -0,0 +1,151 @@ +{ + "excel-basics-basic-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/01-basics/basic-api-call.yaml", + "excel-basics-basic-api-call-es5": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/01-basics/basic-api-call-es5.yaml", + "excel-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/01-basics/basic-common-api-call.yaml", + "excel-chart-axis": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-axis.yaml", + "excel-chart-axis-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-axis-formatting.yaml", + "excel-chart-data-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-table.yaml", + "excel-chart-bubble-chart": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-bubble-chart.yaml", + "excel-chart-create-several-charts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-create-several-charts.yaml", + "excel-chart-create-doughnut-chart": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/create-doughnut-chart.yaml", + "excel-chart-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-formatting.yaml", + "excel-chart-legend": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-legend.yaml", + "excel-chart-point": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-point.yaml", + "excel-chart-series": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series.yaml", + "excel-chart-series-markers": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-markers.yaml", + "excel-chart-series-plotorder": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-series-plotorder.yaml", + "excel-chart-title-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-title-format.yaml", + "excel-chart-data-source": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-source.yaml", + "excel-chart-trendlines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-trendlines.yaml", + "excel-chart-data-labels": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-data-labels.yaml", + "excel-chart-leader-lines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/10-chart/chart-leader-lines.yaml", + "excel-comment-basics": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-basics.yaml", + "excel-comment-mentions": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-mentions.yaml", + "excel-comment-replies": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-replies.yaml", + "excel-comment-resolution": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/comment-resolution.yaml", + "excel-note-basics": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/12-comments-and-notes/excel-note-basics.yaml", + "excel-range-conditional-formatting-basic": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml", + "excel-range-conditional-formatting-advanced": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml", + "excel-custom-functions-basic": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/basic-function.yaml", + "excel-custom-functions-volatile": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/volatile-function.yaml", + "excel-custom-functions-streaming": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/streaming-function.yaml", + "excel-custom-functions-web-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/web-call-function.yaml", + "excel-custom-functions-errors": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/custom-functions-errors.yaml", + "excel-data-types-custom-functions": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/data-types-custom-functions.yaml", + "excel-custom-functions-custom-enum": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/16-custom-functions/custom-enum.yaml", + "excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml", + "excel-custom-xml-parts-test-xml-for-unique-namespace": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml", + "excel-chart-chart-title-ts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/private-samples/excel/20-chart/chart-title-ts.yaml", + "excel-data-types-doubles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-formatted-number.yaml", + "excel-data-types-web-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-web-image.yaml", + "excel-data-types-entity-values": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-values.yaml", + "excel-data-types-error-values": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-error-values.yaml", + "excel-data-types-icons": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-icons.yaml", + "excel-data-types-entity-attribution": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-entity-attribution.yaml", + "excel-data-types-references": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-references.yaml", + "excel-data-types-basic-types": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/20-data-types/data-types-basic-types.yaml", + "excel-data-validation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/22-data-validation/data-validation.yaml", + "excel-document-get-file-in-slices-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/get-file-in-slices-async.yaml", + "excel-document-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/properties.yaml", + "excel-document-custom-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/26-document/custom-properties.yaml", + "excel-events-chartcollection-added-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chartcollection-added-activated.yaml", + "excel-events-chart-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-chart-activated.yaml", + "excel-event-column-and-row-sort": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-column-and-row-sort.yaml", + "excel-events-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-comment-event-handler.yaml", + "excel-events-data-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/data-changed.yaml", + "excel-data-change-event-details": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/data-change-event-details.yaml", + "excel-events-disable-events": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-disable-events.yaml", + "excel-events-formula-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-formula-changed.yaml", + "excel-selection-changed-events": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/selection-changed-events.yaml", + "excel-events-tablecollection-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-tablecollection-changed.yaml", + "excel-event-worksheet-single-click": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/event-worksheet-single-click.yaml", + "excel-events-table-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-table-changed.yaml", + "excel-events-workbook-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-activated.yaml", + "excel-events-workbook-and-worksheet-collection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml", + "excel-events-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet.yaml", + "excel-events-worksheet-protection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/30-events/events-worksheet-protection.yaml", + "excel-named-item-create-and-remove-named-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/create-and-remove-named-item.yaml", + "excel-update-named-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/34-named-item/update-named-item.yaml", + "excel-pivottable-calculations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-calculations.yaml", + "excel-pivottable-create-and-modify": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-create-and-modify.yaml", + "excel-pivottable-filters-and-summaries": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml", + "excel-pivottables-get-pivottables": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-get-pivottables.yaml", + "excel-pivottables-pivotfilters": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotfilters.yaml", + "excel-pivottable-pivotlayout": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-pivotlayout.yaml", + "excel-pivottable-data-source": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-source-data.yaml", + "excel-pivottable-refresh": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-refresh.yaml", + "excel-pivottable-slicer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/38-pivottable/pivottable-slicer.yaml", + "excel-range-auto-fill": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-auto-fill.yaml", + "excel-range-copyfrom": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-copyfrom.yaml", + "excel-range-areas": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-areas.yaml", + "excel-range-find": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-find.yaml", + "excel-range-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/formatting.yaml", + "excel-range-cell-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/cell-properties.yaml", + "excel-range-hyperlink": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-hyperlink.yaml", + "excel-range-insert-delete-and-clear-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/insert-delete-clear-range.yaml", + "excel-outline": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/outline.yaml", + "excel-range-range-relationships": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-relationships.yaml", + "excel-range-remove-duplicates": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-remove-duplicates.yaml", + "excel-range-selected-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/selected-range.yaml", + "excel-precedents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/precedents.yaml", + "excel-range-style": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/style.yaml", + "excel-range-text-orientation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-text-orientation.yaml", + "excel-range-dynamic-arrays": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/dynamic-arrays.yaml", + "excel-range-used-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/used-range.yaml", + "excel-range-values-and-formulas": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/set-get-values.yaml", + "excel-merged-ranges": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-merged-ranges.yaml", + "excel-range-get-range-edge": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-get-range-edge.yaml", + "excel-direct-dependents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-direct-dependents.yaml", + "excel-range-dependents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-dependents.yaml", + "excel-cell-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/42-range/range-cell-control.yaml", + "excel-shape-create-and-delete": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-create-and-delete.yaml", + "excel-shape-images": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-images.yaml", + "excel-shape-lines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-lines.yaml", + "excel-shape-move-and-order": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-move-and-order.yaml", + "excel-shape-groups": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-groups.yaml", + "excel-shape-textboxes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-textboxes.yaml", + "excel-shape-get-active": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/44-shape/shape-get-active.yaml", + "excel-table-add-rows-and-columns-to-a-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml", + "excel-table-convert-range-to-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/convert-range-to-table.yaml", + "excel-table-create-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/create-table.yaml", + "excel-table-filter-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/filter-data.yaml", + "excel-table-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/formatting.yaml", + "excel-table-get-data-from-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/get-data-from-table.yaml", + "excel-table-get-visible-range-of-a-filtered-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml", + "excel-table-import-json-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/import-json-data.yaml", + "excel-table-sort-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/sort-data.yaml", + "excel-table-resize": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/46-table/resize-table.yaml", + "excel-workbook-get-active-cell": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-get-active-cell.yaml", + "excel-settings-create-get-change-delete-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/create-get-change-delete-settings.yaml", + "excel-workbook-calculation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-calculation.yaml", + "excel-workbook-create-workbook": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/create-workbook.yaml", + "excel-culture-info": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info.yaml", + "excel-culture-info-date-time": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/culture-info-date-time.yaml", + "excel-workbook-data-protection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/data-protection.yaml", + "excel-workbook-save-and-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-save-and-close.yaml", + "excel-workbook-insert-external-worksheets": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml", + "excel-workbook-built-in-function": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/50-workbook/workbook-built-in-functions.yaml", + "excel-worksheet-active-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/active-worksheet.yaml", + "excel-worksheet-add-delete-rename-move-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml", + "excel-worksheet-auto-filter": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-auto-filter.yaml", + "excel-worksheet-copy": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-copy.yaml", + "excel-worksheet-find-all": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-find-all.yaml", + "excel-worksheet-freeze-panes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-freeze-panes.yaml", + "excel-worksheet-worksheet-range-cell": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-range-cell.yaml", + "excel-worksheet-gridlines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/gridlines.yaml", + "excel-worksheet-list-worksheets": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/list-worksheets.yaml", + "excel-worksheet-page-layout": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-page-layout.yaml", + "excel-worksheet-reference-worksheets-by-relative-position": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml", + "excel-worksheet-tab-color": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/tab-color.yaml", + "excel-worksheet-visibility": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/54-worksheet/worksheet-visibility.yaml", + "excel-performance-optimization": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/performance-optimization.yaml", + "excel-scenarios-report-generation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/report-generation.yaml", + "excel-scenarios-multiple-property-set": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/multiple-property-set.yaml", + "excel-scenarios-working-with-dates": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/working-with-dates.yaml", + "excel-scenarios-currency-converter": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/90-scenarios/currency-converter.yaml", + "excel-just-for-fun-patterns": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/99-just-for-fun/patterns.yaml", + "excel-just-for-fun-gradient": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/99-just-for-fun/gradient.yaml", + "excel-just-for-fun-path-finder-game": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/99-just-for-fun/path-finder-game.yaml", + "excel-just-for-fun-tetrominos": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/99-just-for-fun/tetrominos.yaml", + "excel-just-for-fun-color-wheel": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/excel/99-just-for-fun/color-wheel.yaml" +} \ No newline at end of file diff --git a/view-prod/outlook.json b/view-prod/outlook.json new file mode 100644 index 000000000..3eeda67db --- /dev/null +++ b/view-prod/outlook.json @@ -0,0 +1,90 @@ +{ + "outlook-roaming-settings-roaming-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/10-roaming-settings/roaming-settings.yaml", + "outlook-item-custom-properties-load-set-get-save": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/15-item-custom-properties/load-set-get-save.yaml", + "outlook-item-body-get-selected-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-selected-data.yaml", + "outlook-item-body-replace-selected-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/replace-selected-text.yaml", + "outlook-item-body-add-inline-base64-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/add-inline-base64-image.yaml", + "outlook-item-body-get-body-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/get-body-format.yaml", + "outlook-item-body-append-text-on-send": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/append-text-on-send.yaml", + "outlook-item-body-prepend-text-to-item-body": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-to-item-body.yaml", + "outlook-item-body-prepend-text-on-send": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/20-item-body/prepend-text-on-send.yaml", + "outlook-item-save-and-close-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close.yaml", + "outlook-close-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/close-async.yaml", + "outlook-item-save-and-close-save": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/25-item-save-and-close/save.yaml", + "outlook-recipients-and-attendees-get-from-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml", + "outlook-recipients-and-attendees-get-from-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml", + "outlook-recipients-and-attendees-get-to-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml", + "outlook-recipients-and-attendees-get-set-to-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml", + "outlook-recipients-and-attendees-get-cc-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml", + "outlook-recipients-and-attendees-get-set-cc-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml", + "outlook-recipients-and-attendees-get-set-bcc-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml", + "outlook-recipients-and-attendees-get-sender-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml", + "outlook-recipients-and-attendees-get-required-attendees-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-set-required-attendees-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-optional-attendees-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-set-optional-attendees-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-organizer-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-organizer-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-all-attendees": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml", + "outlook-notifications-add-getall-remove": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/35-notifications/add-getall-remove.yaml", + "outlook-attachments-attachments-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/attachments-compose.yaml", + "outlook-attachments-get-attachment-content": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachment-content.yaml", + "outlook-attachments-get-attachments-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/40-attachments/get-attachments-read.yaml", + "outlook-categories-work-with-categories": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-categories.yaml", + "outlook-categories-work-with-master-categories": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/45-categories/work-with-master-categories.yaml", + "outlook-recurrence-get-series-id": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-series-id.yaml", + "outlook-recurrence-get-recurrence-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-recurrence-read.yaml", + "outlook-recurrence-get-set-recurrence-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml", + "outlook-display-items-display-new-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-message.yaml", + "outlook-display-items-display-new-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-new-appointment.yaml", + "outlook-display-items-display-existing-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-message.yaml", + "outlook-display-items-display-existing-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-existing-appointment.yaml", + "outlook-display-items-display-reply-forms": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-forms.yaml", + "outlook-display-items-display-reply-with-attachments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/55-display-items/display-reply-with-attachments.yaml", + "outlook-sensitivity-labels-sensitivity-labels-catalog": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml", + "outlook-sensitivity-labels-sensitivity-label": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/60-sensitivity-label/sensitivity-label.yaml", + "outlook-delegates-and-shared-folders-get-shared-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml", + "outlook-mime-headers-get-internet-headers-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml", + "outlook-mime-headers-manage-custom-internet-headers-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml", + "outlook-regex-matches-contextual": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/75-regex-matches/contextual.yaml", + "outlook-events-drag-drop-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/80-events/drag-drop-item.yaml", + "outlook-tokens-and-service-calls-ids-and-urls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml", + "outlook-tokens-and-service-calls-user-identity-token": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml", + "outlook-tokens-and-service-calls-user-callback-token": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml", + "outlook-tokens-and-service-calls-make-ews-request-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml", + "outlook-tokens-and-service-calls-send-message-using-make-ews-request-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml", + "outlook-tokens-and-service-calls-get-icaluid-as-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml", + "outlook-tokens-and-service-calls-get-icaluid-as-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml", + "outlook-other-item-apis-get-subject-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-subject-read.yaml", + "outlook-other-item-apis-get-set-subject-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml", + "outlook-item-body-set-selected-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/set-selected-data.yaml", + "outlook-other-item-apis-get-internet-message-id-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml", + "outlook-other-item-apis-get-item-class-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-read.yaml", + "outlook-other-item-apis-get-item-type": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-type.yaml", + "outlook-other-item-apis-get-start-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-start-read.yaml", + "outlook-other-item-apis-get-set-start-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml", + "outlook-other-item-apis-get-end-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-end-read.yaml", + "outlook-other-item-apis-get-set-end-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml", + "outlook-other-item-apis-get-location-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-location-read.yaml", + "outlook-other-item-apis-get-set-location-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml", + "outlook-other-item-apis-get-add-remove-enhancedlocation-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml", + "outlook-other-item-apis-get-normalized-subject-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml", + "outlook-other-item-apis-get-conversation-id-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml", + "outlook-other-item-apis-get-date-time-created-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml", + "outlook-other-item-apis-get-date-time-modified-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml", + "outlook-other-item-apis-get-diagnostic-information": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml", + "outlook-other-item-apis-work-with-client-signatures": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml", + "outlook-other-item-apis-session-data-apis": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/session-data-apis.yaml", + "outlook-delay-message-delivery": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/delay-message-delivery.yaml", + "outlook-other-item-apis-get-message-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-message-properties.yaml", + "outlook-other-item-apis-get-set-sensitivity-level": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml", + "outlook-get-eml-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-eml-format.yaml", + "outlook-get-in-reply-to": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-in-reply-to.yaml", + "outlook-get-conversation-index": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-conversation-index.yaml", + "outlook-get-item-class-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-item-class-async.yaml", + "outlook-other-item-apis-item-id-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/item-id-compose.yaml", + "outlook-send-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/send-async.yaml", + "outlook-other-item-apis-get-loaded-message-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml", + "outlook-get-set-isalldayevent": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml", + "outlook-set-displayed-body-subject": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml" +} \ No newline at end of file diff --git a/view-prod/powerpoint.json b/view-prod/powerpoint.json new file mode 100644 index 000000000..3174b1a57 --- /dev/null +++ b/view-prod/powerpoint.json @@ -0,0 +1,23 @@ +{ + "powerpoint-basics-basic-api-call-ts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-api-call-ts.yaml", + "powerpoint-basics-basic-api-call-js": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-api-call-js.yaml", + "powerpoint-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/basics/basic-common-api-call.yaml", + "powerpoint-create-presentation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/document/create-presentation.yaml", + "powerpoint-hyperlinks-manage-hyperlinks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml", + "powerpoint-basics-insert-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/images/insert-image.yaml", + "powerpoint-basics-insert-svg": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/images/insert-svg.yaml", + "powerpoint-scenarios-searches-wikipedia-api": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/scenarios/searches-wikipedia-api.yaml", + "powerpoint-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/shapes.yaml", + "powerpoint-shapes-get-set-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-set-shapes.yaml", + "powerpoint-shapes-get-shapes-by-type": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/get-shapes-by-type.yaml", + "powerpoint-shapes-add-modify-tables": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/add-modify-tables.yaml", + "powerpoint-shapes-binding-to-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/binding-to-shapes.yaml", + "powerpoint-shapes-group-ungroup-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/shapes/group-ungroup-shapes.yaml", + "powerpoint-add-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/add-slides.yaml", + "powerpoint-insert-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/insert-slides.yaml", + "powerpoint-basics-get-slide-metadata": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-slide-metadata.yaml", + "powerpoint-slide-management-get-set-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/get-set-slides.yaml", + "powerpoint-slide-management-export-import-slide": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/slide-management/export-import-slide.yaml", + "powerpoint-tags": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/tags/tags.yaml", + "powerpoint-text-get-set-textrange": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/powerpoint/text/get-set-textrange.yaml" +} \ No newline at end of file diff --git a/view-prod/project.json b/view-prod/project.json new file mode 100644 index 000000000..605dd28bd --- /dev/null +++ b/view-prod/project.json @@ -0,0 +1,3 @@ +{ + "project-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/project/basics/basic-common-api-call.yaml" +} \ No newline at end of file diff --git a/view-prod/word.json b/view-prod/word.json new file mode 100644 index 000000000..af44ad5a0 --- /dev/null +++ b/view-prod/word.json @@ -0,0 +1,67 @@ +{ + "word-basics-basic-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-api-call.yaml", + "word-basics-api-call-es5": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-api-call-es5.yaml", + "word-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/01-basics/basic-common-api-call.yaml", + "word-content-controls-insert-and-change-content-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-content-controls.yaml", + "word-content-controls-content-control-onadded-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onadded-event.yaml", + "word-content-controls-content-control-onentered-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onentered-event.yaml", + "word-content-controls-content-control-onselectionchanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml", + "word-content-controls-content-control-ondatachanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondatachanged-event.yaml", + "word-content-controls-content-control-onexited-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-onexited-event.yaml", + "word-content-controls-content-control-ondeleted-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/content-control-ondeleted-event.yaml", + "word-content-controls-insert-and-change-checkbox-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml", + "word-content-controls-insert-and-change-combo-box-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml", + "word-content-controls-insert-and-change-dropdown-list-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml", + "word-content-controls-get-change-tracking-states": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/10-content-controls/get-change-tracking-states.yaml", + "word-images-insert-and-get-pictures": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/15-images/insert-and-get-pictures.yaml", + "word-lists-insert-list": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/insert-list.yaml", + "word-lists-manage-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/manage-list-styles.yaml", + "word-lists-organize-list": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/20-lists/organize-list.yaml", + "word-paragraph-get-paragraph-on-insertion-point": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml", + "word-paragraph-insert-line-and-page-breaks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-line-and-page-breaks.yaml", + "word-paragraph-insert-in-different-locations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-in-different-locations.yaml", + "word-paragraph-insert-formatted-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-formatted-text.yaml", + "word-paragraph-insert-header-and-footer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/insert-header-and-footer.yaml", + "word-paragraph-paragraph-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/paragraph-properties.yaml", + "word-paragraph-search": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/search.yaml", + "word-paragraph-get-word-count": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-word-count.yaml", + "word-paragraph-get-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/get-text.yaml", + "word-paragraph-onadded-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onadded-event.yaml", + "word-paragraph-onchanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/onchanged-event.yaml", + "word-paragraph-ondeleted-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/25-paragraph/ondeleted-event.yaml", + "word-properties-get-built-in-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/get-built-in-properties.yaml", + "word-properties-read-write-custom-document-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/30-properties/read-write-custom-document-properties.yaml", + "word-ranges-scroll-to-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/scroll-to-range.yaml", + "word-ranges-split-words-of-first-paragraph": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/split-words-of-first-paragraph.yaml", + "word-ranges-compare-location": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/compare-location.yaml", + "word-ranges-get-pages": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/35-ranges/get-pages.yaml", + "word-tables-table-cell-access": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/table-cell-access.yaml", + "word-tables-manage-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-formatting.yaml", + "word-tables-manage-custom-style": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/40-tables/manage-custom-style.yaml", + "word-shapes-manage-shapes-text-boxes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-shapes-text-boxes.yaml", + "word-shapes-manage-geometric-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-geometric-shapes.yaml", + "word-shapes-group-ungroup": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/group-ungroup.yaml", + "word-shapes-manage-canvases": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/45-shapes/manage-canvases.yaml", + "word-document-manage-body": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-body.yaml", + "word-document-insert-section-breaks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-section-breaks.yaml", + "word-document-insert-external-document": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/insert-external-document.yaml", + "word-document-manage-change-tracking": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-change-tracking.yaml", + "word-document-manage-tracked-changes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-tracked-changes.yaml", + "word-document-manage-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-comments.yaml", + "word-document-manage-footnotes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-footnotes.yaml", + "word-document-manage-fields": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-fields.yaml", + "word-document-manage-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-settings.yaml", + "word-document-manage-custom-xml-part-ns": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part-ns.yaml", + "word-document-manage-custom-xml-part": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-custom-xml-part.yaml", + "word-document-manage-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-styles.yaml", + "word-document-get-external-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/get-external-styles.yaml", + "word-document-save-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/save-close.yaml", + "word-document-manage-annotations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/manage-annotations.yaml", + "word-document-compare-documents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/50-document/compare-documents.yaml", + "word-scenarios-doc-assembly": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/doc-assembly.yaml", + "word-scenarios-multiple-property-set": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/multiple-property-set.yaml", + "word-scenarios-correlated-objects-pattern": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/90-scenarios/correlated-objects-pattern.yaml", + "word-close-document-window": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/close-document-window.yaml", + "word-insert-and-change-content-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/insert-and-change-content-controls.yaml", + "word-manage-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/prod/samples/word/99-preview-apis/manage-comments.yaml" +} \ No newline at end of file diff --git a/view/excel.json b/view/excel.json index 39395a9e4..6c50b9c80 100644 --- a/view/excel.json +++ b/view/excel.json @@ -1,72 +1,151 @@ { - "excel-basic-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/01-basics/basic-api-call.yaml", - "excel-basic-api-call-es5": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/01-basics/basic-api-call-es5.yaml", - "excel-basics-basic-common-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/01-basics/basic-common-api-call.yaml", - "excel-chart-chart-title-js": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/private-samples/excel/20-chart/chart-title-js.yaml", - "excel-chart-chart-title-ts": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/private-samples/excel/20-chart/chart-title-ts.yaml", - "excel-advanced-report-generation": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/20-scenarios/report-generation.yaml", - "excel-range-conditional-formatting-basic": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/conditional-formatting-basic.yaml", - "excel-range-copy-multiply-values": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/copy-multiply-values.yaml", - "excel-range-create-and-use-range-intersection": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/create-and-use-range-intersection.yaml", - "excel-range-formatting": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/formatting.yaml", - "excel-range-insert-delete-clear-range": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/insert-delete-clear-range.yaml", - "excel-range-range-operations": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/range-operations.yaml", - "excel-range-selected-range": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/selected-range.yaml", - "excel-range-set-get-values": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/set-get-values.yaml", - "excel-range-test-for-used-range": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/test-for-used-range.yaml", - "excel-range-working-with-dates": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/30-range/working-with-dates.yaml", - "excel-worksheet-activeworksheet": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/activeworksheet.yaml", - "excel-worksheet-add-delete-rename-move-worksheet": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/add-delete-rename-move-worksheet.yaml", - "excel-worksheet-hide-unhide-worksheet": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/hide-unhide-worksheet.yaml", - "excel-worksheet-list-worksheets": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/list-worksheets.yaml", - "excel-worksheet-reference-worksheets-by-relative-position": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/reference-worksheets-by-relative-position.yaml", - "excel-worksheet-worksheet-range-cell": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/35-worksheet/worksheet-range-cell.yaml", - "excel-table-add-rows-and-columns-to-a-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/add-rows-and-columns-to-a-table.yaml", - "excel-table-convert-range-to-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/convert-range-to-table.yaml", - "excel-table-create-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/create-table.yaml", - "excel-table-filter-data": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/filter-data.yaml", - "excel-table-format-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/format-table.yaml", - "excel-table-get-data-from-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/get-data-from-table.yaml", - "excel-table-get-visible-range-of-a-filtered-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/get-visible-range-of-a-filtered-table.yaml", - "excel-table-import-json-data": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/import-json-data.yaml", - "excel-table-sort-data": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/40-table/sort-data.yaml", - "excel-create-and-use-named-item-for-range": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/45-named-item/create-and-use-named-item-for-range.yaml", - "excel-named-item-create-and-remove-named-item": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/45-named-item/create-and-remove-named-item.yaml", - "excel-named-item-create-named-item": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/45-named-item/create-named-item.yaml", - "excel-named-item-list-named-items": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/45-named-item/list-named-items.yaml", - "excel-chart-create-column-clustered-chart": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/50-chart/create-column-clustered-chart.yaml", - "excel-chart-create-doughnut-chart": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/50-chart/create-doughnut-chart.yaml", - "excel-chart-create-line-chart": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/50-chart/create-line-chart.yaml", - "excel-chart-create-xyscatter-chart": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/50-chart/create-xyscatter-chart.yaml", - "excel-pivottable-refresh-pivot-table": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/55-pivot-table/refresh-pivot-table.yaml", - "excel-events-data-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/70-events/data-changed.yaml", - "excel-events-selection-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/70-events/selection-changed.yaml", - "excel-events-setting-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/70-events/setting-changed.yaml", - "excel-settings-create-get-change-delete-settings": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/80-settings/create-get-change-delete-settings.yaml", - "excel-document-get-file-in-slices-async": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/82-document/get-file-in-slices-async.yaml", - "excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/85-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml", - "excel-custom-xml-parts-test-xml-for-unique-namespace": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/85-custom-xml-parts/test-xml-for-unique-namespace.yaml", - "excel-multiple-property-set": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/88-common-patterns/multiple-property-set.yaml", - "excel-chart-axis": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-axis.yaml", - "excel-chart-legend": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-legend.yaml", - "excel-chart-point": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-point.yaml", - "excel-chart-series": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-series.yaml", - "excel-chart-series-markers": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-series-markers.yaml", - "excel-chart-trendlines": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/chart-trendlines.yaml", - "excel-document-properties": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/document-properties.yaml", - "excel-events-table-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/events-table-changed.yaml", - "excel-events-tablecollection-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/events-tablecollection-changed.yaml", - "excel-events-worksheet-activated": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/events-worksheet-activated.yaml", - "excel-events-worksheet-changed": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/events-worksheet-changed.yaml", - "excel-update-named-item": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/update-named-item.yaml", - "excel-range-hyperlink": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/range-hyperlink.yaml", - "excel-range-text-orientation": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/range-text-orientation.yaml", - "excel-style": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/style.yaml", - "excel-gridlines": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/worksheet-gridlines.yaml", - "excel-worksheet-tab-color": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/worksheet-tab-color.yaml", - "excel-worksheet-freeze-panes": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/89-preview-apis/worksheet-freeze-panes.yaml", - "excel-just-for-fun-gradient": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/90-just-for-fun/gradient.yaml", - "excel-just-for-fun-patterns": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/90-just-for-fun/patterns.yaml", - "excel-just-for-fun-path-finder-game": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/90-just-for-fun/path-finder-game.yaml", - "excel-just-for-fun-color-wheel": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/excel/90-just-for-fun/color-wheel.yaml" + "excel-basics-basic-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-api-call.yaml", + "excel-basics-basic-api-call-es5": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-api-call-es5.yaml", + "excel-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/01-basics/basic-common-api-call.yaml", + "excel-chart-axis": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-axis.yaml", + "excel-chart-axis-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-axis-formatting.yaml", + "excel-chart-data-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-table.yaml", + "excel-chart-bubble-chart": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-bubble-chart.yaml", + "excel-chart-create-several-charts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-create-several-charts.yaml", + "excel-chart-create-doughnut-chart": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/create-doughnut-chart.yaml", + "excel-chart-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-formatting.yaml", + "excel-chart-legend": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-legend.yaml", + "excel-chart-point": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-point.yaml", + "excel-chart-series": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series.yaml", + "excel-chart-series-markers": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series-markers.yaml", + "excel-chart-series-plotorder": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-series-plotorder.yaml", + "excel-chart-title-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-title-format.yaml", + "excel-chart-data-source": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-source.yaml", + "excel-chart-trendlines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-trendlines.yaml", + "excel-chart-data-labels": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-data-labels.yaml", + "excel-chart-leader-lines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/10-chart/chart-leader-lines.yaml", + "excel-comment-basics": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/comment-basics.yaml", + "excel-comment-mentions": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/comment-mentions.yaml", + "excel-comment-replies": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/comment-replies.yaml", + "excel-comment-resolution": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/comment-resolution.yaml", + "excel-note-basics": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/12-comments-and-notes/excel-note-basics.yaml", + "excel-range-conditional-formatting-basic": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/14-conditional-formatting/conditional-formatting-basic.yaml", + "excel-range-conditional-formatting-advanced": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml", + "excel-custom-functions-basic": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/basic-function.yaml", + "excel-custom-functions-volatile": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/volatile-function.yaml", + "excel-custom-functions-streaming": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/streaming-function.yaml", + "excel-custom-functions-web-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/web-call-function.yaml", + "excel-custom-functions-errors": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/custom-functions-errors.yaml", + "excel-data-types-custom-functions": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/data-types-custom-functions.yaml", + "excel-custom-functions-custom-enum": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/16-custom-functions/custom-enum.yaml", + "excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml", + "excel-custom-xml-parts-test-xml-for-unique-namespace": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml", + "excel-chart-chart-title-ts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/private-samples/excel/20-chart/chart-title-ts.yaml", + "excel-data-types-doubles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-formatted-number.yaml", + "excel-data-types-web-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-web-image.yaml", + "excel-data-types-entity-values": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-values.yaml", + "excel-data-types-error-values": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-error-values.yaml", + "excel-data-types-icons": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-icons.yaml", + "excel-data-types-entity-attribution": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-entity-attribution.yaml", + "excel-data-types-references": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-references.yaml", + "excel-data-types-basic-types": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/20-data-types/data-types-basic-types.yaml", + "excel-data-validation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/22-data-validation/data-validation.yaml", + "excel-document-get-file-in-slices-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/get-file-in-slices-async.yaml", + "excel-document-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/properties.yaml", + "excel-document-custom-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/26-document/custom-properties.yaml", + "excel-events-chartcollection-added-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-chartcollection-added-activated.yaml", + "excel-events-chart-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-chart-activated.yaml", + "excel-event-column-and-row-sort": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/event-column-and-row-sort.yaml", + "excel-events-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-comment-event-handler.yaml", + "excel-events-data-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/data-changed.yaml", + "excel-data-change-event-details": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/data-change-event-details.yaml", + "excel-events-disable-events": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-disable-events.yaml", + "excel-events-formula-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-formula-changed.yaml", + "excel-selection-changed-events": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/selection-changed-events.yaml", + "excel-events-tablecollection-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-tablecollection-changed.yaml", + "excel-event-worksheet-single-click": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/event-worksheet-single-click.yaml", + "excel-events-table-changed": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-table-changed.yaml", + "excel-events-workbook-activated": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-workbook-activated.yaml", + "excel-events-workbook-and-worksheet-collection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml", + "excel-events-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-worksheet.yaml", + "excel-events-worksheet-protection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/30-events/events-worksheet-protection.yaml", + "excel-named-item-create-and-remove-named-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/34-named-item/create-and-remove-named-item.yaml", + "excel-update-named-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/34-named-item/update-named-item.yaml", + "excel-pivottable-calculations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-calculations.yaml", + "excel-pivottable-create-and-modify": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-create-and-modify.yaml", + "excel-pivottable-filters-and-summaries": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-filters-and-summaries.yaml", + "excel-pivottables-get-pivottables": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-get-pivottables.yaml", + "excel-pivottables-pivotfilters": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-pivotfilters.yaml", + "excel-pivottable-pivotlayout": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-pivotlayout.yaml", + "excel-pivottable-data-source": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-source-data.yaml", + "excel-pivottable-refresh": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-refresh.yaml", + "excel-pivottable-slicer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/38-pivottable/pivottable-slicer.yaml", + "excel-range-auto-fill": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-auto-fill.yaml", + "excel-range-copyfrom": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-copyfrom.yaml", + "excel-range-areas": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-areas.yaml", + "excel-range-find": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-find.yaml", + "excel-range-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/formatting.yaml", + "excel-range-cell-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/cell-properties.yaml", + "excel-range-hyperlink": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-hyperlink.yaml", + "excel-range-insert-delete-and-clear-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/insert-delete-clear-range.yaml", + "excel-outline": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/outline.yaml", + "excel-range-range-relationships": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-relationships.yaml", + "excel-range-remove-duplicates": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-remove-duplicates.yaml", + "excel-range-selected-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/selected-range.yaml", + "excel-precedents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/precedents.yaml", + "excel-range-style": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/style.yaml", + "excel-range-text-orientation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-text-orientation.yaml", + "excel-range-dynamic-arrays": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/dynamic-arrays.yaml", + "excel-range-used-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/used-range.yaml", + "excel-range-values-and-formulas": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/set-get-values.yaml", + "excel-merged-ranges": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-merged-ranges.yaml", + "excel-range-get-range-edge": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-get-range-edge.yaml", + "excel-direct-dependents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-direct-dependents.yaml", + "excel-range-dependents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-dependents.yaml", + "excel-cell-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/42-range/range-cell-control.yaml", + "excel-shape-create-and-delete": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-create-and-delete.yaml", + "excel-shape-images": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-images.yaml", + "excel-shape-lines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-lines.yaml", + "excel-shape-move-and-order": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-move-and-order.yaml", + "excel-shape-groups": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-groups.yaml", + "excel-shape-textboxes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-textboxes.yaml", + "excel-shape-get-active": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/44-shape/shape-get-active.yaml", + "excel-table-add-rows-and-columns-to-a-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/add-rows-and-columns-to-a-table.yaml", + "excel-table-convert-range-to-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/convert-range-to-table.yaml", + "excel-table-create-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/create-table.yaml", + "excel-table-filter-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/filter-data.yaml", + "excel-table-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/formatting.yaml", + "excel-table-get-data-from-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/get-data-from-table.yaml", + "excel-table-get-visible-range-of-a-filtered-table": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/get-visible-range-of-a-filtered-table.yaml", + "excel-table-import-json-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/import-json-data.yaml", + "excel-table-sort-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/sort-data.yaml", + "excel-table-resize": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/46-table/resize-table.yaml", + "excel-workbook-get-active-cell": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-get-active-cell.yaml", + "excel-settings-create-get-change-delete-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/create-get-change-delete-settings.yaml", + "excel-workbook-calculation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-calculation.yaml", + "excel-workbook-create-workbook": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/create-workbook.yaml", + "excel-culture-info": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/culture-info.yaml", + "excel-culture-info-date-time": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/culture-info-date-time.yaml", + "excel-workbook-data-protection": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/data-protection.yaml", + "excel-workbook-save-and-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-save-and-close.yaml", + "excel-workbook-insert-external-worksheets": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-insert-external-worksheets.yaml", + "excel-workbook-built-in-function": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/50-workbook/workbook-built-in-functions.yaml", + "excel-worksheet-active-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/active-worksheet.yaml", + "excel-worksheet-add-delete-rename-move-worksheet": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/add-delete-rename-move-worksheet.yaml", + "excel-worksheet-auto-filter": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-auto-filter.yaml", + "excel-worksheet-copy": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-copy.yaml", + "excel-worksheet-find-all": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-find-all.yaml", + "excel-worksheet-freeze-panes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-freeze-panes.yaml", + "excel-worksheet-worksheet-range-cell": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-range-cell.yaml", + "excel-worksheet-gridlines": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/gridlines.yaml", + "excel-worksheet-list-worksheets": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/list-worksheets.yaml", + "excel-worksheet-page-layout": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-page-layout.yaml", + "excel-worksheet-reference-worksheets-by-relative-position": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/reference-worksheets-by-relative-position.yaml", + "excel-worksheet-tab-color": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/tab-color.yaml", + "excel-worksheet-visibility": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/54-worksheet/worksheet-visibility.yaml", + "excel-performance-optimization": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/performance-optimization.yaml", + "excel-scenarios-report-generation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/report-generation.yaml", + "excel-scenarios-multiple-property-set": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/multiple-property-set.yaml", + "excel-scenarios-working-with-dates": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/working-with-dates.yaml", + "excel-scenarios-currency-converter": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/90-scenarios/currency-converter.yaml", + "excel-just-for-fun-patterns": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/patterns.yaml", + "excel-just-for-fun-gradient": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/gradient.yaml", + "excel-just-for-fun-path-finder-game": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/path-finder-game.yaml", + "excel-just-for-fun-tetrominos": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/tetrominos.yaml", + "excel-just-for-fun-color-wheel": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/excel/99-just-for-fun/color-wheel.yaml" } \ No newline at end of file diff --git a/view/outlook.json b/view/outlook.json index 77011f3b3..6e7f14ee6 100644 --- a/view/outlook.json +++ b/view/outlook.json @@ -1,5 +1,90 @@ { - "outlook-compose-basics-get-item-subject": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/outlook/01-compose-basics/get-item-subject.yaml", - "outlook-compose-basics-get-selected-text": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/outlook/01-compose-basics/get-selected-text.yaml", - "outlook-compose-basics-set-selected-text": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/outlook/01-compose-basics/set-selected-text.yaml" + "outlook-roaming-settings-roaming-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/10-roaming-settings/roaming-settings.yaml", + "outlook-item-custom-properties-load-set-get-save": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/15-item-custom-properties/load-set-get-save.yaml", + "outlook-item-body-get-selected-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/get-selected-data.yaml", + "outlook-item-body-replace-selected-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/replace-selected-text.yaml", + "outlook-item-body-add-inline-base64-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/add-inline-base64-image.yaml", + "outlook-item-body-get-body-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/get-body-format.yaml", + "outlook-item-body-append-text-on-send": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/append-text-on-send.yaml", + "outlook-item-body-prepend-text-to-item-body": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/prepend-text-to-item-body.yaml", + "outlook-item-body-prepend-text-on-send": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/20-item-body/prepend-text-on-send.yaml", + "outlook-item-save-and-close-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/close.yaml", + "outlook-close-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/close-async.yaml", + "outlook-item-save-and-close-save": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/25-item-save-and-close/save.yaml", + "outlook-recipients-and-attendees-get-from-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-from-message-read.yaml", + "outlook-recipients-and-attendees-get-from-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-from-message-compose.yaml", + "outlook-recipients-and-attendees-get-to-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-to-message-read.yaml", + "outlook-recipients-and-attendees-get-set-to-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-to-message-compose.yaml", + "outlook-recipients-and-attendees-get-cc-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-cc-message-read.yaml", + "outlook-recipients-and-attendees-get-set-cc-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-cc-message-compose.yaml", + "outlook-recipients-and-attendees-get-set-bcc-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-bcc-message-compose.yaml", + "outlook-recipients-and-attendees-get-sender-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-sender-message-read.yaml", + "outlook-recipients-and-attendees-get-required-attendees-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-required-attendees-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-set-required-attendees-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-required-attendees-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-optional-attendees-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-optional-attendees-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-set-optional-attendees-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-set-optional-attendees-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-organizer-appointment-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-attendee.yaml", + "outlook-recipients-and-attendees-get-organizer-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-organizer-appointment-organizer.yaml", + "outlook-recipients-and-attendees-get-all-attendees": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/30-recipients-and-attendees/get-all-attendees.yaml", + "outlook-notifications-add-getall-remove": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/35-notifications/add-getall-remove.yaml", + "outlook-attachments-attachments-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/attachments-compose.yaml", + "outlook-attachments-get-attachment-content": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/get-attachment-content.yaml", + "outlook-attachments-get-attachments-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/40-attachments/get-attachments-read.yaml", + "outlook-categories-work-with-categories": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/45-categories/work-with-categories.yaml", + "outlook-categories-work-with-master-categories": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/45-categories/work-with-master-categories.yaml", + "outlook-recurrence-get-series-id": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-series-id.yaml", + "outlook-recurrence-get-recurrence-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-recurrence-read.yaml", + "outlook-recurrence-get-set-recurrence-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/50-recurrence/get-set-recurrence-appointment-organizer.yaml", + "outlook-display-items-display-new-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-new-message.yaml", + "outlook-display-items-display-new-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-new-appointment.yaml", + "outlook-display-items-display-existing-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-existing-message.yaml", + "outlook-display-items-display-existing-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-existing-appointment.yaml", + "outlook-display-items-display-reply-forms": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-reply-forms.yaml", + "outlook-display-items-display-reply-with-attachments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/55-display-items/display-reply-with-attachments.yaml", + "outlook-sensitivity-labels-sensitivity-labels-catalog": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/60-sensitivity-label/sensitivity-labels-catalog.yaml", + "outlook-sensitivity-labels-sensitivity-label": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/60-sensitivity-label/sensitivity-label.yaml", + "outlook-delegates-and-shared-folders-get-shared-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/65-delegates-and-shared-folders/get-shared-properties.yaml", + "outlook-mime-headers-get-internet-headers-message-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/70-mime-headers/get-internet-headers-message-read.yaml", + "outlook-mime-headers-manage-custom-internet-headers-message-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/70-mime-headers/manage-custom-internet-headers-message-compose.yaml", + "outlook-regex-matches-contextual": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/75-regex-matches/contextual.yaml", + "outlook-events-drag-drop-item": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/80-events/drag-drop-item.yaml", + "outlook-tokens-and-service-calls-ids-and-urls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/ids-and-urls.yaml", + "outlook-tokens-and-service-calls-user-identity-token": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/user-identity-token.yaml", + "outlook-tokens-and-service-calls-user-callback-token": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/user-callback-token.yaml", + "outlook-tokens-and-service-calls-make-ews-request-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/make-ews-request-async.yaml", + "outlook-tokens-and-service-calls-send-message-using-make-ews-request-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/send-message-using-make-ews-request-async.yaml", + "outlook-tokens-and-service-calls-get-icaluid-as-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-organizer.yaml", + "outlook-tokens-and-service-calls-get-icaluid-as-attendee": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/85-tokens-for-exchange-on-premises/get-icaluid-as-attendee.yaml", + "outlook-other-item-apis-get-subject-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-subject-read.yaml", + "outlook-other-item-apis-get-set-subject-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-subject-compose.yaml", + "outlook-item-body-set-selected-data": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/set-selected-data.yaml", + "outlook-other-item-apis-get-internet-message-id-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-internet-message-id-read.yaml", + "outlook-other-item-apis-get-item-class-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-class-read.yaml", + "outlook-other-item-apis-get-item-type": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-type.yaml", + "outlook-other-item-apis-get-start-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-start-read.yaml", + "outlook-other-item-apis-get-set-start-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-start-appointment-organizer.yaml", + "outlook-other-item-apis-get-end-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-end-read.yaml", + "outlook-other-item-apis-get-set-end-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-end-appointment-organizer.yaml", + "outlook-other-item-apis-get-location-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-location-read.yaml", + "outlook-other-item-apis-get-set-location-appointment-organizer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-location-appointment-organizer.yaml", + "outlook-other-item-apis-get-add-remove-enhancedlocation-appointment": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-add-remove-enhancedlocation-appointment.yaml", + "outlook-other-item-apis-get-normalized-subject-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-normalized-subject-read.yaml", + "outlook-other-item-apis-get-conversation-id-message": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-conversation-id-message.yaml", + "outlook-other-item-apis-get-date-time-created-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-date-time-created-read.yaml", + "outlook-other-item-apis-get-date-time-modified-read": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-date-time-modified-read.yaml", + "outlook-other-item-apis-get-diagnostic-information": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-diagnostic-information.yaml", + "outlook-other-item-apis-work-with-client-signatures": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/work-with-client-signatures.yaml", + "outlook-other-item-apis-session-data-apis": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/session-data-apis.yaml", + "outlook-delay-message-delivery": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/delay-message-delivery.yaml", + "outlook-other-item-apis-get-message-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-message-properties.yaml", + "outlook-other-item-apis-get-set-sensitivity-level": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-set-sensitivity-level.yaml", + "outlook-get-eml-format": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-eml-format.yaml", + "outlook-get-in-reply-to": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-in-reply-to.yaml", + "outlook-get-conversation-index": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-conversation-index.yaml", + "outlook-get-item-class-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-item-class-async.yaml", + "outlook-other-item-apis-item-id-compose": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/item-id-compose.yaml", + "outlook-send-async": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/send-async.yaml", + "outlook-other-item-apis-get-loaded-message-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/90-other-item-apis/get-loaded-message-properties.yaml", + "outlook-get-set-isalldayevent": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/99-preview-apis/get-set-isalldayevent.yaml", + "outlook-set-displayed-body-subject": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/outlook/99-preview-apis/set-displayed-body-subject.yaml" } \ No newline at end of file diff --git a/view/powerpoint.json b/view/powerpoint.json index 04faebc0c..76e7bddc5 100644 --- a/view/powerpoint.json +++ b/view/powerpoint.json @@ -1,5 +1,23 @@ { - "powerpoint-basics-get-slide-metadata": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/powerpoint/basics/get-slide-metadata.yaml", - "powerpoint-basics-insert-image": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/powerpoint/basics/insert-image.yaml", - "powerpoint-basics-basic-common-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/powerpoint/basics/basic-common-api-call.yaml" + "powerpoint-basics-basic-api-call-ts": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-api-call-ts.yaml", + "powerpoint-basics-basic-api-call-js": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-api-call-js.yaml", + "powerpoint-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/basics/basic-common-api-call.yaml", + "powerpoint-create-presentation": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/document/create-presentation.yaml", + "powerpoint-hyperlinks-manage-hyperlinks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/hyperlinks/manage-hyperlinks.yaml", + "powerpoint-basics-insert-image": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/images/insert-image.yaml", + "powerpoint-basics-insert-svg": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/images/insert-svg.yaml", + "powerpoint-scenarios-searches-wikipedia-api": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/scenarios/searches-wikipedia-api.yaml", + "powerpoint-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/shapes.yaml", + "powerpoint-shapes-get-set-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/get-set-shapes.yaml", + "powerpoint-shapes-get-shapes-by-type": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/get-shapes-by-type.yaml", + "powerpoint-shapes-add-modify-tables": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/add-modify-tables.yaml", + "powerpoint-shapes-binding-to-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/binding-to-shapes.yaml", + "powerpoint-shapes-group-ungroup-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/shapes/group-ungroup-shapes.yaml", + "powerpoint-add-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/add-slides.yaml", + "powerpoint-insert-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/insert-slides.yaml", + "powerpoint-basics-get-slide-metadata": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/get-slide-metadata.yaml", + "powerpoint-slide-management-get-set-slides": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/get-set-slides.yaml", + "powerpoint-slide-management-export-import-slide": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/slide-management/export-import-slide.yaml", + "powerpoint-tags": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/tags/tags.yaml", + "powerpoint-text-get-set-textrange": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/powerpoint/text/get-set-textrange.yaml" } \ No newline at end of file diff --git a/view/project.json b/view/project.json index ddf6c8408..34242cfae 100644 --- a/view/project.json +++ b/view/project.json @@ -1,3 +1,3 @@ { - "project-basics-basic-common-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/project/basics/basic-common-api-call.yaml" + "project-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/project/basics/basic-common-api-call.yaml" } \ No newline at end of file diff --git a/view/word.json b/view/word.json index 35f4736f1..3e0da2a29 100644 --- a/view/word.json +++ b/view/word.json @@ -1,23 +1,67 @@ { - "word-basics-basic-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/basic-api-call.yaml", - "word-basic-api-call-es5": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/basic-api-call-es5.yaml", - "word-basics-basic-doc-assembly": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/basic-doc-assembly.yaml", - "word-basics-insert-and-get-pictures": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/insert-and-get-pictures.yaml", - "word-basics-insert-formatted-text": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/insert-formatted-text.yaml", - "word-basics-insert-header": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/insert-header.yaml", - "word-basics-insert-line-and-page-breaks": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/insert-line-and-page-breaks.yaml", - "word-basics-search": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/search.yaml", - "word-basics-basic-common-api-call": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/01-basics/basic-common-api-call.yaml", - "word-basics-insert-in-different-locations": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/02-paragraphs/insert-in-different-locations.yaml", - "word-paragraphs-get-paragraph-on-insertion-point": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/02-paragraphs/get-paragraph-on-insertion-point.yaml", - "word-paragraphs-paragraph-properties": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/02-paragraphs/paragraph-properties.yaml", - "word-content-controls-insert-and-change-content-controls": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/03-content-controls/insert-and-change-content-controls.yaml", - "word-basics-scroll-to-range": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/04-range/scroll-to-range.yaml", - "word-range-split-words-of-first-paragraph": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/04-range/split-words-of-first-paragraph.yaml", - "word-tables-table-cell-access": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/05-tables/table-cell-access.yaml", - "word-lists-insert-list": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/06-lists/insert-list.yaml", - "word-basics-read-write-custom-document-properties": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/07-custom-properties/read-write-custom-document-properties.yaml", - "word-custom-properties-get-built-in-properties": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/07-custom-properties/get-built-in-properties.yaml", - "word-common-patterns-multiple-property-set": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/50-common-patterns/multiple-property-set.yaml", - "word-fabric-insert-form-data": "https://raw.githubusercontent.com/%3CACCOUNT%3E/%3CREPO%3E/%3CBRANCH%3E/samples/word/99-fabric/fabric-insert-form-data.yaml" + "word-basics-basic-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-api-call.yaml", + "word-basics-api-call-es5": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-api-call-es5.yaml", + "word-basics-basic-common-api-call": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/01-basics/basic-common-api-call.yaml", + "word-content-controls-insert-and-change-content-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-content-controls.yaml", + "word-content-controls-content-control-onadded-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onadded-event.yaml", + "word-content-controls-content-control-onentered-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onentered-event.yaml", + "word-content-controls-content-control-onselectionchanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onselectionchanged-event.yaml", + "word-content-controls-content-control-ondatachanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-ondatachanged-event.yaml", + "word-content-controls-content-control-onexited-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-onexited-event.yaml", + "word-content-controls-content-control-ondeleted-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/content-control-ondeleted-event.yaml", + "word-content-controls-insert-and-change-checkbox-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-checkbox-content-control.yaml", + "word-content-controls-insert-and-change-combo-box-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-combo-box-content-control.yaml", + "word-content-controls-insert-and-change-dropdown-list-content-control": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/insert-and-change-dropdown-list-content-control.yaml", + "word-content-controls-get-change-tracking-states": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/10-content-controls/get-change-tracking-states.yaml", + "word-images-insert-and-get-pictures": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/15-images/insert-and-get-pictures.yaml", + "word-lists-insert-list": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/insert-list.yaml", + "word-lists-manage-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/manage-list-styles.yaml", + "word-lists-organize-list": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/20-lists/organize-list.yaml", + "word-paragraph-get-paragraph-on-insertion-point": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-paragraph-on-insertion-point.yaml", + "word-paragraph-insert-line-and-page-breaks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-line-and-page-breaks.yaml", + "word-paragraph-insert-in-different-locations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-in-different-locations.yaml", + "word-paragraph-insert-formatted-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-formatted-text.yaml", + "word-paragraph-insert-header-and-footer": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/insert-header-and-footer.yaml", + "word-paragraph-paragraph-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/paragraph-properties.yaml", + "word-paragraph-search": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/search.yaml", + "word-paragraph-get-word-count": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-word-count.yaml", + "word-paragraph-get-text": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/get-text.yaml", + "word-paragraph-onadded-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/onadded-event.yaml", + "word-paragraph-onchanged-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/onchanged-event.yaml", + "word-paragraph-ondeleted-event": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/25-paragraph/ondeleted-event.yaml", + "word-properties-get-built-in-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/30-properties/get-built-in-properties.yaml", + "word-properties-read-write-custom-document-properties": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/30-properties/read-write-custom-document-properties.yaml", + "word-ranges-scroll-to-range": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/scroll-to-range.yaml", + "word-ranges-split-words-of-first-paragraph": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/split-words-of-first-paragraph.yaml", + "word-ranges-compare-location": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/compare-location.yaml", + "word-ranges-get-pages": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/35-ranges/get-pages.yaml", + "word-tables-table-cell-access": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/table-cell-access.yaml", + "word-tables-manage-formatting": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/manage-formatting.yaml", + "word-tables-manage-custom-style": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/40-tables/manage-custom-style.yaml", + "word-shapes-manage-shapes-text-boxes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-shapes-text-boxes.yaml", + "word-shapes-manage-geometric-shapes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-geometric-shapes.yaml", + "word-shapes-group-ungroup": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/group-ungroup.yaml", + "word-shapes-manage-canvases": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/45-shapes/manage-canvases.yaml", + "word-document-manage-body": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-body.yaml", + "word-document-insert-section-breaks": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/insert-section-breaks.yaml", + "word-document-insert-external-document": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/insert-external-document.yaml", + "word-document-manage-change-tracking": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-change-tracking.yaml", + "word-document-manage-tracked-changes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-tracked-changes.yaml", + "word-document-manage-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-comments.yaml", + "word-document-manage-footnotes": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-footnotes.yaml", + "word-document-manage-fields": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-fields.yaml", + "word-document-manage-settings": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-settings.yaml", + "word-document-manage-custom-xml-part-ns": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-custom-xml-part-ns.yaml", + "word-document-manage-custom-xml-part": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-custom-xml-part.yaml", + "word-document-manage-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-styles.yaml", + "word-document-get-external-styles": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/get-external-styles.yaml", + "word-document-save-close": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/save-close.yaml", + "word-document-manage-annotations": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/manage-annotations.yaml", + "word-document-compare-documents": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/50-document/compare-documents.yaml", + "word-scenarios-doc-assembly": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/doc-assembly.yaml", + "word-scenarios-multiple-property-set": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/multiple-property-set.yaml", + "word-scenarios-correlated-objects-pattern": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/90-scenarios/correlated-objects-pattern.yaml", + "word-close-document-window": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/close-document-window.yaml", + "word-insert-and-change-content-controls": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/insert-and-change-content-controls.yaml", + "word-manage-comments": "https://raw.githubusercontent.com/OfficeDev/office-js-snippets/main/samples/word/99-preview-apis/manage-comments.yaml" } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index 2963aa135..000000000 --- a/yarn.lock +++ /dev/null @@ -1,1383 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@microsoft/office-js-helpers@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@microsoft/office-js-helpers/-/office-js-helpers-0.5.0.tgz#1afa7b0abe0c82b537932f947cd0674c3cd1af2b" - dependencies: - "@types/jquery" "^2.0.39" - "@types/lodash" "^4.14.50" - "@types/office-js" "^0.0.37" - core-js "^2.4.1" - lodash "^4.17.4" - -"@types/chalk@0.4.31": - version "0.4.31" - resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9" - -"@types/jquery@^2.0.39": - version "2.0.41" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-2.0.41.tgz#b87ba051011f99edbe586d8f97282e7786e01a6d" - -"@types/js-yaml@3.5.29": - version "3.5.29" - resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.5.29.tgz#29f4dd9314fbccb080d8bd84b9c23811ec5090c2" - -"@types/lodash@4.14.54", "@types/lodash@^4.14.50": - version "4.14.54" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.54.tgz#287dbbcd97d5da69c25ca99fb5afa81c4839b7fa" - -"@types/node@*", "@types/node@7.0.7": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.7.tgz#92637c6c4844bfc9a0a686323e38f3e9319118c2" - -"@types/office-js@^0.0.37": - version "0.0.37" - resolved "https://registry.yarnpkg.com/@types/office-js/-/office-js-0.0.37.tgz#fba3ba06ffd9f4b83de0bbe66770245cd223b0da" - -"@types/shelljs@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.0.tgz#229c157c6bc1e67d6b990e6c5e18dbd2ff58cff0" - dependencies: - "@types/node" "*" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ansi-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba" - dependencies: - string-width "^1.0.1" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -babel-code-frame@^6.20.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" - dependencies: - chalk "^1.1.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -binary@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" - dependencies: - buffers "~0.1.1" - chainsaw "~0.1.0" - -bindings@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boxen@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.0.0.tgz#b2694baf1f605f708ff0177c12193b22f29aaaab" - dependencies: - ansi-align "^1.1.0" - camelcase "^4.0.0" - chalk "^1.1.1" - cli-boxes "^1.0.0" - string-width "^2.0.0" - term-size "^0.1.0" - widest-line "^1.0.0" - -brace-expansion@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - -brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -buffers@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" - -camelcase@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.0.0.tgz#8b0f90d44be5e281b903b9887349b92595ef07f2" - -capture-stack-trace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chainsaw@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" - dependencies: - traverse ">=0.3.0 <0.4" - -chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -charm@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.1.tgz#68566a7a553d4fe91797030dd1852d0dd6efa82d" - dependencies: - inherits "^2.0.1" - -cli-boxes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" - -cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - -cli-spinners@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.2.0.tgz#85078737913b880f6ec9ffe7b65e83ec7776284f" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -colors@1.1.2, colors@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -configstore@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.0.0.tgz#e1b8669c1803ccc50b545e92f8e6e79aa80e0196" - dependencies: - dot-prop "^4.1.0" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - unique-string "^1.0.0" - write-file-atomic "^1.1.2" - xdg-basedir "^3.0.0" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -core-js@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -create-error-class@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - dependencies: - capture-stack-trace "^1.0.0" - -cross-spawn-async@^2.1.1: - version "2.2.5" - resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" - dependencies: - lru-cache "^4.0.0" - which "^1.2.8" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -crypto-random-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - -csv-parser@^1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/csv-parser/-/csv-parser-1.12.0.tgz#1453f7627794f13f757ace4256feee22d37bc91b" - dependencies: - generate-function "^1.0.1" - generate-object-property "^1.0.0" - inherits "^2.0.1" - minimist "^1.2.0" - ndjson "^1.4.0" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -deep-extend@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - -diff@^3.0.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" - -dot-prop@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.1.1.tgz#a8493f0b7b5eeec82525b5c7587fa7de7ca859c1" - dependencies: - is-obj "^1.0.0" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - -excel@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/excel/-/excel-0.1.7.tgz#00a88e6fed5fc06f44a4aaf6f88f65f85a93c0bc" - dependencies: - libxmljs "~0.18.0" - node-promise "~0.5.3" - underscore "~1.3.3" - unzip2 "0.2.5" - -execa@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" - dependencies: - cross-spawn-async "^2.1.1" - is-stream "^1.1.0" - npm-run-path "^1.0.0" - object-assign "^4.0.1" - path-key "^1.0.0" - strip-eof "^1.0.0" - -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -findup-sync@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - dependencies: - glob "~5.0.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -fstream@~0.1.21: - version "0.1.31" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-0.1.31.tgz#7337f058fbbbbefa8c9f561a28cab0849202c988" - dependencies: - graceful-fs "~3.0.2" - inherits "~2.0.0" - mkdirp "0.5" - rimraf "2" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -generate-function@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-1.1.0.tgz#54c21b080192b16d9877779c5bb81666e772365f" - -generate-object-property@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob@^7.0.0, glob@^7.0.5, glob@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@~5.0.0: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -got@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" - dependencies: - create-error-class "^3.0.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-redirect "^1.0.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - lowercase-keys "^1.0.0" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - unzip-response "^2.0.1" - url-parse-lax "^1.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -graceful-fs@~3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" - -interpret@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-npm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-redirect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - -is-retry-allowed@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - -is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" - -js-yaml@3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" - dependencies: - argparse "^1.0.7" - esprima "^2.6.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -latest-version@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.0.0.tgz#3104f008c0c391084107f85a344bc61e38970649" - dependencies: - package-json "^3.0.0" - -lazy-req@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-2.0.0.tgz#c9450a363ecdda2e6f0c70132ad4f37f8f06f2b4" - -libxmljs@~0.18.0: - version "0.18.7" - resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.18.7.tgz#3673eb17c74cbaffdef9f33cb83ddd82a25055b7" - dependencies: - bindings "1.2.1" - nan "~2.5.0" - node-pre-gyp "~0.6.32" - -lodash@4.17.4, lodash@^4.17.4: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - -lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - -lru-cache@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" - dependencies: - pseudomap "^1.0.1" - yallist "^2.0.0" - -match-stream@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/match-stream/-/match-stream-0.0.2.tgz#99eb050093b34dffade421b9ac0b410a9cfa17cf" - dependencies: - buffers "~0.1.1" - readable-stream "~1.0.0" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-types@^2.1.12, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -"minimatch@2 || 3", minimatch@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - -minimatch@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -nan@~2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" - -natives@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" - -ndjson@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ndjson/-/ndjson-1.5.0.tgz#ae603b36b134bcec347b452422b0bf98d5832ec8" - dependencies: - json-stringify-safe "^5.0.1" - minimist "^1.2.0" - split2 "^2.1.0" - through2 "^2.0.3" - -node-pre-gyp@~0.6.32: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -node-promise@~0.5.3: - version "0.5.12" - resolved "https://registry.yarnpkg.com/node-promise/-/node-promise-0.5.12.tgz#b0acf9bc2229a76407c077b926592f99b3b4e1f1" - -node-status@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-status/-/node-status-1.0.0.tgz#7906a7c47a6587d03496bf74ec634abaa03f8e80" - dependencies: - charm "1.0.1" - cli-cursor "^1.0.2" - cli-spinners "0.2.0" - colors "1.1.2" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -npm-run-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" - dependencies: - path-key "^1.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -once@^1.3.0, once@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - -optimist@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -"over@>= 0.0.5 < 1": - version "0.0.5" - resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" - -package-json@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-3.1.0.tgz#ce281900fe8052150cc6709c6c006c18fdb2f379" - dependencies: - got "^6.7.1" - registry-auth-token "^3.0.1" - registry-url "^3.0.3" - semver "^5.1.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-key@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -pseudomap@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - -pullstream@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" - dependencies: - over ">= 0.0.5 < 1" - readable-stream "~1.0.31" - setimmediate ">= 1.0.2 < 2" - slice-stream ">= 1.0.0 < 2" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -rc@^1.0.1, rc@^1.1.6: - version "1.1.7" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.7.tgz#c5ea564bb07aff9fd3a5b32e906c1d3a65940fea" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -rc@^1.1.7: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@~1.0.0, readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - -registry-auth-token@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.1.0.tgz#997c08256e0c7999837b90e944db39d8a790276b" - dependencies: - rc "^1.1.6" - -registry-url@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - dependencies: - rc "^1.0.1" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -resolve@^1.1.6, resolve@^1.1.7: - version "1.3.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" - dependencies: - path-parse "^1.0.5" - -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -rimraf@2.5.4: - version "2.5.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" - dependencies: - glob "^7.0.5" - -rxjs@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.2.0.tgz#db537de8767c05fa73721587a29e0085307d318b" - dependencies: - symbol-observable "^1.0.1" - -safe-buffer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -semver-diff@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" - dependencies: - semver "^5.0.3" - -semver@^5.0.3, semver@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - -semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -"setimmediate@>= 1.0.2 < 2", setimmediate@~1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -shelljs@0.7.7: - version "0.7.7" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -"slice-stream@>= 1.0.0 < 2": - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" - dependencies: - readable-stream "~1.0.31" - -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -split2@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" - dependencies: - through2 "^2.0.2" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -symbol-observable@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -term-size@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-0.1.1.tgz#87360b96396cab5760963714cda0d0cbeecad9ca" - dependencies: - execa "^0.4.0" - -through2@^2.0.2, through2@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -timed-out@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - -tough-cookie@~2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - -tslint@4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-4.5.1.tgz#05356871bef23a434906734006fc188336ba824b" - dependencies: - babel-code-frame "^6.20.0" - colors "^1.1.2" - diff "^3.0.1" - findup-sync "~0.3.0" - glob "^7.1.1" - optimist "~0.6.0" - resolve "^1.1.7" - tsutils "^1.1.0" - update-notifier "^2.0.0" - -tsutils@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.3.0.tgz#dd86cb304f7a2e86c012deade2f8d0f886f57808" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -typescript@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.1.tgz#4862b662b988a4c8ff691cc7969622d24db76ae9" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -underscore@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.3.3.tgz#47ac53683daf832bfa952e1774417da47817ae42" - -unique-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - dependencies: - crypto-random-string "^1.0.0" - -unzip-response@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" - -unzip2@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/unzip2/-/unzip2-0.2.5.tgz#4ef7a579a78c15c51f550f6a053db194149c8992" - dependencies: - binary "~0.3.0" - fstream "~0.1.21" - match-stream "~0.0.2" - pullstream "~0.4.0" - readable-stream "~1.0.0" - setimmediate "~1.0.1" - -update-notifier@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.1.0.tgz#ec0c1e53536b76647a24b77cb83966d9315123d9" - dependencies: - boxen "^1.0.0" - chalk "^1.0.0" - configstore "^3.0.0" - is-npm "^1.0.0" - latest-version "^3.0.0" - lazy-req "^2.0.0" - semver-diff "^2.0.0" - xdg-basedir "^3.0.0" - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - dependencies: - prepend-http "^1.0.1" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -which@^1.2.8: - version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" - dependencies: - isexe "^1.1.1" - -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - dependencies: - string-width "^1.0.2" - -widest-line@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c" - dependencies: - string-width "^1.0.1" - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -write-file-atomic@^1.1.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - -xdg-basedir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" - -xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -yallist@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.1.tgz#08309c7044b1761d5e1591dc12c67629271b6ac3"