В разговорах об Office Add-ins (надстройки Office) часто упоминается «продуктивность». Это логично, ведь главная цель разработчиков – повышение продуктивности в работе конечных пользователей. Но продуктивность важна и для самих разработчиков. Эта статья о продуктивности в разработке. Речь пойдёт о новом JavaScript API для Office и о том, какие инструменты мы применяем для создания новых решений.
Office Add-in за 1 день
В декабре 2015 года меня пригласили поучаствовать в рабочей сессии по Office 365 как консультанта по созданию надстроек Office. На мероприятии собрались команды, интересующиеся продвижением своих продуктов в Office Store. Цель – за два дня погрузиться в тонкости JavaScript API для Office, сформировать концепты будущих решений и реализовать прототипы.
На второй день в промежутках между ответами на вопросы участников у меня оставалось свободное время. Это позволило начать работу над новой идеей. В VSTO-версии расширения XLTools для Excel есть популярная среди пользователей функция – календарь для ввода дат. Мне давно хотелось реализовать её и для Office Store, но руки не доходили. А т.к. темой рабочей сессии была продуктивность, идея вписывалась как нельзя лучше, поскольку календарь в разы увеличивает скорость работы с документами, в которых требуется ввод дат.
Задуманная функциональность
Для примера возьмем стандартный шаблон для Excel из доступных онлайн – «Список дел»:
Чтобы создать такой документ, откройте в Excel меню Файл > Создать > Ввести в поле «Поиск шаблонов в сети» название шаблона «Список дел».
На экране выше видно, что в таблице присутствуют два поля с типом «Дата»: «Дата начала» и «Дата выполнения». Каждый, кому приходилось работать с датами в Excel, знает, что ввод дат сопряжён с некоторыми сложностями. Вот если бы можно было просто выбирать дату из календаря!
Так и родилась идея. Поразмыслив, я вывел следующий список требований:
- Ввод даты в выбранную ячейку в один клик;
- Автоматическое выделение даты в календаре при выборе ячейки со значением;
- Наглядное отображение информации о выбранной дате (день недели, номер недели);
- Локализация под форматы дат в разных регионах;
- «Встраивание» календаря непосредственно в документ без необходимости установки дополнительных компонент.
Реализация
Я использую Visual Studio. Подходят и другие инструменты, такие как Napa или другой редактора кода, но с точки зрения производительности и удобства, Visual Studio – лучший вариант, т.к. позволяет за минуту создать готовый к запуску и отладке проект надстройки Office. В Napa и других сторонних редакторах отладка Office Add-ins пока не представляется возможной.
Создание проекта
Открываем Visual Studio > File > New > Project > Templates > Office/SharePoint > Apps > Выбираем тип приложения «App for Office». Отмечу, что на момент написания статьи Microsoft заменила название «App» на «Add-in». Наверняка в будущем поменяется и название проекта.
Далее задаем тип приложения. Т.к. надстройка встраиваться в тело документа, выбираем тип «Content» – идеально подходит для решения поставленной задачи. Отличие типа Task pane от Content наглядно демонстрирует нижеприведённый рисунок.
На последнем шаге нам предлагается выбрать шаблон проекта (Basic App – базовый, Document Visualization App – посложнее) и набор поддерживаемых офисных программ: Access, Excel, PowerPoint. Выбираем Basic App и поддержку Excel. Нажимаем Finish. Проект создан и готов к запуску (F5) и отладке.
Проектирование и реализация UI
Давайте ещё раз пройдёмся по требованиям и подумаем, как реализовать каждое из них. Начать стоит с последнего – «встраивание». Тут кроется отличительная особенность нового типа Office Add-ins. По сравнению с традиционными VSTO они не требуют установки дополнительных компонент. Т.е. если создать Excel-документ, добавить в него надстройку из Office Store и отправить документ коллегам, им не потребуется ничего дополнительно устанавливать для работы надстройки. Это ровно то, чего так не хватало пользователям VSTO-версии календаря XLTools.
Календарь не предусматривает сложного UI. В интернете есть море свободно распространяемых JavaScript-библиотек, реализующих функционал отображения календаря. Я выбрал библиотеку Pikaday, удовлетворяющую остальным нашим требованиям на 100%. Библиотека позволяет:
- Отображать календарь непосредственно на веб-странице приложения;
- «Вешать» обработчик на событие «Выбор даты из календаря» (onSelect);
- Выставлять значение выбранной в календаре даты из кода (setDate);
- Переводить название дней недели и месяцев на нужные языки.
Конечно, зачастую мы решаем более сложные задачи, требующие уникального дизайна. Здесь стоит обратить внимание на вышедший недавно фреймворк Office UI Fabric, предоставляющий набор CSS-классов и UI-компонентов, заранее стилизованных под офисные приложения. Стили и компоненты адаптированы для работы под все платформы, поддерживаемые Office: Mobile Apps, Web, Desktop. Использование Office UI Fabric в разы упрощает проектирование и разработку UI. Это как Bootstrap, только специально для разработчиков Office Add-ins.
На UI ушло девять строк кода. Подключение CSS и JavaScript в файле Home.html:
<link href="pikaday.css" rel="stylesheet" type="text/css" />
<script src="pikaday.js" type="text/javascript"></script>
Инициализация календаря в методе Office.initialize в файле Home.js:
var calOptions = {
showWeekNumber: true, // календарь должен отображать номера недель
defaultDate: new Date() // по умолчанию выделяем в календаре текущую дату
};
var placeholder = $("body"); // в качестве «родительского элемента» берем body
var picker = new Pikaday(calOptions); // инициализируем объект календаря
placeholder.append(picker.el); // добавляем элемент календаря в body
Обработка выбора даты в календаре
Pikaday позволяет «навесить» обработчик на событие изменения даты в календаре. Получив дату, мы проставляем её в текущую выделенную ячейку, используя метод из Office API — setSelectedDataAsync:
calOptions.onSelect = function (date) { // задаем обработчик события изменения даты
date = getLocaleShortDateString(date); // преобразуем объект Date в строку
Office.context.document.setSelectedDataAsync(date, // передаем дату в виде строки
{
coercionType: Office.CoercionType.Text // тип значения – «Текст»
},
function (asyncResult) { // обработчик статуса изменения значения ячейки
if (asyncResult.status == "failed") {
app.showNotification("Failed", asyncResult.error.message, 'error');
}
}
);
};
В примере для работы с датой используется функция getLocaleShortDateString. Она необходима, т.к. Excel воспринимает даты как числа и отображает их в виде даты, только если у ячейки задан соответствующий формат. Проблема кроется в том, что число в ячейку мы записать можем, а вот изменить формат ячейки текущее JavaScript API не позволяет. К счастью, нашёлся обходной способ. Чтобы получить в ячейке именно дату, нужно проставить её в виде текста, соблюдая выбранный у пользователя формат региона (локали). Функция getLocaleShortDateString как раз используется для преобразования объекта Date в текстовый локализованный формат. Узнать, какой именно региональный стандарт выбран у пользователя, можно через свойство объекта context – Office.context.displayLanguage.
function getLocaleShortDateString(d) {
var f = getLocaleDateString(),
y = d.getFullYear(),
m = d.getMonth() + 1,
d = d.getDate();
function z(s) {
s = '' + s; return s.length > 1 ? s : '0' + s;
}
f = f.replace(/yyyy/, y); f = f.replace(/yy/, String(y).substr(2));
f = f.replace(/MM/, z(m)); f = f.replace(/M/, m);
f = f.replace(/dd/, z(d)); f = f.replace(/d/, d);
return f;
}
function getLocaleDateString() {
var formats = {
"en-US": "M/d/yyyy",
"ru-RU": "dd.MM.yyyy",
... // еще более 200 форматов
};
return formats[Office.context.displayLanguage] || 'dd/MM/yyyy';
}
Подсветка выбранной даты в календаре
JavaScript API для Excel позволяет обрабатывать событие изменения выделенной области ячеек. Используем это, чтобы отследить изменение пользователем выделенной ячейки:
// обработчик изменения выделения
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged,
function (eventArgs) {
// запрашиваем значение выделенной ячейки
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
{
// говорим, что нам необходимо фактическое значение (число)
valueFormat: Office.ValueFormat.Unformatted
}, function (ufResult) {
if (ufResult.status != "failed") {
var value = ufResult.value;
// если не число - ничего не делаем
if (isInt(value) && value > 0)
{
// переводим число в дату
var date = getJsDateFromExcel(value);
// работаем только с датами +-50 лет от текущей даты
if (new String(date) != "InvalidDate" &&
date.getYear() > new Date().getYear() - 50 &&
date.getYear() < new Date().getYear() + 50)
{
// подсвечиваем значение в календаре
picker.setDate(date, true);
}
}
}
});
});
«Поймав» момент выделения новой ячейки пользователем, проверяем, является ли выбранное значение датой. Чтобы получить значение из выделенной ячейки, используем функцию Office.context.document.getSelectedDataAsync, говорим ей, что вернуть нужно не отформатированное значение. В случае с датой, значением будет целое число (даты со временем не рассматриваем). Далее идут проверки на соответствие значения дате. Определить на 100%, является ли значение в ячейке датой, не представляется возможным. Так, если пользователь выберет ячейку с числом, соответствующим числовому представлению даты – алгоритм посчитает, что это и есть дата. Чтобы минимизировать количество ложных срабатываний на числа, задаём ограничение: проверка даты на +-50 лет от текущего года. Если значение подходит по всем критериям, используем для подсветки метод setDate календаря Pikaday.
Локализация
Сейчас Office Store поддерживает 40 языков. В примерах выше уже показано, как локализовать значение даты. Помимо даты, локализации требует также UI. В случае с календарем Pikaday всё просто:
var myLanguage = Office.context.displayLanguage.split("-")[0];
if (myLanguage == "ru") {
calOptions.firstDay = 1;
calOptions.i18n = {
previousMonth: 'Предыдущий месяц',
nextMonth: 'Следующий месяц',
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
weekdays: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда',
'Четверг', 'Пятница', 'Суббота'],
weekdaysShort: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб']
};
}
Для начала поддерживаем 2 языка: русский и английский. Pikaday по умолчанию англоязычный. Для перевода на русский проверяем текущий регион пользователя и подставляем новые значения для текстовых надписей, если язык интерфейса русский.
Работа с XLTools.net Calendar
Выводы
Меньше чем за один день мне удалось создать Office Add-in, готовый к публикации в Office Store. Такая скорость возможна благодаря опыту и готовым решениям, накопленным годами в веб-разработке. Плюсом является простота JavaScript API для Office, так же как и наличие готового фреймворка Office UI Fabric для построения UI.
Из сложностей можно отметить, что отладка надстроек на разных платформах – неординарная задача. Уже после отправки приложения на проверку в Office Store мне пришлось побороться с отладкой, т.к. первая версия надстройки не прошла проверку из-за ошибок в работе на iPad и в Web-е. С проблемами отладки я справился и напишу об этом отдельную статью.
Недавно надстройка XLTools.net Calendar успешно прошла проверку и теперь доступна для скачивания в Office Store. За две недели мы набрали 1832 скачивания, получили 1 отзыв и 4 максимальных оценки в Office Store. Много положительных отзывов и запросов на доработку функциональности пришло по email. В ближайшее время планируем выпустим усовершенствованный календарь с новыми опциями. Следите за обновлениями!
Об авторе
Петр Ляпин -Технический директор ООО «ВейвПоинт»
Более 10 лет опыта внедрения проектов по автоматизации
бизнес-процессов. Работал со множеством российских и
зарубежных компаний. Основатель проекта XLTools.net.
Автор: Microsoft