Rendering jade template with layout (without express) - templates

When you render jade templates in express you can configure your application with 'view options', { layout: true } and the templates rendered will automatically get plugged into the body local of the layout template.
I'm trying to achieve the equivalent behavior rendering files from node.js, but without the express framework (I'm just building static files as part of a larger pipeline).
There appear to be two options:
Load both the main template and the layout, convert to functions, render the template first and then pass the results to the layout function
Use the standard template inheritance and block structure, but then I'm explicitly using named blocks
Are these the only options (which, fair enough, are still awesome), or am I missing some trick?
Edit
Here's a rough cut of the first option in case anyone is interested:
// Load jade
var jade = require('jade');
// Load actual template text
var layout = fs.readFileSync('layout-path', 'utf8')
tpl = fs.readFileSync('tpl-path', 'utf8');
// Compile template rendering function
layout = jade.compile(layout, { pretty: true, filename: 'layout-path' });
tpl = jade.compile(tpl, { pretty: true, filename: 'tpl-path' });
// Render jade template, passing in the info
var output = layout({ body: tpl({ local1: some_var, local2: some_var }) }
// Write rendered content to file
fs.writeFileSync('output.html', output);

I believe the answer is "no", you're not missing any trick. The two options you outline seem to me the two most straightforward ways to use jade to generate your file. Of course there are plenty of non-jade approaches as well. For example, you could merge the contents with the plates approach, good old String.replace, or split your layout into separate header ad footer fragment files and just concatenate them in head, body, foot order.

Related

Including specific style sheets or javascript in ember-cli-build

The problem
I am working on an Ember.js project which has different versions (products) for different clients. Though the functionality is more or less the same, the styling of each product differs big time. Hence we have "default" and product specific style sheets. I have been asked to modify the build code so that only the corresponding .css (.less) files are compiled into the final app.
Originally I was looking at this issue from the wrong side: I tried to exclude the folders containing the unnecessary files with little success. Only then did I realize that it makes more sense not to include the product specific files by default and add them to the tree during the build.
The solution
After changing my point of view I found out there is another way around. I changed the style sheets so that all the "default looks" went into an import-base.less and I created an import-[name_of_product].less for each of the products, with the latters containing the import statement to the default looks, so I only have one file to build. Using the outputPaths option in EmberApp and assuming that the name of the product is stored in the process environmental variable called FLAVOUR my code looks as follows.
// ember-cli-build.js
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
// y u do dis
const options = { outputPaths: { app: { css: { app: false } } } };
const lessFileName = 'import-' + process.env.FLAVOUR.toLowerCase();
options.outputPaths.app.css[lessFileName] = 'assets/application.css'
const app = new EmberApp(defaults, options);
return app.toTree();
};
There is always something
The only problem with that code is that it still needs an app.less and that line of code or else the build fails, couldn't (haven't had time to) figure out a solution.
I also have to mention that the above solution doesn't resolve the original problem, which was:
How to exclude specific files from the working directory before using app.toTree() so that they wouldn't increase file size unnecessarily. Lux was so kind and pointed out that probably in-repo-addons are to be used for such purposes. Yet again, haven't had time to check. :(
I think you can just use funnel!
something like this:
return new Funnel(app.toTree(), {
include: ['**/*']
exclude: ['styles/*.css']
});
general you can do anything you can do in a Brocfile in your ember-cli-build.js!

Create variable accessible through all templates in PrestaShop

I understood that if I want to make my own template variable in PrestaShop, I would use code like this:
$this->context->smarty->assign( 'varName', 'varValue' );
I also understood that the right way to add this is putting it into a controller... and it all works...
What I can't figure out is how to do this in one place but still being able to access the template variable in ALL templates (my theme's .tpl files)?
PS: Adding it to all controllers seems redundant... I tried to google it out, but I guess I am putting bad keywords to search for...
So I found a solution.
What you want to do is to put your variable definition in some "general" controller - for frontend it is the FrontController. A better way then to edit the core file, is to make an override so I will show you all you need to do - considering PrestaShop 1.6 :
Create a file called FrontController.php and put it in override/classes/controller
Create a content of this file - handy method to override is initHeader(), because the variable will be available in header.tpl and all templates that are using it(tested in header.tpl and index.tpl).
Content of override/classes/controller/FrontController.php:
class FrontController extends FrontControllerCore {
public function initHeader(){
//create your variable
self::$smarty->assign('yourVariable', 'valueOfYourVariable');
//call original method, to maintain default behaviour:
return parent::initHeader();
}
}
Load the override=> go to cache directory (from shop root) and edit file called class_index.php:
find array with key "FrontController" (search for 'FrontController' or "FrontController")
in this array change "WHATEVER" in 'path' => 'WHATEVER', to override/classes/controller/FrontController.php so you will get: 'path' => 'override/classes/controller/FrontController.php',
Use your variable freely in template files as {$yourVariable}
Reference: http://doc.prestashop.com/display/PS16/Overriding+default+behaviors
you can do with modules also, prestashop provides hooks, we can use the header hook inside our module and pass the variables to smarty from the header hook function. The header hook is available on all pages
public function hookHeader($params)
{
$this->smarty->assign(array('var1' => 'value 1', 'var2' => 'value 2', 'var3' => 'value 3',));
}

Silverstripe Template Issue

