001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.console.freemarker; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.*; 022 023/** 024 * One named toolkit pack: ordered CSS and JS asset paths, the packs it depends on, its {@link Kind}, and the 025 * resolver that turns each path into a URL. 026 * 027 * <p> 028 * Register one through {@code ConsoleFreemarkerMixin.Builder.registerToolkitPack(ToolkitPack)}. A pack registered 029 * under an existing name replaces that pack completely, including its {@code dependsOn}. 030 * 031 * <h5 class='section'>Example:</h5> 032 * <p class='bjava'> 033 * ToolkitPack.<jsm>create</jsm>(<js>"datatables-export"</js>) 034 * .js(<jv>jszip</jv>, <jv>pdfmake</jv>, <jv>vfsFonts</jv>) 035 * .dependsOn(<js>"datatables-buttons"</js>) 036 * .kind(ToolkitPack.Kind.<jsf>VENDOR</jsf>) 037 * .resolver(<jv>myResolver</jv>) 038 * .build(); 039 * </p> 040 * 041 * @since 10.0.0 042 */ 043public final class ToolkitPack { 044 045 /** 046 * Where a pack's assets are emitted on the page. 047 * 048 * <p> 049 * {@link #VENDOR} CSS goes before the page {@code css=} and {@link #VENDOR} JS before every {@link #RUNTIME} script. 050 * {@link #RUNTIME} assets keep the position the {@code "views"} runtime always had. A {@link #VENDOR} pack can't 051 * depend on a {@link #RUNTIME} pack. 052 */ 053 public enum Kind { 054 /** A library or glue that runtime packs build on. */ 055 VENDOR, 056 /** A first-party UI runtime ({@code "views"}, {@code "calendar"}). */ 057 RUNTIME 058 } 059 060 private final String name; 061 private final List<String> cssPaths; 062 private final List<String> jsPaths; 063 private final List<String> dependsOn; 064 private final Kind kind; 065 private final ToolkitPackRegistry.AssetUrlResolver resolver; 066 067 private ToolkitPack(Builder b) { 068 name = b.name; 069 cssPaths = List.copyOf(b.cssPaths); 070 jsPaths = List.copyOf(b.jsPaths); 071 dependsOn = List.copyOf(b.dependsOn); 072 kind = b.kind; 073 resolver = b.resolver; 074 } 075 076 /** 077 * Starts a pack. 078 * 079 * @param name The pack name. Must not be blank. 080 * @return A new builder. 081 */ 082 public static Builder create(String name) { 083 if (ib(name)) 084 throw iaex("Toolkit pack name must not be blank."); 085 return new Builder(name.trim()); 086 } 087 088 /** 089 * Returns the pack name. 090 * 091 * @return The pack name. 092 */ 093 public String name() { return name; } 094 095 /** 096 * Returns the ordered CSS asset paths. 097 * 098 * @return The ordered CSS asset paths. 099 */ 100 public List<String> cssPaths() { return cssPaths; } 101 102 /** 103 * Returns the ordered JS asset paths. 104 * 105 * @return The ordered JS asset paths. 106 */ 107 public List<String> jsPaths() { return jsPaths; } 108 109 /** 110 * Returns the names of the packs this one loads after, in order. 111 * 112 * @return The names of the packs this one loads after, in order. 113 */ 114 public List<String> dependsOn() { return dependsOn; } 115 116 /** 117 * Returns the pack kind. 118 * 119 * @return The pack kind. 120 */ 121 public Kind kind() { return kind; } 122 123 /** 124 * Returns the asset-URL resolver. 125 * 126 * @return The asset-URL resolver. 127 */ 128 public ToolkitPackRegistry.AssetUrlResolver resolver() { return resolver; } 129 130 /** Builder for {@link ToolkitPack}. */ 131 public static final class Builder { 132 133 final String name; 134 final List<String> cssPaths = new ArrayList<>(); 135 final List<String> jsPaths = new ArrayList<>(); 136 final List<String> dependsOn = new ArrayList<>(); 137 Kind kind; 138 ToolkitPackRegistry.AssetUrlResolver resolver = ToolkitPackRegistry.VIEWS_RESOLVER; 139 140 Builder(String name) { 141 this.name = name; 142 } 143 144 /** 145 * Appends CSS asset paths. 146 * 147 * @param paths The paths. 148 * @return This object. 149 */ 150 public Builder css(String...paths) { return css(Arrays.asList(paths)); } 151 152 /** 153 * Appends CSS asset paths. 154 * 155 * @param paths The paths. 156 * @return This object. 157 */ 158 public Builder css(List<String> paths) { cssPaths.addAll(paths); return this; } 159 160 /** 161 * Appends JS asset paths. 162 * 163 * @param paths The paths. 164 * @return This object. 165 */ 166 public Builder js(String...paths) { return js(Arrays.asList(paths)); } 167 168 /** 169 * Appends JS asset paths. 170 * 171 * @param paths The paths. 172 * @return This object. 173 */ 174 public Builder js(List<String> paths) { jsPaths.addAll(paths); return this; } 175 176 /** 177 * Appends the names of packs this one depends on. 178 * 179 * @param names The pack names. 180 * @return This object. 181 */ 182 public Builder dependsOn(String...names) { dependsOn.addAll(Arrays.asList(names)); return this; } 183 184 /** 185 * Sets the pack kind. Required. 186 * 187 * @param value The kind. 188 * @return This object. 189 */ 190 public Builder kind(Kind value) { kind = rnn(value); return this; } 191 192 /** 193 * Sets the asset-URL resolver. Defaults to {@link ToolkitPackRegistry#VIEWS_RESOLVER}. 194 * 195 * @param value The resolver. 196 * @return This object. 197 */ 198 public Builder resolver(ToolkitPackRegistry.AssetUrlResolver value) { resolver = rnn(value); return this; } 199 200 /** 201 * Builds the pack. 202 * 203 * @return A new pack. 204 * @throws IllegalArgumentException If no kind was set. 205 */ 206 public ToolkitPack build() { 207 if (n(kind)) 208 throw iaex("Toolkit pack '%s' needs kind(VENDOR) or kind(RUNTIME).", name); 209 return new ToolkitPack(this); 210 } 211 } 212}