‘マッシュアップ!’ カテゴリーのアーカイブ

SharePointウェブサービスとExtJS連携でmoss2007 viewer for developers

SharePointウェブサービスとExtJS連携でmoss2007 viewer for developersをはてなブックマークに追加 SharePointウェブサービスとExtJS連携でmoss2007 viewer for developersをdel.icio.usに追加 Yahoo!ブックマークに登録 SharePointウェブサービスとExtJS連携でmoss2007 viewer for developersをGoogle Bookmarksに追加 SharePointウェブサービスとExtJS連携でmoss2007 viewer for developersをtwitterにポスト
2008年4月10日 木曜日
moss2007viewer.PNG
SharePointのビューアを作ってみました。
ExtJSの使い方を勉強しながらだったのでソースは汚いです。
使ったウィジェットは

  • Ext.grid.EditorGridPanel(エクセルみたいなパネル)
  • Ext.TabPanel(タブパネル)
  • Ext.form.ComboBox(ドロップダウンリスト)
  • Ext.DataView(データビュー。アイテムのソートやフィルタなんかができる)
  • Ext.Window(ウィンドウがポップする)
  • Ext.Panel(普通のパネル)

などです。これだけ使ったのでなんとなくExtJSをどうやって使うのか理解できてきましたが、基本的にはサンプルソースを見ながらいろいろといじくってできたものです。あまり参考にならないかもしれませんし、正しい実装ではないかもしれません。
今回の実装は、基本的にはウェブサービスが返す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";
});

ニコウゴコメントフォームを簡単設置!ブログパーツにしてみたよ

ニコウゴコメントフォームを簡単設置!ブログパーツにしてみたよをはてなブックマークに追加 ニコウゴコメントフォームを簡単設置!ブログパーツにしてみたよをdel.icio.usに追加 Yahoo!ブックマークに登録 ニコウゴコメントフォームを簡単設置!ブログパーツにしてみたよをGoogle Bookmarksに追加 ニコウゴコメントフォームを簡単設置!ブログパーツにしてみたよをtwitterにポスト
2007年10月29日 月曜日

ニコウゴコメントフォームを簡単に設置できるようにしたよ!
もちろんニコニコ風なただ流れるコメントにもできます。いろいろカスタマイズしたい場合は、コッチを参照して、スクリプトをカスタマイズしてください。

<script src="http://labs.mojalog.com/mojascript/nicougo/nicougo.js" type=text/javascript></script>
<input type="text" id="nicougosendmsg">
<input type="button" onclick='initJsr();' value="ニコウゴする!" id="nicougobtn">
<!-- ユーザセッティングタグがない場合はデフォルトの値(以下のとおり)になります。環境に合わせてご利用ください //-->
<!-- ポップするウィンドウの幅指定 //-->
<input type="hidden" id="nicougowidth" value="360">
<!-- ポップするウィンドウの高さ指定 //-->
<input type="hidden" id="nicougoheight" value="240">
<!-- ポップするウィンドウの色指定 //-->
<input type="hidden" id="nicougobgcolor" value="#FFFFFF">
<!-- ポップするウィンドウの縦位置指定 //-->
<input type="hidden" id="nicougovpos" value="240">
<!-- ポップするウィンドウの横位置指定 //-->
<input type="hidden" id="nicougohpos" value="120">
<!-- メッセージのフォントサイズ指定 //-->
<input type="hidden" id="nicougofontsize" value="14">
<!-- ポップするウィンドウの透明度指定 //-->
<input type="hidden" id="nicougoopc" value="80">
<!-- コメントの流れるスピード指定 //-->
<input type="hidden" id="nicougospd" value="8">
<!-- コメントの揺れ幅指定 //-->
<input type="hidden" id="nicougoshake" value="8">
<!-- コメントの表示間隔指定 //-->
<input type="hidden" id="nicougoemgspan" value="80">
<!-- コメントの揺れ表示指定 0 無効 / 1 有効 //-->
<input type="hidden" id="isugougo" value="0">
<!--以下のdivタグはbodyタグを閉じる直前あたりに入れてください //-->
<div id="nicougowrap"></div>

