Skip to content

Commit 067c389

Browse files
committed
Add polling for widget & webwindow presence
Rather than catching all errors indiscriminately, error checking has been added to specific queries in order to properly catch conditions where we're racing MATLAB's UI object initialization and wait for the UI to render prior to querying the base web components. See: #1
1 parent 2c6062a commit 067c389

File tree

1 file changed

+85
-61
lines changed

1 file changed

+85
-61
lines changed

mlapptools.m

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
%
44
% MLAPPTOOLS methods:
55

6+
properties (Constant)
7+
querytimeout = 5; % Dojo query timeout period, seconds
8+
end
9+
610
methods
711
function obj = mlapptools
812
% Dummy constructor so we don't return an empty class instance
@@ -15,76 +19,52 @@
1519
function textAlign(uielement, alignment)
1620
alignment = lower(alignment);
1721
mlapptools.validatealignmentstr(alignment)
18-
19-
rez = '';
20-
while ~strcmp(rez, sprintf('"%s"', alignment))
21-
try
22-
% Get a handle to the webwindow
23-
win = mlapptools.getwebwindow(uielement.Parent);
24-
25-
% Find which element of the DOM we want to edit
26-
data_tag = mlapptools.getdatatag(uielement);
27-
28-
% Manipulate the DOM via a JS command
29-
widgetID = mlapptools.getwidgetID(win, data_tag);
30-
31-
alignsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "textAlign", "%s")', widgetID, alignment);
32-
rez = win.executeJS(alignsetstr);
33-
catch err
34-
% TODO: Check the error so we're not catching errors indiscriminately
35-
pause(1); % Give the figure (webpage) some more time to load
36-
end
37-
end
22+
23+
% Get a handle to the webwindow
24+
win = mlapptools.getwebwindow(uielement.Parent);
25+
26+
% Find which element of the DOM we want to edit
27+
data_tag = mlapptools.getdatatag(uielement);
28+
29+
% Manipulate the DOM via a JS command
30+
widgetID = mlapptools.getwidgetID(win, data_tag);
31+
32+
alignsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "textAlign", "%s")', widgetID, alignment);
33+
win.executeJS(alignsetstr);
3834
end
3935

4036

4137
function fontWeight(uielement, weight)
4238
weight = mlapptools.validatefontweight(weight);
4339

44-
wt = '';
45-
while ~strcmp(wt, sprintf('"%s"', weight))
46-
try
47-
% Get a handle to the webwindow
48-
win = mlapptools.getwebwindow(uielement.Parent);
49-
50-
% Find which element of the DOM we want to edit
51-
data_tag = mlapptools.getdatatag(uielement);
52-
53-
% Manipulate the DOM via a JS command
54-
widgetID = mlapptools.getwidgetID(win, data_tag);
55-
56-
fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "font-weight", "%s")', widgetID, weight);
57-
wt = win.executeJS(fontwtsetstr);
58-
catch err
59-
% TODO: Check the error so we're not catching errors indiscriminately
60-
pause(1); % Give the figure (webpage) some more time to load
61-
end
62-
end
40+
% Get a handle to the webwindow
41+
win = mlapptools.getwebwindow(uielement.Parent);
42+
43+
% Find which element of the DOM we want to edit
44+
data_tag = mlapptools.getdatatag(uielement);
45+
46+
% Manipulate the DOM via a JS command
47+
widgetID = mlapptools.getwidgetID(win, data_tag);
48+
49+
fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "font-weight", "%s")', widgetID, weight);
50+
win.executeJS(fontwtsetstr);
6351
end
6452

6553

6654
function fontcolor(uielement, newcolor)
6755
newcolor = mlapptools.validateCSScolor(newcolor);
56+
57+
% Get a handle to the webwindow
58+
win = mlapptools.getwebwindow(uielement.Parent);
6859

