Jade Includes conditionals to check the actual page - javascript

Is there a way to check which page are you in Jade and include something (a partial page or a specific CSS Style) based in that page? For example:
If I am in homepage, then include just the HOMEPAGE-head.jade
Else - include the NORMAL-head.jade
Here is an in context example:
doctype html
html
body
if HOMEPAGE
include ./includes/HOMEPAGE-head.jade
else
include ./includes/NORMAL-head.jade
h1 My Site
p Welcome to my super lame site.
include ./includes/foot.jade
Thank you!

Alternatively you can structure your Jade to use inheritance to achieve what you want.
E.g.,
layout.jade:
doctype html
html
body
block header
block content
h1 My Site
p Welcome to my super lame site.
block footer
include ./includes/foot.jade
homepage.jade:
extends ./layout.jade
block header
include ./includes/HOMEPAGE-head.jade
normal.jade:
extends ./layout.jade
block header
include ./includes/NORMAL-head.jade
And then have all your normal pages use normal.jade and your homepage to use homepage.jade.

There are two approaches I know of.
Option A: 2 layouts and extends
Make two layouts: layout.jade and layout-homepage.jade, changing the include line accordingly. Most of your pages will extends layout, but index.jade will extends layout-homepage.
Option B: variables block
in layout.jade:
- var HOMEPAGE = false;
block variables
doctype html
html
body
if HOMEPAGE
include ./includes/HOMEPAGE-head.jade
else
include ./includes/NORMAL-head.jade
h1 My Site
p Welcome to my super lame site.
include ./includes/foot.jade
Then in index.jade:
block variables
- HOMEPAGE = true;
h1 This is your home page template...
All the rest of your pages will default to HOMEPAGE = false so they don't need any changes to make this approach work.

An option that I'd suggest is using separate layouts. It takes advantage of the system that Harp already has in place, and helps maintain the concept of "different content, different file." Using Harp, you can specify an explicit layout for any given page in the _data.json or _harp.json files.
From http://harpjs.com/docs/development/layout
Layouts other than _layout can be specified in a _data.json. This is
useful if you need even finer control of Layouts, or if you want to
name your Layout something other than _layout.
myapp.harp.io/
|- _layout.ejs
|- index.ejs
|- about.md
+- articles/
|- _data.json
|- _an-example-layout.ejs
|- _another-one.jade
|- article-one.md
+- article-two.md
Here, it’s possible to make article-one.md use _an-example-layout.ejs by specifying layout in the _data.json file in that folder:
{
"article-one": {
"layout": "_an-example-layout",
"title": "Example Title"
},
"article-two": {
"layout": "_another-one",
"title": "Another Example Title"
}
}
Now, each article will use the specified Layout.
If it's a minor difference you want to make and you can't justify having a completely separate template, you can also pass data through to the include if you use Harp's partial() function instead of Jade's include keyword. Then the logic for handling the different variable value would be in a single head.jade file. Your example might look like this.
foo.jade:
doctype html
html
body
!= partial("./includes/head.jade", { page: bar })
h1 My Site
p Welcome to my super lame site.
include ./includes/foot.jade
head.jade should now have access to the page variable.
A third option can take advantage of the current object that Harp injects into the templates. If you're accessing //site.com/foo/bar, current.source === "bar" and current.path === ["foo", "bar"]. You can use this object to dynamically set class names, etc. You can read more about it here: http://harpjs.com/docs/development/current

Related

Meteor optional template

