How to append block to parent using jade template - node.js

I'm trying to create a modular layout using jade template. I would like to append a script block from a child into its parents parent. I'm not quite sure if its possible at all.
Here is my structure
layout.jade
head.jade
index.jade
users.jade
layout.jade:
doctype
html#html
include head
body
block content
head.jade:
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
block scripts
index.jade:
extends layout
block content
h1 Hello
include users
users.jade
block append scripts
script(src='/javascripts/user.js')
ul
each user, i in users
li(class=i+"-"+user) #{user}
My desired html output should be:
<!DOCTYPE html>
<html id="html">
<head>
<title>Index</title>
<link href="/stylesheets/style.css" rel="stylesheet">
<script src="/javascripts/user.js"> <!--// append this from user.jade into head.jade //-->
</head>
<body>
<h1>Hello bob</h1>
<li class="0-user1">user1</li>

This should be possible, and there are examples in the jade documentation that do exactly this. Your code all looks fine except you need to indent your script tag in users.jade so it is indented below the block append script directive.

I tried to use the same approach to define a tab-control.
I defined the pages in separate jade-files.
Each jade-file appended a block that contained the tab-page which was included.
It also did not work until I appended something to the block in my 'index.jade' as below:
extends layout
append scripts
//- dummy
block content
h1 Hello
include users
However I also would like to add that since I added multiple .jade files I ran in the following. Each file inclued jade-template used block append to add a tab-page but the order in which the pages were added was reversed.

Related

Automatically include assets into template

