PAL Portal (J2 デスクトップの調査)

続き・・・

jetspeed.page.retrievePsml();を見てみよう。まず、pageContentListenerにnew jetspeed.om.PageContentListenerCreateWidget()を与える(と思われる、null だから)。PageContentListenerCreateWidget()は、

// ... jetspeed.om.PageContentListenerCreateWidget
jetspeed.om.PageContentListenerCreateWidget = function()
{
};
jetspeed.om.PageContentListenerCreateWidget.prototype =
{
notifySuccess: function( /* XMLDocument */ data, /* String */ requestUrl, /* Page */ page )
{
page.getPortletsFromPSML( data );
jetspeed.loadPortletWindows();
},
notifyFailure: function( /* String */ type, /* String */ error, /* String */ requestUrl, /* Page */ page )
{
dojo.raise( "PageContentListenerCreateWidget notifyFailure url=" + requestUrl + " type=" + type + " error=" + error ) ;
}
};

と言う感じで、コンストラクタ?では何もしない。メソッドとして、notifySuccessとnotifyFailureを持っている。この段階では、これらのメソッドは関係ないと思うけど。

っで、次にretrievePsml()でpsmlUrlとmimeTypeを取得する。psmlUrlのgetPsmlUrl()は以下のような感じ。

getPsmlUrl: function()
{
if ( this.psmlPath == null )
this.setPsmlPathFromDocumentUrl() ;
return jetspeed.url.basePortalUrl() + this.psmlPath ;
},

この段階では、psmlPathはnullだろうから、

setPsmlPathFromDocumentUrl: function()
{
var psmlPath = jetspeed.url.path.AJAX_API ;
var docPath = document.location.pathname ;
var contextAndServletPath = jetspeed.url.path.DESKTOP ;
var contextAndServletPathPos = docPath.indexOf( contextAndServletPath ) ;
if ( contextAndServletPathPos != -1 && docPath.length > ( contextAndServletPathPos + contextAndServletPath.length ) )
{
psmlPath = psmlPath + docPath.substring( contextAndServletPathPos + contextAndServletPath.length ) ;
}
this.psmlPath = psmlPath ;
},

psmlPathはAJAX用のパス名をセットしている(たとえば、/palportal/ajaxかな)。docPathは現在のURLのパス名でそれに対して、jetspeed.url.path.DESKTOPは/palportal/desktopのようなものだから、それのindexOfを取ろうとしている。docPathが長ければ、psmlPathにそれをくっつけて、最終的なpsmlPathにしているみたいだな。

getPsmlUrlに戻って、jetspeed.url.basePortalUrl()をくっつけて、return して、psmlUrlの完成 🙂 ちなみにbasePortalUrl()は

jetspeed.url.basePortalUrl = function()
{
if ( ! jetspeed.url.path.initialized )
jetspeed.url.pathInitialize();
return jetspeed.url.path.SERVER;    // return document.location.protocol + "//" + document.location.host ;
};

と言う感じで、既にjetspeed.url.path.initializedはtrueだから、単純にjetspeed.url.path.SERVERを返してくる。この値は、http://localhost:8080/palportalみたいな感じかな。

そんで、jetspeed.url.retrieveContentへGo!

