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

続き・・・

postParseAnnotateHtmlは見てみると、必要であれば、URLを書き換えるといった感じだな。URLは基本的には、javascript:doAction(URL,entityId)かjavascript:doRender(URL,entityId)と言う感じになると思われる。

ここまで処理ができたら、どこまで戻るかというと、jetspeed.loadPortletWindowsまで戻り、次は、

jetspeed.page.retrieveAllMenus();   // BOZO: should not be happening here!

だな。というわけで、retrieveAllMenusを見てみよう。これはたぶん、タブメニューのことだろうな。

retrieveAllMenus: function()
{
var contentListener = new jetspeed.om.MenusAjaxApiCallbackContentListener( true );
this.retrieveMenuDeclarations( contentListener );
},

MenusAjaxApiCallbackContentListenerのコンストラクタは、

jetspeed.om.MenusAjaxApiCallbackContentListener = function( /* boolean */ retrieveEachMenu )
{
jetspeed.om.MenusAjaxApiContentListener.call( this, retrieveEachMenu );
};

で、

jetspeed.om.MenusAjaxApiContentListener = function( /* boolean */ retrieveEachMenu )
{
this.retrieveEachMenu = retrieveEachMenu;
};

となっている。おそらく、これも、dojo.io.bindで取得したデータを処理するリスナーだと思う。

次は、retrieveAllMenusのthis.retrieveMenuDeclarationsで、

retrieveMenuDeclarations: function( contentListener )
{
if ( contentListener == null )
contentListener = new jetspeed.om.MenusAjaxApiContentListener( false );
this.clearMenus();
var queryString = "?action=getmenus";
var psmlMenusActionUrl = this.getPsmlUrl() + queryString;
var mimeType = "text/xml";
var ajaxApiContext = new jetspeed.om.Id( "getmenus", { page: this } );
jetspeed.url.retrieveContent( psmlMenusActionUrl, contentListener, null, mimeType, ajaxApiContext, jetspeed.debugContentDumpIds );
},

まず、ここでのcontentListener には、既に定義したと思うので入らないと思う(でも、var contentListenerと言う感じで変数宣言みたいになっているから入るような気もするのだが・・・バグか?)。まぁ、入らないものとして次へ行くと、clearMenusで、

clearMenus: function()
{
this.menus = [];
},

メニュー配列menusを空にするのね。次にいって、psmlMenusActionUrlを作成している。actionをgetmenusとすれば、メニューがとれるんだね~。mimeTypeは text/xml としているな。これをすれば、domツリーでメニューがとれると言うことだな。ajaxApiContextは次のretrieveContentでリスナーのnotifySuccessの引数として渡されるものだね。そして、retrieveContentでdojo.io.bindを使って、コンテンツを取得して、リスナーを呼び出し。notifySuccessは、

notifySuccess: function( /* XMLDocument */ data, /* String */ requestUrl, domainModelObject )
{
var menuDefs = this.getMenuDefs( data, requestUrl, domainModelObject );
var menuContentListener = new jetspeed.om.MenuAjaxApiContentListener( this, menuDefs.length )
for ( var i = 0 ; i < menuDefs.length; i++ )
{
var mObj = menuDefs[i];
domainModelObject.page.putMenu( mObj );
if ( this.retrieveEachMenu )
{
domainModelObject.page.retrieveMenu( mObj.getName(), mObj.getType(), menuContentListener );
}
else if ( i == (menuDefs.length -1) )
{
if ( dojo.lang.isFunction( this.notifyFinished ) )
{
this.notifyFinished( domainModelObject );
}
}
}
},

まずは、menuDefsをセットするのにgetMenuDefsだな。

getMenuDefs: function( /* XMLDocument */ data, /* String */ requestUrl, domainModelObject )
{
var menuDefs = [];
var menuDefElements = data.getElementsByTagName( "menu" );
for( var i = 0; i < menuDefElements.length; i++ )
{
var menuType = menuDefElements[i].getAttribute( "type" );
var menuName = menuDefElements[i].firstChild.nodeValue;
menuDefs.push( new jetspeed.om.Menu( menuName, menuType ) );
}
return menuDefs;
},

