Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 1a32c9e

Browse files
committed
[[ revBrowserCEF ]] Add revBrowser(Add/Remove)JavaScriptHandler functions to revbrowser.
[[ revBrowserCEF ]] Add custom callback handling to revbrowser
1 parent e091e21 commit 1a32c9e

File tree

2 files changed

+292
-23
lines changed

2 files changed

+292
-23
lines changed

revbrowser/src/revbrowser.cpp

Lines changed: 283 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class BrowserInstances
105105
int GetCallbackDepth(int p_id);
106106

107107
bool Callback(int p_instance_id, const char *p_message, const char *p_url = NULL);
108+
bool Callback(int p_id, const char *p_message, char **p_args, uint32_t p_arg_count, bool &r_pass);
108109

109110
void SetActiveInstanceId(int t_id);
110111

@@ -124,6 +125,9 @@ class BrowserInstances
124125
BrowserInstance *m_instances;
125126
BrowserInstance *m_active_instance;
126127
int m_last_instance_id;
128+
129+
bool FindInstanceById(int p_id, BrowserInstance *&r_instance);
130+
void SendMessage(BrowserInstance *p_instance, const char *p_message, bool &r_pass);
127131
};
128132

129133
static BrowserInstances s_browsers;
@@ -152,6 +156,20 @@ BrowserInstances::~BrowserInstances(void)
152156
}
153157
}
154158

