I need to insert some headerdata before Style Definitions. To be more precise I want to insert my google tag manager script before my style sheets due to the loading order of my font-family.
At the moment I do it like this:
page.includeCSS {
file1 = fileadmin/templates/css/bootstrap.css
page.includeCSS.file1.media = all
file2 = fileadmin/templates/css/style.css
page.includeCSS.file2.media = all
file3 = fileadmin/templates/fontawesome/css/all.min.css
page.includeCSS.file3.media = all
}
page.headerData {
10 = TEXT
10.value (
<script data-cookieconsent="ignore">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXXXXX');</script>
)
}
According to the Typo3 Documentation the headerdata "By default, gets inserted after all the style definitions." I think that means, that it also can be inserted before. But I don't know how.
I also don't want to put the css in the headerdata because I cannot concatenate and compress them there.
If you want it at first position you could modify the <head> tag:
page.headTag (
<head>
<script data-cookieconsent="ignore">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXXXXX');</script>
)
A cleaner way would be to reorder the header elements with typoscript:
config {
pageRendererTemplateFile = EXT:site_config/Resources/Private/Templates/templateFile.html
}
and then copy the file you can find under typo3/sysext/core/Resources/Private/Templates/PageRenderer.html to that location and change the order of the markers.
(Yes, it is an old style marker template file)
Now you can reorder addditionalHeaders in front of any CSS or JS.
Related
I have various questions about the webfundamentals implementations, i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import, so im trying to do it all in a customElement component and i have encounter with many and many issues that i find really hard to debug, i will enlist them all.
Does i have to insert html template into the document to actually get it? cant i get its content from js only? and in case i have to, when i intent to replace a shadowHost content hows is it works, i mean i got the template (the link) inside the shadowRoot, my actuall problem is that when i do querySelector(link[rel="import"]).import.querySelector("template") its null after the .import function tag and when i insert that function into the document, it actually gets the template content, heres the doc.
Watching that screenshot i got 2 more questions
Should i use shadowHost.innerHTML = file.querySelector(link[rel="import"]).import.querySelector("template")
to use the tag and copy its content inside the shadowRoot element? i mean how can i implement that approach? im using Angular as first example, they use an HTML file (which im guessing its a template or slots tag) and then they add it into the component as parameters on the constructor, so how with HTMLTemplates and HTMLImport i can implement that behaviour, i have used the documented functions but it doesnt works in the final phase.
Should i keep <link rel="import"> inside the shadowRoot or inside the document.head? can i implement the template without the need of adding it into the document?
I have been trying for days to do a simple customElement with shadowDOM that works completly fine, the problem is when i try to add an external to make it more robust.
Any helps? suggestions? i can show some functions that i use on the components to have an idea.
class EgHeader extends HTMLElement {
constructor() {
super();
this.shadowHost = shadowHost.bind(this);
this.shadowStyle = shadowStyle.bind(this);
this.shadowTemplate = shadowTemplate.bind(this);
this.host = this.shadowHost();
}
connectedCallback() {
this.defaultProperties();
let importSelector = this.host.querySelector(`link[rel="import"]`);
console.log(importSelector);
// this.host.appendChild(importSelector.cloneNode(true));
this.host.innerHTML = importSelector.import.querySelector(
"template"
).content;
}
defaultProperties() {
this.getAttributeNames().forEach(key => {
console.log(key);
if (key === "css") {
return this.shadowStyle(this.getAttribute(key));
}
if (key === "template") {
return this.shadowTemplate(this.getAttribute(key));
}
});
}
}
customElements.define("eg-header", EgHeader);
function shadowHost() {
let root = this.attachShadow({
mode: "open"
});
return root;
}
function shadowStyle(stylesheet) {
let link = document.createElement("link");
link.rel = "stylesheet";
link.href = stylesheet + ".css";
this.host.appendChild(link.cloneNode(true));
return link;
}
function shadowTemplate(link) {
var template = document.createElement("link");
template.rel = "import";
template.id = `${link}-template`;
template.href = link + ".html";
document.head.appendChild(template);
this.host.appendChild(template);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="./Header.js"></script>
<script src="./index.js"></script>
</head>
<body>
<eg-header css="./Header" template="./Header">
</eg-header>
</body>
</html>
// Separated file called Header.html
<template>
<nav>This is X element</nav>
<script>
console.warn("Executed when the template is activated.");
</script>
</template>
i have read that a true web component must have shadowDOM for css encapsulation, customElements for the logic of the component which i really love, and HTML Temapltes and import
What you've read is quite outdated:
HTML Imports are deprecated so you should use another method to load templates.
Because of #1, HTML templates (aka <template> elements) are often replaced par template literals.
Templates literals can be define in Javascript. This way they can be defined in a classical Javascript file or in the ES6 module.
By the way, if you still want to use HTML Imports (not recommanded) , you'll need to use a polyfill.
<link rel="import"> should be put in the <head> element of the main document, not in the Shadow DOM.
If you want to use <template> you don't need to append it to the main document.
var template = document.createElement( 'template' )
template.innerHTML = `
<h1>Title</h1>
<div>Content</div>
`
...
this.shadowRoot.appendChild( template.content.clone( true ) )
I am trying to make a semi-resuseable widget but I am running into a problem. I am trying to encapsulate a some CSS code inside a shadow root so that it does not affect the rest of the webpage but this CSS is used across multiple widgets so I am trying to include a remote stylesheet. None of the examples I have found use a remote style sheet and I was wondering if this was possible.
EX:
<template id="templateContent">
<head>
<link rel="stylesheet" href="css/generalStyle1.css">
</head>
<body>
<div class="affectedByGeneralStyle1"></div>
</body>
</template>
script to include template:
<div id="host"></div>
<script>
var importedData = (html_import_element).import.getElementById("templateContent");
var shadow = document.querySelector('#host').createShadowRoot();
var clone = document.importNode(importedData.content, true);
shadow.appendChild(clone);
</script>
I came across the same problem recently. What I ended up doing was using:
<template id="templateContent">
<style> #import "css/generalStyle.css"; </style>
</template>
Additional info: This worked just fine except that now I'm having some cache issues as Chrome does not seem to reload those resources after a hard reload.
Let add to the answer . Now direct tag is supported in shadow dom.
You can directly use
<link rel="stylesheet" href="yourcss1.css">
<link href="yourcss2.css" rel="stylesheet" type="text/css">
Check they has been update by whatwg and W3C
Useful link for using css in shadow dom.
https://w3c.github.io/webcomponents/spec/shadow/#inertness-of-html-elements-in-a-shadow-tree https://github.com/whatwg/html/commit/43c57866c2bbc20dc0deb15a721a28cbaad2140c
https://github.com/w3c/webcomponents/issues/628
Direct css link can be use in shadow dom
Thanks.
I added the stylesheet's link element directly to the shadow root this way:
let link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'whatever.css');
this.shadowRoot.appendChild(link);
It seems to work fine. (I called this from the constructor of the component.)
actually polymer has an internal utility to load css links, i have implemented a javascript function that is using polymer internal css processor,so if you want to add css links at runtime you can use it:
Polymer('my-element', {
ready: function () {
this.importCss("path/myfile.css");
},
importCss: function (path) {
var $shadow = $(this.shadowRoot);
var $head = $("<div></div>");
var $link = $("<link rel='stylesheet' type='text/css'>");
$link.attr("href", path);
$head.append($link);
var head = $head[0];
this.copySheetAttributes = Polymer.api.declaration.styles.copySheetAttributes;
Polymer.api.declaration.styles.convertSheetsToStyles.call(this, head);
var styles = Polymer.api.declaration.styles.findLoadableStyles(head);
if (styles.length) {
var templateUrl = this.baseURI;
Polymer.styleResolver.loadStyles(styles, templateUrl, function () {
var $style = $shadow.find("style");
if ($style.length > 0){
$shadow.find("style").append($head.find("style").html());
}else{
$shadow.append($head.html());
}
});
}
}
});
Note: this code needs jquery to run
Google Closure Library editor: demo, documentation.
The editable area is an iframe. How can I set the default font of the editable area? Now it is the default font of the browser. I prefer not to put a font tag around the content in the editable area**. That way, I can change the font of my website in the future, without the need to modify every HTML-content written in the editor.
** What I mean by that is something like this:
<font size="2" face="georgia, serif"><b>content</b></font>
I would prefer just this:
<b>content</b>
... and then style the editable area of the editor with the georgia font using CSS. That way, the HTML-content (produced by the editor) in my database wouldn't contain a hard-coded font, so I could change the font in the future.
Edit: maybe I should use a SeamlessField instead of a Field for the editable area?
Once you call makeEditable() on the goog.editor.Field, which creates the iFrame you referenced, the Field fires an event of type goog.editor.Field.EventType.LOAD. If you listen to that event, you can pull out the iFrame and toss in a link element to a CSS stylesheet so you can easily modify the content in your editor.
Here's the equivalent of one of my listeners that should get you on the right track. (I didn't check if the goog.editor.Field was the target of the event, but I assume it is).
some.namespace.Page.prototype.onEditorLoad_ = function(event) {
var editor = /** #type {goog.editor.Field} */ (event.target);
var iFrame = editor.getEditableIframe();
if (iFrame) {
var fieldDomHelper = editor.getEditableDomHelper();
var documentNode =
fieldDomHelper.getFrameContentDocument(iFrame).documentElement;
var head = documentNode.getElementsByTagName(goog.dom.TagName.HEAD)[0];
if (!head) {
head = fieldDomHelper.createDom(goog.dom.TagName.HEAD);
goog.dom.insertChildAt(documentNode, head, 0);
}
fieldDomHelper.appendChild(
head,
fieldDomHelper.createDom(
goog.dom.TagName.LINK,
{ 'href': '/css/myCSS.css', 'rel': 'stylesheet', 'type': 'text/css' }
)
);
}
}
Finally, in that CSS file, you can add whatever styling you want. Such as your font change.
I've just joined a project where we are using sap netweaver to generate the website.
Until now people have been working on their DCP individually and therefore I now have 20 DCP to link together and style.
At the root, each DCP is an IView/IFrame.
We currently have 20 css files that makes it hard to maintain and quickly change so I'm looking to use scss to generate 1 css file to make everything work.
That part works fine, however I hit a problem, since each IFrame renders itself, each one loads a css file so I get 20 calls to the my new css file.
Is there a way to share the css file between the parent view and the IFrame, or at least set it so that the css file is downloaded once and the other 19 just use the cached version?
Cheers
Jason
<script type="text/javascript">
$(document).ready(function() {
//pulling all <style></style> css of parent document
if (parent) {
var oHead = document.getElementsByTagName("head")[0];
var arrStyleSheets = parent.document.getElementsByTagName("style");
for (var i = 0; i < arrStyleSheets.length; i++)
oHead.appendChild(arrStyleSheets[i].cloneNode(true));
}
//pulling all external style css(<link href="css.css">) of parent document
$("link[rel=stylesheet]",parent.document).each(function(){
var cssLink = document.createElement("link")
cssLink.href = "http://"+parent.document.domain+$(this).attr("href");
cssLink .rel = "stylesheet";
cssLink .type = "text/css";
document.body.appendChild(cssLink);
});
});
</script>
It will able to inherit the css which is defined in the external style sheet as well as css defined in the tag of parent document.
How to overwrite some styles on a specified site?
I would like to do it the css-file way.
Still no answer below works in my case..
Depending on the amount of CSS to apply, you could also consider to just add the page ID as a class on the <body>, e.g. <body class="uid-456">:
page.bodyTag >
page.bodyTagCObject = TEXT
page.bodyTagCObject {
field = uid
wrap = <body class="uid-|">
}
Then, in your CSS:
.uid-456 myElement {
myCustomStyle... /* Applies to page ID = 456 only. */
}
UPDATE
Tested with Templavoilà. The following worked (From the Setup field of the main template):
page = PAGE
page {
typeNum = 0
10 = USER
10.userFunc = tx_templavoila_pi1->main_page
bodyTag >
bodyTagCObject = TEXT
bodyTagCObject {
field = uid
wrap = <body class="uid-|">
}
...
}
Use TypoScript to add CSS rules (using page.cssInline) or additional CSS files (page.includeCSS). See TSref, chapter for PAGE.
I recommend using Typoscript Conditions to add/overwrite (css)files.
eg.
page.headerData.10 = TEXT
page.headerData.10.value (
<link rel="stylesheet" href="fileadmin/js_css/style.css" />
)
#### add css to Page ID 1
[globalVar = TSFE:id = 1]
page.headerData.20 = TEXT
page.headerData.20.value (
<link rel="stylesheet" href="fileadmin/js_css/mycustomstyle.css" />
)
[end]
or a dirty but useful way to do so in backend is this little snippet. It uses the abtract field in your page properties where you can add some code into your <head>.
page.headerData.20 = TEXT
page.headerData.20.data = field:abstract
page.headerData.20.wrap = |