package er.extensions.components;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSMutableDictionary;
import er.extensions.appserver.ERXBrowser;
import er.extensions.appserver.ERXRequest;
import er.extensions.appserver.ERXResponseRewriter;
import er.extensions.foundation.ERXUtilities;
import er.extensions.foundation.ERXValueUtilities;
import er.extensions.localization.ERXLocalizer;
/**
* <div class="en">
* ERXComponent provides a common base class for WOComponents along with a bunch
* of miscellaneous handy features.
* </div>
*
* <div class="ja">
* ERXComponent は WOComponents のサブクラスで、多数の便利なコマンドを用意しています
* </div>
*
* @author mschrag
*/
public abstract class ERXComponent extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
protected NSMutableDictionary _dynamicBindings = null;
/**
* Constructs a new ERXComponent.
*
* @param context
* the WOContext
*/
public ERXComponent(WOContext context) {
super(context);
}
/**
* <div class="en">
* This variant of pageWithName provides a Java5 genericized version of the
* original pageWithName. You would call it with:
*
* MyNextPage nextPage = pageWithName(MyNextPage.class);
* </div>
*
* <div class="ja">
* Java5 の新しい pageWithName コマンド。
* 次の様に呼ばれます:
*
* MyNextPage nextPage = pageWithName(MyNextPage.class);
* </div>
*
* @param <T> <div class="en">the type of component to create</div>
* <div class="ja">作成するコンポーネント・タイプ</div>
* @param componentClass <div class="en">the Class of the component to load</div>
* <div class="ja">ロードするコンポーネントのクラス</div>
*
* @return <div class="en">an instance of the requested component class</div>
* <div class="ja">コンポーネント・クラスのインスタンス</div>
*/
@SuppressWarnings("unchecked")
public <T extends WOComponent> T pageWithName(Class<T> componentClass) {
return (T) super.pageWithName(componentClass.getName());
}
@Override
public void _awakeInContext(WOContext aArg0) {
super._awakeInContext(aArg0);
if (isStateless()) {
_dynamicBindings = null;
}
}
/**
* <div class="en">
* _checkAccess is called prior to all three phases of the R-R loop to
* ensure that the user has permission to access this component. You should
* override checkAccess to implement addition security checks.
* </div>
*
* <div class="ja">
* 各リスポンス・リクエスト・ループの最初に _checkAccess 実行され、ユーザがこのコンポーネントへのアクセスが可能かどうかをチェックします。
*
* 他のセキュリティ・チェックを行う時には checkAccess をオーバライドすると良い
* </div>
*
* @throws SecurityException <div class="en">if the user does not have permission</div>
* <div class="ja">ユーザがアクセス権を持っていない場合</div>
*/
protected void _checkAccess() throws SecurityException {
if (!isPageAccessAllowed() && _isPage()) {
throw new SecurityException("You are not allowed to directly access the component '" + name() + "'.");
}
if (shouldCheckAccess()) {
checkAccess();
}
}
/**
* Returns whether or not this component should check access before processing any of the request-response loop.
* The default implementation just returns _isPage().
*
* @return whether or not this component should check access
*/
protected boolean shouldCheckAccess() {
return _isPage();
}
/**
* <div class="en">
* Calls _checkAccess prior to super.takeValuesFromRequest.
* </div>
*
* <div class="ja">
* スーパーの前に _checkAccess のセキュリティ・チェックを行います
* </div>
*
* @param request <div class="en">the current request with the WOComponent object</div>
* <div class="ja">リクエスト</div>
* @param context <div class="en">context of a transaction</div>
* <div class="ja">トランスアクションのコンテキスト</div>
*/
@Override
public void takeValuesFromRequest(WORequest request, WOContext context) {
_checkAccess();
super.takeValuesFromRequest(request, context);
}
/**
* <div class="en">
* Calls _checkAccess prior to super.invokeAction.
* </div>
*
* <div class="ja">
* スーパーの前に _checkAccess のセキュリティ・チェックを行います
* </div>
*
* @param request <div class="en">the current request with the WOComponent object</div>
* <div class="ja">リクエスト</div>
* @param context <div class="en">context of a transaction</div>
* <div class="ja">トランスアクションのコンテキスト</div>
*
* @return <div class="en">a WOActionResults containing the result of the request</div>
* <div class="ja">リクエスト結果を含む WOActionResults</div>
*/
@Override
public WOActionResults invokeAction(WORequest request, WOContext context) {
_checkAccess();
return super.invokeAction(request, context);
}
/**
* <div class="en">
* Calls _checkAccess prior to super.appendToResponse and adds support for
* ClickToOpen (TM).
* </div>
*
* <div class="ja">
* スーパーの前にセキュリティ・チェックし、ClickToOpen (TM) サポート
* </div>
*
* @param response <div class="en">the HTTP response that an application returns to a Web server to complete a cycle of the request-response loop</div>
* <div class="ja">RR ループの最後のリスポンス結果を戻す</div>
* @param context <div class="en">context of a transaction</div>
* <div class="ja">トランスアクションのコンテキスト</div>
*/
@Override
public void appendToResponse(WOResponse response, WOContext context) {
_checkAccess();
preAppendToResponse(response, context);
boolean clickToOpenEnabled = clickToOpenEnabled(response, context);
ERXClickToOpenSupport.preProcessResponse(response, context, clickToOpenEnabled);
try {
super.appendToResponse(response, context);
}
finally {
ERXClickToOpenSupport.postProcessResponse(getClass(), response, context, clickToOpenEnabled);
}
postAppendToResponse(response, context);
_includeCSSResources(response, context);
_includeJavascriptResources(response, context);
}
/**
* <div class="en">
* Returns whether or not click-to-open should be enabled for this
* component. By default this returns ERXClickToOpenSupport.isEnabled().
* </div>
*
* <div class="ja">
* このコンポーネントで click-to-open をサポートしているかどうかを戻します。
* デフォルトでは ERXClickToOpenSupport.isEnabled() を戻します。
* </div>
*
* @param response <div class="en">the response</div>
* <div class="ja">リスポンス</div>
* @param context <div class="en">the context</div>
* <div class="ja">コンテクスト</div>
*
* @return <div class="en">whether or not click-to-open is enabled for this component</div>
* <div class="ja">このコンポーネントで click-to-open をサポートしているかどうか</div>
*/
public boolean clickToOpenEnabled(WOResponse response, WOContext context) {
return ERXClickToOpenSupport.isEnabled();
}
/**
* <div class="en">
* Resolves a given binding as a int value. Useful for image sizes and the
* like.
* </div>
*
* <div class="ja">
* 指定されているバインディングを int 値に変換して戻します。<br>
* イメージ・サイズなどに有効です
* </div>
*
* @param binding <div class="en">binding to be resolved as a int value.</div>
* <div class="ja">int 値として戻すバインディング</div>
* @param defaultValue <div class="en">default int value to be used if the binding is not bound.</div>
* <div class="ja">バインディングが見つからない場合のデフォルト int 値</div>
*
* @return <div class="en">result of evaluating binding as a int.</div>
* <div class="ja">バインディング結果の int 値</div>
*/
protected int intValueForBinding(String binding, int defaultValue) {
return ERXValueUtilities.intValueWithDefault(valueForBinding(binding), defaultValue);
}
/**
* <div class="en">
* Resolves a given binding as a float value.
* </div>
*
* <div class="ja">
* 指定されているバインディングを float 値に変換して戻します。<br>
* </div>
*
* @param binding <div class="en">binding to be resolved as a float value.</div>
* <div class="ja">float 値として戻すバインディング</div>
* @param defaultValue <div class="en">default float value to be used if the binding is not bound.</div>
* <div class="ja">バインディングが見つからない場合のデフォルト float 値</div>
*
* @return <div class="en">result of evaluating binding as a float.</div>
* <div class="ja">バインディング結果の float 値</div>
*/
protected float floatValueForBinding(String binding, float defaultValue) {
return ERXValueUtilities.floatValueWithDefault(valueForBinding(binding), defaultValue);
}
/**
* <div class="en">
* Resolves a given binding as a boolean value. Defaults to false.
* </div>
*
* <div class="ja">
* 指定されているバインディングを boolean 値に変換して戻します。<br>
* デフォルトは false です
* </div>
*
* @param binding <div class="en">binding to be resolved as a boolean value.</div>
* <div class="ja">boolean 値として戻すバインディング</div>
*
* @return <div class="en">result of evaluating binding as a boolean.</div>
* <div class="ja">バインディング結果の boolean 値</div>
*/
protected boolean booleanValueForBinding(String binding) {
return booleanValueForBinding(binding, false);
}
/**
* <div class="en">
* Resolves a given binding as a boolean value.
* </div>
*
* <div class="ja">
* 指定されているバインディングを boolean 値に変換して戻します。
* </div>
*
* @param binding <div class="en">binding to be resolved as a boolean value.</div>
* <div class="ja">boolean 値として戻すバインディング</div>
* @param defaultValue <div class="en">default boolean value to be used if the binding is not bound.</div>
* <div class="ja">バインディングが見つからない場合のデフォルト boolean 値</div>
*
* @return <div class="en">result of evaluating binding as a boolean.</div>
* <div class="ja">バインディング結果の boolean 値</div>
*/
protected boolean booleanValueForBinding(String binding, boolean defaultValue) {
return ERXComponentUtilities.booleanValueForBinding(this, binding, defaultValue);
}
/**
* <div class="en">
* Resolves a given binding as a boolean value with the option of specifying
* a boolean operator as the default value.
* </div>
*
* <div class="ja">
* 指定されているバインディングを boolean 値に変換して戻します。<br>
* boolean operator を指定することが可能です
* </div>
*
* @param binding <div class="en">binding to be resolved as a boolean value.</div>
* <div class="ja">boolean 値として戻すバインディング</div>
* @param defaultValue <div class="en">boolean operator to be evaluated if the binding is not present.</div>
* <div class="ja">バインディングが見つからない場合のデフォルト boolean operator</div>
*
* @return <div class="en">result of evaluating binding as a boolean.</div>
* <div class="ja">バインディング結果の boolean 値</div>
*/
protected boolean booleanValueForBinding(String binding, ERXUtilities.BooleanOperation defaultValue) {
if (hasBinding(binding)) {
return booleanValueForBinding(binding, false);
}
return defaultValue.value();
}
/**
* <div class="en">
* Resolves a given binding as an object in the normal fashion of calling
* <code>valueForBinding</code>. This has the one advantage of being able to
* resolve the resulting object as a {link ERXUtilities$Operation} if it is
* an Operation and then returning the result as the evaluation of that
* operation.
* </div>
*
* <div class="ja">
* 指定されているバインディングを object として戻します。<br>
* <code>valueForBinding</code>と違って、結果オブジェクトを{link ERXUtilities$Operation}
* として戻され、処理が含まれるの場合、処理の結果を取得します。
* </div>
*
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">コンポーネントのバインディング名</div>
*
* @return <div class="en">the object for the given binding and in the case that it is an
* instance of an Operation the value of that operation.</div>
* <div class="ja">指定されているバインディングのオブジェクト(処理の値のインスタンス)</div>
*/
protected Object objectValueForBinding(String binding) {
return objectValueForBinding(binding, null);
}
/**
* <div class="en">
* Resolves a given binding as an object in the normal fashion of calling
* <code>valueForBinding</code>. This has the one advantage of being able to
* resolve the resulting object as a {link ERXUtilities$Operation} if it is
* an Operation and then returning the result as the evaluation of that
* operation.
* </div>
*
* <div class="ja">
* 指定されているバインディングを object として戻します。<br>
* <code>valueForBinding</code>と違って、結果オブジェクトを{link ERXUtilities$Operation}
* として戻され、処理が含まれるの場合、処理の結果を取得します。
* </div>
*
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">コンポーネントのバインディング名</div>
* @param defaultValue <div class="en">value to be used if <code>valueForBinding</code> returns null.</div>
* <div class="ja"><code>valueForBinding</code> が null を戻す場合のデフォルト値</div>
*
* @return <div class="en">the object for the given binding and in the case that it is an
* instance of an Operation the value of that operation.</div>
* <div class="ja">指定されているバインディングのオブジェクト(処理の値のインスタンス)</div>
*/
protected Object objectValueForBinding(String binding, Object defaultValue) {
Object result = null;
if (hasBinding(binding)) {
Object o = valueForBinding(binding);
result = (o == null) ? defaultValue : o;
}
else {
result = defaultValue;
}
if (result instanceof ERXUtilities.Operation) {
result = ((ERXUtilities.Operation) result).value();
}
return result;
}
/**
* <div class="en">
* Retrieves a given binding and if it is not null then returns
* <code>toString</code> called on the bound object.
* </div>
*
* <div class="ja">
* 指定されているバインディングのオブジェクトが nullでなければ、<br>
* <code>toString</code> が呼ばれ、結果を戻します。
* </div>
*
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">コンポーネントのバインディング名</div>
*
* @return <div class="en">resolved binding in string format</div>
* <div class="ja">指定されているバインディングの文字列表現</div>
*/
protected String stringValueForBinding(String binding) {
return stringValueForBinding(binding, null);
}
/**
* <div class="en">
* Retrieves a given binding and if it is not null then returns
* <code>toString</code> called on the bound object.
* </div>
*
* <div class="ja">
* 指定されているバインディングのオブジェクトが nullでなければ、<br>
* <code>toString</code> が呼ばれ、結果を戻します。
* </div>
*
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">コンポーネントのバインディング名</div>
* @param defaultValue <div class="en">value to be used if <code>valueForBinding</code> returns null.</div>
* <div class="ja"><code>valueForBinding</code> が null を戻す場合のデフォルト値</div>
*
* @return <div class="en">resolved binding in string format</div>
* <div class="ja">指定されているバインディングの文字列表現</div>
*/
protected String stringValueForBinding(String binding, String defaultValue) {
Object v = objectValueForBinding(binding, defaultValue);
return v != null ? v.toString() : null;
}
/**
* <div class="en">
* Resolves a given binding as an NSArray object.
* </div>
*
* <div class="ja">
* 指定されているバインディングを NSArray 値に変換して戻します。
* </div>
*
* @param <T> type of array elements
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">NSArray 値として戻すバインディング</div>
*
* @return <div class="en">result of evaluating binding as an NSArray.</div>
* <div class="ja">バインディング結果の NSArray 値</div>
*/
protected <T> NSArray<T> arrayValueForBinding(String binding) {
return arrayValueForBinding(binding, null);
}
/**
* <div class="en">
* Resolves a given binding as an NSArray object.
* </div>
*
* <div class="ja">
* 指定されているバインディングを NSArray 値に変換して戻します。
* </div>
*
* @param <T> type of array elements
* @param binding <div class="en">name of the component binding.</div>
* <div class="ja">NSArray 値として戻すバインディング</div>
* @param defaultValue <div class="en">value to be used if <code>valueForBinding</code> returns null.</div>
* <div class="ja">バインディングが見つからない場合のデフォルト NSArray 値</div>
*
* @return <div class="en">result of evaluating binding as an NSArray.</div>
* <div class="ja">バインディング結果の NSArray 値</div>
*/
@SuppressWarnings("unchecked")
protected <T> NSArray<T> arrayValueForBinding(String binding, NSArray<T> defaultValue) {
return ERXValueUtilities.arrayValueWithDefault(valueForBinding(binding), defaultValue);
}
/**
* <div class="en">
* Convenience method to get the localizer.
* </div>
*
* <div class="ja">
* ローカライザーを取得する為の便利なメソッド
* </div>
*
* @return <div class="en">the current localizer</div>
* <div class="ja">カレント・ローカライザー</div>
*/
public ERXLocalizer localizer() {
return ERXLocalizer.currentLocalizer();
}
/**
* <div class="en">
* Convenience method to get the browser.
* </div>
*
* <div class="ja">
* browser オブジェクトを戻します。基本的には session にも directaction にも browser オブジェクトへのアクセスがありますが、
* session 又は directaction 内にあるかどうか分からない時にはこのコマンドが便利です。
* </div>
*
* @return <div class="en">the current browser</div>
* <div class="ja">browser オブジェクト</div>
*/
public ERXBrowser browser() {
ERXRequest request = (ERXRequest) context().request();
return request.browser();
}
/**
* <div class="en">
* Lazily initialized dictionary which can be used for the 'item' binding in
* a repetition for example: 'item = dynamicBindings.myVariable'. Useful in
* rapid turnaround modes where adding a iVar would cause hot code swapping
* to stop working.
* </div>
*
* <div class="ja">
* ダイナミック・バインディング用ディクショナリー
* repetition内、バインディングの 'item' として使用できます。<br>
* 例えば、 'item = dynamicBindings.myVariable'
* </div>
*
* @return <div class="en">a dictionay for use with dynamic bindings</div>
* <div class="ja">NSMutableDictionary ダイナミック・バインディング・ディクショナリー</div>
*/
public NSMutableDictionary dynamicBindings() {
if (_dynamicBindings == null) {
_dynamicBindings = new NSMutableDictionary();
}
return _dynamicBindings;
}
/**
* <div class="ja">
* このメソッドは、指定されているコンテクストのオブジェクトに対する、
* ステートレス・コンポーネントの一時的リファレンスをリセットもしくは削除します。
* あるコンポーネントの共有化されたインスタンスが、他のセッションによって再利用されるとき、
* このメソッドを利用し、各コンポーネントのインスタンス変数を解放します。
* </div>
*/
@Override
public void reset() {
super.reset();
if (_dynamicBindings != null) {
_dynamicBindings.removeAllObjects();
}
}
/**
* <div class="en">
* Returns the name of this component without the package name.
* </div>
*
* <div class="ja">
* このコンポーネントの名前を戻します。(パッケージ無し)
* </div>
*
* @return <div class="en">the name of this component without the package name</div>
* <div class="ja">このコンポーネントの名前</div>
*/
public String componentName() {
String componentName = name();
if (componentName != null) {
int lastDotIndex = componentName.lastIndexOf('.');
if (lastDotIndex != -1) {
componentName = componentName.substring(lastDotIndex + 1);
}
}
return componentName;
}
/**
* <div class="en">
* Injects per-component CSS dependencies into the head tag based on the
* definitions in useDefaultComponentCSS(), defaultCSSPath(),
* primaryCSSFile(), and additionalCSSFiles().
* <p>
* If you return true for useDefaultComponentCSS (and do not override
* primaryCSSFile), this component will inject a reference to
* defaultCSSPath() + /YourComponentName.css. For instance, if your
* component is named HeaderFooter, useDefaultComponentCSS will
* automatically add a reference to defaultCSSPath() + /HeaderFooter.css for
* you. This allows you to very easily specify per-component CSS files
* without upper-level components knowing about them. Currently
* _includeCSSResources does not try to do anything fancy in terms of
* recombining CSS files.
* <p>
* Override defaultCSSPath to provide the base path relative to
* WebServerResources that contains your CSS files. If all of your CSS is in
* WebServerResources/css, you would return "css" from defaultCSSPath().
* <p>
* If you do not want to use the component's name as the name of the CSS
* file, you can optionally override primaryCSSFile() to return the name of
* a specific CSS file, as well as additionalCSSFiles() to return an NSArray
* of CSS files. All of these file names will be prepended with the
* defaultCSSPath if it is set.
* </div>
*
* <div class="ja">
* useDefaultComponentCSS(), defaultCSSPath(),primaryCSSFile(), と additionalCSSFiles()
* で定義されているコンポーネントに依存した CSS をヘッダー内に挿入します。
* <p>
* useDefaultComponentCSS で true を戻す場合 (primaryCSSFileをオーバライドしないで)
* このコンポーネントは defaultCSSPath() + /YourComponentName.css をヘッダーに挿入します。
* 例えば、コンポーネントの名前が HeaderFooter とし、useDefaultComponentCSS は自動的に
* defaultCSSPath() + /HeaderFooter.css へのレファレンスを作成します。
* この機能を使うことで、簡単にコンポーネントに属している CSS ファイルを作成でき、上位のコンポーネントを
* 意識する必要がありません。
* 現在では _includeCSSResources は CSS ファイルの結合などを行いません。
* <p>
* defaultCSSPath をオーバライドすること、CSS ファイルを含む WebServerResources への元パスを提供します。
* すべての CSS が WebServerResources/css 内にある場合、defaultCSSPath() として "css" を戻します。
* <p>
* CSS ファイルとしてコンポーネント名を使用したく無い場合、primaryCSSFile() をオーバライドすることで、
* ある CSS ファイル名を戻します。それとも、additionalCSSFiles() で CSS ファイルの NSArray を戻します。
* すべてのファイル名は defaultCSSPath を先頭に追加されるのです。
* </div>
*
* @param response <div class="en">the response to write into</div>
* <div class="ja">書き込みするリスポンス</div>
* @param context <div class="en">the current context</div>
* <div class="ja">カレント・コンテクスト</div>
*/
protected void _includeCSSResources(WOResponse response, WOContext context) {
String primaryCSSFile = primaryCSSFile();
if (primaryCSSFile == null && useDefaultComponentCSS()) {
String componentName = componentName();
primaryCSSFile = componentName + ".css";
}
if (primaryCSSFile != null) {
String defaultCSSPath = defaultCSSPath();
if (defaultCSSPath != null && defaultCSSPath.length() > 0 && !defaultCSSPath.endsWith("/")) {
defaultCSSPath += "/";
}
String frameworkName = _frameworkName();
ERXResponseRewriter.addStylesheetResourceInHead(response, context, frameworkName, defaultCSSPath + primaryCSSFile);
}
NSArray<String> additionalCSSFiles = additionalCSSFiles();
if (additionalCSSFiles != null) {
String defaultCSSPath = defaultCSSPath();
if (defaultCSSPath != null && defaultCSSPath.length() > 0 && !defaultCSSPath.endsWith("/")) {
defaultCSSPath += "/";
}
String frameworkName = _frameworkName();
for (String additionalCSSFile : additionalCSSFiles) {
ERXResponseRewriter.addStylesheetResourceInHead(response, context, frameworkName, defaultCSSPath + additionalCSSFile);
}
}
}
/**
* <div class="en">
* Injects per-component javascript dependencies into the head tag based on
* the definitions in useDefaultComponentJavascript(),
* defaultJavascriptPath(), primaryJavascriptFile(), and
* additionalJavascriptFiles().
* <p>
* If you return true for useDefaultComponentJavascript (and do not override
* primaryJavascriptFile), this component will inject a reference to
* defaultJavascriptPath() + /YourComponentName.js. For instance, if your
* component is named HeaderFooter, useDefaultComponentJavascript will
* automatically add a reference to defaultJavascriptPath() +
* /HeaderFooter.js for you. This allows you to very easily specify
* per-component Javascript files without upper-level components knowing
* about them. Currently _includeJavascriptResources does not try to do
* anything fancy in terms of recombinding Javascript files.
* <p>
* Override defaultJavascriptPath to provide the base path relative to
* WebServerResources that contains your Javascript files. If all of your
* Javascript is in WebServerResources/scripts, you would return "scripts"
* from defaultJavascriptPath().
* <p>
* If you do not want to use the component's name as the name of the
* Javascript file, you can optionally override primaryJavascriptFile() to
* return the name of a specific Javascript file, as well as
* additionalJavascriptFiles() to return an NSArray of Javascript files. All
* of these file names will be prepended with the defaultJavascriptPath if
* it is set.
* </div>
*
* <div class="ja">
* useDefaultComponentJavascript(), defaultJavascriptPath(), primaryJavascriptFile(), と additionalJavascriptFiles()
* で定義されているコンポーネントに依存した javascript をヘッダー内に挿入します。
* <p>
* useDefaultComponentJavascript で true を戻す場合 (primaryJavascriptFileをオーバライドしないで)
* このコンポーネントは defaultJavascriptPath() + /YourComponentName.js をヘッダーに挿入します。
* 例えば、コンポーネントの名前が HeaderFooter とし、useDefaultComponentJavascript は自動的に
* defaultJavascriptPath() + /HeaderFooter.js へのレファレンスを作成します。
* この機能を使うことで、簡単にコンポーネントに属している Javascript ファイルを作成でき、上位のコンポーネントを
* 意識する必要がありません。
* 現在では _includeJavascriptResources は Javascript ファイルの結合などを行いません。
* <p>
* defaultJavascriptPath をオーバライドすること、Javascript ファイルを含む WebServerResources への元パスを提供します。
* すべての Javascript が WebServerResources/scripts 内にある場合、defaultJavascriptPath() として "scripts" を戻します。
* <p>
* Javascript ファイルとしてコンポーネント名を使用したく無い場合、primaryJavascriptFile() をオーバライドすることで、
* ある Javascript ファイル名を戻します。それとも、additionalJavascriptFiles() で Javascript ファイルの NSArray を戻します。
* すべてのファイル名は defaultJavascriptPath を先頭に追加されるのです。
* </div>
*
* @param response <div class="en">the response to write into</div>
* <div class="ja">書き込みするリスポンス</div>
* @param context <div class="en">the current context</div>
* <div class="ja">カレント・コンテクスト</div>
*/
protected void _includeJavascriptResources(WOResponse response, WOContext context) {
String primaryJavascriptFile = primaryJavascriptFile();
if (primaryJavascriptFile == null && useDefaultComponentJavascript()) {
String componentName = componentName();
primaryJavascriptFile = componentName + ".js";
}
if (primaryJavascriptFile != null) {
String defaultJavascriptPath = defaultJavascriptPath();
if (defaultJavascriptPath != null && defaultJavascriptPath.length() > 0 && !defaultJavascriptPath.endsWith("/")) {
defaultJavascriptPath += "/";
}
String frameworkName = _frameworkName();
ERXResponseRewriter.addScriptResourceInHead(response, context, frameworkName, defaultJavascriptPath + primaryJavascriptFile);
}
NSArray<String> additionalJavascriptFiles = additionalJavascriptFiles();
if (additionalJavascriptFiles != null) {
String defaultJavascriptPath = defaultJavascriptPath();
if (defaultJavascriptPath != null && defaultJavascriptPath.length() > 0 && !defaultJavascriptPath.endsWith("/")) {
defaultJavascriptPath += "/";
}
String frameworkName = _frameworkName();
for (String additionalJavascriptFile : additionalJavascriptFiles) {
ERXResponseRewriter.addScriptResourceInHead(response, context, frameworkName, defaultJavascriptPath + additionalJavascriptFile);
}
}
}
/**
* <div class="en">
* Returns the name of this component's framework or "app" if
* frameworkName() returns null.
* </div>
*
* <div class="ja">
* このコンポーネントのフレームワークを戻します。
* frameworkName() が null の場合には "app" が戻ります。
* </div>
*
* @return <div class="en">the name of this component's framework</div>
* <div class="ja">このコンポーネントのフレームワーク</div>
*/
protected String _frameworkName() {
String frameworkName = super.frameworkName();
if (frameworkName == null) {
frameworkName = "app";
}
return frameworkName;
}
/**
* <div class="en">
* Returns true if this component provides a default CSS file that has the
* same name as the component itself.
* </div>
*
* <div class="ja">
* コンポーネントと同じ名前を持つデフォルト CSS ファイルがある場合には true が戻ります。
* </div>
*
* @return <div class="en">true if this component provides a default-named CSS</div>
* <div class="ja">デフォルト CSS ファイルがある場合には true</div>
*/
protected boolean useDefaultComponentCSS() {
return false;
}
/**
* <div class="en">
* Returns the default path prefix for CSS, which will be prepended to all
* required CSS files for this component. The default is "".
* </div>
*
* <div class="ja">
* CSS へのデフォルトパスの先頭を戻します。このコンポーネントの全 CSS ファイルに適用します。
* デフォルトは ""
* </div>
*
* @return <div class="en">the default CSS path.</div>
* <div class="ja">デフォルト CSS パス</div>
*/
protected String defaultCSSPath() {
return "";
}
/**
* <div class="en">
* Returns the primary CSS file for this component, or null if there isn't
* one. This path will be prepended with defaultCSSPath().
* </div>
*
* <div class="ja">
* このコンポーネントのメイン CSS ファイルを戻します。無ければ、 null が戻ります。
* このパスは defaultCSSPath() と合成されます。
* </div>
*
* @return <div class="en">the primary CSS file for this component</div>
* <div class="ja">このコンポーネントのメイン CSS ファイル</div>
*/
protected String primaryCSSFile() {
return null;
}
/**
* <div class="en">
* Returns an array of additional CSS files for this component, or null (or
* empty array) if there aren't any. Each path will be prepended with
* defaultCSSPath().
* </div>
*
* <div class="ja">
* このコンポーネントに必要なオプション CSS ファイルの配列。無ければ、null (empty array)
* 各自のパスは defaultCSSPath() と合成されます。
* </div>
*
* @return <div class="en">an array of additional CSS files for this component.</div>
* <div class="ja">このコンポーネントに必要なオプション CSS ファイルの配列</div>
*/
protected NSArray<String> additionalCSSFiles() {
return null;
}
/**
* <div class="en">
* Returns true if this component provides a default Javascript file that
* has the same name as the component itself.
* </div>
*
* <div class="ja">
* コンポーネントと同じ名前を持つデフォルト Javascript ファイルがある場合には true が戻ります。
* </div>
*
* @return <div class="en">true if this component provides a default-named Javascript</div>
* <div class="ja">デフォルト Javascript ファイルがある場合には true</div>
*/
protected boolean useDefaultComponentJavascript() {
return false;
}
/**
* <div class="en">
* Returns the default path prefix for Javascript, which will be prepended
* to all required Javascript files for this component. The default is "".
* </div>
*
* <div class="ja">
* Javascript へのデフォルトパスの先頭を戻します。このコンポーネントの全 Javascript ファイルに適用します。
* デフォルトは ""
* </div>
*
* @return <div class="en">the default Javascript path.</div>
* <div class="ja">デフォルト Javascript パス</div>
*/
protected String defaultJavascriptPath() {
return "";
}
/**
* <div class="en">
* Returns the primary Javascript file for this component, or null if there
* isn't one. This path will be prepended with defaultJavascriptPath().
* </div>
*
* <div class="ja">
* このコンポーネントのメイン Javascript ファイルを戻します。無ければ、 null が戻ります。
* このパスは defaultJavascriptPath() と合成されます。
* </div>
*
* @return <div class="en">the primary Javascript file for this component</div>
* <div class="ja">このコンポーネントのメイン Javascript ファイル</div>
*/
protected String primaryJavascriptFile() {
return null;
}
/**
* <div class="en">
* Returns an array of additional Javascript files for this component, or
* null (or empty array) if there aren't any. Each path will be prepended
* with defaultJavascriptPath().
* </div>
*
* <div class="ja">
* このコンポーネントに必要なオプション Javascript ファイルの配列。無ければ、null (empty array)
* 各自のパスは defaultJavascriptPath() と合成されます。
* </div>
*
* @return <div class="en">an array of additional Javascript files for this component.</div>
* <div class="ja">このコンポーネントに必要なオプション Javascript ファイルの配列</div>
*/
protected NSArray<String> additionalJavascriptFiles() {
return null;
}
/**
* <div class="en">
* Override and return true for any components to which you would like to
* allow page level access.
* </div>
*
* <div class="ja">
* ページ・レベル・アクセス
* true はページへのアクセスが可能です
* </div>
*
* @return <div class="en">true by default</div>
* <div class="ja">デフォルトは true</div>
*/
protected boolean isPageAccessAllowed() {
return true;
}
/**
* <div class="en">
* Override to provide custom security checks. It is not necessary to call
* super on this method.
* </div>
*
* <div class="ja">
* カスタム・セキュリティ・チェックを行う場合にはオーバライドするといいのです。
* スーパーを呼ぶ必要ありません。
* </div>
*
* @throws SecurityException <div class="en">if the security check fails</div>
* <div class="ja">セキュリティ・チェックが失敗した場合</div>
*/
protected void checkAccess() throws SecurityException {
}
/**
* <div class="en">
* Override to hook into appendToResponse after security checks but before
* the super.appendToResponse. It is not necessary to call super on this
* method.
* </div>
*
* <div class="ja">
* セキュリティ・チェックの後で、super.appendToResponse を呼ぶ前の横取り
* このフェーズに何がする必要がある場合は、オーバライドするといいのです
* この中ではスーパーを呼ぶ必要ありません。
* </div>
*
* @param response <div class="en">the current response</div>
* <div class="ja">カレント・リスポンス</div>
* @param context <div class="en">the current context</div>
* <div class="ja">カレント・コンテクスト</div>
*/
protected void preAppendToResponse(WOResponse response, WOContext context) {
}
/**
* <div class="en">
* Override to hook into appendToResponse after super.appendToResponse. It
* is not necessary to call super on this method.
* </div>
*
* <div class="ja">
* super.appendToResponse を直後の横取り
* このフェーズに何がする必要がある場合は、オーバライドするといいのです
* この中ではスーパーを呼ぶ必要ありません。
* </div>
*
* @param response <div class="en">the current response</div>
* <div class="ja">カレント・リスポンス</div>
* @param context <div class="en">the current context</div>
* <div class="ja">カレント・コンテクスト</div>
*/
protected void postAppendToResponse(WOResponse response, WOContext context) {
}
}