So I have started to learn Meteor and trying to get my head around how I should format the template correctly. This is how I set up my project:
A/view.html - html file for template A
A/script.js - import A/view.html. Potentially be the "controller" to work with the interaction
B/view.html - html file for template B
B/script.js - import A/view.html. Potentially be the "controller" to work with the interaction
routes.js - route file, include all script.js for template A and B
So I have two questions:
First, I want to make A as the base template, meaning it will have style and javascript tags as well as a "styles" and "scripts" optional blocks in case the child template wants to add extra files. How can I do this? I have tried normal ways:
Creating 2 blocks named styles and scripts in each child templates. This doesn't work since routes.js imports everything, meteor complains there are 2 templates having the same name
Using Template.dynamic. This work but I have to declare what template I want to render in the block of "styles" and "scripts", which is a bit untidy, in my opinion, when the project goes big.
The second question, as I described what I am currently doing with my routes, what is the best way to localize(?) the block to the current file?. Would it be possible to have 2 blocks called "scripts" in 2 different child templates and meteor not complaining?
Thanks guys :)
I'm not 100% sure what you mean by "blocks", but I assume you want to have A be the template that everything else fits into, and then have other pages feed into it?
If so, it sounds like you would want to use dynamic templates, and have A be a layout.
Here is an example of a layout, which imports other templates from one of my projects (It actually imports two constant templates (loginNavbar and modalWindow) as well as dynamic ones depending on what I call to it. You could add as many styles and other things as you want to the layout itself):
<template name="loginLayout">
<div class="loginNavbarTemplateDiv">
{{> loginNavbar}}
</div>
<div class="loginContentTemplateDiv">
{{> Template.dynamic template=content}}
</div>
{{> modalWindow}}
</template>
So then my routes.js looks like this (renders the outside loginLayout with the inner content of login or register):
FlowRouter.route('/login', {
name: 'login',
action: function() {
BlazeLayout.render("loginLayout", { content: 'login' });
}
});
FlowRouter.route('/register', {
name: 'register',
action: function() {
BlazeLayout.render("loginLayout", { content: 'register' });
}
});
Overall, I wouldn't have two templates named the same thing, and if you structure your files/app properly, it shouldn't be too untidy.
Please let me know if this helps and if you have any other questions, I'd be glad to help.
-
Here is a great tutorial on dynamic templates if you want more:
https://themeteorchef.com/tutorials/using-dynamic-templates
And a guide on how to structure your Meteor app files (helps a ton and makes everything better):
https://guide.meteor.com/structure.html

ng2-ckeditor - how to customise the css loaded inside the editor itself?

I need to customise the ENTER key behaviour of ng2-ckeditor. I understand there is a config option as explained here.
However as that link explains, I should use custom css:
If you want to change it to control paragraph spacing, you should use
stylesheets instead. Edit the contents.css file and set up a suitable
margin value for <p> elements, for example:
p { margin: 0; }
According to this SO question I can load a custom CSS file using a config option, like this:
config.contentsCss = 'mystyles.css'
I tried adding a single file to my project and setting the config in angular 2 component, but the file does not appear to load.
private setConfig(): void {
this.ckConfig = {
height: '250',
extraPlugins: 'divarea',
contentsCss: '/theme/styles/ckeditor.css',
toolbar: [... toolbar configurations ...]
};
}
So how can I get ng2-ckeditor to load this file?
This breaks if you have the DIVAREA plugin activated
Edit (from comment):
This is because contentsCss does not load when using DIVAREA. Makes sense since the CSS would need to be scoped to inside the DIV (easy with iFrame).
Maybe new CSS layers could help here?
github.com/ckeditor/ckeditor4/issues/4640 github.com/ckeditor/ckeditor4/issues/4642

Assign a class on body conditionally in Jade

Assume I have main template file named layout.jade and a bunch of files that extend this template - home, about, products and so on.
In main template I put structure like this:
body
section.main-content
block content
Then pages:
extends ../layouts/default
block content
include partials/banner
include partials/why
So different pages put different content into content block accordingly. I render pages with gulp-jade and in the end I have all the pages as HTML.
My question is - can I put some variable inside child page, like about, so that it to go as a class to body tag of its parent template, like <body class="about">?
Here's a pattern I use for this type of situation. In your main template, set up some variables:
//layouts/default.jade
- var bodyClass;
block variables
html
head
body(class=bodyClass)
section.main-content
block content
Then establish the bodyClass in your page templates.
//about.jade
extends ../layouts/default
block variables
- bodyClass = "about"
block content
h1 This is the About Page
This is how I do my page titles for the <head><title> tag, for example. I can also have logic in the layout.jade file to provide default values, etc.

how to add JS and CSS tags from module without using header hook

