diff --git a/luci-base/Makefile.orig b/luci-base/Makefile.orig new file mode 100644 index 000000000..7f7d7e772 --- /dev/null +++ b/luci-base/Makefile.orig @@ -0,0 +1,50 @@ +# +# Copyright (C) 2008-2015 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-base + +LUCI_TYPE:=mod +LUCI_BASENAME:=base + +LUCI_TITLE:=LuCI core libraries +LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua + +PKG_SOURCE:=LuaSrcDiet-0.12.1.tar.bz2 +PKG_SOURCE_URL:=https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/luasrcdiet +PKG_HASH:=ed7680f2896269ae8633756e7edcf09050812f78c8f49e280e63c30d14f35aea +PKG_LICENSE:=Apache-2.0 + +HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/LuaSrcDiet-0.12.1 + +include $(INCLUDE_DIR)/host-build.mk + +define Package/luci-base/conffiles +/etc/luci-uploads +/etc/config/luci +/etc/config/ucitrack +endef + +include ../../luci.mk + +define Host/Configure +endef + +define Host/Compile + $(MAKE) -C src/ clean po2lmo + $(MAKE) -C $(HOST_BUILD_DIR) bin/LuaSrcDiet.lua +endef + +define Host/Install + $(INSTALL_DIR) $(1)/bin + $(INSTALL_BIN) src/po2lmo $(1)/bin/po2lmo + $(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/LuaSrcDiet.lua $(1)/bin/LuaSrcDiet +endef + +$(eval $(call HostBuild)) + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-base/htdocs/luci-static/resources/cbi.js b/luci-base/htdocs/luci-static/resources/cbi.js index 6c35372cd..0a1961916 100644 --- a/luci-base/htdocs/luci-static/resources/cbi.js +++ b/luci-base/htdocs/luci-static/resources/cbi.js @@ -1244,44 +1244,44 @@ function cbi_validate_field(cbid, optional, type) function cbi_row_swap(elem, up, store) { var tr = elem.parentNode; - while (tr && tr.nodeName.toLowerCase() != 'tr') + + while (tr && !tr.classList.contains('cbi-section-table-row')) tr = tr.parentNode; if (!tr) return false; - var table = tr.parentNode; - while (table && table.nodeName.toLowerCase() != 'table') - table = table.parentNode; + if (up) { + var prev = tr.previousElementSibling; - if (!table) - return false; + if (prev && prev.classList.contains('cbi-section-table-row')) + tr.parentNode.insertBefore(tr, prev); + else + return; + } + else { + var next = tr.nextElementSibling ? tr.nextElementSibling.nextElementSibling : null; - var s = up ? 3 : 2; - var e = up ? table.rows.length : table.rows.length - 1; - - for (var idx = s; idx < e; idx++) - { - if (table.rows[idx] == tr) - { - if (up) - tr.parentNode.insertBefore(table.rows[idx], table.rows[idx-1]); - else - tr.parentNode.insertBefore(table.rows[idx+1], table.rows[idx]); - - break; - } + if (next && next.classList.contains('cbi-section-table-row')) + tr.parentNode.insertBefore(tr, next); + else if (!next) + tr.parentNode.appendChild(tr); + else + return; } var ids = [ ]; - for (idx = 2; idx < table.rows.length; idx++) - { - table.rows[idx].className = table.rows[idx].className.replace( - /cbi-rowstyle-[12]/, 'cbi-rowstyle-' + (1 + (idx % 2)) - ); - if (table.rows[idx].id && table.rows[idx].id.match(/-([^\-]+)$/) ) - ids.push(RegExp.$1); + for (var i = 0, n = 0; i < tr.parentNode.childNodes.length; i++) { + var node = tr.parentNode.childNodes[i]; + if (node.classList && node.classList.contains('cbi-section-table-row')) { + node.classList.remove('cbi-rowstyle-1'); + node.classList.remove('cbi-rowstyle-2'); + node.classList.add((n++ % 2) ? 'cbi-rowstyle-2' : 'cbi-rowstyle-1'); + + if (/-([^\-]+)$/.test(node.id)) + ids.push(RegExp.$1); + } } var input = document.getElementById(store); @@ -1311,58 +1311,6 @@ function cbi_tag_last(container) } } -String.prototype.serialize = function() -{ - var o = this; - switch(typeof(o)) - { - case 'object': - // null - if( o == null ) - { - return 'null'; - } - - // array - else if( o.length ) - { - var i, s = ''; - - for( var i = 0; i < o.length; i++ ) - s += (s ? ', ' : '') + String.serialize(o[i]); - - return '[ ' + s + ' ]'; - } - - // object - else - { - var k, s = ''; - - for( k in o ) - s += (s ? ', ' : '') + k + ': ' + String.serialize(o[k]); - - return '{ ' + s + ' }'; - } - - break; - - case 'string': - // complex string - if( o.match(/[^a-zA-Z0-9_,.: -]/) ) - return 'decodeURIComponent("' + encodeURIComponent(o) + '")'; - - // simple string - else - return '"' + o + '"'; - - break; - - default: - return o.toString(); - } -} - String.prototype.format = function() { if (!RegExp) @@ -1473,10 +1421,6 @@ String.prototype.format = function() subst = esc(param, quot_esc); break; - case 'j': - subst = String.serialize(param); - break; - case 't': var td = 0; var th = 0; @@ -1543,14 +1487,6 @@ String.prototype.nobr = function() return this.replace(/[\s\n]+/g, ' '); } -String.serialize = function() -{ - var a = [ ]; - for (var i = 1; i < arguments.length; i++) - a.push(arguments[i]); - return ''.serialize.apply(arguments[0], a); -} - String.format = function() { var a = [ ]; @@ -1566,3 +1502,75 @@ String.nobr = function() a.push(arguments[i]); return ''.nobr.apply(arguments[0], a); } + + +var dummyElem, domParser; + +function isElem(e) +{ + return (typeof(e) === 'object' && e !== null && 'nodeType' in e); +} + +function toElem(s) +{ + var elem; + + try { + domParser = domParser || new DOMParser(); + elem = domParser.parseFromString(s, 'text/html').body.firstChild; + } + catch(e) {} + + if (!elem) { + try { + dummyElem = dummyElem || document.createElement('div'); + dummyElem.innerHTML = s; + elem = dummyElem.firstChild; + } + catch (e) {} + } + + return elem || null; +} + +function E() +{ + var html = arguments[0], + attr = (arguments[1] instanceof Object && !Array.isArray(arguments[1])) ? arguments[1] : null, + data = attr ? arguments[2] : arguments[1], + elem; + + if (isElem(html)) + elem = html; + else if (html.charCodeAt(0) === 60) + elem = toElem(html); + else + elem = document.createElement(html); + + if (!elem) + return null; + + if (attr) + for (var key in attr) + if (attr.hasOwnProperty(key)) + elem.setAttribute(key, attr[key]); + + if (typeof(data) === 'function') + data = data(elem); + + if (isElem(data)) { + elem.appendChild(data); + } + else if (Array.isArray(data)) { + for (var i = 0; i < data.length; i++) + if (isElem(data[i])) + elem.appendChild(data[i]); + else + elem.appendChild(document.createTextNode('' + data[i])); + } + else if (data !== null && data !== undefined) { + elem.innerHTML = '' + data; + } + + return elem; +} diff --git a/luci-base/luasrc/cbi.lua b/luci-base/luasrc/cbi.lua index 472864211..4800d2aa7 100644 --- a/luci-base/luasrc/cbi.lua +++ b/luci-base/luasrc/cbi.lua @@ -1226,13 +1226,14 @@ function TypedSection.parse(self, novld) local stval = RESORT_PREFIX .. self.config .. "." .. self.sectiontype local order = self.map:formvalue(stval) if order and #order > 0 then - local sid - local num = 0 + local sids, sid = { }, nil for sid in util.imatch(order) do - self.map.uci:reorder(self.config, sid, num) - num = num + 1 + sids[#sids+1] = sid + end + if #sids > 0 then + self.map.uci:reorder(self.config, sids) + self.changed = true end - self.changed = (num > 0) end end diff --git a/luci-base/luasrc/dispatcher.lua b/luci-base/luasrc/dispatcher.lua index 2c58b0ab3..6850d7e3a 100644 --- a/luci-base/luasrc/dispatcher.lua +++ b/luci-base/luasrc/dispatcher.lua @@ -358,7 +358,7 @@ function dispatch(request) elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) elseif key == "FULL_REQUEST_URI" then - local url = { http.getenv("SCRIPT_NAME") or "" , http.getenv("PATH_INFO") } + local url = { http.getenv("SCRIPT_NAME") or "", http.getenv("PATH_INFO") } local query = http.getenv("QUERY_STRING") if query and #query > 0 then url[#url+1] = "?" @@ -507,10 +507,11 @@ function dispatch(request) else ok, err = util.copcall(target, unpack(args)) end - assert(ok, - "Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. - " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. - "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) + if not ok then + error500("Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") .. + " dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" .. + "The called action terminated with an exception:\n" .. tostring(err or "(unknown)")) + end else local root = node() if not root or not root.target then diff --git a/luci-base/luasrc/util.lua b/luci-base/luasrc/util.lua index ce42af2fb..10428b0b3 100644 --- a/luci-base/luasrc/util.lua +++ b/luci-base/luasrc/util.lua @@ -100,6 +100,8 @@ end -- Scope manipulation routines -- +coxpt = setmetatable({}, { __mode = "kv" }) + local tl_meta = { __mode = "k", @@ -697,73 +699,69 @@ function checklib(fullpathexe, wantedlib) return false end +------------------------------------------------------------------------------- +-- Coroutine safe xpcall and pcall versions -- --- Coroutine safe xpcall and pcall versions modified for Luci --- original version: --- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org) +-- Encapsulates the protected calls with a coroutine based loop, so errors can +-- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines +-- yielding inside the call to pcall or xpcall. -- --- Copyright © 2005 Kepler Project. --- Permission is hereby granted, free of charge, to any person obtaining a --- copy of this software and associated documentation files (the "Software"), --- to deal in the Software without restriction, including without limitation --- the rights to use, copy, modify, merge, publish, distribute, sublicense, --- and/or sell copies of the Software, and to permit persons to whom the --- Software is furnished to do so, subject to the following conditions: +-- Authors: Roberto Ierusalimschy and Andre Carregal +-- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas -- --- The above copyright notice and this permission notice shall be --- included in all copies or substantial portions of the Software. +-- Copyright 2005 - Kepler Project -- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, --- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES --- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. --- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, --- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, --- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE --- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $ +------------------------------------------------------------------------------- -local performResume, handleReturnValue -local oldpcall, oldxpcall = pcall, xpcall -coxpt = {} -setmetatable(coxpt, {__mode = "kv"}) +------------------------------------------------------------------------------- +-- Implements xpcall with coroutines +------------------------------------------------------------------------------- +local coromap = setmetatable({}, { __mode = "k" }) --- Identity function for copcall -local function copcall_id(trace, ...) - return ... -end - --- values of either the function or the error handler -function coxpcall(f, err, ...) - local res, co = oldpcall(coroutine.create, f) - if not res then - local params = {...} - local newf = function() return f(unpack(params)) end - co = coroutine.create(newf) - end - local c = coroutine.running() - coxpt[co] = coxpt[c] or c or 0 - - return performResume(err, co, ...) -end - --- values of the function or the error object -function copcall(f, ...) - return coxpcall(f, copcall_id, ...) -end - --- Handle return value of protected call -function handleReturnValue(err, co, status, ...) +local function handleReturnValue(err, co, status, ...) if not status then return false, err(debug.traceback(co, (...)), ...) end - - if coroutine.status(co) ~= 'suspended' then + if coroutine.status(co) == 'suspended' then + return performResume(err, co, coroutine.yield(...)) + else return true, ... end - - return performResume(err, co, coroutine.yield(...)) end --- Resume execution of protected function call function performResume(err, co, ...) return handleReturnValue(err, co, coroutine.resume(co, ...)) end + +local function id(trace, ...) + return trace +end + +function coxpcall(f, err, ...) + local current = coroutine.running() + if not current then + if err == id then + return pcall(f, ...) + else + if select("#", ...) > 0 then + local oldf, params = f, { ... } + f = function() return oldf(unpack(params)) end + end + return xpcall(f, err) + end + else + local res, co = pcall(coroutine.create, f) + if not res then + local newf = function(...) return f(...) end + co = coroutine.create(newf) + end + coromap[co] = current + coxpt[co] = coxpt[current] or current or 0 + return performResume(err, co, ...) + end +end + +function copcall(f, ...) + return coxpcall(f, id, ...) +end diff --git a/luci-base/luasrc/view/cbi/apply_widget.htm b/luci-base/luasrc/view/cbi/apply_widget.htm index 543ef0b80..702512f49 100644 --- a/luci-base/luasrc/view/cbi/apply_widget.htm +++ b/luci-base/luasrc/view/cbi/apply_widget.htm @@ -1,59 +1,98 @@ <% export("cbi_apply_widget", function(redirect_ok) -%> - +