about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/html/catom.nim2
-rw-r--r--src/html/dom.nim46
-rw-r--r--src/html/enums.nim39
-rw-r--r--src/html/formdata.nim12
-rw-r--r--src/server/buffer.nim117
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