カテゴリー別アーカイブ: Office Add-ins

Office アドイン (JavaScript API for Office) をはじめる人の必読記事

Web の Office Add-in (Excel, Word, PowerPoint, Outlook, etc) をはじめる人のために「Office Add-ins とは ?」、「何ができるの ?」、「どう作るの ?」などをザッと読み物として短くまとめたので告知。(もう何ヶ月か前に記事追加したけど、今更告知ですみません 。。。)

連載1回「JavaScriptで誰でも簡単に作って稼げる Officeアドインとは?」
http://www.atmarkit.co.jp/ait/articles/1301/25/news063.html

連載2回「Office アドインの作り方と、できること/できないこと」
http://www.atmarkit.co.jp/ait/articles/1303/04/news091.html

連載3回「Office 2016 における Office アドイン進化のポイント」
http://www.atmarkit.co.jp/ait/articles/1601/15/news026.html

Office アドインは、Office が掲げるマルチ プラットフォーム戦略 (Mac でも、iPad でも、スマホでも、すべての人に快適に Office を使わせる戦略) に沿ったこれからの時代のアドインだ。

 

Office Add-ins の add-in command (カスタム Ribbon ボタン)

de:code 2015 の「Office 開発/Office 365 開発の新機能紹介」でもデモしていたアドイン コマンド (リボン コマンド) が、まずは Outlook の Mail Add-in で試せるようになったので紹介したい。

追記 : Office Add-in Command は、Excel Add-in、Word Add-in、PowerPoint Add-in でも可能になった。Outlook 以外で追加した場合、「個人用アドイン」(My Add-in) に登録されている間、常にアプリ (Excel、Word、PowerPoint) に表示される。(ドキュメント単位ではなく、アプリ単位の挿入。)
PowerPoint Add-in の “Pickit Presentation Images” などで確認できるので、是非試してみてほしい。

平たく書くと、Office Add-ins の Mail Add-ins (Mail Add-in for Outlook) で下図のような ribbon command (ボタンを押すと実行できる処理) が使えるようになったというもので、動作させるには、今のところ Windows 版の Outlook 2016 (現在 Preview) が必要だ。(いずれ Outlook Web App やその他の Native の Outlook などでも対応されるだろう。)

addin_command

これまでの Mail Add-ins では、一度、Taskpane などの形で何某かの Window (Pane) を表示して、そこに必要なボタンなどのコントロールを配置してアプリを作るしかなかったが、こうした Window (Pane) が不要なストレートな処理は、今後は上述の Add-in Command を使って作ることが可能だ。

Manifest の記述方法

今回の新機能では、Manifest (Office Add-ins で作成する .xml ファイル) の記述も大幅に拡張されているが、Office Add-ins (および、JavaScript Library) 自体のバージョンがあがるわけではなく、既存のバージョンの拡張として実装されているらしく、上述の通り、この機能が使えないプラットフォームもあるという点に注意が必要だ。例えば、Outlook 2013 から使用した際に、不明な XML 要素によりエラーが発生するようなケースは避ける必要がある。

そこで、Manifest 作成のアプローチとして、そのまま Add-in Command 用の記述を入れるのではなく、いったん過去のプラットフォーム互換な Manifest を作成し、新しいプラットフォーム (Outlook 2016 など) で使用された場合には、その内容を override するというアプローチで Manifest を記述する。

この際 必要になるのが、VersionOverrides 要素だ。
Manifest には下記の通り記述し、この VersionOverrides の中に Add-in Command 用の設定を書いていく。(この中身は、このあと作成する。)

<?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:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="MailApp">
  <Id>{9AADFD5D-49A0-47C8-897F-1BB59D5116B5}</Id>
  <Version>1.0</Version>
  <ProviderName>Microsoft</ProviderName>
  <DefaultLocale>en-us</DefaultLocale>
  <DisplayName DefaultValue="My App Test"></DisplayName>
  <Description DefaultValue="This is a test"></Description>
  <Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="Mailbox" />
    </Sets>
  </Requirements>
  <FormSettings>
    <Form xsi:type="ItemRead">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app1.html" >
        </SourceLocation>
        <RequestedHeight>150</RequestedHeight>
      </DesktopSettings>
    </Form>
    <Form xsi:type="ItemEdit">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app2.html" >
        </SourceLocation>
      </DesktopSettings>
    </Form>
  </FormSettings>
  <Permissions>ReadWriteItem</Permissions>
  <Rule xsi:type="RuleCollection" Mode="Or">
    <Rule xsi:type="ItemIs"
      ItemType="Message"
      FormType="Edit" />
    <Rule xsi:type="ItemIs"
      ItemType="Appointment"
      FormType="Edit" />
  </Rule>
  <DisableEntityHighlighting>true</DisableEntityHighlighting>
  <VersionOverrides
    xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
    xsi:type="VersionOverridesV1_0">
    <!-- we will write here later -->
  </VersionOverrides>
