ExtJSの使い方を勉強しながらだったのでソースは汚いです。
使ったウィジェットは
- Ext.grid.EditorGridPanel(エクセルみたいなパネル)
- Ext.TabPanel(タブパネル)
- Ext.form.ComboBox(ドロップダウンリスト)
- Ext.DataView(データビュー。アイテムのソートやフィルタなんかができる)
- Ext.Window(ウィンドウがポップする)
- Ext.Panel(普通のパネル)
今回の実装は、基本的にはウェブサービスが返すXMLのビューアみたいな使い方をしています。使っているうちに、そういう風に使うことが効果的なのかなと思いました。
ほいでは、以下にnoticeを記します。アーカイブのダウンロードもできるようにしておきますが、免責事項として、ご利用いただいたスクリプトにて生じるいかなる損害についても責任を負いません。
<moss2007 viewer for developersについて>
moss2007 viewer for developers は、サイト・ライブラリ・フィールドの要素や属性などのビューアです。ホストに対してサイト・ライブラリ・フィールドの変更要求は投げていません。SharePointに関係する開発や管理者向けのビューアです。
moss2007のドキュメントライブラリなどにディレクトリごとアップロードしてください
ローカルの端末から使う場合は、moss.jsの71行目
httpInst.open( "POST", "/_vti_bin/SiteData.asmx", false );
の箇所に以下のようにホストヘッダを追加することで使えます。
httpInst.open( "POST", "http://hogehoge/_vti_bin/SiteData.asmx", false );
<使い方>
「▼サイトURLを選んでください」ドロップダウンより、サイトを選んでエンターキーを押下すると、サイトが保持するライブラリ一覧がタブ(LibDef:)で追加されます。また、「▼ライブラリを選んでください」ドロップダウンに一覧が設定されます。
「▼ライブラリを選んでください」ドロップダウンより、ライブラリを選んでエンターキーを押下すると、ライブラリのフィールド一覧と定期情報タブ(FldDef:)が追加されます。FldDef:タブ内の左ペインのフィールド情報をクリックすると、右ペインに詳細な情報が表示されます。ダブルクリックすると、該当のフィールドを加えて、ライブラリアイテム一覧がタブが追加されます。
String.prototype.ellipse = function(maxLength){
if(this.length > maxLength){
return this.substr(0, maxLength-3) + '...';
}
return this;
};
// ----------------------------------------------------------------------------
// tabCloseFunc.
// ----------------------------------------------------------------------------
Ext.ux.TabCloseMenu = function(){
var tabs, menu, ctxItem;
this.init = function(tp){
tabs = tp;
tabs.on('contextmenu', onContextMenu);
}
function onContextMenu(ts, item, e){
if(!menu){
menu = new Ext.menu.Menu([{
id: tabs.id + '-close',
text: 'Close Tab',
handler : function(){
tabs.remove(ctxItem);
}
},{
id: tabs.id + '-close-others',
text: 'Close Other Tabs',
handler : function(){
tabs.items.each(function(item){
if(item.closable && item != ctxItem){
tabs.remove(item);
}
});
}
}]);
}
ctxItem = item;
var items = menu.items;
items.get(tabs.id + '-close').setDisabled(!item.closable);
var disableOthers = true;
tabs.items.each(function(){
if(this != item && this.closable){
disableOthers = false;
return false;
}
});
items.get(tabs.id + '-close-others').setDisabled(disableOthers);
menu.showAt(e.getPoint());
}
};
// ----------------------------------------------------------------------------
// XMLHttpRequest Func.
// ----------------------------------------------------------------------------
function getHttpReq(){
return window.XMLHttpRequest ? new XMLHttpRequest() : ( function() {
try { return new ActiveXObject( "Msxml2.XMLHTTP" ); }
catch( e ) { return new ActiveXObject( "Microsoft.XMLHTTP" ); }
}());
}
// ----------------------------------------------------------------------------
// SiteData.asmx::GetSite Func.
// ----------------------------------------------------------------------------
function getSiteHttpInst()
{
var httpInst = getHttpReq();
var retHttpInst;
httpInst.open( "POST", "/_vti_bin/SiteData.asmx", false );
httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetSite' );
var postBody = '<?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><GetSite xmlns="http://schemas.microsoft.com/sharepoint/soap/" /></soap:Body></soap:Envelope>';
httpInst.onreadystatechange = function ()
{
if ( httpInst.readyState == 4 ){
retHttpInst = httpInst;
}
}
httpInst.send( postBody );
return retHttpInst;
}
// ----------------------------------------------------------------------------
// Parse get SingleNode list Func.
// ----------------------------------------------------------------------------
function getSingleTagList( xml, tagNm )
{
var urlList = new Array();
var urlElem = xml.getElementsByTagName( tagNm );
var listSize = urlElem.length;
for( idx = 0; idx < listSize; idx++ ){
var tempList = [ urlElem[ idx ].firstChild.nodeValue ];
urlList.push( tempList );
}
return urlList;
}
// ----------------------------------------------------------------------------
// SiteData.asmx::GetListCollection Func.
// ----------------------------------------------------------------------------
function getListCollectionHttpInst( url )
{
var httpInst = getHttpReq();
httpInst.open( "POST", url + "/_vti_bin/SiteData.asmx", false );
httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetListCollection' );
var postBody = '<?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>';
var retHttpInst;
httpInst.onreadystatechange = function ()
{
if ( httpInst.readyState == 4 ){
retHttpInst = httpInst;
}
}
httpInst.send( postBody );
return retHttpInst;
}
// ----------------------------------------------------------------------------
// Lists.asmx::GetList Func.
// ----------------------------------------------------------------------------
function getLibHttpInst( url, listNm )
{
var httpInst = getHttpReq();
var retHttpInst;
httpInst.open( "POST", url + "/_vti_bin/Lists.asmx", false );
httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetList' );
var postBody = '<?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><GetList xmlns="http://schemas.microsoft.com/sharepoint/soap/"><listName>' + listNm + '</listName></GetList></soap:Body></soap:Envelope>';
httpInst.onreadystatechange = function ()
{
if ( httpInst.readyState == 4 ){
retHttpInst = httpInst;
}
}
httpInst.send( postBody );
return retHttpInst;
}
// ----------------------------------------------------------------------------
// get Grid Func.
// ----------------------------------------------------------------------------
function getSiteDataGrid( xml )
{
var tagList = [
"InternalName",
"Title",
"BaseTemplate",
"DefaultViewUrl",
"LastModified",
"InheritedSecurity",
"AllowAnonymousAccess",
"AnonymousViewListItems",
"ReadSecurity"
];
var dataAry = new Array();
var headList = new Array();
var clmnList = new Array();
for( var idx = 0; idx < tagList.length; idx++ ){
headList.push( { name: tagList[ idx ] } );
clmnList.push( {header:tagList[ idx ],width:120,sortable:true,dataIndex:tagList[ idx ],editor:new Ext.form.TextField()} );
}
var listElem = xml.getElementsByTagName( "_sList" );
var listSize = listElem.length;
for( var idx = 0; idx < listSize; idx++ ){
var fieldDataList = new Array();
for( var sdx = 0; sdx < tagList.length; sdx++ ){
fieldDataList.push( xml.getElementsByTagName( tagList[ sdx ] )[ idx ].firstChild.nodeValue );
}
dataAry.push( fieldDataList );
}
var reader = new Ext.data.ArrayReader( {}, headList );
var clmn = new Ext.grid.ColumnModel( clmnList );
clmn.defaultSortable = true;
var grid = new Ext.grid.EditorGridPanel({
store: new Ext.data.GroupingStore({
reader: reader,
data: dataAry,
sortInfo:{ field: 'LastModified', direction: "DESC" },
groupField:'BaseTemplate'
}),
cm: clmn,
clicksToEdit:1,
stripeRows:true,
view: new Ext.grid.GroupingView({
hideGroupedColumn: true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
}),
frame:true
});
return grid;
}
// ----------------------------------------------------------------------------
// get Value List Func.
// ----------------------------------------------------------------------------
function getLibDataList( xml, atrList, parseTarget )
{
var xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
xmlDoc.async = false;
xmlDoc.loadXML( xml );
var rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetListResponse/GetListResult/' + parseTarget );
var dataAry = new Array();
for( var idx = 0; idx < rowsItem.length; idx++ ){
var fieldDataList = new Array();
for( var sdx = 0; sdx < atrList.length; sdx++ ){
fieldDataList.push( rowsItem[ idx ].getAttribute( atrList[ sdx ] ) );
}
dataAry.push( fieldDataList );
}
return dataAry;
}
// ----------------------------------------------------------------------------
// get Attribute List Func.
// ----------------------------------------------------------------------------
function getLibDataAtrList( xml, parseTarget )
{
var xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
xmlDoc.async = false;
xmlDoc.loadXML( xml );
var rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetListResponse/GetListResult/' + parseTarget );
var dataAry = new Array();
var findFlg = false;
for( var idx = 0; idx < rowsItem.length; idx++ ){
for( var sdx = 0; sdx < rowsItem[ idx ].attributes.length; sdx++ ){
for( var pushItemIdx = 0; pushItemIdx < dataAry.length; pushItemIdx++ ){
if( dataAry[ pushItemIdx ] == rowsItem[ idx ].attributes.item( sdx ).name ){
findFlg = true;
break;
}
}
if( !findFlg ){
dataAry.push( rowsItem[ idx ].attributes.item( sdx ).name );
}
findFlg = false;
}
}
return dataAry;
}
// ----------------------------------------------------------------------------
// get List Items Grid Func.
// ----------------------------------------------------------------------------
function getListItems( url, listName, staticNm, dispNm )
{
var httpInst = getHttpReq();
var dataAry = new Array();
var grid;
httpInst.open( "POST", url + "/_vti_bin/Lists.asmx", false );
httpInst.setRequestHeader( 'Content-Type','text/xml; charset=utf-8' );
httpInst.setRequestHeader( 'SOAPAction','http://schemas.microsoft.com/sharepoint/soap/GetListItems' );
var postBody = '<?xml version="1.0" encoding="utf-8"?><soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body><GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/"><listName>' + listName + '</listName><viewName></viewName><query></query><viewFields><ViewFields><FieldRef Name="ID" /><FieldRef Name="Title" /><FieldRef Name="Editor" /><FieldRef Name="Author" /><FieldRef Name="Modified" /><FieldRef Name="Created" /><FieldRef Name="' + staticNm + '" /><FieldRef Name="UniqueId"/></ViewFields></viewFields><rowLimit></rowLimit><queryOptions><QueryOptions/></queryOptions><webID></webID></GetListItems></soap12:Body></soap12:Envelope>';
httpInst.onreadystatechange = function()
{
if ( httpInst.readyState == 4 ){
xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
xmlDoc.async = false;
xmlDoc.loadXML( httpInst.responseText );
rowsItem = xmlDoc.selectNodes( '/soap:Envelope/soap:Body/GetListItemsResponse/GetListItemsResult/listitems/rs:data/z:row' );
for( idx = 0; idx < rowsItem.length; idx++ ){
var fieldDataList = new Array();
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_ID" ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_Title" ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_" + staticNm ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_Editor" ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_Author" ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_Modified" ) );
fieldDataList.push( rowsItem[ idx ].getAttribute( "ows_Created" ) );
dataAry.push( fieldDataList );
}
var reader = new Ext.data.ArrayReader( {}, [
{ name: 'ID' },
{ name: 'Title' },
{ name: staticNm },
{ name: 'Editor' },
{ name: 'Author' },
{ name: 'Modified' },
{ name: 'Created' }
]);
var clmn = new Ext.grid.ColumnModel( [
{ header: 'ID', width: 120, sortable: true, dataIndex: 'ID',editor:new Ext.form.TextField() },
{ header: 'タイトル', width: 120, sortable: true, dataIndex: 'Title',editor:new Ext.form.TextField() },
{ header: dispNm, width: 120, sortable: true, dataIndex: staticNm,editor:new Ext.form.TextField() },
{ header: '更新者', width: 120, sortable: true, dataIndex: 'Editor',editor:new Ext.form.TextField() },
{ header: '作成者', width: 120, sortable: true, dataIndex: 'Author',editor:new Ext.form.TextField() },
{ header: '更新日時', width: 120, sortable: true, dataIndex: 'Modified',editor:new Ext.form.TextField() },
{ header: '作成日時', width: 120, sortable: true, dataIndex: 'Created',editor:new Ext.form.TextField() }
] );
grid = new Ext.grid.EditorGridPanel({
store: new Ext.data.GroupingStore({
reader: reader,
data: dataAry,
sortInfo:{ field: 'Modified', direction: "DESC" },
groupField:'Editor'
}),
cm: clmn,
clicksToEdit:1,
stripeRows:true,
view: new Ext.grid.GroupingView({
hideGroupedColumn: true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
}),
frame:true
});
}
}
httpInst.send( postBody );
return grid;
}
Ext.onReady( function(){
var isOpen = false;
var tb = new Ext.Toolbar();
var index = 0;
var panel = new Ext.TabPanel({
renderTo:'container',
resizeTabs:true,
minTabWidth: 235,
tabWidth:235,
enableTabScroll:true,
width:720,
height:480,
tbar: tb,
bodyStyle:'padding:12px;',
defaults: {autoScroll:true},
plugins: new Ext.ux.TabCloseMenu()
});
var siteLists = getSingleTagList( getSiteHttpInst().responseXML, 'Url' );
var store = new Ext.data.SimpleStore({
fields: [ 'siteurl' ],
data : siteLists
});
var libCombo = new Ext.form.ComboBox({
store: new Ext.data.SimpleStore( { fields: [ 'libnm' ] } ),
displayField: 'libnm',
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText: '▼ライブラリを選んでください',
selectOnFocus:true,
listeners: {
'specialkey': function( textField, evt ){
if( evt.getKey() != Ext.EventObject.ENTER || combo.getValue() == '' || libCombo.getValue() == '' ) return;
if( panel.getComponent( 'img-chooser-dlg' ) != null ){
panel.remove( panel.getComponent( 'img-chooser-dlg' ) );
}
var curHttpInst = getLibHttpInst( combo.getValue(), libCombo.getValue() );
var atrList = getLibDataAtrList( curHttpInst.responseText, 'List/Fields/Field' );
var libDataList = getLibDataList( curHttpInst.responseText, atrList, 'List/Fields/Field' );
var lookup = {};
var dataViewStore = new Ext.data.SimpleStore({
data: libDataList,
fields: atrList
});
var thumbTemplate = new Ext.XTemplate(
'<tpl for=".">',
'<div class="thumb-wrap" id="{StaticName}">',
'<div class="thumb"><input type="text" size="8" value="{DisplayName}"/></div>',
'<span class="x-editable">{shortName}</span></div>',
'</tpl>',
'<div class="x-clear"></div>'
);
var templateSet = '';
for( var atrIdx = 0; atrIdx < atrList.length; atrIdx++ ){
templateSet = templateSet + '<b>' + atrList[ atrIdx ] + ':</b>' + '<span>{' + atrList[ atrIdx ] + '}</span>';
}
var detailsTemplate = new Ext.XTemplate(
'<div class="details">',
'<tpl for=".">',
'<img src="js/img/detail.gif"><div class="details-info">',
templateSet,
'</tpl>',
'</div>'
);
var formatData = function( data ){
data.shortName = data.Type.ellipse( 15 );
lookup[ data.StaticName ] = data;
return data;
};
var view = new Ext.DataView({
tpl: thumbTemplate,
singleSelect: true,
overClass:'x-view-over',
itemSelector: 'div.thumb-wrap',
store: dataViewStore,
listeners: {
'selectionchange': {fn:function(){
var selNode = view.getSelectedNodes();
var detailEl = Ext.getCmp('img-detail-panel').body;
if(selNode && selNode.length > 0){
selNode = selNode[0];
var data = lookup[ selNode.id ];
detailEl.hide();
detailsTemplate.overwrite(detailEl, data);
detailEl.slideIn('l', {stopFx:true,duration:.2});
}else{
detailEl.update('');
}
}},
'beforeselect' : {fn:function(view){
return view.store.getRange().length > 0;
}},
'dblclick' : {fn:function(){
var selNode = view.getSelectedNodes();
var detailEl = Ext.getCmp('img-detail-panel').body;
if(selNode && selNode.length > 0){
selNode = selNode[0];
var data = lookup[ selNode.id ];
var statNm = data.StaticName;
var dispNm = data.DisplayName;
var listGrid = getListItems( combo.getValue(), libCombo.getValue(), statNm, dispNm );
listGrid.closable = true;
listGrid.setTitle( libCombo.getValue() );
panel.add( listGrid ).show();
}
}}
},
prepareData: formatData.createDelegate( view )
});
var dataView = new Ext.Panel({
title:'FldDef: [ ' + libCombo.getValue() + ' ]',
id: 'img-chooser-dlg',
layout: 'border',
frame:true,
items:[{
id: 'img-chooser-view',
region: 'center',
autoScroll: true,
items: view,
tbar:[{
text: 'Filter:'
},{
xtype: 'textfield',
id: 'filter',
selectOnFocus: true,
width: 100,
listeners: {
'render': {fn:function(){
Ext.getCmp('filter').getEl().on('keyup', function(){
var filter = Ext.getCmp('filter');
view.store.filter('DisplayName', filter.getValue());
});
}}
}
}, ' ', '-', {
text: 'Sort By:'
}, {
id: 'sortSelect',
xtype: 'combo',
typeAhead: true,
triggerAction: 'all',
width: 100,
editable: false,
mode: 'local',
displayField: 'desc',
valueField: 'DisplayName',
lazyInit: false,
value: 'DisplayName',
store: new Ext.data.SimpleStore({
fields: ['DisplayName', 'desc'],
data : [['DisplayName', '表示名'],['Type', 'フィールド型'],['StaticName', 'StaticName']]
}),
listeners: {
'select': {fn:function(){
var v = Ext.getCmp('sortSelect').getValue();
view.store.sort(v, v == 'DisplayName' ? 'asc' : 'desc');
}}
}
}, ' ', '-', {
text: 'ライブラリ定義参照',
handler: onLibDefineBtnClick
}]
},{
id: 'img-detail-panel',
region: 'east',
autoScroll: true,
split: true,
width: 240,
minWidth: 240,
maxWidth: 300
}]
});
dataView.closable = true;
panel.add( dataView ).show();
var libDefWindow;
function onLibDefineBtnClick( btn ){
var libDefAtrList = getLibDataAtrList( curHttpInst.responseText, 'List' );
var libDefList = getLibDataList( curHttpInst.responseText, libDefAtrList, 'List' );
var libDefData = new Array();
for( var idx = 0; idx < libDefAtrList.length; idx++ ){
var fieldDataList = new Array();
fieldDataList.push( libDefAtrList[ idx ] );
fieldDataList.push( libDefList[ 0 ][ idx ] );
libDefData.push( fieldDataList );
}
var reader = new Ext.data.ArrayReader( {}, [
{ name: 'Attribute' },
{ name: 'Value' }
]);
var clmn = new Ext.grid.ColumnModel( [
{ header: 'Attribute', width: 200, sortable: true, dataIndex: 'Attribute',editor:new Ext.form.TextField() },
{ header: 'Value', width: 200, sortable: true, dataIndex: 'Value',editor:new Ext.form.TextField() }
] );
var grid = new Ext.grid.EditorGridPanel({
store: new Ext.data.GroupingStore({
reader: reader,
data: libDefData
}),
cm: clmn,
clicksToEdit:1,
stripeRows:true,
frame:true
});
if( !libDefWindow ){
libDefWindow = new Ext.Window({
title:'[ ' + libCombo.getValue() + ' ] ライブラリの定義',
layout:'fit',
width:400,
height:300,
closeAction:'hide',
plain: true,
items:grid,
buttons: [{
text: 'Close',
handler: function(){
libDefWindow.hide();
}
}]
});
}
libDefWindow.show();
}
}
},
width:300
});
var combo = new Ext.form.ComboBox({
store: store,
displayField: 'siteurl',
typeAhead: true,
mode: 'local',
triggerAction: 'all',
emptyText: '▼サイトURLを選んでください',
selectOnFocus:true,
listeners: {
'specialkey': function( textField, evt ){
if( evt.getKey() != Ext.EventObject.ENTER || combo.getValue() == '') return;
var curHttpInst = getListCollectionHttpInst( combo.getValue() );
libCombo.store.loadData( getSingleTagList( curHttpInst.responseXML, 'Title' ), false );
var siteDataGrid = getSiteDataGrid( curHttpInst.responseXML );
siteDataGrid.setTitle( 'LibDef: [ ' + combo.getValue() +' ]' );
siteDataGrid.closable = true;
siteDataGrid.frame = true;
panel.add( siteDataGrid ).show();
}
},
width:300
});
panel.getTopToolbar().add( combo );
panel.getTopToolbar().add( "-", libCombo );
panel.add({
title: 'how to use',
iconCls: 'tabs',
html:document.getElementById( "description" ).innerHTML
}).show();
document.getElementById( "description" ).style.display = "none";
});



