@@ -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
129133static 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+
155173void BrowserInstances::Add (CWebBrowserBase *p_browser, bool p_is_xbrowser)
156174{
157175 BrowserInstance *t_instance;
@@ -217,18 +235,18 @@ CWebBrowserBase *BrowserInstances::GetActiveInstance(void)
217235
218236CWebBrowserBase *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
227245void 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
234252char *BrowserInstances::GetInstanceIds (void )
@@ -251,14 +269,195 @@ char *BrowserInstances::GetInstanceIds(void)
251269int 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" : " "e" );
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
264463bool BrowserInstances::Callback (int p_id, const char *p_message, const char *p_argument)
@@ -301,11 +500,7 @@ end if;\
301500send \" 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