</OfficeApp>

例えば、ボタンを押したら、ある JavaScript 関数を実行する場合は、以下の通りプログラミングする。

まず、下記の JavaScript 関数を含む html ファイルをどこかインターネット上の見える場所に配置しておく。(今回、これを myfunc.html という名前で公開する。)
なお、下記では単にメールの返信画面を起動しているが、JavaScript API for Office の Mail 関連の API では、アイテム変更 (Compose の際)、EWS の呼び出しなど多くのことが可能なので、COM アドインに匹敵する細かな処理を記述することが可能だ。

<meta http-equiv="X-UA-Compatible" content="IE=9" >
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>My Test Page</title>
  <script type="text/javascript"
    src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.debug.js">
  </script>
  <script type="text/javascript">
  Office.initialize = function (reason) 
  {
    //// you can initialize here
    //_Om = Office.context.mailbox;
    //_Item = _Om.item;
    //_UserProfile = _Om.userProfile;
  }

  function showTest(event)
  {
    //// if you need source control, do below
    //var buttonId = event.source.id;

    // if in compose, displayReplyForm does not work ...
    Office.context.mailbox.item.displayReplyForm('reply test !');
	
    //// when compose mode, you can do below
    //
    //_Item.setSubjectAsync('Hello World!');
    //
    //Office.context.mailbox.item.body.prependAsync(
    //  'test!',
    //  {
    //    coercionType: Office.CoercionType.Text,
    //    asyncContext: { ... }
    //  },
    //  function(asyncResult) {
    //    event.completed(true);
    //  });
    
    event.completed();
  }
  </script>
</head>
<body>
</body>
</html>

そして、前述の Manifest 内の VersionOverrides に以下の通り記述する。
ここでは、Ribbon Button を配置し、このボタンが押された際に、上記の関数 showTest を呼び出している。

<VersionOverrides
  xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="VersionOverridesV1_0">

  <Description resid="residDesc" />

  <Requirements>
    <bt:Sets DefaultMinVersion="1.3">
      <bt:Set Name="Mailbox" />
    </bt:Sets>
  </Requirements>

  <Hosts>
    <Host xsi:type="MailHost">

      <DesktopFormFactor>
        <FunctionFile resid="residFuncUrl" />

        <ExtensionPoint xsi:type="MessageReadCommandSurface">
          <OfficeTab id="TabDefault">
            <Group id="msgreadTabMessage.grp1">
              <Label resid="residLabel" />
              <Tooltip resid="residLabelTip" />
 
              <Control xsi:type="Button" id="button1id">
                <Label resid="residUILessButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
                <Action xsi:type="ExecuteFunction">
                  <FunctionName>showTest</FunctionName>
                </Action>
              </Control>

            </Group>
          </OfficeTab>
        </ExtensionPoint>
      </DesktopFormFactor>
    </Host>
  </Hosts>

  <Resources>
    <bt:Images>
      <bt:Image id="icon1"
        DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
      </bt:Image>
      <bt:Image id="icon2"
        DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
      </bt:Image>
      <bt:Image id="icon3"
        DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
      </bt:Image>
    </bt:Images>
    <bt:Urls>
      <bt:Url id="residFuncUrl"
        DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
      </bt:Url>
    </bt:Urls>
    <bt:ShortStrings>
      <bt:String id="residLabel"
        DefaultValue="Test App">
      </bt:String>
      <bt:String id="residUILessButton"
        DefaultValue="Do Func">
      </bt:String>
      <bt:String id="residSuperTipTitle"
        DefaultValue="SuperTip Title">
      </bt:String>
    </bt:ShortStrings>
    <bt:LongStrings>
      <bt:String id="residDesc"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residLabelTip"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residTip"
        DefaultValue="Run Test app">
      </bt:String>
      <bt:String id="residSuperTipDesc"
        DefaultValue="Run Test App">
      </bt:String>
    </bt:LongStrings>
  </Resources>

</VersionOverrides>

この Add-in を登録して Outlook 2016 で開くと、下図の通り、Mail の Read の際に Custom の Button が表示される。

execute01

このボタンをクリックすると、下図の通り、選択したメールの Reply 画面が起動する。

mail_popup

