SharePointにJavaScriptでTickerを実装する - Tickerの作成(1)

jQuery プラグインとして Ticker としてリスト(ul要素など)を表示するものは結構あったけど、下記を満たすものがなかったので自前で作成することに。

  • 定期的(30分とか)に最新のアイテムを取りに行く
  • アイテムが右から流れてきて、左端で停止、しばらく表示したら消えて、次のアイテムへといったような動き
  • アイテムにマウスを乗せると詳細が表示される

まずは Ticker として表示させるデータを前回までに作成した MOSS Client jQuery Plugin で表示させてみる。定義リスト(dl)を使って、アイテムのタイトルと dt として、本文を dd として作成する。

MOSS.Lists.getListItems({
    listName: '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}',
    query: '<Query><OrderBy><FieldRef Name="Modified" Ascending="FALSE"></FieldRef></OrderBy></Query>',
    fields: '<ViewFields><FieldRef Name="ID" /><FieldRef Name="Title" /><FieldRef Name="Body" /><FieldRef Name="ServerUrl" /><FieldRef Name="Modified" /></ViewFields>',
    rowLimit: '5',
    callback: function(result) {
        if ( result.error ) {
            alert('Code : ' + result.error.code + '\nReason : ' + result.error.reason + '\nDetail' + result.error.detail);
        }
        var html = '<dl>';
        for ( var i = 0; i < result.rows.length; i++ )
        {
            var r = result.rows[i];
            var vals = r.getAttribute('ows_ServerUrl').split('/');    vals.pop();
            var url = vals.join("/") + '/DispForm.aspx?ID=' + r.getAttribute('ows_ID');    //    アイテムへのリンク
            html += '<dt><a href="' + url + '">' + r.getAttribute('ows_Title') + 
                    '</a><span>(' + r.getAttribute('ows_Modified') + ')</span></dt>'
            html += '<dd>' + r.getAttribute('ows_Body') + '</dd>';
        }
        html += '</dl>';
        $('body').html(html);
    }});

こんな感じで。あとは作成した定義リストから前述のような動きを実装していく。

SharePointにJavaScriptでTickerを実装する - jQueryプラグイン化(MOSS Client) (2)

詳細はソースをみてもらうとして、それぞれ簡単に例示を。

共通事項

関数の呼び出しはすべて非同期で実行される

MOSS.<endpoint>.<functionName>({
    url : '/_vti_bin/<endpoint>.asmx',
    callback: function(data, error) { },
    <param1>:...,
    <param2>:...,
});
<endpoint> Lists.asmx の場合、Lists というように asmx をのぞいた部分
<functionName> <endpoint> にある関数名
url エンドポイントへのURLを指定する場合は設定する。指定しなくてもかまわない。
callback 呼び出しが完了した際にここで指定した関数が呼ばれる。
第一引数の data は$.ajax({ complete : function (data) {} }); の第一引数(data)がそのまま入る
第二引数の error は SOAP Fault があれば値が入り、エラーがなければ null
<param1> 他 それぞれの関数の必要に応じていろいろ指定

MOSS.SiteData

SiteData.asmx で提供される関数のラッパー

getWeb

GetWeb 関数、主に WebID 調査用のため。

MOSS.SiteData.getWeb({
    callback: function(result) {
        alert(result.webMetadata.title + ' のWebIDは下記の通りです\n\n' + result.webMetadata.webID);
    }});
result.webMetadata webID, title, description, author, lastModified についてまとめたもの
result.data $.ajax({ complete : function (data) {} }); の data
result.error エラー情報(SOAP Fault)

MOSS.Lists

getListCollection

GetListCollection 関数、主にリストの一覧取得のため。

MOSS.Lists.getListCollection({
    callback: function(result) {
        if ( result.error ) {
            alert('Code : ' + result.error.code + '\nReason : ' + result.error.reason + '\nDetail' + result.error.detail);
        }
        var html = '<ul>';
        for ( var i = 0; i < result.lists.length; i++ ) {
            html += '<li><a href="' + result.lists[i].url + '">' + result.lists[i].title + '</a></li>';
        }
        html += '</ul>';
        $('body').html(html);
    }});
