/**
* Copyright 2014 55 Minutes (http://www.55minutes.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fiftyfive.wicket.js;
import fiftyfive.wicket.js.locator.DependencyCollection;
import fiftyfive.wicket.js.locator.JavaScriptDependencyLocator;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.util.lang.Args;
/**
* Represents a JavaScript file, or group of files, that will be injected into
* the <head>. This is the mechanism for programmatically declaring
* JavaScript dependencies within Java code.
* <p>
* There are three ways to use this class:
* <ul>
* <li>Inject a JS file of the same name as your component class, using
* {@link #JavaScriptDependency(Class)}.</li>
* <li>Inject an arbitrary JS classpath resource, using
* {@link #JavaScriptDependency(Class,String)}.</li>
* <li>Inject one of several commonly-used JavaScript libraries, like
* jQuery, using {@link #JavaScriptDependency(String)}.</li>
* </ul>
* <p>
* In all cases, the JavaScript files that you specify will be scanned for
* dependencies. Refer to the <a href="package-summary.html#dependency-resolution">dependency
* resolution guide</a> for more information.
* <p>
* For example, let's say you have {@code MyPanel} which contains custom
* JavaScript in an accompanying {@code MyPanel.js} file. Your JavaScript
* in turn depends on jQuery UI. In {@code MyPanel.js} you would add this
* line:
* <pre class="example">
* //= require jquery-ui</pre>
* <p>
* This informs fiftyfive-wicket-js of the dependency. Then in your Java code,
* you just need to add {@code MyPanel.js} like this:
* <pre class="example">
* public MyPanel(String id)
* {
* super(id);
* add(new JavaScriptDependency(MyPanel.class));
* }</pre>
* <p>
* At runtime, fiftyfive-wicket-js will find {@code MyPanel.js}, scan it
* for dependencies, and notice that jQuery UI is needed. It is smart enough
* to realize jQuery is needed as well. When the page renders, jQuery,
* jQuery UI, and {@code MyPanel.js} will all automatically be included in
* the <head>, and in the correct order. Futhermore, the necessary
* jQuery UI CSS will be included as well (the "redmond" theme, by default).
* <p>
* Internally this class delegates to {@link JavaScriptDependencyLocator}
* to find the actual files and their dependencies. The behavior of this
* dependency discovery can be controlled using the
* {@link JavaScriptDependencySettings}.
*
* @since 2.0
*/
public class JavaScriptDependency extends AbstractJavaScriptContribution
{
/**
* Dependency representing jQuery UI. Automatically injects both jQuery and
* jQuery UI libraries.
*/
public static final JavaScriptDependency JQUERY_UI =
new JavaScriptDependency("jquery-ui");
/**
* Dependency representing jQuery.
*/
public static final JavaScriptDependency JQUERY =
new JavaScriptDependency("jquery");
private Class<?> clazz;
private String fileName;
private String libraryName;
/**
* Creates a JavaScriptDependency for a JavaScript file that accompanies
* a class of the same name. For example, a dependency created for
* {@code MyPanel.class} will look for a corresponding file named
* {@code MyPanel.js} in the same classpath location. Simliar to how Wicket
* locates HTML files, if {@code MyPanel.js} cannot be found, the
* superclass of that panel is searched, and so on.
*/
public JavaScriptDependency(Class<?> cls)
{
super();
Args.notNull(cls, "cls");
this.clazz = cls;
}
/**
* Creates a JavaScriptDependency for a JavaScript library that resides
* in the library search path. The name should not include the .js
* extension. For example:
* <pre class="example">
* add(new JavaScriptDependency("jquery-ui"));</pre>
*
* @see JavaScriptDependencySettings#addLibraryPath
*/
public JavaScriptDependency(String libraryName)
{
super();
Args.notNull(libraryName, "libraryName");
this.libraryName = libraryName;
}
/**
* Creates a JavaScriptDependency for a JavaScript file in the classpath,
* The file name should not include the .js extension.
* For example:
* <pre class="example">
* add(new JavaScriptDependency(MyPanel.class, "jquery.ui.myplugin"));</pre>
*/
public JavaScriptDependency(Class<?> cls, String fileName)
{
super();
Args.notNull(cls, "cls");
Args.notNull(fileName, "fileName");
this.clazz = cls;
this.fileName = fileName;
}
/**
* Injects the JavaScript files into the <head>, using
* {@link JavaScriptDependencyLocator} to first find the files.
*/
@Override
public void renderHead(Component comp, IHeaderResponse response)
{
JavaScriptDependencyLocator locator = settings().getLocator();
DependencyCollection scripts = new DependencyCollection();
if(this.libraryName != null)
{
locator.findLibraryScripts(this.libraryName, scripts);
}
else if(this.fileName != null)
{
locator.findResourceScripts(this.clazz, this.fileName, scripts);
}
else
{
locator.findAssociatedScripts(this.clazz, scripts);
}
renderDependencies(response, scripts, null);
}
/**
* Returns the settings to use. This method exists only for overriding
* during unit tests.
*/
JavaScriptDependencySettings settings()
{
return JavaScriptDependencySettings.get();
}
}