戻り値となるmenuDefs配列を作成して、dojo.io.bindで取得したdomツリーから、menuタグを順に取得していって、type属性とmenuタグ内の文字列をjetspeed.om.Menuに渡して new しているな。

jetspeed.om.Menu = function( /* String */ menuName, /* String */ menuType )
{
this._is_parsed = false;
this.name = menuName;
this.type = menuType;
};

と言った感じ。menuDefs配列ができたところで、notifySuccessに返して、jetspeed.om.MenuAjaxApiContentListenerを作成。

jetspeed.om.MenuAjaxApiContentListener = function( /* jetspeed.om.MenusAjaxApiContentListener */ parentNotifyFinishedListener, /* int */ parentNotifyFinishedAfterIndex )
{
this.parentNotifyFinishedListener = parentNotifyFinishedListener;
this.parentNotifyFinishedAfterIndex = parentNotifyFinishedAfterIndex;
this.parentNotified = false;
this.notifyCount = 0;
};

ふむ。次は、メニューを一つずつ実行。まずは、putMenuを実行。

putMenu: function( /* jetspeed.om.Menu */ menuObj )
{
if ( ! menuObj ) return;
var menuName = ( menuObj.getName ? menuObj.getName() : null );
if ( ! menuName ) dojo.raise( "Page.addMenu argument is invalid - no menu-name can be found" );
this.menus[ menuName ] = menuObj;
},

つまり、メニュー名が存在していることを確認してから、jetspeed.om.Pageのメニュー配列に入れるわけね。

次に、this.retrieveEachMenuはtrueなので、retrieveMenuを実行。

retrieveMenu: function( /* String */ menuName, /* String */ menuType, contentListener )     {
if ( contentListener == null )
contentListener = new jetspeed.om.MenuAjaxApiCallbackContentListener();
var queryString = "?action=getmenu&name=" + menuName;
var psmlMenuActionUrl = this.getPsmlUrl() + queryString;
var mimeType = "text/xml";
var ajaxApiContext = new jetspeed.om.Id( "getmenu-" + menuName, { page: this, menuName: menuName, menuType: menuType } );
jetspeed.url.retrieveContent( psmlMenuActionUrl, contentListener, null, mimeType, ajaxApiContext, jetspeed.debugContentDumpIds );
},

まぁ、もう、見慣れたやつで、actionをgetmenuとして、dojo.io.bindを呼び出しね。リスナーのnotifySuccessは、

notifySuccess: function( /* XMLDocument */ data, /* String */ requestUrl, domainModelObject )
{
this.notifyCount++;
var menuObj = this.parseMenu( data, domainModelObject.menuName, domainModelObject.menuType );
domainModelObject.page.putMenu( menuObj );
if ( ! this.parentNotified && this.parentNotifyFinishedListener != null && this.notifyCount >= this.parentNotifyFinishedAfterIndex && dojo.lang.isFunction( this.parentNotifyFinishedListener.notifyFinished ) )
{
this.parentNotified = true;
this.parentNotifyFinishedListener.notifyFinished( domainModelObject );
}
if ( dojo.lang.isFunction( this.notifyFinished ) )
{
this.notifyFinished( domainModelObject, menuObj );
}
},

parseMenuを見てみると、

parseMenu: function( /* XMLNode */ node, /* String */ menuName, /* String */ menuType )
{
var menu = null;
var jsElements = node.getElementsByTagName( "js" );
if ( ! jsElements || jsElements.length > 1 )
dojo.raise( "unexpected zero or multiple <js> elements in menu xml" );
var children = jsElements[0].childNodes;
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 == "menu" )
{
if ( menu != null )
dojo.raise( "unexpected multiple top level <menu> elements in menu xml" );
menu = this.parseMenuObject( child, new jetspeed.om.Menu() );
}
}
if ( menu != null )
{
if ( menu.name == null )
menu.name == menuName;
if ( menu.type == null )
menu.type = menuType;
}
return menu;
},

メニューの子ノードを取得しているようだな。つまり、タブメニューを作るのかと思っていたら、普通のメニューを作っている気が。参考までに、parseMenuObjectも見てみると、

