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.wicket.markup.head; 018 019import java.util.Objects; 020 021import org.apache.wicket.core.util.string.JavaScriptUtils; 022import org.apache.wicket.markup.html.CrossOrigin; 023import org.apache.wicket.request.Response; 024import org.apache.wicket.util.lang.Args; 025import org.apache.wicket.util.value.AttributeMap; 026 027/** 028 * A {@link org.apache.wicket.markup.head.HeaderItem} that renders a JavaScript reference. 029 */ 030public abstract class AbstractJavaScriptReferenceHeaderItem extends JavaScriptHeaderItem implements ISubresourceHeaderItem 031{ 032 private boolean async; 033 private boolean defer; 034 private String charset; 035 private CrossOrigin crossOrigin; 036 private String integrity; 037 private JavaScriptReferenceType type = JavaScriptReferenceType.TEXT_JAVASCRIPT; 038 039 /** 040 * @return if the script should be loaded and executed asynchronously 041 */ 042 public boolean isAsync() 043 { 044 return async; 045 } 046 047 public AbstractJavaScriptReferenceHeaderItem setAsync(boolean async) 048 { 049 this.async = async; 050 return this; 051 } 052 053 /** 054 * @return if the execution of a script should be deferred (delayed) until after the page has been loaded. 055 */ 056 public boolean isDefer() 057 { 058 return defer; 059 } 060 061 public AbstractJavaScriptReferenceHeaderItem setDefer(boolean defer) 062 { 063 this.defer = defer; 064 return this; 065 } 066 067 /** 068 * @return the optional value of the charset attribute of the script tag 069 */ 070 public String getCharset() 071 { 072 return charset; 073 } 074 075 public AbstractJavaScriptReferenceHeaderItem setCharset(String charset) 076 { 077 this.charset = charset; 078 return this; 079 } 080 081 @Override 082 public CrossOrigin getCrossOrigin() 083 { 084 return crossOrigin; 085 } 086 087 @Override 088 public AbstractJavaScriptReferenceHeaderItem setCrossOrigin(CrossOrigin crossOrigin) 089 { 090 this.crossOrigin = crossOrigin; 091 return this; 092 } 093 094 @Override 095 public String getIntegrity() 096 { 097 return integrity; 098 } 099 100 @Override 101 public AbstractJavaScriptReferenceHeaderItem setIntegrity(String integrity) 102 { 103 this.integrity = integrity; 104 return this; 105 } 106 107 public JavaScriptReferenceType getType() { 108 return type; 109 } 110 111 public AbstractJavaScriptReferenceHeaderItem setType(final JavaScriptReferenceType type) { 112 this.type = type; 113 return this; 114 } 115 116 protected final void internalRenderJavaScriptReference(Response response, String url) 117 { 118 Args.notEmpty(url, "url"); 119 final AttributeMap attributes = createAttributeMap(url); 120 JavaScriptUtils.writeScript(response, attributes); 121 } 122 123 final AttributeMap createAttributeMap(final String url) { 124 final AttributeMap attributes = new AttributeMap(); 125 final JavaScriptReferenceType type = getType(); 126 if (type != null) { 127 attributes.putAttribute(JavaScriptUtils.ATTR_TYPE, type.getType()); 128 } 129 attributes.putAttribute(JavaScriptUtils.ATTR_ID, getId()); 130 attributes.putAttribute(JavaScriptUtils.ATTR_SCRIPT_DEFER, defer); 131 // XXX this attribute is not necessary for modern browsers 132 attributes.putAttribute("charset", charset); 133 attributes.putAttribute(JavaScriptUtils.ATTR_SCRIPT_ASYNC, async); 134 attributes.putAttribute(JavaScriptUtils.ATTR_SCRIPT_SRC, url); 135 attributes.putAttribute(JavaScriptUtils.ATTR_CSP_NONCE, getNonce()); 136 attributes.putAttribute(JavaScriptUtils.ATTR_CROSS_ORIGIN, getCrossOrigin() == null ? null : getCrossOrigin().getRealName()); 137 attributes.putAttribute(JavaScriptUtils.ATTR_INTEGRITY, getIntegrity()); 138 return attributes; 139 } 140 141 @Override 142 public boolean equals(Object o) 143 { 144 if (this == o) 145 return true; 146 if (o == null || getClass() != o.getClass()) 147 return false; 148 if (!super.equals(o)) 149 return false; 150 AbstractJavaScriptReferenceHeaderItem that = (AbstractJavaScriptReferenceHeaderItem)o; 151 return async == that.async && 152 defer == that.defer && 153 Objects.equals(charset, that.charset) && 154 Objects.equals(type, that.type); 155 } 156 157 @Override 158 public int hashCode() 159 { 160 // Not using `Objects.hash` for performance reasons 161 int result = super.hashCode(); 162 result = 31 * result + (async ? 1 : 0); 163 result = 31 * result + (defer ? 1 : 0); 164 result = 31 * result + (charset != null ? charset.hashCode() : 0); 165 result = 31 * result + (type != null ? type.hashCode() : 0); 166 return result; 167 } 168}