jetspeed.url.retrieveContent = function( requestUrl, contentListener, formObject, mimeType, domainModelObject, debugContentDumpIds )
{
if ( ! requestUrl )
{
dojo.raise( "retrieveContent null requestUrl is illegal" );
return;
}
if ( ! mimeType )
mimeType = "text/html";
dojo.io.bind({
url: requestUrl,
formNode: formObject,
mimetype: mimeType,
load: function( type, data, evt )
{
//dojo.debug( "loaded content for url: " + this.url );
//dojo.debug( "r e t r i e v e C o n t e n t . l o a d" ) ;
//dojo.debug( "  type:" );
//dojo.debugShallow( type ) ;
//dojo.debug( "  evt:" );
//dojo.debugShallow( evt ) ;
if ( debugContentDumpIds )
{
var dmId = ( ( domainModelObject && dojo.lang.isFunction( domainModelObject.getId ) ) ? domainModelObject.getId() : "" );
for ( var debugContentIndex = 0 ; debugContentIndex < debugContentDumpIds.length; debugContentIndex++ )
{
if ( dmId.match( new RegExp( debugContentDumpIds[ debugContentIndex ] ) ) )
{
if ( dojo.lang.isString( data ) )
dojo.debug( "retrieveContent [" + ( dmId ? dmId : requestUrl ) + "] content: " + data );
else
{
var textContent = dojo.dom.innerXML( data );
if ( ! textContent )
textContent = ( data != null ? "!= null (IE no XMLSerializer)" : "null" );
dojo.debug( "retrieveContent [" + ( dmId ? dmId : requestUrl ) + "] xml-content: " + textContent );
}
}
}
}
if ( contentListener && dojo.lang.isFunction( contentListener.notifySuccess ) )
{
contentListener.notifySuccess( data, requestUrl, domainModelObject ) ;
}
else
{
dojo.debug( "retrieveContent [" + ( dmId ? dmId : requestUrl ) + "] no valid contentListener" );
}
},
error: function( type, error )
{
//dojo.debug( "r e t r i e v e C o n t e n t . e r r o r" ) ;
//dojo.debug( "  type:" );
//dojo.debugShallow( type ) ;
//dojo.debug( "  error:" );
//dojo.debugShallow( error ) ;
if ( contentListener && dojo.lang.isFunction( contentListener.notifyFailure ) )
{
contentListener.notifyFailure( type, error, requestUrl, domainModelObject );
}
}
});
};

これは、ちょっと長いな・・・。でも、見てみると、requestUrlとmimeTypeをチェックして、dojo.io.bindの呼び出しか。dojo.io.bind内のdebugContentDumpIdsのブロックはデバッグコードっぽいから、まぁ、ここでは読み飛ばすとして、アクセスに成功すると、contentListener.notifySuccessになるのか。これは、前述したnotifySuccessだね。引数は、アクセスして帰ってきたデータ、アクセスしたURL(PSML の URL)、domainModelObjectはjetspeed.url.retrieveContentを呼び出したjetspeed.om.Pageのインスタンスだね。というわけで、

notifySuccess: function( /* XMLDocument */ data, /* String */ requestUrl, /* Page */ page )
{
page.getPortletsFromPSML( data );
jetspeed.loadPortletWindows();
},

に戻る(今回はアクセス失敗時の動作は追わないでおこ)。dojo.io.bindについては http://manual.dojotoolkit.org/io.html を参照。

では、まず、getPortletsFromPSMLを見てみましょ。

getPortletsFromPSML: function( psml )
{
var pageElements = psml.getElementsByTagName( "page" );
if ( ! pageElements || pageElements.length > 1 )
dojo.raise( "unexpected zero or multiple <page> elements in psml" );
var pageElement = pageElements[0];
var children = pageElement.childNodes;
var simpleValueLNames = new RegExp( "(name|path|title|short-title)" );
for ( var i = 0 ; i < children.length ; i++ )
{
var child = children[i];
if ( child.nodeType != dojo.dom.ELEMENT_NODE )
continue;
var childLName = child.nodeName;
if ( childLName == "defaults" )
{
this.layoutDecorator = child.getAttribute( "layout-decorator" );
this.portletDecorator = child.getAttribute( "portlet-decorator" );
}
else if ( childLName && childLName.match( simpleValueLNames  ) )
{
this[ jetspeed.purifyIdentifier( childLName, "", "lo" ) ] = ( ( child && child.firstChild ) ? child.firstChild.nodeValue : null );
}
}
var lis = pageElement.getElementsByTagName( "fragment" );
for( var x=0; x < lis.length; x++ )
{
var fragType = lis[x].getAttribute( "type" );
if ( fragType == "portlet" )
{
var portletName = lis[x].getAttribute( "name" );
var portletEntityId = lis[x].getAttribute( "id" );
var portlet = new jetspeed.om.Portlet( portletName, portletEntityId ) ;
var props = lis[x].getElementsByTagName( "property" );
for( var propsIdx=0; propsIdx < props.length; propsIdx++ )
{
var propName = props[propsIdx].getAttribute( "name" ) ;
var propValue = props[propsIdx].getAttribute( "value" ) ;
portlet.putProperty( propName, propValue ) ;
}
portlet.initialize();
this.putPortlet( portlet ) ;
}
}
},

