Very close to good on templates.

This commit is contained in:
Simon Brooke 2018-05-13 12:05:07 +01:00
parent 18f9e67033
commit 8a7a80a461
2 changed files with 141 additions and 65 deletions

View file

@ -125,32 +125,45 @@
(let
[type (:type (:attrs property))
farname (:entity (:attrs property))
farside (application farname)
farside (first
(children
application
#(and
(= (:tag %) :entity)
(= (:name (:attrs %)) farname))))
fs-distinct (flatten
(list
(children farside #(#{"user" "all"} (:distinct (:attrs %))))
(children
(first
(children farside #(= (:tag %) :key)))
#(#{"user" "all"} (:distinct (:attrs %))))))
farkey (or
(:farkey (:attrs property))
(:name (:attrs (first (children (children farside #(= (:tag %) :key))))))
"id")]
(str "{% for record in " farname " %}<option value='record." farkey "'>"
(s/join
" "
(map
#(str "{{record." (:name (:attrs %)) "}}")
(children farside #(some #{"user" "all"} (:distinct %))))))
"</option>%{ endfor %}"))
[(str "{% for record in " farname " %}<option value='{{record." farkey "}}'>"
(s/join " " (map #(str "{{record." (:name (:attrs %)) "}}") fs-distinct))
"</option>{% endfor %}")]))
(defn typedef
"If this `property` is of type `defined`, return its type definition from
this `application`, else nil."
[property application]
(if
(= (:type (:attrs property)) "defined")
(first
(children
application
#(and
(= (:tag %) :typedef)
(= (:name (:attrs %)) (:typedef (:attrs property))))))))
(defn widget-type
"Return an appropriate HTML5 input type for this property."
([property application]
(widget-type property application (typedef property application)))
([property application typedef]
(let [t (if
typedef
(:type (:attrs typedef))
(:type (:attrs property)))]
(case t
("integer" "real" "money") "number"
("uploadable" "image") "file"
"boolean" "checkbox"
"date" "date"
"time" "time"
"text" ;; default
))))
(defn widget
@ -158,7 +171,7 @@
taken from within this `application`."
[field-or-property form entity application]
(let
[name (:name (:attrs field-or-property))
[widget-name (:name (:attrs field-or-property))
property (if
(= (:tag field-or-property) :property)
field-or-property
@ -168,36 +181,52 @@
#(and
(= (:tag %) :property)
(= (:name (:attrs %)) (:property (:attrs field-or-property)))))))
permissions (permissions property entity application)
typedef
show? true ;;(visible? property permissions)
select? (some #{"entity" "list" "link"} (:type (:attrs property)))]
;; TODO: deal with disabling/hiding if no permission
(println "Property:")
(p/pprint property)
permissions (permissions property form entity application)
typedef (typedef property application)
visible-to (visible-to permissions)
;; if the form isn't actually a form, no widget is writable.
writable-by (if (= (:tag form) :form) (writable-by permissions))
select? (#{"entity" "list" "link"} (:type (:attrs property)))]
(if
show?
(formal-primary-key? property entity)
{:tag :input
:attrs {:id widget-name
:name widget-name
:type "hidden"
:value (str "{{record." widget-name "}}")}}
{:tag :p
:attrs {:class "widget"}
:content [{:tag :label
:attrs {:for name}
:attrs {:for widget-name}
:content [(prompt field-or-property form entity application)]}
"TODO: selmer command to hide for all groups except for those for which it is writable"
(if
select?
{:tag :select
:attrs {:id name
:name name}
:attrs {:id widget-name
:name widget-name}
:content (get-options property form entity application)}
{:tag :input
:attrs {:id name
:name name
:type "text" ;; TODO - or other things
:value (str "{{record." name "}}")}})]}
{:tag :input
:attrs {:id name
:name name
:type :hidden
:value (str "{{record." name "}}")}})))
:attrs (merge
{:id widget-name
:name widget-name
:type (widget-type property application typedef)
:value (str "{{record." widget-name "}}")}
(if
(:minimum (:attrs typedef))
{:min (:minimum (:attrs typedef))})
(if
(:maximum (:attrs typedef))
{:max (:maximum (:attrs typedef))}))})
"{% else %}"
"TODO: selmer if command to hide for all groups except to those for which it is readable"
{:tag :span
:attrs {:id widget-name
:name widget-name
:class "pseudo-widget disabled"}
:content [(str "{{record." widget-name "}}")]}
"{% endif %}"
"{% endif %}"]})))
(defn form-to-template
@ -214,7 +243,7 @@
(and form (= "listed" (:properties (:attrs form))))
;; if we've got a form, collect its fields, fieldgroups and verbs
(flatten
(map #(if (some #{:field :fieldgroup :verb} (:tag %)) %)
(map #(if (#{:field :fieldgroup :verb} (:tag %)) %)
(children form)))
(children entity #(= (:tag %) :property)))]
{:tag :div

View file

@ -58,35 +58,82 @@
(:attrs element)))))
(defn typedef
"If this `property` is of type `defined`, return its type definition from
this `application`, else nil."
[property application]
(if
(= (:type (:attrs property)) "defined")
(first
(children
application
#(and
(= (:tag %) :typedef)
(= (:name (:attrs %)) (:typedef (:attrs property))))))))
(defn permissions
"Return appropriate permissions of this `property`, taken from this `entity` of this
`application`."
[property entity application]
(or
(children property #(= (:tag %) :permission))
(children entity :permission)))
`application`, in the context of this `page`."
[property page entity application]
(first
(remove
empty?
(list
(children page #(= (:tag %) :permission))
(children property #(= (:tag %) :permission))
(children entity #(= (:tag %) :permission))
(children application #(= (:tag %) :permission))))))
(defn visible?
"Return `true` if this property is not `system`-distinct, and is readable
to the `public` group; else return a list of groups to which it is readable,
given these `permissions`."
[property permissions]
(let [attributes (attributes property)]
(if
(not
(and
;; if it's immutable and system distinct, the user should not need to see it.
(= (:immutable attributes) "true")
(= (:distinct attributes) "system")))
(map
#(if
(some #{"read" "insert" "noedit" "edit" "all"} (:permission (:attrs %)))
(:group (:attrs %)))
permissions))))
(defn permission-groups
"Return a list of names of groups to which this `predicate` is true of
some permission taken from these `permissions`, else nil."
[permissions predicate]
(let [groups (remove
nil?
(map
#(if
(apply predicate (list %))
(:group (:attrs %)))
permissions))]
(if groups groups)))
(defn singularise [string]
(defn formal-primary-key?
"Does this `prop-or-name` appear to be a property (or the name of a property)
which is a formal primary key of this entity?"
[prop-or-name entity]
(if
(map? prop-or-name)
(formal-primary-key? (:name (:attrs prop-or-name)) entity)
(let [primary-key (first (children entity #(= (:tag %) :key)))
property (first
(children
primary-key
#(and
(= (:tag %) :property)
(= (:name (:attrs %)) prop-or-name))))]
(= (:distinct (:attrs property)) "system"))))
(defn visible-to
"Return a list of names of groups to which are granted read access,
given these `permissions`, else nil."
[permissions]
(permission-groups permissions #(#{"read" "insert" "noedit" "edit" "all"} (:permission (:attrs %)))))
(defn writable-by
"Return a list of names of groups to which are granted read access,
given these `permissions`, else nil."
[permissions]
(permission-groups permissions #(#{"edit" "all"} (:permission (:attrs %)))))
(defn singularise
"Attempt to construct an idiomatic English-language singular of this string."
[string]
(s/replace (s/replace (s/replace string #"_" "-") #"s$" "") #"ie$" "y"))