antonioloureiro / vuejs.jl Goto Github PK
View Code? Open in Web Editor NEWJulia web app builder using Vue.js
License: Other
Julia web app builder using Vue.js
License: Other
create some basic default rules library developers can use
Rules must be suitable for including within prop
rules
Create default submission behavior, including parsing form elements and building output as JSON object.
VueStruct should accept a function argument aimed at (de)constructing an incoming JSON object.
Function should be able to iterate over a JSON object or a VueJS data model, parse its content and return it's output as a Dict
Value attr of v-select is value, when submitting with no selection made, all items are submitted.
expand-on-hover
and permanent
props not being applied on nav initialization.
Most likely only being applied to the internal v-list.
<v-navigation-drawer clipped app width="300" >
<v-list :width="navigation.width" permanent v-for="item in navigation.value" @change="navigation.value= $event" v-bind:key="item.id" expand-on-hover :items="navigation.value" ><v-list-item dense link @click="open(item.href)">
Solutions:
Expand whitelist of attributes that must be applied to v-navigation-drawer
and not the internal list, maintaining current implementation of UPDATE_VALIDATION["v-navigation-drawer"]
.
Add some prefix to attributes
that should be applied to the internal list, eg. list-prop
= some prop value
, instead of just prop=prop_value
.
Or vice-versa, a nav
prefix for attributes
that should be applied to navigation-drawer
, e.g: @el(navigation,"v-navigation-drawer",width=300, nav-expand-on-hover=true, nav-permanent=true (...) )
Update: whitelisting "expand-on-hover" and "permanent"
x.render_func=y->begin
dom_nav=dom(y,prevent_render_func=true)
nav_attrs=Dict()
for (k,v) in Dict("clipped"=>true,"width"=>200, "expand-on-hover"=>true, "permanent"=>true)
haskey(y.attrs,k) ? nav_attrs[k]=y.attrs[k] : nav_attrs[k]=v
end
HtmlElement("v-navigation-drawer",nav_attrs,12,dom_nav)
end
Example: 2 fields, field1 and field2, on the same row of a card, with cols = 3 and cols = 9, respectively, get displayed with classes col-md-6 and col-md-18, also respectively.
function test(req)
@el(field1, "v-text-field", label = "Field 1", value = "Value 1", cols = 3)
@el(field2, "v-text-field", label = "Field 2", value = "Value 2", cols = 9)
return response(page(card([[field1, field2]], cols = 6)))
end
Class values differ for cards of different widths. For instance, a card with cols = 7 generates fields with classes col-md-5 and col-md-15.
Build a prototype application based on an existing table/data based web app
Allow client-side validation [potentially also sanitization] of html elements, with focus on form elements.
Detected with
mr2 = VueElement("r2", "v-text-field", label="clickable", value="clickable", click="say('hi')"
mpage = page([mr2], methods=Dict("say"=>"alert(teste)"), data=Dict("r2"=>"teste"))
HTML output is erroneous
')'="" :value="r2.value" @input="r2.value= $event">
Does not occur when
[Correctly associates events with the DOM and alerts hi
on text-field click
]
mr2 = VueElement("r2", "v-text-field", label="clickable", value="clickable", click=""" say("hi") """)
mpage = page([mr2], methods=Dict("say"=>"alert(teste)"), data=Dict("r2"=>"teste"))
[Will provide further detail]
When creating a web interface, accept and serve literal string content and HtmlElement(s)
When using FormData, ensure element hierarchy is kept.
If submission is a FormData object, add a special HTTP Header.
(Implement server side routine to parse incoming HTTP Requests that can handle multipart content or any regular String/Json content seamlessly, while also maintaining object hierarchy)
Wait for user to finish typing before filtering and rendering search results.
Adjusts filtering operators based on columns data types [different possible filtering options based on the data to which filter applies]
Added the component "v-treeview" to the other already available components in the library.
Implemented as a VueElement since it does not contain any nested elements.
To be defined correctly, it only needs the items attribute to have data in the tree format.
ex: Parent nodes -> id, name, children
ex: Leaf nodes -> id, name
Ex: Rendering - with more options
Ex: Rendering - expecting icons
Each node may have a new field specified by the "prepend-icon-field" attribute, where the icon information is stored. If it doesn't have it, it is considered a folder (eases file explorer rendering)
Up to 6 pages. Extend general use examples in simple_page
.
Create pages for special components.
Create pages to show page
(app) layout.
Create complex page, with multiple components, multiple bindings and submissions
Enables the creation of a datastructure "globals" in the page instance.
Here we can store variable information and then refer to it dynamically in our VueElements that compose our web page.
It works in a similar fashion as the "data" of a vue instance. It gives us the ability to define data in our page instance, in our server side, instead of relying on javascript to define auxiliary datastructures inside elements.
Examples of usage:
Loading state
All Elements "disabled" prop are binded to "globals.loading_state", mimicking a loading state.
Keeping context
In a mapping view, I need to keep the context of the selected taxonomy and this info is not stored in any visual element, i can do this by setting a "globals.selected_taxonomy".
Easy rendering
Mimics the data of a Vue Application and thus can be used to bind to "v-model" cases. The rendering of a stepper relies on defining the v-model the keeps the step state. This can be achieved by defining in server side a "globals.stepState".
Implement a default filtering logic that:
Allows table filtering across all values in all columns [searchAll]
Allows column based filtering [searchColumn]
Adjusts filtering results based on operators
[either as string Greather than
or via operators >
]
Implement a default v-data-table generation behavior that:
Automatically creates methods
for column based filtering
Is capable of mapping a filtering method
to a given column
Is capable of binding dom events and elements with a given filtering behavior [e.g. associating an onchange
event to a v-text-field
that will only filter table values based on values in column prices
]
Default XHR logic using vanilla Javascript
Enrich an HtmlElement through a template, aimed at adding extra DOM, style or layout features.
Single element template should only affect display/visual properties.
Templates should be reusable by other elements.
Most likely adopt "Mustache syntax" {{ @arg }}
Resources:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
Current slot
definition does not handle more complex slots where the slot operates upon arguments.
For instance, a DataTable with expandable rows
<template>
<v-data-table
:headers="headers"
:items="desserts"
:single-expand="singleExpand"
:expanded.sync="expanded"
item-key="name"
show-expand
class="elevation-1"
>
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>Expandable Table</v-toolbar-title>
<v-spacer></v-spacer>
<v-switch v-model="singleExpand" label="Single expand" class="mt-2"></v-switch>
</v-toolbar>
</template>
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">More info about {{ item.name }}</td>
</template>
</v-data-table>
</template>
v-slot:expanded-item="{ headers, item }"
takes 2 arguments, whereas current implementation does not allow arguments in v-slot
definition.
push!(child,HtmlElement("template",Dict("v-slot:$k"=>true),dom(v)))
Proposed solution
When a slot
pair value's also a Dict, allow usage of specific keys to signal whether, or not, to create complex slots.
Example for defining a expandable row slot in a DataTable
slots=Dict("expanded-item"=>
Dict("args"=>"{ headers, item }",
"content"=>HtmlElement("td", Dict("style"=>"height:50px;", ":colspan"=>"headers.length/2"), "Column 1: {{item.ccolumn1}} )
)
)
Changes to VueElement.jl, that need better handling as not force every slot to use these specific keys (args and content)
## Slots
if length(vuel.slots)!=0
child=[]
for (k,v) in vuel.slots
if v isa Dict
push!(child,HtmlElement("template",Dict("v-slot:$k"=>v["args"]),dom(v["content"])))
else
push!(child,HtmlElement("template",Dict("v-slot:$k"=>true),dom(v)))
end
end
vuel.child=child
end
Script is already performed in JS Closure that allows to use object context.
Use Path to modify app_state.
Original Code:
using Base
Base.getproperty(el::HtmlElement, prop::String) = Base.getproperty(el, Symbol(prop))
function Base.getproperty(el::HtmlElement, prop::Symbol)
return getfield(el, prop)
end
function Base.getindex(v::VueElement, i::String)
if i in string.(fieldnames(typeof(v.dom)))
return getproperty(v.dom, Symbol(i))
end
end
My suggestion:
import Base.getindex
function Base.getindex(el::HtmlElement, i::String)
return Base.getindex(el.attrs, i)
end
function Base.getindex(v::VueElement, i::String)
return Base.getindex(v.dom.attrs, i)
end
The idea is to have attrs from VueElement/HtmlElement we just need to get it from dom
SetIndex should invoke update_validate!!
Use similar function to the one used in methods, but assign it to var (key of calling Dict).
Implement default timeout feature, 5s default. 0s = Always visible (will require a created
hook in the data model)
Implement dismiss feature. Add toggle() to KNOWN_JS_EVENTS
(unnecessary)
Leverage dismissible prop (server-side) to indicate whether message should be dynamically toggled.
(Potentially) Implement timeout
with similar functionality to col_format
, function defined in the element itself (implement configurable delay after clicking dismissible slot/icon)
Datatable
Datatable not allowing header
attribute, conflict with implemented column filtering logic
Implement click:row
event to handle row events
The v-progress-linear
component is used to convey data visually to users. It's a practical way to show users that a loading or importing process is being executed at the moment. (see loading bar examples here)
Default v-progress-linear;
By default it has width corresponding to the size of its container, is indeterminate and is hidden (inactive).
@el(loading, "v-progress-linear")
See live example here (user-password: root-root) using the add taxonomy by url screen. (Taxonomy label - "any value", Taxonomy URL - "http://www.xbrl.org/2005/xbrldt-2005.xsd")
To use in client async calls with new data, e.g. with new param
The v-snackbar
component is used to display a quick message to a user. . It's a practical way to show users a success, warning or error message without taking "space" in the page as opposed to the v-alert
.
@el(snackbar, "v-snackbar", timeout = 3000)
Timeout, color and content properties are all binded to the elements data id.timeout, id.color, id.content, so they can be dynamically changed during page interaction.
Implement set cookies in page response, probably binding to app_state.
html should be @html
V-list component doc
V-alert component doc
V-toolbar component doc
Lifecycle hooks
Handsontable
Data-table
VueStruct
iterable
capabilitiesgetindex
and setindex!
to access and manipulate a struct's elementsMethods & Events
STANDARD_APP_EVENTS
in a documentation pagesub_content
to customize submission payloadComputed
and Async Computed
Live examples
v-text-field
of type=date
to basic examplesArchitectural logic #17
Correctly handle rules
properties, as functions defined within rules
cannot be converted or handled as a quoted string inside a JSON object.
When a VueElement is used as col_template in datatable, the attrs are binded to non existent var.
Check behaviour in v-lists.
When using v-html directive
, it appears that any slot
will be ignored. Most likely a Vue and/or Vuetify issue, not a library issue.
Detected at v-alert
, where its contents are bound to a v-html
directive.
Filters do not correctly handle comprehensive search of String
fields/values.
Example:
Searching AB
for equality in a column where ABC
, AB
and ABD
exist, should return all 3 values, as AB
exists in all of them.
Current behaviour is to return only values exactly matching AB
.
While typing, table is automatically rendering results and, in cases like the aforementioned, table will yield empty results until an exact match is found, making it difficult for users to search efficiently.
Proposals:
Either have an occurs
operator that will search String
columns for occurrences of the supplied search value
or,
Alter ==
operator's default behaviour such that when used over a column of Strings
returns occurrence of the supplied search
, and not only the exact matches.
Currently, when building a vuejs app/page, app
name (VueStructยดs id
field) is immutable and always "app".
Same behavior occurs with el
, state
and data
objects, example bellow:
comp=VueStruct("app",garr,data=data,binds=binds,methods=methods)
scripts=[]
push!(scripts,"const app_state = $(JSON.json(comp.def_data))")
## component script
comp_script=[]
push!(comp_script,"el: '#app'")
push!(comp_script,"vuetify: new Vuetify()")
push!(comp_script,"data: app_state")
Proposal is to make el
mutable and user defined, keeping "app" as a fallback.
For a given name
of type String
, let's say "mail_application"
, code above would look as follows:
$> julia page(..., id="mail_application")
function page(...., id::String="app")
(...)
comp=VueStruct(id, garr,data=data,binds=binds,methods=methods)
scripts=[]
stateObject = "$(id)_state"
push!(scripts,"const $(stateObject) = $(JSON.json(comp.def_data))")
## component script
comp_script=[]
push!(comp_script,"el: '#$id'")
push!(comp_script,"vuetify: new Vuetify()")
push!(comp_script,"data: $(stateObject)")
function home(req)
@el(alert, "v-alert", content="Erro 1", type="error", value=false,
icon="mdi-shield-lock-outline", timeout=1200)
@el(alert2, "v-alert", content="Erro 2", type="error", value=true,
icon="mdi-shield-lock-outline", timeout=5000)
@el(okay, "v-alert", content="OKay", type="success", value=true,
dismissible=true, delay=2500, close-icon="mdi-close-box")
@el(nokay, "v-alert", content="Nested oKay", type="success", value=true,
dismissible=true, delay=1500, close-icon="mdi-close-box")
@el(texto, "v-text-field", value="Teste",
outlined=missing,
label="Texto",
append-icon="mdi-close", prepend-icon="mdi-pencil",
created=["this.vv.texto.value='Texto modificado: Hook Created'"],
mounted=["this.vv.texto.value='kooh detnuom morf desrever'"],
storage=false)
@el(innertext, "v-text-field", label="Inner stuff",
slots=Dict("append"=>"{{reversed}}"),
events=
Dict(
"methods"=>Dict(),
"mounted"=>["this.vv.inner.innertext.value='Alterado por hook'"],
"watch"=>
Dict("vv.inner.innertext.value"=>
(args=["newval"],
script="window.alert('watched: ' + newval);"))
)
)
@el(tostore, "v-text-field", label="From storage", storage=true)
@el(cookie, "v-text-field", label="From cookie",
value="sem cookie",
cookie-read-only=false,
cookie="ras",
expiration=90,
interval=1500)
vt = VueStruct("inner", [innertext, cookie])
vv = VueStruct("vv", [alert, nokay, [tostore, vt], texto])
@el(btnteste, "v-btn", value="ativar nested success alert", click="vv.nokay.value=true")
@el(btn, "v-btn", value="ativar erro", click="vv.alert.value=true")
@el(btns, "v-btn", value="ativar alert2", click="alert2.value=true")
@el(google, "v-btn", value="Go to google method", click="togoogle('teste')")
vs = VueStruct("vs", [alert2, [btns, google]])
vt = VueStruct("fileholder", [vs])
p = page([okay, vv, vs, [btn, btnteste]],
binds=Dict("vs.fileholder.r1.value"=>"r2.value"),
methods=Dict(
"togoogle"=>(args=["file"], script="open('http://google.com')")),
computed=Dict("reversed"=>
"""return this.vv.texto.value.split('').reverse().join('');""")
)
return response(p)
end
router = HTTP.Router()
@HTTP.register(router, "/", home)
try close(server) catch; end
server = Sockets.listen(ip"127.0.0.1", 8887)
@async HTTP.serve(router, server=server)
@info ("Ready")
Implemented support for Hooks
that receive no input arguments.
Struct HookHandler @ VueElement.jl
mutable struct HookHandler <: EventHandler
kind::String
path::String
function_script::String
end
Changes to VueStruct.jl
Added hooks
property
(...) hooks::Vector{EventHandler}
Hooks
are created from a VueStruct's grid array garr
hooks=create_hooks(garr)
And then handled similarly to other Events, but does not call function_script!
since there's no parsing or special internal construction over the provided script to obtain the final script. Inclusion of our closure
script was not working properly and is potentially not required as the keyword this
can be used to refer to the intended app variable.
Further testing required for deeper VueStructs
new_hs=Vector{HookHandler}()
update_events!(comp,new_hs)
sort!(new_hs,by=x->length(x.path),rev=false)
comp.hooks=new_hs
Altered update_events!
method signatures to allow dispatch on different instances of EventHandler
update_events!(vs,new_es::Vector{T} where T<:EventHandler,scope="")
function update_events!(vs::Array,new_es::Vector{T} where T<:EventHandler, scope="")
function update_events!(vs::VueStruct,new_es::Vector{EventHandler},scope="")
function update_events!(vs::VueStruct,new_hs::Vector{HookHandler}, scope="")
Altered Events.jl method events_script
since hook instantiation slightly differs from previous implemented logic (methods, computed and watched)
for hook in KNOWN_HOOKS
hf=filter(x->x.kind==hook, vs.hooks)
if length(hf) > 0
push!(els,"$hook() {"*join(map(y->y.function_script, hf),";")*"}")
end
end
return join(els,",")
Examples
timeout
attribute will be internally handled to produce a created
hook for both v-alert
s. alert
will automatically be dismissed
after x milliseconds
.
close-icon
attribute allows dismissible
prop icon customization. Could not find any native way to implement this without forcing the user to create a slot
. This way, user does not need to provide a complete slot definition just to alter an icon.
delay
attribute refers to the time between a user's click on dismiss
and the alert
disappearing.
The v-text-field
has explicit created
and beforeCreate
hooks. These will be internally handled similarly to how other events are handled.
@el(alert, "v-alert", content="Erro", type="error", value=true,
timeout=1500, icon="mdi-shield-lock-outline")
@el(okay, "v-alert", content="OKay", type="success", value=true,
dismissible=true, timeout=2000, delay=1500, close-icon="mdi-close-box")
@el(texto, "v-text-field", value="Teste", created=["this.texto.value='Texto modificado'"], beforeCreate="window.alert('teste')")
return response(page([alert, okay, texto]))
List of known hooks
const KNOWN_HOOKS = [
"beforeCreate",
"created",
"beforeMount",
"mounted",
"beforeUpdate",
"updated",
"beforeDestroy",
"destroyed",
"activated",
"deactivated"]
Some components will not correctly handle props
with stringified boolean values ("true" or "false").
E.g: Handsontable will incorrectly display "true" for every row header when given rowHeaders="true"
, and some properties do not accept stringified booleans (like search
and filter
).
Handsontable also does not seem to accept empty attributes/props.
Implemented LIBRARY_RULES
in Core/Base.jl
LIBRARY_RULES =
Dict("maxchars"=> (x->return """ value => value.length <= $x || 'Max $x characters' """),
"minchars"=> (x->return """ value => value.length > $x || 'Min $x characters' """),
"required"=> (x->return " value => !!value || 'Required' "),
"min"=>(x->return " value => value >= $x || 'Minimum value is $x' "),
"max"=>(x->return " value => value <= $x || 'Maximum value is $x' "),
"type"=>(x->return "value => typeof(value) === '$x' || 'Please provide a $x'"),
"in"=>(x->return """ value => $x.includes(value) || 'Value not in $x' """)
)
Further testing and validation required for pattern and/or regex expressions
# do further testing for
"pattern"=>(x->return "value => !value || RegExp($x).test(value) || 'E-mail must be valid'")
Implement wrapper around vuetify's v-list
family components, adding improved display capabilities.
Implement default logic for adding list-elements, client-side..
Define and specify core architectural decisions.
Build support documentation with code examples and respective outputs
VueElement should receive both a validation function and a parsing function.
Validator
shall return true
or false
Parser
shall operate on the VueElement and return a significant value
Any v-data-table
with non-empty items will not work when placed inside a VueStruct
.
In the images, t2
is placed at page level and works as expected.
t
is placed inside a @vs teste
and will not display due to an error when accessing the table's col_format
properties.
The reactive prop :col_format
is correctly declared as teste.t.col_format
but the v-html
directive is trying to access t.col_format.col_X
instead of teste.t.col_format.col_X
, which leads to a TypeError: Cannot read property 'col_format' of undefined
v-html
definition for col_format
occurs @ Update_validation_datatable.jl, lines 123 to 125
The datatable
validator is oblivious to the fact the table
may be contained in one, or more, nested structures, therefore cannot correctly define the path
for the col_format
properties.
Proposed implementation for toolbar using VueHolder
Requesting review and feedback for improvement and potential bug fixing
Extensive examples for v-toolbar usage
function exemplo_toolbar(req)
title_template(dialog) = "{{$dialog.mockup_select.value !== null && $dialog.mockup_select.value.length > 0 ? String($dialog.mockup_select.value.length) + ' selected ' : 'Dynamic title'}}"
generic_title(x) = toolbartitle(x, align="left", cols=4)
@el(mockup_close, "v-btn", value="<v-icon>mdi-close</v-icon>", icon=true, dark=true, large=true, cols=1)
@el(dialog_close, "v-btn", value="<v-icon>mdi-close</v-icon>", icon=true, dark=true, large=true, cols=1, click="toggledialog(this.app['active'])")
@el(mockup_submit, "v-btn", value="Save", click="this.app['active'].mockup_alert.value = true", style=Dict("padding-top"=>"1%"), text=true, color="white", large=true)
@el(mockup_input, "v-text-field", label="Mockup", cols=4)
@el(mockup_select, "v-select", label="Select stuff", items=["A","B","C","D"], multiple=true, cols=6)
@el(mockup_switch, "v-switch", hint="Show sub form", persistent-hint=true, cols=4)
@el(mockup_area, "v-textarea", label="Mockup", cols=2)
@el(mockup_alert, "v-alert", type="info", content="Saved!", value=false)
@el(mockup_search, "v-btn", value="<v-icon>mdi-magnify<v-icon>", icon=true, color="white", cols=1)
# menu
mockup_actions = [Dict("title"=>"Clear", "val"=>Dict("what"=>"clear")), Dict("title"=>"Toggle", "val"=>Dict("what"=>"toggle"))]
@el(mockup_menu, "v-menu", items=mockup_actions)
@el(mockup_menu_btn, "v-btn", menu=mockup_menu,
content="<v-icon>mdi-dots-vertical</v-icon>",
click="side_actions(item.val.what)",
icon=true, color="white", cols=1)
@el(mockup_hamburger, "v-btn", menu=mockup_menu, click="side_actions(item.val.what)", value="<v-icon>mdi-menu</v-icon>", icon=true, color="white", cols=1)
##
#= Page components =#
# a simple toolbar in a card with a title and an action button
c1 = card([
toolbar([toolbartitle("Toolbar", align="left"), spacer(cols=7), mockup_hamburger]),
spacer(rows=1), # spacer here because toolbar will have an absolute position, thus the card content would get slightly behind the toolbar
[card(["Content"], cols=6)] ], cols=6)
# card where content is placed over the toolbar
c2 = card([
toolbar([toolbartitle("Toolbar extended", align="left"), spacer(cols=7), mockup_menu_btn], extended=true),
card([html("h3", "Content", Dict(), cols=4), html("v-divider", "", Dict(), cols=2), mockup_area], cols=4)
], cols=6)
# card with nested toolbars
@el(smaller_close, "v-btn", icon=true, small=true, color="white", value="<v-icon>mdi-close</v-icon>", cols=1) #using dense requires some resizing of elements so that they do not extend past the bar
c3 = card([
toolbar([toolbartitle("Toolbar #3", align="left"), spacer(cols=7), mockup_menu_btn]),
spacer(rows=1),
card([
toolbar([toolbartitle("Inner toolbar (nav=true & dense=true)", style=Dict("padding"=>0), align="left"), spacer(cols=7), smaller_close], dense=true),
spacer(rows=1),
[card([html("h3", "Content", Dict("align"=>"left"), cols=6), html("v-divider", "", Dict(), cols=6)]),
card([html("h3", "Content", Dict("align"=>"left"), cols=6), html("h3", "More content", Dict("align"=>"left"), cols=6)])]
], cols=12)
], cols=12)
# simple dialog
@el(toggle_d1, "v-btn", value="Open simple dialog", click="toggledialog(d1)", cols=2, text=true, outlined=true)
d1 = dialog("d1",
[
toolbar([generic_title(title_template("d1")), spacer(cols=7), dialog_close]),
spacer(rows=1),
card([mockup_select], cols=12)
], width="50vw", active=false)
# Using toolbar for form actions
@el(toggle_d2, "v-btn", value="Open form dialog", click="toggledialog(d2)", cols=2, text=true, outlined=true)
d2 = dialog("d2",
[toolbar(
[generic_title("Save placed in the toolbar"),
spacer(cols=6),
mockup_submit,
mockup_menu_btn
]),
spacer(rows=1),
card([[mockup_input, mockup_input], mockup_select], cols=12),
mockup_alert
], width="50vw", active=false)
# Toolbar where nav = false
@el(toggle_d3, "v-btn", value="Open form dialog #2", click="toggledialog(d3)", cols=2, text=true, outlined=true)
@dialog(d3,
[toolbar(
[generic_title("Toolbar nav = false #1"),
spacer(cols=7),
mockup_menu_btn
], nav=false),
html("h4", "When nav=false, the toolbar is not placed in the container edges", Dict(), cols=12),
card([
[mockup_input, mockup_input],
mockup_select,
toolbar([generic_title("Toolbar nav = false #2"), spacer(cols=7), dialog_close], nav=false, dense=true, color="black")],
cols=12),
], width="50vw", active=false)
# Card with more interactions
@el(toggle_d4, "v-btn", value="Open form dialog #3", click="toggledialog(d4)", text=true, outlined=true, cols=2)
@el(mockup_date_input, "v-text-field", type="date", label="Birthday", cols=6)
@el(mockup_input_2, "v-text-field", label="Name", cols=6)
subform = card([
toolbar([toolbartitle("Sub form", cols=4, align="left"), spacer(cols=6), mockup_search, mockup_menu_btn], nav=true),
spacer(rows=1),
[mockup_input_2, mockup_date_input]
], hover=true, tile=true, cols=8)
subform.attrs["v-show"] = "d4.mockup_switch.value == true"
@dialog(d4,
[toolbar(
[generic_title(title_template("d4")),
spacer(cols=6),
mockup_search,
mockup_menu_btn
], nav=true),
mockup_alert,
card([toolbar([mockup_search], collapse=true), spacer(rows=1),
[mockup_input, mockup_input], mockup_select, mockup_switch], cols=12),
subform #sub form
], width="50vw", active=false)
bottom_toolbar = toolbar([toolbartitle("Bottom Toolbar", style=Dict("color"=>"black"), cols=2), toggle_d1, toggle_d2, toggle_d3, toggle_d4], color="white", outlined=true, bottom=true, cols=12)
#= =#
return response(page(
[
[c1, c2], c3,
d1,d2,d3,d4,
bottom_toolbar
],
methods=Dict(
"rand_dialog"=>"function(){dialogs = ['d1','d2','d3','d4']; return app[dialogs[Math.floor(Math.random() * dialogs.length)]]}",
"toggledialog"=>"function(dialog){
if (!dialog) {dialog = this.rand_dialog()}
app['active'] = dialog;
dialog.active.value = !dialog.active.value;
}",
"side_actions"=>"
function(what){
if (what == 'toggle') { this.toggledialog(app['active']) }
else if (what == 'clear') {
for (let key in app['active']) { if (key !== 'active' && app['active'][key].hasOwnProperty('value')) { app['active'][key].value = null;} }
}
}"
)))
end
Result should be similar to figure
HtmlElement should have an Alias, too long to instantiate
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.