/** * 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(); } }