2 LuCI - Configuration Bind Interface
5 Offers an interface for binding configuration values to certain
6 data types. Supports value and range validation and basic dependencies.
12 Copyright 2008 Steven Barth <steven@midlink.org>
14 Licensed under the Apache License, Version 2.0 (the "License");
15 you may not use this file except in compliance with the License.
16 You may obtain a copy of the License at
18 http://www.apache.org/licenses/LICENSE-2.0
20 Unless required by applicable law or agreed to in writing, software
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
27 module("luci.cbi", package.seeall)
29 require("luci.template")
34 local uci = require("luci.model.uci")
35 local class = luci.util.class
36 local instanceof = luci.util.instanceof
44 CREATE_PREFIX = "cbi.cts."
45 REMOVE_PREFIX = "cbi.rts."
47 -- Loads a CBI map from given file, creating an environment and returns it
48 function load(cbimap, ...)
51 require("luci.config")
54 local cbidir = luci.util.libpath() .. "/model/cbi/"
55 local func, err = loadfile(cbidir..cbimap..".lua")
61 luci.i18n.loadc("cbi")
63 luci.util.resfenv(func)
64 luci.util.updfenv(func, luci.cbi)
65 luci.util.extfenv(func, "translate", luci.i18n.translate)
66 luci.util.extfenv(func, "translatef", luci.i18n.translatef)
67 luci.util.extfenv(func, "arg", {...})
71 for i, map in ipairs(maps) do
72 if not instanceof(map, Node) then
73 error("CBI map returns no valid map object!")
82 function _uvl_strip_remote_dependencies(deps)
85 for k, v in pairs(deps) do
86 k = k:gsub("%$config%.%$section%.", "")
87 if k:match("^[%w_]+$") and type(v) == "string" then
96 -- Node pseudo abstract class
99 function Node.__init__(self, title, description)
101 self.title = title or ""
102 self.description = description or ""
103 self.template = "cbi/node"
107 function Node._i18n(self, config, section, option, title, description)
110 if type(luci.i18n) == "table" then
112 local key = config and config:gsub("[^%w]+", "") or ""
114 if section then key = key .. "_" .. section:lower():gsub("[^%w]+", "") end
115 if option then key = key .. "_" .. tostring(option):lower():gsub("[^%w]+", "") end
117 self.title = title or luci.i18n.translate( key, option or section or config )
118 self.description = description or luci.i18n.translate( key .. "_desc", "" )
122 -- Append child nodes
123 function Node.append(self, obj)
124 table.insert(self.children, obj)
127 -- Parse this node and its children
128 function Node.parse(self, ...)
129 for k, child in ipairs(self.children) do
135 function Node.render(self, scope)
139 luci.template.render(self.template, scope)
142 -- Render the children
143 function Node.render_children(self, ...)
144 for k, node in ipairs(self.children) do
151 A simple template element
153 Template = class(Node)
155 function Template.__init__(self, template)
157 self.template = template
160 function Template.render(self)
161 luci.template.render(self.template, {self=self})
166 Map - A map describing a configuration file
170 function Map.__init__(self, config, ...)
171 Node.__init__(self, ...)
172 Node._i18n(self, config, nil, nil, ...)
175 self.parsechain = {self.config}
176 self.template = "cbi/map"
177 self.uci = uci.cursor()
179 if not self.uci:load(self.config) then
180 error("Unable to read UCI data: " .. self.config)
183 self.validator = luci.uvl.UVL()
184 self.scheme = self.validator:get_scheme(self.config)
188 function Map.get_scheme(self, sectiontype, option)
190 return self.scheme and self.scheme.sections[sectiontype]
192 return self.scheme and self.scheme.variables[sectiontype]
193 and self.scheme.variables[sectiontype][option]
198 -- Chain foreign config
199 function Map.chain(self, config)
200 table.insert(self.parsechain, config)
203 -- Use optimized UCI writing
204 function Map.parse(self, ...)
205 Node.parse(self, ...)
208 for i, config in ipairs(self.parsechain) do
209 self.uci:save(config)
211 if luci.http.formvalue("cbi.apply") then
212 for i, config in ipairs(self.parsechain) do
213 self.uci:commit(config)
214 self.uci:apply(config)
216 -- Refresh data because commit changes section names
217 self.uci:load(config)
221 Node.parse(self, ...)
224 for i, config in ipairs(self.parsechain) do
225 self.uci:unload(config)
230 -- Creates a child section
231 function Map.section(self, class, ...)
232 if instanceof(class, AbstractSection) then
233 local obj = class(self, ...)
237 error("class must be a descendent of AbstractSection")
242 function Map.add(self, sectiontype)
243 return self.uci:add(self.config, sectiontype)
247 function Map.set(self, section, option, value)
249 return self.uci:set(self.config, section, option, value)
251 return self.uci:set(self.config, section, value)
256 function Map.del(self, section, option)
258 return self.uci:delete(self.config, section, option)
260 return self.uci:delete(self.config, section)
265 function Map.get(self, section, option)
267 return self.uci:get_all(self.config)
269 return self.uci:get(self.config, section, option)
271 return self.uci:get_all(self.config, section)
281 Page.__init__ = Node.__init__
282 Page.parse = function() end
286 SimpleForm - A Simple non-UCI form
288 SimpleForm = class(Node)
290 function SimpleForm.__init__(self, config, title, description, data)
291 Node.__init__(self, title, description)
293 self.data = data or {}
294 self.template = "cbi/simpleform"
298 function SimpleForm.parse(self, ...)
299 if luci.http.formvalue("cbi.submit") then
300 Node.parse(self, 1, ...)
304 for k, j in ipairs(self.children) do
305 for i, v in ipairs(j.children) do
307 and (not v.tag_missing or not v.tag_missing[1])
308 and (not v.tag_invalid or not v.tag_invalid[1])
313 not luci.http.formvalue("cbi.submit") and 0
317 self.dorender = not self.handle or self:handle(state, self.data) ~= false
320 function SimpleForm.render(self, ...)
321 if self.dorender then
322 Node.render(self, ...)
326 function SimpleForm.section(self, class, ...)
327 if instanceof(class, AbstractSection) then
328 local obj = class(self, ...)
332 error("class must be a descendent of AbstractSection")
336 -- Creates a child field
337 function SimpleForm.field(self, class, ...)
339 for k, v in ipairs(self.children) do
340 if instanceof(v, SimpleSection) then
346 section = self:section(SimpleSection)
349 if instanceof(class, AbstractValue) then
350 local obj = class(self, section, ...)
351 obj.track_missing = true
355 error("class must be a descendent of AbstractValue")
359 function SimpleForm.set(self, section, option, value)
360 self.data[option] = value
364 function SimpleForm.del(self, section, option)
365 self.data[option] = nil
369 function SimpleForm.get(self, section, option)
370 return self.data[option]
374 function SimpleForm.get_scheme()
383 AbstractSection = class(Node)
385 function AbstractSection.__init__(self, map, sectiontype, ...)
386 Node.__init__(self, ...)
387 self.sectiontype = sectiontype
389 self.config = map.config
394 self.tag_invalid = {}
395 self.tag_deperror = {}
398 self.addremove = false
402 -- Appends a new option
403 function AbstractSection.option(self, class, option, ...)
404 -- Autodetect from UVL
405 if class == true and self.map:get_scheme(self.sectiontype, option) then
406 local vs = self.map:get_scheme(self.sectiontype, option)
407 if vs.type == "boolean" then
409 elseif vs.type == "list" then
411 elseif vs.type == "enum" or vs.type == "reference" then
418 if instanceof(class, AbstractValue) then
419 local obj = class(self.map, self, option, ...)
421 Node._i18n(obj, self.config, self.section or self.sectiontype, option, ...)
424 self.fields[option] = obj
426 elseif class == true then
427 error("No valid class was given and autodetection failed.")
429 error("class must be a descendant of AbstractValue")
433 -- Parse optional options
434 function AbstractSection.parse_optionals(self, section)
435 if not self.optional then
439 self.optionals[section] = {}
441 local field = luci.http.formvalue("cbi.opt."..self.config.."."..section)
442 for k,v in ipairs(self.children) do
443 if v.optional and not v:cfgvalue(section) then
444 if field == v.option then
447 table.insert(self.optionals[section], v)
452 if field and #field > 0 and self.dynamic then
453 self:add_dynamic(field)
457 -- Add a dynamic option
458 function AbstractSection.add_dynamic(self, field, optional)
459 local o = self:option(Value, field, field)
460 o.optional = optional
463 -- Parse all dynamic options
464 function AbstractSection.parse_dynamic(self, section)
465 if not self.dynamic then
469 local arr = luci.util.clone(self:cfgvalue(section))
470 local form = luci.http.formvaluetable("cbid."..self.config.."."..section)
471 for k, v in pairs(form) do
475 for key,val in pairs(arr) do
478 for i,c in ipairs(self.children) do
479 if c.option == key then
484 if create and key:sub(1, 1) ~= "." then
485 self:add_dynamic(key, true)
490 -- Returns the section's UCI table
491 function AbstractSection.cfgvalue(self, section)
492 return self.map:get(section)
495 -- Removes the section
496 function AbstractSection.remove(self, section)
497 return self.map:del(section)
500 -- Creates the section
501 function AbstractSection.create(self, section)
505 stat = self.map:set(section, nil, self.sectiontype)
507 section = self.map:add(self.sectiontype)
512 for k,v in pairs(self.children) do
514 self.map:set(section, v.option, v.default)
518 for k,v in pairs(self.defaults) do
519 self.map:set(section, k, v)
527 SimpleSection = class(AbstractSection)
529 function SimpleSection.__init__(self, form, ...)
530 AbstractSection.__init__(self, form, nil, ...)
531 self.template = "cbi/nullsection"
535 Table = class(AbstractSection)
537 function Table.__init__(self, form, data, ...)
538 local datasource = {}
539 datasource.config = "table"
542 function datasource.get(self, section, option)
543 return data[section] and data[section][option]
546 function datasource.del(...)
550 function datasource.get_scheme()
554 AbstractSection.__init__(self, datasource, "table", ...)
555 self.template = "cbi/tblsection"
556 self.rowcolors = true
557 self.anonymous = true
560 function Table.parse(self)
561 for i, k in ipairs(self:cfgsections()) do
562 if luci.http.formvalue("cbi.submit") then
568 function Table.cfgsections(self)
571 for i, v in luci.util.kspairs(self.data) do
572 table.insert(sections, i)
581 NamedSection - A fixed configuration section defined by its name
583 NamedSection = class(AbstractSection)
585 function NamedSection.__init__(self, map, section, stype, ...)
586 AbstractSection.__init__(self, map, stype, ...)
587 Node._i18n(self, map.config, section, nil, ...)
590 self.addremove = false
592 -- Use defaults from UVL
593 if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
594 local vs = self.map:get_scheme(self.sectiontype)
595 self.addremove = not vs.unique and not vs.required
596 self.dynamic = vs.dynamic
597 self.title = self.title or vs.title
598 self.description = self.description or vs.descr
601 self.template = "cbi/nsection"
602 self.section = section
605 function NamedSection.parse(self)
606 local s = self.section
607 local active = self:cfgvalue(s)
609 if self.addremove then
610 local path = self.config.."."..s
611 if active then -- Remove the section
612 if luci.http.formvalue("cbi.rns."..path) and self:remove(s) then
615 else -- Create and apply default values
616 if luci.http.formvalue("cbi.cns."..path) then
624 AbstractSection.parse_dynamic(self, s)
625 if luci.http.formvalue("cbi.submit") then
628 if not self.override_scheme and self.map.scheme then
629 local co = self.map:get()
630 local stat, err = self.map.validator:validate_section(self.config, s, co)
632 --self.map.save = false
633 if err.code == luci.uvl.errors.ERR_DEPENDENCY then
634 self.tag_deperror[s] = true
636 self.tag_invalid[s] = true
638 for i, v in ipairs(err.childs) do
639 if v.option and self.fields[v.option] then
640 if v.code == luci.uvl.errors.ERR_DEPENDENCY then
641 self.fields[v.option].tag_reqerror[s] = true
642 elseif v.code == luci.uvl.errors.ERR_OPTION then
643 self.fields[v.option].tag_invalid[s] = true
650 AbstractSection.parse_optionals(self, s)
656 TypedSection - A (set of) configuration section(s) defined by the type
657 addremove: Defines whether the user can add/remove sections of this type
658 anonymous: Allow creating anonymous sections
659 validate: a validation function returning nil if the section is invalid
661 TypedSection = class(AbstractSection)
663 function TypedSection.__init__(self, map, type, ...)
664 AbstractSection.__init__(self, map, type, ...)
665 Node._i18n(self, map.config, type, nil, ...)
667 self.template = "cbi/tsection"
669 self.anonymous = false
671 -- Use defaults from UVL
672 if not self.override_scheme and self.map:get_scheme(self.sectiontype) then
673 local vs = self.map:get_scheme(self.sectiontype)
674 self.addremove = not vs.unique and not vs.required
675 self.dynamic = vs.dynamic
676 self.anonymous = not vs.named
677 self.title = self.title or vs.title
678 self.description = self.description or vs.descr
682 -- Return all matching UCI sections for this TypedSection
683 function TypedSection.cfgsections(self)
685 self.map.uci:foreach(self.map.config, self.sectiontype,
687 if self:checkscope(section[".name"]) then
688 table.insert(sections, section[".name"])
695 -- Limits scope to sections that have certain option => value pairs
696 function TypedSection.depends(self, option, value)
697 table.insert(self.deps, {option=option, value=value})
700 function TypedSection.parse(self)
701 if self.addremove then
703 local crval = REMOVE_PREFIX .. self.config
704 local name = luci.http.formvaluetable(crval)
705 for k,v in pairs(name) do
706 if self:cfgvalue(k) and self:checkscope(k) then
713 for i, k in ipairs(self:cfgsections()) do
714 AbstractSection.parse_dynamic(self, k)
715 if luci.http.formvalue("cbi.submit") then
718 if not self.override_scheme and self.map.scheme then
719 local co = self.map:get()
720 local stat, err = self.map.validator:validate_section(self.config, k, co)
722 --self.map.save = false
723 if err.code == luci.uvl.errors.ERR_DEPENDENCY then
724 self.tag_deperror[k] = true
726 self.tag_invalid[k] = true
728 for i, v in ipairs(err.childs) do
729 if v.option and self.fields[v.option] then
730 if v.code == luci.uvl.errors.ERR_DEPENDENCY then
731 self.fields[v.option].tag_reqerror[k] = true
732 elseif v.code == luci.uvl.errors.ERR_OPTION then
733 self.fields[v.option].tag_invalid[k] = true
740 AbstractSection.parse_optionals(self, k)
743 if self.addremove then
745 local crval = CREATE_PREFIX .. self.config .. "." .. self.sectiontype
746 local name = luci.http.formvalue(crval)
747 if self.anonymous then
753 -- Ignore if it already exists
754 if self:cfgvalue(name) then
758 name = self:checkscope(name)
761 self.err_invalid = true
764 if name and #name > 0 then
772 -- Verifies scope of sections
773 function TypedSection.checkscope(self, section)
774 -- Check if we are not excluded
775 if self.filter and not self:filter(section) then
779 -- Check if at least one dependency is met
780 if #self.deps > 0 and self:cfgvalue(section) then
783 for k, v in ipairs(self.deps) do
784 if self:cfgvalue(section)[v.option] == v.value then
794 return self:validate(section)
798 -- Dummy validate function
799 function TypedSection.validate(self, section)
805 AbstractValue - An abstract Value Type
806 null: Value can be empty
807 valid: A function returning the value if it is valid otherwise nil
808 depends: A table of option => value pairs of which one must be true
809 default: The default value
810 size: The size of the input fields
811 rmempty: Unset value if empty
812 optional: This value is optional (see AbstractSection.optionals)
814 AbstractValue = class(Node)
816 function AbstractValue.__init__(self, map, section, option, ...)
817 Node.__init__(self, ...)
818 self.section = section
821 self.config = map.config
822 self.tag_invalid = {}
823 self.tag_missing = {}
824 self.tag_reqerror = {}
829 self.track_missing = false
833 self.optional = false
835 -- Use defaults from UVL
836 if not self.override_scheme
837 and self.map:get_scheme(self.section.sectiontype, self.option) then
838 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
839 self.rmempty = not vs.required
840 self.cast = (vs.type == "list") and "list" or "string"
841 self.title = self.title or vs.title
842 self.description = self.description or vs.descr
844 if vs.depends and not self.override_dependencies then
845 for i, deps in ipairs(vs.depends) do
846 deps = _uvl_strip_remote_dependencies(deps)
855 -- Add a dependencie to another section field
856 function AbstractValue.depends(self, field, value)
858 if type(field) == "string" then
865 table.insert(self.deps, {deps=deps, add=""})
868 -- Generates the unique CBID
869 function AbstractValue.cbid(self, section)
870 return "cbid."..self.map.config.."."..section.."."..self.option
873 -- Return whether this object should be created
874 function AbstractValue.formcreated(self, section)
875 local key = "cbi.opt."..self.config.."."..section
876 return (luci.http.formvalue(key) == self.option)
879 -- Returns the formvalue for this object
880 function AbstractValue.formvalue(self, section)
881 return luci.http.formvalue(self:cbid(section))
884 function AbstractValue.additional(self, value)
885 self.optional = value
888 function AbstractValue.mandatory(self, value)
889 self.rmempty = not value
892 function AbstractValue.parse(self, section)
893 local fvalue = self:formvalue(section)
894 local cvalue = self:cfgvalue(section)
896 if fvalue and fvalue ~= "" then -- If we have a form value, write it to UCI
897 fvalue = self:transform(self:validate(fvalue, section))
899 self.tag_invalid[section] = true
901 if fvalue and not (fvalue == cvalue) then
902 self:write(section, fvalue)
904 else -- Unset the UCI or error
905 if self.rmempty or self.optional then
907 elseif self.track_missing and (not fvalue or fvalue ~= cvalue) then
908 self.tag_missing[section] = true
913 -- Render if this value exists or if it is mandatory
914 function AbstractValue.render(self, s, scope)
915 if not self.optional or self:cfgvalue(s) or self:formcreated(s) then
918 scope.cbid = self:cbid(s)
919 scope.striptags = luci.util.striptags
921 scope.ifattr = function(cond,key,val)
923 return string.format(
924 ' %s="%s"', tostring(key),
925 luci.util.pcdata(tostring( val
927 or (type(self[key]) ~= "function" and self[key])
935 scope.attr = function(...)
936 return scope.ifattr( true, ... )
939 Node.render(self, scope)
943 -- Return the UCI value of this object
944 function AbstractValue.cfgvalue(self, section)
945 local value = self.map:get(section, self.option)
946 if not self.cast or self.cast == type(value) then
948 elseif self.cast == "string" then
949 if type(value) == "table" then
952 elseif self.cast == "table" then
957 -- Validate the form value
958 function AbstractValue.validate(self, value)
962 AbstractValue.transform = AbstractValue.validate
966 function AbstractValue.write(self, section, value)
967 return self.map:set(section, self.option, value)
971 function AbstractValue.remove(self, section)
972 return self.map:del(section, self.option)
979 Value - A one-line value
980 maxlength: The maximum length
982 Value = class(AbstractValue)
984 function Value.__init__(self, ...)
985 AbstractValue.__init__(self, ...)
986 self.template = "cbi/value"
991 function Value.value(self, key, val)
993 table.insert(self.keylist, tostring(key))
994 table.insert(self.vallist, tostring(val))
998 -- DummyValue - This does nothing except being there
999 DummyValue = class(AbstractValue)
1001 function DummyValue.__init__(self, ...)
1002 AbstractValue.__init__(self, ...)
1003 self.template = "cbi/dvalue"
1007 function DummyValue.parse(self)
1013 Flag - A flag being enabled or disabled
1015 Flag = class(AbstractValue)
1017 function Flag.__init__(self, ...)
1018 AbstractValue.__init__(self, ...)
1019 self.template = "cbi/fvalue"
1025 -- A flag can only have two states: set or unset
1026 function Flag.parse(self, section)
1027 local fvalue = self:formvalue(section)
1030 fvalue = self.enabled
1032 fvalue = self.disabled
1035 if fvalue == self.enabled or (not self.optional and not self.rmempty) then
1036 if not(fvalue == self:cfgvalue(section)) then
1037 self:write(section, fvalue)
1040 self:remove(section)
1047 ListValue - A one-line value predefined in a list
1048 widget: The widget that will be used (select, radio)
1050 ListValue = class(AbstractValue)
1052 function ListValue.__init__(self, ...)
1053 AbstractValue.__init__(self, ...)
1054 self.template = "cbi/lvalue"
1059 self.widget = "select"
1061 if not self.override_scheme
1062 and self.map:get_scheme(self.section.sectiontype, self.option) then
1063 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1064 if self.value and vs.values and not self.override_values then
1065 if self.rmempty or self.optional then
1068 for k, v in pairs(vs.values) do
1070 if not self.override_dependencies
1071 and vs.enum_depends and vs.enum_depends[k] then
1072 for i, dep in ipairs(vs.enum_depends[k]) do
1073 table.insert(deps, _uvl_strip_remote_dependencies(dep))
1076 self:value(k, v, unpack(deps))
1082 function ListValue.value(self, key, val, ...)
1083 if luci.util.contains(self.keylist, key) then
1088 table.insert(self.keylist, tostring(key))
1089 table.insert(self.vallist, tostring(val))
1091 for i, deps in ipairs({...}) do
1092 table.insert(self.deps, {add = "-"..key, deps=deps})
1096 function ListValue.validate(self, val)
1097 if luci.util.contains(self.keylist, val) then
1107 MultiValue - Multiple delimited values
1108 widget: The widget that will be used (select, checkbox)
1109 delimiter: The delimiter that will separate the values (default: " ")
1111 MultiValue = class(AbstractValue)
1113 function MultiValue.__init__(self, ...)
1114 AbstractValue.__init__(self, ...)
1115 self.template = "cbi/mvalue"
1120 self.widget = "checkbox"
1121 self.delimiter = " "
1124 function MultiValue.render(self, ...)
1125 if self.widget == "select" and not self.size then
1126 self.size = #self.vallist
1129 AbstractValue.render(self, ...)
1132 function MultiValue.value(self, key, val)
1133 if luci.util.contains(self.keylist, key) then
1138 table.insert(self.keylist, tostring(key))
1139 table.insert(self.vallist, tostring(val))
1142 function MultiValue.valuelist(self, section)
1143 local val = self:cfgvalue(section)
1145 if not(type(val) == "string") then
1149 return luci.util.split(val, self.delimiter)
1152 function MultiValue.validate(self, val)
1153 val = (type(val) == "table") and val or {val}
1157 for i, value in ipairs(val) do
1158 if luci.util.contains(self.keylist, value) then
1159 result = result and (result .. self.delimiter .. value) or value
1167 StaticList = class(MultiValue)
1169 function StaticList.__init__(self, ...)
1170 MultiValue.__init__(self, ...)
1172 self.valuelist = self.cfgvalue
1174 if not self.override_scheme
1175 and self.map:get_scheme(self.section.sectiontype, self.option) then
1176 local vs = self.map:get_scheme(self.section.sectiontype, self.option)
1177 if self.value and vs.values and not self.override_values then
1178 for k, v in pairs(vs.values) do
1185 function StaticList.validate(self, value)
1186 value = (type(value) == "table") and value or {value}
1189 for i, v in ipairs(value) do
1190 if luci.util.contains(self.valuelist, v) then
1191 table.insert(valid, v)
1198 DynamicList = class(AbstractValue)
1200 function DynamicList.__init__(self, ...)
1201 AbstractValue.__init__(self, ...)
1202 self.template = "cbi/dynlist"
1208 function DynamicList.value(self, key, val)
1210 table.insert(self.keylist, tostring(key))
1211 table.insert(self.vallist, tostring(val))
1214 function DynamicList.validate(self, value, section)
1215 value = (type(value) == "table") and value or {value}
1218 for i, v in ipairs(value) do
1220 not luci.http.formvalue("cbi.rle."..section.."."..self.option.."."..i) then
1221 table.insert(valid, v)
1230 TextValue - A multi-line value
1233 TextValue = class(AbstractValue)
1235 function TextValue.__init__(self, ...)
1236 AbstractValue.__init__(self, ...)
1237 self.template = "cbi/tvalue"
1243 Button = class(AbstractValue)
1245 function Button.__init__(self, ...)
1246 AbstractValue.__init__(self, ...)
1247 self.template = "cbi/button"
1248 self.inputstyle = nil