/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * See LICENSE.txt included in this distribution for the specific * language governing permissions and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. */ package org.opensolaris.opengrok.web; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * A list-like container for javascripts in the page. * * @author Krystof Tulinger */ public class Scripts implements Iterable<Scripts.Script> { /** * A script wrapper. */ static abstract public class Script { /** * Represents the script information, either * <ul> * <li>script HTML src attribute for remote scripts</li> * <li>inline javascript code for inline scripts</li> * </ul> */ protected String scriptData; protected int priority; public Script(String scriptData, int priority) { this.scriptData = scriptData; this.priority = priority; } abstract public String toHtml(); public String getScriptData() { return scriptData; } public int getPriority() { return priority; } } /** * Script implementing the toHtml() method as an external script resource. */ static public class FileScript extends Script { public FileScript(String script, int priority) { super(script, priority); } @Override public String toHtml() { StringBuilder builder = new StringBuilder(); builder.append("\t<script type=\"text/javascript\" src=\""); builder.append(this.getScriptData()); builder.append("\" data-priority=\""); builder.append(this.getPriority()); builder.append("\"></script>\n"); return builder.toString(); } } /** * Script implementing the toHtml() method as an inline script resource. */ static public class InlineScript extends Script { public InlineScript(String script, int priority) { super(script, priority); } @Override public String toHtml() { StringBuilder builder = new StringBuilder(); builder.append("\t<script type=\"text/javascript\" data-priority=\""); builder.append(this.getPriority()); builder.append("\">/* <![CDATA[ */"); builder.append(this.getScriptData()); builder.append("\n/* ]]> */</script>\n"); return builder.toString(); } } protected static final Map<String, Script> SCRIPTS = new TreeMap<>(); /** * Aliases for the page scripts. The path in the FileScript is relatively to * the request's context path. * * @see HttpServletRequest#getContextPath() */ static { SCRIPTS.put("jquery", new FileScript("js/jquery-3.2.0.min.js", 10)); SCRIPTS.put("jquery-ui", new FileScript("js/jquery-ui-1.12.0-custom.min.js", 11)); SCRIPTS.put("jquery-tablesorter", new FileScript("js/jquery-tablesorter-2.26.6.min.js", 12)); SCRIPTS.put("tablesorter-parsers", new FileScript("js/tablesorter-parsers-0.0.1.js", 13)); SCRIPTS.put("searchable-option-list", new FileScript("js/searchable-option-list-2.0.3.min.js", 14)); SCRIPTS.put("utils", new FileScript("js/utils-0.0.9.js", 15)); SCRIPTS.put("repos", new FileScript("js/repos-0.0.1.js", 20)); SCRIPTS.put("diff", new FileScript("js/diff-0.0.1.js", 20)); } /** * Scripts which will be written to the page. We assume that the length * could be the same as for {@link #SCRIPTS}. */ private final List<Script> outputScripts = new ArrayList<>(SCRIPTS.size()); /** * Convert the page scripts into HTML. * * @return the HTML */ public String toHtml() { StringBuilder builder = new StringBuilder(); for (Script entry : this) { builder.append(entry.toHtml()); } return builder.toString(); } /** * Return the HTML representation of the page scripts. * * @return the HTML * * @see #toHtml() */ @Override public String toString() { return toHtml(); } /** * Return the size of the page scripts. * * @return the size * * @see List#size() */ public int size() { return outputScripts.size(); } /** * Check if there is any script for this page. * * @return true if there is not; false otherwise * * @see List#isEmpty() */ public boolean isEmpty() { return outputScripts.isEmpty(); } /** * Iterator over the page scripts. * * @return the iterator * @see List#iterator() */ @Override public Iterator<Script> iterator() { return outputScripts.iterator(); } /** * Add a script which is identified by the name. * * @param contextPath given context path for the used URL * @param scriptName name of the script * @return true if script was added; false otherwise */ public boolean addScript(String contextPath, String scriptName) { contextPath = contextPath == null || contextPath.isEmpty() ? "" : contextPath + "/"; if (SCRIPTS.containsKey(scriptName)) { this.addScript( // put the context path end append the script path new FileScript(contextPath + SCRIPTS.get(scriptName).getScriptData(), SCRIPTS.get(scriptName).getPriority())); return true; } return false; } /** * Add a script to the page, taking the script priority into account. The * position is determined as the upper bound for the given priority. * * @param script the script */ public void addScript(Script script) { int index = Collections.binarySearch(outputScripts, script, new Comparator<Script>() { @Override public int compare(Script a, Script b) { return a.getPriority() - b.getPriority(); } }); if (index < 0) { /** * Key is not found in the list the index<br> * equals to -(insertion index) - 1. */ this.outputScripts.add(Math.abs(index + 1), script); } else { /** * Key found in the list, append it after the last element with the * same priority => insert it at the upper bound index. */ while (index < this.outputScripts.size() && this.outputScripts.get(index).getPriority() == script.getPriority()) { index++; } this.outputScripts.add(index, script); } } /** * Get the page script by the index * * @param index index of the script * @return the script * * @see List#get(int) */ public Script get(int index) { return outputScripts.get(index); } }