69-
DOMcolor = '';
70-
while ~strcmp(DOMcolor, sprintf('"%s"', newcolor))
71-
try
72-
% Get a handle to the webwindow
73-
win = mlapptools.getwebwindow(uielement.Parent);
74-
75-
% Find which element of the DOM we want to edit
76-
data_tag = mlapptools.getdatatag(uielement);
77-
78-
% Manipulate the DOM via a JS command
79-
widgetID = mlapptools.getwidgetID(win, data_tag);
80-
81-
fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "color", "%s")', widgetID, newcolor);
82-
DOMcolor = win.executeJS(fontwtsetstr);
83-
catch err
84-
% TODO: Check the error so we're not catching errors indiscriminately
85-
pause(1); % Give the figure (webpage) some more time to load
86-
end
87-
end
60+
% Find which element of the DOM we want to edit
61+
data_tag = mlapptools.getdatatag(uielement);
62+
63+
% Manipulate the DOM via a JS command
64+
widgetID = mlapptools.getwidgetID(win, data_tag);
65+
66+
fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "color", "%s")', widgetID, newcolor);
67+
win.executeJS(fontwtsetstr);
8868
end
8969
end
9070

@@ -93,8 +73,29 @@ function fontcolor(uielement, newcolor)
9373
function [win] = getwebwindow(uifigurewindow)
9474
% TODO: Check that we've been passed an app designer figure window
9575
mlapptools.togglewarnings('off')
96-
win = struct(struct(uifigurewindow).Controller).Container.CEF;
76+
77+
tic
78+
while true && (toc < mlapptools.querytimeout)
79+
try
80+
win = struct(struct(uifigurewindow).Controller).Container.CEF;
81+
break
82+
catch err
83+
if strcmp(err.identifier, 'MATLAB:nonExistentField')
84+
pause(0.01)
85+
else
86+
mlapptools.togglewarnings('on')
87+
rethrow(err)
88+
end
89+
end
90+
end
9791
mlapptools.togglewarnings('on')
92+
93+
if toc < mlapptools.querytimeout
94+
msgID = 'mlapptools:getwidgetID:QueryTimeout';
95+
error(msgID, ...
96+
'WidgetID query timed out after %u seconds, UI needs more time to load', ...
97+
mlapptools.querytimeout);
98+
end
9899
end
99100

100101

@@ -107,8 +108,30 @@ function fontcolor(uielement, newcolor)
107108

108109
function [widgetID] = getwidgetID(win, data_tag)
109110
widgetquerystr = sprintf('dojo.getAttr(dojo.query("[data-tag^=''%s''] > div")[0], "widgetid")', data_tag);
110-
widgetID = win.executeJS(widgetquerystr);
111-
widgetID = widgetID(2:end-1);
111+
112+
tic
113+
while true && (toc < mlapptools.querytimeout)
114+
try
115+
widgetID = win.executeJS(widgetquerystr);
116+
widgetID = widgetID(2:end-1);
117+
break
118+
catch err
119+
if ~isempty(strfind(err.message, 'JavaScript error: Uncaught ReferenceError: dojo is not defined'))
120+
pause(0.01)
121+
else
122+
mlapptools.togglewarnings('on')
123+
rethrow(err)
124+
end
125+
end
126+
end
127+
mlapptools.togglewarnings('on')
128+
129+
if toc < mlapptools.querytimeout
130+
msgID = 'mlapptools:getwidgetID:QueryTimeout';
131+
error(msgID, ...
132+
'WidgetID query timed out after %u seconds, UI needs more time to load', ...
133+
mlapptools.querytimeout);
134+
end
112135
end
113136

114137

@@ -125,6 +148,7 @@ function togglewarnings(togglestr)
125148
end
126149
end
127150

151+
128152
function validatealignmentstr(alignment)
129153
if ~ischar(alignment)
130154
msgID = 'mlapptools:alignstring:InvalidInputIype';

0 commit comments

Comments
 (0)