Adding widget (dynamic) CSS in Genshi (TurboGears 2) - css

I'm trying to figure out how to add CSS in Genshi to some markup which is dynamically generated. I'm trying to avoid inline CSS, and ideally the rules would appear in the <head/> tag of the parent document.
I'm working with existing code that looks like this (I rewrote this from the original, to simplify, so I might have some syntax mistakes; but the original works, so I think you can ignore syntax mistakes if any):
templates/widgets/file_widget.html
<html xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
<head>
<style type="text/css">
.file-widget {
background-color:#eee; display:inline-block; padding:4px;
}
</style>
</head>
<py:def function="file_widget(file_name)">
<div class=".file-widget">
...
</div>
</py:def>
</html>
widgets.py
class FileWidget:
...
def html():
markup_template = genshi.template.MarkupTemplate('''
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="my_project/widgets/file_widget.html" />
${description}
${file_widget(file_name)}
</html>''')
markup = markup_template.generate(file_name = self.file_name, description = genshi.core.Markup(self.description))
return markup.render('html', doctype = 'html')
templates/main_page.html
<div py:for='widget in app.widgets'>
${ genshi.core.Markup( widget.html() ) }
</div>
Unfortunately, the <style/> tag gets rendered twice: once, as I want it to be, inside the original document <head/>, and then the widget <head/> gets rendered again.
How can I change the code to properly include the CSS in the right place? Since this is collaborative code, little changes and clearer code are appreciated!
Thanks for reading and for your help.

You might want to use a widget library like ToscaWidget2 which is meant to actually manage widgets with resources.
Otherwise you might want to use a static files framework like fanstatic which provides support for resources inclusion: http://www.fanstatic.org/en/1.0a5/quickstart.html#including-resources-with-fanstatic
If you want to roll your own custom solution you should register the resources somewhere whenever the widget is rendered (like in request) and then add them to the head tag when template is rendered. This is actually what tw2.core.resources does: https://github.com/toscawidgets/tw2.core/blob/develop/tw2/core/resources.py

Related

Inserting content with CSS a second time?

Is it possible to insert -- dynamically generated -- content with CSS into the same website a second time, let's say a div-container like this: <div id="duplicate-me">dynamically generated content</div>
CSS is used to style content that exists or will eventually exist on a page. It can't load or insert dynamic content to a page. It can control showing/hiding content on a page, but the content needs to be placed there first (with the exception of psuedo-classes, but that's not really "dynamic"). As others have mentioned, Javascript/jQuery is what you are needing to use to achieve what you are wanting.
Using pseudo element's in CSS we can kind of create an element and style it in CSS. But then this has it's own limitations.
Javascript is what will essentially help you achieve this using document.createElement() method and other methods line appendChild() etc
CSS cannot be used for duplicating, but you can use javascript to duplicate div,p or any other element. We do it like
In the html file
<head>
<!--all other stuff-->
<script src='sketch.js'></script>
</head>
in the sketch.js file
var dupElem = document.createElement('div');
dupElem.id = "duplicate-me";
document.body.appendChild(dupElem);
//to manipulate the text content we do
dupElem.textContent = "some lorem ipsum"
//or else you can do a for loop
for (let i = 0;i < 3;i++){
document.body.appendChild(dupElem);
}
It is possible to make a copy of a node element but you need Javascript to do that.
<div class="duplicate-me">dynamically generated content</div>
In your Javascript:
let nodeToClone = document.getElementsByClassName("duplicate-me")[0];
let newClone = nodeToClone.cloneNode(true);
document.body.appendChild(newClone);
Please note that id needs to be unique in the document. That is why I used class.
Here you can learn more about clone.
O.K., JavaScript then. I'll look into it. Thank you for the answers. :-)

Can anyone tell me why this gridset css isn't working?

I've used gridsetapp.com in the past to create responsive grids, but on the one I've recently tried creating just isn't working and I can't figure out why.
The link to the css is here; https://get.gridsetapp.com/37722/
Just trying to get something basic:
<html><head>
<link href="https://get.gridsetapp.com/37722/" rel="stylesheet" />
</head>
<body>
<div class="d1-d5" style="background:#aaa">ffggg</div>
</body>
</html>
Any thoughts?
Despite an unusual CSS link, the browser should recognize the CSS file your referenced.
However, looking at your reference, you are just trying to apply CSS to the class d1-d5. However, as best I can tell, there is no exact match in the CSS file to Just d1-d5. Use the Development tools (F12 on most browsers); they are your friend. It will show you what CSS is applied at that moment including, any applied through JavaScript or Linked files.
With CSS, you need to make sure that you call out exactly what the browser can identify, but not more (unless going for a higher order of precedence). For example, the most you could call out to select your d1-d5 is:
html body div.d1-d5{...}
Whereas in you linked CSS file, I see a lot of parents or children when searching d1-d5, such as .d1-d5 .d1,.d1-d5 .d2,.d1-d5 .d3,.d1-d5 .d4,.d1-d5 .d5.
If you wanted the last one in this chain (.d1-d5 .d5), you would need an HTML such as:
<html>
<body>
<div class='d1-d5'>
<div class='d5'>
This text will have the CSS applied.
</div>
</div>
</body>
</html>
The CSS written as .d1-d5 .d5 literally means "select the element with class d5 as a descendent of an element with class .d1-d5". Your HTML doesn't match any of the classes in the CSS file, including the parent and child selectors. If you were to try the above HTML, you would see width:18.05273834%; applied (which isn't a very obvious thing to see... why not try background:yellow; or something like that for an easy verification).
Finally, why are you inline styling when you have the CSS? This is bad form, and only appropriate if you can't control the CSS file.

