<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.js"></script>
<script src="script.js"></script>
</head>
<body spa-domain="menu">
<header><nav><ul><li spa-repeat="item in menu"></ul></nav></header>
<section spa-insert="content"></section>
</body>
</html>
require.config({
paths : {
jquery : '//cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery',
}
});
require(['app'], function(app) {
app.init(); // <==== this starts your website build
});
a:link {
color: cadetblue;
text-decoration: none;
}
a:hover {
color: cornflowerblue;
text-decoration: underline;
}
ul {
list-style: none;
}
header > nav.navbar {
background-color: gainsboro;
}
header > nav .nav-header > a.navbar-brand:not(:hover),
header > nav .nav-header > a.navbar-brand:hover {
font-size: 2rem;
font-weight: 900;
letter-spacing: 2px;
color:white;
}
header > nav ul > li {
cursor: pointer;
height: 2rem;
font-size: 1.5rem;
}
header > nav ul > li a:hover {
text-decoration: none;
}
.route {
text-align:center;
display: block;
margin: 0 auto;
}
.rt-i {
margin-left: 1.3rem;
zoom: 400%;
display: inline-block;
}
.rt {
text-align: center;
display: block;
}
.rt-info {
width: 8rem;
margin-left: 7rem;
opacity: 0.3;
}
define('app', ['require', 'jquery', 'menu', 'content', 'otherstuff', 'route'],
function(require, $, menu, content, otherstuff, route) {
return {
init : function() {
console.info('\'app\' loading')
$('[spa-domain]').hide()
otherstuff.load_css('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css')
route.init();
menu.init();
content.init();
otherstuff.init();
$('[spa-domain]').show()
}
}
}
);
define('menu', ['jquery', 'content'], function ($, content) {
return {
init: function () {
console.info('[controller: menu] loaded')
$('[spa-insert]').each(e => {
let i = $(e).attr('spa-insert')
if( i in content ) {
$(e).insert(content[i])
}
})
$('nav').addClass('navbar navbar-default navbar-static-top')
$('nav > ul').addClass('nav navbar-nav')
$('[spa-repeat]').each(function () {
switch ($(this).attr('spa-repeat')) {
case "item in menu":
$(this).parent().before('<div class="nav-header" class="col-md-2"><a class="navbar-brand" href="#">requireJS-SPA</a></div>')
$('.nav-header').append($(this).parent())
let lis = ''
for (k in content.menu) {
lis = `${lis}<li><a href="${content.menu[k].href}">${content.menu[k].innerText}</a>`
}
$(this).replaceWith(lis)
}
})
}
}
});
define('content', ['jquery'], function ($) {
return {
page_content: 'As requested in comments to the answer of the stackoverflow question <a href="http://stackoverflow.com/questions/32238659/how-to-make-spa-using-javascript-jquery-and-require-js/32238951#32238951">How to make spa using javascript, jquery and require,js</a>. This page should be previewed in windowed mode! So click the little pop-out button if you haven\'t already.',
menu: {
stackoverflow: {innerText: 'stackoverflow', href:'//stackoverflow.com'},
github: {innerText: 'github', href: '//github.com'}
},
init: function () {
console.info('[model: content] loaded')
}
}
});
define('otherstuff', ['jquery', 'content', 'route'],
function($, content, route) {
/* This load CSS stuff would definitely fit better in the app.js,
but for clarity of the example I am keeping it here. */
return {
load_css: function(url) {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;
document.getElementsByTagName("head")[0].appendChild(link);
},
init: function() {
console.info('[controller: otherstuff] loaded')
$('<a class="route" href="#vis">Show me the money!</a><img class="route" src="http://i.imgur.com/Ssns07U.jpg" />')
.insertBefore('section[spa-insert]')
$('img.route').css('visibility', 'hidden')
$('section[spa-insert=content]').addClass('col-md-6 col-md-offset-3').html(content.page_content)
$('<div class="rt-info"><span class="rt-i glyphicon glyphicon-chevron-up" aria-hidden="true"></span> <span class="rt glyphicon-class">this is a route too!</span></div>').insertAfter('header > nav')
route.when('vis',
function() {
console.log('#vis called')
$('img.route').css('visibility', 'visible')
},
function() {
console.log('destroy on #vis called')
$('img.route').css('visibility', 'hidden')
}
)
}
}
}
);
define('route', ['jquery'], function ($) {
return {
routes: {},
when: function (hash, callback, destroy) {
this.routes[hash] = {callback:callback, destroy:destroy}
},
current_destroy: function(){},
init: function () {
route = this
$(document).ready(function() {
$(window).bind( 'hashchange', function(e) {
var anchor = document.location.hash.substring(1)
if(typeof route.current_destroy === 'function') {
route.current_destroy()
}
if (anchor in route.routes) {
route.routes[anchor].callback()
route.current_destroy = route.routes[anchor].destroy
}
})
})
}
}
})