ExtensionPoint の type に指定している MessageReadCommandSurface は、「Mail の Read の画面にボタンを配置」という意味だ。ここに別の type を指定することで、Compose (メール作成・変更) の画面にボタンを配置したり、予定 (Appointment) の作成や閲覧の画面にボタンを配置することが可能だ。
また、command button ではなく、従来通りの custom pane を配置する場合、今後は、この type に CustomPane と指定して内容を記述できるようになっている。(過去のバージョンにも対応させる場合は、上述のような VersionOverrides の外の定義と、この定義の両方を書いておく必要があるだろう。)

また、Action の type に注目してほしい。
上記では ExecuteFunction を指定しているが、ここに下記の通り ShowTaskpane と指定すると、ボタンを押した際に Taskpane を表示させることが可能だ。

<VersionOverrides
  xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="VersionOverridesV1_0">

  <!-- skip here ... (same as above) -->

  <Hosts>
    <Host xsi:type="MailHost">

      <DesktopFormFactor>
        <FunctionFile resid="residFuncUrl" />

        <ExtensionPoint xsi:type="MessageReadCommandSurface">
          <OfficeTab id="TabDefault">
            <Group id="msgreadTabMessage.grp1">
              <Label resid="residLabel" />
              <Tooltip resid="residLabelTip" />
 
              <Control xsi:type="Button" id="button1id">
                <Label resid="residUILessButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
                <Action xsi:type="ExecuteFunction">
                  <FunctionName>showTest</FunctionName>
                </Action>
              </Control>

              <Control xsi:type="Button" id="button2id">
                <Label resid="residTaskpaneButton" />
                <Tooltip resid="residTip" />
                <Supertip>
                  <Title resid="residSuperTipTitle" />
                  <Description resid="residSuperTipDesc" />
                </Supertip>
                <Icon>
                  <bt:Image size="16" resid="icon1" />
                  <bt:Image size="32" resid="icon2" />
                  <bt:Image size="80" resid="icon3" />
                </Icon>
	              <Action xsi:type="ShowTaskpane">
	                <SourceLocation resid="residTaskpaneUrl" />
	              </Action>
              </Control>
              
            </Group>
          </OfficeTab>
        </ExtensionPoint>
      </DesktopFormFactor>
    </Host>
  </Hosts>

  <Resources>
    <bt:Images>
      <bt:Image id="icon1"
        DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
      </bt:Image>
      <bt:Image id="icon2"
        DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
      </bt:Image>
      <bt:Image id="icon3"
        DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
      </bt:Image>
    </bt:Images>
    <bt:Urls>
      <bt:Url id="residFuncUrl"
        DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
      </bt:Url>
      <bt:Url id="residTaskpaneUrl"
        DefaultValue="https://addintest01.azurewebsites.net/mypane.html" >
      </bt:Url>
    </bt:Urls>
    <bt:ShortStrings>
      <bt:String id="residLabel"
        DefaultValue="Test App">
      </bt:String>
      <bt:String id="residUILessButton"
        DefaultValue="Do Func">
      </bt:String>
      <bt:String id="residTaskpaneButton"
        DefaultValue="Show Pane">
      </bt:String>
      <bt:String id="residSuperTipTitle"
        DefaultValue="SuperTip Title">
      </bt:String>
    </bt:ShortStrings>
    <bt:LongStrings>
      <bt:String id="residDesc"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residLabelTip"
        DefaultValue="This is an add-in test.">
      </bt:String>
      <bt:String id="residTip"
        DefaultValue="Run Test app">
      </bt:String>
      <bt:String id="residSuperTipDesc"
        DefaultValue="Run Test App">
      </bt:String>
    </bt:LongStrings>
  </Resources>

</VersionOverrides>

[Show Pane] ボタンを押すと、下図の通り、指定した Url のページが Pane として表示される。
もちろん、この Web ページに、これまでの Mail Add-in のように、メールや予定と連携して動作する何某かの処理 (JavaScript) を埋め込んで使うことが可能だ。

execute02

最終的に作成した Manifest のサンプルを以下に掲載しておくので、コピーして、是非試してみていただきたい。(ただし、下記の Id などは変更しておくこと。)

なお、つい最近、この新機能に関する ドキュメントがリリースされたようなので、是非、参考にされたし !

Office Dev Center : Overview of add-in commands for mail

Office Dev Center : Create a manifest for add-in commands