parseMenuObject: function( /* XMLNode */ node, /* MenuOption */ mObj )
{
var constructObj = null;
var children = node.childNodes;
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 == "menu" )
{
if ( mObj.isLeaf() )
dojo.raise( "unexpected nested <menu> in <option> or <separator>" );
else
mObj.addOption( this.parseMenuObject( child, new jetspeed.om.Menu() ) );
}
else if ( childLName == "option" )
{
if ( mObj.isLeaf() )
dojo.raise( "unexpected nested <option> in <option> or <separator>" );
else
mObj.addOption( this.parseMenuObject( child, new jetspeed.om.MenuOption() ) );
}
else if ( childLName == "separator" )
{
if ( mObj.isLeaf() )
dojo.raise( "unexpected nested <separator> in <option> or <separator>" );
else
mObj.addOption( this.parseMenuObject( child, new jetspeed.om.MenuOptionSeparator() ) );
}
else if ( childLName )
mObj[ childLName ] = ( ( child && child.firstChild ) ? child.firstChild.nodeValue : null );
}
if ( mObj.setParsed )
mObj.setParsed();
return mObj;
}

と言った感じ。パースが終わったら、notifySuccessで、また、putMenuをして、

if ( ! this.parentNotified && this.parentNotifyFinishedListener != null && this.notifyCount >= this.parentNotifyFinishedAfterIndex && dojo.lang.isFunction( this.parentNotifyFinishedListener.notifyFinished ) )
{
this.parentNotified = true;
this.parentNotifyFinishedListener.notifyFinished( domainModelObject );
}
if ( dojo.lang.isFunction( this.notifyFinished ) )
{
this.notifyFinished( domainModelObject, menuObj );
}

だけで、どう処理されるのかね・・・。

まず、parentNotifyFinishedListenerはjetspeed.om.MenusAjaxApiCallbackContentListenerだから、一通り処理が終われば、上のif文に入ることになるだろう。

次のif文は、jetspeed.om.MenuAjaxApiContentListenerだから、notifyFinishedメソッドはないな。というわけで、下のif文にはいることはない。

というわけで、MenusAjaxApiCallbackContentListenerのnotifyFinishedは、

notifyFinished: function( domainModelObject )
{
jetspeed.notifyRetrieveAllMenusFinished();
}

で、

jetspeed.notifyRetrieveAllMenusFinished = function()
{   // dojo.event.connect to this or add to your page content, one of the functions that it invokes ( doMenuBuildAll() or doMenuBuild() )
jetspeed.pageNavigateSuppress = true;
if ( dojo.lang.isFunction( window.doMenuBuildAll ) )
{
window.doMenuBuildAll();
}
var menuNames = jetspeed.page.getMenuNames();
for ( var i = 0 ; i < menuNames.length; i++ )
{
var menuNm = menuNames[i];
var menuWidget = dojo.widget.byId( jetspeed.id.MENU_WIDGET_ID_PREFIX + menuNm );
if ( menuWidget )
{
menuWidget.createJetspeedMenu( jetspeed.page.getMenu( menuNm ) );
}
}
jetspeed.pageNavigateSuppress = false;
};

はて、まず、始めの doMenuBuildAllなんて、見つからんな・・・。というわけで、スキップされるかね。

次にメニュー配列を順番に処理だ。MENU_WIDGET_ID_PREFIXは”jetspeed-menu-“だな・・・。。

menuNmで実際にどういう値が入っているのかわからないと、いまいち、この辺が理解できなくなってくる気が・・・。というわけで、http://www.marevol.com/marevol/ajaxapi?action=getmenus を実行して、実際の値を確認してみる。得られる結果は、

<js>
<status>success</status>
<action>getmenus</action>
<menus>
<menu type="standard">navigations</menu>
<menu type="standard">back</menu>
<menu type="standard">pages</menu>
<menu type="standard">breadcrumbs</menu>
<menu type="custom">site-navigations</menu>
<menu type="custom">additional-links</menu>
<menu type="custom">page-navigations</menu>
</menus>
</js>

という感じ。つまり、jetspeed.om.Pageのmenusに入っている値は、navigations, back, pages…という感じで、J2 の左側に表示されるメニューやタブメニュー、そんでもって、パンくずリストも含んでいたのね。というわけで、jetspeed-menu-にくっつく値は、これらの値か。

