fit-ui 2.4.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Fit.UI.css CHANGED
@@ -3851,6 +3851,13 @@ div.FitUiControlDropDown[data-selectionmodetoggle="true"]
3851
3851
  {
3852
3852
  margin-right: 2em;
3853
3853
  }
3854
+
3855
+ /* WSDropDown: Action Menu (ListView) */
3856
+
3857
+ div.FitUiControlDropDown span.FitUiControlDropDownActionMenuItemDelete
3858
+ {
3859
+ color: #DB1E1E;
3860
+ }
3854
3861
  /* Modern control (default) */
3855
3862
 
3856
3863
  div.FitUiControlFilePicker[data-legacy="false"] input
@@ -4106,7 +4113,7 @@ div.FitUiControlListView > div /* List item */
4106
4113
  white-space: nowrap;
4107
4114
  }
4108
4115
 
4109
- div.FitUiControlListView > div:hover
4116
+ div.FitUiControlListView[data-device="Desktop"] > div:hover
4110
4117
  {
4111
4118
  background-color: #DADADA; /*#C3D9E0*/
4112
4119
  cursor: pointer;
package/dist/Fit.UI.js CHANGED
@@ -648,7 +648,7 @@ Fit._internal =
648
648
  {
649
649
  Core:
650
650
  {
651
- VersionInfo: { Major: 2, Minor: 4, Patch: 1 } // Do NOT modify format - version numbers are programmatically changed when releasing new versions - MUST be on a separate line!
651
+ VersionInfo: { Major: 2, Minor: 5, Patch: 0 } // Do NOT modify format - version numbers are programmatically changed when releasing new versions - MUST be on a separate line!
652
652
  }
653
653
  };
654
654
 
@@ -3048,6 +3048,8 @@ Fit.Controls.Component = function(controlId)
3048
3048
  container = document.createElement("div");
3049
3049
  container.id = id;
3050
3050
  container._internal = { Instance: me };
3051
+
3052
+ Fit.Dom.Data(container, "device", ((Fit.Browser.GetInfo().IsMobile === false) ? "Desktop" : (Fit.Browser.GetInfo().IsPhone === true) ? "Phone" : "Tablet"));
3051
3053
  }
3052
3054
 
3053
3055
  /// <function container="Fit.Controls.Component" name="GetId" access="public" returns="string">
@@ -3278,8 +3280,6 @@ Fit.Controls.ControlBase = function(controlId)
3278
3280
  me._internal.Data("dirty", "false");
3279
3281
  me._internal.Data("enabled", "true");
3280
3282
 
3281
- me._internal.Data("device", ((Fit.Browser.GetInfo().IsMobile === false) ? "Desktop" : (Fit.Browser.GetInfo().IsPhone === true) ? "Phone" : "Tablet"));
3282
-
3283
3283
  // Add hidden inputs which are automatically populated with
3284
3284
  // control value and state information when control is updated.
3285
3285
 
@@ -15924,8 +15924,15 @@ Fit.Controls.DropDown = function(ctlId)
15924
15924
  {
15925
15925
  var target = Fit.Events.GetTarget(e);
15926
15926
 
15927
+ if (target !== document.documentElement && target !== document.body && Fit.Dom.IsRooted(target) === false)
15928
+ {
15929
+ return; // Do not close DropDown if target no longer exists - this may happen if something is removed within DropDown (e.g. an item in the WSDropDown's action menu)
15930
+ }
15931
+
15927
15932
  if (me.IsDropDownOpen() === true && target !== me.GetDomElement() && Fit.Dom.Contained(me.GetDomElement(), target) === false)
15933
+ {
15928
15934
  me.CloseDropDown();
15935
+ }
15929
15936
  });
15930
15937
  Fit.Array.Add(closeHandlers, eventId);
15931
15938
  }
@@ -15942,6 +15949,11 @@ Fit.Controls.DropDown = function(ctlId)
15942
15949
 
15943
15950
  coords = null;
15944
15951
 