result.lists 比較的よく使いそうな id, title, url, description の配列
result.rows selectNodes('/soap:Envelope/soap:Body/GetListCollectionResponse/GetListCollectionResult/Lists/List'); の結果
result.data $.ajax({ complete : function (data) {} }); の data
result.error エラー情報(SOAP Fault)
getListItems

GetListItems 関数、アイテムの取得のため。

MOSS.Lists.getListItems({
    listName: '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}',
    //viewName: 'ビュー名(GUID)',
    //query: '<query>〜〜</query>',
    //fields: '<ViewFields><FieldRef Name="ID" /><FieldRef Name="Title" /><FieldRef Name="Body" /></ViewFields>',
    //rowLimit: '5',
    //options: '<QueryOptions>〜〜</QueryOptions>',
    //webID: 'WebID(GUID)',
    callback: function(result) {
        var html = '<dl>';
        for ( var i = 0; i < result.rows.length; i++ ) {
            html += '<dt>' + result.rows[i].getAttribute('ows_Title') + '</dt>';
            html += '<dd>' + result.rows[i].getAttribute('ows_Body') + '</dd>';
        }
        html += '</dl>';
        $('body').html(html);
    }});
result.rows selectNodes('/soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/listitems/rs:data/z:row'); の結果
result.data $.ajax({ complete : function (data) {} }); の data
result.error エラー情報(SOAP Fault)

MOSS.Imaging

Lists.asmx の画像ライブラリー版(みたいなもの)

listPictureLibrary

ListPictureLibrary 関数、画像ライブラリの一覧取得のため。関数名が違うだけで MOSS.Lists.getListCollection とほぼ同じ。

MOSS.Imaging.listPictureLibrary({
    callback: function(result) {
        var html = '<ul>';
        for ( var i = 0; i < result.lists.length; i++ ) {
            html += '<li>' + result.lists[i].title + '</li>';
        }
        html += '</dl>';
        $('body').html(html);
    }});
getListItems

GetListItems 関数、画像ライブラリのアイテム取得のため。

MOSS.Imaging.getListItems({
    listName: 'リスト名(listPictureLibraryで取得できる title を指定する)',
    //folder: 'フォルダ名',
    callback: function(result) {
        if ( result.error ) {
            alert('Code : ' + result.error.code + '\nReason : ' + result.error.reason + '\nDetail' + result.error.detail);
        }
        var html = '<ul>';
        for ( var i = 0; i < result.rows.length; i++ ) {
            html += '<li>' + result.rows[i].getAttribute('ows_EncodedAbsUrl') + '</li>';
        }
        html += '</ul>';
        $('body').html(html);
    }});

SharePointにJavaScriptでTickerを実装する - jQueryプラグイン化(MOSS Client) (1)

AJAX のために jQuery を使ったので、せっかくだから MOSS の WebService を処理する jQueryプラグインとして作成してみた。
初めて作ってみたのでいろいろ恥ずかしいところがあるかもしれないけどそこはご愛敬。普段は JavaScript をいじらないのでちょっと楽しかった。現状では、ごく一部である下記のサービスに対応している。必要に応じていろいろ追加予定。もし利用される方がいれば各自の責任でご自由にどうぞ。それぞれの説明とかはまた明日以降〜。

Endpoint Function
SiteData.asmx GetWeb
Lists.asxm GetListItems
GetListCollection
Imaging.asmx GetListItems
ListPictureLibrary
////////////////////////////////////////////////////////////////////////////////
//    jQuery Plugin - MOSS Client (by Kz)
 
////////////////////////////////////////////////////////////////////////////////
//    MOSS Clinet Common
var MOSS = MOSS || {
    Imaging: {},
    Lists: {},
    SiteData: {}
};
 