っで次に、上の各メニューでさらに取得した値は、http://www.marevol.com/marevol/ajaxapi?action=getmenu&name=pages という感じで、処理されていたので、みてみると、

<js>
<status>success</status>
<action>getmenu</action>
<menu>
<name>pages</name>
<title>pages</title>
<short-title>pages</short-title>
<skin>tabs</skin>
<hidden>false</hidden>
<selected>true</selected>
<option>
<type>page</type>
<title>ホーム</title>
<short-title>ホーム</short-title>
<skin>orange</skin>
<url>/default-page.psml</url>
<hidden>false</hidden>
<selected>true</selected>
</option>
<option>
<type>page</type>
<title>ノートパッド</title>
<short-title>ノートパッド</short-title>
<skin>orange</skin>
<url>/notepad.psml</url>
<hidden>false</hidden>
<selected>false</selected>
</option>
<option>
<type>page</type>
<title>アドレス帳</title>
<short-title>アドレス帳</short-title>
<skin>orange</skin>
<url>/addresslist.psml</url>
<hidden>false</hidden>
<selected>false</selected>
</option>
<option>
<type>page</type>
<title>Yahoo検索</title>
<short-title>Yahoo検索</short-title>
<skin>orange</skin>
<url>/yws.psml</url>
<hidden>false</hidden>
<selected>false</selected>
</option>
<option>
<type>page</type>
<title>Hello World</title>
<short-title>Hello World</short-title>
<skin>orange</skin>
<url>/helloworld.psml</url>
<hidden>false</hidden>
<selected>false</selected>
</option>
<option>
<type>page</type>
<title>チャート</title>
<short-title>チャート</short-title>
<skin>orange</skin>
<url>/chart.psml</url>
<hidden>false</hidden>
<selected>false</selected>
</option>
</menu>
</js>

という感じ。なるほどね。これで、この辺の処理が納得できると思う。

blue.jspで、タグがあることを確認してみよう。

$ grep "jetspeed-menu-" src/webapp/desktop-themes/blue/blue.jsp
<div widgetId="jetspeed-menu-pages" dojoType="PortalTabContainer" style="width: 100%; height: 30px; margin-top: 2px; margin-left: -1px"></div>
<div widgetId="jetspeed-menu-navigations" dojoType="PortalAccordionContainer" style=""></div>

というわけで、menuWidget.createJetspeedMenuが呼ばれるわけね。

createJetspeedMenuはsrc/webapp/javascript/desktop/widget/PortalTabContainer.jsとsrc/webapp/javascript/desktop/widget/PortalAccordionContainer.jsに含まれている。どっちも確認するのは疲れるから、PortalTabContainerの方を見ることにしよう。

createJetspeedMenu: function( /* jetspeed.om.Menu */ menuObj )
{
if ( ! menuObj ) return;
var menuOpts = menuObj.getOptions();
for ( var i = 0 ; i < menuOpts.length ; i++ )
{
var menuOption = menuOpts[i];
if ( menuOption.isLeaf() && menuOption.getUrl() && ! menuOption.isSeparator() )
{
this.addTab( menuOption );
}
}
},

順番にjetspeed.om.Menu内のオプションに対して実行していくのね。実行されるthis.addTabを見てみよう。

addTab: function( /* jetspeed.om.MenuOption */ menuOpt )
{         if ( ! menuOpt ) return;
this.js_addingTab = true;
var tabDomNode = document.createElement( "div" );
var tab = new dojo.widget.HtmlWidget();   // create a fake widget so that widget.addedTo doesn't bomb when we call this.addChild() below
tab.domNode = tabDomNode;
tab.menuOption = menuOpt;
tab.label = menuOpt.getShortTitle();
this.addChild( tab );
//dojo.debug( "PortalTabContainer.addTab" );         if ( jetspeed.page.equalsPageUrl( menuOpt.getUrl() ) )
{
this.selectTab( tab );   // this.selectedTab
this.selectedTab = null;  // to keep it from matching the fake widgets with no widgetdI
}
this.js_addingTab = false;
},

タブをdojo.widget.HtmlWidgetウィジェットとして作成して、addChildするのね。っで、どこへaddChildかと思ったら、

