"""
TIM plugin: a textfield
"""
from dataclasses import dataclass, asdict
from typing import Any
from flask import render_template_string
from marshmallow.utils import missing
from tim_common.common_schemas import TextfieldStateModel
from tim_common.markupmodels import GenericMarkupModel
from tim_common.pluginserver_flask import (
GenericHtmlModel,
GenericAnswerModel,
create_blueprint,
PluginAnswerResp,
PluginAnswerWeb,
PluginReqs,
)
from tim_common.utils import Missing
[docs]@dataclass
class TextfieldMarkupModel(GenericMarkupModel):
autosave: bool | Missing = missing
autogrow: bool | Missing = missing
autoUpdateTables: bool | Missing = True
clearstyles: bool | Missing = missing
cols: int | Missing = missing
errormessage: str | Missing | None = missing
form: bool | Missing = missing
rows: int | Missing = missing
ignorestyles: bool | Missing = missing
initword: str | Missing | None = missing
inputplaceholder: str | Missing | None = missing
inputstem: str | Missing | None = missing
nosave: bool | Missing = missing
points_array: list[list[float]] | Missing = missing
readOnlyStyle: str | Missing | None = missing
showname: int | Missing | None = missing
tag: str | Missing | None = missing
textarea: bool | Missing = missing
validinput: str | Missing | None = missing
downloadButton: str | Missing = missing
downloadButtonFile: str | Missing = missing
[docs]@dataclass
class TextfieldInputModel:
"""Model for the information that is sent from browser (plugin AngularJS component)."""
c: str
nosave: bool | Missing = missing
[docs]@dataclass
class TextfieldHtmlModel(
GenericHtmlModel[TextfieldInputModel, TextfieldMarkupModel, TextfieldStateModel]
):
[docs] def get_component_html_name(self) -> str:
return "textfield-runner"
[docs] def get_static_html(self) -> str:
return render_static_textfield(self)
[docs]@dataclass
class TextfieldAnswerModel(
GenericAnswerModel[TextfieldInputModel, TextfieldMarkupModel, TextfieldStateModel]
):
pass
[docs]def render_static_textfield(m: TextfieldHtmlModel) -> str:
return render_template_string(
"""
<div>
<h4>{{ header or '' }}</h4>
<p class="stem">{{ stem or '' }}</p>
<div><label>{{ inputstem or '' }} <span>
<input type="text"
class="form-control"
placeholder="{{ inputplaceholder or '' }}"
size="{{cols}}"></span></label>
</div>
<button class="timButton">
{{ buttonText or button or "Save" }}
</button>
<a>{{ resetText }}</a>
<p class="plgfooter">{{ '' }}</p>
</div>""".strip(),
**asdict(m.markup),
)
[docs]class TextfieldAnswerWeb(PluginAnswerWeb, total=False):
clear: bool
[docs]def answer(args: TextfieldAnswerModel) -> PluginAnswerResp:
web: TextfieldAnswerWeb = {}
result: PluginAnswerResp = {"web": web}
c = args.input.c
nosave = args.input.nosave
if args.markup.nosave:
nosave = True
if not nosave:
save: dict[str, Any] = {"c": c}
if not args.markup.clearstyles and args.state is not None:
if args.state.styles:
save = {"c": c, "styles": args.state.styles}
result["save"] = save
web["result"] = "saved"
if args.markup.clearstyles:
web["clear"] = True
return result
[docs]def reqs() -> PluginReqs:
templates = [
"""``` {#PLUGINNAMEHERE plugin="textfield"}
header: # otsikko, tyhjä = ei otsikkoa
stem: # kysymys, tyhjä = ei kysymystä
inputstem: # vastaus, tyhjä = ei vastausta
tag: # seurantaid, tyhjä = ei seurantaid:tä
initword: # alkuarvo, tyhjä = ei alkuarvoa
buttonText: Save # PAINIKKEEN NIMI, TYHJÄ = EI PAINIKETTA
cols: 7 # kentän koko, numeraalinen
autosave: false # autosave, pois päältä
validinput: '^(hyv|hyl|[12345])$' # käyttäjäsyötteen rajoitin, tyhjä = ei rajoitusta
errormessage: #inputcheckerin virheselite, tyhjä = selite on inputchecker
```""",
]
return {
"js": ["/field/js/build/textfield.js"],
"multihtml": True,
"css": ["/field/css/field.css"],
"editor_tabs": [
{
"text": "Fields",
"items": [
{
"text": "Text",
"items": [
{
"data": '#- {defaultplugin="textfield" readonly="view" .fieldCell}\n',
"text": "defaultplugin/textfield",
"expl": "Attribuutit kappaleelle jossa inline textfield",
},
{
"data": "textfield",
"text": "teksti: textfield",
"expl": "Pelkkä kentän tyyppi: textfield",
},
{
"data": "%% 'd;dsum' | gfrange(1,5,'cols: 5') %%\n",
"text": "Joukko numeroituja kenttiä",
"expl": "Valmis joukko samannimisiä numeroituja kenttiä",
},
{
"data": "{#tf1#}",
"text": "Tekstikenttä (inline, autosave)",
"expl": "Luo kenttä jonka syöte on tekstiä",
},
{
"data": templates[0].strip(),
"text": "Tekstikenttä (laajennettu)",
"expl": "Luo kenttä jonka syöte on tekstiä",
},
{
"data": "{#tf2 readOnlyStyle: plaintext #}",
"text": "Label kenttä (inline, read only)",
"expl": "Luo kenttä jonka syötettä käyttäjä ei voi muokata",
},
{
"data": "{#username showname: 1, inputstem: 'Nimi: '#}",
"text": "Käyttäjän nimi (inline)",
"expl": "Kenttä joka näyttää käyttäjän nimen, tarvitsee lohkon alkuun defaultplugin",
},
],
},
],
},
],
}
textfield_route = create_blueprint(
__name__,
"tf",
TextfieldHtmlModel,
TextfieldAnswerModel,
answer,
reqs,
)