I have just started using page.js, a routing library that I intend to use to make a single page application with handlebars. I will use the routes to call different handlebar templates. So far, this functionality is working and is as quick as I had hoped.
I am currently encountering an issue where refreshing the page (pressing F5) or copying the URL, and pasting it into a new tab gives me a 404 not found error. It is not calling the not found page that I created in my app.
The code below is a copy of: https://github.com/visionmedia/page.js/tree/master/examples/notfound
<!DOCTYPE html>
<html>
<head>
<title>Not Found</title>
<script src="/page.js"></script>
</head>
<body>
<h1>Not Found</h1>
<p></p>
<ul>
<li>/</li>
<li>/about</li>
<li>/contact</li>
<li>/not-found</li>
</ul>
<script>
page.base('/notfound');
page('/', index);
page('/about', about);
page('/contact', contact);
page('*', notfound);
page();
function index() {
document.querySelector('p')
.textContent = 'viewing index';
}
function about() {
document.querySelector('p')
.textContent = 'viewing about';
}
function contact() {
document.querySelector('p')
.textContent = 'viewing contact';
}
function notfound() {
document.querySelector('p')
.textContent = 'not found';
}
</script>
</body>
When I refresh this page, I am presented with my localhost's 404 page. I get the same result when I use the link http://127.0.0.1/notfound/about.
My question is this: does page.js support refreshing the browser, or using links to access specific portions of my application?
It seems that the question I should really be asking is this: Would it be possible for the web server to redirect all navigation to the page that loads the application? The answer is Yes.
It seems that refreshing the browser would be a common case. An acceptable solution to this would also be to catch any refresh attempts, and redirect them to the main page. Using links to access specific portions of my application is not as crucial, but would be a nice touch.
Related
I am building a flask website and am trying to make a search bar that is always on the top menĂ¹, I would have liked to handle it in the Python backend but I could not find a way to do that without including whithin each backed page the code to handle it (which if it is the only way is fine) so I decided to try making it work with JavaScript. This is my code (without the parts which I found unrelated to the problem):
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form>
<input type="search" id="searchbar"/>
<button id="goto">Search</button>
</form>
<script>
document.getElementById("goto").addEventListener("click", goTo);
function goTo()
{
var result = document.getElementById("searchbar").value;
window.location.href = "/users/"+result;
}
</script>
</body>
</html>
What it is supposed to do is redirect me to "http://myip/users/WhatItyped" while it just adds "/?" to the end of the URL, any idea of why this is?
Update: I found out that if I add an alert before defining result it works
Try using window.location.pathname
JavaScript Window Location states href points to the full URL, including protocol & hostname. Since you are not changing either of those, you can just change the relative path from the root using pathname.
This has also been answered before:
How can I extract and then change the url path using javascript?
Update
I found 'webview.executeScript' however, I can't access any of the custom functions.
This is a major step forward though. Any suggestions welcome.
Original post
We developed a Kiosk Web Extension for Chrome OS that loads an externally hosted webpage. The page is loaded into a webview. This page display dynamic information that gets updated daily. In order to push "manual" updates out to the page, we maintain an open WebSocket connection to the Kiosk app. This allows us to refresh the page, update the page, push information, etc. However, we need to access either the javascript loaded inside the webview or we need to access the elements. I'm not sure if I'm explaining this right, or if it is possible to do what I am asking.
Right now we are opening two connections to the websocket server. One is from the webpage and the other is from the extension. The goal is to cut down to one connection.
I added pseudo code to give an idea of what is I need to do.
Chrome Web Extension Kiosk index.html
<html>
<head>
<title></title>
</head>
<body>
<div id="page">
</div>
</body>
</html>
Kiosk example background js
(note: I know this wouldn't be doable via jquery)
document.onLoad({
$("#page").html('<webview id="browser" src="example.com"></webview>');
});
function ReceiveWebSocketMessage(msg) {
switch (msg.cmd) {
case "updatedate":
$("browser").UpdateDate(msg.data);
break;
case "reboot":
chrome.runtime.RebootDevice();
break;
}
}
Webpage example.com
<html>
<head>
<title></title>
</head>
<body>
<div id="datetime">
1/1/2016
</div>
</body>
</html>
Webpage example JS http://example.com/app.js
function UpdateDate(newdate) {
$("#datetime").html = newdate;
}
I threw together a quick diagram of what the old design is like and what the new design is.
To sum it up, I need to access functions that are on the external page. I've not had luck trying to accomplish it.
Resolved! I found the following examples:
https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/webview-samples/shared-script
Basically I added this to my code:
function Execute(code) {
var webview = document.querySelector('webview');
webview.executeScript({
code: generateScriptText(code)
});
}
function generateScriptText(fn) {
var fnText = fn.toString()
.replace(/"/g, '\\"') // Escape double-quotes.
.replace(/(\r?\n|\r)/g, '\\n'); // Insert newlines correctly.
var scriptText =
'(function() {\n' +
' var script = document.createElement("script");\n' +
' script.innerHTML = "(function() { (' + fnText + ')(); })()" \n' +
' document.body.appendChild(script);\n' +
'})()';
return scriptText;
}
I am using a $_GET function to load content into the website,
what I want to do is add a Loading image into all that mess.
Right now it looks like it opens a whole new page.
Code:
<?php
if (isset($_GET['page']) || isset($_POST['page'])) {
$page = trim(isset($_POST['page']) ? $_POST['page'] : $_GET['page']);
if (preg_match("/a-z/", $page)) {
}
} else {
$page = "index";
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<div id="navigation">
<ul class="nav-items">
<li>Home</li>
<li>Test</li>
<li>Beta</li>
</ul>
</div>
<div id="content">
<?
if ($page != '')
include('pages/'.$page . '.php');
else
{
include('pages/error.php');
}
?>
</div>
</body>
</html>
Now, it works perfectly but I'd want it to show a Loading... image while loading the content , and instead of reloading whole page would be great to load the content div ONLY.
I did not try javascript solution since I didn't find anything that would work correctly and would keep the links working (for example http://example.com/index.php?page=test with already loaded the text.php file from pages folder). Plus I'm a real newbie in javascript so I have no idea what to start with.
The only solution to this problem is with JavaScript because PHP will only execute on the server and will only present HTML on the client side.
If you understand the HTTP request/response system, you will know that a request is sent to the server and then the server responds back with the page content, which will be the HTML (and CSS and any client-side scripts such as JavaScript). This method normally means having to reload the page but if you use AJAX (Asynchronous JavaScript and XML), this acts as a layer between the client and the server, allowing the user to request content without having to reload the page.
The most simple way of doing this is with jQuery. Be sure to include the jQuery library and put your code inside the $(document).ready(); function so that it executes when the page has finished loading.
Fortunately, this particular task is fairly simple, although it will require restructuring your website/application slightly. You will need to have the content echoed or printed onto a different page with PHP.
On your main page that will be used and seen by the users, you would simply write $("#container").load("page.html"); where container is the id of the container you want to load the content into.
If you want different content to be loaded with different buttons, you could do this (as long as you give your links the correct ids:
$(document).ready(function() {
$("#alpha").onclick(function() {
$("#container").load('page.html?page=alpha');
});
$("#beta").onclick(function() {
$("#container").load('page.html?page=beta');
});
});
Edit: I'm so sorry, I missed out the important part about the loading image, but the other answer demonstrates this well, so there is no point in repeating it.
It looks like it is opening a whole new page because it is. Your only option would be javascript. If I were wanting to do this, I would always only load the index page with nothing in your content div except the loading icon. Then once the page is loaded have jquery read the get variable and make an ajax request for the content of the page and load it into the div.
<div id="content">
<div id='page'></div>
</div>
Then, to make it easier on you since you are unfamiliar with javascript I would include the following jquery plugin: https://github.com/allmarkedup/purl
then in .js file:
$( document ).ready(function() {
var loading_annimation = "<div class='loading'></div>";
var page = $.url().param("page");
if(page){
$('#page').load(loading_annimation ).load('/special_php_file_that_includes_JUST_content.php?page='+page);
} else {
$('#page').load(loading_annimation ).load('/special_php_file_that_includes_JUST_content.php?page=index');
}
$(document).on('click','.link', function(e){
e.preventDefault();
var page = $(this).attr("data-link");
$('#page').load(loading_annimation ).load('/special_php_file_that_includes_JUST_content.php?page='+page);
});
});
Then you will need to change your links to do something like this:
<a class='link' data-link='beta' href="/index.php?page=beta">Beta</a>
Here is the code of my "app.js" :
var app = angular.module('WebUI',[]);
app.config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
app.config(function($locationProvider){
$locationProvider.html5Mode(true);
});
Here is the code of my controller :
var Controller = function ($scope,$http)
{
$scope.thingsList=[];
$http({method: 'GET', url: 'http://192.168.1.4/search'}).success(function(data)
{
results=data.results;
angular.forEach(results,function(result)
{
$scope.thingsList.push(result.split('/')[1]);
});
}).error(function(data){});
}
Here is the code of my HTML page :
<!DOCTYPE html>
<head>
<title>All</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<script src="controller.js" type="text/javascript"></script>
</head>
<body>
HOME
<div id='content' ng-app='WebUI' ng-controller='Controller'>
<li ng-repeat="thing in thingsList">
{{thing}}
</li>
</div>
</body>
</html>
The point here is that I am generating the links using ng-repeat and the list that I get from my controller.js. But what happens is that : When I click "HOME" it gets redirects to the home page and when I click any of the "thing" i.e. generated link, then it throws an error :
Error: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///home/abc/home.html' cannot be created in a document with origin 'null'.
I tried searching online for this error but could not find anything useful. So if anybody knows where the problem is, please help :)
A history state object with URL 'file:///home/abc/home.html' cannot be created in a document with origin 'null'.
Seems you're using angular routing on file urls, and without a server.
Try with a server.
Actually found the answer to my own question.
I searched online and found that generating too many "file:///" links cause a security issue that's why they are not allowed.
Then I tried hosting it on a server http:// and testing, then the URL changed, but the page was not refreshed...so again error.
Then I found out that
`app.config(function($locationProvider){
$locationProvider.html5Mode(true);
});`
This portion of code was throwing errors due to which I was unable to use ng-route and other things.
But location needed this code to parse the get parameters in the URL, so I took reference from What's the most concise way to read query parameters in AngularJS? and I was able to pass the get parameters in the URL using another way like : url#/?target=bob and I was able to parse the parameters now.
So problem solved. $location was able to parse the parameters and I was also now able to access the links which earlier gave error.
try using ng-href
https://docs.angularjs.org/api/ng/directive/ngHref
Hope this helps.
Try using window location:
<li ng-repeat="thing in thingsList">
<a ng-click="gotoHome()">{{thing}}</a>
</li>
In JS,
$scope.gotoHome = function(){
window.location="#/home";
//Give your link above.
}
Hope it helps...
I am trying to use director.js for the routing on my single page application. The issue is when you go to a page by typing it into the address bar the application does not perform the function that the hash in the routing table is pointed to.
Here is the example on github - If I refresh the page with a hash or direct to a page with a hash nothing shows up in the console. But if I click on one of the links console output is shown. How can I change this code so that if a user directly goes to a link the routing table checks the hash and performs it's matching function from the routing table? Please answer with a methodology that utilizes director.js
<html>
<head>
<meta charset="utf-8">
<title>A Gentle Introduction</title>
<script src="https://raw.github.com/flatiron/director/master/build/director.min.js"></script>
<script>
var author = function () { console.log("author"); },
books = function () { console.log("books"); },
viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); };
var routes = {
'/author': author,
'/books': [books, function() { console.log("An inline route handler."); }],
'/books/view/:bookId': viewBook
};
var router = Router(routes);
router.init();
</script>
</head>
<body>
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
</ul>
</body>
</html>
I have not used Director but your issue may be the fact that GitHub serves the "raw" files with a mime type of "text/plain". So the Director js code might not be processed as javascript, causing your test page not to work. Try downloading your own copy of Director and link to the local version instead of the one on GitHub.