jQuery.extend(MOSS, {
    callSoapService: function(param) {
        $.ajax({
            type: 'POST',
            url: param.url,
            contentType: 'text/xml; charset=utf-8',
            dataType: 'xml',
            processData: false,
            data: param.postData,
            complete: function(data) {
                if (param.callback) {
                    var fault = data.responseXml.selectSingleNode('/soap:Envelope/soap:Body/soap:Fault');
                    var error = null;
                    if (fault) {
                        error = {
                            code: fault.selectSingleNode('faultcode').text,
                            reason: fault.selectSingleNode('faultstring').text,
                            detail: fault.selectSingleNode('detail').text
                        };
                    }
                    param.callback(data, error);
                }
            },
            beforeSend: function(req) {
                req.setRequestHeader('Content-Length', param.postData.length);
                req.setRequestHeader('SOAPAction', param.soapAction);
            }
        });
    }
});
////////////////////////////////////////////////////////////////////////////////
//    SiteData.asmx
jQuery.extend(MOSS.SiteData, {
    servicePath: '/_vti_bin/SiteData.asmx',
 
    getWeb: function(param) {
        MOSS.callSoapService({
            url: param.url ? param.url : this.servicePath,
            postData: '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetWeb xmlns="http://schemas.microsoft.com/sharepoint/soap/" /></soap:Body></soap:Envelope>',
            soapAction: 'http://schemas.microsoft.com/sharepoint/soap/GetWeb',
            callback: function(data, error) {
                if (!param.callback) {
                    return;
                }
                var xmlRes = data.responseXml.selectSingleNode('/soap:Envelope/soap:Body/GetWebResponse');
                if (xmlRes) {
                    var xmlWM = xmlRes.selectSingleNode('sWebMetadata');
                    if (xmlWM) {
                        param.callback({
                            webMetadata: {
                                webID: xmlWM.selectSingleNode('WebID').text,
                                title: xmlWM.selectSingleNode('Title').text,
                                description: xmlWM.selectSingleNode('Description').text,
                                author: xmlWM.selectSingleNode('Author').text,
                                lastModified: xmlWM.selectSingleNode('LastModified').text
                            },
                            data: data,
                            error: error
                        });
                        return;
                    }
                }
                //    Failed?
                param.callback({ data: data, error: error });
            }
        });
    }
});
////////////////////////////////////////////////////////////////////////////////
//    Lists.asmx
jQuery.extend(MOSS.Lists, {
    servicePath: '/_vti_bin/Lists.asmx',
 
    getListCollection: function(param) {
        MOSS.callSoapService({
            url: param.url ? param.url : this.servicePath,
            postData: '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/" /></soap:Body></soap:Envelope>',
            soapAction: 'http://schemas.microsoft.com/sharepoint/soap/GetListCollection',
            callback: function(data, error) {
                if (!param.callback) {
                    return;
                }
                var rows = data.responseXml.selectNodes('/soap:Envelope/soap:Body/GetListCollectionResponse/GetListCollectionResult/Lists/List');
                var listArray = [];
                for (var i = 0; i < rows.length; i++) {
                    listArray.push({
                        url: rows[i].getAttribute('DefaultViewUrl'),
                        id: rows[i].getAttribute('ID'),
                        title: rows[i].getAttribute('Title'),
                        descriptiopn: rows[i].getAttribute('Description')
                    });
                }
                param.callback({
                    lists: listArray,
                    rows: rows,
                    data: data,
                    error: error
                });
            }
        });
    },
 
    getListItems: function(param) {
        var postData = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">' +
                        '<listName>' + param.listName + '</listName>' +
                        (param.viewName ? ('<viewName>' + param.viewName + '</viewName>') : '') +
                        (param.query ? ('<query>' + param.query + '</query>') : '') +
                        (param.fields ? ('<viewFields>' + param.fields + '</viewFields>') : '') +
                        (param.rowLimit ? ('<rowLimit>' + param.rowLimit + '</rowLimit>') : '') +
                        (param.options ? ('<queryOptions>' + param.options + '</queryOptions>') : '') +
                        (param.webID ? ('<webID>' + param.webID + '</webID>') : '') +
                        '</GetListItems></soap:Body></soap:Envelope>';
        MOSS.callSoapService({
            url: param.url ? param.url : this.servicePath,
            postData: postData,
            soapAction: 'http://schemas.microsoft.com/sharepoint/soap/GetListItems',
            callback: function(data, error) {
                if (!param.callback) {
                    return;
                }
                param.callback({
                    rows: data.responseXml.selectNodes('/soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/listitems/rs:data/z:row'),
                    data: data,
                    error: error
                });
            }
        });
    }
});
////////////////////////////////////////////////////////////////////////////////
//    Imaging.asmx
jQuery.extend(MOSS.Imaging, {
    servicePath: '/_vti_bin/Imaging.asmx',
 
    listPictureLibrary: function(param) {
        MOSS.callSoapService({
            url: param.url ? param.url : this.servicePath,
            postData: '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ListPictureLibrary xmlns="http://schemas.microsoft.com/sharepoint/soap/ois/" /></soap:Body></soap:Envelope>',
            soapAction: 'http://schemas.microsoft.com/sharepoint/soap/ois/ListPictureLibrary',
            callback: function(data, error) {
                if (!param.callback) {
                    return;
                }
                var rows = data.responseXml.selectNodes('/soap:Envelope/soap:Body/ListPictureLibraryResponse/ListPictureLibraryResult/PictLib/Library');
                var listArray = [];
                for (var i = 0; i < rows.length; i++) {
                    listArray.push({
                        url: rows[i].getAttribute('url'),
                        id: rows[i].getAttribute('guid'),
                        title: rows[i].getAttribute('title'),
                        name: rows[i].getAttribute('name')
                    });
                }
                param.callback({
                    lists: listArray,
                    rows: rows,
                    data: data,
                    error: error
                });
            }
        });
    },
 
    getListItems: function(param) {
        var postData = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/ois/">' +
                        '<strListName>' + param.listName + '</strListName>' +
                        (param.folder ? ('<strFolder>' + param.folder + '</strFolder>') : '') +
                        '</GetListItems></soap:Body></soap:Envelope>';
        MOSS.callSoapService({
            url: param.url ? param.url : this.servicePath,
            postData: postData,
            soapAction: 'http://schemas.microsoft.com/sharepoint/soap/ois/GetListItems',
            callback: function(data, error) {
                if (!param.callback) {
                    return;
                }
                param.callback({
                    rows: data.responseXml.selectNodes('/soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/Library/z:row'),
                    data: data,
                    error: error
                });
            }
        });
    }
});

