├── app ├── shared │ ├── navigation.component.js │ ├── navigation.component.js.map │ ├── button │ │ ├── button.component.css │ │ ├── button.component.js.map │ │ ├── button.component.html │ │ ├── button.component.ts │ │ └── button.component.js │ ├── button.component.js.map │ ├── brand.footer.component.js.map │ ├── office-fabric-component-wrappers │ │ ├── fabric.contextual.menu.wrapper.component.css │ │ ├── fabric.textfield.wrapper.component.html │ │ ├── fabric.contextual.menu.wrapper.component.html │ │ ├── fabric.contextual.menu.wrapper.component.js.map │ │ ├── fabric.textfield.wrapper.component.js.map │ │ ├── fabric.textfield.wrapper.component.ts │ │ ├── fabric.contextual.menu.wrapper.component.ts │ │ ├── TextField.js.map │ │ ├── TextField.ts │ │ ├── fabric.contextual.menu.wrapper.component.js │ │ ├── fabric.textfield.wrapper.component.js │ │ └── TextField.js │ ├── brand-footer │ │ ├── brand.footer.component.js.map │ │ ├── brand.footer.component.html │ │ ├── brand.footer.component.ts │ │ ├── brand.footer.component.js │ │ └── brand.footer.component.css │ ├── contextual.menu.button.component.js.map │ ├── navigation-header │ │ ├── navigation.header.component.css │ │ ├── navigation.header.component.html │ │ ├── navigation.header.component.js.map │ │ ├── navigation.header.component.ts │ │ └── navigation.header.component.js │ ├── contextual-menu-button │ │ ├── contextual.menu.button.component.html │ │ ├── contextual.menu.button.component.js.map │ │ ├── contextual.menu.button.component.ts │ │ ├── contextual.menu.button.component.css │ │ └── contextual.menu.button.component.js │ ├── navigation.header.component.js.map │ ├── star.component.js.map │ ├── brand.footer.component.js │ ├── button.component.js │ ├── contextual.menu.button.component.js │ ├── navigation.header.component.js │ └── star.component.js ├── assets │ └── images │ │ ├── logo-filled.png │ │ ├── blue-pencil-logo.png │ │ ├── blue-pencil-logo-16.png │ │ ├── blue-pencil-logo-32.png │ │ ├── blue-pencil-logo-80.png │ │ └── generic-placeholder.png ├── instructions │ ├── IInstructionStep.js.map │ ├── IInstructionStep.js │ ├── IInstructionStep.ts │ ├── instruction-steps.component.js.map │ ├── instruction-step.component.js.map │ ├── instruction-steps.component.html │ ├── instruction-steps.component.ts │ ├── instruction-step.component.js │ ├── instruction-steps.component.js │ └── instruction-steps.component.css ├── services │ ├── word-document │ │ ├── IReplacementCandidate.js.map │ │ ├── IReplacementCandidate.js │ │ ├── IReplacementCandidate.ts │ │ ├── word.document.service.js.map │ │ ├── word.document.service.ts │ │ └── word.document.service.js │ └── settings-storage │ │ ├── settings.storage.service.js.map │ │ ├── settings.storage.service.ts │ │ └── settings.storage.service.js ├── app.component.js.map ├── main.js.map ├── app.component.ts ├── app.component.css ├── app.module.js.map ├── main.ts ├── settings │ ├── settings.component.js.map │ ├── settings.component.css │ ├── settings.component.html │ ├── settings.component.ts │ └── settings.component.js ├── find-and-replace │ ├── find-and-replace.component.css │ ├── find-and-replace.component.js.map │ ├── find-and-replace.component.html │ ├── find-and-replace.component.ts │ └── find-and-replace.component.js ├── main.js ├── app-routing.module.js.map ├── app.component.js ├── app-routing.module.ts ├── app.module.ts ├── app-routing.module.js └── app.module.js ├── ReadmeImages └── CertificateWarningPrompt.png ├── bs-config.json ├── typings.json ├── tsconfig.json ├── .vscode ├── settings.json ├── launch.json └── tasks.json ├── Word-Add-in-Angular2-StyleChecker.yml ├── .gitignore ├── LICENSE ├── systemjs.config.js ├── index.html ├── tslint.json ├── package.json ├── SECURITY.md ├── README-Localized ├── README-zh-cn.md ├── README-zh-tw.md ├── README-ja-jp.md ├── README-ru-ru.md └── README-pt-br.md ├── Word-Add-in-Angular2-StyleChecker.xml └── README.md /app/shared/navigation.component.js: -------------------------------------------------------------------------------- 1 | //# sourceMappingURL=navigation.component.js.map -------------------------------------------------------------------------------- /app/assets/images/logo-filled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/logo-filled.png -------------------------------------------------------------------------------- /app/assets/images/blue-pencil-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/blue-pencil-logo.png -------------------------------------------------------------------------------- /ReadmeImages/CertificateWarningPrompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/ReadmeImages/CertificateWarningPrompt.png -------------------------------------------------------------------------------- /app/assets/images/blue-pencil-logo-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/blue-pencil-logo-16.png -------------------------------------------------------------------------------- /app/assets/images/blue-pencil-logo-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/blue-pencil-logo-32.png -------------------------------------------------------------------------------- /app/assets/images/blue-pencil-logo-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/blue-pencil-logo-80.png -------------------------------------------------------------------------------- /app/assets/images/generic-placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OfficeDev/Word-Add-in-Angular2-StyleChecker/HEAD/app/assets/images/generic-placeholder.png -------------------------------------------------------------------------------- /app/shared/navigation.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"navigation.component.js","sourceRoot":"","sources":["navigation.component.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /app/instructions/IInstructionStep.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IInstructionStep.js","sourceRoot":"","sources":["IInstructionStep.ts"],"names":[],"mappings":";AAAA,6HAA6H"} -------------------------------------------------------------------------------- /app/services/word-document/IReplacementCandidate.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IReplacementCandidate.js","sourceRoot":"","sources":["IReplacementCandidate.ts"],"names":[],"mappings":";AAAA,6HAA6H"} -------------------------------------------------------------------------------- /bs-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "https": { 3 | "key": "c:/users/YOUR-USER-NAME-ON-COMPUTER/.office-addin-dev-certs/localhost.key", 4 | "cert": "c:/users/YOUR-USER-NAME-ON-COMPUTER/.office-addin-dev-certs/localhost.crt" 5 | } 6 | } -------------------------------------------------------------------------------- /app/instructions/IInstructionStep.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | //# sourceMappingURL=IInstructionStep.js.map -------------------------------------------------------------------------------- /app/services/word-document/IReplacementCandidate.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | //# sourceMappingURL=IReplacementCandidate.js.map -------------------------------------------------------------------------------- /app/shared/button/button.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for the button. 5 | */ 6 | 7 | .button-spacer { 8 | margin-top: 30px; 9 | margin-bottom: 30px; 10 | } -------------------------------------------------------------------------------- /app/app.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"app.component.js","sourceRoot":"","sources":["app.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;EAEE;AAEF,sCAAwC;AAYxC;IAAA;IAA4B,CAAC;IAAhB,YAAY;QAVxB,gBAAS,CAAC;YACP,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,uIAMR;SACL,CAAC;OACW,YAAY,CAAI;IAAD,mBAAC;CAAA,AAA7B,IAA6B;AAAhB,oCAAY"} -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "core-js": "registry:dt/core-js#0.0.0+20160725163759", 4 | "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", 5 | "node": "registry:dt/node#6.0.0+20160909174046", 6 | "office-js": "registry:dt/office-js#0.0.0+20160608071856", 7 | "jquery": "registry:dt/jquery#1.10.0+20160417213236" 8 | } 9 | } -------------------------------------------------------------------------------- /app/shared/button.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"button.component.js","sourceRoot":"","sources":["button.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBACqC,eAAe,CAAC,CAAA;AAMrD;IAAA;IAGA,CAAC;IADI;QAAC,YAAK,EAAE;;wDAAA;IANb;QAAC,gBAAS,CAAC;YACP,QAAQ,EAAE,WAAW;YACrB,WAAW,EAAE,yCAAyC;SACzD,CAAC;;uBAAA;IAIF,sBAAC;AAAD,CAAC,AAHD,IAGC;AAHY,uBAAe,kBAG3B,CAAA"} -------------------------------------------------------------------------------- /app/shared/brand.footer.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"brand.footer.component.js","sourceRoot":"","sources":["brand.footer.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBACgE,eAAe,CAAC,CAAA;AAOhF;IAAA;IAGA,CAAC;IARD;QAAC,gBAAS,CAAC;YACP,QAAQ,EAAE,iBAAiB;YAC3B,WAAW,EAAE,qDAAqD;YAClE,SAAS,EAAE,CAAC,oDAAoD,CAAC;SACpE,CAAC;;4BAAA;IAIF,2BAAC;AAAD,CAAC,AAHD,IAGC;AAHY,4BAAoB,uBAGhC,CAAA"} -------------------------------------------------------------------------------- /app/instructions/IInstructionStep.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | 3 | /* 4 | This file creates a type that is used to hold the contents of a step_number 5 | in a step-by-step procedure. 6 | */ 7 | 8 | export interface IInstructionStep { 9 | step_number: number; 10 | content: string; 11 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2015", "dom"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "removeComments": false, 11 | "noImplicitAny": true, 12 | "suppressImplicitAnyIndexErrors": true 13 | } 14 | } -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file contains the positioning styles for the menu items. 5 | */ 6 | 7 | .ms-ContextualMenu-link.ms-ContextualMenu-link--hasMenu ~ .ms-ContextualMenu { 8 | left: 20px; 9 | top: 40px; } -------------------------------------------------------------------------------- /app/shared/button/button.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"button.component.js","sourceRoot":"","sources":["button.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;EAEE;AAEF,sCAAiD;AAOjD;IAAA;IAIA,CAAC;IADa;QAAR,YAAK,EAAE;;wDAAqB;IAHrB,eAAe;QAL3B,gBAAS,CAAC;YACP,QAAQ,EAAE,WAAW;YACrB,WAAW,EAAE,yCAAyC;YACtD,SAAS,EAAE,CAAC,wCAAwC,CAAC;SACxD,CAAC;OACW,eAAe,CAI3B;IAAD,sBAAC;CAAA,AAJD,IAIC;AAJY,0CAAe"} -------------------------------------------------------------------------------- /app/shared/brand-footer/brand.footer.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"brand.footer.component.js","sourceRoot":"","sources":["brand.footer.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;;;;EAKE;AAEF,sCAAyC;AAOzC;IAAA;IAAmC,CAAC;IAAvB,oBAAoB;QALhC,gBAAS,CAAC;YACP,QAAQ,EAAE,iBAAiB;YAC3B,WAAW,EAAE,qDAAqD;YAClE,SAAS,EAAE,CAAC,oDAAoD,CAAC;SACpE,CAAC;OACW,oBAAoB,CAAG;IAAD,2BAAC;CAAA,AAApC,IAAoC;AAAvB,oDAAoB"} -------------------------------------------------------------------------------- /app/shared/contextual.menu.button.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"contextual.menu.button.component.js","sourceRoot":"","sources":["contextual.menu.button.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBACgE,eAAe,CAAC,CAAA;AAOhF;IAAA;IAGA,CAAC;IARD;QAAC,gBAAS,CAAC;YACP,QAAQ,EAAE,2BAA2B;YACrC,WAAW,EAAE,yEAAyE;YACtF,SAAS,EAAE,CAAC,wEAAwE,CAAC;SACxF,CAAC;;qCAAA;IAIF,oCAAC;AAAD,CAAC,AAHD,IAGC;AAHY,qCAA6B,gCAGzC,CAAA"} -------------------------------------------------------------------------------- /app/shared/navigation-header/navigation.header.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for navigation header. 5 | */ 6 | 7 | .ms-navigation__header { 8 | overflow: hidden; 9 | padding-left: 0px; 10 | padding-right: 0px; 11 | background-color: #DEECF9; 12 | height: 40px; } 13 | -------------------------------------------------------------------------------- /app/shared/navigation-header/navigation.header.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 |
8 | 9 | 10 |
-------------------------------------------------------------------------------- /app/shared/navigation-header/navigation.header.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"navigation.header.component.js","sourceRoot":"","sources":["navigation.header.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;;;;EAKE;AAEF,sCAA0C;AAW1C;IAAA;IAAwC,CAAC;IAA5B,yBAAyB;QALrC,gBAAS,CAAC;YACP,QAAQ,EAAE,sBAAsB;YAChC,WAAW,EAAE,+DAA+D;YAC5E,SAAS,EAAE,CAAC,8DAA8D,CAAC;SAC9E,CAAC;OACW,yBAAyB,CAAG;IAAD,gCAAC;CAAA,AAAzC,IAAyC;AAA5B,8DAAyB"} -------------------------------------------------------------------------------- /app/shared/button/button.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 |
7 | 10 |
-------------------------------------------------------------------------------- /app/services/word-document/IReplacementCandidate.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | 3 | /* 4 | This file creates a type that is used to record the location of a range 5 | relative to another range. 6 | */ 7 | 8 | export interface IReplacementCandidate { 9 | range: Word.Range; 10 | locationRelation: OfficeExtension.ClientResult; 11 | } -------------------------------------------------------------------------------- /app/main.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":";AAAA,kHAAkH;;AAElH;;EAEE;AAEF,8EAA2E;AAE3E,2CAAyC;AAEzC,SAAS,MAAM;IACX,IAAM,QAAQ,GAAG,iDAAsB,EAAE,CAAC;IAC1C,QAAQ,CAAC,eAAe,CAAC,sBAAS,CAAC,CAAC;AACxC,CAAC;AAED,IAAI,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE;IAEpE,wEAAwE;IACxE,oFAAoF;IACpF,yEAAyE;IACzE,MAAM,CAAC,UAAU,GAAG,UAAA,MAAM;QACxB,MAAM,EAAE,CAAC;IACX,CAAC,CAAA;CACF;KACI;IACH,MAAM,EAAE,CAAC;CACV"} -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "**/.git": true, 5 | "**/.DS_Store": true, 6 | "**/app/**/*.js": true, 7 | "**/*.map": true 8 | }, 9 | // Controls auto save of dirty files. Accepted values: "off", "afterDelay", "onFocusChange". If set to "afterDelay" you can configure the delay in "files.autoSaveDelay". 10 | "files.autoSave": "afterDelay" 11 | } -------------------------------------------------------------------------------- /app/shared/contextual-menu-button/contextual.menu.button.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /app/shared/navigation.header.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"navigation.header.component.js","sourceRoot":"","sources":["navigation.header.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBACgE,eAAe,CAAC,CAAA;AAEhF,iDAA8C,oCAAoC,CAAC,CAAA;AACnF,yDAAqD,6EAA6E,CAAC,CAAA;AAQnI;IAAA;IAGA,CAAC;IATD;QAAC,gBAAS,CAAC;YACP,QAAQ,EAAE,sBAAsB;YAChC,WAAW,EAAE,+DAA+D;YAC5E,SAAS,EAAE,CAAC,8DAA8D,CAAC;YAC3E,UAAU,EAAE,CAAC,gEAA6B,EAAE,+EAAoC,CAAC;SACpF,CAAC;;iCAAA;IAIF,gCAAC;AAAD,CAAC,AAHD,IAGC;AAHY,iCAAyB,4BAGrC,CAAA"} -------------------------------------------------------------------------------- /app/app.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines the root component of the application. 5 | */ 6 | 7 | import {Component} from '@angular/core'; 8 | 9 | @Component({ 10 | selector: 'sc-app', 11 | template: ` 12 |
13 |
14 | 15 |
16 |
17 | ` 18 | }) 19 | export class AppComponent { } -------------------------------------------------------------------------------- /app/shared/brand-footer/brand.footer.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /app/services/settings-storage/settings.storage.service.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"settings.storage.service.js","sourceRoot":"","sources":["settings.storage.service.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;EAEE;AAEF,sCAA2C;AAI3C;IAEI;IAAe,CAAC;IAEhB,sCAAK,GAAL,UAAM,WAAmB,EAAE,KAAa;QACpC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,sCAAK,GAAL,UAAM,WAAmB;QACrB,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,uCAAM,GAAN,UAAO,WAAmB;QACtB,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChD,CAAC;IAdQ,sBAAsB;QADlC,iBAAU,EAAE;;OACA,sBAAsB,CAelC;IAAD,6BAAC;CAAA,AAfD,IAeC;AAfY,wDAAsB"} -------------------------------------------------------------------------------- /app/shared/button/button.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a Fabic-styled button. 5 | */ 6 | 7 | import { Component, Input } from '@angular/core'; 8 | 9 | @Component({ 10 | selector: 'sc-button', 11 | templateUrl: 'app/shared/button/button.component.html', 12 | styleUrls: ['app/shared/button/button.component.css'] 13 | }) 14 | export class ButtonComponent { 15 | 16 | // Text for the button label is provided by the parent view. 17 | @Input() buttonlabel: string; 18 | } 19 | -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 |
7 | 8 | 9 | 12 | 14 |
-------------------------------------------------------------------------------- /app/shared/star.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"star.component.js","sourceRoot":"","sources":["star.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBACqC,eAAe,CAAC,CAAA;AAOrD;IAAA;QAKc,kBAAa,GACnB,IAAI,mBAAY,EAAU,CAAC;IAWnC,CAAC;IATG,mCAAW,GAAX;QACI,4BAA4B;QAC5B,yBAAyB;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,+BAAO,GAAP;QACI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,gBAAc,IAAI,CAAC,MAAM,kBAAe,CAAC,CAAC;IACtE,CAAC;IAdD;QAAC,YAAK,EAAE;;qDAAA;IACR;QAAC,YAAK,EAAE;;iDAAA;IAER;QAAC,aAAM,EAAE;;wDAAA;IAVb;QAAC,gBAAS,CAAC;YACP,QAAQ,EAAE,SAAS;YACnB,WAAW,EAAE,gCAAgC;YAC7C,SAAS,EAAE,CAAC,+BAA+B,CAAC;SAC/C,CAAC;;qBAAA;IAkBF,oBAAC;AAAD,CAAC,AAjBD,IAiBC;AAjBY,qBAAa,gBAiBzB,CAAA"} -------------------------------------------------------------------------------- /Word-Add-in-Angular2-StyleChecker.yml: -------------------------------------------------------------------------------- 1 | ### YamlMime:Sample 2 | sample: 3 | - name: Word Style Checking Add-in Built on Angular 2.0 4 | path: '' 5 | description: Learn how to create an add-in that uses the LocationRelation and compareLocationWith APIs of the Word JavaScript APIs to perform a search and replace that skips some ranges based on their location relative to other ranges. 6 | readme: '' 7 | generateZip: FALSE 8 | isLive: TRUE 9 | technologies: 10 | - Office Add-in 11 | - Angular 2.0 12 | azureDeploy: '' 13 | author: rick-kirkham 14 | platforms: [] 15 | languages: 16 | - JavaScript 17 | extensions: 18 | products: 19 | - Word 20 | scenarios: [] 21 | -------------------------------------------------------------------------------- /app/app.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* This file cancels out the browser's default styling, so the specific CSS files can start from a clean slate. */ 4 | 5 | html, body { 6 | width: 100%; 7 | height: 100%; 8 | margin: 0; 9 | padding: 0; 10 | overflow: auto; } 11 | 12 | body { 13 | position: relative; 14 | font-size: 16px; } 15 | 16 | main { 17 | height: 100%; 18 | overflow-y: auto; } 19 | 20 | footer { 21 | width: 100%; 22 | position: relative; 23 | bottom: 0; } 24 | 25 | p, h1, h2, h3, h4, h5, h6 { 26 | margin: 0; 27 | padding: 0; } 28 | 29 | ul { 30 | padding: 0; } 31 | -------------------------------------------------------------------------------- /app/shared/contextual-menu-button/contextual.menu.button.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"contextual.menu.button.component.js","sourceRoot":"","sources":["contextual.menu.button.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;EAEE;AAEF,sCAA8D;AAO9D;IAEI,uCAAoB,OAAmB;QAAnB,YAAO,GAAP,OAAO,CAAY;IAAG,CAAC;IAE3C,sDAAc,GAAd;QACI,IAAI,WAAW,GAAgB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,qCAAqC;aACnD,WAAW,CAAG,uBAAuB;aACrC,WAAW,CAAG,yBAAyB;aACvC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,wCAAwC;QAClG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAVQ,6BAA6B;QALzC,gBAAS,CAAC;YACP,QAAQ,EAAE,2BAA2B;YACrC,WAAW,EAAE,yEAAyE;YACtF,SAAS,EAAE,CAAC,wEAAwE,CAAC;SACxF,CAAC;yCAG+B,iBAAU;OAF9B,6BAA6B,CAWzC;IAAD,oCAAC;CAAA,AAXD,IAWC;AAXY,sEAA6B"} -------------------------------------------------------------------------------- /app/app.module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"app.module.js","sourceRoot":"","sources":["app.module.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;;EAGE;AAEF,sCAA+C;AAC/C,8DAA2D;AAC3D,2DAA4D;AAE5D,oCAAoC;AACpC,iDAAuD;AACvD,4FAAwF;AACxF,0FAAuF;AACvF,oEAAkE;AAClE,qEAAmE;AACnE,sGAAkG;AAClG,uFAAmF;AACnF,qHAAiH;AACjH,+IAA0I;AAC1I,mIAA+H;AAE/H,0EAA0E;AAC1E,wFAAqF;AAErF,+EAA+E;AAC/E,iGAA8F;AA0B9F;IAAA;IAAyB,CAAC;IAAb,SAAS;QAvBrB,eAAQ,CAAC;YACR,OAAO,EAAE;gBACP,gCAAa;gBACb,qCAAgB;aACjB;YACD,YAAY,EAAE;gBACZ,4BAAY;gBACZ,oDAAuB;gBACvB,uDAAyB;gBACzB,sCAAiB;gBACjB,kCAAe;gBACf,uDAAyB;gBACzB,6CAAoB;gBACpB,gEAA6B;gBAC7B,+EAAoC;gBACpC,oEAA+B;aAChC;YACD,SAAS,EAAE;gBACT,2CAAmB;gBACnB,iDAAsB;aACrB;YACH,SAAS,EAAE,CAAE,4BAAY,CAAE;SAC5B,CAAC;OACW,SAAS,CAAI;IAAD,gBAAC;CAAA,AAA1B,IAA0B;AAAb,8BAAS"} -------------------------------------------------------------------------------- /app/instructions/instruction-steps.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"instruction-steps.component.js","sourceRoot":"","sources":["instruction-steps.component.ts"],"names":[],"mappings":";AAAA,6HAA6H;;;;;;;;;;;;AAE7H;;;;;EAKE;AAEF,sCAA0C;AAC1C,0CAAyC;AASzC;IAWI,mCAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;QAT1B,UAAK,GAAW,SAAS,CAAC;QAC1B,sBAAiB,GAAW,8GAA8G,CAAC;QAC3I,gBAAW,GAAW,wBAAwB,CAAC;QAC/C,UAAK,GACb,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE;YAC3D,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,qDAAqD,EAAE;YAClF,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,mGAAmG,EAAE;YAChI,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAEb,CAAC;IAX9B,yBAAyB;QAJrC,gBAAS,CAAC;YACP,WAAW,EAAE,mDAAmD;YAChE,SAAS,EAAE,CAAC,kDAAkD,CAAC;SAClE,CAAC;yCAY8B,eAAM;OAXzB,yBAAyB,CAarC;IAAD,gCAAC;CAAA,AAbD,IAaC;AAbY,8DAAyB"} -------------------------------------------------------------------------------- /app/instructions/instruction-step.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"instruction-step.component.js","sourceRoot":"","sources":["instruction-step.component.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBAA0B,eAAe,CAAC,CAAA;AAC1C,uBAA0C,iBAAiB,CAAC,CAAA;AAE5D,iCAAgC,4BAA4B,CAAC,CAAA;AAQ7D;IAAA;QAEY,UAAK,GAAW,SAAS,CAAC;QAC1B,sBAAiB,GAAW,8GAA8G,CAAC;QAC3I,gBAAW,GAAW,wBAAwB,CAAA;QAC9C,UAAK,GACT,CAAC,EAAC,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAC;YAC5D,EAAC,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,qDAAqD,EAAC;YAChF,EAAC,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,mGAAmG,EAAC;YAC9H,EAAC,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAC,CAAC,CAAA;IAIrD,CAAC;IAlBD;QAAC,gBAAS,CAAC;YACP,WAAW,EAAE,mDAAmD;YAChE,UAAU,EAAE,CAAC,kCAAe,EAAE,0BAAiB,CAAC;YAChD,SAAS,EAAE,CAAC,kDAAkD,CAAC;SAClE,CAAC;;iCAAA;IAcF,gCAAC;AAAD,CAAC,AAbD,IAaC;AAbY,iCAAyB,4BAarC,CAAA"} -------------------------------------------------------------------------------- /app/services/settings-storage/settings.storage.service.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a service that provides CRUD operations on application settings. 5 | */ 6 | 7 | import { Injectable } from '@angular/core'; 8 | 9 | 10 | @Injectable() 11 | export class SettingsStorageService { 12 | 13 | constructor() {} 14 | 15 | store(specificKey: string, value: string) { 16 | window.localStorage.setItem(specificKey, value); 17 | } 18 | 19 | fetch(specificKey: string) : string { 20 | return window.localStorage.getItem(specificKey); 21 | } 22 | 23 | remove(specificKey: string) { 24 | window.localStorage.removeItem(specificKey); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/shared/brand-footer/brand.footer.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a branded footer for a task pane page. It is based on 5 | the navigation sample, created by the Modern Assistance Experience Developer 6 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 7 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 8 | */ 9 | 10 | import { Component} from '@angular/core'; 11 | 12 | @Component({ 13 | selector: 'sc-brand-footer', 14 | templateUrl: 'app/shared/brand-footer/brand.footer.component.html', 15 | styleUrls: ['app/shared/brand-footer/brand.footer.component.css'], 16 | }) 17 | export class BrandFooterComponent {} -------------------------------------------------------------------------------- /app/main.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file bootstraps the root module: AppModule. 5 | */ 6 | 7 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 8 | 9 | import { AppModule } from './app.module'; 10 | 11 | function launch() { 12 | const platform = platformBrowserDynamic(); 13 | platform.bootstrapModule(AppModule); 14 | } 15 | 16 | if (window.hasOwnProperty('Office') && window.hasOwnProperty('Word')) { 17 | 18 | // Application-specific initialization code goes into a function that is 19 | // assigned to the Office.initialize event and runs after the Office.js initializes. 20 | // Bootstrapping of the AppModule must come AFTER Office has initialized. 21 | Office.initialize = reason => { 22 | launch(); 23 | } 24 | } 25 | else { 26 | launch(); 27 | } 28 | -------------------------------------------------------------------------------- /app/settings/settings.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"settings.component.js","sourceRoot":"","sources":["settings.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;;;;EAKE;AAEF,sCAAgF;AAOhF,+EAA+E;AAC/E,kGAA+F;AAM/F;IAME,2BAAoB,eAAuC;QAAvC,oBAAe,GAAf,eAAe,CAAwB;IAAG,CAAC;IAE/D,2CAAe,GAAf;QACE,IAAI,yBAAyB,GAAW,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAExG,+EAA+E;QAC/E,8BAA8B;QAC9B,IAAI,yBAAyB,KAAK,eAAe,EAAE;YACjD,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YAChE,IAAI,CAAC,wBAAwB,CAAC,aAAa,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;SAChF;IACH,CAAC;IAED,iDAAqB,GAArB,UAAsB,eAAuB,EAAE,KAAa;QAC1D,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAlBqB;QAApB,gBAAS,CAAC,QAAQ,CAAC;kCAAoB,iBAAU;gEAAC;IACvB;QAA3B,gBAAS,CAAC,eAAe,CAAC;kCAA2B,iBAAU;uEAAC;IAJvD,iBAAiB;QAJ7B,gBAAS,CAAC;YACP,WAAW,EAAE,sCAAsC;YACnD,SAAS,EAAE,CAAC,qCAAqC,CAAC;SACrD,CAAC;yCAOqC,iDAAsB;OANhD,iBAAiB,CAsB7B;IAAD,wBAAC;CAAA,AAtBD,IAsBC;AAtBY,8CAAiB"} -------------------------------------------------------------------------------- /app/find-and-replace/find-and-replace.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for the find-and-replace view. 5 | */ 6 | 7 | .ms-navigation { 8 | display: -webkit-flex; 9 | display: flex; 10 | -webkit-flex-direction: column; 11 | flex-direction: column; 12 | -webkit-flex-wrap: nowrap; 13 | flex-wrap: nowrap; 14 | height: 100%; } 15 | 16 | .ms-navigation__content { 17 | -webkit-flex: 1 0 0px; 18 | flex: 1 0 0px; 19 | padding-top: 15px; 20 | padding-left: 20px; 21 | padding-right: 20px; 22 | margin-top: 0px; } 23 | 24 | .ms-navigation__content p { 25 | padding-top: 10px; } 26 | 27 | .ms-navigation__content ul { 28 | list-style: none; } 29 | 30 | .ms-navigation__content__title, .ms-navigation__content__subtitle, .ms-navigation__content__text { 31 | margin-bottom: 20px; } 32 | 33 | -------------------------------------------------------------------------------- /app/find-and-replace/find-and-replace.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"find-and-replace.component.js","sourceRoot":"","sources":["find-and-replace.component.ts"],"names":[],"mappings":";AAAA,6HAA6H;;;;;;;;;;;;AAE7H;;;EAGE;AAEF,sCAA4C;AAC5C,0CAAyC;AAOzC,0EAA0E;AAC1E,yFAAsF;AAEtF,gFAAgF;AAChF,kGAA+F;AAO/F;IAOI,iCAAoB,YAAiC,EACjC,eAAuC,EACvC,MAAc;QAFd,iBAAY,GAAZ,YAAY,CAAqB;QACjC,oBAAe,GAAf,eAAe,CAAwB;QACvC,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,8DAA8D;IAC9D,qDAAmB,GAAnB,UAAoB,OAAe;QAC/B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;IAChC,CAAC;IAED,+DAA+D;IAC/D,sDAAoB,GAApB,UAAqB,OAAe;QAChC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IACjC,CAAC;IAED,mFAAmF;IACnF,2DAAyB,GAAzB,UAA0B,OAAe;QACrC,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC;IACrC,CAAC;IAED,yCAAO,GAAP;QACI,IAAI,CAAC,YAAY,CAAC,iCAAiC,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvH,CAAC;IA5BQ,uBAAuB;QAJnC,gBAAS,CAAC;YACP,WAAW,EAAE,sDAAsD;YACnE,SAAS,EAAE,CAAC,qDAAqD,CAAC;SACrE,CAAC;yCAQoC,2CAAmB;YAChB,iDAAsB;YAC/B,eAAM;OATzB,uBAAuB,CA6BnC;IAAD,8BAAC;CAAA,AA7BD,IA6BC;AA7BY,0DAAuB"} -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 22 | 23 | -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fabric.contextual.menu.wrapper.component.js","sourceRoot":"","sources":["fabric.contextual.menu.wrapper.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;EAEE;AAEF,sCAAsD;AACtD,0CAAyC;AAEzC,0EAA0E;AAC1E,4FAAyF;AAOzF;IAEI,8CAAoB,YAAiC,EACjC,MAAc,EACd,OAAmB;QAFnB,iBAAY,GAAZ,YAAY,CAAqB;QACjC,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAY;IAAG,CAAC;IAE3C,kEAAmB,GAAnB;QACI,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC;YACrC,gBAAgB;YAChB,uHAAuH;YACvH,4CAA4C;YAC5C,wKAAwK;YACxK,sFAAsF;SACzF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC;IAED,wDAAS,GAAT;QACI,IAAI,WAAW,GAAgB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,8BAA8B;aAC5C,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAE,wCAAwC;QAClG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAtBQ,oCAAoC;QALhD,gBAAS,CAAC;YACP,QAAQ,EAAE,oBAAoB;YAC9B,WAAW,EAAE,2FAA2F;YACxG,SAAS,EAAC,CAAC,0FAA0F,CAAC;SACzG,CAAC;yCAGoC,2CAAmB;YACzB,eAAM;YACL,iBAAU;OAJ9B,oCAAoC,CAuBhD;IAAD,2CAAC;CAAA,AAvBD,IAuBC;AAvBY,oFAAoC"} -------------------------------------------------------------------------------- /app/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | /* 5 | This file bootstraps the root module: AppModule. 6 | */ 7 | var platform_browser_dynamic_1 = require("@angular/platform-browser-dynamic"); 8 | var app_module_1 = require("./app.module"); 9 | function launch() { 10 | var platform = platform_browser_dynamic_1.platformBrowserDynamic(); 11 | platform.bootstrapModule(app_module_1.AppModule); 12 | } 13 | if (window.hasOwnProperty('Office') && window.hasOwnProperty('Word')) { 14 | // Application-specific initialization code goes into a function that is 15 | // assigned to the Office.initialize event and runs after the Office.js initializes. 16 | // Bootstrapping of the AppModule must come AFTER Office has initialized. 17 | Office.initialize = function (reason) { 18 | launch(); 19 | }; 20 | } 21 | else { 22 | launch(); 23 | } 24 | //# sourceMappingURL=main.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fabric.textfield.wrapper.component.js","sourceRoot":"","sources":["fabric.textfield.wrapper.component.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;;;;AAElH;;EAEE;AAEF,sCAAkG;AAElG,wDAAwD;AACxD,yCAAwC;AAMxC;IAYI,yCAAoB,OAAmB;QAAnB,YAAO,GAAP,OAAO,CAAY;QAL9B,UAAK,GAAW,EAAE,CAAC;QAE5B,sEAAsE;QAC5D,gBAAW,GAA0B,IAAI,mBAAY,EAAU,CAAC;IAE/B,CAAC;IAE5C,mFAAmF;IACnF,yDAAe,GAAf;QACI,IAAI,gBAAgB,GAAgB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,KAAK,GAAG,IAAI,qBAAS,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IAED,mFAAmF;IACnF,8EAA8E;IAC9E,aAAa;IACb,wDAAc,GAAd;QACI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACzC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IArBQ;QAAR,YAAK,EAAE;;uEAAoB;IACnB;QAAR,YAAK,EAAE;;+DAAY;IACX;QAAR,YAAK,EAAE;;kEAAoB;IAGlB;QAAT,aAAM,EAAE;kCAAe,mBAAY;wEAAsC;IAVjE,+BAA+B;QAJ3C,gBAAS,CAAC;YACP,QAAQ,EAAE,cAAc;YACxB,WAAW,EAAE,qFAAqF;SACrG,CAAC;yCAa+B,iBAAU;OAZ9B,+BAA+B,CA2B3C;IAAD,sCAAC;CAAA,AA3BD,IA2BC;AA3BY,0EAA+B"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk 27 | 28 | 29 | ### Windows ### 30 | # Windows image file caches 31 | Thumbs.db 32 | ehthumbs.db 33 | 34 | # Folder config file 35 | Desktop.ini 36 | 37 | # Recycle Bin used on file shares 38 | $RECYCLE.BIN/ 39 | 40 | # Windows Installer files 41 | *.cab 42 | *.msi 43 | *.msm 44 | *.msp 45 | 46 | # Windows shortcuts 47 | *.lnk 48 | 49 | # Ignore the following folders 50 | node_modules/** 51 | bower_components/** 52 | www/** 53 | platforms/** 54 | typings/** 55 | obj/** 56 | bld/** 57 | bin/** 58 | 59 | 60 | # Ignore the cert and key file 61 | *.crt 62 | *.key 63 | *.csr 64 | 65 | 66 | # Misc 67 | underscore.js -------------------------------------------------------------------------------- /app/settings/settings.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for the settngs view. 5 | */ 6 | 7 | .ms-settings { 8 | display: -webkit-flex; 9 | display: flex; 10 | -webkit-flex-direction: column; 11 | flex-direction: column; 12 | -webkit-flex-wrap: nowrap; 13 | flex-wrap: nowrap; 14 | height: 100%; } 15 | 16 | .ms-settings__content { 17 | -webkit-flex: 1 0 0px; 18 | flex: 1 0 0px; 19 | padding-left: 20px; 20 | padding-right: 20px; 21 | margin-top: 0px; } 22 | 23 | .ms-settings__content__title { 24 | padding-top: 15px; 25 | padding-bottom: 10px; } 26 | 27 | .ms-settings__content__subtitle { 28 | padding-top: 15px; 29 | padding-bottom: 15px; } 30 | 31 | .ms-settings__content__text { 32 | padding-top: 10px; } 33 | 34 | .ms-settings__content--link { 35 | padding-bottom: 10px; 36 | padding-top: 10px; 37 | color: #0078d7; } 38 | 39 | .ms-settings__content a { 40 | color: #0078d7; 41 | text-decoration: none; } 42 | -------------------------------------------------------------------------------- /app/app-routing.module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"app-routing.module.js","sourceRoot":"","sources":["app-routing.module.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;EAEE;AAEF,sCAAqD;AACrD,0CAAuD;AACvD,4FAAwF;AACxF,0FAAuF;AACvF,oEAAkE;AAElE,SAAS,uBAAuB;IAC5B,OAAO,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,WAAW,GAAQ;QACnB,EAAE,IAAI,EAAE,mBAAmB,EAAE,SAAS,EAAE,uDAAyB,EAAE;QACnE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,sCAAiB,EAAE;QAClD,EAAE,IAAI,EAAE,kBAAkB,EAAE,SAAS,EAAE,oDAAuB,EAAE;KACnE,CAAC;IAEF,IAAI,YAAY,GAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,EAAC,CAAC;IAEzF,kEAAkE;IAClE,6DAA6D;IAC7D,IAAG,uBAAuB,EAAE,KAAK,eAAe,EAAE;QAC7C,YAAY,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,EAAC,CAAA;KAClF;IACD,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,IAAM,MAAM,GAAW,cAAc,EAAE,CAAC;AASxC;IAAA;IAA+B,CAAC;IAAnB,gBAAgB;QAP5B,eAAQ,CAAC;YACR,OAAO,EAAE,CAAE,qBAAY,CAAC,OAAO,CAAC,MAAM;gBACN,iDAAiD;gBACjD,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC,CAAE;YAClD,OAAO,EAAE,CAAE,qBAAY,CAAE;SAC1B,CAAC;OAEW,gBAAgB,CAAG;IAAD,uBAAC;CAAA,AAAhC,IAAgC;AAAnB,4CAAgB"} -------------------------------------------------------------------------------- /app/shared/navigation-header/navigation.header.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a navigation header for a task pane page. It is based on 5 | the navigation sample, created by the Modern Assistance Experience Developer 6 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 7 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 8 | */ 9 | 10 | import { Component } from '@angular/core'; 11 | 12 | // Import the child components that will be in the header. 13 | import { ContextualMenuButtonComponent } from '../contextual-menu-button/contextual.menu.button.component'; 14 | import { FabricContextualMenuWrapperComponent } from '../office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component'; 15 | 16 | @Component({ 17 | selector: 'sc-navigation-header', 18 | templateUrl: 'app/shared/navigation-header/navigation.header.component.html', 19 | styleUrls: ['app/shared/navigation-header/navigation.header.component.css'], 20 | }) 21 | export class NavigationHeaderComponent {} 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Word Add-in Angular2 Style Checker 2 | 3 | The MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Copyright (c) Microsoft Corporation, 2016. All rights reserved. -------------------------------------------------------------------------------- /app/shared/contextual-menu-button/contextual.menu.button.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a component that provides a button that opens a contextual menu. 5 | */ 6 | 7 | import { Component, OnInit, ElementRef } from '@angular/core'; 8 | 9 | @Component({ 10 | selector: 'sc-contextual-menu-button', 11 | templateUrl: 'app/shared/contextual-menu-button/contextual.menu.button.component.html', 12 | styleUrls: ['app/shared/contextual-menu-button/contextual.menu.button.component.css'], 13 | }) 14 | export class ContextualMenuButtonComponent { 15 | 16 | constructor(private element: ElementRef ){} 17 | 18 | toggleDropDown() { 19 | let menuElement: HTMLElement = this.element.nativeElement // = this 20 | .nextSibling // = an empty text node 21 | .nextSibling // = 22 | .children[0]; // =
    23 | menuElement.classList.toggle("is-open"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/shared/contextual-menu-button/contextual.menu.button.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for the menu hosting button. These make minor overrides of the 5 | standard Fabric classes with the same names. 6 | */ 7 | 8 | .ms-Button.ms-Button--command { 9 | transition: background ease 0.1s, color ease 0.1s; 10 | padding-top: 4px; 11 | padding-left: 20px; 12 | padding-right: 20px; 13 | height: 40px; } 14 | 15 | .ms-Button.ms-Button--command:active, .ms-Button.ms-Button--command:hover { 16 | background: #eff6fc; 17 | cursor: pointer; } 18 | 19 | .ms-Button.ms-Button--command:active { 20 | background: #eff6fc; 21 | -webkit-transform: scale3d(0.98, 0.98, 1); 22 | transform: scale3d(0.98, 0.98, 1); } 23 | 24 | .ms-Button.ms-Button--command--disabled { 25 | opacity: 0.6; 26 | pointer-events: none; 27 | cursor: not-allowed; } 28 | 29 | .ms-Button.ms-Button--command--disabled:active, .ms-Button.ms-Button--command--disabled:hover { 30 | background: transparent; } 31 | 32 | .ms-Button.ms-Button--command--disabled:active { 33 | -webkit-transform: none; 34 | transform: none; } 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/find-and-replace/find-and-replace.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 |
    10 |
    Search and Replace
    11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
    20 |
    21 | 22 |
    23 | 24 | 25 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch", 6 | "type": "node", 7 | "request": "launch", 8 | "program": "${workspaceRoot}/systemjs.config.js", 9 | "stopOnEntry": false, 10 | "args": [], 11 | "cwd": "${workspaceRoot}", 12 | "preLaunchTask": null, 13 | "runtimeExecutable": null, 14 | "runtimeArgs": [ 15 | "--nolazy" 16 | ], 17 | "env": { 18 | "NODE_ENV": "development" 19 | }, 20 | "externalConsole": false, 21 | "sourceMaps": false, 22 | "outDir": null 23 | }, 24 | { 25 | "name": "Attach", 26 | "type": "node", 27 | "request": "attach", 28 | "port": 3000, 29 | "address": "localhost", 30 | "restart": false, 31 | "sourceMaps": false, 32 | "outDir": null, 33 | "localRoot": "${workspaceRoot}", 34 | "remoteRoot": null 35 | }, 36 | { 37 | "name": "Attach to Process", 38 | "type": "node", 39 | "request": "attach", 40 | "processId": "${command.PickProcess}", 41 | "port": 3000, 42 | "sourceMaps": false, 43 | "outDir": null 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /app/app.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.AppComponent = void 0; 11 | /* 12 | This file defines the root component of the application. 13 | */ 14 | var core_1 = require("@angular/core"); 15 | var AppComponent = /** @class */ (function () { 16 | function AppComponent() { 17 | } 18 | AppComponent = __decorate([ 19 | core_1.Component({ 20 | selector: 'sc-app', 21 | template: "\n
    \n
    \n \n
    \n
    \n " 22 | }) 23 | ], AppComponent); 24 | return AppComponent; 25 | }()); 26 | exports.AppComponent = AppComponent; 27 | //# sourceMappingURL=app.component.js.map -------------------------------------------------------------------------------- /app/shared/brand.footer.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var BrandFooterComponent = (function () { 13 | function BrandFooterComponent() { 14 | } 15 | BrandFooterComponent = __decorate([ 16 | core_1.Component({ 17 | selector: 'sc-brand-footer', 18 | templateUrl: 'app/shared/brand-footer/brand.footer.component.html', 19 | styleUrls: ['app/shared/brand-footer/brand.footer.component.css'], 20 | }), 21 | __metadata('design:paramtypes', []) 22 | ], BrandFooterComponent); 23 | return BrandFooterComponent; 24 | }()); 25 | exports.BrandFooterComponent = BrandFooterComponent; 26 | //# sourceMappingURL=brand.footer.component.js.map -------------------------------------------------------------------------------- /app/shared/button.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var ButtonComponent = (function () { 13 | function ButtonComponent() { 14 | } 15 | __decorate([ 16 | core_1.Input(), 17 | __metadata('design:type', String) 18 | ], ButtonComponent.prototype, "buttonlabel", void 0); 19 | ButtonComponent = __decorate([ 20 | core_1.Component({ 21 | selector: 'sc-button', 22 | templateUrl: 'app/shared/button/button.component.html' 23 | }), 24 | __metadata('design:paramtypes', []) 25 | ], ButtonComponent); 26 | return ButtonComponent; 27 | }()); 28 | exports.ButtonComponent = ButtonComponent; 29 | //# sourceMappingURL=button.component.js.map -------------------------------------------------------------------------------- /app/shared/contextual.menu.button.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var ContextualMenuButtonComponent = (function () { 13 | function ContextualMenuButtonComponent() { 14 | } 15 | ContextualMenuButtonComponent = __decorate([ 16 | core_1.Component({ 17 | selector: 'sc-contextual-menu-button', 18 | templateUrl: 'app/shared/contextual-menu-button/contextual.menu.button.component.html', 19 | styleUrls: ['app/shared/contextual-menu-button/contextual.menu.button.component.css'], 20 | }), 21 | __metadata('design:paramtypes', []) 22 | ], ContextualMenuButtonComponent); 23 | return ContextualMenuButtonComponent; 24 | }()); 25 | exports.ContextualMenuButtonComponent = ContextualMenuButtonComponent; 26 | //# sourceMappingURL=contextual.menu.button.component.js.map -------------------------------------------------------------------------------- /app/instructions/instruction-steps.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 |
    8 |
    9 |
    {{title}}
    10 |
    11 | {{addin_description}} 12 |
    13 |
    14 |
    15 |
    16 |

    {{steps_intro}}

    17 | 18 |
      19 |
    • 20 | {{step.step_number}} 21 | 22 | 23 | {{step.content}} 24 | 25 | 26 |
      27 |
    • 28 |
    29 |
    30 |
    31 |

    32 | 33 |

    34 |
    35 |
    36 | -------------------------------------------------------------------------------- /app/instructions/instruction-steps.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | 3 | /* 4 | This file defines an instructions component for a task pane page. It is based on 5 | the instruction-step sample, created by the Modern Assistance Experience Developer 6 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 7 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 8 | */ 9 | 10 | import { Component } from '@angular/core'; 11 | import { Router } from '@angular/router'; 12 | 13 | import { ButtonComponent } from '../shared/button/button.component'; 14 | import { IInstructionStep } from './IInstructionStep'; 15 | 16 | @Component({ 17 | templateUrl: 'app/instructions/instruction-steps.component.html', 18 | styleUrls: ['app/instructions/instruction-steps.component.css'] 19 | }) 20 | export class InstructionStepsComponent { 21 | 22 | private title: string = "WELCOME"; 23 | private addin_description: string = "Style Checker enables you to enforce style rules while exempting paragraphs that you specify from the rules."; 24 | private steps_intro: string = "Just take these steps:"; 25 | private steps: Array = 26 | [{ step_number: 1, content: "Enter a string in the Find box." }, 27 | { step_number: 2, content: "Enter a replacement string in the Replace With box." }, 28 | { step_number: 3, content: "Enter the zero-based numbers of the parapgraphs that should be exempt in the Skip Paragraphs box." }, 29 | { step_number: 4, content: "Press Replace." }]; 30 | 31 | constructor(private router: Router) { } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /systemjs.config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file configures the script loader, SystemJS. 5 | */ 6 | 7 | (function (global) { 8 | System.config({ 9 | paths: { 10 | // paths serve as alias 11 | 'npm:': 'node_modules/' 12 | }, 13 | // map tells the System loader where to look for things 14 | map: { 15 | // our app is within the app folder 16 | app: 'app', 17 | // angular bundles 18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js', 19 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js', 20 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', 21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', 22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 23 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js', 24 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js', 25 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 26 | // other libraries 27 | 'rxjs': 'npm:rxjs', 28 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', 29 | }, 30 | // packages tells the System loader how to load when no filename and/or no extension 31 | packages: { 32 | app: { 33 | main: './main.js', 34 | defaultExtension: 'js' 35 | }, 36 | rxjs: { 37 | defaultExtension: 'js' 38 | }, 39 | 'angular-in-memory-web-api': { 40 | main: './index.js', 41 | defaultExtension: 'js' 42 | } 43 | } 44 | }); 45 | })(this); 46 | -------------------------------------------------------------------------------- /app/shared/button/button.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.ButtonComponent = void 0; 14 | /* 15 | This file defines a Fabic-styled button. 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var ButtonComponent = /** @class */ (function () { 19 | function ButtonComponent() { 20 | } 21 | __decorate([ 22 | core_1.Input(), 23 | __metadata("design:type", String) 24 | ], ButtonComponent.prototype, "buttonlabel", void 0); 25 | ButtonComponent = __decorate([ 26 | core_1.Component({ 27 | selector: 'sc-button', 28 | templateUrl: 'app/shared/button/button.component.html', 29 | styleUrls: ['app/shared/button/button.component.css'] 30 | }) 31 | ], ButtonComponent); 32 | return ButtonComponent; 33 | }()); 34 | exports.ButtonComponent = ButtonComponent; 35 | //# sourceMappingURL=button.component.js.map -------------------------------------------------------------------------------- /app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines the routes of the application. 5 | */ 6 | 7 | import { NgModule } from '@angular/core'; 8 | import { RouterModule, Routes } from '@angular/router'; 9 | import { FindAndReplaceComponent } from './find-and-replace/find-and-replace.component'; 10 | import { InstructionStepsComponent } from './instructions/instruction-steps.component'; 11 | import { SettingsComponent } from './settings/settings.component'; 12 | 13 | function fetchInstructionSetting() : string { 14 | return window.localStorage.getItem("StyleCheckerAddinShowInstructions"); 15 | } 16 | 17 | function setRoutesArray(): any { 18 | let routesArray: any = [ 19 | { path: 'instruction-steps', component: InstructionStepsComponent }, 20 | { path: 'settings', component: SettingsComponent }, 21 | { path: 'find-and-replace', component: FindAndReplaceComponent } 22 | ]; 23 | 24 | let defaultRoute: any = { path: '', redirectTo: '/instruction-steps', pathMatch: 'full'}; 25 | 26 | // If a user has set the application to skip the instruction view, 27 | // then set the default route to the search and replace view. 28 | if(fetchInstructionSetting() === "OnlyFirstTime") { 29 | defaultRoute = { path: '', redirectTo: '/find-and-replace', pathMatch: 'full'} 30 | } 31 | routesArray.unshift(defaultRoute); 32 | return routesArray; 33 | } 34 | 35 | const routes: Routes = setRoutesArray(); 36 | 37 | @NgModule({ 38 | imports: [ RouterModule.forRoot(routes, 39 | // Use hash location strategy in an Office Add-in 40 | {useHash: true}) ], 41 | exports: [ RouterModule ] 42 | }) 43 | 44 | export class AppRoutingModule {} -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | The file defines an Angular 2 component to wrap the Fabric TextField component. 5 | */ 6 | 7 | import { Component, Input, Output, EventEmitter, ElementRef, AfterViewInit } from '@angular/core'; 8 | 9 | // Import the default Fabric implementation of TextField 10 | import { TextField } from './TextField'; 11 | 12 | @Component({ 13 | selector: 'of-textfield', 14 | templateUrl: 'app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.html', 15 | }) 16 | export class FabricTextFieldWrapperComponent implements AfterViewInit { 17 | 18 | private field: TextField; 19 | 20 | // The parent component will supply the values for these properties. 21 | @Input() innerlabel: string; 22 | @Input() id: string; 23 | @Input() value: string = ""; 24 | 25 | // Create an event to run when the user enters text in the text field. 26 | @Output() textEntered: EventEmitter = new EventEmitter(); 27 | 28 | constructor(private element: ElementRef ){ } 29 | 30 | // After the textfield has fully rendered, create a Fabric TextField object for it. 31 | ngAfterViewInit() { 32 | let componentElement: HTMLElement = this.element.nativeElement.children[0]; 33 | this.field = new TextField(componentElement); 34 | } 35 | 36 | // When the user changes the text field's contents, pull the new value up from the 37 | // Fabric component to the Angular 2 component, and tell the parent view about 38 | // the event. 39 | onValueChanged(): void { 40 | this.value = this.field._textField.value; 41 | this.textEntered.emit(this.value); 42 | } 43 | } -------------------------------------------------------------------------------- /app/shared/brand-footer/brand.footer.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.BrandFooterComponent = void 0; 11 | /* 12 | This file defines a branded footer for a task pane page. It is based on 13 | the navigation sample, created by the Modern Assistance Experience Developer 14 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 15 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var BrandFooterComponent = /** @class */ (function () { 19 | function BrandFooterComponent() { 20 | } 21 | BrandFooterComponent = __decorate([ 22 | core_1.Component({ 23 | selector: 'sc-brand-footer', 24 | templateUrl: 'app/shared/brand-footer/brand.footer.component.html', 25 | styleUrls: ['app/shared/brand-footer/brand.footer.component.css'], 26 | }) 27 | ], BrandFooterComponent); 28 | return BrandFooterComponent; 29 | }()); 30 | exports.BrandFooterComponent = BrandFooterComponent; 31 | //# sourceMappingURL=brand.footer.component.js.map -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | Style Checker 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | Loading Style Checker ... 41 | 42 | -------------------------------------------------------------------------------- /app/shared/navigation-header/navigation.header.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.NavigationHeaderComponent = void 0; 11 | /* 12 | This file defines a navigation header for a task pane page. It is based on 13 | the navigation sample, created by the Modern Assistance Experience Developer 14 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 15 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var NavigationHeaderComponent = /** @class */ (function () { 19 | function NavigationHeaderComponent() { 20 | } 21 | NavigationHeaderComponent = __decorate([ 22 | core_1.Component({ 23 | selector: 'sc-navigation-header', 24 | templateUrl: 'app/shared/navigation-header/navigation.header.component.html', 25 | styleUrls: ['app/shared/navigation-header/navigation.header.component.css'], 26 | }) 27 | ], NavigationHeaderComponent); 28 | return NavigationHeaderComponent; 29 | }()); 30 | exports.NavigationHeaderComponent = NavigationHeaderComponent; 31 | //# sourceMappingURL=navigation.header.component.js.map -------------------------------------------------------------------------------- /app/shared/navigation.header.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var contextual_menu_button_component_1 = require('./contextual.menu.button.component'); 13 | var fabric_contextual_menu_wrapper_component_1 = require('./office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component'); 14 | var NavigationHeaderComponent = (function () { 15 | function NavigationHeaderComponent() { 16 | } 17 | NavigationHeaderComponent = __decorate([ 18 | core_1.Component({ 19 | selector: 'sc-navigation-header', 20 | templateUrl: 'app/shared/navigation-header/navigation.header.component.html', 21 | styleUrls: ['app/shared/navigation-header/navigation.header.component.css'], 22 | directives: [contextual_menu_button_component_1.ContextualMenuButtonComponent, fabric_contextual_menu_wrapper_component_1.FabricContextualMenuWrapperComponent] 23 | }), 24 | __metadata('design:paramtypes', []) 25 | ], NavigationHeaderComponent); 26 | return NavigationHeaderComponent; 27 | }()); 28 | exports.NavigationHeaderComponent = NavigationHeaderComponent; 29 | //# sourceMappingURL=navigation.header.component.js.map -------------------------------------------------------------------------------- /app/settings/settings.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 |
    10 |
    Settings
    11 |
    Instructions
    12 |
    13 |
    14 | 16 | 19 |
    20 |
    21 | 23 | 26 |
    27 |
    28 | 29 |
    About this Add-in
    30 |

    Style Checker v1.0.0.0
    © 2016 Microsoft Co.

    31 |
    32 | 33 | 34 | -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | The file defines an Angular 2 component to wrap the Fabric ContextualMenu component. 5 | */ 6 | 7 | import { Component, ElementRef } from '@angular/core'; 8 | import { Router } from '@angular/router'; 9 | 10 | // The WordDocumentService provides methods for manipulating the document. 11 | import { WordDocumentService } from '../../services/word-document/word.document.service'; 12 | 13 | @Component({ 14 | selector: 'of-contextual-menu', 15 | templateUrl: 'app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.html', 16 | styleUrls:['app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.css'] 17 | }) 18 | export class FabricContextualMenuWrapperComponent { 19 | 20 | constructor(private wordDocument: WordDocumentService, 21 | private router: Router, 22 | private element: ElementRef){ } 23 | 24 | insertSampleContent() { 25 | this.wordDocument.replaceDocumentContent([ 26 | "Office Add-ins", 27 | "An OAI executes in an Office application and can interact with data in a document or mail item. As one observer said:", 28 | "\t\"The new OAI model is the cat's meow.\"", 29 | "An OAI is a web app that you can host anywhere. It runs in an Office application. A manifest.xml file specifies where the web app is located and how it should appear.", 30 | "You can find an OAI sample or two (or many) in the OfficeDev organization on GitHub." 31 | ]); 32 | 33 | this.closeMenu(); 34 | } 35 | 36 | closeMenu() { 37 | let menuElement: HTMLElement = this.element.nativeElement // = this 38 | .children[0]; // =
      39 | menuElement.classList.remove("is-open"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/services/settings-storage/settings.storage.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.SettingsStorageService = void 0; 14 | /* 15 | This file defines a service that provides CRUD operations on application settings. 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var SettingsStorageService = /** @class */ (function () { 19 | function SettingsStorageService() { 20 | } 21 | SettingsStorageService.prototype.store = function (specificKey, value) { 22 | window.localStorage.setItem(specificKey, value); 23 | }; 24 | SettingsStorageService.prototype.fetch = function (specificKey) { 25 | return window.localStorage.getItem(specificKey); 26 | }; 27 | SettingsStorageService.prototype.remove = function (specificKey) { 28 | window.localStorage.removeItem(specificKey); 29 | }; 30 | SettingsStorageService = __decorate([ 31 | core_1.Injectable(), 32 | __metadata("design:paramtypes", []) 33 | ], SettingsStorageService); 34 | return SettingsStorageService; 35 | }()); 36 | exports.SettingsStorageService = SettingsStorageService; 37 | //# sourceMappingURL=settings.storage.service.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/TextField.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"TextField.js","sourceRoot":"","sources":["TextField.ts"],"names":[],"mappings":"AAAA,yIAAyI;AAEzI,YAAY,CAAC;;;AAEb,gFAAgF;AAChF,gFAAgF;AAChF,kCAAkC;AAElC,oBAAoB;AAElB,IAAO,eAAe,CAKrB;AALD,WAAO,eAAe;IACpB,IAAY,IAGX;IAHD,WAAY,IAAI;QACZ,6CAAW,CAAA;QACX,2CAAU,CAAA;IACd,CAAC,EAHW,IAAI,GAAJ,oBAAI,KAAJ,oBAAI,QAGf;AACH,CAAC,EALM,eAAe,KAAf,eAAe,QAKrB;AAGD;;;;GAIG;AACH;IAOE;;;;OAIG;IACH,mBAAY,SAAsB;QAChC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,UAAU,GAAqB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;QACzF,IAAI,CAAC,eAAe,GAAgB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAC/E,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,uDAAuD;IAC/C,qCAAiB,GAAzB;QACE,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EAAE;YACnE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;SACnD;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE;YAClE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAClD;IACH,CAAC;IAED,iEAAiE;IACzD,iCAAa,GAArB;QAAA,iBA4BC;QA1BC,iDAAiD;QACjD,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;YAC7D,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,KAAiB;gBAC1D,KAAI,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;YAC9C,CAAC,CAAC,CAAC;YACH,8EAA8E;YAC9E,0CAA0C;YAC1C,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,KAAiB;gBAC/D,KAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAC1B,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,MAAM,EAAE,UAAC,KAAiB;gBACzD,0CAA0C;gBAC1C,IAAI,KAAI,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;oBACtC,KAAI,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;iBAC9C;YACH,CAAC,CAAC,CAAC;SACJ;QACD,kDAAkD;QAClD,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YAC5D,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,KAAiB;gBAC1D,KAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7C,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,MAAM,EAAE,UAAC,KAAiB;gBACzD,KAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;IACH,gBAAC;AAAD,CAAC,AA7DD,IA6DC;AA7DY,8BAAS"} -------------------------------------------------------------------------------- /app/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a settings view. It is based on 5 | the settings sample, created by the Modern Assistance Experience Developer 6 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 7 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 8 | */ 9 | 10 | import { Component, AfterViewInit, ElementRef, ViewChild } from '@angular/core'; 11 | import { Router } from '@angular/router'; 12 | 13 | import { NavigationHeaderComponent} from '../shared/navigation-header/navigation.header.component'; 14 | import { ButtonComponent } from '../shared/button/button.component'; 15 | import { BrandFooterComponent} from '../shared/brand-footer/brand.footer.component'; 16 | 17 | // The SettingsStorageService provides CRUD operations on application settings. 18 | import { SettingsStorageService } from '../services/settings-storage/settings.storage.service'; 19 | 20 | @Component({ 21 | templateUrl: 'app/settings/settings.component.html', 22 | styleUrls: ['app/settings/settings.component.css'] 23 | }) 24 | export class SettingsComponent { 25 | 26 | // Get references to the radio buttons so we can toggle which is selected. 27 | @ViewChild('always') alwaysRadioButton: ElementRef; 28 | @ViewChild('onlyFirstTime') onlyFirstTimeRadioButton: ElementRef; 29 | 30 | constructor(private settingsStorage: SettingsStorageService) {} 31 | 32 | ngAfterViewInit() { 33 | let currentInstructionSetting: string = this.settingsStorage.fetch("StyleCheckerAddinShowInstructions"); 34 | 35 | // Ensure that when the settings view loads, the radio button selection matches 36 | // the user's current setting. 37 | if (currentInstructionSetting === "OnlyFirstTime") { 38 | this.alwaysRadioButton.nativeElement.removeAttribute("checked"); 39 | this.onlyFirstTimeRadioButton.nativeElement.setAttribute("checked", "checked"); 40 | } 41 | } 42 | 43 | onRadioButtonSelected(specificSetting: string, value: string){ 44 | this.settingsStorage.store(specificSetting, value); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /app/shared/star.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var StarComponent = (function () { 13 | function StarComponent() { 14 | this.ratingClicked = new core_1.EventEmitter(); 15 | } 16 | StarComponent.prototype.ngOnChanges = function () { 17 | // Convert x out of 5 starts 18 | // to y out of 86px width 19 | this.starWidth = this.rating * 86 / 5; 20 | }; 21 | StarComponent.prototype.onClick = function () { 22 | this.ratingClicked.emit("The rating " + this.rating + " was clicked!"); 23 | }; 24 | __decorate([ 25 | core_1.Input(), 26 | __metadata('design:type', String) 27 | ], StarComponent.prototype, "innerlabel", void 0); 28 | __decorate([ 29 | core_1.Input(), 30 | __metadata('design:type', Number) 31 | ], StarComponent.prototype, "rating", void 0); 32 | __decorate([ 33 | core_1.Output(), 34 | __metadata('design:type', core_1.EventEmitter) 35 | ], StarComponent.prototype, "ratingClicked", void 0); 36 | StarComponent = __decorate([ 37 | core_1.Component({ 38 | selector: 'ai-star', 39 | templateUrl: 'app/shared/star.component.html', 40 | styleUrls: ['app/shared/star.component.css'] 41 | }), 42 | __metadata('design:paramtypes', []) 43 | ], StarComponent); 44 | return StarComponent; 45 | }()); 46 | exports.StarComponent = StarComponent; 47 | //# sourceMappingURL=star.component.js.map -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | "static-before-instance", 25 | "variables-before-functions" 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [ 30 | true, 31 | "debug", 32 | "info", 33 | "time", 34 | "timeEnd", 35 | "trace" 36 | ], 37 | "no-construct": true, 38 | "no-debugger": true, 39 | "no-duplicate-key": true, 40 | "no-duplicate-variable": true, 41 | "no-empty": false, 42 | "no-eval": true, 43 | "no-inferrable-types": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": false, 46 | "no-switch-case-fall-through": true, 47 | "no-trailing-whitespace": true, 48 | "no-unused-expression": true, 49 | "no-unused-variable": true, 50 | "no-unreachable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | "always" 68 | ], 69 | "triple-equals": [ 70 | true, 71 | "allow-null-check" 72 | ], 73 | "typedef-whitespace": [ 74 | true, 75 | { 76 | "call-signature": "nospace", 77 | "index-signature": "nospace", 78 | "parameter": "nospace", 79 | "property-declaration": "nospace", 80 | "variable-declaration": "nospace" 81 | } 82 | ], 83 | "variable-name": false, 84 | "whitespace": [ 85 | true, 86 | "check-branch", 87 | "check-decl", 88 | "check-operator", 89 | "check-separator", 90 | "check-type" 91 | ] 92 | } 93 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Word-Add-in-Angular2-StyleChecker", 3 | "version": "1.0.1", 4 | "author": "CALC Developer Education Office Add-ins Team", 5 | "description": "Package for the Style Checker sample Word Add-in", 6 | "scripts": { 7 | "start": "concurrently \"npm run tsc:w\" \"npm run lite\" ", 8 | "tsc": "tsc", 9 | "tsc:w": "tsc -w", 10 | "lint": "tslint ./app/**/*.ts -t verbose", 11 | "lite": "lite-server -c bs-config.json" 12 | }, 13 | "license": "MIT", 14 | "dependencies": { 15 | "@angular/common": "^5.2.9", 16 | "@angular/compiler": "^5.2.9", 17 | "@angular/core": "^11.0.5", 18 | "@angular/platform-browser": "^5.2.9", 19 | "@angular/platform-browser-dynamic": "^5.2.9", 20 | "@angular/router": "^5.2.9", 21 | "@angular/upgrade": "^5.2.9", 22 | "core-js": "^2.4.1", 23 | "reflect-metadata": "^0.1.8", 24 | "rxjs": "5.5.12", 25 | "systemjs": "0.19.39", 26 | "zone.js": "^0.6.25" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "^7.11.6", 30 | "@babel/polyfill": "^7.11.5", 31 | "@babel/preset-env": "^7.11.5", 32 | "@types/find-process": "1.2.0", 33 | "@types/office-js": "^1.0.108", 34 | "@types/office-runtime": "^1.0.14", 35 | "babel-loader": "^8.3.0", 36 | "clean-webpack-plugin": "^3.0.0", 37 | "concurrently": "^3.0.0", 38 | "copy-webpack-plugin": "^6.1.1", 39 | "eslint-config-office-addins": "^1.0.19", 40 | "find-process": "^1.4.3", 41 | "file-loader": "^6.2.0", 42 | "lite-server": "^2.2.2", 43 | "html-loader": "^4.2.0", 44 | "html-webpack-plugin": "^5.5.0", 45 | "office-addin-cli": "^1.0.13", 46 | "office-addin-debugging": "^3.0.34", 47 | "office-addin-dev-certs": "^1.5.5", 48 | "office-addin-lint": "^1.0.26", 49 | "office-addin-manifest": "1.5.7", 50 | "office-addin-prettier-config": "^1.0.12", 51 | "source-map-loader": "^4.0.1", 52 | "ts-loader": "^9.4.2", 53 | "typescript": "^4.0.3", 54 | "webpack": "^5.76.0", 55 | "webpack-cli": "^5.0.1", 56 | "webpack-dev-server": "^4.11.1" 57 | }, 58 | "repository": {} 59 | } 60 | -------------------------------------------------------------------------------- /app/instructions/instruction-step.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | var core_1 = require('@angular/core'); 12 | var router_1 = require('@angular/router'); 13 | var button_component_1 = require('../shared/button.component'); 14 | var InstructionStepsComponent = (function () { 15 | function InstructionStepsComponent() { 16 | this.title = "WELCOME"; 17 | this.addin_description = "Style Checker enables you to enforce style rules while exempting paragraphs that you specify from the rules."; 18 | this.steps_intro = "Just take these steps:"; 19 | this.steps = [{ step_number: 1, content: "Enter a string in the Find box." }, 20 | { step_number: 2, content: "Enter a replacement string in the Replace With box." }, 21 | { step_number: 3, content: "Enter the zero-based numbers of the parapgraphs that should be exempt in the Skip Paragraphs box." }, 22 | { step_number: 4, content: "Press Replace." }]; 23 | } 24 | InstructionStepsComponent = __decorate([ 25 | core_1.Component({ 26 | templateUrl: 'app/instructions/instruction-steps.component.html', 27 | directives: [button_component_1.ButtonComponent, router_1.ROUTER_DIRECTIVES], 28 | styleUrls: ['app/instructions/instruction-steps.component.css'], 29 | }), 30 | __metadata('design:paramtypes', []) 31 | ], InstructionStepsComponent); 32 | return InstructionStepsComponent; 33 | }()); 34 | exports.InstructionStepsComponent = InstructionStepsComponent; 35 | //# sourceMappingURL=instruction-step.component.js.map -------------------------------------------------------------------------------- /app/app.module.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file brings together all of the required modules and components and identifies 5 | the component to be bootstrapped. 6 | */ 7 | 8 | import { NgModule } from '@angular/core'; 9 | import { BrowserModule } from '@angular/platform-browser'; 10 | import { AppRoutingModule } from './app-routing.module'; 11 | 12 | // Import all the custom components. 13 | import { AppComponent } from './app.component'; 14 | import { FindAndReplaceComponent } from './find-and-replace/find-and-replace.component'; 15 | import { InstructionStepsComponent } from './instructions/instruction-steps.component'; 16 | import { SettingsComponent } from './settings/settings.component'; 17 | import { ButtonComponent } from './shared/button/button.component'; 18 | import { NavigationHeaderComponent} from './shared/navigation-header/navigation.header.component'; 19 | import { BrandFooterComponent} from './shared/brand-footer/brand.footer.component'; 20 | import { ContextualMenuButtonComponent } from './shared/contextual-menu-button/contextual.menu.button.component'; 21 | import { FabricContextualMenuWrapperComponent } from './shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component'; 22 | import { FabricTextFieldWrapperComponent } from './shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component'; 23 | 24 | // The WordDocumentService provides methods for manipulating the document. 25 | import { WordDocumentService } from './services/word-document/word.document.service'; 26 | 27 | // The SettingsStorageService provides CRUD operations on application settings. 28 | import { SettingsStorageService } from './services/settings-storage/settings.storage.service'; 29 | 30 | 31 | @NgModule({ 32 | imports: [ 33 | BrowserModule, 34 | AppRoutingModule 35 | ], 36 | declarations: [ 37 | AppComponent, 38 | FindAndReplaceComponent, 39 | InstructionStepsComponent, 40 | SettingsComponent, 41 | ButtonComponent, 42 | NavigationHeaderComponent, 43 | BrandFooterComponent, 44 | ContextualMenuButtonComponent, 45 | FabricContextualMenuWrapperComponent, 46 | FabricTextFieldWrapperComponent 47 | ], 48 | providers: [ 49 | WordDocumentService, 50 | SettingsStorageService 51 | ], 52 | bootstrap: [ AppComponent ] 53 | }) 54 | export class AppModule { } -------------------------------------------------------------------------------- /app/shared/contextual-menu-button/contextual.menu.button.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.ContextualMenuButtonComponent = void 0; 14 | /* 15 | This file defines a component that provides a button that opens a contextual menu. 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var ContextualMenuButtonComponent = /** @class */ (function () { 19 | function ContextualMenuButtonComponent(element) { 20 | this.element = element; 21 | } 22 | ContextualMenuButtonComponent.prototype.toggleDropDown = function () { 23 | var menuElement = this.element.nativeElement // = this 24 | .nextSibling // = an empty text node 25 | .nextSibling // = 26 | .children[0]; // =
        27 | menuElement.classList.toggle("is-open"); 28 | }; 29 | ContextualMenuButtonComponent = __decorate([ 30 | core_1.Component({ 31 | selector: 'sc-contextual-menu-button', 32 | templateUrl: 'app/shared/contextual-menu-button/contextual.menu.button.component.html', 33 | styleUrls: ['app/shared/contextual-menu-button/contextual.menu.button.component.css'], 34 | }), 35 | __metadata("design:paramtypes", [core_1.ElementRef]) 36 | ], ContextualMenuButtonComponent); 37 | return ContextualMenuButtonComponent; 38 | }()); 39 | exports.ContextualMenuButtonComponent = ContextualMenuButtonComponent; 40 | //# sourceMappingURL=contextual.menu.button.component.js.map -------------------------------------------------------------------------------- /app/find-and-replace/find-and-replace.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | 3 | /* 4 | This file defines a component that enables a search-and-replace functionality for 5 | the Word document. 6 | */ 7 | 8 | import { Component, } from '@angular/core'; 9 | import { Router } from '@angular/router'; 10 | 11 | import { FabricTextFieldWrapperComponent } from '../shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component'; 12 | import { ButtonComponent } from '../shared/button/button.component'; 13 | import { NavigationHeaderComponent} from '../shared/navigation-header/navigation.header.component'; 14 | import { BrandFooterComponent} from '../shared/brand-footer/brand.footer.component'; 15 | 16 | // The WordDocumentService provides methods for manipulating the document. 17 | import { WordDocumentService } from '../services/word-document/word.document.service'; 18 | 19 | // The SettingsStorageService provides CRUD operations on application settings.. 20 | import { SettingsStorageService } from '../services/settings-storage/settings.storage.service'; 21 | 22 | 23 | @Component({ 24 | templateUrl: 'app/find-and-replace/find-and-replace.component.html', 25 | styleUrls: ['app/find-and-replace/find-and-replace.component.css'], 26 | }) 27 | export class FindAndReplaceComponent { 28 | 29 | private searchString: string; 30 | private replaceString: string; 31 | private excludedParagraph: number; 32 | private subscription: any; 33 | 34 | constructor(private wordDocument: WordDocumentService, 35 | private settingsStorage: SettingsStorageService, 36 | private router: Router) {} 37 | 38 | // Handle the event of a user entering text in the search box. 39 | onSearchTextEntered(message: string): void { 40 | this.searchString = message; 41 | } 42 | 43 | // Handle the event of a user entering text in the replace box. 44 | onReplaceTextEntered(message: string): void { 45 | this.replaceString = message; 46 | } 47 | 48 | // Handle the event of a user entering a number in the box for excluded paragraphs. 49 | onParagraphNumeralEntered(message: number): void { 50 | this.excludedParagraph = message; 51 | } 52 | 53 | replace(): void { 54 | this.wordDocument.replaceFoundStringsWithExceptions(this.searchString, this.replaceString, this.excludedParagraph); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/services/word-document/word.document.service.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"word.document.service.js","sourceRoot":"","sources":["word.document.service.ts"],"names":[],"mappings":";AAAA,kHAAkH;;;;;;;;;AAElH;;EAEE;AAEF,sCAA2C;AAK3C;IAAA;IAiGA,CAAC;IA/FG,aAAa;IACb,2FAA2F;IAC3F,cAAc;IACd,+DAAiC,GAAjC,UAAkC,YAAoB,EAAE,aAAqB,EAAE,iBAAyB;QAEpG,uDAAuD;QACvD,IAAI,CAAC,GAAG,CAAC,UAAU,OAAO;YAEtB,kGAAkG;YAClG,yGAAyG;YACzG,iDAAiD;YACjD,IAAI,UAAU,GAAyB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YAC/J,IAAI,KAAK,GAA8B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YAEzG,qHAAqH;YACrH,OAAO,OAAO,CAAC,IAAI,EAAE;iBAEpB,IAAI,CAAC;gBAEF,yDAAyD;gBACzD,IAAI,cAAc,GAAsB,EAAE,CAAC;gBAC3C,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBAEtE,IAAI,qBAAqB,GAAkC,EAAE,CAAC;gBAE9D,4EAA4E;gBAC5E,sBAAsB;gBACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;oBAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;wBAC5C,qBAAqB,CAAC,IAAI,CAAC;4BACvB,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;4BAC1B,gBAAgB,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;yBAC/E,CAAC,CAAC;qBACN;iBACJ;gBACD,qHAAqH;gBACrH,OAAO,OAAO,CAAC,IAAI,EAAE;qBAEpB,IAAI,CAAC;oBAEF,kFAAkF;oBAClF,qDAAqD;oBACrD,qBAAqB,CAAC,OAAO,CAAC,UAAU,IAAI;wBAExC,QAAQ,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;4BACjC,KAAK,QAAQ,CAAC;4BACd,KAAK,OAAO;gCACR,MAAM;4BACV;gCACI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;yBACvD;oBACL,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;QACP,CAAC,CAAC;aACD,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9B,CAAC;IAGD,aAAa;IACb,2EAA2E;IAC3E,cAAc;IACd,oDAAsB,GAAtB,UAAuB,UAAyB;QAE5C,uDAAuD;QACvD,IAAI,CAAC,GAAG,CAAC,UAAU,OAAO;YAEtB,+CAA+C;YAC/C,IAAI,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YAEjC,sDAAsD;YACtD,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,wEAAwE;YACxE,4EAA4E;YAC5E,8BAA8B;YAC9B,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAEtC,0CAA0C;YAC1C,KAAK,IAAI,CAAC,GAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACrC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aAC/C;YAED,qHAAqH;YACrH,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC,CAAC;aACD,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9B,CAAC;IAED,0CAAY,GAAZ,UAAa,KAAU;QACnB,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK,YAAY,eAAe,CAAC,KAAK,EAAE;YACxC,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;SACjE;IACL,CAAC;IAhGQ,mBAAmB;QAD/B,iBAAU,EAAE;OACA,mBAAmB,CAiG/B;IAAD,0BAAC;CAAA,AAjGD,IAiGC;AAjGY,kDAAmB"} -------------------------------------------------------------------------------- /app/shared/brand-footer/brand.footer.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for branded footer. 5 | */ 6 | 7 | .ms-landing-page { 8 | display: -webkit-flex; 9 | display: flex; 10 | -webkit-flex-direction: column; 11 | flex-direction: column; 12 | -webkit-flex-wrap: nowrap; 13 | flex-wrap: nowrap; 14 | height: 100%; } 15 | 16 | .ms-landing-page__footer { 17 | display: -webkit-inline-flex; 18 | display: inline-flex; 19 | -webkit-justify-content: center; 20 | justify-content: center; 21 | -webkit-align-items: center; 22 | align-items: center; 23 | position: absolute; 24 | bottom: 0;} 25 | 26 | .ms-landing-page__footer--left { 27 | transition: background ease 0.1s, color ease 0.1s; 28 | display: -webkit-inline-flex; 29 | display: inline-flex; 30 | -webkit-justify-content: flex-start; 31 | justify-content: flex-start; 32 | -webkit-align-items: center; 33 | align-items: center; 34 | -webkit-flex: 1 0 0px; 35 | flex: 1 0 0px; 36 | padding: 20px; } 37 | 38 | .ms-landing-page__footer--left:active, .ms-landing-page__footer--left:hover { 39 | background: #005ca4; 40 | cursor: pointer; } 41 | 42 | .ms-landing-page__footer--left:active { 43 | background: #005ca4; } 44 | 45 | .ms-landing-page__footer--left--disabled { 46 | opacity: 0.6; 47 | pointer-events: none; 48 | cursor: not-allowed; } 49 | 50 | .ms-landing-page__footer--left--disabled:active, .ms-landing-page__footer--left--disabled:hover { 51 | background: transparent; } 52 | 53 | .ms-landing-page__footer--left img { 54 | width: 40px; 55 | height: 40px; } 56 | 57 | .ms-landing-page__footer--left h1 { 58 | -webkit-flex: 1 0 0px; 59 | flex: 1 0 0px; 60 | margin-left: 15px; 61 | text-align: left; 62 | width: auto; 63 | max-width: auto; 64 | overflow: hidden; 65 | white-space: nowrap; 66 | text-overflow: ellipsis; } 67 | 68 | .ms-landing-page__footer--right { 69 | transition: background ease 0.1s, color ease 0.1s; 70 | padding: 29px 20px; } 71 | 72 | .ms-landing-page__footer--right:active, .ms-landing-page__footer--right:hover { 73 | background: #005ca4; 74 | cursor: pointer; } 75 | 76 | .ms-landing-page__footer--right:active { 77 | background: #005ca4; } 78 | 79 | .ms-landing-page__footer--right--disabled { 80 | opacity: 0.6; 81 | pointer-events: none; 82 | cursor: not-allowed; } 83 | 84 | .ms-landing-page__footer--right--disabled:active, .ms-landing-page__footer--right--disabled:hover { 85 | background: transparent; } 86 | 87 | -------------------------------------------------------------------------------- /app/instructions/instruction-steps.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.InstructionStepsComponent = void 0; 14 | /* 15 | This file defines an instructions component for a task pane page. It is based on 16 | the instruction-step sample, created by the Modern Assistance Experience Developer 17 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 18 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 19 | */ 20 | var core_1 = require("@angular/core"); 21 | var router_1 = require("@angular/router"); 22 | var InstructionStepsComponent = /** @class */ (function () { 23 | function InstructionStepsComponent(router) { 24 | this.router = router; 25 | this.title = "WELCOME"; 26 | this.addin_description = "Style Checker enables you to enforce style rules while exempting paragraphs that you specify from the rules."; 27 | this.steps_intro = "Just take these steps:"; 28 | this.steps = [{ step_number: 1, content: "Enter a string in the Find box." }, 29 | { step_number: 2, content: "Enter a replacement string in the Replace With box." }, 30 | { step_number: 3, content: "Enter the zero-based numbers of the parapgraphs that should be exempt in the Skip Paragraphs box." }, 31 | { step_number: 4, content: "Press Replace." }]; 32 | } 33 | InstructionStepsComponent = __decorate([ 34 | core_1.Component({ 35 | templateUrl: 'app/instructions/instruction-steps.component.html', 36 | styleUrls: ['app/instructions/instruction-steps.component.css'] 37 | }), 38 | __metadata("design:paramtypes", [router_1.Router]) 39 | ], InstructionStepsComponent); 40 | return InstructionStepsComponent; 41 | }()); 42 | exports.InstructionStepsComponent = InstructionStepsComponent; 43 | //# sourceMappingURL=instruction-steps.component.js.map -------------------------------------------------------------------------------- /app/app-routing.module.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.AppRoutingModule = void 0; 11 | /* 12 | This file defines the routes of the application. 13 | */ 14 | var core_1 = require("@angular/core"); 15 | var router_1 = require("@angular/router"); 16 | var find_and_replace_component_1 = require("./find-and-replace/find-and-replace.component"); 17 | var instruction_steps_component_1 = require("./instructions/instruction-steps.component"); 18 | var settings_component_1 = require("./settings/settings.component"); 19 | function fetchInstructionSetting() { 20 | return window.localStorage.getItem("StyleCheckerAddinShowInstructions"); 21 | } 22 | function setRoutesArray() { 23 | var routesArray = [ 24 | { path: 'instruction-steps', component: instruction_steps_component_1.InstructionStepsComponent }, 25 | { path: 'settings', component: settings_component_1.SettingsComponent }, 26 | { path: 'find-and-replace', component: find_and_replace_component_1.FindAndReplaceComponent } 27 | ]; 28 | var defaultRoute = { path: '', redirectTo: '/instruction-steps', pathMatch: 'full' }; 29 | // If a user has set the application to skip the instruction view, 30 | // then set the default route to the search and replace view. 31 | if (fetchInstructionSetting() === "OnlyFirstTime") { 32 | defaultRoute = { path: '', redirectTo: '/find-and-replace', pathMatch: 'full' }; 33 | } 34 | routesArray.unshift(defaultRoute); 35 | return routesArray; 36 | } 37 | var routes = setRoutesArray(); 38 | var AppRoutingModule = /** @class */ (function () { 39 | function AppRoutingModule() { 40 | } 41 | AppRoutingModule = __decorate([ 42 | core_1.NgModule({ 43 | imports: [router_1.RouterModule.forRoot(routes, 44 | // Use hash location strategy in an Office Add-in 45 | { useHash: true })], 46 | exports: [router_1.RouterModule] 47 | }) 48 | ], AppRoutingModule); 49 | return AppRoutingModule; 50 | }()); 51 | exports.AppRoutingModule = AppRoutingModule; 52 | //# sourceMappingURL=app-routing.module.js.map -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | 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/). 6 | 7 | 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. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | 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). 14 | 15 | 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). 16 | 17 | 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). 18 | 19 | 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: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | 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. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/instructions/instruction-steps.component.css: -------------------------------------------------------------------------------- 1 | /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ 2 | 3 | /* 4 | This file provides the styles for the instructions view. 5 | */ 6 | 7 | .ms-firstrun-instructionstep { 8 | display: -webkit-flex; 9 | display: flex; 10 | -webkit-flex-direction: column; 11 | flex-direction: column; 12 | -webkit-flex-wrap: nowrap; 13 | flex-wrap: nowrap; 14 | height: 100%; 15 | min-height: 600px; } 16 | 17 | .ms-firstrun-instructionstep__header { 18 | padding: 20px; 19 | min-height: 20px; 20 | display: -webkit-flex; 21 | display: flex; 22 | -webkit-flex-direction: column; 23 | flex-direction: column; 24 | -webkit-flex-wrap: nowrap; 25 | flex-wrap: nowrap; } 26 | 27 | .ms-firstrun-instructionstep__header h1 { 28 | letter-spacing: 5px; } 29 | 30 | .ms-firstrun-instructionstep__header p { 31 | margin-top: 15px; } 32 | 33 | .ms-firstrun-instructionstep__header--image { 34 | background: transparent no-repeat center center; 35 | background-image: url("./app/assets/images/blue-pencil-logo.png"); 36 | background-size: cover; 37 | margin-top: 15px; 38 | display: -webkit-flex; 39 | display: flex; 40 | -webkit-flex-direction: column; 41 | flex-direction: column; 42 | -webkit-flex-wrap: nowrap; 43 | flex-wrap: nowrap; 44 | -webkit-justify-content: stretch; 45 | justify-content: stretch; 46 | -webkit-align-items: stretch; 47 | align-items: stretch; 48 | -webkit-flex: 0 1 0; 49 | flex: 0 1 0; 50 | min-height: 180px; 51 | max-width: 200px;} 52 | 53 | .ms-firstrun-instructionstep__welcome-body { 54 | padding-left: 20px; } 55 | 56 | .ms-firstrun-instructionstep__welcome-intro { 57 | padding-top: 6px; 58 | padding-bottom: 20px; } 59 | .ms-firstrun-instructionstep__list { 60 | list-style-type: none; } 61 | 62 | .ms-firstrun-instructionstep__list.ms-List .ms-ListItem { 63 | padding: 0; 64 | margin: 0; 65 | margin-bottom: 20px; } 66 | 67 | .ms-firstrun-instructionstep__list.ms-List .ms-ListItem-primaryText { 68 | color: #0077d6; 69 | background-color: #c6dff3; 70 | border-radius: 100%; 71 | font-size: 12pt; 72 | width: 30px; 73 | height: 30px; 74 | line-height: 30px; 75 | padding: 0; 76 | text-align: center; 77 | position: absolute;} 78 | 79 | .ms-firstrun-instructionstep__list.ms-List .ms-ListItem-secondaryText { 80 | color: #333333; 81 | margin-bottom: 10px; 82 | position: inherit; 83 | top: 0; 84 | /* override fabric positioning */ 85 | padding-left: 40px; 86 | /* Offset by 30px + 10px so that large bullets are aligned properly. */ 87 | white-space: normal; 88 | overflow: auto; 89 | line-height: normal; } 90 | 91 | .ms-firstrun-instructionstep__list li { 92 | margin-bottom: 20px; } 93 | 94 | .ms-firstrun-instructionstep__list li i { 95 | position: relative; 96 | top: 2px; 97 | margin-right: 10px; } 98 | -------------------------------------------------------------------------------- /app/settings/settings.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.SettingsComponent = void 0; 14 | /* 15 | This file defines a settings view. It is based on 16 | the settings sample, created by the Modern Assistance Experience Developer 17 | Docs team. Along with other samples, it is in the Office-Add-in-UX-Design-Patterns-Code 18 | repo: https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code 19 | */ 20 | var core_1 = require("@angular/core"); 21 | // The SettingsStorageService provides CRUD operations on application settings. 22 | var settings_storage_service_1 = require("../services/settings-storage/settings.storage.service"); 23 | var SettingsComponent = /** @class */ (function () { 24 | function SettingsComponent(settingsStorage) { 25 | this.settingsStorage = settingsStorage; 26 | } 27 | SettingsComponent.prototype.ngAfterViewInit = function () { 28 | var currentInstructionSetting = this.settingsStorage.fetch("StyleCheckerAddinShowInstructions"); 29 | // Ensure that when the settings view loads, the radio button selection matches 30 | // the user's current setting. 31 | if (currentInstructionSetting === "OnlyFirstTime") { 32 | this.alwaysRadioButton.nativeElement.removeAttribute("checked"); 33 | this.onlyFirstTimeRadioButton.nativeElement.setAttribute("checked", "checked"); 34 | } 35 | }; 36 | SettingsComponent.prototype.onRadioButtonSelected = function (specificSetting, value) { 37 | this.settingsStorage.store(specificSetting, value); 38 | }; 39 | __decorate([ 40 | core_1.ViewChild('always'), 41 | __metadata("design:type", core_1.ElementRef) 42 | ], SettingsComponent.prototype, "alwaysRadioButton", void 0); 43 | __decorate([ 44 | core_1.ViewChild('onlyFirstTime'), 45 | __metadata("design:type", core_1.ElementRef) 46 | ], SettingsComponent.prototype, "onlyFirstTimeRadioButton", void 0); 47 | SettingsComponent = __decorate([ 48 | core_1.Component({ 49 | templateUrl: 'app/settings/settings.component.html', 50 | styleUrls: ['app/settings/settings.component.css'] 51 | }), 52 | __metadata("design:paramtypes", [settings_storage_service_1.SettingsStorageService]) 53 | ], SettingsComponent); 54 | return SettingsComponent; 55 | }()); 56 | exports.SettingsComponent = SettingsComponent; 57 | //# sourceMappingURL=settings.component.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/TextField.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information. 2 | 3 | "use strict"; 4 | 5 | // Modification to default file: Remove the wrapping namespace when you use the 6 | // file in an Angular 2 application. It is not needed and namespaces don't play 7 | // well with modules in Angular 2. 8 | 9 | //namespace fabric { 10 | 11 | module TextFieldConsts { 12 | export enum Type { 13 | Placeholder, 14 | Underlined 15 | } 16 | } 17 | 18 | 19 | /** 20 | * Text Field Plugin 21 | * 22 | * Adds basic demonstration functionality to .ms-TextField components. 23 | */ 24 | export class TextField { 25 | 26 | private _container: HTMLElement; 27 | public _textField: HTMLInputElement; 28 | private _textFieldLabel: HTMLElement; 29 | private _type: TextFieldConsts.Type[]; 30 | 31 | /** 32 | * 33 | * @param {HTMLDivElement} container - the target container for an instance of TextField 34 | * @constructor 35 | */ 36 | constructor(container: HTMLElement) { 37 | this._container = container; 38 | this._type = []; 39 | this._textField = this._container.querySelector(".ms-TextField-field"); 40 | this._textFieldLabel = this._container.querySelector(".ms-Label"); 41 | this._setTextFieldType(); 42 | this._addListeners(); 43 | } 44 | 45 | /** Populate _type with various kinds of text fields */ 46 | private _setTextFieldType(): void { 47 | if (this._container.classList.contains("ms-TextField--placeholder")) { 48 | this._type.push(TextFieldConsts.Type.Placeholder); 49 | } 50 | if (this._container.classList.contains("ms-TextField--underlined")) { 51 | this._type.push(TextFieldConsts.Type.Underlined); 52 | } 53 | } 54 | 55 | /** Add event listeners according to the type(s) of text field */ 56 | private _addListeners(): void { 57 | 58 | /** Placeholder - hide/unhide the placeholder */ 59 | if (this._type.indexOf(TextFieldConsts.Type.Placeholder) >= 0) { 60 | this._textField.addEventListener("focus", (event: MouseEvent) => { 61 | this._textFieldLabel.style.display = "none"; 62 | }); 63 | // Modify default Fabric code to ensure that the text box gets focus when the 64 | // the placeholder text itself is clicked. 65 | this._textFieldLabel.addEventListener("click", (event: MouseEvent) => { 66 | this._textField.focus(); 67 | }); 68 | this._textField.addEventListener("blur", (event: MouseEvent) => { 69 | // Show only if no value in the text field 70 | if (this._textField.value.length === 0) { 71 | this._textFieldLabel.style.display = "block"; 72 | } 73 | }); 74 | } 75 | /** Underlined - adding/removing a focus class */ 76 | if (this._type.indexOf(TextFieldConsts.Type.Underlined) >= 0) { 77 | this._textField.addEventListener("focus", (event: MouseEvent) => { 78 | this._container.classList.add("is-active"); 79 | }); 80 | this._textField.addEventListener("blur", (event: MouseEvent) => { 81 | this._container.classList.remove("is-active"); 82 | }); 83 | } 84 | } 85 | } 86 | //} 87 | -------------------------------------------------------------------------------- /app/find-and-replace/find-and-replace.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.FindAndReplaceComponent = void 0; 14 | /* 15 | This file defines a component that enables a search-and-replace functionality for 16 | the Word document. 17 | */ 18 | var core_1 = require("@angular/core"); 19 | var router_1 = require("@angular/router"); 20 | // The WordDocumentService provides methods for manipulating the document. 21 | var word_document_service_1 = require("../services/word-document/word.document.service"); 22 | // The SettingsStorageService provides CRUD operations on application settings.. 23 | var settings_storage_service_1 = require("../services/settings-storage/settings.storage.service"); 24 | var FindAndReplaceComponent = /** @class */ (function () { 25 | function FindAndReplaceComponent(wordDocument, settingsStorage, router) { 26 | this.wordDocument = wordDocument; 27 | this.settingsStorage = settingsStorage; 28 | this.router = router; 29 | } 30 | // Handle the event of a user entering text in the search box. 31 | FindAndReplaceComponent.prototype.onSearchTextEntered = function (message) { 32 | this.searchString = message; 33 | }; 34 | // Handle the event of a user entering text in the replace box. 35 | FindAndReplaceComponent.prototype.onReplaceTextEntered = function (message) { 36 | this.replaceString = message; 37 | }; 38 | // Handle the event of a user entering a number in the box for excluded paragraphs. 39 | FindAndReplaceComponent.prototype.onParagraphNumeralEntered = function (message) { 40 | this.excludedParagraph = message; 41 | }; 42 | FindAndReplaceComponent.prototype.replace = function () { 43 | this.wordDocument.replaceFoundStringsWithExceptions(this.searchString, this.replaceString, this.excludedParagraph); 44 | }; 45 | FindAndReplaceComponent = __decorate([ 46 | core_1.Component({ 47 | templateUrl: 'app/find-and-replace/find-and-replace.component.html', 48 | styleUrls: ['app/find-and-replace/find-and-replace.component.css'], 49 | }), 50 | __metadata("design:paramtypes", [word_document_service_1.WordDocumentService, 51 | settings_storage_service_1.SettingsStorageService, 52 | router_1.Router]) 53 | ], FindAndReplaceComponent); 54 | return FindAndReplaceComponent; 55 | }()); 56 | exports.FindAndReplaceComponent = FindAndReplaceComponent; 57 | //# sourceMappingURL=find-and-replace.component.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.FabricContextualMenuWrapperComponent = void 0; 14 | /* 15 | The file defines an Angular 2 component to wrap the Fabric ContextualMenu component. 16 | */ 17 | var core_1 = require("@angular/core"); 18 | var router_1 = require("@angular/router"); 19 | // The WordDocumentService provides methods for manipulating the document. 20 | var word_document_service_1 = require("../../services/word-document/word.document.service"); 21 | var FabricContextualMenuWrapperComponent = /** @class */ (function () { 22 | function FabricContextualMenuWrapperComponent(wordDocument, router, element) { 23 | this.wordDocument = wordDocument; 24 | this.router = router; 25 | this.element = element; 26 | } 27 | FabricContextualMenuWrapperComponent.prototype.insertSampleContent = function () { 28 | this.wordDocument.replaceDocumentContent([ 29 | "Office Add-ins", 30 | "An OAI executes in an Office application and can interact with data in a document or mail item. As one observer said:", 31 | "\t\"The new OAI model is the cat's meow.\"", 32 | "An OAI is a web app that you can host anywhere. It runs in an Office application. A manifest.xml file specifies where the web app is located and how it should appear.", 33 | "You can find an OAI sample or two (or many) in the OfficeDev organization on GitHub." 34 | ]); 35 | this.closeMenu(); 36 | }; 37 | FabricContextualMenuWrapperComponent.prototype.closeMenu = function () { 38 | var menuElement = this.element.nativeElement // = this 39 | .children[0]; // =
          40 | menuElement.classList.remove("is-open"); 41 | }; 42 | FabricContextualMenuWrapperComponent = __decorate([ 43 | core_1.Component({ 44 | selector: 'of-contextual-menu', 45 | templateUrl: 'app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.html', 46 | styleUrls: ['app/shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component.css'] 47 | }), 48 | __metadata("design:paramtypes", [word_document_service_1.WordDocumentService, 49 | router_1.Router, 50 | core_1.ElementRef]) 51 | ], FabricContextualMenuWrapperComponent); 52 | return FabricContextualMenuWrapperComponent; 53 | }()); 54 | exports.FabricContextualMenuWrapperComponent = FabricContextualMenuWrapperComponent; 55 | //# sourceMappingURL=fabric.contextual.menu.wrapper.component.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | var __metadata = (this && this.__metadata) || function (k, v) { 10 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | exports.FabricTextFieldWrapperComponent = void 0; 14 | /* 15 | The file defines an Angular 2 component to wrap the Fabric TextField component. 16 | */ 17 | var core_1 = require("@angular/core"); 18 | // Import the default Fabric implementation of TextField 19 | var TextField_1 = require("./TextField"); 20 | var FabricTextFieldWrapperComponent = /** @class */ (function () { 21 | function FabricTextFieldWrapperComponent(element) { 22 | this.element = element; 23 | this.value = ""; 24 | // Create an event to run when the user enters text in the text field. 25 | this.textEntered = new core_1.EventEmitter(); 26 | } 27 | // After the textfield has fully rendered, create a Fabric TextField object for it. 28 | FabricTextFieldWrapperComponent.prototype.ngAfterViewInit = function () { 29 | var componentElement = this.element.nativeElement.children[0]; 30 | this.field = new TextField_1.TextField(componentElement); 31 | }; 32 | // When the user changes the text field's contents, pull the new value up from the 33 | // Fabric component to the Angular 2 component, and tell the parent view about 34 | // the event. 35 | FabricTextFieldWrapperComponent.prototype.onValueChanged = function () { 36 | this.value = this.field._textField.value; 37 | this.textEntered.emit(this.value); 38 | }; 39 | __decorate([ 40 | core_1.Input(), 41 | __metadata("design:type", String) 42 | ], FabricTextFieldWrapperComponent.prototype, "innerlabel", void 0); 43 | __decorate([ 44 | core_1.Input(), 45 | __metadata("design:type", String) 46 | ], FabricTextFieldWrapperComponent.prototype, "id", void 0); 47 | __decorate([ 48 | core_1.Input(), 49 | __metadata("design:type", String) 50 | ], FabricTextFieldWrapperComponent.prototype, "value", void 0); 51 | __decorate([ 52 | core_1.Output(), 53 | __metadata("design:type", core_1.EventEmitter) 54 | ], FabricTextFieldWrapperComponent.prototype, "textEntered", void 0); 55 | FabricTextFieldWrapperComponent = __decorate([ 56 | core_1.Component({ 57 | selector: 'of-textfield', 58 | templateUrl: 'app/shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component.html', 59 | }), 60 | __metadata("design:paramtypes", [core_1.ElementRef]) 61 | ], FabricTextFieldWrapperComponent); 62 | return FabricTextFieldWrapperComponent; 63 | }()); 64 | exports.FabricTextFieldWrapperComponent = FabricTextFieldWrapperComponent; 65 | //# sourceMappingURL=fabric.textfield.wrapper.component.js.map -------------------------------------------------------------------------------- /app/shared/office-fabric-component-wrappers/TextField.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information. 2 | "use strict"; 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | exports.TextField = void 0; 5 | // Modification to default file: Remove the wrapping namespace when you use the 6 | // file in an Angular 2 application. It is not needed and namespaces don't play 7 | // well with modules in Angular 2. 8 | //namespace fabric { 9 | var TextFieldConsts; 10 | (function (TextFieldConsts) { 11 | var Type; 12 | (function (Type) { 13 | Type[Type["Placeholder"] = 0] = "Placeholder"; 14 | Type[Type["Underlined"] = 1] = "Underlined"; 15 | })(Type = TextFieldConsts.Type || (TextFieldConsts.Type = {})); 16 | })(TextFieldConsts || (TextFieldConsts = {})); 17 | /** 18 | * Text Field Plugin 19 | * 20 | * Adds basic demonstration functionality to .ms-TextField components. 21 | */ 22 | var TextField = /** @class */ (function () { 23 | /** 24 | * 25 | * @param {HTMLDivElement} container - the target container for an instance of TextField 26 | * @constructor 27 | */ 28 | function TextField(container) { 29 | this._container = container; 30 | this._type = []; 31 | this._textField = this._container.querySelector(".ms-TextField-field"); 32 | this._textFieldLabel = this._container.querySelector(".ms-Label"); 33 | this._setTextFieldType(); 34 | this._addListeners(); 35 | } 36 | /** Populate _type with various kinds of text fields */ 37 | TextField.prototype._setTextFieldType = function () { 38 | if (this._container.classList.contains("ms-TextField--placeholder")) { 39 | this._type.push(TextFieldConsts.Type.Placeholder); 40 | } 41 | if (this._container.classList.contains("ms-TextField--underlined")) { 42 | this._type.push(TextFieldConsts.Type.Underlined); 43 | } 44 | }; 45 | /** Add event listeners according to the type(s) of text field */ 46 | TextField.prototype._addListeners = function () { 47 | var _this = this; 48 | /** Placeholder - hide/unhide the placeholder */ 49 | if (this._type.indexOf(TextFieldConsts.Type.Placeholder) >= 0) { 50 | this._textField.addEventListener("focus", function (event) { 51 | _this._textFieldLabel.style.display = "none"; 52 | }); 53 | // Modify default Fabric code to ensure that the text box gets focus when the 54 | // the placeholder text itself is clicked. 55 | this._textFieldLabel.addEventListener("click", function (event) { 56 | _this._textField.focus(); 57 | }); 58 | this._textField.addEventListener("blur", function (event) { 59 | // Show only if no value in the text field 60 | if (_this._textField.value.length === 0) { 61 | _this._textFieldLabel.style.display = "block"; 62 | } 63 | }); 64 | } 65 | /** Underlined - adding/removing a focus class */ 66 | if (this._type.indexOf(TextFieldConsts.Type.Underlined) >= 0) { 67 | this._textField.addEventListener("focus", function (event) { 68 | _this._container.classList.add("is-active"); 69 | }); 70 | this._textField.addEventListener("blur", function (event) { 71 | _this._container.classList.remove("is-active"); 72 | }); 73 | } 74 | }; 75 | return TextField; 76 | }()); 77 | exports.TextField = TextField; 78 | //# sourceMappingURL=TextField.js.map -------------------------------------------------------------------------------- /app/app.module.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.AppModule = void 0; 11 | /* 12 | This file brings together all of the required modules and components and identifies 13 | the component to be bootstrapped. 14 | */ 15 | var core_1 = require("@angular/core"); 16 | var platform_browser_1 = require("@angular/platform-browser"); 17 | var app_routing_module_1 = require("./app-routing.module"); 18 | // Import all the custom components. 19 | var app_component_1 = require("./app.component"); 20 | var find_and_replace_component_1 = require("./find-and-replace/find-and-replace.component"); 21 | var instruction_steps_component_1 = require("./instructions/instruction-steps.component"); 22 | var settings_component_1 = require("./settings/settings.component"); 23 | var button_component_1 = require("./shared/button/button.component"); 24 | var navigation_header_component_1 = require("./shared/navigation-header/navigation.header.component"); 25 | var brand_footer_component_1 = require("./shared/brand-footer/brand.footer.component"); 26 | var contextual_menu_button_component_1 = require("./shared/contextual-menu-button/contextual.menu.button.component"); 27 | var fabric_contextual_menu_wrapper_component_1 = require("./shared/office-fabric-component-wrappers/fabric.contextual.menu.wrapper.component"); 28 | var fabric_textfield_wrapper_component_1 = require("./shared/office-fabric-component-wrappers/fabric.textfield.wrapper.component"); 29 | // The WordDocumentService provides methods for manipulating the document. 30 | var word_document_service_1 = require("./services/word-document/word.document.service"); 31 | // The SettingsStorageService provides CRUD operations on application settings. 32 | var settings_storage_service_1 = require("./services/settings-storage/settings.storage.service"); 33 | var AppModule = /** @class */ (function () { 34 | function AppModule() { 35 | } 36 | AppModule = __decorate([ 37 | core_1.NgModule({ 38 | imports: [ 39 | platform_browser_1.BrowserModule, 40 | app_routing_module_1.AppRoutingModule 41 | ], 42 | declarations: [ 43 | app_component_1.AppComponent, 44 | find_and_replace_component_1.FindAndReplaceComponent, 45 | instruction_steps_component_1.InstructionStepsComponent, 46 | settings_component_1.SettingsComponent, 47 | button_component_1.ButtonComponent, 48 | navigation_header_component_1.NavigationHeaderComponent, 49 | brand_footer_component_1.BrandFooterComponent, 50 | contextual_menu_button_component_1.ContextualMenuButtonComponent, 51 | fabric_contextual_menu_wrapper_component_1.FabricContextualMenuWrapperComponent, 52 | fabric_textfield_wrapper_component_1.FabricTextFieldWrapperComponent 53 | ], 54 | providers: [ 55 | word_document_service_1.WordDocumentService, 56 | settings_storage_service_1.SettingsStorageService 57 | ], 58 | bootstrap: [app_component_1.AppComponent] 59 | }) 60 | ], AppModule); 61 | return AppModule; 62 | }()); 63 | exports.AppModule = AppModule; 64 | //# sourceMappingURL=app.module.js.map -------------------------------------------------------------------------------- /app/services/word-document/word.document.service.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 2 | 3 | /* 4 | This file defines a service for manipulating the Word document. 5 | */ 6 | 7 | import { Injectable } from '@angular/core'; 8 | import { IReplacementCandidate } from './IReplacementCandidate'; 9 | 10 | 11 | @Injectable() 12 | export class WordDocumentService { 13 | 14 | /// 15 | /// Performs a search and replace, but makes no changes to text in the excluded paragraphs. 16 | /// 17 | replaceFoundStringsWithExceptions(searchString: string, replaceString: string, excludedParagraph: number) { 18 | 19 | // Run a batch operation against the Word object model. 20 | Word.run(function (context) { 21 | 22 | // Find and load all ranges that match the search string, and then all paragraphs in the document. 23 | // Only the 'items' property of each is needed, no properties on the items are needed, so add any string 24 | // after the 'items/' part of the load parameter. 25 | let foundItems: Word.RangeCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load('items/NoPropertiesNeeded'); 26 | let paras : Word.ParagraphCollection = context.document.body.paragraphs.load('items/NoPropertiesNeeded'); 27 | 28 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 29 | return context.sync() 30 | 31 | .then(function () { 32 | 33 | // Create an array of paragraphs that have been excluded. 34 | let excludedRanges: Array = []; 35 | excludedRanges.push(paras.items[excludedParagraph].getRange('Whole')); 36 | 37 | let replacementCandidates : Array = []; 38 | 39 | // For each instance of the search string, record whether or not it is in an 40 | // excluded paragraph. 41 | for (let i = 0; i < foundItems.items.length; i++) { 42 | for (let j = 0; j < excludedRanges.length; j++) { 43 | replacementCandidates.push({ 44 | range: foundItems.items[i], 45 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 46 | }); 47 | } 48 | } 49 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 50 | return context.sync() 51 | 52 | .then(function () { 53 | 54 | // Replace instances of the search string with the replace string only if they are 55 | // not inside of (or identical to) an excluded range. 56 | replacementCandidates.forEach(function (item) { 57 | 58 | switch (item.locationRelation.value) { 59 | case "Inside": 60 | case "Equal": 61 | break; 62 | default: 63 | item.range.insertText(replaceString, 'Replace'); 64 | } 65 | }); 66 | }); 67 | }); 68 | }) 69 | .catch(this.errorHandler); 70 | } 71 | 72 | 73 | /// 74 | /// Inserts sample content for testing the find-and-replace functionality.. 75 | /// 76 | replaceDocumentContent(paragraphs: Array) { 77 | 78 | // Run a batch operation against the Word object model. 79 | Word.run(function (context) { 80 | 81 | // Create a proxy object for the document body. 82 | let body = context.document.body; 83 | 84 | // Queue a commmand to clear the contents of the body. 85 | body.clear(); 86 | 87 | // Queue commands to insert text into the end of the Word document body. 88 | // Use insertText for the first to prevent a line break from being inserted 89 | // at the top of the document. 90 | body.insertText(paragraphs[0], "End"); 91 | 92 | // Use insertParagraph for all the others. 93 | for (let i=1; i < paragraphs.length; i++) { 94 | body.insertParagraph(paragraphs[i], 'End'); 95 | } 96 | 97 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 98 | return context.sync(); 99 | }) 100 | .catch(this.errorHandler); 101 | } 102 | 103 | errorHandler(error: any){ 104 | console.log("Error: " + error); 105 | if (error instanceof OfficeExtension.Error) { 106 | console.log("Debug info: " + JSON.stringify(error.debugInfo)); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /app/services/word-document/word.document.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. 3 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 4 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 5 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 6 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 7 | return c > 3 && r && Object.defineProperty(target, key, r), r; 8 | }; 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | exports.WordDocumentService = void 0; 11 | /* 12 | This file defines a service for manipulating the Word document. 13 | */ 14 | var core_1 = require("@angular/core"); 15 | var WordDocumentService = /** @class */ (function () { 16 | function WordDocumentService() { 17 | } 18 | /// 19 | /// Performs a search and replace, but makes no changes to text in the excluded paragraphs. 20 | /// 21 | WordDocumentService.prototype.replaceFoundStringsWithExceptions = function (searchString, replaceString, excludedParagraph) { 22 | // Run a batch operation against the Word object model. 23 | Word.run(function (context) { 24 | // Find and load all ranges that match the search string, and then all paragraphs in the document. 25 | // Only the 'items' property of each is needed, no properties on the items are needed, so add any string 26 | // after the 'items/' part of the load parameter. 27 | var foundItems = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load('items/NoPropertiesNeeded'); 28 | var paras = context.document.body.paragraphs.load('items/NoPropertiesNeeded'); 29 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 30 | return context.sync() 31 | .then(function () { 32 | // Create an array of paragraphs that have been excluded. 33 | var excludedRanges = []; 34 | excludedRanges.push(paras.items[excludedParagraph].getRange('Whole')); 35 | var replacementCandidates = []; 36 | // For each instance of the search string, record whether or not it is in an 37 | // excluded paragraph. 38 | for (var i = 0; i < foundItems.items.length; i++) { 39 | for (var j = 0; j < excludedRanges.length; j++) { 40 | replacementCandidates.push({ 41 | range: foundItems.items[i], 42 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 43 | }); 44 | } 45 | } 46 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 47 | return context.sync() 48 | .then(function () { 49 | // Replace instances of the search string with the replace string only if they are 50 | // not inside of (or identical to) an excluded range. 51 | replacementCandidates.forEach(function (item) { 52 | switch (item.locationRelation.value) { 53 | case "Inside": 54 | case "Equal": 55 | break; 56 | default: 57 | item.range.insertText(replaceString, 'Replace'); 58 | } 59 | }); 60 | }); 61 | }); 62 | }) 63 | .catch(this.errorHandler); 64 | }; 65 | /// 66 | /// Inserts sample content for testing the find-and-replace functionality.. 67 | /// 68 | WordDocumentService.prototype.replaceDocumentContent = function (paragraphs) { 69 | // Run a batch operation against the Word object model. 70 | Word.run(function (context) { 71 | // Create a proxy object for the document body. 72 | var body = context.document.body; 73 | // Queue a commmand to clear the contents of the body. 74 | body.clear(); 75 | // Queue commands to insert text into the end of the Word document body. 76 | // Use insertText for the first to prevent a line break from being inserted 77 | // at the top of the document. 78 | body.insertText(paragraphs[0], "End"); 79 | // Use insertParagraph for all the others. 80 | for (var i = 1; i < paragraphs.length; i++) { 81 | body.insertParagraph(paragraphs[i], 'End'); 82 | } 83 | // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion. 84 | return context.sync(); 85 | }) 86 | .catch(this.errorHandler); 87 | }; 88 | WordDocumentService.prototype.errorHandler = function (error) { 89 | console.log("Error: " + error); 90 | if (error instanceof OfficeExtension.Error) { 91 | console.log("Debug info: " + JSON.stringify(error.debugInfo)); 92 | } 93 | }; 94 | WordDocumentService = __decorate([ 95 | core_1.Injectable() 96 | ], WordDocumentService); 97 | return WordDocumentService; 98 | }()); 99 | exports.WordDocumentService = WordDocumentService; 100 | //# sourceMappingURL=word.document.service.js.map -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls the Typescript compiler (tsc) and 10 | // Compiles a HelloWorld.ts program 11 | { 12 | "version": "0.1.0", 13 | 14 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 15 | "command": "tsc", 16 | 17 | // The command is a shell script 18 | "isShellCommand": true, 19 | 20 | // Show the output window only if unrecognized errors occur. 21 | "showOutput": "silent", 22 | 23 | // args is the HelloWorld program to compile. 24 | "args": [ ], 25 | 26 | // use the standard tsc problem matcher to find compile problems 27 | // in the output. 28 | "problemMatcher": "$tsc" 29 | } 30 | 31 | // A task runner that calls the Typescript compiler (tsc) and 32 | // compiles based on a tsconfig.json file that is present in 33 | // the root of the folder open in VSCode 34 | /* 35 | { 36 | "version": "0.1.0", 37 | 38 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript 39 | "command": "tsc", 40 | 41 | // The command is a shell script 42 | "isShellCommand": true, 43 | 44 | // Show the output window only if unrecognized errors occur. 45 | "showOutput": "silent", 46 | 47 | // Tell the tsc compiler to use the tsconfig.json from the open folder. 48 | "args": ["-p", "."], 49 | 50 | // use the standard tsc problem matcher to find compile problems 51 | // in the output. 52 | "problemMatcher": "$tsc" 53 | } 54 | */ 55 | 56 | // A task runner configuration for gulp. Gulp provides a less task 57 | // which compiles less to css. 58 | /* 59 | { 60 | "version": "0.1.0", 61 | "command": "gulp", 62 | "isShellCommand": true, 63 | "tasks": [ 64 | { 65 | "taskName": "less", 66 | // Make this the default build command. 67 | "isBuildCommand": true, 68 | // Show the output window only if unrecognized errors occur. 69 | "showOutput": "silent", 70 | // Use the standard less compilation problem matcher. 71 | "problemMatcher": "$lessCompile" 72 | } 73 | ] 74 | } 75 | */ 76 | 77 | // Uncomment the following section to use jake to build a workspace 78 | // cloned from https://github.com/Microsoft/TypeScript.git 79 | /* 80 | { 81 | "version": "0.1.0", 82 | // Task runner is jake 83 | "command": "jake", 84 | // Need to be executed in shell / cmd 85 | "isShellCommand": true, 86 | "showOutput": "silent", 87 | "tasks": [ 88 | { 89 | // TS build command is local. 90 | "taskName": "local", 91 | // Make this the default build command. 92 | "isBuildCommand": true, 93 | // Show the output window only if unrecognized errors occur. 94 | "showOutput": "silent", 95 | // Use the redefined Typescript output problem matcher. 96 | "problemMatcher": [ 97 | "$tsc" 98 | ] 99 | } 100 | ] 101 | } 102 | */ 103 | 104 | // Uncomment the section below to use msbuild and generate problems 105 | // for csc, cpp, tsc and vb. The configuration assumes that msbuild 106 | // is available on the path and a solution file exists in the 107 | // workspace folder root. 108 | /* 109 | { 110 | "version": "0.1.0", 111 | "command": "msbuild", 112 | "args": [ 113 | // Ask msbuild to generate full paths for file names. 114 | "/property:GenerateFullPaths=true" 115 | ], 116 | "taskSelector": "/t:", 117 | "showOutput": "silent", 118 | "tasks": [ 119 | { 120 | "taskName": "build", 121 | // Show the output window only if unrecognized errors occur. 122 | "showOutput": "silent", 123 | // Use the standard MS compiler pattern to detect errors, warnings 124 | // and infos in the output. 125 | "problemMatcher": "$msCompile" 126 | } 127 | ] 128 | } 129 | */ 130 | 131 | // Uncomment the following section to use msbuild which compiles Typescript 132 | // and less files. 133 | /* 134 | { 135 | "version": "0.1.0", 136 | "command": "msbuild", 137 | "args": [ 138 | // Ask msbuild to generate full paths for file names. 139 | "/property:GenerateFullPaths=true" 140 | ], 141 | "taskSelector": "/t:", 142 | "showOutput": "silent", 143 | "tasks": [ 144 | { 145 | "taskName": "build", 146 | // Show the output window only if unrecognized errors occur. 147 | "showOutput": "silent", 148 | // Use the standard MS compiler pattern to detect errors, warnings 149 | // and infos in the output. 150 | "problemMatcher": [ 151 | "$msCompile", 152 | "$lessCompile" 153 | ] 154 | } 155 | ] 156 | } 157 | */ 158 | // A task runner example that defines a problemMatcher inline instead of using 159 | // a predefined one. 160 | /* 161 | { 162 | "version": "0.1.0", 163 | "command": "tsc", 164 | "isShellCommand": true, 165 | "args": ["HelloWorld.ts"], 166 | "showOutput": "silent", 167 | "problemMatcher": { 168 | // The problem is owned by the typescript language service. Ensure that the problems 169 | // are merged with problems produced by Visual Studio's language service. 170 | "owner": "typescript", 171 | // The file name for reported problems is relative to the current working directory. 172 | "fileLocation": ["relative", "${cwd}"], 173 | // The actual pattern to match problems in the output. 174 | "pattern": { 175 | // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. 176 | "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", 177 | // The match group that denotes the file containing the problem. 178 | "file": 1, 179 | // The match group that denotes the problem location. 180 | "location": 2, 181 | // The match group that denotes the problem's severity. Can be omitted. 182 | "severity": 3, 183 | // The match group that denotes the problem code. Can be omitted. 184 | "code": 4, 185 | // The match group that denotes the problem's message. 186 | "message": 5 187 | } 188 | } 189 | } 190 | */ -------------------------------------------------------------------------------- /README-Localized/README-zh-cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | --- 14 | # 在 Angular 2.0 基础之上构建的 Word 样式检查外接程序 15 | 16 | 了解如何创建外接程序以使用 Word JavaScript API 的 `LocationRelation` 和 `compareLocationWith` API 执行搜索和替换,从而根据与其他区域的相对位置跳过某些区域。此外接程序是在 Angular 2.0 框架的基础之上构建而成。它还展示了如何使用 [Office 外接程序的用户体验设计模式代码](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code)中的设计示例。 17 | 18 | ## 目录 19 | * [修订记录](#change-history) 20 | * [先决条件](#prerequisites) 21 | * [配置项目](#configure-the-project) 22 | * [部署外接程序](#deploy-the-add-in) 23 | * [运行项目](#run-the-project) 24 | * [启动外接程序](#start-the-add-in) 25 | * [测试外接程序](#test-the-add-in) 26 | * [更改外接程序的设置](#change-the-settings-of-the-add-in) 27 | * [了解代码](#understand-the-code) 28 | * [问题和意见](#questions-and-comments) 29 | * [其他资源](#additional-resources) 30 | 31 | ## 修订记录 32 | 33 | 2016 年 8 月 1 日: 34 | 35 | * 首版。 36 | 37 | 2016 年 9 月 15 日 - 10 月 17 日: 38 | 39 | * 次要更新。 40 | 41 | ## 先决条件 42 | 43 | * Word 2016 for Windows(内部版本 16.0.6727.1000 或更高版本)。 44 | * [节点和 npm](https://nodejs.org/en/) 将项目配置为使用 npm 作为程序包管理器和任务运行程序。还可以配置为将 npm 内置的 Lite Server 用作在开发期间托管此外接程序的 Web 服务器,以便快速启动并运行此外接程序。完全可以使用其他任务运行程序或 Web 服务器。 45 | * [Git Bash](https://git-scm.com/downloads)(或其他 git 客户端。) 46 | 47 | ## 配置项目 48 | 49 | 在要放置项目的文件夹中,于 git bash shell 中运行以下命令: 50 | 51 | 1. ```git clone {代码库 URL}```:将此代码库复制到你的本地计算机。 52 | 2. ```npm install```:安装 package.json 文件中列出明细的所有依赖项。 53 | 3. ```bash gen-cert.sh```:创建运行此示例所需的证书。 54 | 55 | 将此证书设置为受信任的根证书颁发机构。Windows 计算机上的设置步骤: 56 | 57 | 1. 在本地计算机的代码库文件夹中,双击 ca.crt,然后选择**“安装证书”**。 58 | 2. 选择**“本地计算机”**,然后选择**“下一步”**以继续。 59 | 3. 选择**“将所有证书放入下列存储”**,然后选择**“浏览”**。 60 | 4. 选择**“受信任的根证书颁发机构”**,然后选择**“确定”**。 61 | 5. 依次选择**“下一步”**、**“完成”**。 62 | 63 | ## 部署外接程序 64 | 65 | 现在需要让 Microsoft Word 知道在哪里可以找到外接程序。 66 | 67 | 1. 创建网络共享,或[将文件夹共享到网络](https://technet.microsoft.com/en-us/library/cc770880.aspx)。 68 | 2. 将 Word-Add-in-Angular2-StyleChecker.xml 清单文件从项目的根目录复制到共享文件夹。 69 | 3. 启动 Word,然后打开一个文档。 70 | 4. 选择**“文件”**选项卡,然后选择**“选项”**。 71 | 5. 选择**“信任中心”**,然后选择**“信任中心设置”**按钮。 72 | 6. 选择**“受信任的外接程序目录”**。 73 | 7. 在**“目录 URL”**字段中,输入包含 Word-Add-in-Angular2-StyleChecker.xml 的文件夹共享的网络路径,然后选择**“添加目录”**。 74 | 8. 选中**“显示在菜单中”**复选框,然后选择**“确定”**。 75 | 9. 随后会出现一条消息,告知你下次启动 Microsoft Office 时将应用你的设置。关闭 Word。 76 | 77 | ## 运行项目 78 | 79 | 1. 打开项目文件夹中的节点命令窗口,然后运行 ```npm start``` 来启动 Web 服务。让命令窗口一直处于打开状态。 80 | 2. 打开 Internet Explorer 或 Edge,然后在地址框中输入 ```https://localhost:3000```。如果未收到有关证书的任何警告,则关闭浏览器,然后继续执行下面的**“启动外接程序”**部分。如果看到提示证书不受信任的警告,请继续按以下步骤操作: 81 | 3. 除警告外,浏览器还会提供一个可以打开该页面的链接。打开该页面。 82 | 4. 打开页面后,地址栏中会有一条显示为红色的证书错误消息。双击此错误。 83 | 5. 选择**“查看证书”**.。 84 | 5. 选择**“安装证书”**。 85 | 4. 选择**“本地计算机”**,然后选择**“下一步”**以继续。 86 | 3. 选择**“将所有证书放入下列存储”**,然后选择**“浏览”**。 87 | 4. 选择**“受信任的根证书颁发机构”**,然后选择**“确定”**。 88 | 5. 依次选择**“下一步”**、**“完成”**。 89 | 6. 关闭浏览器。 90 | 91 | ## 启动外接程序 92 | 93 | 1. 重新启动 Word 并打开一个 Word 文档。 94 | 2. 在 Word 2016 中的**“插入”**选项卡上,选择**“我的外接程序”**。 95 | 3. 选择**“共享文件夹”** 选项卡。 96 | 4. 依次选择**“样式检查”**和**“确定”**。 97 | 5. 如果 Word 版本支持外接程序命令,UI 将通知你已加载外接程序。 98 | 6. “主页”功能区上有一个名为**“样式检查”**的新组,其中显示标记为**“显示”**的按钮和一个蓝色铅笔图标。单击此按钮,然后此外接程序便会显示说明页。 99 | 100 | > 注意:如果你的 Word 版本不支持外接程序命令,则外接程序将在任务窗格中加载。 101 | 102 | ## 测试外接程序 103 | 104 | 1. 阅读完说明后,单击**“入门”**。 105 | 2. 当**“查找和替换”**页打开后,顶部会显示带有一个菜单按钮的命令栏。单击此按钮,打开菜单。 106 | 3. 选择**“插入示例内容”**。再次单击此按钮,关闭菜单。此时,文档中包含有关 Office 外接程序的无格式文本,包括虚构的引用。编写器已将“Office 外接程序”缩写为“OAI”,匿名引用中也采用了这样的缩写。 107 | 4. 在**“查找”**框中,输入“OAI”。 108 | 5. 在**“替换”**框中,输入“Office 外接程序”。 109 | 6. ***不***得在直接引用的段落中进行此更改。因此,在**“跳过段落编号”** 框中输入数字 **2**。这是从零开始编号的段落编号。 110 | 7. 选择**“替换”**。此时,系统会更改跳过的段落以外的所有“OAI”实例。 111 | 8. 尝试使用其他搜索和替换字符串。 112 | 113 | > 注意:此示例外接程序仅接受在**“跳过段落编号”** 框中输入一个数字。生产外接程序将允许跳过多个段落,并且可通过其他方法指定要跳过的段落;例如基于段落样式跳过段落。 114 | 115 | ## 更改外接程序的设置 116 | 117 | 1. 再次打开命令栏上的菜单按钮,然后选择**“设置”**。 118 | 2. **“设置”**页上的默认设置为,每次运行此外接程序时说明页都会打开。使用单选按钮指定仅在首次运行此外接程序时显示说明页。 119 | 3. 关闭任务窗格,然后选择**“显示”** 按钮重新启动此外接程序。此外接程序会打开显示**“查找和替换”**页,而不是说明页。 120 | 4. 再次导航到**“设置”**页。你可以选择**“显示说明”**按钮打开说明页,也可以将说明设置恢复为在每次运行此外接程序时打开说明页。 121 | 122 | ## 了解代码 123 | 124 | 所有使用 Office 和 Word JavaScript API 的代码均位于 word.document.service.ts 文件中。此示例阐释的 `compareLocationWith()` 方法位于 `replaceFoundStringsWithExceptions()` 方法中。 125 | 126 | 代码首先会获取与用户搜索词匹配的所有区域的集合。然后,代码会获取文档中所有段落区域的集合。 127 | 128 | ```let foundItems:Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 129 | ```let paras :Word.ParagraphCollection = context.document.body.paragraphs.load();``` 130 | 131 | 通过调用 `context.sync()` 加载集合后,代码会创建用户在替换时排除的段落区域的数组。(请注意,`excludedParagraph` 是传递给该方法的参数。) 132 | 133 | ```let excludedRanges:Array = \[];``` 134 | ```excludedRanges.push(paras.items\[excludedParagraph].getRange('Whole'));``` 135 | 136 | 然后,代码循环访问,以确定哪些搜索结果在已排除的段落中,哪些搜索结果不在。对于每个搜索结果,系统都会将此事实记录在 `IReplacementCandidate` 对象中。如果搜索结果在已排除的段落中,那么 `compareLocationWith()` 方法返回“Inside”。如果搜索结果本身就是段落且已遭排除,那么此方法返回“Equal”。 137 | 138 | ``` 139 | for (let i = 0; i < foundItems.items.length; i++) { 140 | for (let j = 0; j < excludedRanges.length; j++) { 141 | replacementCandidates.push({ 142 | range: foundItems.items[i], 143 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 144 | }); 145 | } 146 | } 147 | ``` 148 | 替换候选对象通过调用 `context.sync()` 加载,然后代码将循环访问这些对象,同时将搜索字符串替换为仅在不是已排除段落的段落中的字符串。 149 | 150 | ``` 151 | replacementCandidates.forEach(function (item) { 152 | switch (item.locationRelation.value) { 153 | case "Inside": 154 | case "Equal": 155 | break; 156 | default: 157 | item.range.insertText(replaceString, 'Replace'); 158 | } 159 | }); 160 | ``` 161 | 请参阅同一文件的 `replaceDocumentContent` 方法,了解如何使用 Word 的 `insertText` 和 `nsertParagraph` 方法将示例内容插入文档。 162 | 163 | 请参阅代码文件的其余部分,了解 [Office 外接程序的用户体验设计模式代码](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code)中的设计模式是如何集成到 Angular 2.0 框架中的。 164 | 165 | ## 问题和意见 166 | 167 | 我们乐意倾听你对此示例的反馈。可以在此存储库中的*“问题”*部分向我们发送反馈。 168 | 169 | 与 Microsoft Office 365 开发相关的一般问题应发布到 [Stack Overflow](http://stackoverflow.com/questions/tagged/office-js+API)。如果你的问题是关于 Office JavaScript API,请务必为问题添加 \[office-js] 和 \[API].标记。 170 | 171 | ## 其他资源 172 | 173 | * [Office 外接程序文档](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 174 | * [Office 开发人员中心](http://dev.office.com/) 175 | * 有关更多 Office 外接程序示例,请访问 [Github 上的 OfficeDev](https://github.com/officedev)。 176 | 177 | ## 版权信息 178 | 版权所有 (c) 2016 Microsoft Corporation。保留所有权利。 179 | 180 | 181 | 182 | 此项目已采用 [Microsoft 开放源代码行为准则](https://opensource.microsoft.com/codeofconduct/)。有关详细信息,请参阅[行为准则 FAQ](https://opensource.microsoft.com/codeofconduct/faq/)。如有其他任何问题或意见,也可联系 [opencode@microsoft.com](mailto:opencode@microsoft.com)。 183 | -------------------------------------------------------------------------------- /README-Localized/README-zh-tw.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | --- 14 | # 內建在 Angular 2.0 上的文字樣式檢查增益集 15 | 16 | 了解如何建立使用 Word JavaScript API 的 `LocationRelation` 和 `compareLocationWith` API 執行搜索及取代的增益集,其根據相對於其他範圍的位置略過某些範圍。該增益集內建於 Angular 2.0 架構,也會顯示如何使用 [Office 增益集 UX 設計模式程式碼](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code)的設計範例。 17 | 18 | ## 目錄 19 | * [變更歷程記錄](#change-history) 20 | * [必要條件](#prerequisites) 21 | * [設定專案](#configure-the-project) 22 | * [部署增益集](#deploy-the-add-in) 23 | * [執行專案](#run-the-project) 24 | * [啟動增益集](#start-the-add-in) 25 | * [測試增益集](#test-the-add-in) 26 | * [變更增益集的設定](#change-the-settings-of-the-add-in) 27 | * [瞭解程式碼](#understand-the-code) 28 | * [問題與意見](#questions-and-comments) 29 | * [其他資源](#additional-resources) 30 | 31 | ## 變更歷程記錄 32 | 33 | 2016 年 8 月 1 日: 34 | 35 | * 初始版本。 36 | 37 | 2016 年 9 月 15 日 - 10 月 17 日: 38 | 39 | * 次要更新。 40 | 41 | ## 必要條件 42 | 43 | * Word 2016 for Windows,組建 16.0.6727.1000 或更新版本。 44 | * [節點和 npm](https://nodejs.org/en/) 專案設定為使用 npm 作為封裝管理員和工作執行器。它也設定為使用內建 npm 的精簡版伺服器作為 Web 伺服器,在開發期間裝載增益集,因此您可以快速地啟動並執行增益集。您也可以自由地使用其他工作執行器或 Web 伺服器。 45 | * [Git Bash](https://git-scm.com/downloads) (或其他 git 用戶端。) 46 | 47 | ## 設定專案 48 | 49 | 在您要放置專案的資料夾中,以 git bash shell 執行下列命令︰ 50 | 51 | 1. ```git clone {此儲存機制的 URL}``` 以複製此儲存機制到本機電腦。 52 | 2. ```npm install``` 以安裝 package.json 檔案中的所有分項相依性。 53 | 3. ```bash gen-cert.sh``` 以建立執行這個範例所需的憑證。 54 | 55 | 將憑證設定為受信任的根授權。在 Windows 電腦上的步驟如下︰ 56 | 57 | 1. 在您本機電腦上的儲存機制資料夾中,連按兩下 ca.crt,然後選取 **\[安裝憑證]**。 58 | 2. 選取 **\[本機電腦]**,然後選取 **\[下一步]** 以繼續。 59 | 3. 選取 **\[將所有憑證放入以下的存放區]**,然後選取 **\[瀏覽]**。 60 | 4. 選取 **\[信任的根憑證授權]**,然後選取 **\[確定]**。 61 | 5. 選取 **\[下一步]**,然後選取 **\[完成]**。 62 | 63 | ## 部署增益集 64 | 65 | 現在,您需要讓 Microsoft Word 知道哪裡可以找到此增益集。 66 | 67 | 1. 建立網路共用,或[在網路上共用資料夾](https://technet.microsoft.com/en-us/library/cc770880.aspx)。 68 | 2. 將一份 Word-Add-in-Angular2-StyleChecker.xml 資訊清單檔,從專案的根目錄放入共用資料夾中。 69 | 3. 啟動 Word 並開啟一個文件。 70 | 4. 選擇 **\[檔案]** 索引標籤,然後選擇 **\[選項]**。 71 | 5. 選擇 **\[信任中心]**,然後選擇 **\[信任中心設定]** 按鈕。 72 | 6. 選擇 **\[受信任的增益集目錄]**。 73 | 7. 在 **\[目錄 URL]** 欄位中,輸入包含 Word-Add-in-Angular2-StyleChecker.xml 的資料夾共用的網路路徑,然後選擇 **\[新增目錄]**。 74 | 8. 選取 **\[顯示於功能表中]** 核取方塊,然後選擇 **\[確定]**。 75 | 9. 接著會顯示訊息,通知您下次啟動 Microsoft Office 時就會套用您的設定。關閉 Word。 76 | 77 | ## 執行專案 78 | 79 | 1. 開啟專案的資料夾中節點的命令視窗,並執行 ```npm start``` 以啟動 Web 服務。保留命令視窗開啟。 80 | 2. 開啟 Internet Explorer 或 Microsoft Edge,並在網址方塊中輸入 ```https://localhost:3000```。如果您未收到與憑證相關的任何警告,請關閉瀏覽器,並繼續進行下面主題為**啟動增益集**的章節。如果您收到憑證不受信任的警告,請繼續執行下列步驟︰ 81 | 3. 儘管有警告,瀏覽器還是可以給予您用以開啟頁面的連結。將其開啟。 82 | 4. 開啟網頁後,在網址列中會有紅色的憑證錯誤訊息。按兩下錯誤。 83 | 5. 選取 **\[檢視憑證]**。 84 | 5. 選取 **\[安裝憑證]**。 85 | 4. 選取 **\[本機電腦]**,然後選取 **\[下一步]** 以繼續。 86 | 3. 選取 **\[將所有憑證放入以下的存放區]**,然後選取 **\[瀏覽]**。 87 | 4. 選取 **\[信任的根憑證授權]**,然後選取 **\[確定]**。 88 | 5. 選取 **\[下一步]**,然後選取 **\[完成]**。 89 | 6. 關閉瀏覽器。 90 | 91 | ## 啟動增益集 92 | 93 | 1. 重新啟動 Word,並開啟 Word 文件。 94 | 2. 在 Word 2016 的 **\[插入]** 索引標籤上,選擇 **\[我的增益集]**。 95 | 3. 選取 **\[共用資料夾]** 索引標籤。 96 | 4. 選擇 **\[樣式檢查]**,然後選取 **\[確定]**。 97 | 5. 如果您的 Word 版本支援增益集命令,UI 會通知您已載入增益集。 98 | 6. 在 \[首頁] 功能區中的是稱為**樣式檢查**的新群組,具有標示為 **\[顯示]** 的按鈕和藍色鉛筆圖示。按一下該按鈕,增益集將會開啟指示網頁。 99 | 100 | > 附註:如果您的 Word 版本不支援增益集命令,增益集會載入工作窗格。 101 | 102 | ## 測試增益集 103 | 104 | 1. 當您完成指示時,請按一下 **\[開始使用]**。 105 | 2. **\[尋找和取代]** 頁面開啟時,頂端會出現命令列 (包含功能表按鈕)。按一下該按鈕以開啟功能表。 106 | 3. 選取 **\[插入範例內容]**。再按一下按鈕以關閉功能表。文件現在有與 Office 增益集有關 (包括虛構的引號) 的未格式化文字。寫入器已使用「OAI」縮寫「Office 增益集 」,匿名的引號也使用相同的縮寫方式。 107 | 4. 在 **\[尋找]** 方塊中輸入「OAI」。 108 | 5. 在 **\[取代]** 方塊中輸入「Office 增益集」。 109 | 6. 變更***不***應該在直接引文的段落中進行變更,因此請在 **\[略過段落]** 方塊中輸入數字 **2**。段落以零為起始數字。 110 | 7. 選取 **\[取代]**。除了略過段落中的一個執行個體之外,每個「OAI」執行個體皆已變更。 111 | 8. 試驗其他搜尋及取代的字串。 112 | 113 | > 注意:此範例增益集僅接受 **\[略過段落]** 方塊中的一個數字。實際執行增益集允許略過多個段落,且有其他方法可指定應略過的段落,例如根據段落樣式來略過。 114 | 115 | ## 變更增益集的設定 116 | 117 | 1. 再次開啟命令列上的功能表按鈕,然後選取 **\[設定]**。 118 | 2. 在 **\[設定]** 頁面上,您會看到在預設情況下,每次執行增益集時就會開啟指示頁。您可以使用選項按鈕來指定只會在第一次執行增益集時出現指示頁。 119 | 3. 關閉工作窗格,再次選取 **\[顯示]** 按鈕,然後重新啟動增益集。增益集將會以 **\[尋找和取代]** 頁面開啟而不是指示頁。 120 | 4. 再次瀏覽到 **\[設定]** 頁面。您可以選取 **\[顯示指示]** 按鈕以開啟指示頁,或將指示設定變更回每次執行增益集時就開啟指令頁。 121 | 122 | ## 瞭解程式碼 123 | 124 | 使用 Office 和 Word JavaScript ApI 的所有程式碼皆位於檔案 word.document.service.ts 中。此範例示範的 `compareLocationWith()` 方法位於 `replaceFoundStringsWithExceptions()` 方法中。 125 | 126 | 程式碼第一次取得的所有範圍集合與使用者的搜尋字詞相符。然後程式碼接著取得文件中所有段落範圍的集合。 127 | 128 | ```let foundItems:Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 129 | ```let paras :Word.ParagraphCollection = context.document.body.paragraphs.load();``` 130 | 131 | 集合都已使用 `context.sync()` 呼叫載入後,程式碼便會建立段落範圍的陣列,使用者就可以從取代排除。(請注意,`excludedParagraph` 為傳遞至方法的參數。) 132 | 133 | ```let excludedRanges:Array = \[];``` 134 | ```excludedRanges.push(paras.items\[excludedParagraph].getRange('Whole'));``` 135 | 136 | 程式碼接著透過反覆迴圈以判斷搜尋結果是否落在排除的段落。針對每個搜尋結果,此事實記錄在 `IReplacementCandidate` 物件。如果搜尋結果在排除的段落內,`compareLocationWith()` 方法會傳回「內部」。如果搜尋結果本身是一個段落,而且已經被排除,則會傳回「等於」。 137 | 138 | ``` 139 | for (let i = 0; i < foundItems.items.length; i++) { 140 | for (let j = 0; j < excludedRanges.length; j++) { 141 | replacementCandidates.push({ 142 | range: foundItems.items[i], 143 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 144 | }); 145 | } 146 | } 147 | ``` 148 | 取代的候選物件會使用呼叫載入到 `context.sync()`,然後程式碼接著會逐一查看,將搜尋字串取代成取代字串,取代情況只在發生在非排除段落的段落中。 149 | 150 | ``` 151 | replacementCandidates.forEach(function (item) { 152 | switch (item.locationRelation.value) { 153 | case "Inside": 154 | case "Equal": 155 | break; 156 | default: 157 | item.range.insertText(replaceString, 'Replace'); 158 | } 159 | }); 160 | ``` 161 | 請參閱相同檔案的 `replaceDocumentContent` 方法,查看如何使用 Word `insertText` 和 `nsertParagraph` 方法將範例內容插入文件。 162 | 163 | 若要查看已將 [Office 增益集 UX 設計模式程式碼](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code)的設計模式整合到 Angular 2.0 架構的方式,請參閱程式碼檔案的其餘部分。 164 | 165 | ## 問題與意見 166 | 167 | 我們很樂於收到您對於此範例的意見反應。您可以在此儲存機制的 *\[問題]* 區段中,將您的意見反應傳送給我們。 168 | 169 | 請在 [Stack Overflow](http://stackoverflow.com/questions/tagged/office-js+API) 提出有關 Microsoft Office 365 開發的一般問題。如果您的問題是關於 Office JavaScript API,請確定您的問題標記有 \[office js] 與 \[API]。 170 | 171 | ## 其他資源 172 | 173 | * [Office 增益集文件](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 174 | * [Office 開發中心](http://dev.office.com/) 175 | * 在 [Github 上的 OfficeDev](https://github.com/officedev) 中有更多 Office 增益集範例 176 | 177 | ## 著作權 178 | Copyright (c) 2016 Microsoft Corporation.著作權所有,並保留一切權利。 179 | 180 | 181 | 182 | 此專案已採用 [Microsoft 開放原始碼管理辦法](https://opensource.microsoft.com/codeofconduct/)。如需詳細資訊,請參閱[管理辦法常見問題集](https://opensource.microsoft.com/codeofconduct/faq/),如果有其他問題或意見,請連絡 [opencode@microsoft.com](mailto:opencode@microsoft.com)。 183 | -------------------------------------------------------------------------------- /Word-Add-in-Angular2-StyleChecker.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 579de60b-c4a1-4f57-91ff-9557b1b633be 14 | 15 | 16 | 1.0.0.0 17 | MAX Developer Documentation 18 | en-US 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | AppDomain1 29 | AppDomain2 30 | AppDomain3 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ReadWriteDocument 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | <!-- Description of the Getting Started callout. resid points to a LongString resource --> 62 | <Description resid="MAXDevDocs.Start.Desc"/> 63 | 64 | <!-- Point to a url resource which details how the add-in should be used. --> 65 | <LearnMoreUrl resid="MAXDevDocs.Start.LearnMoreUrl"/> 66 | </GetStarted> 67 | 68 | 69 | <!-- PrimaryCommandSurface is the main Office Ribbon. --> 70 | <ExtensionPoint xsi:type="PrimaryCommandSurface"> 71 | <!-- Use OfficeTab to extend an existing Tab. Use CustomTab to create a new tab. --> 72 | <OfficeTab id="TabHome"> 73 | <!-- Ensure you provide a unique id for the group. Recommendation for any IDs is to namespace using your company name. --> 74 | <Group id="MAXDevDocs.Group1"> 75 | <!-- Label for your group. resid must point to a ShortString resource. --> 76 | <Label resid="MAXDevDocs.Group1Label" /> 77 | <!-- Icons. Required sizes 16,32,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX. --> 78 | <!-- Use PNG icons. All URLs on the resources section must use HTTPS. --> 79 | <Icon> 80 | <bt:Image size="16" resid="MAXDevDocs.tpicon_16x16" /> 81 | <bt:Image size="32" resid="MAXDevDocs.tpicon_32x32" /> 82 | <bt:Image size="80" resid="MAXDevDocs.tpicon_80x80" /> 83 | </Icon> 84 | 85 | <!-- Control. It can be of type "Button" or "Menu". --> 86 | <Control xsi:type="Button" id="MAXDevDocs.TaskpaneButton"> 87 | <Label resid="MAXDevDocs.TaskpaneButton.Label" /> 88 | <Supertip> 89 | <!-- ToolTip title. resid must point to a ShortString resource. --> 90 | <Title resid="MAXDevDocs.TaskpaneButton.Label" /> 91 | <!-- ToolTip description. resid must point to a LongString resource. --> 92 | <Description resid="MAXDevDocs.Button.Tooltip" /> 93 | </Supertip> 94 | <Icon> 95 | <bt:Image size="16" resid="MAXDevDocs.tpicon_16x16" /> 96 | <bt:Image size="32" resid="MAXDevDocs.tpicon_32x32" /> 97 | <bt:Image size="80" resid="MAXDevDocs.tpicon_80x80" /> 98 | </Icon> 99 | 100 | <!-- This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFunction or ShowTaskpane. --> 101 | <Action xsi:type="ShowTaskpane"> 102 | <TaskpaneId>ButtonId1</TaskpaneId> 103 | <!-- Provide a url resource id for the location that will be displayed on the task pane. --> 104 | <SourceLocation resid="MAXDevDocs.Taskpane.Url" /> 105 | </Action> 106 | </Control> 107 | </Group> 108 | </OfficeTab> 109 | </ExtensionPoint> 110 | </DesktopFormFactor> 111 | </Host> 112 | </Hosts> 113 | 114 | <!-- You can use resources across hosts and form factors. --> 115 | <Resources> 116 | <bt:Images> 117 | <bt:Image id="MAXDevDocs.tpicon_16x16" DefaultValue="https://localhost:3000/app/assets/images/blue-pencil-logo-16.png" /> 118 | <bt:Image id="MAXDevDocs.tpicon_32x32" DefaultValue="https://localhost:3000/app/assets/images/blue-pencil-logo-32.png" /> 119 | <bt:Image id="MAXDevDocs.tpicon_80x80" DefaultValue="https://localhost:3000/app/assets/images/blue-pencil-logo-80.png" /> 120 | </bt:Images> 121 | <bt:Urls> 122 | <bt:Url id="MAXDevDocs.Taskpane.Url" DefaultValue="https://localhost:3000" /> 123 | <bt:Url id="MAXDevDocs.Start.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812" /> 124 | </bt:Urls> 125 | <!-- ShortStrings max characters==125. --> 126 | <bt:ShortStrings> 127 | <bt:String id="MAXDevDocs.TaskpaneButton.Label" DefaultValue="Show" /> 128 | <bt:String id="MAXDevDocs.Group1Label" DefaultValue="Style Checker" /> 129 | <bt:String id="MAXDevDocs.Start.Title" DefaultValue="Get started with the Style Checker!" /> 130 | </bt:ShortStrings> 131 | <!-- LongStrings max characters==250. --> 132 | <bt:LongStrings> 133 | <bt:String id="MAXDevDocs.Button.Tooltip" DefaultValue="Click to open the style checker" /> 134 | <bt:String id="MAXDevDocs.Start.Desc" DefaultValue="The Style Checker add-in loaded succesfully. Go to the HOME tab and click the 'Show' button in the Style Checker group to get started." /> 135 | </bt:LongStrings> 136 | </Resources> 137 | </VersionOverrides> 138 | <!-- End Add-in Commands Mode integration. --> 139 | 140 | </OfficeApp> 141 | -------------------------------------------------------------------------------- /README-Localized/README-ja-jp.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | --- 14 | # Angular 2.0 で開発された Word スタイル チェック アドイン 15 | 16 | Word JavaScript API の `LocationRelation API` と `compareLocationWith API` を使用してアドインを作成し、他の範囲を基準とする位置に基づいて一部の範囲をスキップする検索と置換を実行する方法について説明します。このアドインは Angular 2.0 フレームワークでビルドされ、[Office アドイン UX 設計パターン コード](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code) からの設計サンプルを使用する方法も表示します。 17 | 18 | ## 目次 19 | * [変更履歴](#change-history) 20 | * [前提条件](#prerequisites) 21 | * [プロジェクトを構成する](#configure-the-project) 22 | * [アドインを展開する](#deploy-the-add-in) 23 | * [プロジェクトを実行する](#run-the-project) 24 | * [アドインを起動する](#start-the-add-in) 25 | * [アドインをテストする](#test-the-add-in) 26 | * [アドインの設定を変更する](#change-the-settings-of-the-add-in) 27 | * [コードを理解する](#understand-the-code) 28 | * [質問とコメント](#questions-and-comments) 29 | * [その他の技術情報](#additional-resources) 30 | 31 | ## 変更履歴 32 | 33 | 2016 年 8 月 1 日: 34 | 35 | * 初期バージョン。 36 | 37 | 2016 年 9 月 15 日 - 10 月 17 日: 38 | 39 | * マイナー アップデート。 40 | 41 | ## 前提条件 42 | 43 | * Windows 用の Word 2016 (16.0.6727.1000 以降のビルド)。 44 | * [Node と npm](https://nodejs.org/en/) プロジェクトはパッケージ マネージャーとタスク ランナーの両方として npm を使用するように構成されます。また、開発中にアドインをホストする Web サーバーとして npm にビルドされている Lite サーバーを使用するようにも構成されるため、アドインをすばやくオンにして実行することができます。別のタスク ランナーまたは Web サーバーを使用することもできます。 45 | * [Git バッシュ](https://git-scm.com/downloads) (またはその他の Git クライアント。) 46 | 47 | ## プロジェクトを構成する 48 | 49 | プロジェクトを配置するフォルダーで、Git バッシュ シェルで次のコマンドを実行します。 50 | 51 | 1. ```git clone {このリポジトリの URL}``` ローカル コンピューターにこのリポジトリのクローンを作成します。 52 | 2. ```npm install``` package.json ファイル内のアイテム化されたすべての依存関係をインストールします。 53 | 3. ```bash gen-cert.sh``` このサンプルを実行するために必要な証明書を作成します。 54 | 55 | 証明書を信頼されたルート機関にするように設定します。Windows コンピューターでの手順は次のとおりです。 56 | 57 | 1. ローカル コンピューターにあるリポジトリ フォルダーで、ca.crt をダブルクリックし、\[**証明書のインストール**] を選択します。 58 | 2. \[**ローカル コンピューター**] を選択して、\[**次へ**] を選択して続行します。 59 | 3. \[**証明書をすべて次のストアに配置する**] を選択してから \[**参照**] を選択します。 60 | 4. \[**信頼されたルート証明機関**] を選択して、\[**OK**] を選択します。 61 | 5. \[**次へ**]、\[**完了**] の順に選択します。 62 | 63 | ## アドインを展開する 64 | 65 | 次に、Microsoft Word がアドインを検索する場所を認識できるようにする必要があります。 66 | 67 | 1. ネットワーク共有を作成するか、[フォルダーをネットワークに共有します](https://technet.microsoft.com/en-us/library/cc770880.aspx)。 68 | 2. プロジェクトのルートから、Word-Add-in-Angular2-StyleChecker.xml マニフェスト ファイルのコピーを共有フォルダーに配置します。 69 | 3. Word を起動し、ドキュメントを開きます。 70 | 4. \[**ファイル**] タブを選択し、\[**オプション**] を選択します。 71 | 5. \[**セキュリティ センター**] を選択し、\[**セキュリティ センターの設定**] ボタンを選択します。 72 | 6. \[**信頼されているアドイン カタログ**] を選択します。 73 | 7. \[**カタログの URL**] フィールドに、Word-Add-in-Angular2-StyleChecker.xml があるフォルダー共有へのネットワーク パスを入力して、\[**カタログの追加**] を選択します。 74 | 8. \[**メニューに表示する**] チェック ボックスをオンにし、\[**OK**] を選択します。 75 | 9. これらの設定は Microsoft Office を次回起動したときに適用されることを示すメッセージが表示されます。Word を終了します。 76 | 77 | ## プロジェクトを実行する 78 | 79 | 1. プロジェクトのフォルダー内でノード コマンド ウィンドウを開き、```npm start``` を実行して Web サービスを開始します。コマンド ウィンドウを開いたままにしておきます。 80 | 2. Internet Explorer または Microsoft Edge を開いて、```https://localhost:3000``` をアドレス ボックスに入力します。証明書に関する警告が表示されない場合は、ブラウザーを閉じて、「**アドインを起動する**」というタイトルのセクションに進みます。証明書が信頼されていないという警告が表示された場合は、以下の手順に進みます。 81 | 3. 警告があっても、ブラウザーにはページを開くためのリンクが表示されます。そのリンクを開きます。 82 | 4. ページが開いたら、アドレス バーに赤い証明書エラーが表示されます。エラーをダブルクリックします。 83 | 5. \[**証明書の表示**] を選択します。 84 | 5. \[**証明書のインストール**] を選択します。 85 | 4. \[**ローカル コンピューター**] を選択して、\[**次へ**] を選択して続行します。 86 | 3. \[**証明書をすべて次のストアに配置する**] を選択してから \[**参照**] を選択します。 87 | 4. \[**信頼されたルート証明機関**] を選択して、\[**OK**] を選択します。 88 | 5. \[**次へ**]、\[**完了**] の順に選択します。 89 | 6. ブラウザーを閉じます。 90 | 91 | ## アドインを起動する 92 | 93 | 1. Word を再起動して、Word 文書を開きます。 94 | 2. Word 2016 の\[**挿入**] タブで、\[**マイ アドイン**] を選択します。 95 | 3. \[**共有フォルダー**] タブを選択します。 96 | 4. \[**スタイル チェック**]、\[**OK**] の順に選択します。 97 | 5. ご使用の Word バージョンでアドイン コマンドがサポートされている場合、UI によってアドインが読み込まれたことが通知されます。 98 | 6. \[ホーム] では、リボンは**スタイル チェック**と呼ばれる新しいグループであり、\[**表示**] というラベル付きのボタンと青色の鉛筆アイコンがあります。そのボタンをクリックすると、アドインが手順ページに開きます。 99 | 100 | > 注記:アドイン コマンドが Word バージョンによってサポートされていない場合は、アドインが作業ウィンドウに読み込まれます。 101 | 102 | ## アドインをテストする 103 | 104 | 1. 手順が完了したら、\[**はじめに**] をクリックします。 105 | 2. \[**検索および置換**] ページが開くと、メニュー ボタンとともに上部にコマンド バーがあります。そのボタンをクリックして、メニューを開きます。 106 | 3. \[**サンプルのコンテンツを挿入する**] を選択します。もう 1 度ボタンをクリックして、メニューを閉じます。ドキュメントには、架空の引用を含む、Office アドインに関する書式なしのテキストが存在します。ライターは、"Office Add-in" の省略形に "OAI" を使用しており、匿名の引用についても同様です。 107 | 4. \[**検索**] ボックスに「OAI」と入力します。 108 | 5. \[**置換**] ボックスに「Office アドイン」と入力します。 109 | 6. 直接引用である段落で変更はされ***ない***ため、\[**段落をスキップ**] ボックスに数字「**2**」を入力します。これは、0 から始まる段落番号です。 110 | 7. \[**置換**] を選択します。スキップした段落のインスタンス以外の、すべてのインスタンスの "OAI" は変更されます。 111 | 8. 他の検索を試し、文字列を置換します。 112 | 113 | > 注:このサンプル アドインは、\[**段落番号をスキップ**] ボックスの 1 つの数のみを受け入れます。運用アドインを使用すると、複数の段落をスキップすることができ、どの段落をスキップするかを指定する別の方法をとることもできます (例: 段落のスタイルに基づいてスキップを行う)。 114 | 115 | ## アドインの設定を変更する 116 | 117 | 1. もう 1 度コマンド バーのメニュー ボタンを開き、\[**設定**] を選択します。 118 | 2. \[**設定**] ページで、既定では、アドインが実行されるたびに手順ページが開きます。オプション ボタンを使用して、アドインが初めて実行される場合のみ手順ページが表示されるように指定します。 119 | 3. 作業ウィンドウを閉じて、もう一度 \[**表示**] ボタンを選択し、アドインを再起動します。手順ページの代わりに、\[**検索と置換**] ページでアドインが開きます。 120 | 4. もう一度 \[**設定**] ページに移動します。\[**手順を表示**] ボタンを選択して、手順ページを開くことができます。または、アドインが実行されるたびに手順ページが開くように、手順設定を戻すことができます。 121 | 122 | ## コードを理解する 123 | 124 | Office および Word の JavaScript API を使用するすべてのコードは、word.document.service.ts ファイルにあります。このサンプルが示す `compareLocationWith()` メソッドは、`replaceFoundStringsWithExceptions()` メソッドにあります。 125 | 126 | コードは、まず、ユーザーの検索用語に一致するすべての範囲のコレクションを取得します。次に、ドキュメント内のすべての段落範囲のコレクションを取得します。 127 | 128 | ```let foundItems:Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 129 | ```let paras :Word.ParagraphCollection = context.document.body.paragraphs.load();``` 130 | 131 | `context.sync()` の呼び出しでコレクションが読み込まれた後、コードは、ユーザーが置換から除外する段落範囲の配列を作成します。(`excludedParagraph` は、メソッドに渡されたパラメーターであることに注意してください。) 132 | 133 | ```let excludedRanges:Array<Word.Range> = \[];``` 134 | ```excludedRanges.push(paras.items\[excludedParagraph].getRange('Whole'));``` 135 | 136 | コードは、検索結果が除外された段落内にあるかないかを決定するために、iterable をループ処理します。それぞれの検索結果に対して、このファクトは `IReplacementCandidate` オブジェクトに記録されます。`compareLocationWith()` メソッドは、検索結果が除外されている段落内にある場合に、"Inside" を返します。検索結果自体が段落であり、除外されている場合は、"Equal" を返します。 137 | 138 | ``` 139 | for (let i = 0; i < foundItems.items.length; i++) { 140 | for (let j = 0; j < excludedRanges.length; j++) { 141 | replacementCandidates.push({ 142 | range: foundItems.items[i], 143 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 144 | }); 145 | } 146 | } 147 | ``` 148 | 置換候補のオブジェクトは、`context.sync()` への呼び出しで読み込まれ、コードはオブジェクト内を反復処理します。除外された段落にはない段落でのみ、検索文字列を置換文字列に置換します。 149 | 150 | ``` 151 | replacementCandidates.forEach(function (item) { 152 | switch (item.locationRelation.value) { 153 | case "Inside": 154 | case "Equal": 155 | break; 156 | default: 157 | item.range.insertText(replaceString, 'Replace'); 158 | } 159 | }); 160 | ``` 161 | ドキュメントにサンプル コンテンツを挿入するための、Word の `insertText` メソッドおよび `nsertParagraph` メソッドの使用方法を知るために、同じファイルの `replaceDocumentContent` メソッドを参照します。 162 | 163 | [Office アドイン UX 設計パターン コード](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code)からの設計パターンが Angular 2.0 フレームワークに統合される方法を知るために、残りのコード ファイルを参照します。 164 | 165 | ## 質問とコメント 166 | 167 | このサンプルに関するフィードバックをお寄せください。このリポジトリの「*問題*」セクションでフィードバックを送信できます。 168 | 169 | Microsoft Office 365 開発全般の質問につきましては、「[スタック オーバーフロー](http://stackoverflow.com/questions/tagged/office-js+API)」に投稿してください。Office JavaScript API に関する質問の場合は、必ず質問に \[office-js] と \[API] のタグを付けてください。 170 | 171 | ## その他の技術情報 172 | 173 | * [Office アドインのドキュメント](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 174 | * [Office デベロッパー センター](http://dev.office.com/) 175 | * [Github の OfficeDev](https://github.com/officedev) にあるその他の Office アドイン サンプル 176 | 177 | ## 著作権 178 | Copyright (c) 2016 Microsoft Corporation.All rights reserved. 179 | 180 | 181 | 182 | このプロジェクトでは、[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) が採用されています。詳細については、「[Code of Conduct の FAQ](https://opensource.microsoft.com/codeofconduct/faq/)」を参照してください。また、その他の質問やコメントがあれば、[opencode@microsoft.com](mailto:opencode@microsoft.com) までお問い合わせください。 183 | -------------------------------------------------------------------------------- /README-Localized/README-ru-ru.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | --- 14 | # Надстройка Word для проверки стиля на Angular 2.0 15 | 16 | Узнайте, как создать надстройку, использующую API `LocationRelation` и `compareLocationWith` (API JavaScript для Word) для поиска и замены строк, пропуская диапазоны на основе их расположения. Надстройка создана на платформе Angular 2.0\. Из этого примера вы также узнаете, как использовать [код шаблонов оформления надстроек Office](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code). 17 | 18 | ## Содержание 19 | * [Журнал изменений](#change-history) 20 | * [Предварительные требования](#prerequisites) 21 | * [Настройка проекта](#configure-the-project) 22 | * [Развертывание надстройки](#deploy-the-add-in) 23 | * [Запуск проекта](#run-the-project) 24 | * [Запуск надстройки](#start-the-add-in) 25 | * [Тестирование надстройки](#test-the-add-in) 26 | * [Изменение параметров надстройки](#change-the-settings-of-the-add-in) 27 | * [Разбор кода](#understand-the-code) 28 | * [Вопросы и комментарии](#questions-and-comments) 29 | * [Дополнительные ресурсы](#additional-resources) 30 | 31 | ## Журнал изменений 32 | 33 | 1 августа 2016 г. 34 | 35 | * Исходная версия. 36 | 37 | 15 сентября – 17 октября 2016 г. 38 | 39 | * Незначительные изменения. 40 | 41 | ## Необходимые компоненты 42 | 43 | * Word 2016 для Windows, сборка 16.0.6727.1000 или более поздняя. 44 | * [Node и npm.](https://nodejs.org/en/) В этом проекте npm используется как диспетчер пакетов и как средство запуска задач. В качестве веб-сервера используется Lite Server, встроенный в npm. Надстройка размещается на нем во время разработки, чтобы ее можно было быстро настроить и запустить. Вы можете использовать другое средство запуска задач или другой веб-сервер. 45 | * [Git Bash](https://git-scm.com/downloads) (или другой клиент git). 46 | 47 | ## Настройка проекта 48 | 49 | В папке проекта выполните следующие команды в консоли git bash: 50 | 51 | 1. ```git clone {URL-адрес этого репозитория}```, чтобы клонировать этот репозиторий на локальный компьютер. 52 | 2. ```npm install```, чтобы установить все детализированные зависимости в файл package.json. 53 | 3. ```bash gen-cert.sh```, чтобы создать сертификат, необходимый для запуска этого примера. 54 | 55 | Сделайте сертификат доверенным корневым центром. Для этого на компьютере с Windows выполните указанные ниже действия. 56 | 57 | 1. В папке репозитория на локальном компьютере дважды щелкните файл ca.crt и выберите элемент **Установить сертификат**. 58 | 2. Выберите **Локальный компьютер** и нажмите кнопку **Далее**, чтобы продолжить. 59 | 3. Выберите **Поместить все сертификаты в следующее хранилище** и нажмите кнопку **Обзор**. 60 | 4. Выберите **Доверенные корневые центры сертификации** и нажмите кнопку **OK**. 61 | 5. Выберите **Далее**, а затем **Готово**. 62 | 63 | ## Развертывание надстройки 64 | 65 | Теперь необходимо сообщить Microsoft Word, где находится эта надстройка. 66 | 67 | 1. Создайте сетевую папку или [предоставьте общий доступ к папке через сеть](https://technet.microsoft.com/en-us/library/cc770880.aspx). 68 | 2. Поместите копию файла манифеста Word-Add-in-Angular2-StyleChecker.xml из корня проекта в общую папку. 69 | 3. Запустите Word и откройте документ. 70 | 4. Перейдите на вкладку **Файл** и выберите **Параметры**. 71 | 5. Выберите **Центр управления безопасностью** и нажмите кнопку **Параметры центра управления безопасностью**. 72 | 6. Выберите пункт **Доверенные каталоги надстроек**. 73 | 7. В поле **URL-адрес каталога** введите сетевой путь к общей папке с файлом Word-Add-in-Angular2-StyleChecker.xml и выберите **Добавить каталог**. 74 | 8. Установите флажок **Показывать в меню** и нажмите кнопку **OK**. 75 | 9. Появится сообщение, информирующее о том, что параметры будут применены при следующем запуске Microsoft Office. Закройте Word. 76 | 77 | ## Запуск проекта 78 | 79 | 1. Откройте командное окно узла в папке проекта и выполните команду ```npm start``` для запуска веб-службы. Не закрывайте командное окно. 80 | 2. Откройте Internet Explorer или Microsoft Edge и введите ```https://localhost:3000``` в адресной строке. Если вы не получите никаких предупреждений о сертификате, закройте браузер и перейдите к приведенному ниже разделу под названием **Запуск надстройки**. Если вы получите предупреждение, что сертификат не является доверенным, выполните указанные ниже действия. 81 | 3. Несмотря на предупреждение в браузере отобразится ссылка на открытие страницы. Откройте ее. 82 | 4. После открытия страницы в адресной строке появится оповещение об ошибке сертификата красного цвета. Дважды щелкните это оповещение. 83 | 5. Выберите элемент **Просмотр сертификата**. 84 | 5. Нажмите **Установить сертификат**. 85 | 4. Выберите **Локальный компьютер** и нажмите кнопку **Далее**, чтобы продолжить. 86 | 3. Выберите **Поместить все сертификаты в следующее хранилище** и нажмите кнопку **Обзор**. 87 | 4. Выберите **Доверенные корневые центры сертификации** и нажмите кнопку **OK**. 88 | 5. Выберите **Далее**, а затем **Готово**. 89 | 6. Закройте браузер. 90 | 91 | ## Запуск надстройки 92 | 93 | 1. Перезапустите Word и откройте документ Word. 94 | 2. На вкладке **Вставка** в Word 2016 выберите **Мои надстройки**. 95 | 3. Откройте вкладку **ОБЩАЯ ПАПКА**. 96 | 4. Выберите элемент **Style Checker** и нажмите кнопку **OK**. 97 | 5. Если ваша версия Word поддерживает команды надстроек, то в пользовательском интерфейсе появятся сведения о том, что надстройка загружена. 98 | 6. На вкладке "Главная" появится новая группа **Style Checker** с кнопкой **Показать** и значком в виде синего карандаша. Нажмите эту кнопку, и откроется страница с инструкциями. 99 | 100 | > Примечание. Если ваша версия Word не поддерживает команды надстроек, то надстройка загрузится в области задач. 101 | 102 | ## Тестирование надстройки 103 | 104 | 1. Просмотрите инструкции, а затем нажмите кнопку **Get Started** (Начать работу). 105 | 2. Когда откроется страница **Find and Replace** (Поиск и замена), вверху вы увидите панель команд с кнопкой меню. Нажмите кнопку, чтобы открыть меню. 106 | 3. Выберите **Insert sample content** (Вставить пример содержимого). Нажмите кнопку еще раз, чтобы закрыть меню. Теперь документ содержит неформатированный текст о надстройках Office, в том числе вымышленную цитату. В тексте и анонимной цитате для обозначения надстройки Office используется аббревиатура "OAI". 107 | 4. В поле **Find** (Поиск) введите "OAI". 108 | 5. В поле **Replace** (Замена) введите "Надстройка Office". 109 | 6. Для абзаца с цитатой изменение ***не*** требуется, поэтому введите число **2** в поле **Skip Paragraph Number** (Пропустить абзац номер). Это номер абзаца с отчетом от нуля. 110 | 7. Нажмите кнопку **Replace** (Заменить). Все экземпляры "OAI", кроме экземпляра в пропущенном абзаце, будут заменены. 111 | 8. Поэкспериментируйте с другими строками поиска и замены. 112 | 113 | > Примечание. В этом примере надстройки в поле **Skip Paragraph Number** (Пропустить абзац номер) можно ввести только одно число. В рабочей надстройке можно будет пропускать несколько абзацев, а также использовать другие способы обозначения абзацев для пропуска, например пропуск с учетом стиля абзаца. 114 | 115 | ## Изменение параметров надстройки 116 | 117 | 1. Откройте меню на панели команд еще раз и выберите **Settings** (Параметры). 118 | 2. На странице **Settings** (Параметры) вы увидите, что по умолчанию страница с инструкциями открывается при каждом запуске надстройки. Выберите настройку, при которой страница с инструкциями отображается только при первом запуске надстройки. 119 | 3. Закройте область задач и повторно запустите надстройку, нажав кнопку **Показать**. Откроется страница **Find and Replace** (Поиск и замена), а не страница с инструкциями. 120 | 4. Снова перейдите на страницу **Settings** (Параметры). Вы можете нажать кнопку **Show Instructions** (Показать инструкции), чтобы открыть страницу с инструкциями, или вернуться к настройке, при которой страница с инструкциями открывается при каждом запуске надстройки. 121 | 122 | ## Разбор кода 123 | 124 | Весь код, который использует API JavaScript для Office и Word, находится в файле word.document.service.ts. Метод `compareLocationWith()`, демонстрируемый в этом примере, находится в методе `replaceFoundStringsWithExceptions()`. 125 | 126 | Код сначала получает коллекцию всех диапазонов, которые соответствуют условию поиска пользователя. Затем он получает коллекцию всех диапазонов абзацев в документе. 127 | 128 | ```let foundItems: Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 129 | ```let paras : Word.ParagraphCollection = context.document.body.paragraphs.load();``` 130 | 131 | После загрузки коллекций методом `context.sync()` код создает массив диапазонов абзацев, исключенных пользователем. Обратите внимание, что в метод передается параметр `excludedParagraph`. 132 | 133 | ```let excludedRanges: Array<Word.Range> = \[];``` 134 | ```excludedRanges.push(paras.items\[excludedParagraph].getRange('Whole'));``` 135 | 136 | Затем код просматривает итерируемые объекты, чтобы определить результаты поиска в исключенных абзацах. Для каждого результата поиска этот факт записывается в объекте `IReplacementCandidate`. Метод `compareLocationWith()` возвращает значение "Inside", если результат поиска находится в исключенном абзаце. Если результат поиска совпадает с исключенным абзацем, возвращается значение "Equal". 137 | 138 | ``` 139 | for (let i = 0; i < foundItems.items.length; i++) { 140 | for (let j = 0; j < excludedRanges.length; j++) { 141 | replacementCandidates.push({ 142 | range: foundItems.items[i], 143 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 144 | }); 145 | } 146 | } 147 | ``` 148 | Потенциальные объекты замены загружаются методом `context.sync()`, а затем код выполняет итерацию по ним, заменяя строки только в неисключенных абзацах. 149 | 150 | ``` 151 | replacementCandidates.forEach(function (item) { 152 | switch (item.locationRelation.value) { 153 | case "Inside": 154 | case "Equal": 155 | break; 156 | default: 157 | item.range.insertText(replaceString, 'Replace'); 158 | } 159 | }); 160 | ``` 161 | Просмотрите метод `replaceDocumentContent` в том же файле, чтобы узнать, как методы `insertText` и `nsertParagraph` Word используются для вставки примеров содержимого в документ. 162 | 163 | Просмотрите остальные файлы кода, чтобы узнать, как шаблоны оформления из [кода шаблонов оформления надстроек Office](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code) интегрированы в платформу Angular 2.0. 164 | 165 | ## Вопросы и комментарии 166 | 167 | Мы будем рады узнать ваше мнение об этом примере. Своими мыслями можете поделиться на вкладке *Issues* (Проблемы) этого репозитория. 168 | 169 | Общие вопросы о разработке решений для Microsoft Office 365 следует задавать на сайте [Stack Overflow](http://stackoverflow.com/questions/tagged/office-js+API). Если ваш вопрос касается API JavaScript для Office, добавьте к нему теги \[office-js] и \[API]. 170 | 171 | ## Дополнительные ресурсы 172 | 173 | * [Документация по надстройкам Office](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 174 | * [Центр разработчиков Office](http://dev.office.com/) 175 | * Другие примеры надстроек Office см. на странице [OfficeDev на Github](https://github.com/officedev). 176 | 177 | ## Авторские права 178 | © Корпорация Майкрософт (Microsoft Corporation), 2016. Все права защищены. 179 | 180 | 181 | 182 | Этот проект соответствует [правилам поведения Майкрософт, касающимся обращения с открытым кодом](https://opensource.microsoft.com/codeofconduct/). Дополнительные сведения см. в разделе [вопросов и ответов о правилах поведения](https://opensource.microsoft.com/codeofconduct/faq/). Если у вас возникли вопросы или замечания, напишите нам по адресу [opencode@microsoft.com](mailto:opencode@microsoft.com). 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | description: "Learn how to create an add-in that uses the `LocationRelation` and `compareLocationWith` APIs of the Word JavaScript APIs to perform a search and replace that skips some ranges based on their location relative to other ranges." 14 | --- 15 | # Word Style Checking Add-in Built on Angular 2.0 16 | 17 | > **Important Note 1**: This repo is being archived because we do not have the staff to update it or to support Angular. It can still be used for the educational purposes described below. 18 | 19 | > **Important Note 2**: This sample has several security alerts. These vulnerabilities do not pose a problem for running and modifying this sample on your development computer, but do not use the vulnerable libraries in a production add-in. For example, it uses the latest lite-server (version 2.6.1) to host the add-in. This server package has a dependency on a version of the xmlhttprequest-ssl package that has a security vulnerability. 20 | 21 | Learn how to create an add-in that uses the `LocationRelation` and `compareLocationWith` APIs of the Word JavaScript APIs to perform a search and replace that skips some ranges based on their location relative to other ranges. The add-in is built on the Angular 2.0 framework, and it also shows how to use the design samples from [Office Add-in UX Design Patterns Code](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code). 22 | 23 | ## Table of Contents 24 | * [Change History](#change-history) 25 | * [Prerequisites](#prerequisites) 26 | * [Configure the project](#configure-the-project) 27 | * [Deploy the add-in](#deploy-the-add-in) 28 | * [Run the project](#run-the-project) 29 | * [Start the add-in](#start-the-add-in) 30 | * [Test the add-in](#test-the-add-in) 31 | * [Change the settings of the add-in](#change-the-settings-of-the-add-in) 32 | * [Understand the code](#understand-the-code) 33 | * [Questions and comments](#questions-and-comments) 34 | * [Additional resources](#additional-resources) 35 | 36 | ## Change History 37 | 38 | August 1, 2016: 39 | 40 | * Initial version. 41 | 42 | September 15 - October 17th, 2016: 43 | 44 | * Minor updates. 45 | 46 | December 11th, 2020: 47 | 48 | * Changed system for creating and installing the SSL certificates for HTTPS. 49 | 50 | May 23rd, 2023: 51 | 52 | * Archiving. 53 | 54 | ## Prerequisites 55 | 56 | * Word 2016 for Windows, build 16.0.6727.1000 or later. 57 | * [Node and npm](https://nodejs.org/en/) The project is configured to use npm as both a package manager and a task runner. It is also configured to use the Lite Server built into npm as the web server that will host the add-in during development, so you can have the add-in up and running quickly. You are welcome to use another task runner or web server. 58 | * [Git Bash](https://git-scm.com/downloads) (Or another git client.) 59 | 60 | ## Configure the project 61 | 62 | 1. In the folder where you want to put the project open a git bash shell and take these steps: 63 | 64 | 1. Run ```git clone {URL of this repo}``` to clone this repo to your local machine. Your project will be created in a subfolder. 65 | 2. In the bash shell, navigate to the root of the new project. 66 | 3. Run ```npm install``` to install all of the dependencies itemized in the package.json file. 67 | 68 | 2. Open a system Command Prompt *as an administrator* and take these steps: 69 | 70 | 1. Navigate to the root of the project. 71 | 2. Run the command: ```npx office-addin-dev-certs install --machine```. 72 | 73 | If you get the following prompt, click Yes. 74 | 75 | ![Screenshot of a dialog that warns about the SSL certificate and asks user to accept or deny installation of it.](./ReadmeImages/CertificateWarningPrompt.png) 76 | 77 | 3. Leave the Command Prompt open. 78 | 79 | 3. In your code editor, open the `bs-config.json` file in the root of the project. 80 | 4. Replace the string "YOUR-USER-NAME-ON-COMPUTER" in both places with your username on the computer. 81 | 5. Save and close the file. 82 | 83 | ## Deploy the add-in 84 | 85 | Now you need to let Microsoft Word know where to find the add-in. 86 | 87 | 1. Create a network share, or [share a folder to the network](https://technet.microsoft.com/en-us/library/cc770880.aspx). 88 | 2. Place a copy of the Word-Add-in-Angular2-StyleChecker.xml manifest file, from the root of the project, into the shared folder. 89 | 3. Launch Word and open a document. 90 | 4. Choose the **File** tab, and then choose **Options**. 91 | 5. Choose **Trust Center**, and then choose the **Trust Center Settings** button. 92 | 6. Choose **Trusted Add-ins Catalogs**. 93 | 7. In the **Catalog Url** field, enter the network path to the folder share that contains Word-Add-in-Angular2-StyleChecker.xml, and then choose **Add Catalog**. 94 | 8. Select the **Show in Menu** check box, and then choose **OK**. 95 | 9. A message is displayed to inform you that your settings will be applied the next time you start Microsoft Office. Close Word. 96 | 97 | ## Run the project 98 | 99 | In the Command Prompt, run ```npm start``` to start the web service. (The home page of the project may open in the default browser. Just close it. Add-ins can only run correctly in the context of an Office application.) 100 | 101 | 102 | ## Start the add-in 103 | 104 | 1. Restart Word and open a Word document. 105 | 2. On the **Insert** tab in Word 2016, choose **My Add-ins**. 106 | 3. Select the **SHARED FOLDER** tab. 107 | 4. Choose **Style Checker**, and then select **OK**. 108 | 5. If add-in commands are supported by your version of Word, the UI will inform you that the add-in was loaded. 109 | 6. On the Home ribbon is a new group called **Style Checker** with a button labeled **Show** and a blue pencil icon. Click that button and the add-in will open to a page of instructions. 110 | 111 | > Note: The add-in will load in a task pane if add-in commands are not supported by your version of Word. 112 | 113 | ## Test the add-in 114 | 115 | 1. When you are finished with the instructions, click **Get Started**. 116 | 2. When the **Find and Replace** page opens, there is a command bar at the top with a menu button. Click the button to open the menu. 117 | 3. Select **Insert sample content**. Click the button again to close the menu. The document now has unformatted text about Office Add-ins, including a fictional quotation. The writer has used an "OAI" to abbreviate "Office Add-in" and so does the anonymous quotation. 118 | 4. In the **Find** box enter "OAI". 119 | 5. In the **Replace** box enter "Office Add-in". 120 | 6. The change should ***not*** be made in the paragraph that is a direct quotation, so enter the number **2** in the **Skip Paragraph Number** box. This is the zero-based number of the paragraph. 121 | 7. Select **Replace**. Every instance of "OAI" except the one in the skipped paragraph is changed. 122 | 8. Experiment with other search and replace strings. 123 | 124 | > Note: This sample add-in accepts only one number in the **Skip Paragraph Number** box and you must have some number in the box. A production add-in would allow no paragraphs to be skipped or multiple paragraphs to be skipped and would have additional ways of designating which paragraphs should be skipped; such as skipping based on paragraph style. 125 | 126 | ## Change the settings of the add-in 127 | 128 | 1. Open the menu button on the command bar again and select **Settings**. 129 | 2. On the **Settings** page, you'll see that by default the instructions page opens every time the add-in is run. Use the radio buttons to specify that the instructions page will appear only the first time that the add-in is run. 130 | 3. Close the task pane and then relaunch the add-in by selecting the **Show** button again. The add-in will open with the **Find and Replace** page instead of the instructions page. 131 | 4. Navigate to the **Settings** page again. You can select the **Show Instructions** button to open the instructions page, or change the instructions setting back to open the instructions page every time the add-in is run. 132 | 133 | ## Understand the code 134 | 135 | All of the code that uses the Office and Word JavaScript APIs is in the file word.document.service.ts. The `compareLocationWith()` method that this sample demonstrates is in the `replaceFoundStringsWithExceptions()` method. 136 | 137 | The code first gets a collection of all the ranges that match the user's search term. It then gets a collection of all the paragraph ranges in the document. 138 | 139 | ```let foundItems: Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 140 | ```let paras : Word.ParagraphCollection = context.document.body.paragraphs.load();``` 141 | 142 | After the collections are loaded with a call of `context.sync()`, the code creates an array of the paragraph ranges that the user excludes from the replacement. (Note that `excludedParagraph` is a parameter passed to the method.) 143 | 144 | ```let excludedRanges: Array<Word.Range> = [];``` 145 | ```excludedRanges.push(paras.items[excludedParagraph].getRange('Whole'));``` 146 | 147 | The code then loops through the iterables to determine which search results are inside excluded paragraphs and which are not. For each search result, this fact is recorded in a `IReplacementCandidate` object. The `compareLocationWith()` method returns "Inside" if the search result is inside the excluded paragraph. It returns "Equal" if the search result is a paragraph by itself and has been excluded. 148 | 149 | ``` 150 | for (let i = 0; i < foundItems.items.length; i++) { 151 | for (let j = 0; j < excludedRanges.length; j++) { 152 | replacementCandidates.push({ 153 | range: foundItems.items[i], 154 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 155 | }); 156 | } 157 | } 158 | ``` 159 | The replacement candidate objects are loaded with a call to `context.sync()` and then the code iterates through them, replacing the search string with the replace string only in the paragraphs which are not in an excluded paragraph. 160 | 161 | ``` 162 | replacementCandidates.forEach(function (item) { 163 | switch (item.locationRelation.value) { 164 | case "Inside": 165 | case "Equal": 166 | break; 167 | default: 168 | item.range.insertText(replaceString, 'Replace'); 169 | } 170 | }); 171 | ``` 172 | See the `replaceDocumentContent` method of the same file to see how the Word `insertText` and `nsertParagraph` methods are used to insert sample content into the document. 173 | 174 | See the rest of the code files to see how the design patterns from [Office Add-in UX Design Patterns Code](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code) have been integrated into the Angular 2.0 framework. 175 | 176 | ## Questions and comments 177 | 178 | We'd love to get your feedback about this sample. You can send your feedback to us in the *Issues* section of this repository. 179 | 180 | Questions about Microsoft Office 365 development in general should be posted to [Stack Overflow](http://stackoverflow.com/questions/tagged/office-js+API). If your question is about the Office JavaScript APIs, make sure that your questions are tagged with [office-js] and [API]. 181 | 182 | ## Additional resources 183 | 184 | * [Office add-in documentation](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 185 | * [Office Dev Center](http://dev.office.com/) 186 | * More Office Add-in samples at [OfficeDev on Github](https://github.com/officedev) 187 | 188 | ## Copyright 189 | Copyright (c) 2016 and 2020 Microsoft Corporation. All rights reserved. 190 | 191 | 192 | 193 | 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. 194 | -------------------------------------------------------------------------------- /README-Localized/README-pt-br.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | products: 4 | - office-word 5 | - office-365 6 | languages: 7 | - javascript 8 | extensions: 9 | contentType: samples 10 | technologies: 11 | - Add-ins 12 | createdDate: 8/9/2016 11:08:27 AM 13 | --- 14 | # Suplemento de Verificação de Estilo do Word criado em Angular 2.0 15 | 16 | Saiba como usar um suplemento que usa as APIs `LocationRelation` e `compareLocationWith` das APIs JavaScript do Word para realizar uma pesquisa e substituição ignorando alguns intervalos com base na localização em relação a outros intervalos. O suplemento está incluído na estrutura Angular 2.0 e também mostra como usar os exemplos de design do [Código de Padrões de Design da Experiência do Usuário de Suplementos do Office](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code). 17 | 18 | ## Sumário 19 | * [Histórico de alterações](#change-history) 20 | * [Pré-requisitos](#prerequisites) 21 | * [Configurar o projeto](#configure-the-project) 22 | * [Implantar o suplemento](#deploy-the-add-in) 23 | * [Executar o projeto](#run-the-project) 24 | * [Iniciar o suplemento](#start-the-add-in) 25 | * [Testar o suplemento](#test-the-add-in) 26 | * [Alterar as configurações do suplemento](#change-the-settings-of-the-add-in) 27 | * [Compreender o código](#understand-the-code) 28 | * [Perguntas e comentários](#questions-and-comments) 29 | * [Recursos adicionais](#additional-resources) 30 | 31 | ## Histórico de alterações 32 | 33 | 1º de agosto de 2016: 34 | 35 | * Versão inicial. 36 | 37 | 15 de setembro - 17 de outubro de 2016: 38 | 39 | * Atualizações secundárias. 40 | 41 | ## Pré-requisitos 42 | 43 | * Word 2016 para Windows, build 16.0.6727.1000 ou superior. 44 | * [Nó e npm](https://nodejs.org/en/) Configuramos o projeto para usar npm como gerenciador de pacotes e executor de tarefas. Ele também é configurado para usar o Lite Server integrado ao npm como o servidor Web que hospedará o suplemento durante o desenvolvimento, de modo que você possa começar a usar o suplemento rapidamente. Você também pode usar outro executor de tarefas ou servidor Web. 45 | * [Git Bash](https://git-scm.com/downloads) (ou outro cliente git) 46 | 47 | ## Configurar o projeto 48 | 49 | Na pasta em que deseja armazenar o projeto, execute os seguintes comandos no shell do Git Bash: 50 | 51 | 1. ```git clone {URL deste repositório}``` para clonar este repositório em seu computador local. 52 | 2. ```npm install``` para instalar todas as dependências discriminadas no arquivo package.json. 53 | 3. ```bash gen-cert.sh``` para criar os certificados necessários para executar este exemplo. 54 | 55 | Defina o certificado como uma autoridade raiz confiável. Em um computador com Windows, as etapas são as seguintes: 56 | 57 | 1. Na pasta do repositório do computador local, clique duas vezes em cada ca.crt e escolha **Instalar Certificado**. 58 | 2. Escolha **Computador Local** e **Avançar** para continuar. 59 | 3. Selecione **Colocar todos os certificados no armazenamento a seguir** e escolha **Procurar**. 60 | 4. Escolha **Autoridades de Certificação Raiz Confiáveis** e selecione **OK**. 61 | 5. Escolha **Avançar** e **Concluir**. 62 | 63 | ## Implantar o suplemento 64 | 65 | Agora, você precisa informar ao Microsoft Word onde encontrar o suplemento. 66 | 67 | 1. Crie um compartilhamento de rede ou [compartilhe uma pasta na rede](https://technet.microsoft.com/en-us/library/cc770880.aspx). 68 | 2. Coloque uma cópia do arquivo de manifesto Word-Add-in-Angular2-StyleChecker.xml na raiz do projeto, na pasta compartilhada. 69 | 3. Inicie o Word e abra um documento. 70 | 4. Escolha a guia **Arquivo** e escolha **Opções**. 71 | 5. Escolha **Central de Confiabilidade** e escolha o botão **Configurações da Central de Confiabilidade**. 72 | 6. Escolha **Catálogos de Suplementos Confiáveis**. 73 | 7. No campo **Url do Catálogo**, insira o caminho de rede do compartilhamento de pasta que contém Word-Add-in-Angular2-StyleChecker.xml e escolha **Adicionar Catálogo**. 74 | 8. Marque a caixa de seleção **Mostrar no Menu** e escolha **OK**. 75 | 9. O sistema exibirá uma mensagem para informar que suas configurações serão aplicadas na próxima vez que você iniciar o Microsoft Office. Feche o Word. 76 | 77 | ## Executar o projeto 78 | 79 | 1. Abra uma janela de comando de nó na pasta do projeto e execute ```npm start``` para iniciar o serviço Web. Deixe a janela de comando aberta. 80 | 2. Abra o Internet Explorer ou o Microsoft Edge e insira ```https://localhost:3000``` na caixa de endereço. Se não receber avisos sobre o certificado, feche o navegador e avance para a seção abaixo chamada **Iniciar o suplemento**. Se receber um aviso informando que o certificado não é confiável, vá para as etapas seguintes: 81 | 3. Independentemente do aviso, o navegador fornecerá um link para você abrir a página. Abra-a. 82 | 4. Após abri-la, o sistema exibirá um Erro de Certificado vermelho na barra de endereços. Clique duas vezes no erro. 83 | 5. Escolha **Exibir Certificado**. 84 | 5. Escolha **Instalar Certificado**. 85 | 4. Escolha **Computador Local** e **Avançar** para continuar. 86 | 3. Selecione **Colocar todos os certificados no armazenamento a seguir** e escolha **Procurar**. 87 | 4. Escolha **Autoridades de Certificação Raiz Confiáveis** e selecione **OK**. 88 | 5. Escolha **Avançar** e **Concluir**. 89 | 6. Feche o navegador. 90 | 91 | ## Iniciar o suplemento 92 | 93 | 1. Reinicie o Word e abra um documento. 94 | 2. Na guia **Inserir** no Word 2016, escolha **Meus suplementos**. 95 | 3. Selecione a guia **PASTA COMPARTILHADA**. 96 | 4. Escolha **Verificador de Estilo** e selecione **OK**. 97 | 5. Se os comandos de suplemento forem compatíveis com sua versão do Word, a interface do usuário informará que o suplemento foi carregado. 98 | 6. Na faixa de opções da Página Inicial, há um novo grupo chamado **Verificador de Estilo** com um botão rotulado como **Mostrar** e um ícone de lápis azul. Clique no botão e o suplemento abrirá uma página de instruções. 99 | 100 | > Observação: O suplemento será carregado no painel de tarefas se os comandos de suplemento não forem compatíveis com sua versão do Word. 101 | 102 | ## Testar o suplemento 103 | 104 | 1. Quando concluir as instruções, clique em **Introdução**. 105 | 2. Quando a página **Localizar e Substituir** é aberta, há uma barra de comandos na parte superior com um botão de menu. Clique no botão para abrir o menu. 106 | 3. Selecione **Inserir conteúdo de exemplo**. Clique no botão novamente para fechar o menu. Agora o documento tem texto não formatado sobre Suplementos do Office, incluindo uma citação fictícia. O autor usou "OAI" para abreviar "Suplemento do Office", e a citação anônima também o faz. 107 | 4. Na caixa **Localizar**, insira “OAI”. 108 | 5. Na caixa **Substituir**, insira “Suplemento do Office”. 109 | 6. A alteração ***não*** deve ser feita no parágrafo que é uma citação direta. Portanto, insira o número **2** na caixa **Ignorar Número de Parágrafo**. Este é o número do parágrafo com base em zero. 110 | 7. Selecione **Substituir**. Todas as instâncias de "OAI" são alteradas, exceto aquelas no parágrafo ignorado. 111 | 8. Experimente outras pesquisas e substitua cadeias de caracteres. 112 | 113 | > Observação: Este suplemento de exemplo aceita somente um número na caixa **Ignorar Número de Parágrafo**. Um suplemento de produção permite que vários parágrafos sejam ignorados e outras maneiras de designar quais parágrafos devem ser ignorados; por exemplo, ignorar com base no estilo de parágrafo. 114 | 115 | ## Alterar as configurações do suplemento 116 | 117 | 1. Abra o botão de menu na barra de comandos novamente e selecione **Configurações**. 118 | 2. Na página **Configurações**, você verá que, por padrão, a página de instruções é aberta sempre que o suplemento é executado. Use os botões de opção para especificar que a página de instruções será mostrada apenas na primeira vez que o suplemento for executado. 119 | 3. Feche o painel de tarefas e reinicie o suplemento, selecionando novamente o botão **Mostrar**. O suplemento será aberto coma a página **Localizar e Substituir** em vez da página de instruções. 120 | 4. Navegue até a página **Configurações** novamente. Você pode selecionar o botão **Mostrar Instruções** para abrir a página de instruções ou alterar a configurações de instruções novamente para abrir a página de instruções sempre que o suplemento for executado. 121 | 122 | ## Compreender o código 123 | 124 | Todo o código que usa APIs JavaScript do Office e do Word está no arquivo word.document.service.ts. O método `compareLocationWith()` que este exemplo demonstra está no método `replaceFoundStringsWithExceptions()`. 125 | 126 | Primeiro, o código obtém uma coleção de todos os intervalos que correspondem ao termo de pesquisa do usuário. Em seguida, obtém uma coleção de todos os intervalos de parágrafos no documento. 127 | 128 | ```let foundItems: Word.SearchResultCollection = context.document.body.search(searchString, { matchCase: false, matchWholeWord: true }).load();``` 129 | ```let paras : Word.ParagraphCollection = context.document.body.paragraphs.load();``` 130 | 131 | Depois que as coleções são carregadas com uma chamada de `context.sync()`, o código cria uma matriz dos intervalos de parágrafos que o usuário exclui da substituição. (Observe que `excludedParagraph` é um parâmetro passado para o método.) 132 | 133 | ```let excludedRanges: Array<Word.Range> = \[];``` 134 | ```excludedRanges.push(paras.items\[excludedParagraph].getRange('Whole'));``` 135 | 136 | Em seguida, o código percorre os itens iteráveis para determinar quais resultados da pesquisa estão dentro de parágrafos excluídos e quais não estão. Para cada resultado da pesquisa, esse fato é registrado em um objeto `IReplacementCandidate`. O método `compareLocationWith()` retornará “Dentro” se o resultado da pesquisa estiver dentro do parágrafo excluído. Retornará "Igual" se o resultado da pesquisa for um parágrafo por si só e tiver sido excluído. 137 | 138 | ``` 139 | for (let i = 0; i < foundItems.items.length; i++) { 140 | for (let j = 0; j < excludedRanges.length; j++) { 141 | replacementCandidates.push({ 142 | range: foundItems.items[i], 143 | locationRelation: foundItems.items[i].compareLocationWith(excludedRanges[j]) 144 | }); 145 | } 146 | } 147 | ``` 148 | Os objetos de candidato de substituição são carregados com uma chamada para `context.sync()` e, em seguida, o código itera por eles, substituindo a cadeia de caracteres de pesquisa por uma cadeia de caracteres de substituição somente nos parágrafos que não estão em um parágrafo excluído. 149 | 150 | ``` 151 | replacementCandidates.forEach(function (item) { 152 | switch (item.locationRelation.value) { 153 | case "Inside": 154 | case "Equal": 155 | break; 156 | default: 157 | item.range.insertText(replaceString, 'Replace'); 158 | } 159 | }); 160 | ``` 161 | Confira o método `replaceDocumentContent` do mesmo arquivo para ver como os métodos do Word `insertText` e `insertParagraph` são usados para inserir conteúdo de exemplo no documento. 162 | 163 | Confira o restante dos arquivos de código para ver como os padrões de design do [Código de Padrões de Design da Experiência do Usuário de Suplemento do Office](https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code) foram integrados à estrutura Angular 2.0. 164 | 165 | ## Perguntas e comentários 166 | 167 | Gostaríamos de saber sua opinião sobre este exemplo. Você pode enviar comentários na seção *Problemas* deste repositório. 168 | 169 | As perguntas sobre o desenvolvimento do Microsoft Office 365 em geral devem ser postadas no [Stack Overflow](http://stackoverflow.com/questions/tagged/office-js+API). Se sua pergunta estiver relacionada às APIs JavaScript para Office, não deixe de marcá-la com as tags \[office-js] e \[API]. 170 | 171 | ## Recursos adicionais 172 | 173 | * [Documentação dos suplementos do Office](https://msdn.microsoft.com/en-us/library/office/jj220060.aspx) 174 | * [Centro de Desenvolvimento do Office](http://dev.office.com/) 175 | * Confira outros exemplos de Suplemento do Office em [OfficeDev no Github](https://github.com/officedev) 176 | 177 | ## Direitos autorais 178 | Copyright (c) 2016 Microsoft Corporation. Todos os direitos reservados. 179 | 180 | 181 | 182 | Este projeto adotou o [Código de Conduta do Código Aberto da Microsoft](https://opensource.microsoft.com/codeofconduct/). Para saber mais, confira [Perguntas frequentes sobre o Código de Conduta](https://opensource.microsoft.com/codeofconduct/faq/) ou contate [opencode@microsoft.com](mailto:opencode@microsoft.com) se tiver outras dúvidas ou comentários. 183 | --------------------------------------------------------------------------------