dojo.inherits(jetspeed.ui.widget.PortalTabContainer, dojo.widget.html.TabContainer);

TabContainerなのか。つまり、dojo.widget.html.TabContainerの動作とあまり変わらんと言うことかね。TabContainerを見てみると、addChildをしたら、_setupTabを呼び出して、タグを作っている模様。参考までに、

_setupTab: function(tab){
tab.domNode.style.display="none";
// Create label
tab.div = document.createElement("div");
dojo.html.addClass(tab.div, "dojoTabPaneTab");
var span = document.createElement("span");
span.innerHTML = tab.label;
dojo.html.disableSelection(span);
if (this.closeButton=="tab") {
var img = document.createElement("div");
dojo.html.addClass(img, "dojoTabPaneTabClose");
var self = this;
dojo.event.connect(img, "onclick", function(evt){ self._runOnCloseTab(tab); dojo.event.browser.stopEvent(evt); });
dojo.event.connect(img, "onmouseover", function(){ dojo.html.addClass(img,"dojoTabPaneTabCloseHover"); });
dojo.event.connect(img, "onmouseout", function(){ dojo.html.removeClass(img,"dojoTabPaneTabCloseHover"); });
span.appendChild(img);
}
tab.div.appendChild(span);
this.dojoTabLabels.appendChild(tab.div);
var self = this;
dojo.event.connect(tab.div, "onclick", function(){ self.selectTab(tab); });
if(!this.selectedTabWidget || this.selectedTab==tab.widgetId || tab.selected){
this.selectedTabWidget = tab;
} else {
this._hideTab(tab);
}
},

と言う感じで、今まで見てきたけど、メニューの処理が一通り終わると、表示に関する処理が完了して、ブラウザ上で表示されていることでしょう。結構、じっくりと動作を見てきたので、だいたい理解できた。というわけで、skyデスクトップテーマを作っていきましょ~。

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

続き・・・

jetspeed.url.retrieveContentは既に確認しているので、詳細は飛ばすが、jetspeed.url.retrieveContentはアクセスに成功すると、contentListener.notifySuccess( data, requestUrl, domainModelObject ) ;を呼び出す。ここで、contentListenerは、PortletContentListenerなので、

jetspeed.om.PortletContentListener.prototype =
{
notifySuccess: function( /* String */ portletContent, /* String */ requestUrl, /* Portlet */ portlet )
{
portlet.setPortletContent( portletContent, requestUrl );
},
notifyFailure: function( /* String */ type, /* String */ error, /* String */ requestUrl, /* Portlet */ portlet )
{
dojo.debug( "PortletContentListener notifyFailure url=" + requestUrl + " type=" + type + " error=" + error ) ;
}
};

portletContentはStringっぽいな。retrieveContentでmimeTypeがtext/htmlとしてアクセスしたからかね。setPortletContentを見てみよう。

setPortletContent: function( portletContent, renderUrl )
{
var windowWidget = this.getPortletWindow();
if ( windowWidget )
{
windowWidget.setPortletContent( portletContent, renderUrl );
}
},

まず、getPortletWindowは

getPortletWindow: function()
{
var windowWidgetId = this.getProperty( jetspeed.id.PORTLET_PROP_WIDGET_ID );
if ( windowWidgetId )
return dojo.widget.byId( windowWidgetId );
return null;
},

dojoのポートレットウィンドウのウィジェットを取得しているのね。それをsetPortletContentに戻して、そのウィジェットのsetPortletContentを見てみると、