SharePointにJavaScriptでTickerを実装する - WebService の呼び出し(3)

返値

正常時

GetListItems は /soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/Library 以下に1アイテム 1row としてデータが返ってくる。それぞれのフィールドの値は row の属性値とその値だが、viewFields で指定したフィールド名の頭に ows_ がなぜだかついてくる。

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
            <GetListItemsResult>
                <listitems xmlns:s='uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' xmlns:dt='uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'>
                    <rs:data ItemCount="11">
                        <z:row ows_Attachments='0' ows_LinkTitle='〜〜〜〜' ows_Modified='2008-08-21 10:33:23' ows_MetaInfo='5;#' ows__ModerationStatus='0' ows__Level='1' ows_Title='〜〜〜〜' ows_ID='5' ows_owshiddenversion='6' ows_UniqueId='5;#{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}' ows_FSObjType='5;#0' ows_Created_x0020_Date='5;#2007-05-21 16:11:45' ows_Created='2007-05-21 16:11:45' ows_FileLeafRef='5;#5_.000' ows_FileRef='5;#Lists/List4/5_.000' />
                        (略)
                    </rs:data>
                </listitems>
            </GetListItemsResult>
        </GetListItemsResponse>
    </soap:Body>
</soap:Envelope>
エラー時

SOAP のエラーとして返ってくるので、/soap:Envelope/soap:Body/soap:Fault があればエラーと見てよさそう。下記は viewName を指定したけど、そのビューがなかった場合のエラー例

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Server</faultcode>
            <faultstring>種類 'Microsoft.SharePoint.SoapServer.SoapServerException' の例外がスローされました。</faultstring>
            <detail>
                <errorstring xmlns="http://schemas.microsoft.com/sharepoint/soap/">
                    ビューがありません。
                    選択したページは、存在しないビューを参照しています。他のユーザーによって削除された可能性があります。
                </errorstring>
                <errorcode xmlns="http://schemas.microsoft.com/sharepoint/soap/">0x82000005</errorcode>
            </detail>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

jQuery プラグイン - SOAP Client

SOAP を扱う jQuery プラグインってあるかなーと探してたら発見。

これは、Xml から JSON へ変換してくれるプラグインと一緒に利用するらしい。今回は MOSS をいじるだけなのでこれを使うと冗長になりそうだったから利用は見送ったけど、備忘録代わりに。