using afIoc::Injectusing afIocConfig::Configusing afBedSheet** Defines a '<link>' tag to be injected into the bottom of your head. Created via `HtmlInjector`.** ** If defining a stylesheet, note that any 'Content-Security-Policy' response header will be updated to ensure it can be loaded.** ** @see `https://developer.mozilla.org/en/docs/Web/HTML/Element/link` class LinkTagBuilder { @Inject private HttpResponse httpRes @Inject private ClientAssetCache clientAssets @Inject { optional=true}// nullable for testingprivate BedSheetServer? bedServer @Inject { optional=true}// nullable for testingprivate FileHandler? fileHandlerprivate HtmlElement elementprivate HtmlConditional ieConditional @Config private Bool updateCspHeaderinternalnew make(|This|in){ in(this)this.element = HtmlElement("link") ieConditional = HtmlConditional(){ element, }}** Sets the 'href' attribute to an external URL.** Returns 'this'. LinkTagBuilder fromExternalUrl(Uri externalUrl){if(externalUrl.host == null)throw ArgErr(ErrMsgs.externalUrlsNeedHost(externalUrl)) element["href"] = externalUrl.encodeif(updateCsp){ host := (externalUrl + `/`).encodeif(host.endsWith("/")) host = host[0..<-1]if(host.startsWith("//")) host = host[2..-1] csp := httpRes.headers.contentSecurityPolicyif(addCsp(csp, host)) httpRes.headers.contentSecurityPolicy = csp cspro := httpRes.headers.contentSecurityPolicyReportOnlyif(addCsp(cspro, host)) httpRes.headers.contentSecurityPolicyReportOnly = cspro}returnthis}** Sets the 'href' attribute to a local URL. ** The URL **must** be mapped by BedSheet's 'ClientAsset' cache service.** The URL may be rebuilt to take advantage of any asset caching strategies, such as [Cold Feet]`http://eggbox.fantomfactory.org/pods/afColdFeet`.** Returns 'this'. LinkTagBuilder fromLocalUrl(Uri localUrl){// ClientAssets adds ColdFeet digests, BedServer does not clientUrl := clientAssets.getAndUpdateOrProduce(localUrl)?.clientUrl ?: bedServer.toClientUrl(localUrl) element["href"] = clientUrl.encodeif(updateCsp){ csp := httpRes.headers.contentSecurityPolicyif(addCsp(csp, "'self'")) httpRes.headers.contentSecurityPolicy = csp cspro := httpRes.headers.contentSecurityPolicyReportOnlyif(addCsp(cspro, "'self'")) httpRes.headers.contentSecurityPolicyReportOnly = cspro}returnthis}** Creates a 'href' URL attribute from the given file. ** The file **must** exist on the file system and be mapped by BedSheet's 'FileHandler' service.** The URL is built to take advantage of any asset caching strategies, such as [Cold Feet]`http://eggbox.fantomfactory.org/pods/afColdFeet`.** Returns 'this'. LinkTagBuilder fromServerFile(File serverFile){ fileAsset := fileHandler.fromServerFile(serverFile, true)// this add any ColdFeet digests element["href"] = fileAsset.clientUrl.encodeif(updateCsp){ csp := httpRes.headers.contentSecurityPolicyif(addCsp(csp, "'self'")) httpRes.headers.contentSecurityPolicy = csp cspro := httpRes.headers.contentSecurityPolicyReportOnlyif(addCsp(cspro, "'self'")) httpRes.headers.contentSecurityPolicyReportOnly = cspro}returnthis}** Sets the 'type' attribute.** Returns 'this'. LinkTagBuilder withType(MimeType type){ element["type"] = type.toStrreturnthis}** Sets the 'media' attribute.** Returns 'this'. LinkTagBuilder withMedia(Str media){ element["media"] = mediareturnthis}** Wraps the '<link>' element in a [conditional IE comment]`http://www.quirksmode.org/css/condcom.html`. ** The given 'condition' should be everything in the square brackets. Example:** ** ifIe("if gt IE 6")** ** would render:** ** <!--[if gt IE 6]>** <link src="..." >** <![endif]--> LinkTagBuilder ifIe(Str condition){ ieConditional.condition = condition returnthis}** Sets the 'rel' attribute.** Returns 'this'. LinkTagBuilder withRel(Str rel){ element["rel"] = relreturnthis}** Sets the 'title' attribute.** Returns 'this'. LinkTagBuilder withTitle(Str title){ element["title"] = titlereturnthis}** Sets an arbitrary attribute on the '<link>' element. LinkTagBuilder setAttr(Str name, Str value){ element[name] = valuereturnthis}** Returns an attribute value on the '<link>' element. Str? getAttr(Str name){ element[name]} @NoDoc // looks like it could be useful! HtmlNode htmlNode(){ ieConditional}private Bool updateCsp(){if(!updateCspHeader)returnfalse type := MimeType(element["type"] ?: "", false)?.noParams?.toStr rel := element["rel"]return type == "text/css" || rel == "stylesheet"}privatestatic Bool addCsp([Str:Str]? csp, Str newDir){if(csp == null)returnfalse directive := csp["style-src"]?.trimToNull ?: csp["default-src"]?.trimToNullif(directive == null)returnfalse directives := directive.splitif(directives.contains(newDir))// e.g. 'self'returnfalse csp["style-src"] = directive + " " + newDirreturntrue}}