dojo.io.bindで取った、data は、XMLDocumentになるのね。帰ってくるPSMLデータについては、 http://jetspeed-japan.sourceforge.jp/jetspeed-2-trans/ja/guides/guide-ajax-api.html を参照。

getPortletsFromPSMLを見て、現状の問題点に気づく。まず、title の meta タグが無視されているので、ページのタイトルが国際化されない。あとは、25%,75%の2列のレイアウトを選んでも、2列に表示されるが50%,50%くらいに表示されるな~っと思っていたら、ここで、無視していたからなのね。

内容についてみてみると、前半部分ではページに関する情報を取得しているだけだね(まぁ、あとで、meta タグの処理をいれんといかんけど)。後半部分では、各ポートレット情報の取得だな。portletName と portletEntityIdをセットして、jetspeed.om.Portlet を作成している。portletName は、たとえば、blog::BlogTitleViewPortletみたいな感じで、portletEntityId はフラグメントの ID だから、ポータル全体でユニークな値だね。次にjetspeed.om.Portletは

jetspeed.om.Portlet = function( /* String */ portletName, /* String */ portletEntityId, /* special */ alternateContentRetriever )
{
this.name = portletName;
this.entityId = portletEntityId;
this.properties = {};
if ( alternateContentRetriever )
this.contentRetriever = alternateContentRetriever;
};

だから、name, entityId と使う properties を作成して、alternateContentRetriever をセットするみたいだね。ここでは、alternateContentRetriever はなしと思われる。というわけで、getPortletsFromPSMLに戻る。

var props = lis[x].getElementsByTagName( "property" );
for( var propsIdx=0; propsIdx < props.length; propsIdx++ )
{
var propName = props[propsIdx].getAttribute( "name" ) ;
var propValue = props[propsIdx].getAttribute( "value" ) ;
portlet.putProperty( propName, propValue ) ;
}

っで、fragmentタグ内にあるpropertyタグを処理していくのだね。propertyタグのnameとvalue属性を順番にportletインスタンスに入れていっている。ちなみに、Portlet クラスの putProperty は

putProperty: function(name, value)
{
this.properties[name] = value;
},

と言う感じで、properties に入れていっているだけだね。そして、getPortletsFromPSMLでは、次に、portlet.initialize();を呼び出しとるね。

initialize: function()
{   // must be called once init sensitive putProperty calls are complete
if ( ! this.getProperty( jetspeed.id.PORTLET_PROP_WIDGET_ID ) )
{
this.putProperty( jetspeed.id.PORTLET_PROP_WIDGET_ID, jetspeed.id.PORTLET_WINDOW_ID_PREFIX + this.entityId );
}
if ( ! this.getProperty( jetspeed.id.PORTLET_PROP_CONTENT_RETRIEVER ) )
{
this.putProperty( jetspeed.id.PORTLET_PROP_CONTENT_RETRIEVER, this.contentRetriever );
}
var colSpan = this.getProperty( jetspeed.id.PORTLET_PROP_COLUMN_SPAN );
if ( colSpan != null )
{
if ( ! jetspeed.prefs.windowTiling || ! dojo.lang.isNumber( colSpan ) || colSpan <= 1 )
{
colSpan = null ;
this.putProperty( jetspeed.id.PORTLET_PROP_COLUMN_SPAN, null );
}
}
var posStatic = this.getProperty( jetspeed.id.PORTLET_PROP_WINDOW_POSITION_STATIC );
if ( posStatic != null && posStatic && ( ! jetspeed.prefs.windowTiling || colSpan != null ) )
{
posStatic = false ;
this.putProperty( jetspeed.id.PORTLET_PROP_WINDOW_POSITION_STATIC, false );
}
else if ( posStatic == null )
{
if ( jetspeed.prefs.windowTiling )
this.putProperty( jetspeed.id.PORTLET_PROP_WINDOW_POSITION_STATIC, true );
else
this.putProperty( jetspeed.id.PORTLET_PROP_WINDOW_POSITION_STATIC, false );
}
var windowtitle = this.getProperty( jetspeed.id.PORTLET_PROP_WINDOW_TITLE );
if ( ! windowtitle && this.name )
{
var re = (/^[^:]*:*/);
windowtitle = this.name.replace( re, "" );
this.putProperty( jetspeed.id.PORTLET_PROP_WINDOW_TITLE, windowtitle );
}
},

