Commit ef729b48 authored by Steffen Michels's avatar Steffen Michels

Merge branch 'select2' into 'master'

Add withSelect2 Editor modifier to use the Select2 jQuery plugin instead of plain select tags

See merge request !433
parents b92b96af 18e80527
Pipeline #44329 passed with stage
in 13 minutes and 15 seconds
......@@ -43,6 +43,7 @@ Examples/BasicAPIExamples/SequentialExamples/CoffeeMachine
Examples/BasicAPIExamples/SequentialExamples/EditPerson1by1
Examples/BasicAPIExamples/SequentialExamples/Palindrome
Examples/DynamicEditor/TypedTaskEditor
Examples/Extensions/Select2
Examples/GIS/LeafletMapExample
Examples/WasmTest
Tests/Interactive/GenericEditors/TestADTMultiCons
......
definition module BasicAPIExamples.Extensions.Select2
import iTasks
from iTasks.Extensions.Admin.WorkflowAdmin import :: Workflow
wf :: String -> Workflow
main :: Task ()
implementation module BasicAPIExamples.Extensions.Select2
import Text
import iTasks
import iTasks.UI.Editor.Common
import iTasks.Extensions.Editors.Select2
wf :: String -> Workflow
wf a = workflow a "Try out the Select2 extension for searchable select boxes" main
main :: Task ()
main = ArrangeWithTabs False @>>
allTasks
[ select2AndNormal "Enter expression (withSelect2)" enterExpression
, select2AndNormal "Dropdown" enterWithDropdown
, select2AndNormal "Dropdown with groups" enterWithDropdownWithGroups
, withShared fruits \shared ->
Title "Dropdown with dynamic options" @>> (
(Hint "Enter options:" @>> updateSharedInformation [] shared) ||-
select2AndNormal "" (dropdownWithDynamicOptions shared)
)
]
@! ()
where
select2AndNormal title task = Title title @>> ArrangeHorizontal @>>
(
forever (task True "with Select2 input fields")
-&&-
forever (task False "with standard HTML select boxes")
)
@! ()
:: Expr
= Literal Int
| Add Expr Expr
| Sum [Expr]
derive class iTask Expr
enterExpression :: !Bool !String -> Task Expr
enterExpression select2 hint =
Hint (concat ["Enter an expression ",hint,":"]) @>>
enterInformation [EnterUsing id editor] >>! \expr ->
Hint "You entered:" @>>
viewInformation [] expr >>! return
where
editor = if select2 (withSelect2 True gEditor{|*|}) gEditor{|*|}
fruits =: ["Apple", "Banana", "Cherry"]
veggies =: ["Arugula", "Broccoli", "Chickpea"]
enterWithDropdown :: !Bool !String -> Task String
enterWithDropdown select2 hint =
Hint (concat ["Enter a value ",hint,":"]) @>>
enterInformation [EnterUsing id (choose fruits)] @ ((!!) fruits) >>! \choice ->
Hint "You entered:" @>>
viewInformation [] choice >>! return
where
choose = if select2 chooseWithSelect2Dropdown chooseWithDropdown
enterWithDropdownWithGroups :: !Bool !String -> Task String
enterWithDropdownWithGroups select2 hint =
Hint (concat ["Enter a value ",hint,":"]) @>>
enterInformation [EnterUsing id editor] @ (fst o (!!) options) >>! \choice ->
Hint "You entered:" @>>
viewInformation [] choice >>! return
where
editor = bijectEditorValue
(\i -> [i])
(\sel -> case sel of [x] -> x; _ -> 0)
(withConstantChoices numberedOptions
(if select2 select2DropdownWithGroups dropdownWithGroups))
numberedOptions =
[({ChoiceText | id=i, text=t}, group) \\ (t,group) <- options & i <- [0..]]
options =
[(opt, Just "Fruits") \\ opt <- fruits] ++
[(opt, Just "Veggies") \\ opt <- veggies]
derive class iTask ChoiceText
dropdownWithDynamicOptions :: !(SimpleSDSLens [String]) !Bool !String -> Task [String]
dropdownWithDynamicOptions options select2 hint =
ArrangeVertical @>>
Hint (concat ["Make a choice ",hint,":"]) @>>
editSelectionWithShared
[ SelectUsing
(\opts -> [{ChoiceText | id=i,text=o} \\ o <- opts & i <- [0..]])
(\opts is -> [opts !! i \\ i <- is])
editor
]
options
(const []) >>! \choices ->
Hint "You entered:" @>>
viewInformation [] choices >>! return
where
editor = if select2 select2Dropdown dropdown <<@ multipleAttr True
Version: 1.4
Global
ProjectRoot: ...
Target: iTasks
Exec: {Project}/BasicAPIExamples/Extensions/Select2
ByteCode: {Project}/BasicAPIExamples/Extensions/Select2.bc
CodeGen
CheckStacks: False
CheckIndexes: True
OptimiseABC: True
GenerateByteCode: True
Application
HeapSize: 209715200
StackSize: 20971520
ExtraMemory: 8192
IntialHeapSize: 204800
HeapSizeMultiplier: 4096
ShowExecutionTime: False
ShowGC: False
ShowStackSize: False
MarkingCollector: False
DisableRTSFlags: False
StandardRuntimeEnv: True
Profile
Memory: False
MemoryMinimumHeapSize: 0
Time: False
Stack: False
Dynamics: True
GenericFusion: False
DescExL: True
Output
Output: ShowConstructors
Font: Monaco
FontSize: 9
WriteStdErr: False
Link
LinkMethod: Static
GenerateRelocations: False
GenerateSymbolTable: False
GenerateLinkMap: False
LinkResources: False
ResourceSource:
GenerateDLL: False
ExportedNames:
StripByteCode: True
KeepByteCodeSymbols: True
PrelinkByteCode: True
Paths
Path: {Project}
Precompile:
Postlink:
MainModule
Name: BasicAPIExamples.Extensions.Select2Main
Dir: {Project}
Compiler
NeverMemoryProfile: False
NeverTimeProfile: False
StrictnessAnalysis: True
ListTypes: StrictExportTypes
ListAttributes: True
Warnings: True
Verbose: True
ReadableABC: False
ReuseUniqueNodes: True
Fusion: False
module BasicAPIExamples.Extensions.Select2Main
import BasicAPIExamples.Extensions.Select2
Start :: *World -> *World
Start world = doTasks main world
definition module iTasks.Extensions.Editors.Select2
/**
* Allows you to replace standard HTML `select` boxes in editors with Select2
* input fields (https://select2.org/). This lets the user search for options.
*/
from StdMaybe import :: Maybe
from iTasks.UI.Editor import :: Editor
from iTasks.UI.Editor.Controls import :: ChoiceText
/**
* Replaces HTML `select` boxes in the editor with Select2 input fields
* (https://select2.org/).
*
* @param When `True`, also the `select` boxes of child editors, which are
* added dynamically, are modified to use Select2.
*/
withSelect2 :: !Bool !(Editor a) -> Editor a
/**
* A replacement for `dropdown` (iTasks.UI.Editor.Controls) using Select2 input
* fields (https://select2.org/).
*/
select2Dropdown :: Editor ([ChoiceText], [Int])
/**
* A replacement for `dropdownWithGroups` (iTasks.UI.Editor.Controls) using
* Select2 input fields (https://select2.org/).
*/
select2DropdownWithGroups :: Editor ([(ChoiceText, Maybe String)], [Int])
/**
* A replacement for `chooseWithDropdown` (iTasks.UI.Editor.Common) using
* Select2 input fields (https://select2.org/).
*/
chooseWithSelect2Dropdown :: [String] -> Editor Int
implementation module iTasks.Extensions.Editors.Select2
import StdEnv
import StdMaybe
import Data.Func
import ABC.Interpreter.JavaScript
import iTasks
JQUERY_JS :== "/select2/jquery-3.5.1.slim.min.js"
SELECT2_JS :== "/select2/select2.min.js"
SELECT2_CSS :== "/select2/select2.min.css"
jQuery :== jsGlobal "jQuery"
withSelect2 :: !Bool !(Editor a) -> Editor a
withSelect2 observeMutations editor=:{Editor | genUI} =
{ Editor
| editor
& genUI = withClientSideInit initUI genUI
}
where
initUI :: !JSVal !*JSWorld -> *JSWorld
initUI me world
# world = addCSSFromUrl SELECT2_CSS world
# (orgInitDOMEl,world) = me .# "initDOMEl" .? world
# (fun,world) = jsWrapFun (initDOMEl me orgInitDOMEl) me world
= (me .# "initDOMEl" .= fun) world
initDOMEl me orgInitDOMEl _ world
# world = (jsCall (orgInitDOMEl .# "bind") me .$! ()) world
# (fun,world) = jsWrapFun (initDOMEl` me) me world
= addJSFromUrl JQUERY_JS (Just fun) world
initDOMEl` me _ world
# (fun,world) = jsWrapFun (initDOMEl`` me) me world
= addJSFromUrl SELECT2_JS (Just fun) world
initDOMEl`` me _ world
# (onSelect,world) = jsWrapFun onSelect me world
// Install select2 on the currently present select fields
# world = installSelect2 onSelect (me .# "domEl") world
| not observeMutations
= world
// Install a MutationObserver to also install select fields added later
# (onDOMMutation,world) = jsWrapFun (onDOMMutation onSelect) me world
# (observer,world) = jsNew "MutationObserver" onDOMMutation world
# config = jsRecord ["childList" :> True, "subtree" :> True]
= (observer .# "observe" .$! (me .# "domEl", config)) world
installSelect2 onSelect elem world
# (tag,world) = elem .# "tagName" .? world
| jsValToString` "" tag == "SELECT"
= initSelect2 elem world
# (elem,world) = (jQuery .$ elem) world
# (elems,world) = (elem .# "find" .$ "select") world
# (elems,world) = jsValToList` elems id world
= seqSt initSelect2 elems world
where
initSelect2 elem world
# (jelem,world) = (jQuery .$ elem) world
// Don't reinitialize; https://select2.org/programmatic-control/methods#checking-if-the-plugin-is-initialized
# (initialized,world) = (jelem .# "hasClass" .$ "select2-hidden-accessible") world
| jsValToBool` False initialized
= world
// Initialize
# (select2,world) = (jelem .# "select2" .$ ()) world
# world = (select2 .# "on" .$! ("select2:select", onSelect)) world
// Move original select tag to inside the select2 div, so that node list indices computed by iTasks still work
= (elem .# "nextElementSibling" .# "appendChild" .$! elem) world
onSelect {[0]=ev} world
# target = ev .# "target"
# (value,world) = ev .# "params" .# "data" .# "id" .? world
# value = jsValToString` "" value
# (options,world) = target .# "options" .? world
# (options,world) = jsValToList` options id world
# world = selectOption value options world
# (ev,world) = jsNew "Event" "change" world
= (target .# "dispatchEvent" .$! ev) world
where
selectOption _ [] world
= world
selectOption id [opt:opts] world
# (value,world) = opt .# "value" .? world
| jsValToString` "" value == id
= (opt .# "selected" .= True) world
= selectOption id opts world
onDOMMutation onSelect {[0]=mutations} world
# (mutations,world) = jsValToList` mutations id world
= seqSt handleMutation mutations world
where
handleMutation mutation world
# (addedNodes,world) = jsValToList` (mutation .# "addedNodes") id world
= seqSt (installSelect2 onSelect) addedNodes world
select2Dropdown :: Editor ([ChoiceText], [Int])
select2Dropdown = withSelect2 False dropdown
select2DropdownWithGroups :: Editor ([(ChoiceText, Maybe String)], [Int])
select2DropdownWithGroups = withSelect2 False dropdownWithGroups
chooseWithSelect2Dropdown :: [String] -> Editor Int
chooseWithSelect2Dropdown labels = bijectEditorValue
(\i -> [i])
(\sel -> case sel of [x] -> x; _ -> 0)
(withConstantChoices options select2Dropdown <<@ multipleAttr False)
where
options = [{ChoiceText|id=i,text=t} \\ t <- labels & i <- [0..]]
......@@ -66,6 +66,7 @@ selectEditor [SelectInList toView fromView:_] = SelectUsing toView fromView choi
selectEditor [SelectInGrid toView fromView:_] = SelectUsing toView fromView grid
selectEditor [SelectInTree toView fromView:_] = SelectUsing toView fromView tree
selectEditor [SelectInTabs toView fromView:_] = SelectUsing toView fromView tabBar
selectEditor [SelectUsing toView fromView editor:_] = SelectUsing toView fromView editor
selectEditor [_:es] = selectEditor es
selectEditor [] = SelectUsing (const []) (\_ _ -> []) dropdown //Empty dropdown
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment