I just bought a HTML landing page and I am totally newbie with all of this...
There are 3 different folders :
/windows /ios /android
How can I use nodejs and express to display the landing page?
I mean, how to redirect the client to /ios if he uses an iPhone for example.
#Detuned posted some really good links that answer your question.
Basically, you'd want to check the userAgent and render a page based on where they're coming from.
The userAgent names aren't correct, or shouldn't be since i've not checked them but i'd expect something similar to this :
app.get('/', function(req, res) {
var userAgent = req.headers['user-agent'];
if (userAgent.startsWith('Mozilla') || userAgent.startsWith('Chrome') || userAgent.startsWith('Explorer')) {
res.render('index_windows', {})
} else if (userAgent.startsWith('iOS')) {
res.render('index_ios', {})
} else if (userAgent.startsWith('android')) {
res.render('index_android', {})
}
else {
res.render('index_windows', {})
}
});
This basically grabs the / which is your home url like www.example.com/ and does a check on the headers to determine where the user has come from.
There are two ways of going about this: you would detect the browser/platform type on the client side (here) or server side (here). You would, then, send that information over to the server side so that you can render the appropriate static assets based on that information.
For rendering static assets in Node.js, refer here
Related
I am currently developing a website that will dynamically load the page content using ajax triggered by hash changes.
The code looks like this
$("*").delegate("a", "click", function () {
// Trigger Hash Change
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function () {
let newHash = window.location.hash.substring(1);
$("#main-content").load(newHash + " #ajax-content", function (responseTxt, statusTxt, xhr) {
}).hide().fadeIn();
});
Basically what I am working on now is making the URL look "Pretty", I have modified the .htaccess file to remove the .html extension
So a URL that looks like this
www.example.com/about.html
will become this
www.example.com/about
If I navigate the index (home) "www.example.com" page of the website and then navigate from there to the about page, the URL looks fine. "www.example.com#about" since the server does not display the "index" in the URL.
However, if I navigate straight to the about page like this www.example.com/about, then from the about page to another page, for example, the contact page. I get a URL that looks like this www.example.com/about#contact. When it should look like this www.example.com#contact.
My question is what is the best way to handle this? should I use jquery to redirect all to the index page and then add the hash to load the correct content? or is there some way I can not display the unnecessary part of the URL?
I hope my question was clear, I'm new to the server-side stuff involving the .htaccess file. FOr the ajax stuff I was following this tutorial from CSS tricks
https://css-tricks.com/video-screencasts/85-best-practices-dynamic-content/
You can use history.pushState
window.history.pushState("object or string", "Title", "/new-url");
The url will be www.example.com/new-url
in fact you can get history.state after use this method.
console.log(window.history.state)
output should be "object or string"
You can see the docs here.
Remember to use / to override the entire path.
To do what i think that you want, you can just override the url to / and set the hash.
This is probably not the best way to do this, but I have managed to redirect any page to the home page and then replace the / with the hash value so that the site wont end up wit "messy" URLs.
if(window.location.pathname != "/home.html")
{
window.location.replace("home.html" + window.location.pathname.replace("/", "#"));
}
what happens id the user navigates to "*www.example.com/about*" they will actually be sent to the homepage with the #about.html. So the never end up like this "*www.example.com/about#about*"
In my Onsen app I have the following splitter. I am using Jade, and rendering all the other pages from the list items in html (despite the fact that they are in separate jade files) by including the files at the bottom of the page, as shown below:
body(ng-controller='...')
ons-splitter(var='mySplitter')
ons-splitter-side(var='menu' side='left' width='220px' collapse swipeable)
ons-page
ons-list
ons-list-item(ng-click="root.load('home.jade')", tappable='')
| Home
ons-list-item(ng-click="root.load('search.jade')", tappable='')
| Search
... more list items
ons-template(id='home.jade')
ons-page(ng-controller='...')
ons-toolbar
.left
ons-toolbar-button(ng-click='mySplitter.left.open()')
ons-icon(icon='md-menu')
.center
| My App
//- google maps stuff
ons-input#pac-input.controls(type='text', placeholder='Search Box')
div#map.col-md-12
ons-bottom-toolbar
.center
| MyApp
include search.jade
I believe this is a dirty shortcut, and will load the contents of search.jade (as well as every other file I include) before the user even clicks the item in the splitter.
I do not want this functionality. I would like to instead have server code in NodeJs that renders the jade files in html when they are ready to be displayed to the user. Something like this:
jade.renderFile('search.jade')
This angular code is currently how I am loading the page from the item in the splitter:
mySplitter.content.load(page)
.then(function() {
$scope.pop = page;
mySplitter.left.close();
});
However I am very confused about how to write this in a node route. Do I just abandon the splitter function in angular?
Can anyone help clarify this for me and show me a clear example of how to write the node route to render the jade files as html each time they are loaded?
Please see solution 1 of the selected answer from this stack overflow post for a reference of what exactly I am trying to do: stack overflow post
I am currently using solution 2 from that post.
I believe this is the relevant code in server.js:
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
However when I change jade to html, I receive the error:
Error: Cannot find module 'html'
All my front-end files in the views folder have .jade extensions and are written in jade.
Update
Here is how I am serving index.jade (which is in the views folder) in a file called index.js:
module.exports = function(app){
/* Get home page. */
app.get('/', function(req, res, next) {
res.render('index', { title: 'My App' });
});
}
This was my old route NodeJS route which is no longer being used because of the splitter:
// get user search page
app.get('/user/search', function(req, res, next) {
return res.render('searchForTrainer');
});
Hmm. Since your code seems relatively small I would guess that what it does may be just serving all your files from views and actually "rendering" them. So probably you are just failing to access them properly later on. Maybe you have a url like /search.html or /search (instead of /search.jade). Could you try to confirm whether you can access such a url?
Also is your index.jade file served in some other way like startingPoint: 'index.jade' or something similar or is it also located in the views folder?
Basically as long as your index file has the same treatment as your other views then everything should be fine.
Update:
With what you just provided we can see the way in which you are serving your index.
app.get('/', function(req, res, next) {
res.render('index', { title: 'Fitness App' });
});
The equivalent of that is exactly the same as what you said you had before:
app.get('/user/search', function(req, res, next) {
return res.render('searchForTrainer');
});
Here res.render is what converts your jade into html and then returns it to the client. Since the splitter is expecting html that means you shouldn't have made changes to the server when you started using it.
Here is how the process looks like:
Client | HTTP | Server
| |
content.load('page') → GET /page ↘
| | res.render('page') // convert jade to html
html is loaded ← 200 OK html content ↙
in splitter.content | |
TL;DR - if you use your old route everything should be fine. Just remember to change the page url in the splitter from search.jade to /user/search (or whatever the url for will be).
If I have an application in WebPages, I would like to know how to enable multi-site capabilities? I understand the _SiteLayout.cshtml file or what not can handle the template for one site, but how about if I wanted to change that for a different site? The different site would be passed to the application by ServerVariable (domain name), so I'm assuming there would need to be some type of controller in place to handle this? But WebPages doesn't have controllers and I'm not learning MVC now. What would be my options at this point? Thank you.
You could check the requested domain and then select the layout page, like this:
#{
if (Request.Url.Host == "domain1.com")
{
Layout = "/Shared/_Layout1.cshtml";
}
else if (Request.Url.Host == "domain2.com")
{
Layout = "/Shared/_Layout2.cshtml";
}
else
{
Layout = "/Shared/_Layout.cshtml";
}
}
Having a tough time doing a simple web site in EJS.
I have this set up in my server file:
//Use the .html extension instead of having to name the views as *.ejs
server.engine('.html', require('ejs').__express);
// This avoids having to provide the extension to res.render()
server.set('view engine', 'html');
//set up directory to serve css and javascript files
server.use(Express.static(__dirname, '/views'));
This works great. I have HTML files, I have graphics, I have CSS. I am serving it up with a simple controller that renders the page. Nothing dynamic in these pages. But I do want them protected with an id/password system, and only served up through Express.
The access works fine, I have an end point set up to serve them. I'm forcing log in in that end point. But the problem is, that if someone knows the actual path to those files, they can get at them. So, the access is localhost:8081/admin/documentation/. However, the files are at /views/app_documents. And by entering in localhost:8081/views/app_documents/file_name.html, they can download/view the content, without going through my controls. I moved the content out of views, and grab it in my code, and serve it up, but that doesn't work for images or CSS.
Any suggestions for how to get around this?
Well, the things you find out after the fact.
This:
server.use(Express.static(__dirname, '/views'));
Is very bad. It should be:
server.use(Express.static('./views'));
The way it was, you could download our code, also. So, server.js was available for download. Yikes.
Live and learn.
Still can download the content without going through my authentication, though.
In case anyone else wants to do this, took a while. There are a few problems, as you still need to be able to directly access JS libraries, images and CSS. I found my answer in enter link description here.
The following modifications to that code does the trick. UserIsAllowed checks my permissions system to see if they can access that folder. If they can, no harm, off you go. Otherwise, kill the attempt. They get ACCESS_DENIED back as a string. I can't just kill anyone not going through my code, because then the CSS and images would not work. But this functions nicely. I now am able to serve up content based on my custom permissions system, which is part of a bunch of other administration functions. I can also have multiple different areas based on the URL that are protected by different privileges.
// This function returns a middleware function. It checks to see if the user has access
var protectPath = function(regex)
{
return function(request, response, next)
{
if (!regex.test(request.url)) { return next(); }
userIsAllowed(regex,function(allowed)
{
if (allowed)
{
next(); // send the request to the next handler, which is express.static
}
else
{
response.end('ACCESS_DENIED');
}
});
function userIsAllowed(regex,callback) {
if (regex.test('documentation_website') && request.session.admin_me && _.contains(request.session.admin_me["privileges"],"view_server_documentation")) callback(true);
else callback(false);
}
};
};
server.use(protectPath(/^\/documentation_website\/.*$/));
I am trying to use HTML5 Appcache to speed up my web-mobile app by caching images and css/JS files. The app is based on dynamic web pages.
As already known – when using Appcache the calling html page is always cached -> bad for dynamic websites.
My solution - Create a first static page and in this page call the manifest file (manifest="cache.appcache") and load all my cached content. Then when the user is redirected to another dynamic page the resources will already be available. (Of course this second dynamic page will not have the manifest tag).
The problem is that if the second page is refreshed by the user, the resources are not loaded from the cache; they are loaded directly from the server!
This solution is very similar to using an Iframe on the first dynamic file. I found that the Iframe solution have the exact same problem.
Is there any solution for that? Can Appcache really be used with dynamic content?
Thanks
Yes appcache can be used for dynamic content if you handle you url parameters differently.
I solved this by using local storage (I used the jquery localstorage plugin to help with this).
The process is
Internally from the page when you would normally href from an anchor or redirect, instead call a function to redirects for you. This function stores the parameters from the url to localstorage, and then only redirects to the url without the parameters.
On the receiving target page. Get the parameters from localstorage.
Redirect code
function redirectTo(url) {
if (url.indexOf('?') === -1) {
document.location = url;
} else {
var params = url.split('?')[1];
$.localStorage.set("pageparams", params);
document.location = url.split('?')[0];
};
}
Target page code
var myParams = GetPageParamsAsJson();
var page = myParams.page;
function GetPageParamsAsJson() {
return convertUrlParamsToJson($.localStorage.get('pageparams'));
}
function convertUrlParamsToJson(params) {
if (params) {
var json = '{"' + decodeURI(params).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}';
return JSON.parse(json);
}
return [];
}
I had a hell of a time figuring out how to cache dynamic pages accessed by a URI scheme like this:
domain.com/admin/page/1
domain.com/admin/page/2
domain.com/admin/page/3
Now the problem is that the appcache won't cache each individual admin/page/... unless you visit it.
What I did was use the offline page to represent these pages that you may want to allow a user to access offline.
The JS in the offline page looks up the URI and scrapes it to find out which page it should show and fetches the data from localStorage which was populated with all the page data when the user visited the admin dashboard before being presented with the links to each individual page.
I'm open to other solutions but this is all I could figure out to bring a bunch of separate pages offline with only visiting the single admin page.