ニコウゴコメントフォームをあなたのブログやサイトに設置する方法

ニコウゴコメントフォームをあなたのブログやサイトに設置する方法をはてなブックマークに追加 ニコウゴコメントフォームをあなたのブログやサイトに設置する方法をdel.icio.usに追加 Yahoo!ブックマークに登録 ニコウゴコメントフォームをあなたのブログやサイトに設置する方法をGoogle Bookmarksに追加 ニコウゴコメントフォームをあなたのブログやサイトに設置する方法をtwitterにポスト
2007年10月27日 土曜日
nicougo.PNG

mojaラボ ニコウゴコメントフォームをJSONPでクロスドメイン対応にしました!
トップページにフォームがおいてあります

GET URLの構築

送信するURLはコチラです。
http://labs.mojalog.com/mojascript/nicougo/nicougo.php

リクエストURL例

http://labs.mojalog.com/mojascript/nicougo/nicougo.php?url=http%3a%2f%2fmojalog%2ecom%2f&msg=&fmt=nicougoload

リクエストパラメータ例

url=http%3a%2f%2fmojalog%2ecom%2f【URL】(document.URLをencodeURIしたもの)
msg=【投稿メッセージ】(空だと投稿は行いません)
fmt=nicougoload【nicougoloadというメソッド名で実装する】

パラメータ 説明
url string(URLエンコード) 利用者のURLです。URL(http/https)形式かどうかをサーバ側で判定しています。
msg string(URLエンコード) 送信するメッセージです。空だと投稿はされません。
fmt string(コールバックメソッド名) 実装するスクリプトのコールバック関数名を与えます

レスポンスフィールド例

nicougoload ([{"datetime" : "2007/10/27 22:50:25", "item" : "キタ――――(゚∀゚)――――"},{"datetime" : "2007/10/27 22:00:53", "item" : "32文字以上ですとサーバ側で切り落とします。"},{"datetime" : "2007/10/27 22:00:25", "item" : "投稿できる文字数は32文字になっています。32文字以上ですとサー…"},{"datetime" : "2007/10/27 21:58:31", "item" : "こんにちは"},{"datetime" : "2007/10/27 13:16:06", "item" : "firefoxだと妙に重い"},{"datetime" : "2007/10/27 13:06:12", "item" : "ニコウゴニコウゴ"},{"datetime" : "2007/10/27 13:04:30", "item" : "ニッコウゴにしてやんよ"},{"datetime" : "2007/10/27 13:04:10", "item" : "(゚∀゚)にこうご"},{"datetime" : "2007/10/27 13:03:35", "item" : "firefoxでも一応動くように…"},{"datetime" : "", "item" : "END"}]);

パラメータのfmtを省略した場合RESTで結果を返却します。

<?xml version="1.0" encoding="UTF-8" ?>
<elems>
<elem datetime="2007/10/27 22:50:25">キタ――――(゚∀゚)――――</elem>
<elem datetime="2007/10/27 22:00:53">32文字以上ですとサーバ側で切り落とします。</elem>
<elem datetime="2007/10/27 22:00:25">投稿できる文字数は32文字になっています。32文字以上ですとサー…</elem>
<elem datetime="2007/10/27 21:58:31">こんにちは</elem>
<elem datetime="2007/10/27 13:16:06">firefoxだと妙に重い</elem>
<elem datetime="2007/10/27 13:06:12">ニコウゴニコウゴ</elem>
<elem datetime="2007/10/27 13:04:30">ニッコウゴにしてやんよ</elem>
<elem datetime="2007/10/27 13:04:10">(゚∀゚)にこうご</elem>
<elem datetime="2007/10/27 13:03:35">firefoxでも一応動くように…</elem>
</elems>