<?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:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides"
  xsi:type="MailApp">
  <Id>{9AADFD5D-49A0-47C8-897F-1BB59D5116B5}</Id>
  <Version>1.0</Version>
  <ProviderName>Microsoft</ProviderName>
  <DefaultLocale>en-us</DefaultLocale>
  <DisplayName DefaultValue="My App Test"></DisplayName>
  <Description DefaultValue="This is a test"></Description>
  <Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="Mailbox" />
    </Sets>
  </Requirements>

  <FormSettings>
    <Form xsi:type="ItemRead">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app1.html" >
        </SourceLocation>
        <RequestedHeight>150</RequestedHeight>
      </DesktopSettings>
    </Form>
    <Form xsi:type="ItemEdit">
      <DesktopSettings>
        <SourceLocation
          DefaultValue="https://addintest01.azurewebsites.net/app2.html" >
        </SourceLocation>
      </DesktopSettings>
    </Form>
  </FormSettings>
  <Permissions>ReadWriteItem</Permissions>
  <Rule xsi:type="RuleCollection" Mode="Or">
    <Rule xsi:type="ItemIs"
      ItemType="Message"
      FormType="Edit" />
    <Rule xsi:type="ItemIs"
      ItemType="Appointment"
      FormType="Edit" />
  </Rule>
  <DisableEntityHighlighting>true</DisableEntityHighlighting>

  <VersionOverrides
    xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
    xsi:type="VersionOverridesV1_0">

    <Description resid="residDesc" />

    <Requirements>
      <bt:Sets DefaultMinVersion="1.3">
        <bt:Set Name="Mailbox" />
      </bt:Sets>
    </Requirements>

    <Hosts>
      <Host xsi:type="MailHost">

        <DesktopFormFactor>
          <FunctionFile resid="residFuncUrl" />

          <ExtensionPoint xsi:type="MessageReadCommandSurface">
            <OfficeTab id="TabDefault">
              <Group id="msgreadTabMessage.grp1">
                <Label resid="residLabel" />
                <Tooltip resid="residLabelTip" />
 
                <Control xsi:type="Button" id="button1id">
                  <Label resid="residUILessButton" />
                  <Tooltip resid="residTip" />
                  <Supertip>
                    <Title resid="residSuperTipTitle" />
                    <Description resid="residSuperTipDesc" />
                  </Supertip>
                  <Icon>
                    <bt:Image size="16" resid="icon1" />
                    <bt:Image size="32" resid="icon2" />
                    <bt:Image size="80" resid="icon3" />
                  </Icon>
                  <Action xsi:type="ExecuteFunction">
                    <FunctionName>showTest</FunctionName>
                  </Action>
                </Control>
                
                <Control xsi:type="Button" id="button2id">
                  <Label resid="residTaskpaneButton" />
                  <Tooltip resid="residTip" />
                  <Supertip>
                    <Title resid="residSuperTipTitle" />
                    <Description resid="residSuperTipDesc" />
                  </Supertip>
                  <Icon>
                    <bt:Image size="16" resid="icon1" />
                    <bt:Image size="32" resid="icon2" />
                    <bt:Image size="80" resid="icon3" />
                  </Icon>
	                <Action xsi:type="ShowTaskpane">
	                  <SourceLocation resid="residTaskpaneUrl" />
	                </Action>
                </Control>

              </Group>
            </OfficeTab>
          </ExtensionPoint>
        </DesktopFormFactor>
      </Host>
    </Hosts>

    <Resources>
      <bt:Images>
        <bt:Image id="icon1"
          DefaultValue="https://addintest01.azurewebsites.net/myimg16.bmp" >
        </bt:Image>
        <bt:Image id="icon2"
          DefaultValue="https://addintest01.azurewebsites.net/myimg32.bmp" >
        </bt:Image>
        <bt:Image id="icon3"
          DefaultValue="https://addintest01.azurewebsites.net/myimg80.bmp">
        </bt:Image>
      </bt:Images>
      <bt:Urls>
        <bt:Url id="residFuncUrl"
          DefaultValue="https://addintest01.azurewebsites.net/myfunc.html" >
        </bt:Url>
        <bt:Url id="residTaskpaneUrl"
          DefaultValue="https://addintest01.azurewebsites.net/mypane.html" >
        </bt:Url>
      </bt:Urls>
      <bt:ShortStrings>
        <bt:String id="residLabel"
          DefaultValue="Test App">
        </bt:String>
        <bt:String id="residUILessButton"
          DefaultValue="Do Func">
        </bt:String>
        <bt:String id="residTaskpaneButton"
          DefaultValue="Show Pane">
        </bt:String>
        <bt:String id="residSuperTipTitle"
          DefaultValue="SuperTip Title">
        </bt:String>
      </bt:ShortStrings>
      <bt:LongStrings>
        <bt:String id="residDesc"
          DefaultValue="This is an add-in test.">
        </bt:String>
        <bt:String id="residLabelTip"
          DefaultValue="This is an add-in test.">
        </bt:String>
        <bt:String id="residTip"
          DefaultValue="Run Test app">
        </bt:String>
        <bt:String id="residSuperTipDesc"
          DefaultValue="Run Test App">
        </bt:String>
      </bt:LongStrings>
    </Resources>

  </VersionOverrides>
