Commit 548e90a6 authored by Thomas Lechauve's avatar Thomas Lechauve

New feature: Can start or stop an instance

You can now change the state of an instance with buttons.
There is also an autorefresh every 30 seconds to update all parameters
in the instance's form.
parent 7f1b6510
(function ($) { (function ($) {
"use strict"; 'use strict';
var methods = { var methods = {
init: function (options) { init: function (options) {
var settings = $.extend({ var settings = $.extend({
...@@ -38,13 +38,13 @@ ...@@ -38,13 +38,13 @@
/* Cookie storage method */ /* Cookie storage method */
cStore: function (name, value) { cStore: function (name, value) {
if (value !== undefined) { if (value !== undefined) {
document.cookie = name + "=" + value + ";domain=" + window.location.hostname + ";path=" + window.location.pathname; document.cookie = name + '=' + value + ';domain=' + window.location.hostname + ';path=' + window.location.pathname;
} else { } else {
var i, x, y, cookies = document.cookie.split(';'); var i, x, y, cookies = document.cookie.split(';');
for (i = 0; i < cookies.length; i += 1) { for (i = 0; i < cookies.length; i += 1) {
x = cookies[i].substr(0, cookies[i].indexOf('=')); x = cookies[i].substr(0, cookies[i].indexOf('='));
y = cookies[i].substr(cookies[i].indexOf('=') + 1); y = cookies[i].substr(cookies[i].indexOf('=') + 1);
x = x.replace(/^\s+|\s+$/g, ""); x = x.replace(/^\s+|\s+$/g, '');
if (x === name) { if (x === name) {
return unescape(y); return unescape(y);
} }
...@@ -54,15 +54,14 @@ ...@@ -54,15 +54,14 @@
statusDefault: function () { statusDefault: function () {
return { return {
0: function () { console.error("status error code: 0"); }, 0: function () { console.error('status error code: 0'); },
404: function () { console.error("status error code: Not Found !"); }, 404: function () { console.error('status error code: Not Found !'); },
500: function () { console.error("Server error !"); } 500: function () { console.error('Server error !'); }
}; };
}, },
request: function (type, authentication, args) { request: function (type, authentication, args) {
var statusCode; var statusCode, data;
var data;
if (args.hasOwnProperty('statusCode')) { if (args.hasOwnProperty('statusCode')) {
statusCode = args.statusCode || methods.statusDefault(); statusCode = args.statusCode || methods.statusDefault();
} else { } else {
...@@ -73,7 +72,7 @@ ...@@ -73,7 +72,7 @@
} else { } else {
data = undefined; data = undefined;
} }
delete args.data delete args.data;
$.extend(args, {statusCode: statusCode}); $.extend(args, {statusCode: statusCode});
return this.each(function () { return this.each(function () {
var ajaxOptions = { var ajaxOptions = {
...@@ -83,9 +82,11 @@ ...@@ -83,9 +82,11 @@
datatype: 'json', datatype: 'json',
context: $(this), context: $(this),
beforeSend: function (xhr) { beforeSend: function (xhr) {
if ($(this).slapos("access_token") && authentication) { xhr.setRequestHeader('REMOTE_USER', 'test_vifib_customer');
xhr.setRequestHeader("Authorization", $(this).slapos("store", "token_type") + " " + $(this).slapos("access_token")); xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader("Accept", "application/json"); if ($(this).slapos('access_token') && authentication) {
//xhr.setRequestHeader('Authorization', $(this).slapos('store', 'token_type') + ' ' + $(this).slapos('access_token'));
//xhr.setRequestHeader('Accept', 'application/json');
} }
} }
}; };
...@@ -96,8 +97,9 @@ ...@@ -96,8 +97,9 @@
prepareRequest: function (methodName, args) { prepareRequest: function (methodName, args) {
var $this = $(this); var $this = $(this);
return this.each(function(){ args = args || {};
$(this).slapos('discovery', function(access){ return this.each(function () {
$(this).slapos('discovery', function (access) {
if (access.hasOwnProperty(methodName)) { if (access.hasOwnProperty(methodName)) {
var url = args.url || access[methodName].url; var url = args.url || access[methodName].url;
$.extend(args, {'url': url}); $.extend(args, {'url': url});
...@@ -107,16 +109,16 @@ ...@@ -107,16 +109,16 @@
args); args);
} }
}); });
}) });
}, },
discovery: function (callback) { discovery: function (callback) {
return this.each(function(){ return this.each(function () {
$.ajax({ $.ajax({
url: "http://10.8.2.34:12002/erp5/portal_vifib_rest_api_v1", url: 'http://10.8.2.34:12006/erp5/portal_vifib_rest_api_v1',
dataType: "json", dataType: 'json',
beforeSend: function (xhr) { beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader('Accept', 'application/json');
}, },
success: callback success: callback
}); });
...@@ -134,7 +136,7 @@ ...@@ -134,7 +136,7 @@
}, },
instanceRequest: function (args) { instanceRequest: function (args) {
return $(this).slapos('prepareRequest', 'request_instance', args) return $(this).slapos('prepareRequest', 'request_instance', args);
} }
}; };
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
<script id="instance" type="text/html"> <script id="instance" type="text/html">
{{! Service page template }} {{! Service page template }}
<article> <article>
<form class="form-horizontal"> <form class="form-horizontal" id="instance-form">
<fieldset> <fieldset>
<legend> <legend>
{{ title }} {{ title }}
...@@ -87,41 +87,36 @@ ...@@ -87,41 +87,36 @@
<div class="control-group"> <div class="control-group">
<label class="control-label">Reference</label> <label class="control-label">Reference</label>
<div class="controls"> <div class="controls">
<span class="uneditable-input">{{ title }}</span> <input name="title" type="text" value="{{ title }}" readOnly></input>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">Software release</label> <label class="control-label">Software release</label>
<div class="controls"> <div class="controls">
<span class="uneditable-input">{{ software_release }}</span> <input type="text" name="software_release" value="{{ software_release }}" readOnly></input>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">Software type</label> <label class="control-label">Software type</label>
<div class="controls"> <div class="controls">
<span class="uneditable-input">{{ software_type }}</span> <input type="text" name="software_type" value="{{ software_type }}"></input>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">Status</label> <label class="control-label">Status</label>
<div class="controls"> <div class="controls" id="instanceStatus">
<div class="btn-group"> {{{ status }}}
<button class="btn" id="stopInstance">Stop</button>
<button class="btn btn-success disabled" id="startInstance">Started</button>
</div>
</div> </div>
</div> </div>
</fieldset> </fieldset>
</form>
<table class="table"> <table class="table">
<caption>Connection parameters</caption> <caption>Connection parameters</caption>
{{# connection}} {{# connection}}
<tr><td>key</td><td>{{ key }}</td></tr> <tr><td>{{.}}</td><td>{{ key }}</td></tr>
{{/ connection}} {{/ connection}}
</table> </table>
<form>
<fieldset> <fieldset>
<legend> <legend>
Parameter XML Parameter XML
...@@ -142,6 +137,27 @@ ...@@ -142,6 +137,27 @@
</article> </article>
</script> </script>
<script id="instance.stop_requested" type="text/html">
<div class="btn-group">
<button class="btn btn-danger disabled" disabled="disabled" id="stopInstance">Stopped</button>
<button class="btn" id="startInstance">Start</button>
</div>
</script>
<script id="instance.draft" type="text/html">
<div class="btn-group">
<button class="btn disabled" disabled="disabled">Stop</button>
<button class="btn disabled" disabled="disabled">Start</button>
</div>
</script>
<script id="instance.start_requested" type="text/html">
<div class="btn-group">
<button class="btn" id="stopInstance">Stop</button>
<button class="btn btn-success disabled" disabled="disabled" id="startInstance">Started</button>
</div>
</script>
<script id="simple-form" type="text/html"> <script id="simple-form" type="text/html">
<form class="form-inline"> <form class="form-inline">
<fieldset> <fieldset>
...@@ -222,6 +238,6 @@ ...@@ -222,6 +238,6 @@
<script type="text/javascript" src="static/js/jquery.slapos.js"></script> <script type="text/javascript" src="static/js/jquery.slapos.js"></script>
<!--<script type="text/javascript" src="static/js/fake.js"></script>--> <!--<script type="text/javascript" src="static/js/fake.js"></script>-->
<script type="text/javascript" src="static/js/urlHandler.js"></script> <script type="text/javascript" src="static/js/urlHandler.js"></script>
<script type="text/javascript" src="static/js/form.js"></script> <script type="text/javascript" src="static/js/core.js"></script>
</body> </body>
</html> </html>
...@@ -28,7 +28,7 @@ var comp1 = {computer_id: "COMP-1", ...@@ -28,7 +28,7 @@ var comp1 = {computer_id: "COMP-1",
var inst0 = var inst0 =
{instance_id: "INST-0", {instance_id: "INST-0",
status: "start", status: "start_requested",
software_release: "http://example.com/example.cfg", software_release: "http://example.com/example.cfg",
software_type: "type_provided_by_the_software", software_type: "type_provided_by_the_software",
slave: "False", slave: "False",
...@@ -49,7 +49,7 @@ var inst0 = ...@@ -49,7 +49,7 @@ var inst0 =
var inst1 = var inst1 =
{instance_id: "INST-1", {instance_id: "INST-1",
status: "start", status: "stop_requested",
software_release: "http://example.com/example.cfg", software_release: "http://example.com/example.cfg",
software_type: "type_provided_by_the_software", software_type: "type_provided_by_the_software",
slave: "False", slave: "False",
...@@ -71,11 +71,11 @@ var inst1 = ...@@ -71,11 +71,11 @@ var inst1 =
var fakeserver = sinon.fakeServer.create(); var fakeserver = sinon.fakeServer.create();
// Get instance // Get instance
fakeserver.respondWith("GET", "/instance/200",[200, {"Content-Type":"application/json; charset=utf-8"}, JSON.stringify(inst0)]); fakeserver.respondWith("GET", "/instance/stop",[200, {"Content-Type":"application/json; charset=utf-8"}, JSON.stringify(inst0)]);
fakeserver.respondWith("GET", "/instance/201",[200, {"Content-Type":"application/json; charset=utf-8"}, JSON.stringify(inst1)]); fakeserver.respondWith("GET", "/instance/start",[200, {"Content-Type":"application/json; charset=utf-8"}, JSON.stringify(inst1)]);
// Get instance FAIL // Get instance FAIL
fakeserver.respondWith("GET", "/instance/408",[408, {"Content-Type":"application/json; charset=utf-8"}, "NOT FOUND"]); fakeserver.respondWith("GET", "/instance/start",[200, {"Content-Type":"application/json; charset=utf-8"}, "NOT FOUND"]);
fakeserver.respondWith("POST", "/instance",[401, {"Content-Type":"application/json; charset=utf-8"}, "NEED AUTH"]); fakeserver.respondWith("GET", "/instance/stop",[200, {"Content-Type":"application/json; charset=utf-8"}, "NEED AUTH"]);
var tmp = $.ajax; var tmp = $.ajax;
$.ajax = function(url, options){ $.ajax = function(url, options){
......
/**
* NEXEDI
* Author: Thomas Lechauve
* Date: 4/17/12
*/
(function($) {
var routes = {
"/instance" : "requestInstance",
"/instance/:url" : "showInstance",
"/computers" : "listComputers",
"/instances" : "listInstances",
"/invoices" : "listInvoices"
}
var router = function(e, d){
var $this = $(this);
$.each(routes, function(pattern, callback){
pattern = pattern.replace(/:\w+/g, '([^\/]+)');
var regex = new RegExp('^' + pattern + '$');
var result = regex.exec(d);
if (result) {
result.shift();
methods[callback].apply($this, result);
}
});
}
var getDate = function () {
var today = new Date();
return [today.getFullYear(), today.getMonth(), today.getDay()].join('/')
+ ' ' + [today.getHours(), today.getMinutes(), today.getSeconds()].join(':');
};
var substractLists = function(l1, l2){
var newList = [];
$.each(l2, function(){
if ($.inArray(""+this, l1) == -1) {
newList.push(""+this);
}
});
return newList;
};
var redirect = function(){
$(this).vifib('render', 'auth', {
'host':'http://10.8.2.34:12002/erp5/web_site_module/hosting/request-access-token',
'client_id': 'client',
'redirect':escape(window.location.href)
})
};
var payment = function(jqxhr){
var message = $.parseJSON(jqXHR.responseText).error
$(this).vifib('popup', message, "information");
};
var notFound = function(jqxhr){
var message = $.parseJSON(jqXHR.responseText).error
$(this).vifib('popup', message);
};
var serverError = function(jqxhr){
var message = $.parseJSON(jqxhr.responseText).error
$(this).vifib('popup', message);
};
var spinOptions = {color: "#FFF", lines:9, length:3, width:2, radius:6, rotate:0, trail:36, speed:1.0};
var methods = {
init: function() {
// Initialize slapos in this context
$(this).slapos();
var $this = $(this);
// Bind Loading content
$("#loading").ajaxStart(function(){
$(this).spin(spinOptions);
}).ajaxStop(function(){
$(this).spin(false);
});
// Bind to urlChange event
return this.each(function(){
$.subscribe("urlChange", function(e, d){
router.call($this, e, d);
});
$.subscribe("auth", function(e, d){
$(this).vifib("authenticate", d);
});
});
},
genInstanceUrl: function(uri){
return location.href.split('#')[0] + "#/instance/" + encodeURIComponent(uri)
},
extractInstanceURIFromUrl: function () {
return decodeURIComponent($(this).attr('href').split('/').pop())
},
authenticate: function(data) {
for (var d in data) {
if (data.hasOwnProperty(d)) {
$(this).slapos('store', d, data[d]);
}
}
},
refresh: function(method, interval, eventName){
eventName = eventName || 'ajaxStop';
var $this = $(this);
$(this).one(eventName, function(){
var id = setInterval(function(){
method.call($this);
}, interval * 1000);
$.subscribe('urlChange', function(e, d){
clearInterval(id);
})
});
},
showInstance: function (uri) {
var statusCode = {
401: redirect,
402: payment,
404: notFound,
500: serverError
};
$(this).slapos('instanceInfo', uri, {
success: function(infos){
$(this).vifib('render', 'instance', infos);
},
statusCode: statusCode
});
},
getCurrentList: function () {
var list = [];
$.each($(this).find('a'), function () {
list.push($(this).vifib('extractInstanceURIFromUrl'));
});
return list;
},
listComputers: function(){
$(this).vifib('render', 'server.list');
},
refreshRowInstance: function(){
return this.each(function(){
var url = $(this).find('a').vifib('extractInstanceURIFromUrl');
$(this).vifib('fillRowInstance', url);
});
},
fillRowInstance: function(url){
return this.each(function(){
$(this).slapos('instanceInfo', url, {
success: function(instance){
$.extend(instance, {'url': methods.genInstanceUrl(url)});
$(this).vifib('render', 'instance.list.elem', instance);
}
});
});
},
refreshListInstance: function () {
var currentList = $(this).vifib('getCurrentList');
$(this).slapos('instanceList', {
success: function (data) {
var $this = $(this);
var newList = substractLists(currentList, data['list']);
var oldList = substractLists(data['list'], currentList);
$.each(newList, function(){
var url = this+"";
var row = $("<tr></tr>").vifib('fillRowInstance', url);
$this.prepend(row);
});
console.log("newList")
console.log(newList)
console.log("oldList")
console.log(oldList)
},
});
},
listInstances: function(){
var $this = $(this);
var statusCode = {
401: redirect,
402: payment,
404: notFound,
500: serverError,
503: serverError
};
var table = $(this).vifib('render', 'instance.list').find("#instance-table");
table.vifib('refresh', methods.refreshListInstance, 30);
$(this).slapos('instanceList', {
success: function(data){
$.each(data['list'], function(){
var url = this+"";
var row = $("<tr></tr>").vifib('fillRowInstance', url);
row.vifib('refresh', methods.refreshRowInstance, 30);
table.append(row);
});
}, statusCode: statusCode});
},
listInvoices: function(){
$(this).vifib('render', 'invoice.list');
},
instanceInfo: function (url, callback) {
$(this).slapos('instanceInfo', {
success: callback, url: url
});
},
requestInstance: function() {
$(this).vifib('render', 'form.new.instance');
var data = {};
$(this).find("form").submit(function(){
$(this).find('input').serializeArray().map(function(elem){
data[elem["name"]] = elem["value"];
});
$(this).vifib('requestAsking', data);
return false;
});
},
requestAsking: function(data){
var statusCode = {
401: redirect,
402: payment,
404: notFound,
500: serverError
};
var instance = {
software_type: "type_provided_by_the_software",
slave: false,
status: "started",
parameter: {
Custom1: "one string",
Custom2: "one float",
Custom3: ["abc", "def"],
},
sla: {
computer_id: "COMP-0",
}
};
$.extend(instance, data);
var args = {
statusCode: statusCode,
data: instance,
success: function (response) {
console.log(response);
}
};
return this.each(function(){
$(this).slapos('instanceRequest', args);
});
},
popup: function(message, state) {
state = state || 'error';
return this.each(function(){
$(this).prepend(ich['error'](
{'message': message, 'state': state, 'date': getDate()}
, true))
})
},
render: function(template, data){
return this.each(function(){
$(this).html(ich[template](data, true));
});
},
renderAppend: function(template, data){
$(this).append(ich[template](data, true));
},
renderPrepend: function(template, data){
$(this).prepend(ich[template](data, true));
}
};
$.fn.vifib = function(method){
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.vifib' );
}
};
})(jQuery);
$("#main").vifib();
(function ($) { (function ($) {
"use strict"; 'use strict';
var methods = { var methods = {
init: function (options) { init: function (options) {
var settings = $.extend({ var settings = $.extend({
...@@ -38,13 +38,13 @@ ...@@ -38,13 +38,13 @@
/* Cookie storage method */ /* Cookie storage method */
cStore: function (name, value) { cStore: function (name, value) {
if (value !== undefined) { if (value !== undefined) {
document.cookie = name + "=" + value + ";domain=" + window.location.hostname + ";path=" + window.location.pathname; document.cookie = name + '=' + value + ';domain=' + window.location.hostname + ';path=' + window.location.pathname;
} else { } else {
var i, x, y, cookies = document.cookie.split(';'); var i, x, y, cookies = document.cookie.split(';');
for (i = 0; i < cookies.length; i += 1) { for (i = 0; i < cookies.length; i += 1) {
x = cookies[i].substr(0, cookies[i].indexOf('=')); x = cookies[i].substr(0, cookies[i].indexOf('='));
y = cookies[i].substr(cookies[i].indexOf('=') + 1); y = cookies[i].substr(cookies[i].indexOf('=') + 1);
x = x.replace(/^\s+|\s+$/g, ""); x = x.replace(/^\s+|\s+$/g, '');
if (x === name) { if (x === name) {
return unescape(y); return unescape(y);
} }
...@@ -54,15 +54,14 @@ ...@@ -54,15 +54,14 @@
statusDefault: function () { statusDefault: function () {
return { return {
0: function () { console.error("status error code: 0"); }, 0: function () { console.error('status error code: 0'); },
404: function () { console.error("status error code: Not Found !"); }, 404: function () { console.error('status error code: Not Found !'); },
500: function () { console.error("Server error !"); } 500: function () { console.error('Server error !'); }
}; };
}, },
request: function (type, authentication, args) { request: function (type, authentication, args) {
var statusCode; var statusCode, data;
var data;
if (args.hasOwnProperty('statusCode')) { if (args.hasOwnProperty('statusCode')) {
statusCode = args.statusCode || methods.statusDefault(); statusCode = args.statusCode || methods.statusDefault();
} else { } else {
...@@ -73,7 +72,7 @@ ...@@ -73,7 +72,7 @@
} else { } else {
data = undefined; data = undefined;
} }
delete args.data delete args.data;
$.extend(args, {statusCode: statusCode}); $.extend(args, {statusCode: statusCode});
return this.each(function () { return this.each(function () {
var ajaxOptions = { var ajaxOptions = {
...@@ -83,9 +82,11 @@ ...@@ -83,9 +82,11 @@
datatype: 'json', datatype: 'json',
context: $(this), context: $(this),
beforeSend: function (xhr) { beforeSend: function (xhr) {
if ($(this).slapos("access_token") && authentication) { xhr.setRequestHeader('REMOTE_USER', 'test_vifib_customer');
xhr.setRequestHeader("Authorization", $(this).slapos("store", "token_type") + " " + $(this).slapos("access_token")); xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader("Accept", "application/json"); if ($(this).slapos('access_token') && authentication) {
//xhr.setRequestHeader('Authorization', $(this).slapos('store', 'token_type') + ' ' + $(this).slapos('access_token'));
//xhr.setRequestHeader('Accept', 'application/json');
} }
} }
}; };
...@@ -96,8 +97,9 @@ ...@@ -96,8 +97,9 @@
prepareRequest: function (methodName, args) { prepareRequest: function (methodName, args) {
var $this = $(this); var $this = $(this);
return this.each(function(){ args = args || {};
$(this).slapos('discovery', function(access){ return this.each(function () {
$(this).slapos('discovery', function (access) {
if (access.hasOwnProperty(methodName)) { if (access.hasOwnProperty(methodName)) {
var url = args.url || access[methodName].url; var url = args.url || access[methodName].url;
$.extend(args, {'url': url}); $.extend(args, {'url': url});
...@@ -107,16 +109,16 @@ ...@@ -107,16 +109,16 @@
args); args);
} }
}); });
}) });
}, },
discovery: function (callback) { discovery: function (callback) {
return this.each(function(){ return this.each(function () {
$.ajax({ $.ajax({
url: "http://10.8.2.34:12002/erp5/portal_vifib_rest_api_v1", url: 'http://10.8.2.34:12006/erp5/portal_vifib_rest_api_v1',
dataType: "json", dataType: 'json',
beforeSend: function (xhr) { beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader('Accept', 'application/json');
}, },
success: callback success: callback
}); });
...@@ -134,7 +136,7 @@ ...@@ -134,7 +136,7 @@
}, },
instanceRequest: function (args) { instanceRequest: function (args) {
return $(this).slapos('prepareRequest', 'request_instance', args) return $(this).slapos('prepareRequest', 'request_instance', args);
} }
}; };
......
...@@ -5,21 +5,24 @@ ...@@ -5,21 +5,24 @@
*/ */
// Hash parser utility /**
* @param {String} hashTag hashTag.
* @return {String} a clean hashtag.
*/
$.parseHash = function(hashTag) { $.parseHash = function(hashTag) {
var tokenized = $.extractAuth(hashTag); var tokenized = $.extractAuth(hashTag);
if (tokenized) { if (tokenized) {
$.publish('auth', tokenized); $.publish('auth', tokenized);
location.hash = hashTag.split("&")[0] location.hash = hashTag.split('&')[0];
return location.hash return location.hash;
} }
return hashTag return hashTag;
}; };
$.extractAuth = function (hashTag) { $.extractAuth = function (hashTag) {
var del = hashTag.indexOf('&'); var del = hashTag.indexOf('&');
if (del != -1) { if (del != -1) {
var splitted = hashTag.substring(del+1).split('&'); var splitted = hashTag.substring(del + 1).split('&');
var result = {}; var result = {};
for (p in splitted) { for (p in splitted) {
var s = splitted[p].split('='); var s = splitted[p].split('=');
...@@ -39,6 +42,7 @@ $.genHash = function(url) { ...@@ -39,6 +42,7 @@ $.genHash = function(url) {
What's happening when we destroy a DOM object subscribed ? What's happening when we destroy a DOM object subscribed ?
*/ */
var o = $({}); var o = $({});
$.subscribe = function() { $.subscribe = function() {
o.on.apply(o, arguments); o.on.apply(o, arguments);
}; };
...@@ -50,8 +54,8 @@ $.publish = function() { ...@@ -50,8 +54,8 @@ $.publish = function() {
}; };
// Event Handlers // Event Handlers
$.hashHandler = function(){ $.publish("urlChange", $.parseHash(window.location.hash.substr(1))); }; $.hashHandler = function(){ $.publish('urlChange', $.parseHash(window.location.hash.substr(1))); };
$.redirectHandler = function(event, url){ window.location.hash = $.genHash(url); }; $.redirectHandler = function(e, url){ window.location.hash = $.genHash([url]); };
// redirections manager // redirections manager
$.redirect = function(url){ $.publish('redirect', url); }; $.redirect = function(url){ $.publish('redirect', url); };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment