Skip to content

Commit 345376f

Browse files
committed
Improved method for UI object identification.
- widgetID is now a structure (this is more robust). - Refactored helper styling methods - now all go through setStyle. - Adapted TableDemo to new ID conventions. - getWidgetInfo is possibly broken (due to the "registry.byId" call which doesn't work in the general ID_struct case). Internal documentation updated accordingly.
1 parent 46cec70 commit 345376f

2 files changed

Lines changed: 73 additions & 39 deletions

File tree

Demo/TableDemo.m

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,54 @@
66
UITable matlab.ui.control.Table
77
Button matlab.ui.control.Button
88
end
9+
10+
properties (Access = private, Constant = true)
11+
ID_ATTRIBUTE_NAME = 'id';
12+
end
913

1014
methods (Access = private)
1115

1216
% Button pushed function: Button
1317
function ButtonPushed(app, ~)
14-
% Return all registered widgets:
18+
IAN = app.ID_ATTRIBUTE_NAME;
19+
hWin = mlapptools.getWebWindow(app.UIFigure);
20+
% Return all registered widgets:
1521
[~,w] = mlapptools.getWidgetList(app.UIFigure);
1622
% Filter list:
1723
w = w(~cellfun(@isempty,w.id) & ...
1824
cellfun(@(x)~isempty(strfind(x,'uniq')),w.id),:); %#ok<STREMP>
1925
% Apply random styles:
2026
for ind1 = 1:4:size(w,1)
2127
mlapptools.setStyle(...
22-
app.UIFigure,...
28+
hWin,...
2329
'border',...
2430
'2px solid red',...
25-
w{ind1,'id'}{1});
31+
struct('ID_attr',IAN,'ID_val',w{ind1,IAN}{1}));
2632
end
2733

2834
for ind2 = 2:4:size(w,1)
2935
mlapptools.setStyle(...
30-
app.UIFigure,...
36+
hWin,...
3137
'background-image',...
3238
'url(http://lorempixel.com/40/120/)',...
33-
w{ind2,'id'}{1});
39+
struct('ID_attr',IAN,'ID_val',w{ind2,IAN}{1}));
3440
end
3541

3642
for ind3 = 3:4:size(w,1)
3743
mlapptools.setStyle(...
38-
app.UIFigure,...
44+
hWin,...
3945
'background-color',...
4046
['rgb(' num2str(randi(255)) ',' num2str(randi(255)) ',' ...
4147
num2str(randi(255)) +')'],...
42-
w{ind3,'id'}{1});
48+
struct('ID_attr',IAN,'ID_val',w{ind3,IAN}{1}));
4349
end
4450

4551
for ind4 = 4:4:size(w,1)
4652
mlapptools.setStyle(...
47-
app.UIFigure,...
53+
hWin,...
4854
'padding',...
4955
'0cm 1cm 0cm 0cm',...
50-
w{ind4,'id'}{1});
56+
struct('ID_attr',IAN,'ID_val',w{ind4,IAN}{1}));
5157
end
5258

5359
end

mlapptools.m

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
properties (Access = private, Constant = true)
2525
QUERY_TIMEOUT = 5; % Dojo query timeout period, seconds
2626
TAG_TIMEOUT = 'QUERY_TIMEOUT';
27+
DEF_ID_ATTRIBUTE = 'id';
2728
end
2829

2930
methods (Access = public, Static = true)
@@ -53,21 +54,19 @@ function fontColor(uiElement, newcolor)
5354
% A method for manipulating text color.
5455
newcolor = mlapptools.validateCSScolor(newcolor);
5556

56-
[win, widgetID] = mlapptools.getWebElements(uiElement);
57+
[win, ID_struct] = mlapptools.getWebElements(uiElement);
5758

58-
fontColorSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "color", "%s")', widgetID, newcolor);
59-
win.executeJS(fontColorSetStr);
59+
mlapptools.setStyle(win, 'color', newcolor, ID_struct);
6060
end % fontColor
6161

6262
function fontWeight(uiElement, weight)
6363
% A method for manipulating font weight, which controls how thick or
6464
% thin characters in text should be displayed.
65-
weight = mlapptools.validateFontWeight(weight);
65+
weight = mlapptools.validateFontWeight(weight);
6666

67-
[win, widgetID] = mlapptools.getWebElements(uiElement);
67+
[win, ID_struct] = mlapptools.getWebElements(uiElement);
6868

69-
fontWeightSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "font-weight", "%s")', widgetID, weight);
70-
win.executeJS(fontWeightSetStr);
69+
mlapptools.setStyle(win, 'font-weight', weight, ID_struct);
7170
end % fontWeight
7271

7372
function [fullHTML] = getHTML(hUIFig)
@@ -126,7 +125,8 @@ function fontWeight(uiElement, weight)
126125
end % getWebWindow
127126

128127
function [nfo] = getWidgetInfo(win, widgetID, verboseFlag)
129-
% A method for gathering information about a specific dijit widget.
128+
% A method for gathering information about a specific dijit widget, if its
129+
% HTML div id is known.
130130
%% Handling required positional inputs:
131131
assert(nargin >= 2,'mlapptools:getWidgetInfo:insufficientInputs',...
132132
'getWidgetInfo must be called with at least 2 inputs.');
@@ -136,7 +136,7 @@ function fontWeight(uiElement, weight)
136136
end
137137
%% Querying dijit
138138
win.executeJS(['var W; require(["dijit/registry"], '...
139-
'function(registry){W = registry.byId("' widgetID '");}); W = [W];']);
139+
'function(registry){W = registry.byId("' widgetID.ID_val '");}); W = [W];']);
140140
% Decoding
141141
try
142142
nfo = mlapptools.decodeDijitRegistryResult(win,verboseFlag);
@@ -194,8 +194,9 @@ function fontWeight(uiElement, weight)
194194
% 3-parameter call:
195195
% widgetID = setStyle(hControl, styleAttr, styleValue)
196196
% 4-parameter call:
197-
% setStyle(hUIFig, styleAttr, styleValue, widgetID)
197+
% setStyle(hWin, styleAttr, styleValue, ID_struct)
198198