setPortletContent: function( html, url )
{
var initialHtmlStr = html.toString();
if ( ! this.getInitProperty( jetspeed.id.PORTLET_PROP_EXCLUDE_PCONTENT ) )
{
initialHtmlStr = '<div class="PContent" >' + initialHtmlStr + '</div>';   // BOZO: get this into the template ?
}
var ppR = null;
if ( this.portlet )
{
ppR = this.portlet.preParseAnnotateHtml( initialHtmlStr, url );
}
else
{
ppR = jetspeed.ui.preParseAnnotateHtml( initialHtmlStr, url );
}
//this.executeScripts = true;
var setContentObj = { titles: [], scripts: ppR.preParsedScripts, linkStyles: [], styles: [], remoteScripts: ppR.preParsedRemoteScripts, xml: ppR.preParsedContent, url: url, requires: [] };
this.setContent( setContentObj );
if ( setContentObj.scripts && setContentObj.scripts.length > 0 )
{   // do inline scripts  - taken from dojo ContentPane.js _executeScripts
var repl = null;
for( var i = 0; i < setContentObj.scripts.length; i++ )
{
// not sure why comment and carraige return clean is needed
// but better safe than sorry so we keep it, Fredrik
// Clean up content: remove inline script  comments
repl = new RegExp('//.*?$', 'gm');
setContentObj.scripts[i] = setContentObj.scripts[i].replace(repl, '\n');
// BOZO: despite the comment above from the dojo code, we cannot do this (carriage returns are syntatically required in javascript)
// Clean up content: remove carraige returns
//repl = new RegExp('[\n\r]', 'g');
//setContentObj.scripts[i] = setContentObj.scripts[i].replace(repl, ' ');
// Execute commands
if ( jetspeed.debug.setPortletContent )
dojo.debug( "setPortletContent [" + ( this.portlet ? this.portlet.entityId : this.widgetId ) + "] script: " + setContentObj.scripts[i] );
eval( setContentObj.scripts[i] );
}
}
else
{
if ( jetspeed.debug.setPortletContent )
dojo.debug( "setPortletContent [" + ( this.portlet ? this.portlet.entityId : this.widgetId ) + "]" );
}
this._executeScripts( { scripts: [], remoteScripts: setContentObj.remoteScripts } );
if ( this.portlet )
this.portlet.postParseAnnotateHtml( this.containerNode );
}

まず、始めのif文は、jetspeed.id.PORTLET_PROP_EXCLUDE_PCONTENTはnullだろうから、入って、ポートレットのコンテンツに対して、PContentクラスを持つ div タグを追加するだろう。

次に、this.portletはnullでないので、this.portlet.preParseAnnotateHtmlを実行。

preParseAnnotateHtml: function( /* String */ portletContent )
{
return jetspeed.ui.preParseAnnotateHtml( portletContent );
},

jetspeed.ui.preParseAnnotateHtmlは、