注意点

  • mojaラボ ニコウゴウェブサービスは、パラメータのurlが正しく解決できれば、サーバ側で持っているメッセージをすべて閲覧することが可能です。ある掲示板に、URL名でスレッドがたっているだけというイメージでご利用ください。
  • つまり、ニコウゴフォームを設置したサイトからでなくとも投稿や閲覧が可能です。何らかのパスワードや機密情報、個人情報などの投稿はお控えください。
  • ブログやサイトに設置する方は、エンドユーザに上記内容をお知らせすることをオススメします
  • 投稿されたメッセージはURL毎に30件保管します。それ以上のメッセージが送られると古いものから削除されます。(サーバの負荷などを見て変更されることがあります)
  • 投稿されたすべてのメッセージは、ご利用される方に通知連絡なしで削除されることがあります。
  • mojalog管理人は、ユーザが本サービスを利用して、損害や不利益を被った場合でも、一切の責任を負わず、一切の損害賠償の義務を負わないものとします

HTMLサンプル

サンプルhtmlはエントリ下部に記します。このhtmlサンプルは3つのjavascriptライブラリを利用しています。
1.JSONscriptRequestというライブラリを使用しています。
JSON and the Dynamic Script Tag: Easy, XML-less Web Services for JavaScript
こちらからダウンロードしてきてください。「1.My JSONscriptRequest class」ってとこにアンカされてます。

2.firefoxブラウザを判定するためのスクリプト
as flash as flexさん■[AJAX/JavaScript] UserAgentからブラウザを判定するオールマイティなJavaScript(browsercheck.js)を利用させてもらっています。

3.ニコニコでウゴウゴな表示をするためのスクリプト
nicougo.zip
dynamicdriveにあったドラッグ&ドロップスクリプトを利用しています。
via : dynamicdrive
nicougo.jsの中身は表示方法などを記述したスクリプトです。ご自由にいじってくださっても構いません。といいますか、いい感じな見せ方ができたら教えて欲しいです。ワタシscriptいじるの下手なんで。

htmlに必要なのは以下のコードです。タグのidがご自身のページで競合した場合は、スクリプトのほうも合わせて変更してください。
最後のdivタグ(id=nicougowrap)はbodyタグを閉じる直前あたりに書いたほうがいいかもしれません。

<input type="text" id="nicougosendmsg">
<input type="button" onclick='initJsr();' value="ニコウゴする!" id="nicougobtn">
<div id="nicougowrap"></div>

nicougo.jsはご自由にいじってください。一応 user setting に適当なコンフィグを用意しておきました。