</OfficeApp>

Add-in for Outlook.com (旧 Hotmail における Web Add-in 対応)

既に春にアナウンスされたが、outlook.com (旧 Hotmail) でも Mail Add-in (旧 App for Outlook の Mail App) が扱えるようになる。

Hotmail_App

Option メニューから [Manage Add-in] を選択すると Add-in の管理画面が表示され、

Manage_Addin

通常の (Exchange 版 Outlook の) Mail Add-in 同様、ここから Add-in のファイル (拡張子 .app) やオンライン上で公開されている URL を入力すれば登録が可能だ。
(正式リリースの際には、おそらく、ストアからのダウンロードも可能になるのだろう。)

Add_Addin

outlook.com で扱えるようになったことによる、もう 1 つの隠れたメリット (開発者のメリット) として、Napa で動かしやすくなったことだ。

このブログでも紹介したように、Tenant-less Napa を使うと Microsoft Account だけで Office Add-in が簡単に開発できるが、これまで、Mail Add-in (Add-in for Outlook) の展開 (配置) の際には Exchange (Exchange Online 含む) に登録する必要があり、再度、Office 365 のアカウントなどで入りなおす必要があった。
これが、この outlook.com の Add-in 対応で、Microsoft Account でログインしたまま、Add-in の動作確認まで可能になった

なお、現時点では、Preview に申し込んだ Developer のみが試せるようになっている。

Browser Only, Office 365 不要の Office Add-in 開発 – Tenant-less Napa

「Napa」という名前のブラウザ ベースの Office Add-in 開発環境があるが、これまで、Napa を使うには以下の面倒な手続きが必要だった。

  1. Office 365 アカウントを取得する (お金がかかるので、1 ヶ月試用版など)
  2. Office 365 にログインして、SharePoint の developer site を構築する
  3. 作成した site の Site Contents として、Office Store から Napa をインストールする
  4. ようやく Napa を使える

特に、昨今、Mac を利用している人も多いので Napa のような Browser ベースの開発環境は重宝するが、ただ Office Add-in 開発をするだけなのに、1 ヶ月限定の Office 365 trial を契約し、SharePoint の使い方をおぼえるなど、意味のないハードルを超える必要があった。

今後は、Napa だけ使うなら、Office 365 や SharePoint が不要で Microsoft Account さえあれば、将来に渡ってタダで利用可能 になった。(厳密には、Napa は、Live Services のアプリとして提供されるようになった。)
以下にアクセスして Microsoft Account で SignIn すれば、すぐに Napa を使い始めることができる。

Tenant-less Napa
https://www.napacloudapp.com

napa

Visual Studio Online “Monaco” さながらの Browser Editor で開発をおこなえる。

edit

そして、Run Project] を実行すると、アプリに応じて、Excel Online、Word Online、Outlook Web App などが起動して動作をすぐに確認できる。
裏側では OneDrive が使用されている

run

完成したら、Visual Studio のプロジェクトとして出力も可能だ。

Add-in for Outlook (旧 メール・アプリ) の場合のみ、「@IT – Office 用アプリの作り方と、できること/できないこと」で解説したように Exchange (サーバー) が必要となるため、結局、実行時に Office 365 アカウントにログインする必要があるが、今後 (もうすぐ)、Add-in for Outlook も Outlook.com (旧 Hotmail) で動かすことができるので、こうなると、すべての Add-in 開発で Office 365 へのログインは不要になる。(この Outlook.com 対応は、現在、限定的な Preview として提供されている。)

Office Add-in Context Highlighting

最近開催された MS の大きなイベント (BUILD, Ignite) にあわせて、Office Add-ins (旧 App for Office) にいくつか Preview を含む機能が追加されている。
そんなわけで、ちょっと自分の整理のためにも、ここ数か月で Update された Office Add-ins の内容についてメモしておきたい。

まず、少し前に提供された OWA の Context Highlighting について。

「Office用アプリ」の作り方と、できること/できないこと』で解説したように、Mail Add-ins for Outlook (旧 メール アプリ) では正規表現などの Rule (ItemHasKnownEntity, ItemHasRegularExpressionMatch を使用した Rule) を持つ Contextual Add-in では、その条件 (正規表現など) とマッチングしている場合に下図の通り Add-ins のリンクが表示されるが、まあ正直、これに気付いてクリックしてくれる人は実際なかなかいなかったのではないかと思う。。。