I'm using the linkedIn fork of Dust with Node.JS & Express.
My template hierarchy is having:
1 layout template - The base template
1 Page template - This is the template that will be rendered
Optional number of partials - Might be included by the page template
layout.dust (layout template):
<html>
<head>
<script src="/js/layout.js"></script>
<link rel="stylesheet" href="/css/layout.css">
<script src="/js/home.js"></script>
<link rel="stylesheet" href="/css/home.css">
<script src="/js/sidebar.js"></script>
<link rel="stylesheet" href="/css/sidebar.css">
<script src="/js/widget.js"></script>
<link rel="stylesheet" href="/css/widget.css">
</head>
<body>
{+content}{/content}
</body>
</html>
home.dust (page template):
{>layout/}
{<content}
<div>
{>sidebar/}
</div>
<div>
{>widget/}
</div>
{/content}
When the user visits the website homepage, then home.dust will be rendered, and the user will see a page with the sidebar and some widget. The content of sidebar.dust and widget.dust is irrelevant.
As you can see in layout.dust, there are 4 sets of JavaScript and CSS included in the head section, one for each of the templates and partials. My problem is finding a way to automatically include each asset into the layout (without hardcoding). Ideally I would like to be able to just do this:
{#scripts}
<script src="{.}"></script>
{/scripts}
Different pages may require different assets.
How can I push each script source path into the context of layout.dust?
What do other developers do, do they just hardcode them?
I'd be adding all scripts to the head of the layout without pushing any from the pages that extend from this layout. I'm not sure how knowledgeable you are on javascript minification but it's common practice to bundle all (or most) of your javascript assets into one file and serve them up to the user with a single HTTP request. This speeds up your page a lot; checkout what Google has to say about it here.
It's not hard because there are a few tools to do this for you automatically. You could go for an asset manager or Grunt.
ASSET MANAGER:
There are a few on npm. I found one called Express Asset Manager and another called Asset Pipeline.
GRUNT:
Use contrib-uglify and contrib-concat to handle you minification. There are plenty of others that you should find useful. You can do the exact same thing with all of your CSS too.
Obviously in development you don't really want to try to debug minified code so you can do something like the following:
{?production}
<script src="production-minified-script.js"></script>
{:else}
{#scripts}
<script src="{.}"></script>
{/scripts}
{/production}
where production is a variable passed to your template from process.env.NODE_ENV. To avoid manually adding in each script, you could pass them in as an array by
STILL WANT TO ADD FROM OTHER PAGES?
If you still want to add from other pages, add in a block to your head below your main scripts, something like:
{+otherScripts}{/otherScripts}

Should Partial Views contain <head> element

I encounter in some web app that some partial view that is used has head element (it loads some Jquery things).
The thing is that with that and the _layout.xml I get this wierd HTML page structure
<head>
...
</head>
<body>
...
</body>
<head>
...
</head>
<body>
....
</body>
doesn't feel right..
What's the best practice to load some .css.js to particular page? is it all done by _layout.xml and bundles?
and in general - only _layout.xml should contain head element? no other view in my solution?
You want only one head. Use layout with sections and add MVC sections in normal pages to add CSS or JScript. See here on basic section usage http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx. If you want to use partial create a helper to render section from partial see this answer Using sections in Editor/Display templates

Jade Include doesn't render included page content

I'm trying do an app with Node/Express/Jade/Stylus.
The problem is that Jade won't render the content of an included file.
Here are the files:
layout.jade:
doctype 5
html
block head
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
header
block header
#main-container
block content
footer
block footer
index.jade:
extends layout
include helpers/header
block content
form#form-login
helpers/header.jade:
extends ../layout
block header
#test
p Hello World
img(src="images/Logo.jpg" alt="Logo")
The rendered page is blank. In the page there is nothing. The image url is right, so tha's not part of the problem. I checked the page code, and header.jade was completely ignored.
I checked if the header.jade is loaded, and it is loaded (I tried putting an error in it).
Here the code of the rendered page:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<header></header>
<div id="main-container">
<form id="form-login"></form>
</div>
<footer></footer>
</body>
</html>
It looks like a block doesn't propagate properly from an include to a layout (I'm not overly familiar with Jade so this might be intended behaviour), because this seems to work:
// index.jade
extends layout
block header
include helpers/header
block content
form#form-login
Also, you shouldn't use extends ../layout in your header include, otherwise your layout file will be rendered twice.

Using a global wrapper template in Express/Jade

I've had a quick skim of the Jade documentation and I can't seem to figure out how to apply a wrapper to all templates that I output.
How is this usually done?
It sounds like you want template inheritance:
// layout.jade
!!!5
html
body
block content
The content block is what you define in all templates that are going to inherit the layout template:
// index.jade
extends layout
block content
h1 Hello World!
When you render index.jade, this is the result:
<!DOCTYPE html>
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
So in layout.jade, you set up all common elements like JS/CSS, headers/footers, etc.

Thickbox inline problem

I am trying to create a modal window with hidden content using thickbox
It opens the window fine , not sure whys its not showing the content inside the id="hiddencontent".
i am following as suggested in the examples for inline http://jquery.com/demo/thickbox/#
-thanks
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Untitled Document</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="thickbox.js"></script>
<link rel="stylesheet" href="thickbox.css" type="text/css" media="screen" />
</head>
<body>
Show Content
<div id="hiddenContent" style="display: none">inline content comes here</div>
</body>
</html>
It seems you don't have css file, you can copy thickbox css on http://jquery.com/demo/thickbox/#sectiona-3 to your page (or save as style.css file).
-- edit --
Yeh, sorry, didn't notice that css is already loaded :(
By the way, just found the solution, try to add p tag inside your hiddenContent div:
<div id="hiddenContent" style="display: none"><p>inline content comes here</p></div>
Hope helps ;)
This is a bug in thickbox. Here is how you can fix it:
Inside thickbox.js
on or about line 221 you should see this line of code:
$("#TB_ajaxContent").append($('#'+params['inlineId']).children());
change it to this:
$("#TB_ajaxContent").html($('#'+params['inlineId']).html())
and then, on or about line 223 you will see this line:
$('#'+params['inlineId']).append($("#TB_ajaxContent").children());
disable the line by adding two slashes before it like this:
//$('#'+params['inlineId']).append($("#TB_ajaxContent").children());
Explanation:
When thickbox copies the content from the hidden div into the thickbox container, it does so by copying all .children() elements. If you have only text inside your hidden div there ARE NO CHILDREN because text is not itself a child element. This is why wrapping your content in a <p> tag will work because now there is a child (the <p> tag).
So if you want to have text only in your hidden div using .html() instead will grab everything in your hidden div. The second line being disabled prevents thickbox from trying to copy the content back to the hidden div when the thickbox closes, which would cause any content within child tags to be duplicated in the hidden div.
There is no need to edit the .js file, the solution is quite simple.
Maybe a bit later :) but I overcomed the issue only changing the ? char in #TB_inline? by &
The issue is on the internal parseQuery tickbox function, that parses match pairs but it blows when the query have a double ? like in the case.
UPDATE: In some cases the <p> fix is also needed ;)
Hope it helps.
The function tb_position() needs to be updated.
this condition
if ( !(jQuery.browser.msie && jQuery.browser.version < 7))
is the reason for error.
jQuery does not support jQuery.browser anymore. For detecting IE6 in this case change the above condition to this
if ( !(/\bMSIE 6/.test(navigator.userAgent)))

Resources