// user setting.
var NICOUGOWIDTH    = 360;       // display width.
var NICOUGOHEIGHT   = 240;       // display height.
var NICOUGOBGCOLOR  = "#FFFFFF"; // display color.
var NICOUGOVPOS     = "240px";   // display vertical position.
var NICOUGOHPOS     = "120px";   // display horizonal position.
var NICOUGOFONTSIZE = 14;        // font size.
var NICOUGOOPC      = 80;        // opacity.
var NICOUGOSPD      = 16;        // speed.
var NICOUGOSHAKE    = 8;         // ugougo shakes.
var NICOUGOEMGSPAN  = 80;        // emerge span.
// user setting.
var itemList;
var topBlurList;
var leftBlurList;
var jsrInst;
var dataSize     = 0;
var nowRendering = false;
var Drag = {
obj : null,
init : function( o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper )
{
o.onmousedown = Drag.start;
o.onmouseover = Drag.over;
o.onmouseout  = Drag.out;
o.hmode       = bSwapHorzRef ? false : true ;
o.vmode       = bSwapVertRef ? false : true ;
o.root = oRoot && oRoot != null ? oRoot : o ;
if ( o.hmode  && isNaN( parseInt( o.root.style.left   ) ) ) o.root.style.left   = "0px";
if ( o.vmode  && isNaN( parseInt( o.root.style.top    ) ) ) o.root.style.top    = "0px";
if ( !o.hmode && isNaN( parseInt( o.root.style.right  ) ) ) o.root.style.right  = "0px";
if ( !o.vmode && isNaN( parseInt( o.root.style.bottom ) ) ) o.root.style.bottom = "0px";
o.minX    = typeof minX != 'undefined' ? minX : null;
o.minY    = typeof minY != 'undefined' ? minY : null;
o.maxX    = typeof maxX != 'undefined' ? maxX : null;
o.maxY    = typeof maxY != 'undefined' ? maxY : null;
o.xMapper = fXMapper ? fXMapper : null;
o.yMapper = fYMapper ? fYMapper : null;
o.root.onDragStart = new Function();
o.root.onDragEnd   = new Function();
o.root.onDrag      = new Function();
},
start : function( e )
{
var o = Drag.obj = this;
e = Drag.fixE( e );
var y = parseInt( o.vmode ? o.root.style.top  : o.root.style.bottom );
var x = parseInt( o.hmode ? o.root.style.left : o.root.style.right  );
o.root.onDragStart( x, y );
o.lastMouseX = e.clientX;
o.lastMouseY = e.clientY;
if ( o.hmode ) {
if ( o.minX != null ) o.minMouseX = e.clientX - x + o.minX;
if ( o.maxX != null ) o.maxMouseX = o.minMouseX + o.maxX - o.minX;
}
else {
if ( o.minX != null ) o.maxMouseX = -o.minX + e.clientX + x;
if ( o.maxX != null ) o.minMouseX = -o.maxX + e.clientX + x;
}
if ( o.vmode ) {
if ( o.minY != null ) o.minMouseY = e.clientY - y + o.minY;
if ( o.maxY != null ) o.maxMouseY = o.minMouseY + o.maxY - o.minY;
}
else {
if ( o.minY != null ) o.maxMouseY = -o.minY + e.clientY + y;
if ( o.maxY != null ) o.minMouseY = -o.maxY + e.clientY + y;
}
document.onmousemove = Drag.drag;
document.onmouseup   = Drag.end;
return false;
},
drag : function( e )
{
e = Drag.fixE( e );
var o = Drag.obj;
var ey = e.clientY;
var ex = e.clientX;
var y = parseInt( o.vmode ? o.root.style.top  : o.root.style.bottom );
var x = parseInt( o.hmode ? o.root.style.left : o.root.style.right  );
var nx, ny;
if ( o.minX != null ) ex = o.hmode ? Math.max( ex, o.minMouseX ) : Math.min( ex, o.maxMouseX );
if ( o.maxX != null ) ex = o.hmode ? Math.min( ex, o.maxMouseX ) : Math.max( ex, o.minMouseX );
if ( o.minY != null ) ey = o.vmode ? Math.max( ey, o.minMouseY ) : Math.min( ey, o.maxMouseY );
if ( o.maxY != null ) ey = o.vmode ? Math.min( ey, o.maxMouseY ) : Math.max( ey, o.minMouseY );
nx = x + ( ( ex - o.lastMouseX ) * ( o.hmode ? 1 : -1 ) );
ny = y + ( ( ey - o.lastMouseY ) * ( o.vmode ? 1 : -1 ) );
if ( o.xMapper )      nx = o.xMapper( y )
else if ( o.yMapper ) ny = o.yMapper( x )
Drag.obj.root.style[ o.hmode ? "left" : "right" ] = nx + "px";
Drag.obj.root.style[ o.vmode ? "top" : "bottom" ] = ny + "px";
Drag.obj.lastMouseX = ex;
Drag.obj.lastMouseY = ey;
Drag.obj.root.onDrag( nx, ny );
return false;
},
end : function()
{
document.onmousemove = null;
document.onmouseup   = null;
Drag.obj.root.onDragEnd( parseInt( Drag.obj.root.style[ Drag.obj.hmode ? "left" : "right" ] ),
parseInt( Drag.obj.root.style[ Drag.obj.vmode ? "top" : "bottom" ] ) );
Drag.obj = null;
},
over : function( e )
{
nowRendering = true;
return false;
},
out : function( e )
{
nowRendering = false;
rendering();
return false;
},
fixE : function( e )
{
if ( typeof e        == 'undefined' ) e = window.event;
if ( typeof e.layerX == 'undefined' ) e.layerX = e.offsetX;
if ( typeof e.layerY == 'undefined' ) e.layerY = e.offsetY;
return e;
}
};
// setup json script request.
function initJsr()
{
// ローカルでテストする場合は encodeURI( document.URL ) を'http%3a%2f%2fexample%2ecom%2f'など実URLに変更する必要があります
jsrInst = new JSONscriptRequest( 'http://labs.mojalog.com/mojascript/nicougo/nicougo.php?url='
+ encodeURI( document.URL ) + '&msg='
+ encodeURI( document.getElementById( "nicougosendmsg" ).value )
+ '&fmt=nicougoload' );
jsrInst.buildScriptTag();
jsrInst.addScriptTag();
}
function nicougoload( param ){
var nicougoItem = "";
dataSize = param.length;
for( idx = 0; idx < dataSize; idx++ ){
nicougoItem = nicougoItem + '<div id="nicougomsg' + idx
+ '" style="position:absolute; top:0px; left:' + NICOUGOWIDTH
+ 'px; font-size:' + NICOUGOFONTSIZE
+ 'px;"><Nobr><ruby><rb>' + param[ idx ].item
+ '</rb><rp>(</rp><rt>' + param[ idx ].datetime
+ '</rt><rp>)</rp></ruby></Nobr></div>';
}
isRender = true;
var browserInf = new BrowserInfo();
var inf = 'filter:Alpha( opacity=' + NICOUGOOPC + ' );';
if( browserInf.firefox ){
inf = '-moz-opacity:' + NICOUGOOPC / 100 + ';';
}
else if( browserInf.opera ){
inf = 'opacity:' + NICOUGOOPC / 100 + ';';
}
document.getElementById( "nicougowrap" ).innerHTML = '<div id="nicougo" style="position:absolute; top:' + NICOUGOVPOS
+ '; left:' + NICOUGOHPOS
+ '; width:' + NICOUGOWIDTH
+ 'px; height:' + NICOUGOHEIGHT
+ 'px; padding: 5px; cursor:move; background-color:#ffffff;'
+ inf
+ '"><span style="cursor:pointer;" onclick="unload()">'
+ '<img alt="閉じる" src="close.PNG" /></span>'
+ nicougoItem + '</div>';
jsrInst.removeScriptTag();
Drag.init( document.getElementById( "nicougo" ) );
setupItem();
rendering();
}
function setupItem()
{
itemList     = new Array();
topBlurList  = new Array();
leftBlurList = new Array();
for( idx = 0; idx < dataSize; idx++ ){
itemList.push( document.getElementById( "nicougomsg" + idx ) );
itemList[ idx ].style.top = 20 + ( Math.random() * ( NICOUGOHEIGHT - 60 ) );
topBlurList.push( parseInt( itemList[ idx ].style.top ) );
leftBlurList.push( parseInt( itemList[ idx ].style.left ) + ( idx * NICOUGOEMGSPAN ) );
}
nowRendering = false;
}
function rendering(){
document.getElementById( "nicougobtn" ).disabled = true;
if( nowRendering ) return false;
for( idx = 0; idx < dataSize; idx++ ){
itemList[ idx ].style.position = 'absolute';
leftBlurList[ idx ] = leftBlurList[ idx ] - NICOUGOSPD;
if( leftBlurList[ idx ] <= NICOUGOWIDTH ){
itemList[ idx ].style.display = "";
itemList[ idx ].style.left = parseInt( itemList[ idx ].style.left ) - NICOUGOSPD + "px";
}
else {
itemList[ idx ].style.display = "none";
}
var browserInf = new BrowserInfo();
var vanishPoint = 0;
if( browserInf.firefox ){
vanishPoint = 0;
}
else {
vanishPoint = itemList[ idx ].innerText.length * parseInt( itemList[ idx ].style.fontSize );
}
if( leftBlurList[ idx ] + ( vanishPoint ) <= 0 ){
itemList[ idx ].innerHTML = "";
}
itemList[ idx ].style.top = topBlurList[ idx ] + ( Math.random() * NICOUGOSHAKE ) + "px";
}
if( itemList[ dataSize -1 ].innerHTML == "" ){
unload();
}
else {
setTimeout( 'rendering()', 100 );
}
}
function unload(){
nowRendering = false;
document.getElementById( "nicougobtn" ).disabled = false;
document.getElementById( "nicougowrap" ).innerHTML = "";
}