В разговорах об 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, знает, что ввод дат сопряжён с некоторыми сложностями. Вот если бы можно было просто выбирать дату из календаря!

Так и родилась идея. Поразмыслив, я вывел следующий список требований:
  1. Ввод даты в выбранную ячейку в один клик;
  2. Автоматическое выделение даты в календаре при выборе ячейки со значением;
  3. Наглядное отображение информации о выбранной дате (день недели, номер недели);
  4. Локализация под форматы дат в разных регионах;
  5. «Встраивание» календаря непосредственно в документ без необходимости установки дополнительных компонент.


Реализация


Я использую 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.

Комментарии (0)