dt-officestoreapp_01_10

今後は、Outlook Web App で参照した際に、マッチングしている箇所に下図の通りリンクが表示されて、このリンクをクリックすることで Add-ins (アプリ) がポップアップで表示されるようになった。(下図のような感じ)

Click 前
Content_Highlighting01

Click 後
Content_Highlighting02

この機能 (Context Highlighting) は、下記のいずれかの条件に合致する場合には適用されない (その場合には、従来通りの表示方法になる) ので注意してほしい。

  • ItemHasKnownEntity として、Url か EmailAddress の Entity が使われた場合
  • type が ItemHasRegularExpressionMatch で、Property が NameBodyAsHTML か SenderSMTPAddress の Rule がある場合
  • 以下の条件に合致する OR の RuleCollection がある場合
    • 最初の Rule の type が ItemIs で、itemType が Appointment か Message
    • 次の Rule の type が ItemHasKnownEntity か ItemHasRegularExpressionMatch
  • e-mail の body が複雑な場合

例えば、下記のような Rule では、下図のように表示される。

<Rule xsi:type="RuleCollection" Mode="And">
  <Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
  <Rule xsi:type="ItemHasRegularExpressionMatch" 
    PropertyName="BodyAsPlaintext" RegExName="highlighttest"
    RegExValue="This is [a-zA-Z0-9_-]*" />
</Rule>

Custom_Sample

JavaScript API 1.1 for Office でメール編集アプリが可能に !

JavaScript API 1.1 for Office が公開されたようだ。

JavaScript API 1.1 for Office :
https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js

この API は、Office 2013 SP1 と組み合わせて使うようなので、あとは SP1 を待つだけだ。ちなみに、 Office Blogs の投稿 によれば、 Office 2013 SP1 のリリースもそう遠くはないだろう。

さて、この Update で自分が特に注目しているのは、Mail Add-in (旧 メール アプリ) だ。

既にドキュメントが出ているが、 Office 2013 SP1 を適用することで Mail Add-in の Compose form、つまり、メール (Message) や予定 (Appointment) の作成・編集画面でもアプリを表示することができる。(これまでは表示画面でしかアプリを扱えなかった。) さらに、JavaScript 1.1 の API リファレンスを見ると、「Added to enable creating and editing the body of a message or appointment in compose mode」と書かれており、 添付ファイル (Attachment) を追加する addFileAttachmentAsync メソッドや、Body への setSelectedDataAsync メソッドなどが追加されている。

バージョンこそマイナーアップだが、想像してもらうとわかるが、これは相当可能性が広がる。
例えば、メール (Message) の作成を支援したり、コンテキストにあわせた予定表 (Appintment) の作成をおこなうような、ようやく実用的な Mail App (メール アプリ) が作れるようになってくる。

@IT : Office App の作り方と、できること/できないこと」にも書いたが、 もともと Mail Add-in の API は可能性が広く、この点 (作成・編集を扱えない点) が指摘されてきたが、これからは Mail Add-in がますますおもしろくなってきそうだ。(きっとフィードバックも多かったのだろう)

Word の Content Control を使った Office Add-ins のドキュメント テンプレート

Office Add-ins (旧 App for Office) について記事を書いたので紹介したい。

@IT : Officeストアで世界に飛び出そう! 最新Office 2013アプリ開発入門

前編は、まず、Office Add-ins がどのようなものか基本を理解し、後編で、「じゃあ、どのような設計方針で作っていくか」、「どこまで出来て、どこからできないか」 など全体像を解説して理解を深めてもらう予定だ。(既に原稿はあるが、結構きれいにまとめたつもりなので期待しててほしい。)

後編で解説するが、Word を使用した Office Add-in では Custom XML Part と連携したアプリ開発も可能で、Word のドキュメント テンプレートと組み合わせた Office Add-in (Task-pane Add-in) も作成可能だ。ただ、この辺りを万人にわかるようにちゃんと説明すると、「そもそも Custom XML Part って何 ?」 から始まり、さらに動くソース コードまで載せると、それだけでも長い記事になってしまうので、この辺りは「できること」、「できないこと」を明示する程度の解説を予定している。

そこで、この投稿では、ちょっとその辺りの開発手法について補足しておこう。

Content Control と Custom XML Part

まずは、背景から解説する。

Word のコンテンツ コントロール (Content Control) とは、 Word に挿入できるテキスト ボックスやチェック ボックスなどの入力欄のことで、 Word (Word 2007 以上) のリボンの開発タブ (Developer Tab) を表示することで挿入できる。下図のようなフォームを作成する際に使えるコントロールだ。