jetspeed.ui.preParseAnnotateHtml = function( /* String */ initialHtmlStr, /* String */ url )
{   // deal with embedded script tags -  /=/=/=/=/=  taken from dojo ContentPane.js  splitAndFixPaths()  =/=/=/=/=/
var scripts = [];
var remoteScripts = [];
// cut out all script tags, stuff them into scripts array
var match = [];
while ( match )
{
match = initialHtmlStr.match(/<script([^>]*)>([\s\S]*?)<\/script>/i);
if(!match){ break; }
if(match[1]){
attr = match[1].match(/src=(['"]?)([^"']*)\1/i);
if ( attr )
{
// remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
if ( (attr[2].search(/\/?\bdojo.js(?:\.uncompressed.js)?/i) != -1) && (dojo.hostenv.getBaseScriptUri() == attr[2].match(/[.\/]*/)[0]) )
{
dojo.debug("Security note! inhibit:"+attr[2]+" from  beeing loaded again.");
}
else
{
remoteScripts.push( attr[2] );
}
}
}
if ( match[2] )
{
// get rid of html comment blanket
var scriptText = match[2].replace(/^\s*<!--/, "");
scriptText = scriptText.replace(/-->\s*$/, "");
scriptText = scriptText.replace(/function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g, "window.$1 = function(" );
// strip out all djConfig variables from script tags nodeValue
// this is ABSOLUTLY needed as reinitialize djConfig after dojo is initialised
// makes a dissaster greater than Titanic
scripts.push(scriptText.replace(/(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo.hostenv.writeIncludes\(\s*\);?/g, ""));
}
initialHtmlStr = initialHtmlStr.replace(/<script[^>]*>[\s\S]*?<\/script>/i, "");
}
//dojo.debug( "= = = = = =  annotated content for: " + ( url ? url : "unknown url" ) );
//dojo.debug( initialHtmlStr );
//if ( scripts.length > 0 )
//{
//    dojo.debug( "      = = =  script content for: " + ( url ? url : "unknown url" ) );
//    for ( var i = 0 ; i < scripts.length; i++ )
//        dojo.debug( "      =[" + (i+1) + "]:" + scripts[i] );
//}
//     /=/=/=/=/=  end of taken from dojo ContentPane.js  splitAndFixPaths()  =/=/=/=/=/
//dojo.debug( "preParse  scripts: " + ( scripts ? scripts.length : "0" ) + " remoteScripts: " + ( remoteScripts ? remoteScripts.length : "0" ) );
return { preParsedContent: initialHtmlStr, preParsedScripts: scripts, preParsedRemoteScripts: remoteScripts };
};

やっていることをまとめると、ポートレットのコンテンツにJavaScriptのタグが含まれているなら、それをscriptsかremoteScriptsに入れる。remoteScriptsはjsファイルみたいな呼び出しをされていた場合みたいだな。

それがポートレットウィンドウのsetPortletContentでppRにセットする。そしたら、setContentObjを作成して、setContentを呼び出す。このsetContentはdojo.widget.html.ContentPaneのメソッド。コンテンツは、ここで、this.containerNodeまたはthis.domNodeにくっつけることになる。続いて、javascriptの処理。まず、scriptタグで記述されているスクリプトを順にevalで実行。続いて、src属性でscriptタグにあるものをthis._executeScriptsに渡す。この_executeScriptsもdojo.widget.html.ContentPaneのメソッド。dojo.io.bindを使って、取得して処理するようだ。そして、最後に、this.portlet.postParseAnnotateHtmlを実行。

postParseAnnotateHtml: function( /* DOMNode */ containerNode )
{
if ( containerNode )
{
var cNode = containerNode;
var formList = cNode.getElementsByTagName( "form" );
var debugOn = jetspeed.debug.postParseAnnotateHtml;
if ( formList )
{
for ( var i = 0 ; i < formList.length ; i++ )
{
var cForm = formList[i];
var cFormAction = cForm.action;
var cFormPortletEntityId = this.entityId;  // BOZO:can I assume that it is always my entity-id (ignoring the one in parsedPseudoUrl)
var parsedPseudoUrl = this.parseJSPseudoUrlActionRender( cFormAction );
var submitOperation = parsedPseudoUrl.operation;
if ( submitOperation == this.PORTLET_REQUEST_ACTION || submitOperation == this.PORTLET_REQUEST_RENDER )
{
var replacementActionUrl = this._generateJSPseudoUrlActionRender( parsedPseudoUrl );
if ( replacementActionUrl == cFormAction )
{
if ( debugOn )
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] adding onSubmit (portlet-" + submitOperation + ") and leaving form action as is: " + cFormAction );
}
else
{
cForm.action = replacementActionUrl;
if ( debugOn )
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] adding onSubmit (portlet-" + submitOperation + ") and changing form action attribute from: " + cFormAction + " to: " +  replacementActionUrl );
}
this._addOnSubmitActionRender( cForm, cFormPortletEntityId, submitOperation );
}
else
{
if ( djConfig.isDebug )  // want to see this, for now
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] form action attribute doesn't match annotation criteria, leaving as is: " + cFormAction ) ;
}
}
}
var aList = cNode.getElementsByTagName( "a" );
if ( aList )
{
for ( var i = 0 ; i < aList.length ; i++ )
{
var aNode = aList[i];
var aHref = aNode.href;
var parsedPseudoUrl = this.parseJSPseudoUrlActionRender( aHref );
var replacementHref = this._generateJSPseudoUrlActionRender( parsedPseudoUrl );
if ( ! replacementHref )
{
if ( debugOn )
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] leaving href as is: " + aHref );
}
else if ( replacementHref == aHref )
{
if ( debugOn )
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] href parsed and regenerated identically: " + aHref );
}
else
{
if ( debugOn )
dojo.debug( "postParseAnnotateHtml [" + this.entityId + "] href parsed, replacing: " + aHref + " with: " + replacementHref );
aNode.href = replacementHref;
}
}
}
}
},

長いな・・・。これをざっと見た感じでは、formとaタグのリンクの書き換えだな。

今日はここまで・・・