199+
narginchk(3,4);
199200
% Unpack inputs:
200201
styleAttr = varargin{2};
201202
styleValue = varargin{3};
@@ -204,16 +205,15 @@ function fontWeight(uiElement, weight)
204205
case 3
205206
hControl = varargin{1};
206207
% Get a handle to the webwindow
207-
[win, widgetID] = mlapptools.getWebElements(hControl);
208+
[win, ID_struct] = mlapptools.getWebElements(hControl);
208209
case 4
209-
hUIFig = varargin{1};
210-
widgetID = varargin{4};
211-
212-
% Get a handle to the webwindow
213-
win = mlapptools.getWebWindow(hUIFig);
214-
end
215-
216-
styleSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "%s", "%s")', widgetID, styleAttr, styleValue);
210+
% If we know the ID_struct, the webwindow handle must be available
211+
win = varargin{1};
212+
ID_struct = varargin{4};
213+
end
214+
215+
styleSetStr = sprintf('dojo.style(dojo.query("[%s = ''%s'']")[0], "%s", "%s")',...
216+
ID_struct.ID_attr, ID_struct.ID_val, styleAttr, styleValue);
217217
% ^ this might result in junk if widgetId=='null'.
218218
try
219219
win.executeJS(styleSetStr);
@@ -226,7 +226,7 @@ function fontWeight(uiElement, weight)
226226

227227
% Assign outputs:
228228
if nargout >= 1
229-
varargout{1} = widgetID;
229+
varargout{1} = ID_struct;
230230
end
231231

232232
end % setStyle
@@ -241,10 +241,9 @@ function textAlign(uiElement, alignment)
241241
alignment = lower(alignment);
242242
mlapptools.validateAlignmentStr(alignment)
243243

244-
[win, widgetID] = mlapptools.getWebElements(uiElement);
244+
[win, ID_struct] = mlapptools.getWebElements(uiElement);
245245

246-
alignSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "textAlign", "%s")', widgetID, alignment);
247-
win.executeJS(alignSetStr);
246+
mlapptools.setStyle(win, 'textAlign', alignment, ID_struct);
248247
end % textAlign
249248

250249
function win = waitForFigureReady(hUIFig)
@@ -346,17 +345,46 @@ function textAlign(uiElement, alignment)
346345
hFig = hFigs(hWebwindow == ww);
347346
end % figFromWebwindow
348347

349-
function [widgetID] = getWidgetID(win, data_tag)
348+
function [ID_struct] = getWidgetID(win, data_tag)
349+
% This method returns a structure containing some uniquely-identifying information
350+
% about a DOM node.
350351
widgetquerystr = sprintf('dojo.getAttr(dojo.query("[data-tag^=''%s''] > div")[0], "widgetid")', data_tag);
351-
hFig = mlapptools.figFromWebwindow(win);
352-
mlapptools.waitTillFigureLoaded(hFig);
352+
mlapptools.waitTillWebwindowLoaded(win);
353353
try % should work for most UI objects
354-
widgetID = win.executeJS(widgetquerystr);
355-
widgetID = widgetID(2:end-1);
354+
ID = win.executeJS(widgetquerystr);
355+
ID_struct = struct('ID_attr', mlapptools.DEF_ID_ATTRIBUTE, 'ID_val', ID(2:end-1));
356356
catch % fallback for problematic objects
357-
warning('Problematic control encountered with no fallback implemented yet.')
358-
% TODO
357+
% We retry by using the dijit registry:
358+
win.executeJS(['var W; require(["dijit/registry"], '...
359+
'function(registry){W = registry.toArray().map(x => x.domNode.childNodes);});']);
360+
nWidgets = jsondecode(win.executeJS('W.length'));
361+
try
362+
for ind1 = 0:nWidgets-1
363+
nChild = jsondecode(win.executeJS(sprintf('W[%d].length',ind1)));
364+
for ind2 = 0:nChild-1
365+
tmp = win.executeJS(sprintf('W[%d][%d].dataset',ind1,ind2));
366+
if isempty(tmp)
367+
continue
368+
else
369+
tmp = jsondecode(tmp);
370+
end
371+
if isfield(tmp,'tag') && strcmp(tmp.tag,data_tag)
372+
ID = win.executeJS(sprintf('dojo.getAttr(W[%d][%d].parentNode,"widgetid")',ind1,ind2));
373+
error('Bailout!');
374+
end
375+
end
376+
end
377+
catch
378+
if strcmp(tmp.type,'matlab.ui.container.TreeNode')
379+
tmp = jsondecode(win.executeJS(sprintf(...
380+
'dojo.byId(%s).childNodes[0].childNodes[0].childNodes[0].childNodes[%d].dataset',...
381+
ID(2:end-1),ind2-1)));
382+
ID_struct = struct('ID_attr', 'data-reactid', 'ID_val', tmp.reactid);
383+
end
384+
% do nothing - bailout.
385+
end
359386
end
387+
360388
end % getWidgetID
361389

362390
function to = getTimeout(hFig)

0 commit comments

Comments
 (0)