15952
+ if (target !== document.documentElement && target !== document.body && Fit.Dom.IsRooted(target) === false)
15953
+ {
15954
+ return; // Do not close DropDown if target no longer exists - this may happen if something is removed within DropDown (e.g. an item in the WSDropDown's action menu)
15955
+ }
15956
+
15945
15957
  if (me.IsDropDownOpen() === true && target !== me.GetDomElement() && Fit.Dom.Contained(me.GetDomElement(), target) === false)
15946
15958
  {
15947
15959
  coords = Fit.Events.GetPointerState().Coordinates.Document;
@@ -16532,6 +16544,19 @@ Fit.Controls.DropDown = function(ctlId)
16532
16544
  if (txt.parentElement.parentElement === null)
16533
16545
  txt = txtPrimary;
16534
16546
  }
16547
+ else
16548
+ {
16549
+ // User selected an item which is already selected
16550
+
16551
+ if (me.TextSelectionMode() === true)
16552
+ {
16553
+ updateTextSelection(); // Make sure any search value is removed and text selection is restored
16554
+ }
16555
+ else
16556
+ {
16557
+ me.ClearInput(); // Make sure any search value is removed
16558
+ }
16559
+ }
16535
16560
 
16536
16561
  // DISABLED: Now handled using picker.OnFocus(..) handler further down - see https://github.com/Jemt/Fit.UI/issues/86 for details
16537
16562
  // if (eventArgs.ProgrammaticallyChanged === false && (isMobile === false || focusInputOnMobile === true))
@@ -17403,6 +17428,34 @@ Fit.Controls.DropDown = function(ctlId)
17403
17428
  Fit.Array.Add(onCloseHandlers, cb);
17404
17429
  }
17405
17430
 
17431
+ // ============================================
17432
+ // Protected
17433
+ // ============================================
17434
+
17435
+ this._internal = (this._internal ? this._internal : {});
17436
+
17437
+ // Clear input field without firing OnInputChanged, and make placeholder appear
17438
+ this._internal.ClearInputAndShowPlaceholder = function(forceFocusInput)
17439
+ {
17440
+ Fit.Validation.ExpectBoolean(forceFocusInput, true);
17441
+
17442
+ txtPrimary.value = "";
17443
+ updatePlaceholder(true);
17444
+
17445
+ if (forceFocusInput)
17446
+ {
17447
+ // By default focus is never assigned to input on mobile if user opened the
17448
+ // DropDown by clicking the arrow icon. ForceFocusInput allows us to ignore this
17449
+ // aspect. On desktop the input field always remains focused as it automatically
17450
+ // steals back focus immediately after interacting with a picker control. See
17451
+ // picker.OnFocusIn handler registered in SetPicker(..)
17452
+ var orgFocusInputOnMobile = focusInputOnMobile;
17453
+ focusInputOnMobile = true;
17454
+ focusInput(txtActive);
17455
+ focusInputOnMobile = orgFocusInputOnMobile;
17456
+ }
17457
+ }
17458
+
17406
17459
  // ============================================
17407
17460
  // Private
17408
17461
  // ============================================
@@ -18182,7 +18235,7 @@ Fit.Controls.DropDown = function(ctlId)
18182
18235
 
18183
18236
  if (placeholder !== "" || force === true)
18184
18237
  {
18185
- var setPlaceholder = placeholder !== "" && itemCollectionOrdered.length === 0 && me.GetInputValue() === "" && willAssumeInputValue !== true;
18238
+ var setPlaceholder = placeholder !== "" && (me.TextSelectionMode() === true || itemCollectionOrdered.length === 0) && me.GetInputValue() === "" && willAssumeInputValue !== true;
18186
18239
 
18187
18240
  Fit.Dom.Data(itemContainer, "placeholder", setPlaceholder === true ? placeholder : null);
18188
18241
  Fit.Dom.Data(itemContainer, "placeholder-autoclear", setPlaceholder === true ? Fit.Browser.GetBrowser() === "MSIE" ? "true" : "false" : null);
@@ -18396,6 +18449,12 @@ Fit.Controls.DropDown = function(ctlId)
18396
18449
  Fit.Dom.SetCaretPosition(txtPrimary, 0);
18397
18450
  }
18398
18451
 