I'm getting to grips with the Silverstripe framework and I've come across a strange error.
Say for example I want to create a new 'membership' page. Within mysite/code I have set up a membership.php page as follows:
class Membership extends Page {
}
class Membership_Controller extends Page_Controller {
}
Then I have created a membership.ss file within my templates/layout folder with some test output. I then do a dev build and create a page in the CMS of type 'membership'. On the front end if I click the new page form the nav bar membership I don't see the test text so it seems that the template is not being read?
Any ideas?
Thanks.
Alan.
There are several common pitfalls regarding templates:
how flushing works has changed several times in the past versions.
I will not explain the details here, as those are prossibly subject to change soon again.
However there are 2 things in the current version (3.1) that is of relevance here:
/dev/build does NOT flush at all
/dev/build?flush=1 does ONLY flush manifest and config (NO templates)
(dev build does not use the template, so there is no flushing the template performed)
this means that you have do do a ?flush=1 on a normal page, not just on dev/build
The Template file has to be named exactly like the class (I think its case sensitive)
check that the template file is not overwritten by another template file in another location. (eg if you have moduleName/templates/Foo.ss and themes/simple/templates/Foo.ss than the template of the theme will overwrite the module template
make sure the template is not empty (this causes an error in SilverStripe, at least in version 3.1)
Actions on a Controller can overwrite template ussage. here some examples:
// this will not use a template at all, it will just print "some string"
public function index() { return "some string"; }
// this will not use a template at all, it will output an empty string
public function index() { return; }
// this will use template named "Bar.ss"
public function index() { return $this->renderWith(array('Bar')); }
SilverStripe also provides a debug option to see what templates are used.
you can active it by 2 ways:
set source_file_comments in your yml config:
SSViewer:
# display template filenames as comments in the html output
source_file_comments: true
use the "URL Variable Tools": just add ?showtemplate=1 when viewing your website
when enabled, see the HTML source (CTRL+u in firefox) of the page
silverstripe will add comments to let you know what templates are used.
Make sure your class has a Page_Controller extension declared and named correctly. I recently had this issue. The page controller extension had a typo, so the template file was not being used.
So for example, if your page class is RidiculouslyNamedPage
class RidiculouslyNamedPage extends Page {
}
class RidiculouslyNamedPage_Controller extends Page_Controller {
}
Then in your themes/[theme-name]/templates/Layout/ folder you would have your RidiculouslyNamedPage.ss.
If you misspell RidiculouslyNamedPage_Controller the template will not get called.
I found the answer to the problem.
My .php was missing the following:
function getInfo() {
return $this->renderWith('Media');
}
ithout this the Media.ss file will not be used! Hopefully this will help other who might be getting to grips with SS!

Yesod Julius Interpolation of Messages

I've been using Yesod's messages system to help keep my language consistent. For example, I have a message named MsgBrand, which gets interpolated into Hamlet files with no problem. However, I am now using a JavaScript library which needs this kind of information.
var tour = Tour.new();
tour.addSteps([
{ element: "#some-id",
title: "Some Title",
content: "_{MsgTourStepFoo}"
}
]);
However, _{MsgTourStepFoo} is appearing in the rendered JavaScript code verbatim. In other words, there is no interpolation. Is this normal or am I missing something?
This is normal. We could have a i18n-variant of Julius, but have avoided it so far simply because it seems like it would be more confusion than it's worth. Instead, you can use getMessageRender to get the message rendering function and then call it from Julius, something like:
Haskell:
messageRender <- getMessageRender
Julius:
content: "#{messageRender MsgTourStepFoo}"

Request context in a Go template

I would like to write such a conditional fragment in a Go HTML template :
{{if isUserAdmin}}
<a href"/admin/nuke">Go to the big red nuclear button</a>
{{end}}
However, this is not directly possible because the template is not aware of the request that triggered its execution, so it cannot determine if the user is admin or not.
Is there some normal way to achieve this ?
In advance I point out that :
I do not want to use Pipelines for this specific data (see other question about this)
I acknowledge that only the handlers/controllers should deal with logic, and views should only do the rendering. But the condition {{if isUserAdmin}} is not logic itself, it's a necessary construct to leverage a boolean value already calculated by the controller.
The Funcs method can help, but is currently not lean enough for easily defining specific method isUserAdmin()
I would agree with Darshan Computing, I think the proper way of passing information from the request would be in the pipeline. You can have your data being split between the data you want to render and the context, e.g. by having your template data structure embed them both if you want to clearly separate the two:
type TemplateData struct {
*Content
*Context
}
Which gives this for example. You can then reuse some of your context/content information depending on what is shared and what is query specific.
Here is a working solution attempt (link to Playground) using Funcs to overwrite "isAdmin", after template compilation but before each execution (thanks to Valentin CLEMENT in other question).
But it has several flaws :
It is weird to declare a dummy empty "isAdmin" function before template compilation.
(Using Funcs several times is painful because I cannot just overwrite a single method, I have to provide a complete FuncMap with all the functions) edit : in fact previous funcs are not lost, i was wrong about that.
It is inherently not thread-safe and will fail when several goroutines alter and execute the same template
The normal thing to do is to simply pass your template a struct with whatever static data you like. Unless I've misunderstood what you're trying to do, there doesn't seem to be any need for Funcs here. Simplifying your example:
package main
import (
"html/template"
"os"
)
const hometmpl = `
{{if .IsAdmin}}
Go to the big red nuclear button
{{end}}
`
var t = template.Must(template.New("home").Parse(hometmpl))
func isAdmin(token string) bool {
const adminToken = "0xCAFEBABE"
return token == adminToken
}
func main() {
token := "0xCAFEBABE" // Or extracted from the http.Request
t.ExecuteTemplate(os.Stdout, "home", struct{IsAdmin bool}{isAdmin(token)})
}