Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
iTasks-SDK
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
75
Issues
75
List
Boards
Labels
Service Desk
Milestones
Merge Requests
7
Merge Requests
7
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
clean-and-itasks
iTasks-SDK
Commits
8ebd0c58
Commit
8ebd0c58
authored
Feb 28, 2013
by
Bas Lijnse
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More UI diff improvements
git-svn-id:
https://svn.cs.ru.nl/repos/iTask-system/trunk@2370
63da3aa8-80fd-4f01-9db8-e6ea747a3da2
parent
55382fe3
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
141 additions
and
139 deletions
+141
-139
Client/app/container/Panel.js
Client/app/container/Panel.js
+2
-4
Client/app/container/Window.js
Client/app/container/Window.js
+10
-1
Client/app/controller/Controller.js
Client/app/controller/Controller.js
+20
-14
Server/API/Core/LayoutCombinators.icl
Server/API/Core/LayoutCombinators.icl
+8
-9
Server/Framework/UIDiff.dcl
Server/Framework/UIDiff.dcl
+3
-28
Server/Framework/UIDiff.icl
Server/Framework/UIDiff.icl
+98
-83
No files found.
Client/app/container/Panel.js
View file @
8ebd0c58
...
@@ -26,10 +26,8 @@ Ext.define('itwc.container.Panel',{
...
@@ -26,10 +26,8 @@ Ext.define('itwc.container.Panel',{
this
.
callParent
(
arguments
);
this
.
callParent
(
arguments
);
},
},
afterRender
:
function
()
{
afterRender
:
function
()
{
var
me
=
this
;
this
.
callParent
(
arguments
);
this
.
initHotkeys
();
me
.
callParent
();
me
.
initHotkeys
();
},
},
onDestroy
:
function
()
{
onDestroy
:
function
()
{
this
.
destroyHotkeys
();
this
.
destroyHotkeys
();
...
...
Client/app/container/Window.js
View file @
8ebd0c58
...
@@ -2,7 +2,8 @@ Ext.define('itwc.container.Window',{
...
@@ -2,7 +2,8 @@ Ext.define('itwc.container.Window',{
extend
:
'
Ext.window.Window
'
,
extend
:
'
Ext.window.Window
'
,
alias
:
'
widget.itwc_window
'
,
alias
:
'
widget.itwc_window
'
,
requires
:
[
'
itwc.layout.container.Box
'
],
requires
:
[
'
itwc.layout.container.Box
'
],
mixins
:
[
'
itwc.component.edit.Editable
'
],
mixins
:
[
'
itwc.component.edit.Editable
'
,
'
itwc.container.HotkeyArea
'
],
autoShow
:
true
,
autoShow
:
true
,
autoScroll
:
true
,
autoScroll
:
true
,
...
@@ -45,5 +46,13 @@ Ext.define('itwc.container.Window',{
...
@@ -45,5 +46,13 @@ Ext.define('itwc.container.Window',{
me
.
viewport
=
me
.
findViewport
();
me
.
viewport
=
me
.
findViewport
();
me
.
viewport
.
fireEvent
(
'
action
'
,
me
.
closeTaskId
,
'
Close
'
);
me
.
viewport
.
fireEvent
(
'
action
'
,
me
.
closeTaskId
,
'
Close
'
);
return
false
;
return
false
;
},
afterRender
:
function
()
{
this
.
callParent
(
arguments
);
this
.
initHotkeys
();
},
onDestroy
:
function
()
{
this
.
destroyHotkeys
();
this
.
callParent
(
arguments
);
}
}
});
});
Client/app/controller/Controller.js
View file @
8ebd0c58
...
@@ -223,28 +223,34 @@ Ext.define('itwc.controller.Controller', {
...
@@ -223,28 +223,34 @@ Ext.define('itwc.controller.Controller', {
partialUpdate
:
function
(
updates
)
{
partialUpdate
:
function
(
updates
)
{
var
me
=
this
,
var
me
=
this
,
numUpdates
=
updates
.
length
,
numUpdates
=
updates
.
length
,
update
,
cmp
,
i
;
update
,
cmp
,
operations
,
numOperations
,
operation
,
i
,
j
;
for
(
i
=
0
;
i
<
numUpdates
;
i
++
)
{
for
(
i
=
0
;
i
<
numUpdates
;
i
++
)
{
update
=
updates
[
i
];
update
=
updates
[
i
];
try
{
try
{
if
(
cmp
=
me
.
viewport
.
getComponentByPath
(
update
.
path
))
{
if
(
cmp
=
me
.
viewport
.
getComponentByPath
(
update
.
path
))
{
//Try to call the update method
operations
=
update
.
operations
;
if
(
cmp
&&
typeof
cmp
[
update
.
method
]
==
'
function
'
)
{
numOperations
=
operations
.
length
;
cmp
[
update
.
method
].
apply
(
cmp
,
update
.
arguments
);
}
else
{
//If multiple operations need to be done on the same component, don't layout in between
//If replace is not defined as function, try remove followed by add
if
(
numOperations
>
1
&&
cmp
.
doLayout
)
{
if
(
update
.
method
==
'
replace
'
&&
typeof
cmp
[
'
remove
'
]
==
'
function
'
&&
typeof
cmp
[
'
insert
'
]
==
'
function
'
)
{
cmp
.
suspendLayout
=
true
;
me
.
warn
(
"
Doing inefficient replace by using remove followed by add in
"
+
update
.
arguments
[
1
].
xtype
);
}
cmp
.
suspendLayout
=
true
;
//Don't layout in between remove and add
for
(
j
=
0
;
j
<
numOperations
;
j
++
)
{
cmp
.
remove
(
update
.
arguments
[
0
]);
operation
=
operations
[
j
];
cmp
.
insert
(
update
.
arguments
[
0
],
update
.
arguments
[
1
]);
cmp
.
suspendLayout
=
false
;
//Try to call the update method
cmp
.
doLayout
();
//Now do the layout
if
(
cmp
&&
typeof
cmp
[
operation
.
method
]
==
'
function
'
)
{
cmp
[
operation
.
method
].
apply
(
cmp
,
operation
.
arguments
);
}
else
{
}
else
{
me
.
error
(
"
Can't apply
"
+
update
.
method
+
"
to
"
+
cmp
.
getId
()
+
"
(
"
+
cmp
.
getXType
()
+
"
)
"
);
me
.
error
(
"
Can't apply
"
+
operation
.
method
+
"
to
"
+
cmp
.
getId
()
+
"
(
"
+
cmp
.
getXType
()
+
"
)
"
);
}
}
}
}
if
(
cmp
.
suspendLayout
)
{
cmp
.
suspendLayout
=
false
;
cmp
.
doLayout
();
}
}
else
{
}
else
{
me
.
error
(
"
Could not find user interface component at location
"
+
update
.
path
);
me
.
error
(
"
Could not find user interface component at location
"
+
update
.
path
);
}
}
...
...
Server/API/Core/LayoutCombinators.icl
View file @
8ebd0c58
...
@@ -301,22 +301,22 @@ sequenceMerge :: ParallelLayout
...
@@ -301,22 +301,22 @@ sequenceMerge :: ParallelLayout
sequenceMerge
=
merge
sequenceMerge
=
merge
where
where
merge
prompt
=:{
UIControlSequence
|
attributes
,
controls
,
direction
}
defs
merge
prompt
=:{
UIControlSequence
|
attributes
,
controls
,
direction
}
defs
#
(
actions
,
parts
)
=
unzip
(
map
processDef
defs
)
#
parts
=
(
map
processDef
defs
)
#
controls
=
decoratePrompt
controls
++
[
c
\\
Just
(
Lef
t
c
)
<-
parts
]
#
controls
=
decoratePrompt
controls
++
[
c
\\
(_,_,
Jus
t
c
)
<-
parts
]
#
windows
=
[
w
\\
Just
(
Right
w
)
<-
parts
]
#
actions
=
flatten
[
a
\\
(
a
,_,_
)
<-
parts
]
#
actions
=
foldr
(++)
[]
actions
#
windows
=
flatten
[
w
\\
(_,
w
,_)
<-
parts
]
=
UIAbstractContainer
{
UIAbstractContainer
|
attributes
=
attributes
,
controls
=
controls
,
direction
=
direction
,
actions
=
actions
,
windows
=
windows
,
hotkeys
=[]}
=
UIAbstractContainer
{
UIAbstractContainer
|
attributes
=
attributes
,
controls
=
controls
,
direction
=
direction
,
actions
=
actions
,
windows
=
windows
,
hotkeys
=[]}
//Action sets do not get a panel in the sequence. Their actions are passed upwards
//Action sets do not get a panel in the sequence. Their actions are passed upwards
processDef
(
UIActionSet
{
UIActionSet
|
actions
})
processDef
(
UIActionSet
{
UIActionSet
|
actions
})
=
(
actions
,
Nothing
)
=
(
actions
,
[],
Nothing
)
processDef
def
processDef
def
|
hasWindowAttr
(
uiDefAttributes
def
)
//TODO: Pass hotkeys along
|
hasWindowAttr
(
uiDefAttributes
def
)
//TODO: Pass hotkeys along
#
(
actions
,_,
window
)
=
placeWindowActions
(
uiDefActions
def
)
(
defToWindow
(
layoutControls
def
))
#
(
actions
,_,
window
)
=
placeWindowActions
(
uiDefActions
def
)
(
defToWindow
(
layoutControls
def
))
=
([],
Just
(
Right
window
)
)
=
([],
[
window
:
uiDefWindows
def
],
Nothing
)
|
otherwise
|
otherwise
#
(
actions
,_,
panel
)
=
placePanelActions
(
uiDefActions
def
)
False
(
defToPanel
(
layoutControls
def
))
#
(
actions
,_,
panel
)
=
placePanelActions
(
uiDefActions
def
)
False
(
defToPanel
(
layoutControls
def
))
=
(
actions
,
Just
(
Left
panel
)
)
=
(
actions
,
uiDefWindows
def
,
Just
panel
)
sideMerge
::
UISide
Int
ParallelLayout
->
ParallelLayout
sideMerge
::
UISide
Int
ParallelLayout
->
ParallelLayout
sideMerge
side
size
restMerge
=
merge
sideMerge
side
size
restMerge
=
merge
...
@@ -395,7 +395,7 @@ where
...
@@ -395,7 +395,7 @@ where
#
(
tabsAndWindows
,
actions
)
=
unzip
[
mkTabOrWindow
(
i
==
active
)
d
\\
d
<-
defs
&
i
<-
[
0
..]]
#
(
tabsAndWindows
,
actions
)
=
unzip
[
mkTabOrWindow
(
i
==
active
)
d
\\
d
<-
defs
&
i
<-
[
0
..]]
=
((
setDirection
Horizontal
o
setHeight
WrapSize
o
setBaseCls
"x-tab-bar"
)
(
defaultContainer
[
tab
\\
Left
tab
<-
tabsAndWindows
])
=
((
setDirection
Horizontal
o
setHeight
WrapSize
o
setBaseCls
"x-tab-bar"
)
(
defaultContainer
[
tab
\\
Left
tab
<-
tabsAndWindows
])
,[
window
\\
Right
window
<-
tabsAndWindows
]
,[
window
\\
Right
window
<-
tabsAndWindows
]
,
f
oldr
(++)
[]
actions
,
f
latten
actions
)
)
mkTabOrWindow
active
def
mkTabOrWindow
active
def
...
@@ -412,7 +412,6 @@ where
...
@@ -412,7 +412,6 @@ where
#
tabOpts
=
{
text
=
text
,
focusTaskId
=
taskId
,
active
=
active
,
closeTaskId
=
close
,
iconCls
=
iconCls
}
#
tabOpts
=
{
text
=
text
,
focusTaskId
=
taskId
,
active
=
active
,
closeTaskId
=
close
,
iconCls
=
iconCls
}
=
(
Left
(
UITab
defaultSizeOpts
tabOpts
),
if
active
actions
[])
=
(
Left
(
UITab
defaultSizeOpts
tabOpts
),
if
active
actions
[])
hideLayout
::
Layout
hideLayout
::
Layout
hideLayout
=
hideLayout
=
{
editor
=
\
prompt
->
[]
{
editor
=
\
prompt
->
[]
...
...
Server/Framework/UIDiff.dcl
View file @
8ebd0c58
...
@@ -3,34 +3,9 @@ definition module UIDiff
...
@@ -3,34 +3,9 @@ definition module UIDiff
import
UIDefinition
import
UIDefinition
from
Task
import
::
Event
from
Task
import
::
Event
::
UIUpdate
=
UIUpdate
!
UIPath
!
UIUpdateOperation
::
UIUpdate
=
UIUpdate
!
UIPath
![
UIUpdateOperation
]
::
UIUpdateOperation
::
UIUpdateOperation
:==
(
String
,[
JSONNode
])
//Component updates
=
UISetValue
!
JSONNode
// Set the value of a component
|
UISetOptions
!
JSONNode
// Change the options in a choice component
|
UISetTaskId
!
String
// Set taskId a component belongs to
|
UISetCloseTaskId
!(
Maybe
String
)
|
UISetFocusTaskId
!(
Maybe
String
)
|
UISetEditorId
!
String
// Set editorId a component belongs to
|
UISetActionId
!
String
// Set actionId a component belongs to
|
UISetName
!
String
// Set name of a component
|
UISetEnabled
!
Bool
// Enable/disable form elements
|
UISetActive
!
Bool
// Make a tab active/inactive
|
UISetTitle
!(
Maybe
String
)
// Set/reset title of a container
|
UISetText
!(
Maybe
String
)
// Set/reset text of a button
|
UISetIconCls
!(
Maybe
String
)
// Set/reset icon of component
|
UISetTooltip
!(
Maybe
String
)
// Set/reset tooltip of a component
|
UISetHotkeys
![
UIKeyAction
]
// Set hotkeys for a container
|
UISelfUpdate
!
UIControl
// Let a component update itself with a new UI definition (for custom components)
//Structure edits
|
UIAdd
!
Int
!
UIControl
//Add child element at index
|
UIRemove
!
Int
//Remove child element at index
|
UIReplace
!
Int
!
UIControl
//Replace child element at index
|
UIAddWindow
!
Int
!
UIWindow
//Add a window
|
UIRemoveWindow
!
Int
//Remove a window
//Changing size
|
UIResize
!
UISizeOpts
::
UIPath
:==
[
UIStep
]
::
UIPath
:==
[
UIStep
]
::
UIStep
::
UIStep
=
ItemStep
!
Int
//Select item i
=
ItemStep
!
Int
//Select item i
...
...
Server/Framework/UIDiff.icl
View file @
8ebd0c58
...
@@ -21,7 +21,7 @@ diffUIDefinitions :: !UIDef !UIDef !Event -> [UIUpdate]
...
@@ -21,7 +21,7 @@ diffUIDefinitions :: !UIDef !UIDef !Event -> [UIUpdate]
diffUIDefinitions
(
UIFinal
(
UIViewport
iOpts1
opts1
))
(
UIFinal
(
UIViewport
iOpts2
opts2
))
event
diffUIDefinitions
(
UIFinal
(
UIViewport
iOpts1
opts1
))
(
UIFinal
(
UIViewport
iOpts2
opts2
))
event
=
diffItems
[]
event
iOpts1
.
UIItemsOpts
.
items
iOpts2
.
UIItemsOpts
.
items
=
diffItems
[]
event
iOpts1
.
UIItemsOpts
.
items
iOpts2
.
UIItemsOpts
.
items
++
diffAllWindows
event
opts1
.
UIViewportOpts
.
windows
opts2
.
UIViewportOpts
.
windows
++
diffAllWindows
event
opts1
.
UIViewportOpts
.
windows
opts2
.
UIViewportOpts
.
windows
++
diffHotkeys
[]
(
fromMaybe
[]
opts1
.
UIViewportOpts
.
hotkeys
)
(
fromMaybe
[]
opts2
.
UIViewportOpts
.
hotkeys
)
++
(
case
(
diffHotkeys
(
fromMaybe
[]
opts1
.
UIViewportOpts
.
hotkeys
)
(
fromMaybe
[]
opts2
.
UIViewportOpts
.
hotkeys
))
of
[]
=
[];
ops
=
[
UIUpdate
[]
ops
]
)
diffUIDefinitions
d1
d2
event
diffUIDefinitions
d1
d2
event
=
diffItems
[]
event
(
uiDefControls
d1
)
(
uiDefControls
d2
)
=
diffItems
[]
event
(
uiDefControls
d1
)
(
uiDefControls
d2
)
...
@@ -88,23 +88,22 @@ diffControls path event c1 c2
...
@@ -88,23 +88,22 @@ diffControls path event c1 c2
// check their instance id. Different: replace, Equals: update (mostly taskId)
// check their instance id. Different: replace, Equals: update (mostly taskId)
(
UITasklet
sOpts1
opts1
,
UITasklet
sOpts2
opts2
)
(
UITasklet
sOpts1
opts1
,
UITasklet
sOpts2
opts2
)
|
opts1
.
UITaskletOpts
.
iid
==
opts2
.
UITaskletOpts
.
iid
|
opts1
.
UITaskletOpts
.
iid
==
opts2
.
UITaskletOpts
.
iid
=
[
DiffPossible
[
UIUpdate
path
(
UISelfUpdate
=
[
DiffPossible
[
UIUpdate
path
[(
"selfUpdate"
,[
encodeUIControl
(
UITaskletPH
sOpts2
{
UITaskletPHOpts
|
iid
=
opts2
.
UITaskletOpts
.
iid
,
taskId
=
opts2
.
UITaskletOpts
.
taskId
}))
]]
(
UITaskletPH
sOpts2
{
UITaskletPHOpts
|
iid
=
opts2
.
UITaskletOpts
.
iid
,
taskId
=
opts2
.
UITaskletOpts
.
taskId
})])]
]]
=
[
DiffImpossible
]
=
[
DiffImpossible
]
(
UITaskletPH
sOpts1
opts1
,
UITasklet
sOpts2
opts2
)
(
UITaskletPH
sOpts1
opts1
,
UITasklet
sOpts2
opts2
)
|
opts1
.
UITaskletPHOpts
.
iid
==
opts2
.
UITaskletOpts
.
iid
|
opts1
.
UITaskletPHOpts
.
iid
==
opts2
.
UITaskletOpts
.
iid
=
[
DiffPossible
[
UIUpdate
path
(
UISelfUpdate
=
[
DiffPossible
[
UIUpdate
path
[(
"selfUpdate"
,[
encodeUIControl
(
UITaskletPH
sOpts2
{
UITaskletPHOpts
|
iid
=
opts2
.
UITaskletOpts
.
iid
,
taskId
=
opts2
.
UITaskletOpts
.
taskId
}))
]]
(
UITaskletPH
sOpts2
{
UITaskletPHOpts
|
iid
=
opts2
.
UITaskletOpts
.
iid
,
taskId
=
opts2
.
UITaskletOpts
.
taskId
})])]
]]
=
[
DiffImpossible
]
=
[
DiffImpossible
]
// Placeholder on the right hand side: update
// Placeholder on the right hand side: update
(
UITaskletPH
sOpts1
opts1
,
UITaskletPH
sOpts2
opts2
)
(
UITaskletPH
sOpts1
opts1
,
UITaskletPH
sOpts2
opts2
)
|
opts1
.
UITaskletPHOpts
.
iid
==
opts2
.
UITaskletPHOpts
.
iid
|
opts1
.
UITaskletPHOpts
.
iid
==
opts2
.
UITaskletPHOpts
.
iid
=
[
DiffPossible
[
UIUpdate
path
(
UISelfUpdate
(
UITaskletPH
sOpts2
opts2
))
]]
=
[
DiffPossible
[
UIUpdate
path
[(
"selfUpdate"
,[
encodeUIControl
(
UITaskletPH
sOpts2
opts2
)])]
]]
=
[
DiffImpossible
]
=
[
DiffImpossible
]
(
UITasklet
sOpts1
opts1
,
UITaskletPH
sOpts2
opts2
)
(
UITasklet
sOpts1
opts1
,
UITaskletPH
sOpts2
opts2
)
|
opts1
.
UITaskletOpts
.
iid
==
opts2
.
UITaskletPHOpts
.
iid
|
opts1
.
UITaskletOpts
.
iid
==
opts2
.
UITaskletPHOpts
.
iid
=
[
DiffPossible
[
UIUpdate
path
(
UISelfUpdate
(
UITaskletPH
sOpts2
opts2
))
]]
=
[
DiffPossible
[
UIUpdate
path
[(
"selfUpdate"
,[
encodeUIControl
(
UITaskletPH
sOpts2
opts2
)])]
]]
=
[
DiffImpossible
]
=
[
DiffImpossible
]
(
UIContainer
sOpts1
iOpts1
opts1
,
UIContainer
sOpts2
iOpts2
opts2
)
(
UIContainer
sOpts1
iOpts1
opts1
,
UIContainer
sOpts2
iOpts2
opts2
)
...
@@ -117,34 +116,34 @@ diffControls path event c1 c2
...
@@ -117,34 +116,34 @@ diffControls path event c1 c2
// = [diffSizeOpts path sOpts1 sOpts2,diffItemsOpts path event iOpts1 iOpts2, diffOpts opts1 opts2]
// = [diffSizeOpts path sOpts1 sOpts2,diffItemsOpts path event iOpts1 iOpts2, diffOpts opts1 opts2]
(_,_)
(_,_)
=
[
DiffImpossible
]
=
[
DiffImpossible
]
=
DiffPossible
(
replaceIfImpossible
path
c2
parts
)
=
DiffPossible
(
replace
Control
IfImpossible
path
c2
parts
)
//As a first step, only do diffs for value changes, all other diffs trigger replacements...
//As a first step, only do diffs for value changes, all other diffs trigger replacements...
diffSizeOpts
::
UIPath
UISizeOpts
UISizeOpts
->
DiffResult
diffSizeOpts
::
UIPath
UISizeOpts
UISizeOpts
->
DiffResult
diffSizeOpts
path
opts1
opts2
diffSizeOpts
path
opts1
opts2
|
opts1
===
opts2
=
DiffPossible
[]
|
opts1
===
opts2
=
DiffPossible
[]
=
DiffImpossible
// DiffPossible [UIResize (toString path) opts2]
=
DiffImpossible
diffViewOpts
::
UIPath
(
UIViewOpts
a
)
(
UIViewOpts
a
)
->
DiffResult
|
gEq
{|*|}
a
&
encodeUIValue
a
diffViewOpts
::
UIPath
(
UIViewOpts
a
)
(
UIViewOpts
a
)
->
DiffResult
|
gEq
{|*|}
a
&
encodeUIValue
a
diffViewOpts
path
opts1
opts2
diffViewOpts
path
opts1
opts2
|
opts1
===
opts2
=
DiffPossible
[]
|
opts1
===
opts2
=
DiffPossible
[]
=
DiffPossible
[
UIUpdate
path
(
UISetValue
(
encodeUIValue
opts2
.
UIViewOpts
.
value
))
]
=
DiffPossible
[
UIUpdate
path
[(
"setValue"
,[
encodeUIValue
opts2
.
UIViewOpts
.
value
])]
]
diffEditOpts
::
UIPath
Event
(
UIEditOpts
a
)
(
UIEditOpts
a
)
->
DiffResult
|
gEq
{|*|}
a
&
encodeUIValue
a
diffEditOpts
::
UIPath
Event
(
UIEditOpts
a
)
(
UIEditOpts
a
)
->
DiffResult
|
gEq
{|*|}
a
&
encodeUIValue
a
diffEditOpts
path
event
opts1
opts2
diffEditOpts
path
event
opts1
opts2
|
isEmpty
taskIdUpd
&&
isEmpty
editorIdUpd
|
isEmpty
taskIdUpd
&&
isEmpty
editorIdUpd
=
DiffPossible
(
f
oldr
(++)
[]
[
taskIdUpd
,
editorIdUpd
,
valueUpd
])
=
DiffPossible
(
f
latten
[
taskIdUpd
,
editorIdUpd
,
valueUpd
])
|
otherwise
|
otherwise
=
DiffImpossible
=
DiffImpossible
where
where
taskIdUpd
=
if
(
opts1
.
UIEditOpts
.
taskId
==
opts2
.
UIEditOpts
.
taskId
)
[]
[
UIUpdate
path
(
UISetTaskId
opts2
.
UIEditOpts
.
taskId
)
]
taskIdUpd
=
if
(
opts1
.
UIEditOpts
.
taskId
==
opts2
.
UIEditOpts
.
taskId
)
[]
[
UIUpdate
path
[(
"setTaskId"
,[
toJSON
opts2
.
UIEditOpts
.
taskId
])]
]
editorIdUpd
=
if
(
opts1
.
UIEditOpts
.
editorId
==
opts2
.
UIEditOpts
.
editorId
)
[]
[
UIUpdate
path
(
UISetEditorId
opts2
.
UIEditOpts
.
editorId
)
]
editorIdUpd
=
if
(
opts1
.
UIEditOpts
.
editorId
==
opts2
.
UIEditOpts
.
editorId
)
[]
[
UIUpdate
path
[(
"setEditorId"
,[
toJSON
opts2
.
UIEditOpts
.
editorId
])]
]
valueUpd
valueUpd
|
eventMatch
opts2
event
|
eventMatch
opts2
event
#
value2
=
encodeUIValue
opts2
.
UIEditOpts
.
value
#
value2
=
encodeUIValue
opts2
.
UIEditOpts
.
value
=
if
(
eventValue
event
===
value2
)
[]
[
UIUpdate
path
(
UISetValue
value2
)
]
=
if
(
eventValue
event
===
value2
)
[]
[
UIUpdate
path
[(
"setValue"
,[
value2
])]
]
|
otherwise
|
otherwise
=
if
(
opts1
.
UIEditOpts
.
value
===
opts2
.
UIEditOpts
.
value
)
[]
[
UIUpdate
path
(
UISetValue
(
encodeUIValue
opts2
.
UIEditOpts
.
value
))
]
=
if
(
opts1
.
UIEditOpts
.
value
===
opts2
.
UIEditOpts
.
value
)
[]
[
UIUpdate
path
[(
"setValue"
,[
encodeUIValue
opts2
.
UIEditOpts
.
value
])]
]
eventMatch
{
UIEditOpts
|
taskId
,
editorId
}
(
EditEvent
matchTask
matchEditor
_)
=
(
taskId
==
toString
matchTask
)
&&
(
editorId
==
matchEditor
)
eventMatch
{
UIEditOpts
|
taskId
,
editorId
}
(
EditEvent
matchTask
matchEditor
_)
=
(
taskId
==
toString
matchTask
)
&&
(
editorId
==
matchEditor
)
eventMatch
_
_
=
False
eventMatch
_
_
=
False
...
@@ -158,14 +157,14 @@ diffChoiceOpts path opts1 opts2
...
@@ -158,14 +157,14 @@ diffChoiceOpts path opts1 opts2
|
opts1
.
UIChoiceOpts
.
options
=!=
opts2
.
UIChoiceOpts
.
options
=
DiffImpossible
|
opts1
.
UIChoiceOpts
.
options
=!=
opts2
.
UIChoiceOpts
.
options
=
DiffImpossible
=
DiffPossible
valueDiff
//(valueDiff ++ optionDiff)
=
DiffPossible
valueDiff
//(valueDiff ++ optionDiff)
where
where
valueDiff
=
if
(
opts1
.
UIChoiceOpts
.
value
===
opts2
.
UIChoiceOpts
.
value
)
[]
[
UIUpdate
path
(
UISetValue
(
toJSON
opts2
.
UIChoiceOpts
.
value
))
]
valueDiff
=
if
(
opts1
.
UIChoiceOpts
.
value
===
opts2
.
UIChoiceOpts
.
value
)
[]
[
UIUpdate
path
[(
"setValue"
,[
toJSON
opts2
.
UIChoiceOpts
.
value
])]
]
optionDiff
=
if
(
opts1
.
UIChoiceOpts
.
options
===
opts2
.
UIChoiceOpts
.
options
)
[]
[
UIUpdate
path
(
UISetOptions
(
toJSON
opts2
.
UIChoiceOpts
.
options
))
]
optionDiff
=
if
(
opts1
.
UIChoiceOpts
.
options
===
opts2
.
UIChoiceOpts
.
options
)
[]
[
UIUpdate
path
[(
"setOptions"
,[
toJSON
opts2
.
UIChoiceOpts
.
options
])]
]
diffActionOpts
::
UIPath
UIActionOpts
UIActionOpts
->
DiffResult
diffActionOpts
::
UIPath
UIActionOpts
UIActionOpts
->
DiffResult
diffActionOpts
path
opts1
opts2
=
DiffPossible
(
flatten
[
taskIdUpd
,
actionIdUpd
])
diffActionOpts
path
opts1
opts2
=
DiffPossible
(
flatten
[
taskIdUpd
,
actionIdUpd
])
where
where
taskIdUpd
=
if
(
opts1
.
UIActionOpts
.
taskId
==
opts2
.
UIActionOpts
.
taskId
)
[]
[
UIUpdate
path
(
UISetTaskId
opts2
.
UIActionOpts
.
taskId
)
]
taskIdUpd
=
if
(
opts1
.
UIActionOpts
.
taskId
==
opts2
.
UIActionOpts
.
taskId
)
[]
[
UIUpdate
path
[(
"setTaskId"
,[
toJSON
opts2
.
UIActionOpts
.
taskId
])]
]
actionIdUpd
=
if
(
opts1
.
UIActionOpts
.
actionId
==
opts2
.
UIActionOpts
.
actionId
)
[]
[
UIUpdate
path
(
UISetActionId
opts2
.
UIActionOpts
.
actionId
)
]
actionIdUpd
=
if
(
opts1
.
UIActionOpts
.
actionId
==
opts2
.
UIActionOpts
.
actionId
)
[]
[
UIUpdate
path
[(
"setActionId"
,[
toJSON
opts2
.
UIActionOpts
.
actionId
])]
]
diffItemsOpts
::
UIPath
!
Event
UIItemsOpts
UIItemsOpts
->
DiffResult
diffItemsOpts
::
UIPath
!
Event
UIItemsOpts
UIItemsOpts
->
DiffResult
diffItemsOpts
path
event
opts1
opts2
diffItemsOpts
path
event
opts1
opts2
...
@@ -185,13 +184,21 @@ diffOpts opts1 opts2
...
@@ -185,13 +184,21 @@ diffOpts opts1 opts2
selfUpdate
::
UIPath
UIControl
UIControl
->
DiffResult
selfUpdate
::
UIPath
UIControl
UIControl
->
DiffResult
selfUpdate
path
c1
c2
selfUpdate
path
c1
c2
|
c1
===
c2
=
DiffPossible
[]
|
c1
===
c2
=
DiffPossible
[]
=
DiffPossible
[
UIUpdate
path
(
UISelfUpdate
c2
)]
=
DiffPossible
[
UIUpdate
path
[(
"selfUpdate"
,[
encodeUIControl
c2
])]]
//Group multiple operations in a single component update
diffMultiProperties
::
UIPath
[[
UIUpdateOperation
]]
->
DiffResult
diffMultiProperties
path
ops
=
case
flatten
ops
of
[]
=
DiffPossible
[]
ops
=
DiffPossible
[
UIUpdate
path
ops
]
//Specialized diffs for the control specific options
//Specialized diffs for the control specific options
diffPanelOpts
::
UIPath
Event
UIPanelOpts
UIPanelOpts
->
DiffResult
diffPanelOpts
::
UIPath
Event
UIPanelOpts
UIPanelOpts
->
DiffResult
diffPanelOpts
path
event
opts1
opts2
diffPanelOpts
path
event
opts1
opts2
|
impossible
=
DiffImpossible
|
impossible
=
DiffImpossible
=
DiffPossible
(
flatten
[
titleUpd
,
menusUpd
,
hotkeyUpd
])
=
case
flatten
[
titleUpd
,
hotkeyUpd
]
of
[]
=
DiffPossible
menusUpd
ops
=
DiffPossible
[
UIUpdate
path
ops
:
menusUpd
]
where
where
impossible
=
opts1
.
UIPanelOpts
.
frame
<>
opts2
.
UIPanelOpts
.
frame
impossible
=
opts1
.
UIPanelOpts
.
frame
<>
opts2
.
UIPanelOpts
.
frame
||
opts1
.
UIPanelOpts
.
iconCls
<>
opts2
.
UIPanelOpts
.
iconCls
||
opts1
.
UIPanelOpts
.
iconCls
<>
opts2
.
UIPanelOpts
.
iconCls
...
@@ -200,31 +207,49 @@ where
...
@@ -200,31 +207,49 @@ where
||
(
isJust
opts1
.
UIPanelOpts
.
tbar
&&
isNothing
opts2
.
UIPanelOpts
.
tbar
)
//Can only update menu items, not create a menubar suddenly
||
(
isJust
opts1
.
UIPanelOpts
.
tbar
&&
isNothing
opts2
.
UIPanelOpts
.
tbar
)
//Can only update menu items, not create a menubar suddenly
||
(
isNothing
opts1
.
UIPanelOpts
.
tbar
&&
isJust
opts2
.
UIPanelOpts
.
tbar
)
||
(
isNothing
opts1
.
UIPanelOpts
.
tbar
&&
isJust
opts2
.
UIPanelOpts
.
tbar
)
titleUpd
=
if
(
opts1
.
UIPanelOpts
.
title
==
opts2
.
UIPanelOpts
.
title
)
[]
[
UIUpdate
path
(
UISetTitle
opts2
.
UIPanelOpts
.
title
)]
titleUpd
=
if
(
opts1
.
UIPanelOpts
.
title
==
opts2
.
UIPanelOpts
.
title
)
[]
[(
"setTitle"
,[
toJSON
opts2
.
UIPanelOpts
.
title
])]
hotkeyUpd
=
diffHotkeys
(
fromMaybe
[]
opts1
.
UIPanelOpts
.
hotkeys
)
(
fromMaybe
[]
opts2
.
UIPanelOpts
.
hotkeys
)
menusUpd
=
diffItems
[
MenuStep
:
path
]
event
(
fromMaybe
[]
opts1
.
UIPanelOpts
.
tbar
)
(
fromMaybe
[]
opts2
.
UIPanelOpts
.
tbar
)
menusUpd
=
diffItems
[
MenuStep
:
path
]
event
(
fromMaybe
[]
opts1
.
UIPanelOpts
.
tbar
)
(
fromMaybe
[]
opts2
.
UIPanelOpts
.
tbar
)
hotkeyUpd
=
diffHotkeys
path
(
fromMaybe
[]
opts1
.
UIPanelOpts
.
hotkeys
)
(
fromMaybe
[]
opts2
.
UIPanelOpts
.
hotkeys
)
diffWindowOpts
::
UIPath
Event
UIWindowOpts
UIWindowOpts
->
DiffResult
diffWindowOpts
path
event
opts1
opts2
|
impossible
=
DiffImpossible
=
case
flatten
[
titleUpd
,
hotkeyUpd
]
of
[]
=
DiffPossible
menusUpd
ops
=
DiffPossible
[
UIUpdate
path
ops
:
menusUpd
]
where
impossible
=
opts1
.
UIWindowOpts
.
focusTaskId
=!=
opts2
.
UIWindowOpts
.
focusTaskId
//TODO Make more possible on client
||
opts1
.
UIWindowOpts
.
closeTaskId
=!=
opts2
.
UIWindowOpts
.
closeTaskId
||
opts1
.
UIWindowOpts
.
iconCls
=!=
opts2
.
UIWindowOpts
.
iconCls
||
opts1
.
UIWindowOpts
.
baseCls
=!=
opts2
.
UIWindowOpts
.
baseCls
||
opts1
.
UIWindowOpts
.
bodyCls
=!=
opts2
.
UIWindowOpts
.
bodyCls
titleUpd
=
if
(
opts1
.
UIWindowOpts
.
title
==
opts2
.
UIWindowOpts
.
title
)
[]
[(
"setTitle"
,[
toJSON
opts2
.
UIWindowOpts
.
title
])]
hotkeyUpd
=
diffHotkeys
(
fromMaybe
[]
opts1
.
UIWindowOpts
.
hotkeys
)
(
fromMaybe
[]
opts2
.
UIWindowOpts
.
hotkeys
)
menusUpd
=
diffItems
[
MenuStep
:
path
]
event
(
fromMaybe
[]
opts1
.
UIWindowOpts
.
tbar
)
(
fromMaybe
[]
opts2
.
UIWindowOpts
.
tbar
)
diffButtonOpts
::
UIPath
UIButtonOpts
UIButtonOpts
->
DiffResult
diffButtonOpts
::
UIPath
UIButtonOpts
UIButtonOpts
->
DiffResult
diffButtonOpts
path
b1
b2
=
DiffPossible
(
flatten
[
textUpd
,
iconUpd
,
enabledUpd
])
diffButtonOpts
path
b1
b2
=
diffMultiProperties
path
[
textUpd
,
iconUpd
,
enabledUpd
]
where
where
textUpd
=
if
(
b1
.
UIButtonOpts
.
text
===
b2
.
UIButtonOpts
.
text
)
[]
[
UIUpdate
path
(
UISetText
b2
.
UIButtonOpts
.
text
)]
textUpd
=
if
(
b1
.
UIButtonOpts
.
text
===
b2
.
UIButtonOpts
.
text
)
[]
[
(
"setText"
,[
toJSON
b2
.
UIButtonOpts
.
text
]
)]
iconUpd
=
if
(
b1
.
UIButtonOpts
.
iconCls
===
b2
.
UIButtonOpts
.
iconCls
)
[]
[
UIUpdate
path
(
UISetIconCls
b2
.
UIButtonOpts
.
iconCls
)]
iconUpd
=
if
(
b1
.
UIButtonOpts
.
iconCls
===
b2
.
UIButtonOpts
.
iconCls
)
[]
[
(
"setIconCls"
,[
toJSON
b2
.
UIButtonOpts
.
iconCls
]
)]
enabledUpd
=
if
(
b1
.
UIButtonOpts
.
disabled
===
b2
.
UIButtonOpts
.
disabled
)
[]
[
UIUpdate
path
(
UISetEnabled
(
not
b2
.
UIButtonOpts
.
disabled
)
)]
enabledUpd
=
if
(
b1
.
UIButtonOpts
.
disabled
===
b2
.
UIButtonOpts
.
disabled
)
[]
[
(
"setDisabled"
,[
toJSON
b2
.
UIButtonOpts
.
disabled
]
)]
diffIconOpts
::
UIPath
UIIconOpts
UIIconOpts
->
DiffResult
diffIconOpts
::
UIPath
UIIconOpts
UIIconOpts
->
DiffResult
diffIconOpts
path
i1
i2
=
DiffPossible
(
flatten
[
iconUpd
,
tooltipUpd
])
diffIconOpts
path
i1
i2
=
diffMultiProperties
path
[
iconUpd
,
tooltipUpd
]
where
where
iconUpd
=
if
(
i1
.
UIIconOpts
.
iconCls
===
i2
.
UIIconOpts
.
iconCls
)
[]
[
UIUpdate
path
(
UISetIconCls
(
Just
i2
.
UIIconOpts
.
iconCls
)
)]
iconUpd
=
if
(
i1
.
UIIconOpts
.
iconCls
===
i2
.
UIIconOpts
.
iconCls
)
[]
[
(
"setIconCls"
,[
toJSON
i2
.
UIIconOpts
.
iconCls
]
)]
tooltipUpd
=
if
(
i1
.
UIIconOpts
.
tooltip
===
i2
.
UIIconOpts
.
tooltip
)
[]
[
UIUpdate
path
(
UISetTooltip
i2
.
UIIconOpts
.
tooltip
)]
tooltipUpd
=
if
(
i1
.
UIIconOpts
.
tooltip
===
i2
.
UIIconOpts
.
tooltip
)
[]
[
(
"setTooltip"
,[
toJSON
i2
.
UIIconOpts
.
tooltip
]
)]
diffTabOpts
::
UIPath
UITabOpts
UITabOpts
->
DiffResult
diffTabOpts
::
UIPath
UITabOpts
UITabOpts
->
DiffResult
diffTabOpts
path
t1
t2
=
DiffPossible
(
flatten
[
textUpd
,
activeUpd
,
focusUpd
,
closeUpd
,
iconUpd
])
diffTabOpts
path
t1
t2
=
diffMultiProperties
path
[
textUpd
,
activeUpd
,
focusUpd
,
closeUpd
,
iconUpd
]
where
where
textUpd
=
if
(
t1
.
UITabOpts
.
text
===
t2
.
UITabOpts
.
text
)
[]
[
UIUpdate
path
(
UISetText
(
Just
t2
.
UITabOpts
.
text
))]
textUpd
=
if
(
t1
.
UITabOpts
.
text
===
t2
.
UITabOpts
.
text
)
[]
[(
"setText"
,[
toJSON
t2
.
UITabOpts
.
text
])]
activeUpd
=
if
(
t1
.
UITabOpts
.
active
==
t2
.
UITabOpts
.
active
)
[]
[
UIUpdate
path
(
UISetActive
t2
.
UITabOpts
.
active
)]
activeUpd
=
if
(
t1
.
UITabOpts
.
active
==
t2
.
UITabOpts
.
active
)
[]
[(
"setActive"
,[
toJSON
t2
.
UITabOpts
.
active
])]
focusUpd
=
if
(
t1
.
UITabOpts
.
focusTaskId
===
t2
.
UITabOpts
.
focusTaskId
)
[]
[
UIUpdate
path
(
UISetFocusTaskId
t2
.
UITabOpts
.
focusTaskId
)]
focusUpd
=
if
(
t1
.
UITabOpts
.
focusTaskId
===
t2
.
UITabOpts
.
focusTaskId
)
[]
[(
"setFocusTaskId"
,[
toJSON
t2
.
UITabOpts
.
focusTaskId
])]
closeUpd
=
if
(
t1
.
UITabOpts
.
closeTaskId
===
t2
.
UITabOpts
.
closeTaskId
)
[]
[
UIUpdate
path
(
UISetCloseTaskId
t2
.
UITabOpts
.
closeTaskId
)]
closeUpd
=
if
(
t1
.
UITabOpts
.
closeTaskId
===
t2
.
UITabOpts
.
closeTaskId
)
[]
[(
"setCloseTaskId"
,[
toJSON
t2
.
UITabOpts
.
closeTaskId
])]
iconUpd
=
if
(
t1
.
UITabOpts
.
iconCls
===
t2
.
UITabOpts
.
iconCls
)
[]
[
UIUpdate
path
(
UISetIconCls
t2
.
UITabOpts
.
iconCls
)]
iconUpd
=
if
(
t1
.
UITabOpts
.
iconCls
===
t2
.
UITabOpts
.
iconCls
)
[]
[(
"setIconCls"
,[
toJSON
t2
.
UITabOpts
.
iconCls
])]
diffItems
::
UIPath
Event
[
UIControl
]
[
UIControl
]
->
[
UIUpdate
]
diffItems
::
UIPath
Event
[
UIControl
]
[
UIControl
]
->
[
UIUpdate
]
diffItems
path
event
items1
items2
=
diff
path
event
0
items1
items2
diffItems
path
event
items1
items2
=
diff
path
event
0
items1
items2
...
@@ -232,11 +257,11 @@ where
...
@@ -232,11 +257,11 @@ where
diff
path
event
i
[]
[]
diff
path
event
i
[]
[]
=
[]
=
[]
diff
path
event
i
items1
[]
//Less items in new than old (remove starting with the last item)
diff
path
event
i
items1
[]
//Less items in new than old (remove starting with the last item)
=
[
UIUpdate
path
(
UIRemove
n
)
\\
n
<-
reverse
[
i
..
i
+
length
items1
-
1
]]
=
[
UIUpdate
path
[(
"remove"
,[
toJSON
n
])]
\\
n
<-
reverse
[
i
..
i
+
length
items1
-
1
]]
diff
path
event
i
[]
items2
//More items in new than old
diff
path
event
i
[]
items2
//More items in new than old
=
[
UIUpdate
path
(
UIAdd
n
def
)
\\
n
<-
[
i
..]
&
def
<-
items2
]
=
[
UIUpdate
path
[(
"add"
,[
toJSON
n
,
encodeUIControl
def
])]
\\
n
<-
[
i
..]
&
def
<-
items2
]
diff
path
event
i
[
c1
:
c1s
]
[
c2
:
c2s
]
//Compare side by side
diff
path
event
i
[
c1
:
c1s
]
[
c2
:
c2s
]
//Compare side by side
=
replaceIfImpossible
[
ItemStep
i
:
path
]
c2
[
diffControls
[
ItemStep
i
:
path
]
event
c1
c2
]
=
replace
Control
IfImpossible
[
ItemStep
i
:
path
]
c2
[
diffControls
[
ItemStep
i
:
path
]
event
c1
c2
]
++
diff
path
event
(
i
+
1
)
c1s
c2s
++
diff
path
event
(
i
+
1
)
c1s
c2s
diffAllWindows
::
Event
[
UIWindow
]
[
UIWindow
]
->
[
UIUpdate
]
diffAllWindows
::
Event
[
UIWindow
]
[
UIWindow
]
->
[
UIUpdate
]
...
@@ -245,38 +270,52 @@ where
...
@@ -245,38 +270,52 @@ where
diff
event
i
[]
[]
diff
event
i
[]
[]
=
[]
=
[]
diff
event
i
windows1
[]
//Less windows
diff
event
i
windows1
[]
//Less windows
=
[
UIUpdate
[]
(
UIRemoveWindow
n
)
\\
n
<-
reverse
[
i
..
i
+
length
windows1
-
1
]]
=
[
UIUpdate
[]
[(
"removeWindow"
,[
toJSON
n
])]
\\
n
<-
reverse
[
i
..
i
+
length
windows1
-
1
]]
diff
event
i
[]
items2
//More windows
diff
event
i
[]
items2
//More windows
=
[
UIUpdate
[]
(
UIAddWindow
n
def
)
\\
n
<-
[
i
..]
&
def
<-
windows2
]
=
[
UIUpdate
[]
[(
"addWindow"
,[
toJSON
n
,
encodeUIWindow
def
])]
\\
n
<-
[
i
..]
&
def
<-
windows2
]
diff
event
i
[
w1
:
w1s
]
[
w2
:
w2s
]
//Compare side by side (TODO: Make more granular)
diff
event
i
[
w1
:
w1s
]
[
w2
:
w2s
]
//Compare side by side (TODO: Make more granular)
=
if
(
w1
===
w2
)
[]
[
UIUpdate
[]
(
UIRemoveWindow
i
),
UIUpdate
[]
(
UIAddWindow
i
w2
)]
=
diffWindows
[
WindowStep
i
]
event
w1
w2
++
diff
event
(
i
+
1
)
w1s
w2s
++
diff
event
(
i
+
1
)
w1s
w2s
++
diff
event
(
i
+
1
)
w1s
w2s
diffWindows
::
UIPath
Event
UIWindow
UIWindow
->
DiffResult
diffWindows
::
UIPath
Event
UIWindow
UIWindow
->
[
UIUpdate
]
diffWindows
path
event
w1
w2
=
DiffImpossible
diffWindows
path
event
w1
=:(
UIWindow
sOpts1
iOpts1
opts1
)
w2
=:(
UIWindow
sOpts2
iOpts2
opts2
)
=
replaceWindowIfImpossible
path
w2
[
diffSizeOpts
path
sOpts1
sOpts2
,
diffItemsOpts
path
event
iOpts1
iOpts2
,
diffWindowOpts
path
event
opts1
opts2
]
diffHotkeys
::
UIPath
[
UIKeyAction
]
[
UIKeyAction
]
->
[
UIUpdate
]
diffHotkeys
::
[
UIKeyAction
]
[
UIKeyAction
]
->
[
UIUpdateOperation
]
diffHotkeys
path
keys1
keys2
=
if
(
keys1
===
keys2
)
[]
[
UIUpdate
path
(
UISetHotkeys
keys2
)]
diffHotkeys
keys1
keys2
=
if
(
keys1
===
keys2
)
[]
[(
"setHotkeys"
,[
toJSON
keys2
]
)]
//Try to diff a control in parts. If one of the parts is impossible, then return a full replace instruction
//Try to diff a control in parts. If one of the parts is impossible, then return a full replace instruction
replaceIfImpossible
::
UIPath
UIControl
[
DiffResult
]
->
[
UIUpdate
]
replaceControlIfImpossible
::
UIPath
UIControl
[
DiffResult
]
->
[
UIUpdate
]
replaceIfImpossible
path
fallback
parts
replaceControlIfImpossible
path
fallback
parts
|
allPossible
parts
=
foldr
(++)
[]
[
d
\\
DiffPossible
d
<-
parts
]
|
allDiffsPossible
parts
=
flatten
[
d
\\
DiffPossible
d
<-
parts
]
=
[
UIUpdate
parentPath
(
UIReplace
parentIndex
fallback
)]
=
[
UIUpdate
parentPath
[(
"remove"
,[
toJSON
parentIndex
])
,(
"add"
,[
toJSON
parentIndex
,
encodeUIControl
fallback
])]]
where
where
[
ItemStep
parentIndex
:
parentPath
]
=
path
[
ItemStep
parentIndex
:
parentPath
]
=
path
allPossible
[]
=
True
replaceWindowIfImpossible
::