18452
+ // Remove placeholder in case it was added using this._internal.ClearInputAndShowPlaceholder()
18453
+
18454
+ updatePlaceholder(true);
18455
+
18456
+ // Have TextSelection removed when input is changed
18457
+
18399
18458
  clearTextSelectionOnInputChange = true;
18400
18459
  }
18401
18460
 
@@ -19027,6 +19086,7 @@ Fit.Controls.WSDropDown = function(ctlId)
19027
19086
  var me = this;
19028
19087
  var list = null;
19029
19088
  var tree = null;
19089
+ var actionMenu = null;
19030
19090
 
19031
19091
  var search = "";
19032
19092
  var forceNewSearch = false;
@@ -19040,6 +19100,9 @@ Fit.Controls.WSDropDown = function(ctlId)
19040
19100
  var currentRequest = null;
19041
19101
  var classes = null;
19042
19102
  var autoUpdatedSelections = null; // Cached result from AutoUpdateSelected: [{ Title:string, Value:string, Exists:boolean }, ...]
19103
+ var useActionMenu = false;
19104
+ var useActionMenuForced = false;
19105
+ var translations = null;
19043
19106
 
19044
19107
  var onRequestHandlers = [];
19045
19108
  var onResponseHandlers = [];
@@ -19155,6 +19218,22 @@ Fit.Controls.WSDropDown = function(ctlId)
19155
19218
  {
19156
19219
  fireOnDataLoaded();
19157
19220
  }
19221
+
19222
+ // If no data is returned and DropDown is in TextSelectionMode, the user will
19223
+ // not have an easy way to remove objects from the DropDown, unless SelectionModeToggle
19224
+ // is true. Therefore we allow for items to be removed using an action menu.
19225
+ // EDIT: Now displays action menu in both Visual and Text Selection Mode for consistency.
19226
+
19227
+ if (useActionMenuForced === false)
19228
+ {
19229
+ useActionMenu = eventArgs.Children.length === 0;
19230
+ }
19231
+
19232
+ if (/*me.TextSelectionMode() === true &&*/ useActionMenu === true)
19233
+ {
19234
+ updateActionMenu();
19235
+ me.SetPicker(actionMenu);
19236
+ }
19158
19237
  }
19159
19238
  });
19160
19239
  tree.OnAbort(function(sender, eventArgs)
@@ -19245,6 +19324,104 @@ Fit.Controls.WSDropDown = function(ctlId)
19245
19324
  me.SetPicker(tree);
19246
19325
  });
19247
19326
 