ContentsControl

さて、この Content Control の嬉しい点は、 Word (Word 2007 以上) の Office OpenXML (OOXML) とのバインドが可能な点だ。

例えば、Office Open XML (OOXML) のフォーマットになってから、 Word 文書には独自の XML ファイル (外部システムで作成した XML ファイルなど) が挿入できるようになっていて、 これをカスタム XML パーツ (Custom XML Part) と呼ぶ。(このファイルは、Word の利用者からは見えない。) この挿入された XML ファイルの各要素を、 上図の Content Control にバインドすることが可能であり、 Word の外のプログラムなどから、この XML ファイルの内容を更新することで、バインドされた Word 文書上の Content Control の内容を変更できる。 例えば、外部のシステムから送られてくる発注データの XML をそのまま使って、 Word 文書と連携させることができる。(SOA によるシステム間連携のシナリオ、など)

もちろん、Office Open XML (OOXML) を使って、直接 Content Control の値 (データ) を変更しても良いが、 このバインドを使った方法だと、 データ (すなわち、XML ファイル) とビュー (Word 文書) のデザインを切り離して管理できるわけだ。プログラムは、 特定の Custom XML Parts と連携するように作っておけば、 Word 文書のほうは自由に変更して構わない。また、単一の Custom XML Parts から複数の Content Control にもバインドできるため、Word 文書内で項目を関連付けておくことができる。

事前準備

OOXML を使って Custom XML Parts を挿入したり、Content Control とバインドする方法は、実は Microsoft Word には提供されていない。この処理をおこなう正統派の方法は、プログラミングだ。C# には、OOXML を含むパッケージ フォーマットのファイルを扱うライブラリーがあり (System.IO.Packaging 名前空間のクラス)、 このライブラリーを使うことで、こうした処理が可能だ。 もちろん、.docx ファイル (実体は .zip) を展開して、手動で zip ファイルの中身を編集しても良いが、 やってもらうとわかるが、相当きつい。(関連する定義が複数の場所に書かれていて、これらをすべて正しく編集しないと Word で開けなくなる。)

そこで、実は、CodePlex に、こうした編集を簡素化できるツールが提供されている。以下のツールをインストールしてみてほしい。

[CodePlex] Word Content Control Toolkit
http://dbe.codeplex.com/

例えば、独自の XML ファイルを Custom XML として挿入した Word 文書 (.docx) を、 Word Content Control Toolkit で参照すると、以下の通りだ。右ペインに Custom XML の内容が表示され、 左ペインには Word 文書に挿入している Content Control が表示される。

ContentControlToolkit

左の Content Control と右の XML の要素をバインドするには、 右ペインを [Bind View] に切り替え、 右の要素から左の要素にドラッグ・アンド・ドロップをおこなう。下図は、右 (Custom XML) の「Name」と、左 (Content Control) の「Name」をバインドさせた場合だ。下図の通り、 左ペインには、バインドしている Custom XML の XPath が表示される。

Bind

動作はご想像の通り、Word 文書内を変更するとリアル タイムに Word 内部の XML (Custom XML Part) が変更され、 逆に、プログラムなどを使って XML を変更すると、リアル タイムに Word 文書が変更される。

Execute1

開発手法 – Add-in for Word の Programming

では、この Custom XML を使用した簡単な Office Add-ins のプログラムを記述してみよう。 今回の Office Add-in では、「Bing Maps の Geocode、逆 Geocode のプログラミング」で紹介したプログラミングを使って、Bing Maps を使って地図をクリックすると、その住所を取得して、上記の Custom XML に設定する簡単なサンプル コードを作成する。すなわち、Bing Maps をクリックすると、下図の Word 文書の住所欄が、選択された住所に変更される。
Execute2

