We have been having discussions in our product dev team regarding html maintainability and reuse. To set the context, we started with HTML5/CSS3 front end with plain JS under Play MVC, which in turn uses RESTful backend. Then we thought of adding AngularJS to the spin and to adopting a hybrid approach only to realize that two strong MVC frameworks don't necessarily work together and you have to pick one. So for the performance and type-safety among other issues, we decided to go with using Play framework and Scala based templates.
Here's the challenge: We would like to create reusable web components just like Apache Tiles, so that common elements such as header, menus, footer, etc. can be reused. These components are ready to go in Play to which dynamic content could be added to serve the entire page.
Can this be done? If yes, how?
Secondly, play templates seem to take you back in the time since they don't allow the separation of concern in html. Therefore for re-designing or improving html content, the html developer will have to deal with the template or merging new html with existing templates. How to make this process easier?
I'm don't know exactly how Apache Tiles works, but if I properly understand, it offers a way to create pages using smaller components (like header, menu, footer, etc) and some sort of include mechanism to glue these components together and then compose the page.
That said, you can achieve the same thing using Twirl. You just need to declare reusable blocks that can be used inside the same page, or you can have something like Rails partials that can be reused across different pages.
Let's see an example. Consider that you have the following files:
File app/views/partials/header.scala.html:
<header>
<h1>My Header</h1>
</header>
File app/views/partials/navigation.scala.html:
<nav>
<ul>
<li>Home</li>
<li>Profile</li>
<li>FAQ</li>
</ul>
</nav>
File app/views/partials/footer.scala.html:
<footer>
Some copyright info
</footer>
File app/views/main.scala.html:
#(title: String)(content: Html)
<!DOCTYPE html>
<html lang="en">
<head>
<title>#title</title>
<link rel="stylesheet" media="screen" href="#routes.Assets.versioned("stylesheets/main.css")">
<script src="#routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
</head>
<body>
#partials.header()
#partials.navigation()
#content
#partials.footer()
</body>
</html>
The files above defines not only some reusable partial templates (header, navigation and footer), but also a common layout (main) that all the pages of your application can reuse. Now, lets see a page that uses the structure above:
File app/views/users/profile.scala.html:
#(user: models.User)
#main(title = "User Profile Page") {
<h2>This is the profile page of #user.username</h2>
}
And there is more: since views are compiled to Scala code, you can import code written in Scala/Java and call it directly from your views, something like Rails view helpers:
File app/views/helpers/DateHelpers.scala:
package views.helpers
object DateHelpers {
def formatToISO8601(date: Date) = {
??? // format the date
}
}
Let's use this helper in our app/views/users/profile.scala.html page:
#(user: models.User)
#import controllers.DateHelpers._
#main(title = "User Profile Page") {
<h2>This is the profile page of #user.username.</h2>
<p>User since #formatToISO8601(user.createdAt)</p>
}
And there are other approaches to consider:
Ping-Play: Big Pipe Streaming for the Play Framework
You can create a Play module that integrate with Apache Tiles. I'm pretty sure this is possible.
A quick answer would be the following. If you are comfortable with Yeoman, you can keep most of the UI part in existing HTML, while rendering some pages with Scala templates. I would recommend Play-yeoman, which may help such that you can--with minimum effort--reuse UI components.
For instance, you may easily convert a NodeJS+Angular app into Play+Angular. The Play-yeoman plugin helps a lot. But it is not so flexible as it does not support any arbitrary Yeoman configuration, just Angular.
Related
how to using script block in layout
layout file:
<html>
-- styles files ---
<body>
<%- body %> <!-- view content -->
-- layout's scripts ---
</body>
</html>
view file:
--- html tags ---
view's scripts
=> i want view's scripts below layout's scripts but can't.
when i put script in layout, it is body, mean it will above of layout's scripts.
I don't known sailsjs have any way to define block like php laravel framework or not ? or any way to do it .
Thank you!
This is not exactly possible using the default asset pipeline.
Recommended workaround:
If you can, I'd actually recommend avoiding the issue altogether: instead, go in to your tasks/pipeline.js file and add the script you'd like to bring in there. That does mean it will be included on all pages (as a script tag in development, and in the minified bundle in staging/production). But in my experience, it is worth it for the clarity. (Plus, keep in mind that in production, you'll probably want all your scripts in a single bundle-- or most of them anyway.)
Another way:
If that still doesn't fit your needs, and you absolutely cannot have the script exist on other pages (e.g. because you're in post-production and are optimizing down the size of your bundle) then you can accomplish what you originally set out to do by modifying the Grunt tasks to support a different linker, or use another tool like Brunch, Webpack, or Gulp.
Or, if you (understandably) don't feel like customizing your Grunt tasks, then one other solution you might use is to add a script tag in layout.ejs, but wrap it in a conditional:
… (the automatically-injected scripts)
<script src="/dependencies/lodash.js"></script>
<script src="/js/utils/baz.js"></script>
<script src="/js/components/datepicker.component.js"></script>
<script src="/js/pages/foo/bar.page.js"></script>
<script src="/js/pages/beep/boop.page.js"></script>
… (etc)
<!--SCRIPTS END-->
<% if (view.path === 'pages/entrance/login') { %>
<!-- Additional script, since this is the login page: -->
<script>alert('hey!');</script>
<% } %>
BTW, you can also use something like the above to conditionally include Google Analytics, etc. so you're not tracking test requests as actual production traffic -- just check the environment (that's what we do on the Sails website, for example). This is also useful for conditionally including/omitting the robots/noindex meta tag (to prevent indexing duplicate content on your staging server), helpdesk chat widget, typekit, other analytics services, etc.
I've been trying to use the vue-router package for days without figuring out how it works, and it kind of drives me crazy.
My problem: I want to make a Single Page Application using VueJS, and I have taken the vue-router package since it is the routing package officially supported by the VueJS development team.
I've read a lot of "getting started" articles, lots of them start by hard-writing the template like this:
const Foo = { template: '<div>foo</div>' }
But since I'm not really into writing my entire template between those two quotes marks, I searched for a way to write my template into a file, and then load the file's content into a JS variable.
It seems that it's possible to write the templates into .vue files, and then load them into variables using:
import App from './App.vue';
But when I do this that way I get this error: "Unexpected token import".
I'm really frustrated by that, haven't they thought about a really convenient way for the template loading to be compatible on every browser? What did I miss?
I suggest you look into Vue CLI for helping you set up a desired scaffold for your project. Based on the options you choose you can end up with a webpack backed template along with the vue-router included. Webpack will take care of bundling your project so you don't encounter errors like that one.
Generally what you want to do is use vue files. A vue file is divided into three parts, and would look something like this:
<template>
// Your HTML for this component goes here
</template>
<script>
// Your JS for this component goes here
</script>
<style>
// Your CSS for this component goes here
</style>
Once you have your components organized like this, handling routing is pretty straightforward. You designate a file to contain the router object that handles the routing.
These are pretty much basics, so I won't go into details here but you can learn a lot more on the official Vue docs page. Here is also an example project that shows how to construct simple components in vue files and how to properly use the vue-router.
I am somewhat new to AEM and Sightly. I have written a 'page' component to house my page content. I have a number of devices with different CSS under /etc/designs/myapp as follows:
/etc/designs/myapp
- /128/style.css
- /240/style.css
etc etc..
Back in my page component, I have a number of different HTML files that I use to trigger the correct CSS via a Sling selector. For example:
/apps/myapp/components/page
- 128.html
- 240.html
The purpose of these files is to include the HTML <head> section with the CSS as an inline style (cannot link to external CSS due to device limitations).
The problem that I am having is that if I place 128/style.css inside the component itself, the include works. If I have it under /etc/designs/myapp, I can't get it to include properly. I have tried using ${currentDesign.path # appendPath='/128/style.css'} and I have tried explicitly referencing the whole path.
Here is an example of 128.html, under the page component:
<html>
<head><!--/*
*/--><div data-sly-include="/libs/wcm/core/components/init/init.jsp" data-sly-unwrap></div><!--/*
*/-->
<title>${currentPage.title}</title>
<div data-sly-unwrap data-sly-include="/etc/designs/myapp/128/style.css"></div>
</head>
<body class="main" role="document" data-sly-include="body.html"></body>
</html>
I realise that I need a <style></style> section wrapping any CSS that is included, but for now, I am just trying to get a page to include from /etc/designs.
Any help would be greatly appreciated.
From the definition of data-sly-include: https://docs.adobe.com/docs/en/aem/6-1/develop/sightly/block-statements.html#include
data-sly-include: Replaces the content of the host element with the markup generated by the indicated HTML template file (Sightly, JSP, ESP etc.) when it is processed by its corresponding template engine. The rendering context of the included file will not include the current Sightly context (that of the including file); Consequently, for inclusion of Sightly files, the current data-sly-use would have to be repeated in the included file (In such a case it is usually better to use data-sly-template and data-sly-call)
It's not meant to be used for the type of inclusion you are trying to do since you are not calling any renderer. I think you should use client libraries and include your CSS files only, here is the documentation about this : http://blogs.adobe.com/experiencedelivers/experience-management/sightly-clientlibs/
You should define a client library category for each of your styles and call the right clientlib when you need it using <meta data-sly-call="${clientLib.css # categories='category.style.128'}" data-sly-unwrap></meta>
Hope this helps.
We have a web application that its UI is based on GWT.
We are pretty satisfied from the technology, but we have one major problem: We get html files from our designer, and it takes a lot of time to integrate them into our GWT code.
Is there a quick way or rules to do that?
For instance, I would like to take the html, put it almost "as is" in a ui.xml file, and then start binding the components to UiBinder fields.
What is the quickest way to do that? What should I do with the CSS and JS files that I get?
I need some guidelines to make this conversion, so it will be quick & easy.
We have the same problem. It might be hard for a designer to get used to GWT widgets. But he'll have to forget about making HTML proof-of-concepts and using GWT directly.
We didn't overcame the difficulty. As a result, many GWT features are under-used (like CSSResources, or GWT-Bootstrap layout capabilities).
I would advise to have him learn the xml of GWT widget libraries.
You can also start by using GWT Designer. This way he can still do the design, learn the XML bit by bit, and you can still work on wiring the components.
Of course it is a slow process. People don't change old habits instantly.
Errai seems to fit your requirements.
Basically is uses regular HTML5 templates, binded to GWT logic.
"Create standard conform HTML5 templates or use existing HTML and CSS files to design your web and mobile applications."
http://errai.github.io/
Here is an example of a sign-in page:
<!DOCTYPE html>
<link rel=stylesheet href="css/TodoList.css">
<div data-field="main">
<h1>Get it done with Errai.</h1>
<div class=form>
<p class=error data-field=loginError>
Login failed. Please check that your email address and password were entered correctly.
</p>
<input type=text data-field=username placeholder="Email">
<input type=password data-field=password placeholder="Password">
<button data-field=loginButton>Sign In</button>
<p>New here? Sign up in seconds!</p>
</div>
</div>
source
(p.s. I've never used it, yet)
I've been using the Lift Web Framework as a REST only service for quite a while, but I need to use it as a stand alone tool now.
<lift:surround with="default" at="content">
<head>
<script data-lift="with-resource-id" src="/test.js" type="text/javascript"></script>
</head>
<h2>Welcome to your project!</h2>
<p><lift:helloWorld.howdy /></p>
</lift:surround>
I have the above very basic Lift template. The problem is when I view it in the browser something is adding an <?xml> DOCTYPE and the browser defaults to interpreting the resource as XML instead of plain HTML.
How do I tell Jetty/Lift that my static file is HTML?
Sounds like you may be using the XHTML doctype. In your Boot.scala file, you may want to try adding:
LiftRules.htmlProperties.default.set((r: Req) =>
new Html5Properties(r.userAgent))
That should set your application to use HTML5, and should turn off adding the <?xml... encoding header.
Also, as #VasyaNovikov mentioned, the lift: prefixed tags are an older construct (even though a lot of documentation still mentions them). They still work but will have some issues with HTML5. It is recommended to use either of the equivalent forms:
Original:
<lift:surround with="default" at="content">...</lift:surround>
HTML5:
<span data-lift="surround?with=default;at=content"></span>
<span class="lift:surround?with=default;at=content"></span>
If you want to use the lift: variety, the biggest issue you'll find is that in HTML5 the tags and attributes are converted to lowercase, so <lift:helloWorld.howdy /> will be interpreted as <lift:helloworld.howdy />, and Lift will not find the snippet. Using <span data-lift="helloWorld.howdy"></span> should allow you to work around that.
Maybe adding the header will help?
<html>
<head>...
Example:
https://github.com/lift/lift_25_sbt/blob/master/scala_29/lift_basic/src/main/webapp/index.html
In general, you use a very old approach to templates, with custom tags <lift:surround>, <lift:helloWorld> and such. Where did you get them? I suggest to use the new template style like in the link I posted.