diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/html/catom.nim | 2 | ||||
-rw-r--r-- | src/html/dom.nim | 46 | ||||
-rw-r--r-- | src/html/enums.nim | 39 | ||||
-rw-r--r-- | src/html/formdata.nim | 12 | ||||
-rw-r--r-- | src/server/buffer.nim | 117 |
5 files changed, 130 insertions, 86 deletions
diff --git a/src/html/catom.nim b/src/html/catom.nim index 5e5f6174..5a05ffab 100644 --- a/src/html/catom.nim +++ b/src/html/catom.nim @@ -42,8 +42,10 @@ macro makeStaticAtom = satIntegrity = "integrity" satIsmap = "ismap" satLanguage = "language" + satMax = "max", satMedia = "media" satMethod = "method" + satMin = "min", satMultiple = "multiple" satName = "name" satNomodule = "nomodule" diff --git a/src/html/dom.nim b/src/html/dom.nim index 692a80de..41869a95 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -1008,13 +1008,13 @@ iterator inputs(form: HTMLFormElement): HTMLInputElement {.inline.} = iterator radiogroup(form: HTMLFormElement): HTMLInputElement {.inline.} = for input in form.inputs: - if input.inputType == INPUT_RADIO: + if input.inputType == itRadio: yield input iterator radiogroup(document: Document): HTMLInputElement {.inline.} = for input in document.elements(TAG_INPUT): let input = HTMLInputElement(input) - if input.form == nil and input.inputType == INPUT_RADIO: + if input.form == nil and input.inputType == itRadio: yield input iterator radiogroup*(input: HTMLInputElement): HTMLInputElement {.inline.} = @@ -1764,14 +1764,13 @@ func isSubmitButton*(element: Element): bool = return element.attr(satType) == "submit" elif element of HTMLInputElement: let element = HTMLInputElement(element) - return element.inputType in {INPUT_SUBMIT, INPUT_IMAGE} + return element.inputType in {itSubmit, itImage} return false func canSubmitImplicitly*(form: HTMLFormElement): bool = const BlocksImplicitSubmission = { - INPUT_TEXT, INPUT_SEARCH, INPUT_URL, INPUT_TEL, INPUT_EMAIL, INPUT_PASSWORD, - INPUT_DATE, INPUT_MONTH, INPUT_WEEK, INPUT_TIME, INPUT_DATETIME_LOCAL, - INPUT_NUMBER + itText, itSearch, itURL, itTel, itEmail, itPassword, itDate, itMonth, + itWeek, itTime, itDatetimeLocal, itNumber } var found = false for control in form.controls: @@ -2197,20 +2196,24 @@ proc sheets*(document: Document): seq[CSSStylesheet] = func inputString*(input: HTMLInputElement): string = case input.inputType - of INPUT_CHECKBOX, INPUT_RADIO: - if input.checked: "*" - else: " " - of INPUT_SEARCH, INPUT_TEXT, INPUT_EMAIL, INPUT_URL, INPUT_TEL: + of itCheckbox, itRadio: + if input.checked: + "*" + else: + " " + of itSearch, itText, itEmail, itURL, itTel: input.value.padToWidth(int(input.attrulgz(satSize).get(20))) - of INPUT_PASSWORD: + of itPassword: '*'.repeat(input.value.len).padToWidth(int(input.attrulgz(satSize).get(20))) - of INPUT_RESET: + of itReset: if input.value != "": input.value else: "RESET" - of INPUT_SUBMIT, INPUT_BUTTON: - if input.value != "": input.value - else: "SUBMIT" - of INPUT_FILE: + of itSubmit, itButton: + if input.value != "": + input.value + else: + "SUBMIT" + of itFile: if input.file.isNone: "".padToWidth(int(input.attrulgz(satSize).get(20))) else: @@ -2236,7 +2239,7 @@ func isButton*(element: Element): bool = return true if element of HTMLInputElement: let element = HTMLInputElement(element) - return element.inputType in {INPUT_SUBMIT, INPUT_BUTTON, INPUT_RESET, INPUT_IMAGE} + return element.inputType in {itSubmit, itButton, itReset, itImage} return false func action*(element: Element): string = @@ -3148,13 +3151,12 @@ proc resetElement*(element: Element) = of TAG_INPUT: let input = HTMLInputElement(element) case input.inputType - of INPUT_SEARCH, INPUT_TEXT, INPUT_PASSWORD: - input.value = input.attr(satValue) - of INPUT_CHECKBOX, INPUT_RADIO: + of itCheckbox, itRadio: input.checked = input.attrb(satChecked) - of INPUT_FILE: + of itFile: input.file = none(URL) - else: discard + else: + input.value = input.attr(satValue) input.invalid = true of TAG_SELECT: let select = HTMLSelectElement(element) diff --git a/src/html/enums.nim b/src/html/enums.nim index 856b7813..1cac0742 100644 --- a/src/html/enums.nim +++ b/src/html/enums.nim @@ -1,17 +1,32 @@ import std/strutils import std/tables -import utils/twtstr - import chame/tags type InputType* = enum - INPUT_TEXT, INPUT_BUTTON, INPUT_CHECKBOX, INPUT_COLOR, INPUT_DATE, - INPUT_DATETIME_LOCAL, INPUT_EMAIL, INPUT_FILE, INPUT_HIDDEN, INPUT_IMAGE, - INPUT_MONTH, INPUT_NUMBER, INPUT_PASSWORD, INPUT_RADIO, INPUT_RANGE, - INPUT_RESET, INPUT_SEARCH, INPUT_SUBMIT, INPUT_TEL, INPUT_TIME, INPUT_URL, - INPUT_WEEK + itText = "text" + itButton = "button" + itCheckbox = "checkbox" + itColor = "color" + itDate = "date" + itDatetimeLocal = "datetime-local" + itEmail = "email" + itFile = "file" + itHidden = "hidden" + itImage = "image" + itMonth = "month" + itNumber = "number" + itPassword = "password" + itRadio = "radio" + itRange = "range" + itReset = "reset" + itSearch = "search" + itSubmit = "submit" + itTel = "tel" + itTime = "time" + itURL = "url" + itWeek = "week" ButtonType* = enum BUTTON_SUBMIT, BUTTON_RESET, BUTTON_BUTTON @@ -31,7 +46,7 @@ type NOTATION_NODE = 12 const InputTypeWithSize* = { - INPUT_SEARCH, INPUT_TEXT, INPUT_EMAIL, INPUT_PASSWORD, INPUT_URL, INPUT_TEL + itSearch, itText, itEmail, itPassword, itURL, itTel } const AutocapitalizeInheritingElements* = { @@ -56,9 +71,7 @@ const ResettableElements* = { func getInputTypeMap(): Table[string, InputType] = for i in InputType: - let enumname = $InputType(i) - let tagname = enumname.split('_')[1..^1].join('_').toLowerAscii() - result[tagname] = InputType(i) + result[$InputType(i)] = InputType(i) const inputTypeMap = getInputTypeMap() @@ -66,6 +79,6 @@ func inputType*(s: string): InputType = return inputTypeMap.getOrDefault(s.toLowerAscii()) const AutoDirInput* = { - INPUT_HIDDEN, INPUT_TEXT, INPUT_SEARCH, INPUT_TEL, INPUT_URL, INPUT_EMAIL, - INPUT_PASSWORD, INPUT_SUBMIT, INPUT_RESET, INPUT_BUTTON + itHidden, itText, itSearch, itTel, itURL, itEmail, itPassword, itSubmit, + itReset, itButton } diff --git a/src/html/formdata.nim b/src/html/formdata.nim index cfdf6dce..d34b0194 100644 --- a/src/html/formdata.nim +++ b/src/html/formdata.nim @@ -106,7 +106,7 @@ func toNameValuePairs*(list: seq[FormDataEntry]): # https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set # Warning: we skip the first "constructing entry list" check; the caller must # do it. -proc constructEntryList*(form: HTMLFormElement, submitter: Element = nil, +proc constructEntryList*(form: HTMLFormElement; submitter: Element = nil; encoding = "UTF-8"): seq[FormDataEntry] = assert not form.constructingEntryList form.constructingEntryList = true @@ -118,9 +118,9 @@ proc constructEntryList*(form: HTMLFormElement, submitter: Element = nil, continue if field of HTMLInputElement: let field = HTMLInputElement(field) - if field.inputType in {INPUT_CHECKBOX, INPUT_RADIO} and not field.checked: + if field.inputType in {itCheckbox, itRadio} and not field.checked: continue - if field.inputType == INPUT_IMAGE: + if field.inputType == itImage: var name = field.attr(satName) if name != "": name &= '.' @@ -139,17 +139,17 @@ proc constructEntryList*(form: HTMLFormElement, submitter: Element = nil, elif field of HTMLInputElement: let field = HTMLInputElement(field) case field.inputType - of INPUT_CHECKBOX, INPUT_RADIO: + of itCheckbox, itRadio: let v = field.attr(satValue) let value = if v != "": v else: "on" entrylist.add((name, value)) - of INPUT_FILE: + of itFile: #TODO file discard - of INPUT_HIDDEN: + of itHidden: if name.equalsIgnoreCase("_charset_"): entrylist.add((name, encoding)) else: diff --git a/src/server/buffer.nim b/src/server/buffer.nim index 71deed82..bcc39aa2 100644 --- a/src/server/buffer.nim +++ b/src/server/buffer.nim @@ -346,7 +346,7 @@ func canSubmitOnClick(fae: FormAssociatedElement): bool = if fae of HTMLButtonElement and HTMLButtonElement(fae).ctype == BUTTON_SUBMIT: return true if fae of HTMLInputElement and - HTMLInputElement(fae).inputType in {INPUT_SUBMIT, INPUT_BUTTON}: + HTMLInputElement(fae).inputType in {itSubmit, itButton}: return true return false @@ -1390,13 +1390,7 @@ proc readSuccess*(buffer: Buffer, s: string): ReadSuccessResult {.proxy.} = of TAG_INPUT: let input = HTMLInputElement(buffer.document.focus) case input.inputType - of INPUT_SEARCH, INPUT_TEXT, INPUT_PASSWORD: - input.value = s - input.invalid = true - buffer.do_reshape() - result.repaint = true - result.open = implicitSubmit(input) - of INPUT_FILE: + of itFile: let cdir = parseURL("file://" & getCurrentDir() & DirSep) let path = parseURL(s, cdir) if path.isSome: @@ -1405,7 +1399,12 @@ proc readSuccess*(buffer: Buffer, s: string): ReadSuccessResult {.proxy.} = buffer.do_reshape() result.repaint = true result.open = implicitSubmit(input) - else: discard + else: + input.value = s + input.invalid = true + buffer.do_reshape() + result.repaint = true + result.open = implicitSubmit(input) of TAG_TEXTAREA: let textarea = HTMLTextAreaElement(buffer.document.focus) textarea.value = s @@ -1535,57 +1534,84 @@ proc click(buffer: Buffer, textarea: HTMLTextAreaElement): ClickResult = repaint: repaint ) +const InputTypePrompt = [ + itText: "TEXT", + itButton: "", + itCheckbox: "", + itColor: "Color", + itDate: "Date", + itDatetimeLocal: "Local date/time", + itEmail: "E-Mail", + itFile: "Filename", + itHidden: "", + itImage: "Image", + itMonth: "Month", + itNumber: "Number", + itPassword: "Password", + itRadio: "Radio", + itRange: "Range", + itReset: "", + itSearch: "Search", + itSubmit: "", + itTel: "Telephone number", + itTime: "Time", + itURL: "URL input", + itWeek: "Week" +] + proc click(buffer: Buffer, input: HTMLInputElement): ClickResult = - result.repaint = buffer.restoreFocus() + let repaint = buffer.restoreFocus() case input.inputType - of INPUT_SEARCH: - result.repaint = buffer.setFocus(input) - result.readline = some(ReadLineResult( - prompt: "SEARCH: ", - value: input.value - )) - of INPUT_TEXT, INPUT_PASSWORD: - result.repaint = buffer.setFocus(input) - result.readline = some(ReadLineResult( - prompt: "TEXT: ", - value: input.value, - hide: input.inputType == INPUT_PASSWORD - )) - of INPUT_FILE: - result.repaint = buffer.setFocus(input) + of itFile: var path = if input.file.isSome: input.file.get.path.serialize_unicode() else: "" - result.readline = some(ReadLineResult( - prompt: "Filename: ", - value: path - )) - of INPUT_CHECKBOX: + return ClickResult( + repaint: buffer.setFocus(input) or repaint, + readline: some(ReadLineResult( + prompt: InputTypePrompt[itFile] & ": ", + value: path + )) + ) + of itCheckbox: input.checked = not input.checked input.invalid = true - result.repaint = true buffer.do_reshape() - of INPUT_RADIO: + return ClickResult(repaint: true) + of itRadio: for radio in input.radiogroup: radio.checked = false radio.invalid = true input.checked = true input.invalid = true - result.repaint = true buffer.do_reshape() - of INPUT_RESET: + return ClickResult(repaint: true) + of itReset: if input.form != nil: input.form.reset() - result.repaint = true buffer.do_reshape() - of INPUT_SUBMIT, INPUT_BUTTON: + return ClickResult(repaint: true) + return ClickResult(repaint: false) + of itSubmit, itButton: if input.form != nil: - result.open = submitForm(input.form, input) + return ClickResult(open: submitForm(input.form, input), repaint: repaint) + return ClickResult(repaint: false) else: - result.repaint = buffer.restoreFocus() + # default is text. + var prompt = InputTypePrompt[input.inputType] + if input.inputType == itRange: + prompt &= " (" & input.attr(satMin) & ".." & input.attr(satMax) & ")" + return ClickResult( + repaint: buffer.setFocus(input) or repaint, + readline: some(ReadLineResult( + prompt: prompt & ": ", + value: input.value, + hide: input.inputType == itPassword + )) + ) -proc click(buffer: Buffer, clickable: Element): ClickResult = +proc click(buffer: Buffer; clickable: Element): ClickResult = case clickable.tagType of TAG_LABEL: return buffer.click(HTMLLabelElement(clickable)) @@ -1602,9 +1628,9 @@ proc click(buffer: Buffer, clickable: Element): ClickResult = of TAG_INPUT: return buffer.click(HTMLInputElement(clickable)) else: - result.repaint = buffer.restoreFocus() + return ClickResult(repaint: buffer.restoreFocus()) -proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = +proc click*(buffer: Buffer; cursorx, cursory: int): ClickResult {.proxy.} = if buffer.lines.len <= cursory: return var called = false var canceled = false @@ -1617,11 +1643,12 @@ proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = if not canceled: if clickable != nil: var res = buffer.click(clickable) - res.repaint = called + if called: # override repaint + res.repaint = true return res return ClickResult(repaint: called) -proc select*(buffer: Buffer, selected: seq[int]): ClickResult {.proxy.} = +proc select*(buffer: Buffer; selected: seq[int]): ClickResult {.proxy.} = if buffer.document.focus != nil and buffer.document.focus of HTMLSelectElement: let select = HTMLSelectElement(buffer.document.focus) @@ -1643,7 +1670,7 @@ proc select*(buffer: Buffer, selected: seq[int]): ClickResult {.proxy.} = proc readCanceled*(buffer: Buffer): bool {.proxy.} = return buffer.restoreFocus() -proc findAnchor*(buffer: Buffer, anchor: string): bool {.proxy.} = +proc findAnchor*(buffer: Buffer; anchor: string): bool {.proxy.} = return buffer.document != nil and buffer.document.findAnchor(anchor) != nil type GetLinesResult* = tuple[ @@ -1652,7 +1679,7 @@ type GetLinesResult* = tuple[ bgcolor: CellColor ] -proc getLines*(buffer: Buffer, w: Slice[int]): GetLinesResult {.proxy.} = +proc getLines*(buffer: Buffer; w: Slice[int]): GetLinesResult {.proxy.} = var w = w if w.b < 0 or w.b > buffer.lines.high: w.b = buffer.lines.high |