159+
bool BrowserInstances::FindInstanceById(int p_id, BrowserInstance *&r_instance)
160+
{
161+
for(BrowserInstance *t_instance = m_instances; t_instance != nil; t_instance = t_instance->next)
162+
{
163+
if (t_instance->instance_id == p_id)
164+
{
165+
r_instance = t_instance;
166+
return true;
167+
}
168+
}
169+
170+
return false;
171+
}
172+
155173
void BrowserInstances::Add(CWebBrowserBase *p_browser, bool p_is_xbrowser)
156174
{
157175
BrowserInstance *t_instance;
@@ -217,18 +235,18 @@ CWebBrowserBase *BrowserInstances::GetActiveInstance(void)
217235

218236
CWebBrowserBase *BrowserInstances::GetInstance(int p_id)
219237
{
220-
for(BrowserInstance *t_instance = m_instances; t_instance != NULL; t_instance = t_instance -> next)
221-
if (t_instance -> instance_id == p_id)
222-
return t_instance -> browser;
223-
224-
return NULL;
238+
BrowserInstance *t_instance;
239+
if (FindInstanceById(p_id, t_instance))
240+
return t_instance->browser;
241+
else
242+
return nil;
225243
}
226244

227245
void BrowserInstances::SetActiveInstanceId(int p_id)
228246
{
229-
for(BrowserInstance *t_instance = m_instances; t_instance != NULL; t_instance = t_instance -> next)
230-
if (t_instance -> instance_id == p_id)
231-
m_active_instance = t_instance;
247+
BrowserInstance *t_instance;
248+
if (FindInstanceById(p_id, t_instance))
249+
m_active_instance = t_instance;
232250
}
233251

234252
char *BrowserInstances::GetInstanceIds(void)
@@ -251,14 +269,195 @@ char *BrowserInstances::GetInstanceIds(void)
251269
int BrowserInstances::GetCallbackDepth(int p_id)
252270
{
253271
BrowserInstance *t_instance;
254-
for(t_instance = m_instances; t_instance != NULL; t_instance = t_instance -> next)
255-
if (t_instance -> instance_id == p_id)
256-
break;
272+
if (FindInstanceById(p_id, t_instance))
273+
return t_instance->callback_depth;
274+
else
275+
return 0;
276+
}
257277

258-
if (t_instance != NULL)
259-
return t_instance -> callback_depth;
278+
bool is_escape_char(char p_char)
279+
{
280+
return p_char == '"';
281+
}
282+
283+
// IM-2014-03-06: [[ revBrowserCEF ]] Handle double-quote in strings by generating LC expression
284+
// that evaluates to the original string (using string concatenation with the "quote" constant)
285+
bool MCCStringQuote(const char *p_string, char *&r_quoted)
286+
{
287+
if (p_string == nil || p_string[0] == '\0')
288+
return MCCStringClone("", r_quoted);
289+
290+
bool t_success;
291+
t_success = true;
292+
293+
char *t_quoted;
294+
t_quoted = nil;
295+
296+
while (t_success && *p_string)
297+
{
298+
if (!is_escape_char(*p_string))
299+
{
300+
const char *t_run_start;
301+
t_run_start = p_string;
302+
303+
uint32_t t_run_length;
304+
t_run_length = 0;
305+
306+
while (*p_string != '\0' && !is_escape_char(*p_string))
307+
p_string++;
308+
309+
t_run_length = p_string - t_run_start;
310+
311+
t_success = MCCStringAppendFormat(t_quoted, t_quoted == nil ? "\"%*.*s\"" : "&\"%*.*s\"", t_run_length, t_run_length, t_run_start);
312+
}
313+
else if (*p_string == '"')
314+
{
315+
t_success = MCCStringAppend(t_quoted, t_quoted == nil ? "quote" : "&quote");
316+
p_string++;
317+
}
318+
}
319+
320+
if (t_success)
321+
r_quoted = t_quoted;
322+
else if (t_quoted != nil)
323+
MCCStringFree(t_quoted);
324+
325+
return t_success;
326+
}
327+
328+
#define MCSCRIPT_CALLBACK "\
329+
local tID=%d;\
330+
local tWinID=%d\
331+
%s;%s\
332+
global XBrowservar;\
333+
if XBrowservar is empty or the windowId of XBrowservar is not tWinID then;\
334+
repeat for each line tLine in the openStacks;\
335+
if the windowId of stack tLine is tWinID then;\
336+
put the long id of stack tLine into XBrowservar;\
337+
exit repeat;\
338+
end if;\
339+
end repeat;\
340+
end if;\
341+
send \"%s tID%s\" to this card of XBrowservar"
342+
343+
// IM-2014-03-06: [[ revBrowserCEF ]] Create script to call handler with the given parameters
344+
bool revBrowserCreateCallbackScript(int p_id, int p_window_id, const char *p_message, char **p_args, uint32_t p_arg_count, char *&r_script)
345+
{
346+
bool t_success;
347+
t_success = true;
348+
349+
char *t_assigns;
350+
t_assigns = nil;
351+
352+
char *t_locals;
353+
t_locals = nil;
354+
355+
for (uint32_t i = 0; t_success && i < p_arg_count; i++)
356+
{
357+
char *t_quoted_string;
358+
t_quoted_string = nil;
359+
360+
t_success = MCCStringQuote(p_args[i], t_quoted_string);
361+
if (t_success)
362+
{
363+
t_success = MCCStringAppendFormat(t_locals, ", tArg%d", i);
364+
if (t_success)
365+
t_success = MCCStringAppendFormat(t_assigns, "put %s into tArg%d;", t_quoted_string, i);
366+
}
367+
368+
if (t_quoted_string != nil)
369+
MCCStringFree(t_quoted_string);
370+
}
371+
372+
char *t_script;
373+
t_script = nil;
374+
375+
if (t_success)
376+
{
377+
char *t_locals_str = t_locals ? t_locals : "";
378+
char *t_assigns_str = t_assigns ? t_assigns : "";
379+
t_success = MCCStringFormat(t_script, MCSCRIPT_CALLBACK, p_id, p_window_id, t_locals_str, t_assigns_str, p_message, t_locals_str);
380+
}
381+
if (t_locals)
382+
MCCStringFree(t_locals);
383+
if (t_assigns)
384+
MCCStringFree(t_assigns);
385+
386+
if (t_success)
387+
r_script = t_script;
388+
else
389+
{
390+
if (t_script)
391+
MCCStringFree(t_script);
392+
}
393+
394+
return t_success;
395+
}
396+
397+
bool BrowserInstances::Callback(int p_id, const char *p_message, char **p_args, uint32_t p_arg_count, bool &r_pass)
398+
{
399+
bool t_success;
400+
t_success = true;
401+
402+
BrowserInstance *t_instance;
403+
if (t_success)
404+
t_success = FindInstanceById(p_id, t_instance);
405+
406+
if (t_success)
407+
{
408+
int t_retval;
409+
if (t_instance -> stack_id != NULL)
410+
SetGlobal("XBrowservar", t_instance -> stack_id, &t_retval);
411+
else
412+
SetGlobal("XBrowservar", "", &t_retval);
413+
}
414+
415+
char *t_script;
416+
t_script = nil;
417+
418+
if (t_success)
419+
t_success = revBrowserCreateCallbackScript(p_id, t_instance->browser->GetWindowId(), p_message, p_args, p_arg_count, t_script);
420+
421+
bool t_pass;
422+
if (t_success)
423+
SendMessage(t_instance, t_script, t_pass);
424+
425+
if (t_script)
426+
MCCStringFree(t_script);
427+
428+
if (t_success)
429+
r_pass = t_pass;
430+
431+
return t_success;
432+
}
433+
434+
void BrowserInstances::SendMessage(BrowserInstance *p_instance, const char *p_message, bool &r_pass)
435+
{
436+
int t_retval;
437+
SetGlobal(p_instance->xbrowser_callbacks ? "XBrowserCancel" : "browserCancel", "FALSE", &t_retval);
438+
439+
p_instance -> callback_depth += 1;
440+
SendCardMessage(p_message, &t_retval);
441+
p_instance -> callback_depth -= 1;
260442

261-
return 0;
443+
if (p_instance -> stack_id != NULL)
444+
free(p_instance -> stack_id);
445+
446+
p_instance -> stack_id = GetGlobal("XBrowservar", &t_retval);
447+
448+
bool t_pass;
449+
450+
char *t_cancel;
451+
t_cancel = GetGlobal(p_instance -> xbrowser_callbacks ? "XBrowserCancel" : "browserCancel", &t_retval);
452+
if (t_cancel != NULL)
453+
{
454+
t_pass = !StrToBool(t_cancel);
455+
free(t_cancel);
456+
}
457+
else
458+
t_pass = true;
459+
460+
r_pass = t_pass;
262461
}
263462

264463
bool BrowserInstances::Callback(int p_id, const char *p_message, const char *p_argument)
@@ -301,11 +500,7 @@ end if;\
301500
send \"browser%s\" && %d, quote & \"%s\" & quote to this card of XBrowservar";
302501

303502
BrowserInstance *t_instance;
304-
for(t_instance = m_instances; t_instance != NULL; t_instance = t_instance -> next)
305-
if (t_instance -> instance_id == p_id)
306-
break;
307-
308-
if (t_instance == NULL)
503+
if (!FindInstanceById(p_id, t_instance))
309504
return true;
310505

311506
int t_retval;
@@ -436,6 +631,15 @@ BrowserProp browserProperties[] =
436631
// CALLBACKS
437632
//
438633

634+
// IM-2014-03-06: [[ revBrowserCEF ]] Send a custom callback with the given params
635+
void CB_Custom(int p_instance_id, const char *p_message, char **p_args, uint32_t p_arg_count, bool *r_cancel)
636+
{
637+
bool t_success, t_pass;
638+
t_success = s_browsers.Callback(p_instance_id, p_message, p_args, p_arg_count, t_pass);
639+
640+
*r_cancel = t_success && !t_pass;
641+
}
642+
439643
// Callback:
440644
// XBrowser_BeforeNavigate pURL
441645
// Description:
@@ -808,7 +1012,7 @@ void revBrowserExecuteScript(CWebBrowserBase *p_instance, char *args[], int narg
8081012
t_result = t_browser -> ExecuteScript(args[0]);
8091013
if (t_result == NULL)
8101014
{
811-
*retstring = "error in script";
1015+
*retstring = strdup("error in script");
8121016
*error = True;
8131017
}
8141018
else
@@ -1108,6 +1312,61 @@ void revBrowserSnapshot(CWebBrowserBase *p_instance, char *args[], int nargs, ch
11081312
*retstring = result != NULL ? result: (char *)calloc(1,0);
11091313
}
11101314

1315+
// IM-2014-03-06: [[ revBrowserCEF ]] Allows a LiveCode handler to be called from within JavaScript
1316+
// creates a JS function with the same name as the handler within a global liveCode JS object
1317+
void revBrowserAddJavaScriptHandler(CWebBrowserBase *p_instance, char *p_args[], int p_arg_count, char **r_result, Bool *r_pass, Bool *r_error)
1318+
{
1319+
char *result = NULL;
1320+
1321+
bool t_success;
1322+
t_success = true;
1323+
1324+
// We must be given 1 argument. The argument is the handler name to add.
1325+
if (t_success)
1326+
{
1327+
if (p_arg_count != 1)
1328+
{
1329+
/* UNCHECKED */ MCCStringClone("incorrect number of arguments", *r_result);
1330+
t_success = false;
1331+
}
1332+
}
1333+
1334+
if (t_success)
1335+
p_instance->AddJavaScriptHandler(p_args[0]);
1336+
1337+
*r_error = !t_success;
1338+
*r_pass = False;
1339+
if (*r_result == nil)
1340+
/* UNCHECKED */ MCCStringClone("", *r_result);
1341+
}
1342+
1343+
// IM-2014-03-06: [[ revBrowserCEF ]] Removes the named handler function from the global liveCode JS object
1344+
void revBrowserRemoveJavaScriptHandler(CWebBrowserBase *p_instance, char *p_args[], int p_arg_count, char **r_result, Bool *r_pass, Bool *r_error)
1345+
{
1346+
char *result = NULL;
1347+
1348+
bool t_success;
1349+
t_success = true;
1350+
1351+
// We must be given 1 argument. The argument is the handler name to add.
1352+
if (t_success)
1353+
{
1354+
if (p_arg_count != 1)
1355+
{
1356+
/* UNCHECKED */ MCCStringClone("incorrect number of arguments", *r_result);
1357+
t_success = false;
1358+
}
1359+
}
1360+
1361+
if (t_success)
1362+
p_instance->RemoveJavaScriptHandler(p_args[0]);
1363+
1364+
*r_error = !t_success;
1365+
*r_pass = False;
1366+
if (*r_result == nil)
1367+
/* UNCHECKED */ MCCStringClone("", *r_result);
1368+
}
1369+
11111370
// Function:
11121371
// revBrowserGet(pInstanceId, pProperty)
11131372
// Description:
@@ -1254,7 +1513,7 @@ void revBrowserGetProp(CWebBrowserBase *p_instance, char *args[], int nargs, cha
12541513
break;
12551514
}
12561515

1257-
*retstring = result != NULL ? result: (char *)calloc(1,0);
1516+
*retstring = result != NULL ? result: (char *)calloc(1,1);
12581517
}
12591518

12601519
// Property:
@@ -1423,7 +1682,7 @@ void revBrowserSetProp(CWebBrowserBase *p_instance, char *args[], int nargs, cha
14231682
break;
14241683

14251684
case BROWSERPROP_HSCROLL:
1426-
t_browser -> SetHScroll(atof(args[1]));
1685+
t_browser -> SetHScroll(atoi(args[1]));
14271686
break;
14281687

14291688
case BROWSERPROP_WINDOWID:
@@ -1634,6 +1893,8 @@ EXTERNAL_BEGIN_DECLARATIONS("revBrowser")
16341893
EXTERNAL_DECLARE_COMMAND_OBJC("revBrowserSnapshot", revBrowserWrapper<revBrowserSnapshot>)
16351894
EXTERNAL_DECLARE_COMMAND_OBJC("revBrowserFind", revBrowserWrapper<revBrowserFind>)
16361895
EXTERNAL_DECLARE_FUNCTION_OBJC("revBrowserCallScript", revBrowserWrapper<revBrowserCallScript>)
1896+
EXTERNAL_DECLARE_COMMAND_OBJC("revBrowserAddJavaScriptHandler", revBrowserWrapper<revBrowserAddJavaScriptHandler>)
1897+
EXTERNAL_DECLARE_COMMAND_OBJC("revBrowserRemoveJavaScriptHandler", revBrowserWrapper<revBrowserRemoveJavaScriptHandler>)
16371898
EXTERNAL_DECLARE_COMMAND_OBJC("XBrowser_Open", XBrowserOpen)
16381899
EXTERNAL_DECLARE_COMMAND_OBJC("XBrowser_Close", XBrowserWrapper<revBrowserClose> )
16391900
EXTERNAL_DECLARE_COMMAND_OBJC("XBrowser_Stop", XBrowserWrapper<revBrowserStop> )

0 commit comments

Comments
 (0)