PR 12: Merge feature/agave to master
- Add calendar XML file - Restyling - prep for reload of calendar - Link up calendar reloading - Consolidate loading code - Fix proxy objects for office.js case to work with reloads - fix IE11 button focus styling
This commit is contained in:
Коммит
4d72aecb83
|
@ -0,0 +1,32 @@
|
|||
<?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" xsi:type="ContentApp">
|
||||
<Id>A1EB8AB4-5807-4D99-9A70-26F65D933ED6</Id>
|
||||
<Version>1.12.0.0</Version>
|
||||
<ProviderName>Microsoft</ProviderName>
|
||||
<DefaultLocale>en-US</DefaultLocale>
|
||||
<DisplayName DefaultValue="Calendar (local)">
|
||||
</DisplayName>
|
||||
<Description DefaultValue="Calendar control">
|
||||
</Description>
|
||||
<IconUrl DefaultValue="https://edera.cloudapp.net/images/ChartTypeArea.32x32x32.png">
|
||||
</IconUrl>
|
||||
<HighResolutionIconUrl DefaultValue="https://edera.cloudapp.net/images/ChartTypeArea.64x64x32.png">
|
||||
</HighResolutionIconUrl>
|
||||
<SupportUrl DefaultValue="http://aka.ms/mixhelp"></SupportUrl>
|
||||
<Hosts>
|
||||
<Host Name="Workbook"/>
|
||||
</Hosts>
|
||||
<AppDomains>
|
||||
<AppDomain>https://login.microsoftonline.com</AppDomain>
|
||||
<AppDomain>https://login.live.com</AppDomain>
|
||||
<AppDomain>https://accounts.google.com</AppDomain>
|
||||
</AppDomains>
|
||||
<DefaultSettings>
|
||||
<SourceLocation DefaultValue="http://localhost:3000/loader"></SourceLocation>
|
||||
<RequestedWidth>640</RequestedWidth>
|
||||
<RequestedHeight>480</RequestedHeight>
|
||||
</DefaultSettings>
|
||||
<Permissions>ReadWriteDocument</Permissions>
|
||||
<!--Allowed snapshot can be true or false for InContent Agaves only-->
|
||||
<AllowSnapshot>true</AllowSnapshot>
|
||||
</OfficeApp>
|
|
@ -0,0 +1,32 @@
|
|||
<?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" xsi:type="ContentApp">
|
||||
<Id>5CBA2DDA-F8EC-4C6D-A070-11E24E123226</Id>
|
||||
<Version>1.12.0.0</Version>
|
||||
<ProviderName>Microsoft</ProviderName>
|
||||
<DefaultLocale>en-US</DefaultLocale>
|
||||
<DisplayName DefaultValue="Calendar">
|
||||
</DisplayName>
|
||||
<Description DefaultValue="Calendar control">
|
||||
</Description>
|
||||
<IconUrl DefaultValue="https://edera.cloudapp.net/images/ChartTypeArea.32x32x32.png">
|
||||
</IconUrl>
|
||||
<HighResolutionIconUrl DefaultValue="https://edera.cloudapp.net/images/ChartTypeArea.64x64x32.png">
|
||||
</HighResolutionIconUrl>
|
||||
<SupportUrl DefaultValue="http://aka.ms/mixhelp"></SupportUrl>
|
||||
<Hosts>
|
||||
<Host Name="Workbook"/>
|
||||
</Hosts>
|
||||
<AppDomains>
|
||||
<AppDomain>https://login.microsoftonline.com</AppDomain>
|
||||
<AppDomain>https://login.live.com</AppDomain>
|
||||
<AppDomain>https://accounts.google.com</AppDomain>
|
||||
</AppDomains>
|
||||
<DefaultSettings>
|
||||
<SourceLocation DefaultValue="https://officenet.azurewebsites.net/loader"></SourceLocation>
|
||||
<RequestedWidth>640</RequestedWidth>
|
||||
<RequestedHeight>480</RequestedHeight>
|
||||
</DefaultSettings>
|
||||
<Permissions>ReadWriteDocument</Permissions>
|
||||
<!--Allowed snapshot can be true or false for InContent Agaves only-->
|
||||
<AllowSnapshot>true</AllowSnapshot>
|
||||
</OfficeApp>
|
|
@ -1 +1 @@
|
|||
html{width:100%;height:100%}body{margin:0px;padding:0px;overflow:hidden;width:100%;height:100%}
|
||||
html{width:100%;height:100%;overflow:hidden}body{margin:0px;padding:0px;overflow:hidden;width:100%;height:100%}
|
|
@ -1,6 +1,7 @@
|
|||
html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
|
@ -1,26 +1,16 @@
|
|||
import * as $ from 'jquery';
|
||||
import * as _ from 'lodash';
|
||||
import { pnhost, IEchoService, EchoServiceName, ITableService, TableServiceName, ITableListener } from '../api/index';
|
||||
import { Promise } from 'es6-promise';
|
||||
import { pnhost, IEchoService, EchoServiceName, ITable, ITableService, TableServiceName, ITableListener } from '../api/index';
|
||||
var fullcalendar = require('fullcalendar');
|
||||
var qtip = require('qtip2');
|
||||
|
||||
// TODO better wrap this into some kind of model structure
|
||||
var rowsModel: any[] = [];
|
||||
var pendingDeletes: any[] = [];
|
||||
class TableListener implements ITableListener {
|
||||
constructor(private _viewModel: CalendarViewModel) {
|
||||
}
|
||||
|
||||
class TableListener implements ITableListener {
|
||||
rowsChanged(rows: any[]): Promise<void> {
|
||||
// compute the difference between the existing rowsModel and the updates
|
||||
let deletedRows = _.filter(rowsModel, (rowModel) => _.find(rows, (row) => row.id === rowModel.id) === undefined);
|
||||
$('#calendar').fullCalendar('removeEvents', (event) => {
|
||||
return _.find(deletedRows, (deletedRow) => deletedRow.id === event.id);
|
||||
});
|
||||
|
||||
// Add the rows to delete to the pending list
|
||||
pendingDeletes = pendingDeletes.concat(deletedRows);
|
||||
|
||||
// Update the model with the changed rows
|
||||
rowsModel = rows;
|
||||
this._viewModel.rowsChanged(rows);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -30,113 +20,208 @@ class TableListener implements ITableListener {
|
|||
}
|
||||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
let tableServiceP: Promise<ITableService>;
|
||||
if (pnhost) {
|
||||
tableServiceP = pnhost.listServices().then((services) => {
|
||||
return _.includes(services, TableServiceName) ? pnhost.getService(TableServiceName) : Promise.resolve(null);
|
||||
class RemoteCalendar {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getCalendars(): Promise<Calendar[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.ajax("/calendars", {
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
success: (calData: Calendar[]) => resolve(calData),
|
||||
error: (jqXHR: JQueryXHR, textStatus: string, errorThrown: string) => reject(jqXHR)
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
tableServiceP = Promise.resolve(null);
|
||||
}
|
||||
|
||||
class CalendarViewModel {
|
||||
private _calendar = new RemoteCalendar();
|
||||
private _tableServiceP: Promise<ITableService>;
|
||||
private _cachedCalendars: Calendar[];
|
||||
private _pendingDeletes: any[] = [];
|
||||
private _tableP: Promise<ITable>;
|
||||
private _tableListener: TableListener;
|
||||
private _tableBoundRows: any[];
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
$.ajax("/calendars", {
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
success: (calData: Calendar[]) => {
|
||||
if (pnhost) {
|
||||
$("#buttons").append($('<button id="load-table">Export to Table</button><button id="save">Save</button>'));
|
||||
|
||||
// Save processes any pending calendar changes
|
||||
$("#save").click(() => {
|
||||
// iterate over the deletedRows URLs and delete them
|
||||
for (let pendingDelete of pendingDeletes) {
|
||||
$.ajax(pendingDelete.self, { method: "DELETE" });
|
||||
console.log(`DELETE: ${pendingDelete.self}`);
|
||||
}
|
||||
});
|
||||
private initView() {
|
||||
$("#buttons").append($('<div class="fc-right"><div class="fc-button-group"><button id="reload" class="fc-button fc-state-default" type="button">Reload</button></div></div>'));
|
||||
$("#reload").click(() => {
|
||||
this.loadAndCacheCalendars();
|
||||
});
|
||||
|
||||
$("#load-table").click(() => {
|
||||
tableServiceP.then((tableService) => {
|
||||
if (!tableService) {
|
||||
return;
|
||||
}
|
||||
if (pnhost) {
|
||||
$("#buttons").append($('<div class="fc-left"><div class="fc-button-group"><button id="load-table" class="fc-button fc-state-default" type="button">Export to Table</button></div></div>'));
|
||||
$("#buttons .fc-right .fc-button-group").append('<button id="save" class="fc-button fc-state-default" type="button">Save</button>');
|
||||
|
||||
tableService.createTable().then((table) => {
|
||||
let columns = ['provider', 'title', 'location', 'start', 'end', 'responseStatus'];
|
||||
for (let calendar of calData) {
|
||||
for (let event of calendar.events) {
|
||||
rowsModel.push({
|
||||
id: event.id,
|
||||
provider: calendar.sourceName,
|
||||
title: event.title,
|
||||
location: event.location,
|
||||
start: event.start,
|
||||
end: event.end,
|
||||
responseStatus: event.responseStatus,
|
||||
self: event.self
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
table.loadData(columns, rowsModel);
|
||||
|
||||
// Listen for updates
|
||||
table.addListener(new TableListener());
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// page is now ready, initialize the calendar...
|
||||
var fcOptions = <FullCalendar.Options>{
|
||||
minTime: "07:00:00",
|
||||
maxTime: "21:00:00",
|
||||
weekends: false,
|
||||
height: "auto",
|
||||
eventRender: (event, element) => {
|
||||
var content = event.title;
|
||||
if (event.location && (event.location.length > 0)) {
|
||||
content += ("<br/>" + event.location);
|
||||
}
|
||||
if (event.responseStatus && (event.responseStatus.length > 0)) {
|
||||
content += ("<br/>" + event.responseStatus);
|
||||
}
|
||||
var qtipOptions: QTip2.QTipOptions = {
|
||||
content: content,
|
||||
position: {
|
||||
my: "left center",
|
||||
at: "center"
|
||||
}
|
||||
};
|
||||
element.qtip(qtipOptions);
|
||||
// Save processes any pending calendar changes
|
||||
$("#save").click(() => {
|
||||
// iterate over the deletedRows URLs and delete them
|
||||
for (let pendingDelete of this._pendingDeletes) {
|
||||
$.ajax(pendingDelete.self, { method: "DELETE" });
|
||||
console.log(`DELETE: ${pendingDelete.self}`);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var events: FullCalendar.EventObject[] = [];
|
||||
for (var ncal = calData.length, ical = 0; ical < ncal; ical++) {
|
||||
var cal = calData[ical];
|
||||
var borderColor = (ical == 0) ? "black" : "darkblue";
|
||||
var color = (ical == 0) ? "purple" : "green";
|
||||
$("#load-table").click(() => {
|
||||
// Disable future loads since we're now bound to the host
|
||||
$("#load-table").prop('disabled', true);
|
||||
|
||||
for (var nevent = cal.events.length, iev = 0; iev < nevent; iev++) {
|
||||
let ev = cal.events[iev];
|
||||
events.push({
|
||||
id: ev.id,
|
||||
title: ev.title,
|
||||
color: color,
|
||||
borderColor: borderColor,
|
||||
location: ev.location,
|
||||
responseStatus: ev.responseStatus,
|
||||
start: new Date(ev.start),
|
||||
end: new Date(ev.end),
|
||||
});
|
||||
this.loadPNHostTable();
|
||||
});
|
||||
}
|
||||
|
||||
var fcOptions = <FullCalendar.Options>{
|
||||
minTime: "07:00:00",
|
||||
maxTime: "21:00:00",
|
||||
weekends: false,
|
||||
height: "auto",
|
||||
eventRender: (event, element) => {
|
||||
var content = event.title;
|
||||
if (event.location && (event.location.length > 0)) {
|
||||
content += ("<br/>" + event.location);
|
||||
}
|
||||
if (event.responseStatus && (event.responseStatus.length > 0)) {
|
||||
content += ("<br/>" + event.responseStatus);
|
||||
}
|
||||
var qtipOptions: QTip2.QTipOptions = {
|
||||
content: content,
|
||||
position: {
|
||||
my: "left center",
|
||||
at: "center"
|
||||
}
|
||||
};
|
||||
element.qtip(qtipOptions);
|
||||
}
|
||||
fcOptions.events = events;
|
||||
$('#calendar').fullCalendar(fcOptions);
|
||||
$('#calendar').fullCalendar('changeView', 'agendaWeek');
|
||||
};
|
||||
|
||||
$('#calendar').fullCalendar(fcOptions);
|
||||
$('#calendar').fullCalendar('changeView', 'agendaWeek');
|
||||
}
|
||||
|
||||
private loadPNHostTable() {
|
||||
if (!this._tableP) {
|
||||
this._tableP = this._tableServiceP.then((tableService) => tableService.createTable());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._tableP.then((table) => {
|
||||
let columns = ['provider', 'title', 'location', 'start', 'end', 'responseStatus'];
|
||||
|
||||
// Get and store the rows we will bind to the pnhost table
|
||||
this._tableBoundRows = [];
|
||||
for (let calendar of this._cachedCalendars) {
|
||||
for (let event of calendar.events) {
|
||||
this._tableBoundRows.push({
|
||||
id: event.id,
|
||||
provider: calendar.sourceName,
|
||||
title: event.title,
|
||||
location: event.location,
|
||||
start: event.start,
|
||||
end: event.end,
|
||||
responseStatus: event.responseStatus,
|
||||
self: event.self
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Load the rows into the hosted table
|
||||
table.loadData(columns, this._tableBoundRows);
|
||||
|
||||
// Setup a table listener if it doesn't already exist
|
||||
if (!this._tableListener) {
|
||||
this._tableListener = new TableListener(this);
|
||||
table.addListener(this._tableListener);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private loadAndCacheCalendars(): Promise<Calendar[]> {
|
||||
return this._calendar.getCalendars().then((calendars) => {
|
||||
// Clear any pending deletes - a reload resets any interactions
|
||||
this._pendingDeletes = [];
|
||||
|
||||
// Initialize the custom UI once we load the first batch of data
|
||||
if (this._cachedCalendars === undefined) {
|
||||
this.initView();
|
||||
}
|
||||
|
||||
this._cachedCalendars = calendars;
|
||||
|
||||
// Update the calendar UI
|
||||
this.loadCalendarView(calendars);
|
||||
|
||||
// Refresh the pnhost table with the new fields
|
||||
if (this._tableP) {
|
||||
this.loadPNHostTable();
|
||||
}
|
||||
|
||||
return calendars;
|
||||
})
|
||||
}
|
||||
|
||||
rowsChanged(rows: any[]) {
|
||||
// compute the difference between the received rows and the bound data
|
||||
let deletedRows = _.filter(this._tableBoundRows, (rowModel) => _.find(rows, (row) => row.id === rowModel.id) === undefined);
|
||||
$('#calendar').fullCalendar('removeEvents', (event) => {
|
||||
return _.find(deletedRows, (deletedRow) => deletedRow.id === event.id);
|
||||
});
|
||||
|
||||
// Add the rows to delete to the pending list
|
||||
this._pendingDeletes = this._pendingDeletes.concat(deletedRows);
|
||||
|
||||
// Update the bound data values
|
||||
this._tableBoundRows = rows;
|
||||
}
|
||||
|
||||
private loadCalendarView(calendars: Calendar[]) {
|
||||
var events: FullCalendar.EventObject[] = [];
|
||||
for (var ncal = calendars.length, ical = 0; ical < ncal; ical++) {
|
||||
var cal = calendars[ical];
|
||||
var borderColor = (ical == 0) ? "black" : "darkblue";
|
||||
var color = (ical == 0) ? "purple" : "green";
|
||||
|
||||
for (var nevent = cal.events.length, iev = 0; iev < nevent; iev++) {
|
||||
let ev = cal.events[iev];
|
||||
events.push({
|
||||
id: ev.id,
|
||||
title: ev.title,
|
||||
color: color,
|
||||
borderColor: borderColor,
|
||||
location: ev.location,
|
||||
responseStatus: ev.responseStatus,
|
||||
start: new Date(ev.start),
|
||||
end: new Date(ev.end),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update the calendar view
|
||||
$('#calendar').fullCalendar('removeEvents');
|
||||
for (let event of events) {
|
||||
$('#calendar').fullCalendar('renderEvent', event);
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
if (pnhost) {
|
||||
this._tableServiceP = pnhost.listServices().then((services) => {
|
||||
return _.includes(services, TableServiceName) ? pnhost.getService(TableServiceName) : Promise.resolve(null);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._tableServiceP = Promise.resolve(null);
|
||||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
this.loadAndCacheCalendars();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create and initialize the view model that will bind to and run the UI
|
||||
let viewModel = new CalendarViewModel();
|
||||
viewModel.init();
|
|
@ -27,16 +27,21 @@ class Table implements ITable {
|
|||
loadData(columns: string[], rows: any[]): Promise<void> {
|
||||
console.log('load data');
|
||||
let columnOptions = columns.map((column) => new TableColumn({prop: column}));
|
||||
|
||||
// TODO There's a bug in the angular table where changing column options adds extra padding
|
||||
// to the table. So assuming the columns don't change between loads for now.
|
||||
if (!this.options) {
|
||||
this.options = new TableOptions({
|
||||
columnMode: ColumnMode.force,
|
||||
headerHeight: 50,
|
||||
footerHeight: 50,
|
||||
rowHeight: 'auto',
|
||||
selectionType: SelectionType.multi,
|
||||
columns: columnOptions
|
||||
});
|
||||
}
|
||||
|
||||
this.options = new TableOptions({
|
||||
columnMode: ColumnMode.force,
|
||||
headerHeight: 50,
|
||||
footerHeight: 50,
|
||||
rowHeight: 'auto',
|
||||
selectionType: SelectionType.multi,
|
||||
columns: columnOptions
|
||||
});
|
||||
|
||||
this.selection = [];
|
||||
this.rows = rows;
|
||||
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
<head>
|
||||
<link rel='stylesheet' href='/node_modules/fullcalendar/dist/fullcalendar.css' />
|
||||
<link rel='stylesheet' href='/node_modules/qtip2/dist/jquery.qtip.css' />
|
||||
<script src='/dist/views/calendar/driver.js'></script>
|
||||
<script src='/dist/views/calendar/driver.js'></script>
|
||||
<style>
|
||||
.clearfix:after {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.mui-controls {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='buttons'></div>
|
||||
<div class="fc clearfix mui-controls">
|
||||
<div id='buttons' class="fc-toolbar">
|
||||
</div>
|
||||
</div>
|
||||
<div id='calendar'></div>
|
||||
</body>
|
|
@ -3,7 +3,7 @@
|
|||
<link href="/stylesheets/embed.css" rel="stylesheet" />
|
||||
{{/styles}}
|
||||
|
||||
{{$content}}
|
||||
{{$content}}
|
||||
<iframe src="/documents/calendar" frameborder="0" style="overflow:hidden;height:100%;width:100%" height="100%" width="100%"></iframe>
|
||||
{{/content}}
|
||||
|
||||
|
@ -84,44 +84,65 @@
|
|||
|
||||
// Run a batch operation against the Excel object model
|
||||
Excel.run(function (ctx) {
|
||||
// Create a proxy object for the active worksheet
|
||||
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
|
||||
if (that.table) {
|
||||
var tableRows = ctx.workbook.tables.getItem('calendarTable').rows;
|
||||
tableRows.load('items');
|
||||
return ctx.sync().then(function() {
|
||||
for (var i = tableRows.items.length - 1; i >= 0; i--) {
|
||||
tableRows.items[i].delete();
|
||||
}
|
||||
|
||||
// I imagine I can do C style 'a' + number - but not sure how yet in JS
|
||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
var endPosition = possible.charAt(columns.length - 1) + 1;
|
||||
var table = sheet.tables.add('A1:' + endPosition, true);
|
||||
table.name = "calendarTable";
|
||||
table.getHeaderRowRange().values = [columns];
|
||||
|
||||
var rowsToLoad = [];
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var newRow = [];
|
||||
for (var j = 0; j < columns.length; j++) {
|
||||
newRow.push(rows[i][columns[j]]);
|
||||
}
|
||||
table.rows.add(null, [newRow]);
|
||||
}
|
||||
|
||||
//Run the queued commands, and return a promise to indicate task completion
|
||||
return ctx.sync().then(function() {
|
||||
//Create a new table binding for myTable
|
||||
Office.context.document.bindings.addFromNamedItemAsync(
|
||||
"calendarTable",
|
||||
Office.CoercionType.Table,
|
||||
{ id: "myBinding" },
|
||||
function (asyncResult) {
|
||||
if (asyncResult.status == "failed") {
|
||||
console.log("Action failed with error: " + asyncResult.error.message);
|
||||
}
|
||||
else {
|
||||
// If successful, add the event handler to the table binding.
|
||||
Office.select("bindings#myBinding").addHandlerAsync(Office.EventType.BindingDataChanged, function() {
|
||||
that.displayDataForBinding();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
var rowsToLoad = [];
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var newRow = [];
|
||||
for (var j = 0; j < columns.length; j++) {
|
||||
newRow.push(rows[i][columns[j]]);
|
||||
}
|
||||
tableRows.add(null, [newRow]);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Create a proxy object for the active worksheet
|
||||
var sheet = ctx.workbook.worksheets.getActiveWorksheet();
|
||||
|
||||
// I imagine I can do C style 'a' + number - but not sure how yet in JS
|
||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
var endPosition = possible.charAt(columns.length - 1) + 1;
|
||||
var table = sheet.tables.add('A1:' + endPosition, true);
|
||||
that.table = table;
|
||||
table.name = "calendarTable";
|
||||
table.getHeaderRowRange().values = [columns];
|
||||
|
||||
var rowsToLoad = [];
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var newRow = [];
|
||||
for (var j = 0; j < columns.length; j++) {
|
||||
newRow.push(rows[i][columns[j]]);
|
||||
}
|
||||
table.rows.add(null, [newRow]);
|
||||
}
|
||||
|
||||
//Run the queued commands, and return a promise to indicate task completion
|
||||
return ctx.sync().then(function() {
|
||||
//Create a new table binding for myTable
|
||||
Office.context.document.bindings.addFromNamedItemAsync(
|
||||
"calendarTable",
|
||||
Office.CoercionType.Table,
|
||||
{ id: "myBinding" },
|
||||
function (asyncResult) {
|
||||
if (asyncResult.status == "failed") {
|
||||
console.log("Action failed with error: " + asyncResult.error.message);
|
||||
}
|
||||
else {
|
||||
// If successful, add the event handler to the table binding.
|
||||
Office.select("bindings#myBinding").addHandlerAsync(Office.EventType.BindingDataChanged, function() {
|
||||
that.displayDataForBinding();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function () {
|
||||
console.log("Success!");
|
||||
|
|
Загрузка…
Ссылка в новой задаче