Module:Calculator - Wikipedia
From Wikipedia, the free encyclopedia
local Calculator = {} Calculator.__index__ = Calculator function Calculator:new(params) params = params or {} local root = params.root or mw.html.create(getElement(params)) if params.scoped ~= false then root:addClass('calculator-container') :attr('data-calculator-refresh-on-load', boolString(params.refreshOnLoad)) end root:addClass(params.class) :attr('style', params.style) local obj = { root = root, noJSFallback = '', templatestyles = {} } if params.noJSFallback then -- If fallback exists, wrap with calculatorgadget-enabled class root:addClass('calculatorgadget-enabled') :css('display', 'none') -- No need to create html node for fallback if it's an empty string if params.noJSFallback ~= '' then obj.noJSFallback = tostring( mw.html.create(getElement(params)) :addClass('calculatorgadget-fallback') :wikitext(params.noJSFallback) ) end end self.__index = self return setmetatable(obj, Calculator) end function Calculator:field(params) return self.root:tag('span') :addClass('calculator-field') :addClass(params.class) :attr('id', params.id and ('calculator-field-' .. params.id) or nil) :attr('data-calculator-type', params.type or 'number') :attr('style', params.style) :css('display', params.type == 'hidden' and 'none' or nil) :attr('data-calculator-formula', params.formula) :attr('data-calculator-readonly', boolString(params.readonly)) :attr('data-calculator-size', params.size) :attr('data-calculator-max', params.max) :attr('data-calculator-min', params.min) :attr('data-calculator-placeholder', params.placeholder) :attr('data-calculator-name', params.name) :attr('data-calculator-precision', params.precision) :attr('data-calculator-exponential-precision', params['exponential-precision']) :attr('data-calculator-decimals', params.decimals) :attr('data-calculator-nan-text', params['NaN-text']) :attr('data-calculator-class', params['class-live']) :attr('aria-describedby', params['aria-describedby']) :attr('aria-labelledby', params['aria-labelledby']) :attr('aria-label', params['aria-label']) :attr('data-calculator-enterkeyhint', params.enterkeyhint) :attr('data-calculator-mapping', params.mapping) :attr('data-calculator-aria-role', params.role) :attr('data-calculator-aria-atomic', params['aria-atomic']) :attr('data-calculator-aria-relevant', params['aria-relevant']) :attr('data-calculator-aria-live', params['aria-live']) :attr('data-calculator-checked', boolString(params.checked)) :attr('data-calculator-value', params.value) :attr('data-calculator-inputmode', params.inputmode or (params.type == 'text' and params.mapping == nil and 'numeric' or nil)) :attr('data-calculator-step', params.step) :wikitext(params.default or '') end function Calculator:button(params) local button = self.root:tag('span') :addClass('calculator-field-button') :addClass(params.class) :attr('id', params.id) :attr('title', params.title) :attr('style', params.style) :attr('data-calculator-alt', params.alt) :attr('data-calculator-disabled', boolString(params.disabled)) :attr('data-calculator-for', params['for']) :attr('data-calculator-formula', params.formula) :attr('role', params.role) :attr('data-calculator-aria-live', params['aria-live']) :attr('data-calculator-delay', params.delay) :attr('data-calculator-max-iterations', params['max iterations']) :attr('data-calculator-toggle', params.toggle) :attr('data-calculator-class', params['class-live']) :wikitext(params.contents or params.text or params[1] or 'Click me') local type = params.type or 'plain' if type ~= 'plain' then button:addClass('cdx-button') button:addClass('cdx-button--action-'..type) button:addClass('cdx-button--weight-'..(params.weight or 'normal')) button:addClass('cdx-button--size-'..(params.size or 'medium')) end return button end function Calculator:hidden(params) params.type = 'hidden' return self:field(params) end function Calculator:plain(params) params.type = 'plain' return self:field(params) end function Calculator:text(params) params.type = 'text' return self:field(params) end function Calculator:radio(params) params.type = 'radio' return self:field(params) end function Calculator:checkbox(params) params.type = 'checkbox' return self:field(params) end function Calculator:codexText(params) params.type = 'text' params['class-live'] = 'cdx-text-input__input ' .. (params['class-live'] or '') return self:field(params) end function Calculator:codexRadio(params) params.type = 'radio' params['class-live'] = 'cdx-radio__input ' .. (params['class-live'] or '') local outer = self:subContainer({ class = 'cdx-radio ' .. (params.inline and 'cdx-radio--inline' or '') .. (params['codex-div-class'] or '') }) local inner = outer:subContainer({ class = 'cdx-radio__wrapper' }) inner:field(params) inner:tag('span'):addClass('cdx-radio__icon') inner:codexLabel({ ['codex-class'] = 'cdx-radio__label', ['for'] = params.id, description = params.description, label = params.label }) if params.custominput then outer:tag('div') :addClass('cdx-radio__custom-input') :wikitext(params.custominput) end return outer end function Calculator:codexCheckbox(params) params.type = 'checkbox' params['class-live'] = 'cdx-checkbox__input ' .. (params['class-live'] or '') local outer = self:subContainer({ class = 'cdx-checkbox ' .. (params.inline and 'cdx-checkbox--inline' or '') .. (params['codex-div-class'] or '') }) local inner = outer:subContainer({ class = 'cdx-checkbox__wrapper' }) inner:field(params) inner:tag('span'):addClass('cdx-checkbox__icon') inner:codexLabel({ ['codex-class'] = 'cdx-checkbox__label', ['for'] = params.id, description = params.description, label = params.label }) if params.custominput then outer:tag('div') :addClass('cdx-checkbox__custom-input') :wikitext(params.custominput) end return outer end function Calculator:codexToggle(params) params.type = 'checkbox' params['class-live'] = 'cdx-toggle-switch__input ' .. (params['codex-live'] or '') params.default = '<span style="display:none">' .. (params.default or '') .. '</span>' local container = self:subContainer({ element = 'span', class = 'cdx-toggle-switch' }) container:field(params) container:tag('span'):addClass('cdx-toggle-switch__switch') :tag('span'):addClass('cdx-toggle-switch__switch__grip') container:codexLabel({ ['codex-class'] = 'cdx-toggle-switch__label ' .. (params.hiddendescription and 'cdx-label--visually-hidden' or ''), ['for'] = params.id, description = params.description, label = params.label, style = params.labelstyle }) return container end function Calculator:passthru(params) params.type = 'passthru' return self:field(params) end function Calculator:label(params) if params.codex then return self:codexLabel(params) end return self.root:tag('span') :addClass('calculator-field-label') :addClass(params.class) :attr('data-for', params['for'] and ('calculator-field-'.. params['for']) or nil) :attr('data-calculator-class', params['class-live']) :attr('title', params.title) :attr('id', params.id) :attr('style', params.style) :wikitext(params.label or params[1]) end function Calculator:codexLabel(params) local div = self.root:tag('div') :addClass('cdx-label') :addClass(params['codex-class']) local outerSpan = div:tag('span') :addClass('calculator-field-label cdx-label__label') :addClass(params.class) :attr('data-for', params['for'] and ('calculator-field-' .. params['for']) or nil) :attr('data-calculator-class', params['class-live']) :attr('title', params.title) :attr('id', params.id) :attr('style', params.style) outerSpan:tag('span') :addClass('cdx-label__label__text') :wikitext(params.label or params[1]) if params.flag then outerSpan:tag('span') :addClass('cdx-label__label__optional-flag') :wikitext(' ' .. params.flag) end if params.description then -- Note: this doesn't yet set proper aria-describedby on the input widget div:tag('span') :addClass('cdx-label__description') :attr('id', params['description-id']) :wikitext(params.description) end return div end function Calculator:hideIfZero(params) table.insert(self.templatestyles, 'Template:Calculator-hideifzero/styles.css') return self.root:tag(getElement(params)) :addClass('calculator-field calculator-hideifzero') :addClass(params.starthidden and 'calculator-value-false' or nil) :addClass(params.class) :attr('data-calculator-type', 'passthru') :attr('style', params.style) :attr('data-calculator-formula', params.formula) :attr('data-calculator-aria-live', params['aria-live']) :attr('data-calculator-aria-atomic', params['aria-atomic']) :attr('role', params.role) :attr('data-calculator-class', params['class-live']) :wikitext(params.text or params[1]) end -- Add arbitrary wikitext within the calculator container function Calculator:wikitext(text) self.root:wikitext(text) end -- Add arbitrary html node within the calculator container. -- Note: if you would need to add calculator fields within that -- node, use subContainer() instead. function Calculator:tag(tagName) return self.root:tag(tagName) end -- Add a wrapper html node within the calculator container, -- for instance for styling. Additional calculator fields can -- be added inside it. function Calculator:subContainer(params) params = params or {} local subRoot = self.root:tag(getElement(params)) return Calculator:new({ root = subRoot, scoped = false, class = params.class, style = params.style, noJSFallback = params.noJSFallback }) end function Calculator:__tostring() local frame = mw.getCurrentFrame() local styles = '' for idx, page in ipairs(self.templatestyles) do styles = styles .. frame:extensionTag('templatestyles', '', {src = page}) end return styles .. tostring(self.root) .. self.noJSFallback .. '[[Category:Pages using gadget Calculator]]' end function getElement(params) return params.element or (params.block == false and 'span' or 'div') end function boolString(value) return value and tostring(value) or nil end return Calculator