diff options
4 files changed, 109 insertions, 138 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/xhr.js b/modules/luci-base/htdocs/luci-static/resources/xhr.js index 25a90e725..8292fcdb6 100644 --- a/modules/luci-base/htdocs/luci-static/resources/xhr.js +++ b/modules/luci-base/htdocs/luci-static/resources/xhr.js @@ -1,24 +1,65 @@ /* * xhr.js - XMLHttpRequest helper class - * (c) 2008-2010 Jo-Philipp Wich + * (c) 2008-2018 Jo-Philipp Wich <jo@mein.io> */ -XHR = function() -{ - this.reinit = function() - { - if (window.XMLHttpRequest) { - this._xmlHttp = new XMLHttpRequest(); +XHR.prototype = { + _encode: function(obj) { + obj = obj ? obj : { }; + obj['_'] = Math.random(); + + if (typeof obj == 'object') { + var code = ''; + var self = this; + + for (var k in obj) + code += (code ? '&' : '') + + k + '=' + encodeURIComponent(obj[k]); + + return code; } - else if (window.ActiveXObject) { - this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); + + return obj; + }, + + _response: function(callback, ts) { + if (this._xmlHttp.readyState !== 4) + return; + + var status = this._xmlHttp.status, + login = this._xmlHttp.getResponseHeader("X-LuCI-Login-Required"), + type = this._xmlHttp.getResponseHeader("Content-Type"), + json = null; + + if (status === 403 && login === 'yes') { + XHR.halt(); + + showModal(_('Session expired'), [ + E('div', { class: 'alert-message warning' }, + _('A new login is required since the authentication session expired.')), + E('div', { class: 'right' }, + E('div', { + class: 'btn primary', + click: function() { + var loc = window.location; + window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search; + } + }, _('To login…'))) + ]); } - else { - alert("xhr.js: XMLHttpRequest is not supported by this browser!"); + else if (type && type.toLowerCase().match(/^application\/json\b/)) { + try { + json = JSON.parse(this._xmlHttp.responseText); + } + catch(e) { + json = null; + } } - } - this.busy = function() { + callback(this._xmlHttp, json, Date.now() - ts); + }, + + busy: function() { if (!this._xmlHttp) return false; @@ -32,20 +73,18 @@ XHR = function() default: return false; } - } + }, - this.abort = function() { + abort: function() { if (this.busy()) this._xmlHttp.abort(); - } + }, - this.get = function(url,data,callback,timeout) - { - this.reinit(); + get: function(url, data, callback, timeout) { + this._xmlHttp = new XMLHttpRequest(); - var ts = Date.now(); - var xhr = this._xmlHttp; - var code = this._encode(data); + var xhr = this._xmlHttp, + code = this._encode(data); url = location.protocol + '//' + location.host + url; @@ -60,83 +99,51 @@ XHR = function() if (!isNaN(timeout)) xhr.timeout = timeout; - xhr.onreadystatechange = function() - { - if (xhr.readyState == 4) { - var json = null; - if (xhr.getResponseHeader("Content-Type") == "application/json") { - try { json = JSON.parse(xhr.responseText); } - catch(e) { json = null; } - } - - callback(xhr, json, Date.now() - ts); - } - } - + xhr.onreadystatechange = this._response.bind(this, callback, Date.now()); xhr.send(null); - } - - this.post = function(url,data,callback,timeout) - { - this.reinit(); + }, - var ts = Date.now(); - var xhr = this._xmlHttp; - var code = this._encode(data); + post: function(url, data, callback, timeout) { + this._xmlHttp = new XMLHttpRequest(); - xhr.onreadystatechange = function() - { - if (xhr.readyState == 4) { - var json = null; - if (xhr.getResponseHeader("Content-Type") == "application/json") { - try { json = JSON.parse(xhr.responseText); } - catch(e) { json = null; } - } - - callback(xhr, json, Date.now() - ts); - } - } + var xhr = this._xmlHttp, + code = this._encode(data); xhr.open('POST', url, true); if (!isNaN(timeout)) xhr.timeout = timeout; + xhr.onreadystatechange = this._response.bind(this, callback, Date.now()); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(code); - } + }, - this.cancel = function() - { - this._xmlHttp.onreadystatechange = function(){}; + cancel: function() { + this._xmlHttp.onreadystatechange = function() {}; this._xmlHttp.abort(); - } + }, - this.send_form = function(form,callback,extra_values) - { + send_form: function(form, callback, extra_values) { var code = ''; - for (var i = 0; i < form.elements.length; i++) - { + for (var i = 0; i < form.elements.length; i++) { var e = form.elements[i]; - if (e.options) - { + if (e.options) { code += (code ? '&' : '') + form.elements[i].name + '=' + encodeURIComponent( e.options[e.selectedIndex].value ); } - else if (e.length) - { + else if (e.length) { for (var j = 0; j < e.length; j++) if (e[j].name) { code += (code ? '&' : '') + e[j].name + '=' + encodeURIComponent(e[j].value); } } - else - { + else { code += (code ? '&' : '') + e.name + '=' + encodeURIComponent(e.value); } @@ -147,46 +154,25 @@ XHR = function() code += (code ? '&' : '') + key + '=' + encodeURIComponent(extra_values[key]); - return( - (form.method == 'get') - ? this.get(form.getAttribute('action'), code, callback) - : this.post(form.getAttribute('action'), code, callback) - ); - } - - this._encode = function(obj) - { - obj = obj ? obj : { }; - obj['_'] = Math.random(); - - if (typeof obj == 'object') - { - var code = ''; - var self = this; - - for (var k in obj) - code += (code ? '&' : '') + - k + '=' + encodeURIComponent(obj[k]); - - return code; - } - - return obj; + return (form.method == 'get' + ? this.get(form.getAttribute('action'), code, callback) + : this.post(form.getAttribute('action'), code, callback)); } } -XHR.get = function(url, data, callback) -{ +XHR.get = function(url, data, callback) { (new XHR()).get(url, data, callback); } -XHR.poll = function(interval, url, data, callback, post) -{ +XHR.post = function(url, data, callback) { + (new XHR()).post(url, data, callback); +} + +XHR.poll = function(interval, url, data, callback, post) { if (isNaN(interval) || interval < 1) interval = 5; - if (!XHR._q) - { + if (!XHR._q) { XHR._t = 0; XHR._q = [ ]; XHR._r = function() { @@ -213,8 +199,7 @@ XHR.poll = function(interval, url, data, callback, post) return e; } -XHR.stop = function(e) -{ +XHR.stop = function(e) { for (var i = 0; XHR._q && XHR._q[i]; i++) { if (XHR._q[i] === e) { e.xhr.cancel(); @@ -226,10 +211,8 @@ XHR.stop = function(e) return false; } -XHR.halt = function() -{ - if (XHR._i) - { +XHR.halt = function() { + if (XHR._i) { /* show & set poll indicator */ try { document.getElementById('xhr_poll_status').style.display = ''; @@ -242,10 +225,8 @@ XHR.halt = function() } } -XHR.run = function() -{ - if (XHR._r && !XHR._i) - { +XHR.run = function() { + if (XHR._r && !XHR._i) { /* show & set poll indicator */ try { document.getElementById('xhr_poll_status').style.display = ''; @@ -260,9 +241,10 @@ XHR.run = function() } } -XHR.running = function() -{ +XHR.running = function() { return !!(XHR._r && XHR._i); } +function XHR() {} + document.addEventListener('DOMContentLoaded', XHR.run); diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 1e610e748..c4066a259 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -417,6 +417,7 @@ function dispatch(request) context.path = {} http.status(403, "Forbidden") + http.header("X-LuCI-Login-Required", "yes") tmpl.render(track.sysauth_template or "sysauth", { duser = default_user, fuser = user @@ -433,6 +434,7 @@ function dispatch(request) if not sid or not sdat then http.status(403, "Forbidden") + http.header("X-LuCI-Login-Required", "yes") return end diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua index 6f0921fdc..4a31146a0 100644 --- a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua @@ -117,14 +117,14 @@ function used.cfgvalue(self, section) end unmount = v:option(Button, "unmount", translate("Unmount")) +function unmount.cfgvalue(self, section) + return non_system_mounts[section].umount +end + unmount.render = function(self, section, scope) - if non_system_mounts[section].umount then - self.title = translate("Unmount") - self.inputstyle = "remove" - Button.render(self, section, scope) - else - luci.http.write(" ") - end + self.title = translate("Unmount") + self.inputstyle = "remove" + Button.render(self, section, scope) end unmount.write = function(self, section) diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css index 35ea81500..5f9d7e603 100644 --- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css +++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css @@ -387,20 +387,20 @@ form .cbi-tab-descr { } form .clearfix, -form .cbi-value { +.cbi-value { margin-bottom: 18px; zoom: 1; } form .clearfix:before, form .clearfix:after, -form .cbi-value:before, form .cbi-value:after { +.cbi-value:before, .cbi-value:after { display: table; content: ""; zoom: 1; } form .clearfix:after, -form .cbi-value:after { +.cbi-value:after { clear: both; } @@ -415,11 +415,11 @@ textarea { } form .input, -form .cbi-value-field { +.cbi-value-field { margin-left: 200px; } -form .cbi-value label.cbi-value-title { +.cbi-value label.cbi-value-title { padding-top: 6px; font-size: 13px; line-height: 18px; @@ -1770,19 +1770,6 @@ a.label:hover { /* LuCI specific items */ .hidden { display: none } -#memtotal > div, -#memfree > div, -#memcache > div, -#membuff > div, -#conns > div { - border: 1px solid #ccc; - border-radius: 3px 3px 3px 3px; - color: #808080; - display: inline-block; - font-size: 13px; - line-height: 18px; -} - #xhr_poll_status { cursor: pointer; } |