is there any way to add JS and CSS tags just for the page where the module is contained?
If i use the code snippet
$this->context->controller->addjs('js/file.js', 'all');
in the "hookHeader", the script is added for the whole website (index, cms pages, etc.) where hook is used.
Thanks, any help would be appreciated.
If you want to add a js file only in page product and category for example, you can do this :
public function hookDisplayHeader($params)
{
$allowed_controllers = array('product', 'category');
$_controller = $this->context->controller;
if (isset($_controller->php_self) && in_array($_controller->php_self, $allowed_controllers)) {
$this->context->controller->addCss($this->_path . 'css/front.css', 'all');
$this->context->controller->addJs($this->_path . 'js/front.js');
}
}
Yes you can do it easily.
What you need to do it to call addJs or addCss in the desired hook function only. For example, if you are hooking your module at left column on certain pages only, then if you call
$this->context->controller->addjs('js/file.js', 'all');
at your hookLeftColumn (what ever the method name is nowadays :P ), then that js or css file will be only used when that module is displayed.
Or you can just place that css / js file directly in the template.
If your module will appear on specific pages, you can define "Exceptions" - the same that can be defined via Back Office > Modules > Positions > Transplant a module.
This way the hookDisplayHeader for that module will not be even executed and no CSS and JS files will be added. This is a better solution from a performance view point.

ASP.net MVC - Views and jQuery Best Practices

I'm trying to figure out what the best practice is for using jQuery in an MVC app. Specifically, I would like to know what I should do so that I don't clutter all my views with individual document.ready statements.
As an example:
I have the following Views:
/Views/Shared/_Layout.cshtml
/Views/Home/Index.cshtml
/Views/Home/_Dialog.cshtml
/Views/Home/_AnotherDialog.cshtml
I have a controller action that will render the Home/Index View, which uses the Layout and renders two partial views (or editor templates, display templates, etc.). This one controller action has rendered 4 or more views. Each view is using some jquery document.ready code.
Currently, I have the code at the bottom of each view:
// In Index
<script type="text/javascript">
$(function() {
$('#tabs').tabs()
});
</script>
// In _Dialog
<script type="text/javascript">
$(function() {
$('#some-dialog').dialog( ... );
});
</script>
I know this isn't a very good practice because it is already getting unmanageable in my small project. What are some good practices to follow when I have tons of pages that all need some jQuery / javascript initialization code separated across dozens of views?
You could do something along the lines of what Telerik do with their javascript registrar. Basically, make this registrar available in your view model. At the simplest level, all it has to do is keep track of strings added to it:
public class JavascriptRegistrar
{
private StringBuilder jsBuilder_ = new StringBuilder();
public Add(string js)
{
builder.Append(js).Append('\n');
}
public string ToString()
{
return "<script type=\"text/javascript\">" + jsBuilder_.ToString() + "\n</script>";
}
}
Your partial views will then add to this when rendering:
<h1>In my view!</h1>
#Model.Registrar.Add("$function() { /* ... */ }")
Finally, at the bottom of your main view, when you're done:
#Model.Registrar.ToString()
Which will write out all the javascript it has collected during rendering.
If the initialisation is specific to a view and you know it definitely won't be used outside that view, for example some page specific behaviour, then just leave it in the view!
There is nothing wrong with having script tags in all your views, as long as you aren't replicating js between views. I think people tend to misunderstand 'separation of concerns' in this case and think that simply means 'keep different languages away from each other at all costs'...that is wrong, clearly if some page initialisation logic/behaviour is specific to a page, then the html and js intrinsically 'concern' each other, therefore moving the js into a separate file is not really 'good practice', if anything it makes your code more difficult to understand.
I personally like to open up a View, and be able to see all the js and css that is specific to that page as soon as I open it, makes it nice and readable. However, obviously if code needs to be shared then you need to bust it out your view and get in your scripts folder whwere it can be referenced by anything!
EDIT
In your example above I see in your Index view you initialise your tabs. This is fine as it is, however, if you added tabs somewhere else in the project then it might be better to create your tabs using a .tabs class rather than #tabs id, and then in an external js file initialise all your tabs at once by calling $('.tabs').

Categories