19327
+ // Create action menu
19328
+
19329
+ var skipUpdateActionMenuOnChange = false;
19330
+
19331
+ actionMenu = new Fit.Controls.ListView(ctlId + "__ActionsListView");
19332
+ actionMenu.OnSelect(function(sender, item) // Using OnSelect instead of OnItemSelectionChanging since DropDown fires OnItemSelectionChanging when selection is changed, which would result in OnItemSelectionChanging being executed multiple times
19333
+ {
19334
+ if (item.Value === "SearchMore")
19335
+ {
19336
+ me._internal.ClearInputAndShowPlaceholder(true); // NOTICE: TextSelectionMode only - Visual Selection Mode cannot be temporarily cleared to display the place holder
19337
+ }
19338
+ else if (item.Value === "ShowAll")
19339
+ {
19340
+ me.SetPicker(tree);
19341
+ }
19342
+ else if (item.Value === "RemoveAll")
19343
+ {
19344
+ skipUpdateActionMenuOnChange = true;
19345
+ me.ClearSelections(); // Fires OnChange
19346
+ skipUpdateActionMenuOnChange = false;
19347
+
19348
+ updateActionMenu(); // Update action menu (remove all "Remove: xyz" options)
19349
+ }
19350
+ else if (item.Value.indexOf("Remove:") === 0)
19351
+ {
19352
+ var dataValue = item.Value.replace("Remove:", "");
19353
+
19354
+ // Find item below if using keyboard to remove item
19355
+
19356
+ var above = null;
19357
+ var below = null;
19358
+
19359
+ if (Fit.Browser.GetInfo().IsMobile === false && Fit.Events.GetPointerState().Buttons.Primary === false) // Do not find and highlight item below on touch devices, or if using the mouse
19360
+ {
19361
+ var items = actionMenu.GetItems();
19362
+ var stopNext = false;
19363
+
19364
+ for (var i = 0 ; i < items.length ; i++)
19365
+ {
19366
+ if (items[i].Value.indexOf("Remove:") !== 0)
19367
+ {
19368
+ continue; // Skip items that do not remove individual selections
19369
+ }
19370
+
19371
+ if (items[i].Value.replace("Remove:", "") === dataValue)
19372
+ {
19373
+ stopNext = true;
19374
+ continue;
19375
+ }
19376
+
19377
+ if (stopNext === false)
19378
+ {
19379
+ above = items[i].Value;
19380
+ }
19381
+ else
19382
+ {
19383
+ below = items[i].Value;
19384
+ break;
19385
+ }
19386
+ }
19387
+ }
19388
+
19389
+ // Remove item
19390
+
19391
+ skipUpdateActionMenuOnChange = true;
19392
+ me.RemoveSelection(dataValue); // Fires OnChange
19393
+ skipUpdateActionMenuOnChange = false;
19394
+
19395
+ // Update list of removable items
19396
+
19397
+ actionMenu.RemoveItem(item.Value);
19398
+
19399
+ if (me.GetSelections().length === 1)
19400
+ {
19401
+ updateActionMenu(); // Update action menu to get rid of "Remove all" item when only one item is left
19402
+ }
19403
+
19404
+ // Highlight item below (or above) the item that was just removed
19405
+
19406
+ if (above !== null || below !== null)
19407
+ {
19408
+ actionMenu.RevealItemInView(below !== null ? below : above);
19409
+ }
19410
+ }
19411
+
19412
+ return false; // Prevent selection of behavioural item
19413
+ });
19414
+
19415
+ me.OnChange(function(sender)
19416
+ {
19417
+ if (skipUpdateActionMenuOnChange === false)
19418
+ {
19419
+ updateActionMenu();
19420
+ }
19421
+ });
19422
+
19423
+ // Misc
19424
+
19248
19425
  me.OnOpen(function()
19249
19426
  {
19250
19427
  if (suppressTreeOnOpen === true)
@@ -19253,9 +19430,19 @@ Fit.Controls.WSDropDown = function(ctlId)
19253
19430
  return;
19254
19431
  }
19255
19432
 
19256
- me.SetPicker(tree);
19257
- ensureTreeViewData();
19433
+ if (useActionMenu === true)
19434
+ {
19435
+ me.SetPicker(actionMenu);
19436
+ }
19437
+ else
19438
+ {
19439
+ me.SetPicker(tree);
19440
+ ensureTreeViewData();
19441
+ }
19258
19442
  });
19443
+
19444
+ Fit.Internationalization.OnLocaleChanged(localize);
19445
+ localize();
19259
19446
  }
19260
19447
 
19261
19448
  // ============================================
@@ -19480,7 +19667,6 @@ Fit.Controls.WSDropDown = function(ctlId)
19480
19667
  return base(val);
19481
19668
  });
19482
19669
 
19483
-
19484
19670
  /// <function container="Fit.Controls.WSDropDown" name="GetListView" access="public" returns="Fit.Controls.WSListView">
19485
19671
  /// <description> Get WSListView control used to display data in a flat list view </description>
19486
19672
  /// </function>
@@ -19497,6 +19683,44 @@ Fit.Controls.WSDropDown = function(ctlId)
19497
19683
  return tree;
19498
19684
  }
19499
19685
 
19686
+ /// <function container="Fit.Controls.WSDropDown" name="UseActionMenu" access="public">
19687
+ /// <description> Get/set value indicating whether control uses the built-in action menu to ease addition and removal of items </description>
19688
+ /// <param name="val" type="boolean" default="undefined"> If defined, True enables the action menu, False disables it </param>
19689
+ /// </function>
19690
+ this.UseActionMenu = function(val)
19691
+ {
19692
+ Fit.Validation.ExpectBoolean(val, true);
19693
+
19694
+ if (Fit.Validation.IsSet(val) === true)
19695
+ {
19696
+ useActionMenuForced = true;
19697
+
19698
+ if (val !== useActionMenu)
19699
+ {
19700
+ useActionMenu = val;
19701
+
19702
+ if (val === true)
19703
+ {
19704
+ updateActionMenu();
19705
+
19706
+ if (me.IsDropDownOpen() === true)
19707
+ {
19708
+ me.SetPicker(actionMenu);
19709
+ }
19710
+ }
19711
+ else
19712
+ {
19713
+ if (me.GetPicker() === actionMenu)
19714
+ {
19715
+ me.SetPicker(tree.GetChildren().length > 0 ? tree : list);
19716
+ }
19717
+ }
19718
+ }
19719
+ }
19720
+
19721
+ return useActionMenu;
19722
+ }
19723
+
19500
19724
  // See documentation on ControlBase
19501
19725
  this.Dispose = Fit.Core.CreateOverride(this.Dispose, function()
19502
19726
  {
@@ -19504,10 +19728,13 @@ Fit.Controls.WSDropDown = function(ctlId)
19504
19728
 
19505
19729
  list.Destroy();
19506
19730
  tree.Destroy();
19731
+ actionMenu.Destroy();
19507
19732
 
19508
19733
  cancelSearch();
19509
19734
 
19510
- me = list = tree = search = forceNewSearch = hideLinesForFlatData = dataRequested = dataLoading = requestCount = onDataLoadedCallback = suppressTreeOnOpen = timeOut = currentRequest = classes = autoUpdatedSelections = onRequestHandlers = onResponseHandlers = null;
19735
+ Fit.Internationalization.RemoveOnLocaleChanged(localize);
19736
+
19737
+ me = list = tree = actionMenu = search = forceNewSearch = hideLinesForFlatData = dataRequested = dataLoading = requestCount = onDataLoadedCallback = suppressTreeOnOpen = timeOut = currentRequest = classes = autoUpdatedSelections = useActionMenu = useActionMenuForced = translations = onRequestHandlers = onResponseHandlers = null;
19511
19738
 
19512
19739
  base();
19513
19740
  });
@@ -19698,6 +19925,48 @@ Fit.Controls.WSDropDown = function(ctlId)
19698
19925
  }
19699
19926
  }
19700
19927
 
19928
+ function updateActionMenu()
19929
+ {
19930
+ if (useActionMenu === false)
19931
+ {
19932
+ return;
19933
+ }
19934
+
19935
+ var searchIcon = "<span class='FitUiControlDropDownActionMenuItem FitUiControlDropDownActionMenuItemSearch fa fa-search'></span> ";
19936
+ var showAllIcon = "<span class='FitUiControlDropDownActionMenuItem FitUiControlDropDownActionMenuItemShowAll fa fa-sitemap'></span> ";
19937
+ var delIcon = "<span class='FitUiControlDropDownActionMenuItem FitUiControlDropDownActionMenuItemDelete fa fa-times'></span> ";
19938
+
19939
+ var selectedItems = me.GetSelections();
19940
+ var addRemoveAll = selectedItems.length > 1;
19941
+
19942
+ actionMenu.RemoveItems();
19943
+
19944
+ actionMenu.AddItem(searchIcon + translations.SearchMore, "SearchMore");
19945
+
19946
+ if (dataRequested === false || tree.GetChildren().length > 0)
19947
+ {
19948
+ actionMenu.AddItem(showAllIcon + translations.ShowAllOptions, "ShowAll");
19949
+ }
19950
+
19951
+ if (addRemoveAll === true)
19952
+ {
19953
+ actionMenu.AddItem(delIcon + translations.RemoveAll, "RemoveAll");
19954
+ }
19955
+
19956
+ Fit.Array.ForEach(selectedItems, function(item)
19957
+ {
19958
+ actionMenu.AddItem((addRemoveAll === true ? " &nbsp; &nbsp; &nbsp; " : "") + delIcon + translations.Remove + " " + item.Title, "Remove:" + item.Value);
19959
+ });
19960
+ }
19961
+
19962
+ function localize()
19963
+ {
19964
+ var locale = Fit.Internationalization.GetLocale(me);
19965
+ translations = locale.Translations;
19966
+
19967
+ updateActionMenu();
19968
+ }
19969
+
19701
19970
  function onDataLoaded(cb)
19702
19971
  {
19703
19972
  Fit.Validation.ExpectFunction(cb);
@@ -19775,31 +20044,46 @@ Fit.Controls.WSDropDown = function(ctlId)
19775
20044
  // All locales inherit from en. All country specific overrides inherit
19776
20045
  // from their primary locale (e.g. de_AT inherits from de).
19777
20046
  // English (en) MUST be defined!
19778
-
20047
+
19779
20048
  "en": // US
19780
20049
  {
19781
20050
  Translations:
19782
20051
  {
19783
- InvalidSelection : "Invalid selection"
20052
+ InvalidSelection : "Invalid selection",
20053
+
20054
+ SearchMore : "Search for more options",
20055
+ ShowAllOptions : "Show all available options",
20056
+ RemoveAll : "Remove all selected",
20057
+ Remove : "Remove"
19784
20058
  }
19785
20059
  },
19786
20060
  "da":
19787
20061
  {
19788
20062
  Translations:
19789
20063
  {
19790
- InvalidSelection : "Ugyldigt valg"
20064
+ InvalidSelection : "Ugyldigt valg",
20065
+
20066
+ SearchMore : "Søg efter flere valgmuligheder",
20067
+ ShowAllOptions : "Vis alle tilgængelige valgmuligheder",
20068
+ RemoveAll : "Fjern alle valgte",
20069
+ Remove : "Fjern"
19791
20070
  }
19792
20071
  },
19793
20072
  "de":
19794
20073
  {
19795
20074
  Translations:
19796
20075
  {
19797
- InvalidSelection : "Ungültige Auswahl"
20076
+ InvalidSelection : "Ungültige Auswahl",
20077
+
20078
+ SearchMore : "Nach weiteren Optionen suchen",
20079
+ ShowAllOptions : "Alle verfügbaren Optionen anzeigen",
20080
+ RemoveAll : "Alle ausgewählten entfernen",
20081
+ Remove : "Entfernen"
19798
20082
  }
19799
20083
  }
19800
20084
  }
19801
20085
  Fit.Internationalization.AddLocalization(Fit.Controls.DropDown, locale);
19802
- Fit.Internationalization.AddLocalization(Fit.Controls.WSDropDown, locale);
20086
+ Fit.Internationalization.AddLocalization(Fit.Controls.WSDropDown, locale);
19803
20087
  })();
19804
20088
  /// <container name="Fit.Controls.FilePicker" extends="Fit.Controls.ControlBase">
19805
20089
  /// Control allowing for files to be selected locally and uploaded asynchronously.
@@ -22710,6 +22994,9 @@ Fit.Controls.ListView = function(controlId)
22710
22994
  var firstWasHighlighted = false;
22711
22995
  var isIe8 = (Fit.Browser.GetInfo().Name === "MSIE" && Fit.Browser.GetInfo().Version === 8);
22712
22996
 
22997
+ var onSelectHandlers = [];
22998
+ var onSelectedHandlers = [];
22999
+
22713
23000
  function init()
22714
23001
  {
22715
23002
  list.tabIndex = "0";
@@ -22763,12 +23050,17 @@ Fit.Controls.ListView = function(controlId)
22763
23050
 
22764
23051
  // Fire OnChanging and OnChange events
22765
23052
 
23053
+ var item = convertItemElementToObject(elm);
23054
+ var selectionCanceled = fireOnSelectHandlers(item) === false;
23055
+
22766
23056
  // Notice: We always pass False as current selection state to OnItemSelectionChanging since ListView does
22767
23057
  // not keep track of selection state. In theory item could very well already be selected in host control.
22768
23058
  // Event handlers should not trust boolean to reveal selection in host control, only in picker.
22769
- if (me._internal.FireOnItemSelectionChanging(Fit.Dom.Text(elm), decode(Fit.Dom.Data(elm, "value")), false, false) === true)
23059
+ if (selectionCanceled === false && me._internal.FireOnItemSelectionChanging(item.Title, item.Value, false, false) === true)
22770
23060
  {
22771
- me._internal.FireOnItemSelectionChanged(Fit.Dom.Text(elm), decode(Fit.Dom.Data(elm, "value")), true, false);
23061
+ fireOnSelectedHandlers(item);
23062
+
23063
+ me._internal.FireOnItemSelectionChanged(item.Title, item.Value, true, false);
22772
23064
  me._internal.FireOnItemSelectionComplete();
22773
23065
  }
22774
23066
  }
@@ -22888,6 +23180,21 @@ Fit.Controls.ListView = function(controlId)
22888
23180
  return null;
22889
23181
  }
22890
23182
 
23183
+ /// <function container="Fit.Controls.ListView" name="GetItems" access="public" returns="Fit.Controls.ListViewTypeDefs.ListViewItem[]">
23184
+ /// <description> Get all items - returns array containing objects with Title (string) and Value (string) properties </description>
23185
+ /// </function>
23186
+ this.GetItems = function()
23187
+ {
23188
+ var items = [];
23189
+
23190
+ Fit.Array.ForEach(list.children, function(child)
23191
+ {
23192
+ Fit.Array.Add(items, convertItemElementToObject(child));
23193
+ });
23194
+
23195
+ return items;
23196
+ }
23197
+
22891
23198
  /// <function container="Fit.Controls.ListView" name="HasItem" access="public" returns="boolean">
22892
23199
  /// <description> Returns value indicating whether control contains item with specified value </description>
22893
23200
  /// <param name="value" type="string"> Value of item to check for </param>
@@ -22911,6 +23218,11 @@ Fit.Controls.ListView = function(controlId)
22911
23218
  if (item !== null)
22912
23219
  {
22913
23220
  Fit.Dom.Remove(item);
23221
+
23222
+ if (item === active)
23223
+ {
23224
+ active = null;
23225
+ }
22914
23226
  }
22915
23227
  }
22916
23228
 
@@ -22974,12 +23286,17 @@ Fit.Controls.ListView = function(controlId)
22974
23286
 
22975
23287
  if (active !== null)
22976
23288
  {
23289
+ var item = convertItemElementToObject(active);
23290
+ var selectionCanceled = fireOnSelectHandlers(item) === false;
23291
+
22977
23292
  // Notice: We always pass False as current selection state to OnItemSelectionChanging since ListView does
22978
23293
  // not keep track of selection state. In theory item could very well already be selected in host control.
22979
23294
  // Event handlers should not trust boolean to reveal selection in host control, only in picker.
22980
- if (me._internal.FireOnItemSelectionChanging(Fit.Dom.Text(active), decode(Fit.Dom.Data(active, "value")), false, false) === true)
23295
+ if (selectionCanceled === false && me._internal.FireOnItemSelectionChanging(item.Title, item.Value, false, false) === true)
22981
23296
  {
22982
- me._internal.FireOnItemSelectionChanged(Fit.Dom.Text(active), decode(Fit.Dom.Data(active, "value")), true, false);
23297
+ fireOnSelectedHandlers(item);
23298
+
23299
+ me._internal.FireOnItemSelectionChanged(item.Title, item.Value, true, false);
22983
23300
  me._internal.FireOnItemSelectionComplete();
22984
23301
  }
22985
23302
  }
@@ -23038,6 +23355,47 @@ Fit.Controls.ListView = function(controlId)
23038
23355
  return highlightFirst;
23039
23356
  }
23040
23357
 
23358
+ /// <function container="Fit.Controls.ListViewTypeDefs" name="OnSelectEventHandler" returns="boolean | void">
23359
+ /// <description> OnSelect event handler </description>
23360
+ /// <param name="sender" type="$TypeOfThis"> Instance of control </param>
23361
+ /// <param name="item" type="{ Title: string, Value: string }"> Selected item </param>
23362
+ /// </function>
23363
+
23364
+ /// <function container="Fit.Controls.ListView" name="OnSelect" access="public">
23365
+ /// <description>
23366
+ /// Register event handler fired when item is being selected.
23367
+ /// Selection can be canceled by returning False.
23368
+ /// The following arguments are passed to event handler function:
23369
+ /// Sender (ListView) and Item (with Title (string) and Value (string) properties).
23370
+ /// </description>
23371
+ /// <param name="cb" type="Fit.Controls.ListViewTypeDefs.OnSelectEventHandler"> Event handler function </param>
23372
+ /// </function>
23373
+ this.OnSelect = function(cb)
23374
+ {
23375
+ Fit.Validation.ExpectFunction(cb);
23376
+ Fit.Array.Add(onSelectHandlers, cb);
23377
+ }
23378
+
23379
+ /// <function container="Fit.Controls.ListViewTypeDefs" name="OnSelectedEventHandler">
23380
+ /// <description> OnSelected event handler </description>
23381
+ /// <param name="sender" type="$TypeOfThis"> Instance of control </param>
23382
+ /// <param name="item" type="{ Title: string, Value: string }"> Selected item </param>
23383
+ /// </function>
23384
+
23385
+ /// <function container="Fit.Controls.ListView" name="OnSelected" access="public">
23386
+ /// <description>
23387
+ /// Register event handler fired when item is selected.
23388
+ /// The following arguments are passed to event handler function:
23389
+ /// Sender (ListView) and Item (with Title (string) and Value (string) properties).
23390
+ /// </description>
23391
+ /// <param name="cb" type="Fit.Controls.ListViewTypeDefs.OnSelectedEventHandler"> Event handler function </param>
23392
+ /// </function>
23393
+ this.OnSelected = function(cb)
23394
+ {
23395
+ Fit.Validation.ExpectFunction(cb);
23396
+ Fit.Array.Add(onSelectedHandlers, cb);
23397
+ }
23398
+
23041
23399
  this.Destroy = Fit.Core.CreateOverride(this.Destroy, function(calledInternally)
23042
23400
  {
23043
23401
  Fit.Validation.ExpectBoolean(calledInternally, true);
@@ -23063,7 +23421,7 @@ Fit.Controls.ListView = function(controlId)
23063
23421
  me.Destroy(true); // PickerBase.Destroy()
23064
23422
  }
23065
23423
 
23066
- me = list = active = persistView = scrollPositionTop = highlightFirst = firstWasHighlighted = isIe8 = null;
23424
+ me = list = active = persistView = scrollPositionTop = highlightFirst = firstWasHighlighted = isIe8 = onSelectHandlers = onSelectedHandlers = null;
23067
23425
  });
23068
23426
 
23069
23427
  // ============================================
@@ -23175,6 +23533,37 @@ Fit.Controls.ListView = function(controlId)
23175
23533
  }
23176
23534
  }
23177
23535
 
23536
+ function fireOnSelectHandlers(item)
23537
+ {
23538
+ Fit.Validation.ExpectObject(item);
23539
+ Fit.Validation.ExpectString(item.Title);
23540
+ Fit.Validation.ExpectString(item.Value);
23541
+
23542
+ var selectionCanceled = false;
23543
+
23544
+ Fit.Array.ForEach(onSelectHandlers, function(handler)
23545
+ {
23546
+ if (handler(me, item) === false)
23547
+ {
23548
+ selectionCanceled = true;
23549
+ }
23550
+ });
23551
+
23552
+ return selectionCanceled === true ? false : true; // Return False if canceled
23553
+ }
23554
+
23555
+ function fireOnSelectedHandlers(item)
23556
+ {
23557
+ Fit.Validation.ExpectObject(item);
23558
+ Fit.Validation.ExpectString(item.Title);
23559
+ Fit.Validation.ExpectString(item.Value);
23560
+
23561
+ Fit.Array.ForEach(onSelectedHandlers, function(handler)
23562
+ {
23563
+ handler(me, item);
23564
+ });
23565
+ }
23566
+
23178
23567
  function repaint()
23179
23568
  {
23180
23569
  if (isIe8 === true)