Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве разъясняется, как выполнить сборку надстройки Outlook, которую можно использовать в режиме создания сообщения для вставки содержимого в его текст.
В этом руководстве описан порядок выполнения перечисленных ниже задач.
- Создание проекта надстройки Outlook
- Определять кнопки, которые отображаются в окне создания сообщения
- Реализация функции первого запуска, которая собирает сведения и извлекает данные из внешней службы
- Реализация кнопки без пользовательского интерфейса, вызывающей функцию
- Реализация области задач, вставляющей содержимое в текст сообщения
Совет
Если вам нужна полная версия этого руководства, посетите репозиторий примеров надстроек Office на сайте GitHub.
Предварительные условия
Node.js (последняя версия Active LTS). Посетите сайтNode.js , чтобы скачать и установить версию, подходящую для вашей операционной системы.
Последняя версия Yeoman и генератора Yeoman для надстроек Office. Выполните в командной строке указанную ниже команду, чтобы установить эти инструменты глобально.
npm install -g yo generator-officeПримечание.
Даже если вы уже установили генератор Yeoman, рекомендуем обновить пакет до последней версии из npm.
Пакет Office, подключенный к подписке Microsoft 365 (включая Office в Интернете).
Примечание.
Если у вас еще нет Office, вы можете претендовать на подписку разработчика Microsoft 365 E5 в рамках программы для разработчиков Microsoft 365; дополнительные сведения см. в разделе "Вопросы и ответы". Также вы можете зарегистрироваться для получения бесплатной пробной версии на 1 месяц или приобрести план Microsoft 365.
Visual Studio Code (VS Code) или предпочитаемый вами редактор кода.
Outlook в Интернете, в Windows (новой или классической) или в Mac.
Учетная запись GitHub .
Setup
Надстройка в этом руководстве считывает gist из учетной записи GitHub и добавляет выбранный gist в текст сообщения. Выполните указанные ниже действия для создания двух новых элементов gist, с помощью которых можно проверить создаваемую надстройку.
-
В поле Gist description... (Описание gist) введите Hello World Markdown.
В поле Filename including extension... (Имя файла с расширением) введите test.md.
Добавьте в многострочное текстовое поле указанную ниже разметку.
# Hello World This is content converted from Markdown! Here's a JSON sample: ```json { "foo": "bar" } ```Нажмите кнопку Create public gist (Создать общедоступный элемент gist).
-
В поле Gist description... (Описание gist) введите Hello World Html.
В поле Filename including extension... (Имя файла с расширением) введите test.html.
Добавьте в многострочное текстовое поле указанную ниже разметку.
<html> <head> <style> h1 { font-family: Calibri; } </style> </head> <body> <h1>Hello World!</h1> <p>This is a test</p> </body> </html>Нажмите кнопку Create public gist (Создать общедоступный элемент gist).
Создание проекта надстройки Outlook
Выполните следующую команду, чтобы создать проект надстройки с помощью генератора Yeoman. Папка, содержащая проект, будет добавлена в текущий каталог.
yo officeПримечание.
При выполнении команды
yo officeможет появиться запрос о политиках сбора данных генератора Yeoman и средств CLI надстройки Office. Используйте предоставленные сведения, чтобы ответить на запросы подходящим образом.При появлении запроса предоставьте следующую информацию для создания проекта надстройки.
Шаги по созданию проекта немного различаются в зависимости от типа манифеста.
Примечание.
Единый манифест для Microsoft 365 позволяет объединить надстройку Office с приложением Teams в приложение для Microsoft 365 в качестве единой единицы разработки и развертывания. Дополнительные сведения см. в статье Надстройки Office с единым манифестом. Пример приложения для Microsoft 365, сочетающего приложение Teams и надстройку Outlook, см. в разделе "Предложения по скидкам".
Мы будем рады вашим отзывам об объединенном манифесте. Если у вас есть предложения, создайте проблему в репозитории для библиотеки Office JavaScript.
Примечание.
Единый манифест для Microsoft 365 в настоящее время не поддерживается в Outlook для Mac. Если вы используете Outlook для Mac, выберите вкладку манифеста только для надстроек и следуйте указанным инструкциям. Дополнительные сведения см. в статье Поддержка надстроек с единым манифестом для Microsoft 365.
Выберите тип проекта -
Office Add-in Task Pane projectВыберите тип сценария -
JavaScriptКак вы хотите назвать свою надстройку? -
Git the gistКакое клиентское приложение Office должно поддерживаться? -
OutlookКакой манифест вы бы хотели использовать? -
unified manifest for Microsoft 365
После завершения работы мастера генератор создаст проект и установит вспомогательные компоненты Node.
Перейдите к корневому каталогу проекта.
cd "Git the gist"Откройте проект в VS Code или используемом вами редакторе кода.
Совет
В Windows вы можете перейти в корневой каталог проекта с помощью командной строки и ввести
code ., чтобы открыть эту папку в VS Code. На компьютере Mac потребуется добавить в путь командуcodeперед использованием этой команды для открытия папки проекта в VS Code.
Обновление манифеста
Манифест надстройки управляет ее отображением в Outlook. Он определяет, как надстройка отображается в списке, а также задает кнопки на ленте и URL-адреса файлов HTML и JavaScript, используемых надстройкой.
Указание основных сведений
Внесите в файл манифеста следующие изменения, чтобы указать основные сведения о надстройке.
Найдите свойство
"description", замените значения по умолчанию"short"и"full"на описания надстройки и сохраните файл."description": { "short": "Gets gists.", "full": "Allows users to access their GitHub gists." },Сохраните файл.
Тестирование созданной надстройки
Прежде чем продолжить, протестируйте базовую надстройку, созданную генератором, чтобы подтвердить правильную настройку проекта.
Примечание.
Надстройки Office должны использовать HTTPS, а не HTTP, даже во время разработки. Если запрос на установку сертификата появится после выполнения одной из следующих команд, примите запрос на установку сертификата, предоставляемый генератором Yeoman. Кроме того, вам может потребоваться запустить командную строку или терминал с правами администратора, чтобы внести изменения.
Если вы впервые разрабатываете надстройку Office на своем компьютере, в командной строке вам может быть предложено предоставить Microsoft Edge WebView исключение замыкания на себя ("Разрешить замыкание localhost на себя для Microsoft Edge WebView?"). При появлении запроса введите
Yразрешение исключения. Обратите внимание, что для разрешения исключения вам потребуются права администратора. Если это разрешение было разрешено, при загрузке неопубликованных надстроек Office в будущем (если вы не удалите исключение со своего компьютера), вам не следует предлагать создать исключение. Дополнительные сведения см. в статье "Не удается открыть эту надстройку с localhost" при загрузке надстройки Office или использовании Fiddler.
Когда вы впервые используете генератор Yeoman для разработки надстройки Office, в браузере по умолчанию открывается окно, в котором вам будет предложено войти в учетную запись Microsoft 365. Если окно входа не открывается и возникает ошибка загрузки неопубликованных приложений или времени ожидания выхода, запустите
atk auth login m365
Выполните следующую команду в корневом каталоге своего проекта. При выполнении этой команды запускается локальный веб-сервер и загружается неопубликованная надстройка.
npm startПримечание.
Когда вы впервые используете генератор Yeoman для разработки надстройки Office, в браузере по умолчанию открывается окно, в котором вам будет предложено войти в учетную запись Microsoft 365. Если окно входа не открывается и возникает ошибка загрузки неопубликованных приложений или времени ожидания входа, запустите
atk auth login m365перед повторным запускомnpm start.Если надстройка не была загружена автоматически, выполните инструкции в статье Загрузка неопубликованных надстроек Outlook для проверки , чтобы вручную загрузить неопубликованную надстройку в Outlook.
Откройте в Outlook существующее сообщение и нажмите кнопку Показать область задач.
При появлении запроса с диалоговым окном Остановка при загрузке веб-представления выберите ОК.
Примечание.
После нажатия кнопки Отменадиалоговое окно не будет отображаться в процессе работы с этим экземпляром надстройки. Однако при перезапуске надстройки диалоговое окно снова появится.
Если все настроено правильно, откроется область задач и отобразится страница приветствия надстройки.
Если вы хотите остановить локальный веб-сервер и удалить надстройку, следуйте соответствующим инструкциям:
Чтобы остановить сервер, выполните следующую команду. Если вы использовали
npm start, следующая команда также должна удалить надстройку.npm stopЕсли вы загрузили неопубликованную надстройку вручную, см. раздел "Удаление неопубликованной надстройки".
Определение кнопок
После проверки работы базовой надстройки можно ее настроить для добавления функций. По умолчанию манифест определяет только кнопки для окна чтения сообщения. Можно обновить манифест, чтобы удалить кнопки из окна чтения сообщения и определить две новые кнопки для окна создания сообщения:
Отображение основного списка: кнопка, открывающая область задач
Insert default gist (Вставить gist по умолчанию): кнопка, вызывающая функцию
Процедура зависит от используемого манифеста.
Выполните следующие действия.
Откройте файл manifest.json .
В массиве
"extensions.runtimes"есть два объекта среды выполнения. Для второго, с"id"of , замените на"insertDefaultGist""actions.id"."CommandsRuntime"Это имя функции, создаваемой на более позднем этапе. Когда все будет готово, объект среды выполнения должен выглядеть следующим образом:{ "id": "CommandsRuntime", "type": "general", "code": { "page": "https://localhost:3000/commands.html" }, "actions": [ { "id": "insertDefaultGist", "type": "executeFunction" } ] }Измените значение элемента массива
"extensions.ribbons.contexts"на"mailCompose". Это означает, что кнопки отображаются только в окне создания сообщения или ответа."contexts": [ "mailCompose" ],Массив
"extensions.ribbons.tabs.groups"содержит объект группы. Внесите следующие изменения в этот объект.- Измените свойство
"id"на"msgComposeCmdGroup". - Измените свойство
"label"на "Git the gist".
- Измените свойство
Тот же объект группы содержит
"controls"массив из двух объектов управления. Нам нужно внести изменения в JSON для каждого из них. В первом из них выполните следующие действия.- Измените на
"id""msgComposeShowGistListTaskPane". - Измените на
"label""Отобразить основной список". - Измените на
"supertip.title""Отобразить основной список". - Измените значение на
"supertip.description""Отображает список основных сообщений и позволяет вставить их содержимое в текущее сообщение".
- Измените на
Во втором объекте управления выполните следующие действия.
- Измените на
"id""msgComposeInsertDefaultGist". - Измените на
"label""Вставить gist по умолчанию". - Измените на
"supertip.title""Вставить gist по умолчанию". - Измените значение на
"supertip.description""Вставляет в текущее сообщение основное сообщение, которое вы пометили как стандартное". - Измените на
"actionId""insertDefaultGist". Это соответствует"action.id"тому"CommandsRuntime", что вы задали на предыдущем шаге.
Когда все будет готово, свойство
"ribbons"должно выглядеть следующим образом:"ribbons": [ { "contexts": [ "mailCompose" ], "tabs": [ { "builtInTabId": "TabDefault", "groups": [ { "id": "msgComposeCmdGroup", "label": "Git the gist", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "controls": [ { "id": "msgComposeInsertGist", "type": "button", "label": "Display gist list", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "supertip": { "title": "Display gist list", "description": "Displays a list of your gists and allows you to insert their contents into the current message." }, "actionId": "TaskPaneRuntimeShow" }, { "id": "msgComposeInsertDefaultGist", "type": "button", "label": "Insert default gist", "icons": [ { "size": 16, "file": "https://localhost:3000/assets/icon-16.png" }, { "size": 32, "file": "https://localhost:3000/assets/icon-32.png" }, { "size": 80, "file": "https://localhost:3000/assets/icon-80.png" } ], "supertip": { "title": "Insert default gist", "description": "Inserts the content of the gist you mark as default into the current message." }, "actionId": "insertDefaultGist" } ] } ] } ] } ]- Измените на
Сохраните изменения манифеста.
Переустановка надстройки
Чтобы изменения манифеста вступили в силу, переустановите надстройку.
Если веб-сервер запущен, выполните следующую команду.
npm stopВыполните указанные ниже команды, чтобы запустить локальный веб-сервер и автоматически загрузить неопубликованную надстройку.
npm start
После переустановки надстройки можно убедиться, что она успешно установлена, выполнив поиск команд "Отобразить список основных идей " и "Вставить основной текст по умолчанию в окне создания сообщения". Обратите внимание, что при выборе этих двух элементов ничего не происходит, так как вы еще не закончили создание этой надстройки.
Если вы запускаете эту надстройку в классической версии Outlook для Windows или в Outlook для Mac, на ленте окна создания сообщения вы должны увидеть две новые кнопки: "Отобразить список основных моментов" и "Вставить основные черты по умолчанию".
Если вы запускаете эту надстройку в Outlook в Интернете или в новом Outlook в Windows, выберите "Приложения " на ленте окна создания сообщения, а затем Git the gist , чтобы увидеть параметры отображения gist list и Insert gist по умолчанию .
Совет
Инструкции по размещению надстроек на ленте см. в статье "Использование надстроек в Outlook".
Реализация интерфейса первого запуска
Эта надстройка должна иметь возможность читать gist из учетной записи GitHub и определять выбранный gist по умолчанию. Для достижения этих целей надстройка предлагает указать имя пользователя GitHub и выбрать gist по умолчанию из коллекции существующих gist. Выполните действия, описанные в этом разделе, чтобы реализовать функцию первого запуска, при которой отображается диалоговое окно для сбора этой информации.
Создание пользовательского интерфейса диалогового окна
Начнем с создания пользовательского интерфейса для диалогового окна.
Создайте в папке ./src новую подпапку с именем settings.
В папке ./src/settings создайте файл с именем dialog.html.
В dialog.htmlдобавьте следующую разметку, чтобы определить базовую форму с текстовым вводом для имени пользователя GitHub и пустым списком для gist, который будет заполняться с помощью JavaScript.
<!doctype html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <title>Settings</title> <!-- Office JavaScript API --> <script type="text/javascript" src="https://officeapis.public.onecdn.static.microsoft/1/office.js"></script> <!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui. --> <link rel="stylesheet" href="https://res-1.cdn.office.net/files/fabric-cdn-prod_20230815.002/office-ui-fabric-core/11.1.0/css/fabric.min.css" /> <!-- Template styles --> <link href="dialog.css" rel="stylesheet" type="text/css" /> </head> <body class="ms-font-l"> <main> <section class="ms-font-m ms-fontColor-neutralPrimary"> <div class="not-configured-warning ms-MessageBar ms-MessageBar--warning"> <div class="ms-MessageBar-content"> <div class="ms-MessageBar-icon"> <i class="ms-Icon ms-Icon--Info"></i> </div> <div class="ms-MessageBar-text"> Oops! It looks like you haven't configured <strong>Git the gist</strong> yet. <br /> Please configure your GitHub username and select a default gist, then try that action again! </div> </div> </div> <div class="ms-font-xxl">Settings</div> <div class="ms-Grid"> <div class="ms-Grid-row"> <div class="ms-TextField"> <label class="ms-Label">GitHub Username</label> <input class="ms-TextField-field" id="github-user" type="text" value="" placeholder="Please enter your GitHub username" /> </div> </div> <div class="error-display ms-Grid-row"> <div class="ms-font-l ms-fontWeight-semibold">An error occurred:</div> <pre><code id="error-text"></code></pre> </div> <div class="gist-list-container ms-Grid-row"> <div class="list-title ms-font-xl ms-fontWeight-regular">Choose Default Gist</div> <form> <div id="gist-list"></div> </form> </div> </div> <div class="ms-Dialog-actions"> <div class="ms-Dialog-actionsRight"> <button class="ms-Dialog-action ms-Button ms-Button--primary" id="settings-done" disabled> <span class="ms-Button-label">Done</span> </button> </div> </div> </section> </main> <script type="text/javascript" src="../helpers/gist-api.js"></script> </body> </html>Вы могли заметить, что HTML-файл ссылается на файл JavaScript gist-api.js, который еще не существует. Этот файл будет создан в разделе Fetch data from GitHub .
Сохраните изменения.
Затем создайте файл с именем dialog.css в папке ./src/settings.
В dialog.css добавьте следующий код, чтобы указать стили, используемые dialog.html.
body { background-color: #ffffff; } section { margin: 10px 20px; } .not-configured-warning { display: none; } .error-display { display: none; } .gist-list-container { margin: 10px -8px; display: none; } .list-title { border-bottom: 1px solid #a6a6a6; padding-bottom: 5px; } ul { margin-top: 10px; } .ms-ListItem-secondaryText, .ms-ListItem-tertiaryText { padding-left: 15px; }Сохраните изменения.
Разработка функционала диалога
Теперь, после определения пользовательского интерфейса диалогового окна, можно написать код для выполнения в нем действий.
В папке ./src/settings создайте файл с именем dialog.js.
Добавьте в него указанный ниже код.
(function () { "use strict"; // The onReady function must be run each time a new page is loaded. Office.onReady(function () { function initializeDialog() { if (window.location.search) { // Check if warning should be displayed. const warn = getParameterByName("warn"); if (warn) { document.querySelector(".not-configured-warning").style.display = "block"; } else { // See if the config values were passed. // If so, pre-populate the values. const user = getParameterByName("gitHubUserName"); const gistId = getParameterByName("defaultGistId"); document.getElementById("github-user").value = user; loadGists(user, function (success) { if (success) { document.querySelectorAll(".ms-ListItem").forEach(function (item) { item.classList.remove("is-selected"); if (item.value === gistId) { item.classList.add("is-selected"); item.checked = true; } }); document.getElementById("settings-done").disabled = false; } }); } } // When the GitHub username changes, try to load gists. document.getElementById("github-user").addEventListener("change", function () { document.getElementById("gist-list").textContent = ""; const ghUser = document.getElementById("github-user").value; if (ghUser.length > 0) { loadGists(ghUser); } }); // When the Done button is selected, send the values back to the caller as a serialized object. document.getElementById("settings-done").addEventListener("click", function () { const settings = {}; settings.gitHubUserName = document.getElementById("github-user").value; const selectedGist = document.querySelector(".ms-ListItem.is-selected"); if (selectedGist) { settings.defaultGistId = selectedGist.value; sendMessage(JSON.stringify(settings)); } }); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initializeDialog); } else { initializeDialog(); } }); // Load gists using the GitHub API and build the list. function loadGists(user, callback) { getUserGists(user, function (gists, error) { if (error) { document.querySelector(".gist-list-container").style.display = "none"; document.getElementById("error-text").textContent = JSON.stringify(error, null, 2); document.querySelector(".error-display").style.display = "block"; if (callback) callback(false); } else { document.querySelector(".error-display").style.display = "none"; buildGistList(document.getElementById("gist-list"), gists, onGistSelected); document.querySelector(".gist-list-container").style.display = "block"; if (callback) callback(true); } }); } function onGistSelected() { document.querySelectorAll(".ms-ListItem").forEach(function (item) { item.classList.remove("is-selected"); item.checked = false; }); const selectedItem = this.querySelector(".ms-ListItem"); selectedItem.classList.add("is-selected"); selectedItem.checked = true; document.querySelector(".not-configured-warning").style.display = "none"; document.getElementById("settings-done").disabled = false; } function sendMessage(message) { Office.context.ui.messageParent(message); } function getParameterByName(name, url) { return new URL(url || window.location.href).searchParams.get(name); } })();Сохраните изменения.
Обновление настроек конфигурации webpack
Наконец, откройте файл webpack.config.js, расположенный в корневом каталоге проекта, и выполните описанные ниже шаги.
Найдите объект
entryв объектеconfigи добавьте новую запись дляdialog.dialog: "./src/settings/dialog.js",После этого новый
entryобъект будет выглядеть следующим образом:entry: { polyfill: ["core-js/stable", "regenerator-runtime/runtime"], taskpane: ["./src/taskpane/taskpane.js", "./src/taskpane/taskpane.html"], commands: "./src/commands/commands.js", dialog: "./src/settings/dialog.js", },Найдите массив
pluginsв объектеconfig. В массивpatternsобъектаnew CopyWebpackPluginдобавьте новые записи для taskpane.css и dialog.css.{ from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", },После этого
new CopyWebpackPluginобъект будет выглядеть следующим образом. Обратите внимание на небольшую разницу, если надстройка использует манифест только надстройки.new CopyWebpackPlugin({ patterns: [ { from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", }, { from: "assets/*", to: "assets/[name][ext][query]", }, { from: "manifest*.*", to: "[name]" + "[ext]", transform(content) { if (dev) { return content; } else { return content.toString().replace(new RegExp(urlDev, "g"), urlProd); } }, }, ]}),В том же массиве
pluginsв объектеconfigдобавьте этот новый объект в конец массива.new HtmlWebpackPlugin({ filename: "dialog.html", template: "./src/settings/dialog.html", chunks: ["polyfill", "dialog"] })После этого новый
pluginsмассив будет выглядеть следующим образом. Обратите внимание на небольшую разницу, если надстройка использует манифест только надстройки.plugins: [ new HtmlWebpackPlugin({ filename: "taskpane.html", template: "./src/taskpane/taskpane.html", chunks: ["polyfill", "taskpane"], }), new CopyWebpackPlugin({ patterns: [ { from: "./src/taskpane/taskpane.css", to: "taskpane.css", }, { from: "./src/settings/dialog.css", to: "dialog.css", }, { from: "assets/*", to: "assets/[name][ext][query]", }, { from: "manifest*.*", to: "[name]." + buildType + "[ext]", transform(content) { if (dev) { return content; } else { return content.toString().replace(new RegExp(urlDev, "g"), urlProd); } }, }, ], }), new HtmlWebpackPlugin({ filename: "commands.html", template: "./src/commands/commands.html", chunks: ["polyfill", "commands"], }), new HtmlWebpackPlugin({ filename: "dialog.html", template: "./src/settings/dialog.html", chunks: ["polyfill", "dialog"] }) ],
Получение данных из GitHub
Только что созданный файл dialog.js определяет, что надстройка должна загружать элементы gist, если возникает событие change для поля имени пользователя GitHub. Чтобы получить gist из GitHub, вы будете использовать API GitHub Gists.
Создайте в папке ./src новую подпапку с именем helpers.
В папке ./src/helpers создайте файл с именем gist-api.js.
В gist-api.jsдобавьте следующий код, чтобы получить gist из GitHub и создать список gist.
function getUserGists(user, callback) { const requestUrl = "https://api.github.com/users/" + encodeURIComponent(user) + "/gists"; fetchJson(requestUrl, callback); } function buildGistList(parent, gists, clickFunc) { gists.forEach(function (gist) { const listItem = document.createElement("div"); parent.appendChild(listItem); const radioItem = document.createElement("input"); radioItem.classList.add("ms-ListItem", "is-selectable"); radioItem.type = "radio"; radioItem.name = "gists"; radioItem.tabIndex = 0; radioItem.value = gist.id; listItem.appendChild(radioItem); const descPrimary = document.createElement("span"); descPrimary.classList.add("ms-ListItem-primaryText"); descPrimary.textContent = gist.description; listItem.appendChild(descPrimary); const descSecondary = document.createElement("span"); descSecondary.classList.add("ms-ListItem-secondaryText"); descSecondary.textContent = " - " + buildFileList(gist.files); listItem.appendChild(descSecondary); const updated = new Date(gist.updated_at); const descTertiary = document.createElement("span"); descTertiary.classList.add("ms-ListItem-tertiaryText"); descTertiary.textContent = " - Last updated " + updated.toLocaleString(); listItem.appendChild(descTertiary); listItem.addEventListener("click", clickFunc); }); } function buildFileList(files) { let fileList = ""; for (let file in files) { if (files.hasOwnProperty(file)) { if (fileList.length > 0) { fileList = fileList + ", "; } fileList = fileList + files[file].filename + " (" + files[file].language + ")"; } } return fileList; }Сохраните изменения.
Выполните указанную ниже команду, чтобы повторно собрать проект.
npm run build
Реализация кнопки без пользовательского интерфейса
Кнопка "Вставить gist по умолчанию" этой надстройки — это кнопка без пользовательского интерфейса, которая вызывает функцию JavaScript, а не открывает область задач, как многие кнопки надстроек. При нажатии кнопки "Вставить gist по умолчанию " соответствующая функция JavaScript проверяет, настроена ли надстройка.
Если надстройка уже настроена, функция загружает содержимое основного текста, выбранного вами по умолчанию, и вставляет его в текст сообщения.
Если надстройка еще не настроена, в диалоговом окне "Параметры" появится запрос на ввод имени пользователя GitHub.
Обновление файла функции (HTML)
Функция, вызываемая кнопкой без пользовательского интерфейса, должна быть определена в файле, указанном в элементе <FunctionFile> манифеста для соответствующего форм-фактора. Этот манифест надстройки указывает https://localhost:3000/commands.html в качестве файла функции.
Откройте ./src/commands/commands.html и замените все содержимое следующей разметкой.
<!doctype html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <!-- Office JavaScript API --> <script type="text/javascript" src="https://officeapis.public.onecdn.static.microsoft/1/office.js"></script> <script type="text/javascript" src="../helpers/addin-config.js"></script> <script type="text/javascript" src="../helpers/gist-api.js"></script> </head> <body> <!-- NOTE: The body is empty on purpose. Since functions in commands.js are invoked via a button, there is no UI to render. --> </body> </html>Вы могли заметить, что HTML-файл ссылается на файл JavaScript addin-config.js, который еще не существует. Этот файл будет создан в этом руководстве в разделе Создание файла для управления параметрами конфигурации ниже.
Сохраните изменения.
Обновление файла функции (JavaScript)
Откройте файл ./src/commands/commands.js и замените все содержимое приведенным ниже кодом. Обратите внимание, что если функция insertDefaultGist определяет, что надстройка еще не настроена, она добавляет
?warn=1параметр в URL-адрес диалогового окна. В результате диалоговое окно параметров отображает панель сообщений, определенную в ./src/settings/dialog.html, чтобы сообщить, почему вы видите диалоговое окно.let config; let btnEvent; // The onReady function must be run each time a new page is loaded. Office.onReady(); function showError(error) { Office.context.mailbox.item.notificationMessages.replaceAsync( "github-error", { type: "errorMessage", message: error, }, function (result) {} ); } let settingsDialog; function insertDefaultGist(event) { config = getConfig(); // Check if the add-in has been configured. if (config && config.defaultGistId) { // Get the default gist content and insert. try { getGist(config.defaultGistId, function (gist, error) { if (gist) { buildBodyContent(gist, function (content, error) { if (content) { Office.context.mailbox.item.body.setSelectedDataAsync( content, { coercionType: Office.CoercionType.Html }, function (result) { event.completed(); } ); } else { showError(error); event.completed(); } }); } else { showError(error); event.completed(); } }); } catch (err) { showError(err); event.completed(); } } else { // Save the event object so we can finish up later. btnEvent = event; // Not configured yet, display settings dialog with warn=1 to display warning. const url = new URL("dialog.html?warn=1", window.location.href).toString(); const dialogOptions = { width: 20, height: 40, displayInIframe: true }; Office.context.ui.displayDialogAsync(url, dialogOptions, function (result) { settingsDialog = result.value; settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived, receiveMessage); settingsDialog.addEventHandler(Office.EventType.DialogEventReceived, dialogClosed); }); } } // Register the function. Office.actions.associate("insertDefaultGist", insertDefaultGist); function receiveMessage(message) { config = JSON.parse(message.message); setConfig(config, function (result) { settingsDialog.close(); settingsDialog = null; btnEvent.completed(); btnEvent = null; }); } function dialogClosed(message) { settingsDialog = null; btnEvent.completed(); btnEvent = null; }Сохраните изменения.
Создание файла для управления параметрами конфигурации
В папке ./src/helpers создайте файл с именем addin-config.js и добавьте указанный ниже код. В этом коде используется объект RoamingSettings, позволяющий получать и задавать значения конфигурации.
function getConfig() { const config = {}; config.gitHubUserName = Office.context.roamingSettings.get('gitHubUserName'); config.defaultGistId = Office.context.roamingSettings.get('defaultGistId'); return config; } function setConfig(config, callback) { Office.context.roamingSettings.set('gitHubUserName', config.gitHubUserName); Office.context.roamingSettings.set('defaultGistId', config.defaultGistId); Office.context.roamingSettings.saveAsync(callback); }Сохраните изменения.
Создание новых функций для обработки элементов gist
Затем откройте файл ./src/helpers/gist-api.js и добавьте указанные ниже функции. Обратите внимание на следующее:
Если суть содержит HTML, надстройка вставляет HTML "как есть" в текст сообщения.
Если суть содержит Markdown, надстройка использует API GitHub Markdown для преобразования Markdown в HTML, а затем вставляет полученный HTML в текст сообщения.
Если элемент gist содержит любой код, отличный от HTML или Markdown, надстройка вставит его в текст сообщения как фрагмент кода.
function getGist(gistId, callback) { const requestUrl = "https://api.github.com/gists/" + encodeURIComponent(gistId); fetchJson(requestUrl, callback); } function fetchJson(url, callback) { fetch(url, { headers: { Accept: "application/vnd.github+json" } }) .then(function (response) { if (!response.ok) { throw new Error("GitHub request failed: " + response.status + " " + response.statusText); } return response.json(); }) .then(function (data) { callback(data); }) .catch(function (error) { callback(null, error); }); } function buildBodyContent(gist, callback) { // Find the first non-truncated file in the gist and use it. for (let filename in gist.files) { if (gist.files.hasOwnProperty(filename)) { const file = gist.files[filename]; if (!file.truncated) { switch (file.language) { case "HTML": // Insert as is. callback(file.content); break; case "Markdown": // Use GitHub's renderer so gist Markdown matches github.com. fetch("https://api.github.com/markdown", { method: "POST", headers: { Accept: "application/vnd.github+json", "Content-Type": "application/json", }, body: JSON.stringify({ text: file.content, mode: "gfm" }), }) .then(function (response) { if (!response.ok) { throw new Error("GitHub Markdown request failed: " + response.status + " " + response.statusText); } return response.text(); }) .then(function (html) { callback(html); }) .catch(function (error) { callback(null, error); }); break; default: // Insert contents as a <code> block. const codeElement = document.createElement("code"); codeElement.textContent = file.content; const preElement = document.createElement("pre"); preElement.appendChild(codeElement); callback(preElement.outerHTML); } return; } } } callback(null, "No suitable file found in the gist"); }Сохраните изменения.
Тестирование кнопки Insert default gist (Вставить gist по умолчанию)
Если локальный веб-сервер еще не запущен, запустите
npm startего из командной строки.Откройте Outlook и создайте новое сообщение.
В окне создания сообщения нажмите кнопку Insert default gist (Вставить gist по умолчанию). Появится диалоговое окно с предложением указать имя пользователя GitHub.
В диалоговом окне параметров введите свое имя пользователя GitHub, а затем нажмите клавишу TAB или щелкните в другом месте диалогового окна, чтобы вызвать событие изменения . Это действие загружает ваш список общедоступных gist. Выберите общую кнопку, которая будет использоваться по умолчанию, затем нажмите "Готово".
Снова нажмите кнопку Insert default gist (Вставить gist по умолчанию). На этот раз содержимое основного текста по умолчанию вставляется в текст сообщения.
Примечание.
Классический Outlook для Windows: чтобы выбрать последние параметры, может потребоваться закрыть и снова открыть окно создания сообщения.
Реализация области задач
Кнопка "Отобразить список основных идей" в этой надстройке открывает область задач и отображает ваши основные черты. Затем можно выбрать одну из основ для вставки в текст сообщения. Если надстройка еще не настроена, вам будет предложено это сделать.
Указание HTML для области задач
В созданном вами проекте HTML области задач указан в файле ./src/taskpane/taskpane.html. Откройте этот файл и замените все содержимое приведенной ниже разметкой.
<!doctype html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Contoso Task Pane Add-in</title> <!-- Office JavaScript API --> <script type="text/javascript" src="https://officeapis.public.onecdn.static.microsoft/1/office.js"></script> <!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui. --> <link rel="stylesheet" href="https://res-1.cdn.office.net/files/fabric-cdn-prod_20230815.002/office-ui-fabric-core/11.1.0/css/fabric.min.css" /> <!-- Template styles --> <link href="taskpane.css" rel="stylesheet" type="text/css" /> </head> <body class="ms-font-l ms-landing-page"> <main class="ms-landing-page__main"> <section class="ms-landing-page__content ms-font-m ms-fontColor-neutralPrimary"> <div id="not-configured" style="display: none"> <div class="centered ms-font-xxl ms-u-textAlignCenter">Welcome!</div> <div class="ms-font-xl" id="settings-prompt"> Please choose the <strong>Settings</strong> icon at the bottom of this window to configure this add-in. </div> </div> <div id="gist-list-container" style="display: none"> <form> <div id="gist-list"></div> </form> </div> <div id="error-display" style="display: none" class="ms-u-borderBase ms-fontColor-error ms-font-m ms-bgColor-error ms-borderColor-error"></div> </section> <button class="ms-Button ms-Button--primary" id="insert-button" tabindex="0" disabled> <span class="ms-Button-label">Insert</span> </button> </main> <footer class="ms-landing-page__footer ms-bgColor-themePrimary"> <div class="ms-landing-page__footer--left"> <img src="../../assets/logo-filled.png" /> <h1 class="ms-font-xl ms-fontWeight-semilight ms-fontColor-white">Git the gist</h1> </div> <div id="settings-icon" class="ms-landing-page__footer--right" aria-label="Settings" tabindex="0"> <i class="ms-Icon enlarge ms-Icon--Settings ms-fontColor-white"></i> </div> </footer> <script type="text/javascript" src="../helpers/addin-config.js"></script> <script type="text/javascript" src="../helpers/gist-api.js"></script> </body> </html>Сохраните изменения.
Указание CSS для области задач
В созданном вами проекте CSS области задач указан в файле ./src/taskpane/taskpane.css. Откройте этот файл и замените все содержимое приведенным ниже кодом.
/* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */ html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: auto; } body { position: relative; font-size: 16px; background-color: #ffffff; } main { height: 100%; overflow-y: auto; } footer { width: 100%; position: relative; bottom: 0; margin-top: 10px; } p, h1, h2, h3, h4, h5, h6 { margin: 0; padding: 0; } ul { padding: 0; } #settings-prompt { margin: 10px 0; } #error-display { padding: 10px; } #insert-button { margin: 0 10px; } .clearfix { display: block; clear: both; height: 0; } .pointerCursor { cursor: pointer; } .invisible { visibility: hidden; } .undisplayed { display: none; } .ms-Icon.enlarge { position: relative; font-size: 20px; top: 4px; } .ms-ListItem-secondaryText, .ms-ListItem-tertiaryText { padding-left: 15px; } .ms-landing-page { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; height: 100%; } .ms-landing-page__main { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; -webkit-flex: 1 1 0; flex: 1 1 0; height: 100%; } .ms-landing-page__content { display: -webkit-flex; display: flex; -webkit-flex-direction: column; flex-direction: column; -webkit-flex-wrap: nowrap; flex-wrap: nowrap; height: 100%; -webkit-flex: 1 1 0; flex: 1 1 0; padding: 20px; } .ms-landing-page__content h2 { margin-bottom: 20px; } .ms-landing-page__footer { display: -webkit-inline-flex; display: inline-flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; } .ms-landing-page__footer--left { transition: background ease 0.1s, color ease 0.1s; display: -webkit-inline-flex; display: inline-flex; -webkit-justify-content: flex-start; justify-content: flex-start; -webkit-align-items: center; align-items: center; -webkit-flex: 1 0 0px; flex: 1 0 0px; padding: 20px; } .ms-landing-page__footer--left:active { cursor: default; } .ms-landing-page__footer--left--disabled { opacity: 0.6; pointer-events: none; cursor: not-allowed; } .ms-landing-page__footer--left--disabled:active, .ms-landing-page__footer--left--disabled:hover { background: transparent; } .ms-landing-page__footer--left img { width: 40px; height: 40px; } .ms-landing-page__footer--left h1 { -webkit-flex: 1 0 0px; flex: 1 0 0px; margin-left: 15px; text-align: left; width: auto; max-width: auto; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .ms-landing-page__footer--right { transition: background ease 0.1s, color ease 0.1s; padding: 29px 20px; } .ms-landing-page__footer--right:active, .ms-landing-page__footer--right:hover { background: #005ca4; cursor: pointer; } .ms-landing-page__footer--right:active { background: #005ca4; } .ms-landing-page__footer--right--disabled { opacity: 0.6; pointer-events: none; cursor: not-allowed; } .ms-landing-page__footer--right--disabled:active, .ms-landing-page__footer--right--disabled:hover { background: transparent; }Сохраните изменения.
Указание JavaScript для области задач
В созданном вами проекте область задач JavaScript указана в файле ./src/taskpane/taskpane.js. Откройте этот файл и замените все содержимое приведенным ниже кодом.
(function () { "use strict"; let config; let settingsDialog; Office.onReady(function () { function initializeTaskPane() { config = getConfig(); // Check if add-in is configured. if (config && config.gitHubUserName) { // If configured, load the gist list. loadGists(config.gitHubUserName); } else { // Not configured yet. document.getElementById("not-configured").style.display = ""; } // When insert button is selected, build the content and insert into the body. document.getElementById("insert-button").addEventListener("click", function () { const selectedGist = document.querySelector(".ms-ListItem.is-selected"); const gistId = selectedGist && selectedGist.value; getGist(gistId, function (gist, error) { if (gist) { buildBodyContent(gist, function (content, error) { if (content) { Office.context.mailbox.item.body.setSelectedDataAsync( content, { coercionType: Office.CoercionType.Html }, function (result) { if (result.status === Office.AsyncResultStatus.Failed) { showError("Could not insert gist: " + result.error.message); } } ); } else { showError("Could not create insertable content: " + error); } }); } else { showError("Could not retrieve gist: " + error); } }); }); // When the settings icon is selected, open the settings dialog. document.getElementById("settings-icon").addEventListener("click", function () { // Display settings dialog. const url = new URL("dialog.html", window.location.href); if (config) { // If the add-in has already been configured, pass the existing values to the dialog. url.searchParams.set("gitHubUserName", config.gitHubUserName); url.searchParams.set("defaultGistId", config.defaultGistId); } const dialogOptions = { width: 20, height: 40, displayInIframe: true }; Office.context.ui.displayDialogAsync(url.toString(), dialogOptions, function (result) { settingsDialog = result.value; settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived, receiveMessage); settingsDialog.addEventHandler(Office.EventType.DialogEventReceived, dialogClosed); }); }); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initializeTaskPane); } else { initializeTaskPane(); } }); function loadGists(user) { document.getElementById("error-display").style.display = "none"; document.getElementById("not-configured").style.display = "none"; document.getElementById("gist-list-container").style.display = ""; getUserGists(user, function (gists, error) { if (error) { } else { const gistList = document.getElementById("gist-list"); gistList.textContent = ""; buildGistList(gistList, gists, onGistSelected); } }); } function onGistSelected() { document.getElementById("insert-button").disabled = false; document.querySelectorAll(".ms-ListItem").forEach(function (item) { item.classList.remove("is-selected"); item.checked = false; }); const selectedItem = this.querySelector(".ms-ListItem"); selectedItem.classList.add("is-selected"); selectedItem.checked = true; } function showError(error) { document.getElementById("not-configured").style.display = "none"; document.getElementById("gist-list-container").style.display = "none"; const errorDisplay = document.getElementById("error-display"); errorDisplay.textContent = error; errorDisplay.style.display = ""; } function receiveMessage(message) { config = JSON.parse(message.message); setConfig(config, function (result) { settingsDialog.close(); settingsDialog = null; loadGists(config.gitHubUserName); }); } function dialogClosed(message) { settingsDialog = null; } })();Сохраните изменения.
Проверьте кнопку "Отобразить список основных идей"
Если локальный веб-сервер еще не запущен, запустите
npm startего из командной строки.Откройте Outlook и создайте новое сообщение.
В окне создания сообщения нажмите кнопку Отобразить список основных сведений . Откроется область задач.
В области задач выберите элемент gist Hello World Html и нажмите кнопку Insert (Вставить) для вставки этого элемента gist в текст сообщения.
Дальнейшие действия
С помощью этого руководства вы выполнили сборку надстройки Outlook, которую можно использовать в режиме создания сообщения для вставки содержимого в его текст. Чтобы узнать больше о разработке надстроек Outlook, перейдите к следующей статье.
Примеры кода
- Пройденное руководство по надстройке Outlook: результат выполнения этого руководства.
См. также
Office Add-ins