Apply styles to only to one element

I am including styles in normal way like this:
<link rel="stylesheet" href="/css/boostrap.css" type="text/css" />
this styles has a lot of styles which destroy my main view, it applies to body element, is it possible to applay the style only to one particular div?
Put that <div> into a separate page and include bootstrap CSS only in that page.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/css/boostrap.css" type="text/css" />
</head>
<body>
<div>This is your DIV</div>
</body>
</html>
Your main page won't be touched by that and you'll be able to display that div inside your main page simply using an iframe, change (for example) this:
<div>This is your DIV</div>
To this:
<iframe src="url of the other page"></iframe>
Of course you may need to change little bit the logic of your page to accommodate this (primary I guess because of server side C# code, for client side JavaScript code it should be easier because the come from the same domain).
Yes, you can do that by ID:
<div id="myDiv"></div>
and then the CSS would be:
#myDiv { ... }
and that will apply that style to anything named myDiv. You could also use classes:
<div class="someClass"></div>
and then the CSS would be:
.someClass { ... }
and that will apply that style to anything with that class attached.
Based on what you're describing, surrounding the generality of the CSS that's breaking the already defined CSS, you're going to want to get rid of those general element styles and use ID's because it sounds like you're trying to merge some CSS.
You try to remove all styles of body with javascript code, and after that, after you add a name/id to the body style in your correct css, set this as class attribute of your body. (js code too after the document is completely loaded)
Another (stupid) solution depends on what do you have in the css file. Do you can edit the /css/boostrap.css, simply replace all body word with ".body1" (fe => make a class from it)?

css for html that is included via object

I have an html file that I'm "including" via object:
<object type="text/html" data="try.html">
</object>
I'd like to use CSS to control how the contents look, but the CSS code seems to be ignored for the HTML in the object. If I pull in pieces directly the CSS works so I know it's "right". If I look at the HTML with a debugger, I can see there's another BODY & HTML tag, but since I'm using an ID I figured it would still find it.
Any suggestions ?
EDIT
so I got this to work using the jquery with $.get() like this :
<div id="here">
</div>
<script>
$.get("try.html", function(data) {
$('#here').html(data);
});
</script>
but I'd still like to know why, the CSS didn't apply to the HTML code included by the object tag. I haven't found a good explanation of that yet.

Head <style> block with plone.app.z3cform

I have a grok'ed plone.directives.form code below:
class EditForm(TreeFormMixin, form.SchemaForm):
"""
Edit form for our model.
We got one dummy button which allows us to manually inspect the data postback values.
"""
grok.context(ISiteRoot)
grok.name("dgftreeselect-test")
grok.require('zope2.View')
ignoreContext = True
schema = IFormSchema
label = u"Tree selection demo and manual testing"
#button.buttonAndHandler(u'Turbo boost')
def handleApply(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
raise ActionExecutionError(Invalid(u"Please see that data stays intact over postback"))
it results to this form - which is not that good looking:
Since it is a demo form I'd like to keep all the related material in the same .py file. However, as the form is ugly looking, I'd like to inject a <style> CSS block on the page from a Python source code string to fix some of the most outstanding issues with the CSS styles.
What kind of hooks plone.app.forms / BrowserViews provide to inject your own <style> block in the <head> or in any part of the resulting HTML page? I prefer not to create any additional files and CSS registrations for this task.
Full source:
https://github.com/miohtama/collective.z3cform.dgftreeselect/blob/master/src/collective/z3cform/dgftreeselect/testform.py
plone.app.z3cform and Zope browser views don't provide any hooks to inject custom things into the head directly, but you can use a custom template by specifying the template attribute in the form class:
template = grok.Template('path/to/template.pt')
And then in template.pt, fill the style_slot to include your styles. The entire template could look like this:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="context/main_template/macros/master"
i18n:domain="plone">
<body>
<metal:block fill-slot="style_slot">
<style type="text/css">
/* insert styles here */
</style>
</metal:block>
<metal:content-core fill-slot="main">
<metal:content-core define-macro="content-core">
<tal:button metal:use-macro="context/##ploneform-macros/titlelessform" />
</metal:content-core>
</metal:content-core>
</body>
</html>
This is not a best practice since the styles must be served every time the widget is rendered. Instead it's usually better to register CSS in the portal_css tool.

Resources