From 863891f702b3050685c4b42d7d331bdeffdd9f2c Mon Sep 17 00:00:00 2001 From: Jimmy Thomsen Date: Sat, 16 Jan 2016 13:44:30 +0100 Subject: [PATCH] TreeView, WSTreeView, Browser, Dom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TreeView - Fixed ContextMenu positioning when opened using keyboard. WSTreeView - Fixed loading indicator which got stuck when requesting children for multiple nodes simultaneously. Browser - Fixed StorageSupported function which did not properly cache the result of the first call - result written to wrong internal property. - Renamed StorageSupported function to IsStorageSupported Dom - Added Replace(oldElement, newElement) function - Fixed CreateElement function which did not include text nodes - e.g.: CreateElement(“Hello world”); The " world” portion would have been excluded. - Fixed GetPosition function which returned float values when requesting position relative to viewport. --- Controls/TreeView/TreeView.js | 2 +- Controls/TreeView/WSTreeView.js | 47 +++++++++++++++---------------- Core/Browser.js | 11 ++++---- Core/Dom.js | 49 +++++++++++++++++++++++---------- 4 files changed, 63 insertions(+), 46 deletions(-) diff --git a/Controls/TreeView/TreeView.js b/Controls/TreeView/TreeView.js index 96b1511..06bd966 100644 --- a/Controls/TreeView/TreeView.js +++ b/Controls/TreeView/TreeView.js @@ -229,7 +229,7 @@ Fit.Controls.TreeView = function(ctlId) if (ev.keyCode === 93 || (Fit.Events.GetModifierKeys().Shift === true && ev.keyCode === 121)) // Context menu button or Shift+F10 { var label = node.GetDomElement().querySelector("span"); - var pos = Fit.Dom.GetPosition(label); + var pos = Fit.Dom.GetPosition(label, true); // True argument = get position relative to viewport rather than document pos.X = pos.X + label.offsetWidth - 10; pos.Y = pos.Y + label.offsetHeight - 5; diff --git a/Controls/TreeView/WSTreeView.js b/Controls/TreeView/WSTreeView.js index c5f6e02..125597e 100644 --- a/Controls/TreeView/WSTreeView.js +++ b/Controls/TreeView/WSTreeView.js @@ -29,7 +29,6 @@ Fit.Controls.WSTreeView = function(ctlId) var orgSelected = []; var loadDataOnInit = true; var selectAllMode = Fit.Controls.WSTreeView.SelectAllMode.Progressively; - var loading = null; var onRequestHandlers = []; var onResponseHandlers = []; var onAbortHandlers = []; @@ -54,14 +53,6 @@ Fit.Controls.WSTreeView = function(ctlId) if (node.GetDomElement()._internal.WSHasChildren === false) return; - // Loading indicator - - var li = node.GetDomElement(); - - loading = document.createElement("i"); - Fit.Dom.AddClass(loading, "FitUiControlLoadingIndicator"); - Fit.Dom.Add(li, loading); - // Get data node.GetDomElement()._internal.WSLoading = true; @@ -82,23 +73,10 @@ Fit.Controls.WSTreeView = function(ctlId) node.AddChild(createNodeFromJson(c)); }); - // Remove loading indicator - - Fit.Dom.Remove(loading); - loading = null; - node.GetDomElement()._internal.WSDone = true; node.Expanded(true); // Unfortunately causes both OnToggle and OnToggled to be fired, although OnToggle has already been fired once (canceled below) }); - // Remove loading indicator if request was canceled - - if (canceled === true) - { - Fit.Dom.Remove(loading); - loading = null; - } - return false; // Cancel toggle, will be "resumed" when data is loaded }); @@ -889,6 +867,14 @@ Fit.Controls.WSTreeView = function(ctlId) cb(node, eventArgs); // Callback is responsible for populating TreeView + // Remove loading indicator + + if (request._loadingIndicator !== undefined) // Loading indicator not set when requesting root nodes + { + Fit.Dom.Remove(request._loadingIndicator); + delete request._loadingIndicator; + } + // Select nodes found in preselections if (Fit.Core.IsEqual(preSelected, {}) === false) // Prevent nodes from being iterated if no preselections are found @@ -922,10 +908,10 @@ Fit.Controls.WSTreeView = function(ctlId) request.OnAbort(function(req) { - if (loading !== null) // Loading indicator not set when requesting root nodes + if (request._loadingIndicator !== undefined) // Loading indicator not set when requesting root nodes { - Fit.Dom.Remove(loading); // Remove loading indicator - loading = null; + Fit.Dom.Remove(request._loadingIndicator); + delete request._loadingIndicator; } if (node !== null) // Null when requesting root nodes @@ -936,6 +922,17 @@ Fit.Controls.WSTreeView = function(ctlId) fireEventHandlers(onAbortHandlers, eventArgs); }); + // Display loading indicator + + if (node !== null) // Null when requesting root nodes + { + var li = node.GetDomElement(); + + request._loadingIndicator = document.createElement("i"); + Fit.Dom.AddClass(request._loadingIndicator, "FitUiControlLoadingIndicator"); + Fit.Dom.Add(li, request._loadingIndicator); + } + // Invoke request request.Start(); diff --git a/Core/Browser.js b/Core/Browser.js index cbcd762..7c3f28b 100644 --- a/Core/Browser.js +++ b/Core/Browser.js @@ -266,13 +266,15 @@ Fit.Browser.GetInfo = function() return Fit.Core.Clone(Fit._internal.Browser.Info); // Clone to ensure values are not shared and potentially changed } -/// +/// /// Returns value indicating whether Session and Local storage is supported or not /// -Fit.Browser.StorageSupported = function() +Fit.Browser.IsStorageSupported = function() { if (Fit._internal.Browser.StorageSupported === undefined) { + Fit._internal.Browser.StorageSupported = false; + try { if (window.localStorage && window.sessionStorage) @@ -285,14 +287,13 @@ Fit.Browser.StorageSupported = function() sessionStorage.setItem(x, x); sessionStorage.removeItem(x); - Fit._internal.StorageSupported = true; + Fit._internal.Browser.StorageSupported = true; } } catch (err) { - Fit._internal.StorageSupported = false; } } - return Fit._internal.StorageSupported; + return Fit._internal.Browser.StorageSupported; } diff --git a/Core/Dom.js b/Core/Dom.js index 919a10f..0e47ce1 100644 --- a/Core/Dom.js +++ b/Core/Dom.js @@ -165,8 +165,22 @@ Fit.Dom.InsertAt = function(container, position, newElm) } } +/// +/// Replace element with another one +/// Element to replace (Element or Text) +/// Replacement element (Element or Text) +/// +Fit.Dom.Replace = function(oldElm, newElm) // http://jsfiddle.net/Jemt/eu74o984/ +{ + Fit.Validation.ExpectContentNode(oldElm); + Fit.Validation.ExpectContentNode(newElm); + + var container = oldElm.parentElement; + container.replaceChild(newElm, oldElm); +} + /// -/// Add DOMElement to container +/// Add element to container /// Add element to this container /// Element or Text node to add to container /// @@ -257,7 +271,12 @@ Fit.Dom.CreateElement = function(html, containerTagName) var container = document.createElement(((Fit.Validation.IsSet(containerTagName) === true) ? containerTagName : "div")); container.innerHTML = html; - if (container.children.length === 1) + // Using childNodes property instead of children property to include text nodes, + // which the DOM functions in Fit.UI usually do not take into account. + // If text nodes are not included, a call like the following would exclude + // the " world" portion. We do not want to throw away data, naturally! Example: + // Fit.Dom.CreateElement("Hello world"); // Returns
Hello world
+ if (container.childNodes.length === 1) return container.firstChild; return container; @@ -480,26 +499,26 @@ Fit.Dom.GetPosition = function(elm, relativeToViewport) Fit.Validation.ExpectDomElement(elm); Fit.Validation.ExpectBoolean(relativeToViewport, true); - // Return position within viewport + // Return position within viewport - if (relativeToViewport === true) - { - var res = elm.getBoundingClientRect(); - return { X: res.left, Y: res.top }; - } + if (relativeToViewport === true) + { + var res = elm.getBoundingClientRect(); // DOMRect object with float properties + return { X: Math.floor(res.left), Y: Math.floor(res.top) }; + } - // Return position within document + // Return position within document - var pos = { X: 0, Y: 0 }; + var pos = { X: 0, Y: 0 }; while (elm) - { - pos.X += elm.offsetLeft; - pos.Y += elm.offsetTop; - elm = elm.offsetParent; + { + pos.X += elm.offsetLeft; + pos.Y += elm.offsetTop; + elm = elm.offsetParent; } - return pos; + return pos; } ///