word.run 在服务器环境中不工作
word.run did not work in server enviroment
绑定对象 (Word)
URL: https://dev.office.com/reference/add-ins/shared/bindings.bindings
创建变量绑定:
- 使用 Office.context.document.getSelectedDataAsync(),asyncResult.value(响应)使用 TextBinding 添加
Office.context.document.bindings.addFromSelectionAsync() 到当前选择
填充内容
- 使用 Binding.setDataAsync 方法,我们将数据写入由指定绑定对象表示的文档的绑定部分。
此时的问题是我们无法设置 {coercionType: "html"} 以在文档的绑定部分插入富文本,它适用于文本。
问题:
- 无法在 Online word 中使用 setDataAsync() 插入富文本
- 无法使用 bindingId 主动选择内容,这将帮助我们使用 Office.context.document.setSelectedDataAsync() 将数据写入文档中的当前选择(富文本适用于此 API ).使用此方法前需要解除绑定
- 无法通过在 Office.initialize 之后将函数传递到 Word.run() 方法来执行
Word.run(函数(上下文){});
没有控制台错误或警告,但 Word.run() 块在尝试通过服务器执行代码时从未运行。本地开发环境在这种情况下有效。
Error Reference Picture
清单
<?xml version="1.0" encoding="UTF-8"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
<!-- BeginBasicSettings: Add-in metadata, used for all versions of Office unless override provided -->
<!--IMPORTANT! Id must be unique for your add-in, if you clone this manifest ensure that you change this id to your own GUID -->
<Id>010861c8-0558-472c-b350-f7795e27cfa5</Id>
<!--Version. Updates from the store only get triggered if there is a version change -->
<Version>1.0.0.0</Version>
<ProviderName>Parrot365 : [QA]</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<!-- The display name of your add-in. Used on the store and various placed of the Office UI such as the add-ins dialog -->
<DisplayName DefaultValue="Parrot365 : [QA]" />
<Description DefaultValue="Parrot365 : QA Mode"/>
<!--Icon for your add-in. Used on installation screens and the add-ins dialog -->
<IconUrl DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png" />
<HighResolutionIconUrl DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_128px.png" />
<SupportUrl DefaultValue="http://support.wittyparrot.com/support/home" />
<!--BeginTaskpaneMode integration. Office 2013 and any client that doesn't understand commands will use this section.
This section will also be used if there are no VersionOverrides -->
<Hosts>
<Host Name="Document" />
<Host Name="Workbook" />
<Host Name="Presentation" />
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice" />
</DefaultSettings>
<!--EndTaskpaneMode integration -->
<Permissions>ReadWriteDocument</Permissions>
<!--BeginAddinCommandsMode integration-->
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<!-- Optional, override the description of the Add-in -->
<Description resid="residToolTip" />
<!--Required, hosts node. Each host can have a different set of commands -->
<Hosts>
<!--Specific host. Workbook=Excel, Document=Word, Presentation=PowerPoint -->
<Host xsi:type="Document">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
<Host xsi:type="Workbook">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
<Host xsi:type="Presentation">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="icon1_16x16" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/widget_logo.png">
</bt:Image>
<bt:Image id="icon1_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
<bt:Image id="icon1_80x80" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_80px.png">
</bt:Image>
<bt:Image id="icon2_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
<bt:Image id="icon3_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
</bt:Images>
<bt:Urls>
<bt:Url id="residDesktopFuncUrl" DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice">
</bt:Url>
<bt:Url id="residUnitConverterUrl" DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice">
</bt:Url>
<!--LearnMore URL currently not used -->
<bt:Url id="Witty.GetStarted.LearnMoreUrl" DefaultValue="https://qaparrot365.wittyparrot.com">
</bt:Url>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residLabel" DefaultValue="Launch Widget">
</bt:String>
<bt:String id="residLabel3" DefaultValue="Parrot365">
</bt:String>
<bt:String id="residLabel4" DefaultValue=" ">
</bt:String>
<bt:String id="Witty.GetStarted.Title" DefaultValue="Parrot365 Widget Loaded Successfully">
</bt:String>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residToolTip" DefaultValue="Parrot365 add-in provides improves productivity, accuracy and consistency in communication.">
</bt:String>
<bt:String id="Witty.GetStarted.Description" DefaultValue="Get going by opening the Home tab on the Ribbon then click Parrot365 button">
</bt:String>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>
'use strict';
var count = 0;
(function() {
angular.module('wpoffice')
.directive('wittyWordVariable', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'app/components/witty-word-variable/witty-word-variable_template.html',
scope: {},
bindToController: true,
controller: 'WordVariableController',
controllerAs: 'WordVariableCtrl'
};
})
.controller('WordVariableController', WordVariableController);
function WordVariableController($q, ngNotify) {
var vm = this;
vm.init = init;
vm.getSelectedWordFromDocument = getSelectedWordFromDocument;
vm.populateWordVar = populateWordVar;
function init() {
console.log('Initialized WordVariableController');
vm.inputBoxObjects = [];
vm.varValues = [];
vm.onloadVariablesFound = [];
if (Office.context.document) {
getAllSelectedContentControl();
} else {
ngNotify.set('Please reload Parrot365', 'error');
}
}
/*
*getAllSelectedContentControl----it will load the variable and corresponding text box
*@param --- no param
*/
function getAllSelectedContentControl() {
console.log('getAllSelectedContentControl');
console.log(Word);
Word.run(function(context) {
console.log('inside getSelectedContentControl 2');
var thisDocument = context.document;
context.load(thisDocument, 'contentControls/id, contentControls/text, contentControls/tag');
return context.sync().then(function() {
console.log('returned getSelectedContentControl');
if (thisDocument.contentControls.items.length !== 0) {
console.log(thisDocument.contentControls.items.length);
for (var i = 0; i < thisDocument.contentControls.items.length; i++) {
var variableLabel = thisDocument.contentControls.items[i].text;
var tagId = thisDocument.contentControls.items[i].tag;
if (tagId) {
getVarArray(variableLabel,tagId).then(function(arrayObj) {
createInputboxes(arrayObj);
});
}
}
} else {
console.log('Content is empty');
}
});
}).then(function() {
console.log('completed');
})
.catch(function(error) {
console.log('Error: ' + error);
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
console.log('Error code and message: ' + error.toString());
}
});
}
/*
*getVarArray----creates object on load
*@param variablevalue---value of variable
*@param TagId -----id of variable
*/
function getVarArray(variablevalue,tagId)
{
var deferred = $q.defer();
var allBindings = [];
var tagPrefix, variableLabel;
if (tagId && tagId.lastIndexOf("__") != -1) {
tagPrefix = tagId.substr(0,tagId.lastIndexOf('__'));
var index = tagId.indexOf("_");
if(index) {
variableLabel = tagId.substr(0,index);
}
}
var temp = {
'id': tagId,
'variableLabel': variableLabel,
'tagPrefix': tagPrefix,
'value': variablevalue
};
var indexOfBinding = _.findIndex(allBindings, {
variableLabel: variableLabel,
tagPrefix: tagPrefix
});
if (indexOfBinding === -1) {
allBindings.push(temp);
}
deferred.resolve(allBindings);
return deferred.promise;
}
/*
*createInputboxes ----call createVariable function which will create scope obj
*/
function createInputboxes(arrayOfBindinds)
{
angular.forEach(arrayOfBindinds, function(binding) {
console.log(binding);
var textBoxValue = binding.value ? binding.value:'Enter Text';
console.log(binding.variableLabel+'===='+binding.tagPrefix+'===='+textBoxValue+'===='+binding.id);
createVariable (binding.variableLabel,binding.tagPrefix,textBoxValue,binding.id);
});
}
/*getSelectedWord - Get Selected Data from the document which user has selected manually.
*@no param
*called on user selection
*
*/
function getSelectedWordFromDocument()
{
console.log('abc');
Word.run(function(context) {
console.log('inside word.run');
var range = context.document.getSelection();
var ContentControlForSelection = range.insertContentControl();
ContentControlForSelection.load('text');
return context.sync().then(function() {
var variableLabel = ContentControlForSelection.text;
var tagPrefix = variableLabel + '_tag';
ContentControlForSelection.tag = tagPrefix + '__' + count;
//var conditionalVariable = 'Onseletion';
//createVariable(variableLabel, tagPrefix);
console.log('variable created with'+variableLabel);
getVarArrayOnSelection(ContentControlForSelection.tag,variableLabel, tagPrefix).then(function(bindings) {
console.log(bindings);
createInputboxes(bindings);
});
});
})
.catch(function(error) {
console.log('Error: ' + error);
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
/*
*getVarArrayOnSelection --- it creates obj for selected word in document
*@param--tagId
*@param--userSelectedText
*@param--tagPrefix
*/
function getVarArrayOnSelection(tagId,userSelectedText,tagPrefix)
{
var deferred = $q.defer();
var allBindings = [];
var temp = {
'id': tagId,
'variableLabel': userSelectedText,
'tagPrefix': tagPrefix
};
var indexOfBinding = _.findIndex(allBindings, {
variableLabel: userSelectedText,
tagPrefix: tagPrefix
});
if (indexOfBinding === -1) {
allBindings.push(temp);
}
deferred.resolve(allBindings);
return deferred.promise;
}
function createVariable(variableLabel, tagPrefix, newValue, id) {
console.log(variableLabel+'===='+ tagPrefix+'===='+ newValue+'===='+ id);
var flag = false;
var inputObj = {
id: id,
label: variableLabel,
tag: tagPrefix,
value: newValue
};
if (vm.inputBoxObjects.length > 0) {
var index = _.findIndex(vm.inputBoxObjects, {
label: variableLabel
});
if (index === -1) {
vm.inputBoxObjects.push(inputObj);
} else {
console.log('it already exists in the array');
}
} else {
vm.inputBoxObjects.push(inputObj);
}
}
/*populateWordVar
*@TextBoxId = Text Box Id
*@tagPrefix = unique identifier
**/
function populateWordVar(obj, $event, $index)
{
console.log(obj);
var TextboxValue = ($event.target.value === '' ? obj.label : $event.target.value);
console.log(TextboxValue);
Word.run(function (context) {
var contentControlsWithTag = context.document.contentControls.getByTag(obj.id);
context.load(contentControlsWithTag, 'text');
return context.sync().then(function () {
if (contentControlsWithTag.items.length === 0) {
console.log("There isn't a content control with a tag in this document.");
} else {
console.log('The first content control with the tag has this text: ' + contentControlsWithTag.items[0].text);
for (var i = 0;i<contentControlsWithTag.items.length;i++){
contentControlsWithTag.items[i].insertHtml(TextboxValue, 'Replace');
}
}
});
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
}
})();
<div class="flex layout-column pad-box-10 profile-container" ng-init="WordVariableCtrl.init()">
<div class="layout-row">
<button class="ms-Button ms-Button--primary" ng-click="WordVariableCtrl.getSelectedWordFromDocument ()">
<span class="ms-Button-label">Create Variable</span>
</button>
</div>
<div class="layout-row">
<div class="layout-column">
<div ng-if="WordVariableCtrl.inputBoxObjects.length > 0" class="layout-row flex layout-align-start-center margin-d-10" id="innerDiv" data-ng-repeat="inputBox in WordVariableCtrl.inputBoxObjects">
<label class="ms-Label margin-r-10" for="{{inputBox.id}}" style="width:40%;overflow: hidden;display: inline-block;
text-overflow: ellipsis;white-space: nowrap;">{{inputBox.label}}</label>
<input type="text" name="" placeholder="Enter value" value="{{inputBox.value}}" id={{inputBox.id}} ng-blur="WordVariableCtrl.populateWordVar(inputBox,$event,$index)" class="ms-TextField-field flex flex-rem send-email-input">
</div>
</div>
</div>
</div>
您的清单声明您的 add-in 适用于 Word、PowerPoint 和 Excel,但它指向的代码正在利用 Word Api。您应该确保您的清单声明对 Word API 的依赖并删除 Excel 和 PowerPoint。这将确保 add-in 仅显示在受支持的位置。
代码被大大缩小了,因此很难弄清楚它到底在做什么。我怀疑您的问题是您正在使用 Word API 1.3 或 1.4 进行调用,Word Online 尚不支持这些版本。这可以解释为什么您在桌面上使用 Word 时看到正确的行为,但在与 Word Online 一起使用时却看不到。我建议查看代码以确保您不会依赖任何 new methods introduced with 1.3。
您还将参数从清单传递到应用程序。您的 add-in 的源页面不应依赖于参数。此处的指导是为您的 add-in 使用独特的登录页面。在初始化 add-in 并建立 Word 和 add-in 之间的通信通道后,您可以将用户重定向到新的 URI。
关于设置数据,我已经在你的另一个问题中回答了这个问题:
绑定对象 (Word)
URL: https://dev.office.com/reference/add-ins/shared/bindings.bindings
创建变量绑定:
- 使用 Office.context.document.getSelectedDataAsync(),asyncResult.value(响应)使用 TextBinding 添加 Office.context.document.bindings.addFromSelectionAsync() 到当前选择
填充内容
- 使用 Binding.setDataAsync 方法,我们将数据写入由指定绑定对象表示的文档的绑定部分。 此时的问题是我们无法设置 {coercionType: "html"} 以在文档的绑定部分插入富文本,它适用于文本。
问题:
- 无法在 Online word 中使用 setDataAsync() 插入富文本
- 无法使用 bindingId 主动选择内容,这将帮助我们使用 Office.context.document.setSelectedDataAsync() 将数据写入文档中的当前选择(富文本适用于此 API ).使用此方法前需要解除绑定
- 无法通过在 Office.initialize 之后将函数传递到 Word.run() 方法来执行 Word.run(函数(上下文){});
没有控制台错误或警告,但 Word.run() 块在尝试通过服务器执行代码时从未运行。本地开发环境在这种情况下有效。
Error Reference Picture
清单
<?xml version="1.0" encoding="UTF-8"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
<!-- BeginBasicSettings: Add-in metadata, used for all versions of Office unless override provided -->
<!--IMPORTANT! Id must be unique for your add-in, if you clone this manifest ensure that you change this id to your own GUID -->
<Id>010861c8-0558-472c-b350-f7795e27cfa5</Id>
<!--Version. Updates from the store only get triggered if there is a version change -->
<Version>1.0.0.0</Version>
<ProviderName>Parrot365 : [QA]</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<!-- The display name of your add-in. Used on the store and various placed of the Office UI such as the add-ins dialog -->
<DisplayName DefaultValue="Parrot365 : [QA]" />
<Description DefaultValue="Parrot365 : QA Mode"/>
<!--Icon for your add-in. Used on installation screens and the add-ins dialog -->
<IconUrl DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png" />
<HighResolutionIconUrl DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_128px.png" />
<SupportUrl DefaultValue="http://support.wittyparrot.com/support/home" />
<!--BeginTaskpaneMode integration. Office 2013 and any client that doesn't understand commands will use this section.
This section will also be used if there are no VersionOverrides -->
<Hosts>
<Host Name="Document" />
<Host Name="Workbook" />
<Host Name="Presentation" />
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice" />
</DefaultSettings>
<!--EndTaskpaneMode integration -->
<Permissions>ReadWriteDocument</Permissions>
<!--BeginAddinCommandsMode integration-->
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<!-- Optional, override the description of the Add-in -->
<Description resid="residToolTip" />
<!--Required, hosts node. Each host can have a different set of commands -->
<Hosts>
<!--Specific host. Workbook=Excel, Document=Word, Presentation=PowerPoint -->
<Host xsi:type="Document">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
<Host xsi:type="Workbook">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
<Host xsi:type="Presentation">
<!-- Form factor. Currenly only DesktopFormFactor is supported. We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--GetStarted information used on the callout that appears when installing the add-in.
Ensure you have build 16.0.6769 or above for GetStarted section to work-->
<GetStarted>
<!--Title of the Getting Started callout. resid points to a ShortString resource -->
<Title resid="Witty.GetStarted.Title"/>
<!--Description of the Getting Started callout. resid points to a LongString resource -->
<Description resid="Witty.GetStarted.Description"/>
<!--Not used right now but you need to provide a valid resource. We will add code in the future to consume this URL.
resid points to a Url resource -->
<LearnMoreUrl resid="Witty.GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="residDesktopFuncUrl" />
<!--PrimaryCommandSurface==Main Office Ribbon-->
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<!--Group. Ensure you provide a unique id. Recommendation for any IDs is to namespace using your companyname-->
<Group id="Witty.Citations.Group1Id1">
<!--Label for your group. resid must point to a ShortString resource -->
<Label resid="residLabel4" />
<!--Icons. Required sizes 16,31,80, optional 20, 24, 40, 48, 64. Strongly recommended to provide all sizes for great UX -->
<!--Use PNG icons and remember that all URLs on the resources section must use HTTPS -->
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--Control. It can be of type "Button" or "Menu" -->
<Control xsi:type="Button" id="Button3Id1">
<!--Label for your button. resid must point to a ShortString resource -->
<Label resid="residLabel3" />
<Supertip>
<!--ToolTip title. resid must point to a ShortString resource -->
<Title resid="residLabel" />
<!--ToolTip description. resid must point to a LongString resource -->
<Description resid="residToolTip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="icon1_16x16" />
<bt:Image size="32" resid="icon3_32x32" />
<bt:Image size="80" resid="icon1_80x80" />
</Icon>
<!--This is what happens when the command is triggered (E.g. click on the Ribbon). Supported actions are ExecuteFuncion or ShowTaskpane-->
<Action xsi:type="ShowTaskpane">
<!--Provide a url resource id for the location that will be displayed on the taskpane -->
<SourceLocation resid="residUnitConverterUrl" />
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="icon1_16x16" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/widget_logo.png">
</bt:Image>
<bt:Image id="icon1_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
<bt:Image id="icon1_80x80" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_80px.png">
</bt:Image>
<bt:Image id="icon2_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
<bt:Image id="icon3_32x32" DefaultValue="https://qaparrot365.wittyparrot.com/resources/assets/images/wp_logo_32px.png">
</bt:Image>
</bt:Images>
<bt:Urls>
<bt:Url id="residDesktopFuncUrl" DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice">
</bt:Url>
<bt:Url id="residUnitConverterUrl" DefaultValue="https://qaparrot365.wittyparrot.com?source=msoffice">
</bt:Url>
<!--LearnMore URL currently not used -->
<bt:Url id="Witty.GetStarted.LearnMoreUrl" DefaultValue="https://qaparrot365.wittyparrot.com">
</bt:Url>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residLabel" DefaultValue="Launch Widget">
</bt:String>
<bt:String id="residLabel3" DefaultValue="Parrot365">
</bt:String>
<bt:String id="residLabel4" DefaultValue=" ">
</bt:String>
<bt:String id="Witty.GetStarted.Title" DefaultValue="Parrot365 Widget Loaded Successfully">
</bt:String>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residToolTip" DefaultValue="Parrot365 add-in provides improves productivity, accuracy and consistency in communication.">
</bt:String>
<bt:String id="Witty.GetStarted.Description" DefaultValue="Get going by opening the Home tab on the Ribbon then click Parrot365 button">
</bt:String>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>
'use strict';
var count = 0;
(function() {
angular.module('wpoffice')
.directive('wittyWordVariable', function() {
return {
restrict: 'E',
replace: true,
templateUrl: 'app/components/witty-word-variable/witty-word-variable_template.html',
scope: {},
bindToController: true,
controller: 'WordVariableController',
controllerAs: 'WordVariableCtrl'
};
})
.controller('WordVariableController', WordVariableController);
function WordVariableController($q, ngNotify) {
var vm = this;
vm.init = init;
vm.getSelectedWordFromDocument = getSelectedWordFromDocument;
vm.populateWordVar = populateWordVar;
function init() {
console.log('Initialized WordVariableController');
vm.inputBoxObjects = [];
vm.varValues = [];
vm.onloadVariablesFound = [];
if (Office.context.document) {
getAllSelectedContentControl();
} else {
ngNotify.set('Please reload Parrot365', 'error');
}
}
/*
*getAllSelectedContentControl----it will load the variable and corresponding text box
*@param --- no param
*/
function getAllSelectedContentControl() {
console.log('getAllSelectedContentControl');
console.log(Word);
Word.run(function(context) {
console.log('inside getSelectedContentControl 2');
var thisDocument = context.document;
context.load(thisDocument, 'contentControls/id, contentControls/text, contentControls/tag');
return context.sync().then(function() {
console.log('returned getSelectedContentControl');
if (thisDocument.contentControls.items.length !== 0) {
console.log(thisDocument.contentControls.items.length);
for (var i = 0; i < thisDocument.contentControls.items.length; i++) {
var variableLabel = thisDocument.contentControls.items[i].text;
var tagId = thisDocument.contentControls.items[i].tag;
if (tagId) {
getVarArray(variableLabel,tagId).then(function(arrayObj) {
createInputboxes(arrayObj);
});
}
}
} else {
console.log('Content is empty');
}
});
}).then(function() {
console.log('completed');
})
.catch(function(error) {
console.log('Error: ' + error);
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
console.log('Error code and message: ' + error.toString());
}
});
}
/*
*getVarArray----creates object on load
*@param variablevalue---value of variable
*@param TagId -----id of variable
*/
function getVarArray(variablevalue,tagId)
{
var deferred = $q.defer();
var allBindings = [];
var tagPrefix, variableLabel;
if (tagId && tagId.lastIndexOf("__") != -1) {
tagPrefix = tagId.substr(0,tagId.lastIndexOf('__'));
var index = tagId.indexOf("_");
if(index) {
variableLabel = tagId.substr(0,index);
}
}
var temp = {
'id': tagId,
'variableLabel': variableLabel,
'tagPrefix': tagPrefix,
'value': variablevalue
};
var indexOfBinding = _.findIndex(allBindings, {
variableLabel: variableLabel,
tagPrefix: tagPrefix
});
if (indexOfBinding === -1) {
allBindings.push(temp);
}
deferred.resolve(allBindings);
return deferred.promise;
}
/*
*createInputboxes ----call createVariable function which will create scope obj
*/
function createInputboxes(arrayOfBindinds)
{
angular.forEach(arrayOfBindinds, function(binding) {
console.log(binding);
var textBoxValue = binding.value ? binding.value:'Enter Text';
console.log(binding.variableLabel+'===='+binding.tagPrefix+'===='+textBoxValue+'===='+binding.id);
createVariable (binding.variableLabel,binding.tagPrefix,textBoxValue,binding.id);
});
}
/*getSelectedWord - Get Selected Data from the document which user has selected manually.
*@no param
*called on user selection
*
*/
function getSelectedWordFromDocument()
{
console.log('abc');
Word.run(function(context) {
console.log('inside word.run');
var range = context.document.getSelection();
var ContentControlForSelection = range.insertContentControl();
ContentControlForSelection.load('text');
return context.sync().then(function() {
var variableLabel = ContentControlForSelection.text;
var tagPrefix = variableLabel + '_tag';
ContentControlForSelection.tag = tagPrefix + '__' + count;
//var conditionalVariable = 'Onseletion';
//createVariable(variableLabel, tagPrefix);
console.log('variable created with'+variableLabel);
getVarArrayOnSelection(ContentControlForSelection.tag,variableLabel, tagPrefix).then(function(bindings) {
console.log(bindings);
createInputboxes(bindings);
});
});
})
.catch(function(error) {
console.log('Error: ' + error);
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
/*
*getVarArrayOnSelection --- it creates obj for selected word in document
*@param--tagId
*@param--userSelectedText
*@param--tagPrefix
*/
function getVarArrayOnSelection(tagId,userSelectedText,tagPrefix)
{
var deferred = $q.defer();
var allBindings = [];
var temp = {
'id': tagId,
'variableLabel': userSelectedText,
'tagPrefix': tagPrefix
};
var indexOfBinding = _.findIndex(allBindings, {
variableLabel: userSelectedText,
tagPrefix: tagPrefix
});
if (indexOfBinding === -1) {
allBindings.push(temp);
}
deferred.resolve(allBindings);
return deferred.promise;
}
function createVariable(variableLabel, tagPrefix, newValue, id) {
console.log(variableLabel+'===='+ tagPrefix+'===='+ newValue+'===='+ id);
var flag = false;
var inputObj = {
id: id,
label: variableLabel,
tag: tagPrefix,
value: newValue
};
if (vm.inputBoxObjects.length > 0) {
var index = _.findIndex(vm.inputBoxObjects, {
label: variableLabel
});
if (index === -1) {
vm.inputBoxObjects.push(inputObj);
} else {
console.log('it already exists in the array');
}
} else {
vm.inputBoxObjects.push(inputObj);
}
}
/*populateWordVar
*@TextBoxId = Text Box Id
*@tagPrefix = unique identifier
**/
function populateWordVar(obj, $event, $index)
{
console.log(obj);
var TextboxValue = ($event.target.value === '' ? obj.label : $event.target.value);
console.log(TextboxValue);
Word.run(function (context) {
var contentControlsWithTag = context.document.contentControls.getByTag(obj.id);
context.load(contentControlsWithTag, 'text');
return context.sync().then(function () {
if (contentControlsWithTag.items.length === 0) {
console.log("There isn't a content control with a tag in this document.");
} else {
console.log('The first content control with the tag has this text: ' + contentControlsWithTag.items[0].text);
for (var i = 0;i<contentControlsWithTag.items.length;i++){
contentControlsWithTag.items[i].insertHtml(TextboxValue, 'Replace');
}
}
});
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
}
})();
<div class="flex layout-column pad-box-10 profile-container" ng-init="WordVariableCtrl.init()">
<div class="layout-row">
<button class="ms-Button ms-Button--primary" ng-click="WordVariableCtrl.getSelectedWordFromDocument ()">
<span class="ms-Button-label">Create Variable</span>
</button>
</div>
<div class="layout-row">
<div class="layout-column">
<div ng-if="WordVariableCtrl.inputBoxObjects.length > 0" class="layout-row flex layout-align-start-center margin-d-10" id="innerDiv" data-ng-repeat="inputBox in WordVariableCtrl.inputBoxObjects">
<label class="ms-Label margin-r-10" for="{{inputBox.id}}" style="width:40%;overflow: hidden;display: inline-block;
text-overflow: ellipsis;white-space: nowrap;">{{inputBox.label}}</label>
<input type="text" name="" placeholder="Enter value" value="{{inputBox.value}}" id={{inputBox.id}} ng-blur="WordVariableCtrl.populateWordVar(inputBox,$event,$index)" class="ms-TextField-field flex flex-rem send-email-input">
</div>
</div>
</div>
</div>
您的清单声明您的 add-in 适用于 Word、PowerPoint 和 Excel,但它指向的代码正在利用 Word Api。您应该确保您的清单声明对 Word API 的依赖并删除 Excel 和 PowerPoint。这将确保 add-in 仅显示在受支持的位置。
代码被大大缩小了,因此很难弄清楚它到底在做什么。我怀疑您的问题是您正在使用 Word API 1.3 或 1.4 进行调用,Word Online 尚不支持这些版本。这可以解释为什么您在桌面上使用 Word 时看到正确的行为,但在与 Word Online 一起使用时却看不到。我建议查看代码以确保您不会依赖任何 new methods introduced with 1.3。
您还将参数从清单传递到应用程序。您的 add-in 的源页面不应依赖于参数。此处的指导是为您的 add-in 使用独特的登录页面。在初始化 add-in 并建立 Word 和 add-in 之间的通信通道后,您可以将用户重定向到新的 URI。
关于设置数据,我已经在你的另一个问题中回答了这个问题: