Changeset 5773

Show
Ignore:
Timestamp:
03/09/10 03:05:49 (3 years ago)
Author:
jow
Message:

luci-0.9: backport CBI from trunk, adds tab support, auto-hiding of commit notifications and better layout control

Location:
luci/branches/luci-0.9/libs/cbi
Files:
2 added
5 modified

Legend:

Unmodified
Added
Removed
  • luci/branches/luci-0.9/libs/cbi/htdocs/luci-static/resources/cbi.js

    r4013 r5773  
    33 
    44    Copyright 2008 Steven Barth <steven@midlink.org> 
    5     Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> 
     5    Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org> 
    66 
    77    Licensed under the Apache License, Version 2.0 (the "License"); 
     
    1515 
    1616var cbi_d = []; 
     17var cbi_t = []; 
     18var cbi_c = []; 
    1719 
    1820function cbi_d_add(field, dep, next) { 
     
    4446    var value; 
    4547 
    46     if (!t || !t.value) { 
     48    if (!t) { 
     49        var tl = document.getElementsByName(target); 
     50 
     51        if( tl.length > 0 && tl[0].type == 'radio' ) 
     52            for( var i = 0; i < tl.length; i++ ) 
     53                if( tl[i].checked ) { 
     54                    value = tl[i].value; 
     55                    break; 
     56                } 
     57 
     58        value = value ? value : ""; 
     59    } else if (!t.value) { 
    4760        value = ""; 
    4861    } else { 
     
    5871 
    5972function cbi_d_check(deps) { 
     73    var reverse; 
     74    var def = false; 
    6075    for (var i=0; i<deps.length; i++) { 
    61         var istat = true 
     76        var istat = true; 
     77        reverse = false; 
    6278        for (var j in deps[i]) { 
    63             istat = (istat && cbi_d_checkvalue(j, deps[i][j])) 
     79            if (j == "!reverse") { 
     80                reverse = true; 
     81            } else if (j == "!default") { 
     82                def = true; 
     83                istat = false; 
     84            } else { 
     85                istat = (istat && cbi_d_checkvalue(j, deps[i][j])) 
     86            } 
    6487        } 
    6588        if (istat) { 
    66             return true 
    67         } 
    68     } 
     89            return !reverse; 
     90        } 
     91    } 
     92    return def; 
    6993} 
    7094 
     
    79103        if (node && node.parentNode && !cbi_d_check(entry.deps)) { 
    80104            node.parentNode.removeChild(node); 
    81             state = (state || !node.parentNode) 
     105            state = true; 
     106            if( entry.parent ) 
     107                cbi_c[entry.parent]--; 
    82108        } else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) { 
    83109            if (!next) { 
     
    86112                next.parentNode.insertBefore(entry.node, next); 
    87113            } 
    88             state = (state || (node && node.parentNode)) 
    89         } 
    90     } 
     114            state = true; 
     115            if( entry.parent ) 
     116                cbi_c[entry.parent]++; 
     117        } 
     118    } 
     119 
     120    if (entry.parent) { 
     121        cbi_t_update(); 
     122    } 
     123 
    91124    if (state) { 
    92125        cbi_d_update(); 
     
    220253    } 
    221254} 
     255 
     256 
     257function cbi_t_add(section, tab) { 
     258    var t = document.getElementById('tab.' + section + '.' + tab); 
     259    var c = document.getElementById('container.' + section + '.' + tab); 
     260 
     261    if( t && c ) { 
     262        cbi_t[section] = (cbi_t[section] || [ ]); 
     263        cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id }; 
     264    } 
     265} 
     266 
     267function cbi_t_switch(section, tab) { 
     268    if( cbi_t[section] && cbi_t[section][tab] ) { 
     269        var o = cbi_t[section][tab]; 
     270        var h = document.getElementById('tab.' + section); 
     271        for( var tid in cbi_t[section] ) { 
     272            var o2 = cbi_t[section][tid]; 
     273            if( o.tab.id != o2.tab.id ) { 
     274                o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled "); 
     275                o2.container.style.display = 'none'; 
     276            } 
     277            else { 
     278                if(h) h.value = tab; 
     279                o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab "); 
     280                o2.container.style.display = 'block'; 
     281            } 
     282        } 
     283    } 
     284    return false 
     285} 
     286 
     287function cbi_t_update() { 
     288    for( var sid in cbi_t ) 
     289        for( var tid in cbi_t[sid] ) 
     290            if( cbi_c[cbi_t[sid][tid].cid] == 0 ) { 
     291                cbi_t[sid][tid].tab.style.display = 'none'; 
     292            } 
     293            else if( cbi_t[sid][tid].tab && cbi_t[sid][tid].tab.style.display == 'none' ) { 
     294                cbi_t[sid][tid].tab.style.display = ''; 
     295 
     296                var t = cbi_t[sid][tid].tab; 
     297                window.setTimeout(function() { t.className = t.className.replace(/ cbi-tab-highlighted/g, '') }, 750); 
     298                cbi_t[sid][tid].tab.className += ' cbi-tab-highlighted'; 
     299            } 
     300} 
     301 
  • luci/branches/luci-0.9/libs/cbi/luasrc/cbi.lua

    r5383 r5773  
    231231        local key = config and config:gsub("[^%w]+", "") or "" 
    232232 
    233         if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end 
     233        if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end 
    234234        if option  then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "")  end 
    235235 
     
    237237        self.description = description or luci.i18n.translate( key .. "_desc", "" ) 
    238238    end 
     239end 
     240 
     241-- hook helper 
     242function Node._run_hook(self, hook) 
     243    if type(self[hook]) == "function" then 
     244        return self[hook](self) 
     245    end  
     246end 
     247 
     248function Node._run_hooks(self, ...) 
     249    local f 
     250    local r = false 
     251    for _, f in ipairs(arg) do 
     252        if type(self[f]) == "function" then 
     253            self[f](self) 
     254            r = true 
     255        end 
     256    end 
     257    return r 
    239258end 
    240259 
     
    358377function Map.parse(self, readinput, ...) 
    359378    self.readinput = (readinput ~= false) 
     379    self:_run_hooks("on_parse") 
    360380 
    361381    if self:formvalue("cbi.skip") then 
     
    371391        end 
    372392        if self:submitstate() and ((not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply")) then 
     393            self:_run_hooks("on_before_commit") 
    373394            for i, config in ipairs(self.parsechain) do 
    374395                self.uci:commit(config) 
     
    377398                self.uci:load(config) 
    378399            end 
     400            self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") 
    379401            if self.apply_on_parse then 
    380402                self.uci:apply(self.parsechain) 
     403                self:_run_hooks("on_apply", "on_after_apply") 
    381404            else 
    382405                self._apply = function() 
     
    414437 
    415438function Map.render(self, ...) 
     439    self:_run_hooks("on_init") 
    416440    Node.render(self, ...) 
    417441    if self._apply then 
     
    419443        fp:read("*a") 
    420444        fp:close() 
     445        self:_run_hooks("on_apply") 
    421446    end 
    422447end 
     
    507532    self.readinput = true 
    508533    self.allow_reset = false 
     534    self.allow_cancel = false 
    509535    self.allow_back = false 
    510536    self.allow_finish = false 
     
    513539 
    514540function Delegator.set(self, name, node) 
    515     if type(node) == "table" and getmetatable(node) == nil then 
    516         node = Compound(unpack(node)) 
    517     end 
    518     assert(type(node) == "function" or instanceof(node, Compound), "Invalid") 
    519541    assert(not self.nodes[name], "Duplicate entry") 
    520542 
     
    528550 
    529551function Delegator.insert_after(self, name, after) 
    530     local n = #self.chain 
     552    local n = #self.chain + 1 
    531553    for k, v in ipairs(self.chain) do 
    532         if v == state then 
     554        if v == after then 
    533555            n = k + 1 
    534556            break 
     
    556578 
    557579function Delegator.get(self, name) 
    558     return self.nodes[name] 
     580    local node = self.nodes[name] 
     581 
     582    if type(node) == "string" then 
     583        node = load(node, name) 
     584    end 
     585 
     586    if type(node) == "table" and getmetatable(node) == nil then 
     587        node = Compound(unpack(node)) 
     588    end 
     589 
     590    return node 
    559591end 
    560592 
    561593function Delegator.parse(self, ...) 
     594    if self.allow_cancel and Map.formvalue(self, "cbi.cancel") then 
     595        if self:_run_hooks("on_cancel") then 
     596            return FORM_DONE 
     597        end 
     598    end 
     599     
     600    if not Map.formvalue(self, "cbi.delg.current") then 
     601        self:_run_hooks("on_init") 
     602    end 
     603 
    562604    local newcurrent 
    563605    self.chain = self.chain or self:get_chain() 
     
    587629    if not Map.formvalue(self, "cbi.submit") then 
    588630        return FORM_NODATA 
    589     elseif not newcurrent or not self:get(newcurrent) then 
    590         return FORM_DONE 
     631    elseif stat > FORM_PROCEED  
     632    and (not newcurrent or not self:get(newcurrent)) then 
     633        return self:_run_hook("on_done") or FORM_DONE 
    591634    else 
    592         self.current = newcurrent 
     635        self.current = newcurrent or self.current 
    593636        self.active = self:get(self.current) 
    594637        if type(self.active) ~= "function" then 
    595             self.active:parse(false) 
    596             return FROM_PROCEED 
     638            self.active:populate_delegator(self) 
     639            local stat = self.active:parse(false) 
     640            if stat == FORM_SKIP then 
     641                return self:parse(...) 
     642            else 
     643                return FORM_PROCEED 
     644            end 
    597645        else 
    598646            return self:parse(...) 
     
    658706    if self:formvalue("cbi.skip") then 
    659707        return FORM_SKIP 
     708    end 
     709 
     710    if self:formvalue("cbi.cancel") and self:_run_hooks("on_cancel") then 
     711        return FORM_DONE 
    660712    end 
    661713 
     
    780832    self.addremove = false 
    781833    self.dynamic = false 
     834end 
     835 
     836-- Define a tab for the section 
     837function AbstractSection.tab(self, tab, title, desc) 
     838    self.tabs      = self.tabs      or { } 
     839    self.tab_names = self.tab_names or { } 
     840 
     841    self.tab_names[#self.tab_names+1] = tab 
     842    self.tabs[tab] = { 
     843        title       = title, 
     844        description = desc, 
     845        childs      = { } 
     846    } 
    782847end 
    783848 
     
    813878end 
    814879 
     880-- Appends a new tabbed option 
     881function AbstractSection.taboption(self, tab, ...) 
     882 
     883    assert(tab and self.tabs and self.tabs[tab], 
     884        "Cannot assign option to not existing tab %q" % tostring(tab)) 
     885 
     886    local l = self.tabs[tab].childs 
     887    local o = AbstractSection.option(self, ...) 
     888 
     889    if o then l[#l+1] = o end 
     890 
     891    return o 
     892end 
     893 
     894-- Render a single tab 
     895function AbstractSection.render_tab(self, tab, ...) 
     896 
     897    assert(tab and self.tabs and self.tabs[tab], 
     898        "Cannot render not existing tab %q" % tostring(tab)) 
     899 
     900    for _, node in ipairs(self.tabs[tab].childs) do 
     901        node:render(...) 
     902    end 
     903end 
     904 
    815905-- Parse optional options 
    816906function AbstractSection.parse_optionals(self, section) 
     
    12161306    self.tag_error = {} 
    12171307    self.deps = {} 
     1308    self.subdeps = {} 
    12181309    --self.cast = "string" 
    12191310 
     
    13571448        scope.cbid      = self:cbid(s) 
    13581449        scope.striptags = luci.util.striptags 
     1450        scope.pcdata    = luci.util.pcdata 
    13591451 
    13601452        scope.ifattr = function(cond,key,val) 
     
    15451637 
    15461638    for i, deps in ipairs({...}) do 
    1547         table.insert(self.deps, {add = "-"..key, deps=deps}) 
     1639        self.subdeps[#self.subdeps + 1] = {add = "-"..key, deps=deps} 
    15481640    end 
    15491641end 
  • luci/branches/luci-0.9/libs/cbi/luasrc/view/cbi/map.htm

    r3529 r5773  
    1515 
    1616<div class="cbi-map" id="cbi-<%=self.config%>"> 
    17     <h2><a id="content" name="content"><%=self.title%></a></h2> 
    18     <div class="cbi-map-descr"><%=self.description%></div> 
     17    <% if self.title and #self.title > 0 then %> 
     18        <h2> 
     19            <% 
     20                if self.breadcrumb then 
     21                    local elem 
     22                    for _, elem in ipairs(self.breadcrumb) do 
     23            -%> 
     24                    <a href="<%=luci.util.pcdata(elem[1])%>"><%=luci.util.pcdata(elem[2])%></a> &raquo; 
     25            <% 
     26                    end 
     27                end 
     28            -%> 
     29            <a id="content" name="content"><%=self.title%></a> 
     30        </h2> 
     31    <% end %> 
     32 
     33    <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %> 
    1934    <%- if self._apply then -%> 
    20         <fieldset class="cbi-section"> 
     35        <fieldset class="cbi-section" id="cbi-apply-<%=self.config%>"> 
    2136            <legend><%:cbi_applying%></legend> 
    2237            <ul class="cbi-apply"><%- 
     
    3146            -%></ul> 
    3247        </fieldset> 
     48        <script type="text/javascript"> 
     49            window.setTimeout(function() { 
     50                var e = document.getElementById('cbi-apply-<%=self.config%>'); 
     51                if(e) e.style.display = 'none'; 
     52            }, 2000); 
     53        </script> 
    3354    <%- end -%> 
    3455    <%- self:render_children() %> 
  • luci/branches/luci-0.9/libs/cbi/luasrc/view/cbi/nsection.htm

    r3550 r5773  
    22LuCI - Lua Configuration Interface 
    33Copyright 2008 Steven Barth <steven@midlink.org> 
    4 Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> 
     4Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal> 
    55 
    66Licensed under the Apache License, Version 2.0 (the "License"); 
     
    2727            </div> 
    2828        <%- end %> 
     29        <%+cbi/tabmenu%> 
    2930        <div class="cbi-section-node" id="cbi-<%=self.config%>-<%=section%>"> 
    3031            <%+cbi/ucisection%> 
  • luci/branches/luci-0.9/libs/cbi/luasrc/view/cbi/tsection.htm

    r3550 r5773  
    2525            </div> 
    2626        <%- end %> 
    27         <% section = k; isempty = false %> 
     27 
     28        <%- section = k; isempty = false -%> 
    2829 
    2930        <% if not self.anonymous then -%> 
    30             <h3><%=k:upper()%></h3> 
     31            <h3><%=section:upper()%></h3> 
    3132        <%- end %> 
     33 
     34        <%+cbi/tabmenu%> 
    3235 
    3336        <fieldset class="cbi-section-node" id="cbi-<%=self.config%>-<%=section%>">