ここでは、いくつか定数があるな・・・。これを見る前にjetspeed.idを確認。

jetspeed.id =
{
DESKTOP: "jetspeedDesktop",
TASKBAR: "jetspeedTaskbar",
COLUMNS: "jetspeedColumns",
SELECTOR: "jetspeedSelector",
PORTLET_STYLE_CLASS: "portlet",
PORTLET_WINDOW_STYLE_CLASS: "dojoFloatingPane",
PORTLET_WINDOW_GHOST_STYLE_CLASS: "ghostPane",
PORTLET_WINDOW_ID_PREFIX: "portletWindow_",
PORTLET_PROP_WIDGET_ID: "widgetId",
PORTLET_PROP_CONTENT_RETRIEVER: "contentRetriever",
PORTLET_PROP_WINDOW_POSITION_STATIC: "windowPositionStatic",
PORTLET_PROP_COLUMN_SPAN: "windowColumnSpan",
PORTLET_PROP_WINDOW_THEME: "windowTheme",
PORTLET_PROP_WINDOW_TITLE: "title",
PORTLET_PROP_WINDOW_ICON: "windowIcon",
PORTLET_PROP_WIDTH: "width",
PORTLET_PROP_HEIGHT: "height",
PORTLET_PROP_LEFT: "left",
PORTLET_PROP_TOP: "top",
PORTLET_PROP_COLUMN: "column",
PORTLET_PROP_ROW: "row",
PORTLET_PROP_EXCLUDE_PCONTENT: "excludePContent",
PORTLET_PROP_WINDOW_STATE: "windowState",
MENU_WIDGET_ID_PREFIX: "jetspeed-menu-",
WINDOW_THEMES: [ "tigris", "blueocean" ]     // temporary validation to avoid trying to use an undefined window theme
};

initializeを見てみると、初期設定という感じだな。jetspeed.id.PORTLET_PROP_WIDGET_IDはIDだな。jetspeed.id.PORTLET_PROP_CONTENT_RETRIEVERは、デフォルトの値が入ると思われるから、

dojo.inherits( jetspeed.om.Portlet, jetspeed.om.Id);
dojo.lang.extend( jetspeed.om.Portlet,
{
name: null,
entityId: null,
contentRetriever: new jetspeed.om.PortletContentRetriever(),
windowFactory: null,
lastSavedWindowState: null,
JAVASCRIPT_ACTION_PREFIX: "javascript:doAction(",
JAVASCRIPT_RENDER_PREFIX: "javascript:doRender(",
JAVASCRIPT_ARG_QUOTE: "&" + "quot;",
PORTLET_REQUEST_ACTION: "action",
PORTLET_REQUEST_RENDER: "render",

にあるjetspeed.om.PortletContentRetriever()だな。コンストラクタでは、何もしていないみたい。

jetspeed.om.PortletContentRetriever = function()
{
};

と言う感じでjetspeed.id.PORTLET_PROP_CONTENT_RETRIEVERが決定。

jetspeed.id.PORTLET_PROP_COLUMN_SPANはfragementタグのpropertyタグに値があれば、それを使うけど、変な値があれば、nullにしているっぽい。そんで、jetspeed.id.PORTLET_PROP_WINDOW_POSITION_STATICは、場所を固定するかどうかだな。これもpsmlで設定できるのか・・・。jetspeed.id.PORTLET_PROP_WINDOW_TITLEはその名の通り、タイトルかね。これまた、psmlでできるのかね?でも、デフォルトだと、タイトルはポートレット名から取得している。ポートレットのインスタンスからはとらんのか?あとで、セットしているのかもしれんけど。

そして、getPortletsFromPSML間で戻って、portlet.initialize()の次は、putPortletは、

putPortlet: function( /* Portlet */ portlet )
{
if (!portlet) return ;
if (! this.portlets) this.portlets = [] ;
this.portlets[ portlet.entityId ] = portlet ;
},

portlets配列がなければ、作成して、ポートレットインスタンスを格納。

ふ~、これで、getPortletsFromPSMLが終わった・・・。つまりのところ、こいつで、ポートレット情報の取得と初期化だな。で、次は、notifySuccessまで戻って、jetspeed.loadPortletWindows();だそうな。

今日のところはこれまで・・・

コメントを残す

メールアドレスが公開されることはありません。