このプログラムは、下記のようなコードになる。(Office Add-ins のプログラミング手法については、上記の @IT の記事を参照してほしい。)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery/
    jquery-1.9.0.min.js"></script>
  <script src="http://appsforoffice.microsoft.com/lib/1.0/hosted/
    office.js"></script>
  <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?
    v=6.3&mkt=ja-jp"></script>
  <script>
  Office.initialize = function (reason) {
    $(document).ready(function () {
      map = new VEMap('map');
      map.LoadMap();
      map.SetCenterAndZoom(new VELatLong(35.70, 139.7), 13); 
      map.AttachEvent("onclick", function (e) {
        // execute when right click !
        if (!e.rightMouseButton)
          return;

        $('#msgline').html('getting location ...');

        // Get latlong
        var lat;
        if (e.latLong) {
          lat = e.latLong;
        } else {
          var pxl = new VEPixel(e.mapX, e.mapY);
          lat = map.PixelToLatLong(pxl);
        }

        // Push a pin 
        map.Clear()
        var shape = new VEShape(VEShapeType.Pushpin, lat);
        map.AddShape(shape);

        // Reverse-geocode 
        map.FindLocations(lat, function (loc) {
          if (loc != null && loc.length > 0) {
            Office.context.document.customXmlParts.getByNamespaceAsync(
              "TestNS1", function (resXml) {
              var xmlPart = resXml.value[0];
              xmlPart.getNodesAsync(
                '/ns0:EmployeeInfo[1]/ns0:Address[1]',
                function (resNode) {
                resNode.value[0].setXmlAsync(
                  '<Address xmlns="TestNS1">'
                  + loc[0].Name
                  + '</Address>');
              });
            });
          }
        });

        $('#msgline').html('location changed !');
      });

      $('#msgline').html('ready !');
    });
  };
  </script>
</head>
<body>
  <div id="map" style="position:relative;width:250px;height:400px;"> 
  </div>
  <p id="msgline" style="background-color:gray;">initializing ...</p>
</body>
</html>

上記のコードで、XPath (/ns0:EmployeeInfo[1]/ns0:Address[1]) として「ns0」の Prefix を暗黙裡に使用しているが、 実際のプログラミングでは、xmlPart.namespaceManager.getPrefixAsync を使って、割り当てられた Prefix を取得したほうが良い。(いちおう、ns0、ns1、ns2 という具合に、 順番に割り当てられる。今回は、さぼって書いている。)

なお、Office Add-ins の JavaScript API では、上記の通り、Custom XML データの入出力はできるが、バインドができないため注意が必要だ。つまり、C# でプログラミングする場合に可能であった Custom XML データの変更イベントの取得などは、この JavaScript API では不可能だ。(ただし、Node 自体の Insert、Delete、Replace のイベントをとることは可能だ。)

また、今後修正されるかもしれないが、今 (Preview 2 では)、上記のプログラムの通り、変更箇所に XML 名前空間の定義 (xmlns) を明示しておかなければいけないようだ。(これを省略すると、setXmlAsync メソッドが、名前空間としてブランクを設定するため。)

xmlns=”TestNS1″>Some address text

これに限らず、まだ、いくつか制限があるようなので、実際のプログラミングでは注意してほしい。

なお、Visual Studio を使うと、こうしたドキュメント テンプレートを使用した開発の場合に、下図の通り、ドキュメントを指定してデバッグ実行できる。Office Add-in のプログラミングは、PHP、Ruby、Node などサーバー側の開発言語に依存せず同じように書ける点が魅力だが、 上記の記事にも記載した通り、実際、「開発レベル」のプログラミングの場合には VS を使っておいたほうが無難だ。(逆の言い方をすれば、VS 以外で作ろうとすると、デバッグが結構きつい。。。)

VSDebug

Document Driven Office Add-in (まとめ)

今回は Custom XML を介してドキュメント連携をおこなったが、Add-in for Word では HTML や OOXML を挿入できるので、 例えば、Word 文書にイメージ ファイルなどのマルチメディア情報を挿入することもできる。(ただし、OOXML を使って文書のフルカスタマイズができるわけではないので注意してほしい。OOXML を使って Add-in の JavaScript API でできることは限られている。)

また、上記を応用して、SharePoint との連携も可能だ。 一般に、Word 文書と SharePoint のドキュメント ライブラリーに保存するプロパティを連携させる場合には、クイック パーツ (Quick Parts) が使用されるが、これも基本的には上記と同じ仕組み (Custom XML) を使った実装だからだ。(SharePoint のプロパティは、CustomXML の http://schemas.microsoft.com/office/2006/metadata/properties 名前空間の、documentManagement 要素に入っている。)
SharePoint の Content Type を作成して、この Content Type の document template (Word 文書) を取得すると、既に Custom XML が設定されているので、この Custom XML と連携して動作する Office Add-in を上記の通り構築し、 この Add-in を貼り付けた Word 文書 (.dotx, .docx) を、この Content Type の document template として設定しなおせば良い。

なお、SharePoint 2013 で Content Type の既定の document template を取得するには、 その Content Type を使用した Document Library を作成して、 エクスプローラー ビュー (Explorer View)、または、 SharePoint Designer から参照 (「すべてのファイル」から参照) することで、 テンプレート (template.dotx) を取得できる。

さらに、こうしたテンプレートを含んだリスト定義そのものを SharePoint Add-ins (旧 Apps for SharePoint) として配布することもできるだろう。