-
Notifications
You must be signed in to change notification settings - Fork 590
/
tagui_header.js
executable file
·1924 lines (1708 loc) · 143 KB
/
tagui_header.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Q1. Why is formatting for this file so messed up? - it's created on the road
// If you want to know more - https://github.com/kelaberetiv/TagUI/issues/490
// Q2. Is there a beautified version for easier viewing or editing?
// Use this to view pretty version - https://prettier.io/playground
// xpath for object identification
var xps666 = require('casper').selectXPath;
// assign parameters to p1-p8 variables
var p1 = casper.cli.raw.get(0); var p2 = casper.cli.raw.get(1); var p3 = casper.cli.raw.get(2);
var p4 = casper.cli.raw.get(3); var p5 = casper.cli.raw.get(4); var p6 = casper.cli.raw.get(5);
var p7 = casper.cli.raw.get(6); var p8 = casper.cli.raw.get(7); // p9 (${10}) is less portable
// default p1-p8 to blank instead of undefined
if (!p1) p1 = ''; if (!p2) p2 = ''; if (!p3) p3 = ''; if (!p4) p4 = '';
if (!p5) p5 = ''; if (!p6) p6 = ''; if (!p7) p7 = ''; if (!p8) p8 = '';
// save start time to measure execution time
var automation_start_time = Date.now(); casper.echo('\nSTART - automation started - ' + Date().toLocaleString());
// initialise time for timer() function
var timer_start_time = Date.now();
// infinity constant for use in for loops
var infinity = 1024;
// initialise default global variables
var quiet_mode = false; var save_text_count = 0; var snap_image_count = 0;
// counters for tracking messages in r, python, sikuli, chrome integrations
var r_count = 0; var py_count = 0; var sikuli_count = 0; var chrome_id = 0;
// chrome context for frame handling and targetid for popup handling
var chrome_context = 'document'; var chrome_targetid = '';
// to track download path if set by user using 'download to location' step
var download_path = '';
// variables to track frame offset if current context is within a frame
var frame_step_offset_x = 0; var frame_step_offset_y = 0;
var original_frame_step_offset_x = 0; var original_frame_step_offset_y = 0;
// variable for ask step to accept user input
var ask_result = '';
// JSON variable to pass variables into browser DOM
var dom_json = {}; var dom_result = '';
// variable for user OS with values windows, mac, linux
var user_system = require('system').os.name;
// telegram step api endpoint, you can host on your own server or cloud
// see https://github.com/kelaberetiv/TagUI/tree/master/src/telegram
var telegram_endpoint = 'https://tebel.org/taguibot';
// variable for advance usage of api step
var api_config = {method:'GET', header:[], body:{}};
// variables for api and run steps execution result
var api_result = ''; var api_json = {}; var run_result = ''; var run_json = {};
// variables for R and Python integration execution result
var r_result = ''; var r_json = {}; var py_result = ''; var py_json = {};
// variables for Excel integration execution result
var excel_result = ''; var excel_json = {}; var excel_files = [];
var excel_focus = false; var excel_visible = true;
var excel_password = '';
// variables for Word integraton execution result
var word_result = ''; var word_json = {};
// variables for PDF integraton execution result
var pdf_result = ''; var pdf_json = {};
// track begin-finish blocks for integrations eg - py, r, run, vision, js, dom
var inside_py_block = 0; var inside_r_block = 0; var inside_run_block = 0;
var inside_vision_block = 0; var inside_js_block = 0; var inside_dom_block = 0;
// determine how many casper.then steps to skip
function teleport_distance(teleport_marker) {number_to_hop = 0;
if (teleport_marker.indexOf('[BREAK_SIGNAL]') > -1) {for (s = casper.steps.length-1; s >= 0; s--) {
if (casper.steps[s].toString() == ("function () {for_loop_signal = '"+teleport_marker+"';}"))
{number_to_hop = s; break;}};} // search backward direction for break step
else if (teleport_marker.indexOf('[CONTINUE_SIGNAL]') > -1) {for (s = casper.step; s <= casper.steps.length-1; s++) {
if (casper.steps[s].toString() == ("function () {for_loop_signal = '"+teleport_marker+"';}"))
{number_to_hop = s; break;}}; // search forward direction for continue step
if (number_to_hop == 0) {for (s = casper.steps.length-1; s >= 0; s--) {if (casper.steps[s].toString() ==
("function () {for_loop_signal = '"+teleport_marker.replace('[CONTINUE_SIGNAL]','[BREAK_SIGNAL]')+"';}"))
{number_to_hop = s; break;}};}} // handle as break if no step left to continue
else return 0; if ((number_to_hop - casper.step) > 0) return (number_to_hop - casper.step); else return 0;}
// techo function for handling quiet option
function techo(echo_string) {if (!quiet_mode) { // mute about:blank, eg for desktop automation
if ((echo_string == 'about:blank - \n') || (echo_string == '\nabout:blank - ')) casper.echo('');
else if (tagui_language.toLowerCase() == 'english') casper.echo(echo_string);
else {var translated_string = translate(echo_string,'to',tagui_language.toLowerCase()); casper.echo(translated_string);
if (translated_string.indexOf('ERROR - translation engine') !== -1) casper.exit();}} return;}
// for muting echo in test automation scripts
function dummy_echo(muted_string) {return;}
// for saving text information to file
function save_text(file_name,info_text) {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
if (!file_name) {save_text_count++; file_name = flow_path + ds + 'text' + save_text_count.toString() + '.txt';}
var fs = require('fs'); fs.write(file_name, info_text + '\r\n', 'w');}
// for appending text information to file
function append_text(file_name,info_text) {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
if (!file_name) {if (save_text_count==0) save_text_count++; // increment if 0, else use same count to append
file_name = flow_path + ds + 'text' + save_text_count.toString() + '.txt';}
var fs = require('fs'); fs.write(file_name, info_text + '\r\n', 'a');}
// for saving snapshots of website to file
function snap_image() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
snap_image_count++; return (flow_path + ds + 'snap' + snap_image_count.toString() + '.png');}
// for saving table from website to file
function save_table(file_name,selector) {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
if (!file_name) {save_text_count++; file_name = flow_path + ds + 'table' + save_text_count.toString() + '.csv';}
var row_data = ""; var table_cell = ""; var fs = require('fs'); fs.write(file_name, '', 'w'); // always reset file
if (!casper.exists(selector) || (selector.toString().indexOf('xpath selector: ')==-1)) return false; // exit if invalid
if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16); // get xpath
for (table_row=1; table_row<=1024; table_row++) {row_data = ""; for (table_col=1; table_col<=1024; table_col++) {
table_cell = '(((' + selector + '//tr)[' + table_row + ']//th)' + '|'; // build cell xpath selector to include
table_cell += '((' + selector + '//tr)[' + table_row + ']//td))[' + table_col + ']'; // both th and td elements
if (casper.exists(xps666(table_cell))) row_data = row_data + '","' + casper.fetchText(xps666(table_cell)).trim();
else break;} // if searching for table cells (th and td) is not successful, means end of row is reached
if (row_data.substr(0,2) == '",') {row_data = row_data.substr(2); row_data += '"'; append_text(file_name,row_data);}
else return true;}} // if '",' is not found, means end of table is reached as there is no cell found in row
function windows_path(input_path) { // for converting file path to windows standard for excel integration
if (!input_path || input_path == '') return ''; // replace / and \\ characters to be \ character
input_path = input_path.replace(/\//g,'\\'); return input_path.replace(/\\\\/,'\\');}
function excel_range_to_size(input_range) { // for converting excel range to array size
if (!input_range || input_range == '') return [0,0]; else if (input_range.indexOf(':') == -1) return [1,1];
var range_start = input_range.split(':')[0].trim(); var range_end = input_range.split(':')[1].trim();
var row_start = range_start.match(/\d+/g); var row_end = range_end.match(/\d+/g);
var col_start = range_start.match(/[a-zA-Z]+/g); var col_end = range_end.match(/[a-zA-Z]+/g);
// use special number 1234567 to mark column and row selection, since excel max rows is 1048576 and max cols is 16384
if (row_start == null && row_end == null) return [1,1234567];
else if (col_start == null && col_end == null) return [1234567,1];
var height = parseInt(row_end) - parseInt(row_start) + 1;
col_start = col_start.toString().toUpperCase(); var col_start_count = 0; var col_start_len = col_start.length;
for (cs_pos = 0; cs_pos < col_start_len; cs_pos++) {
col_start_count += (col_start.charCodeAt(cs_pos) - 64) * Math.pow(26, col_start_len - cs_pos - 1);}
col_end = col_end.toString().toUpperCase(); var col_end_count = 0; var col_end_len = col_end.length;
for (ce_pos = 0; ce_pos < col_end_len; ce_pos++) {
col_end_count += (col_end.charCodeAt(ce_pos) - 64) * Math.pow(26, col_end_len - ce_pos - 1);}
var width = col_end_count - col_start_count + 1; return [width,height];}
function read_excel(input_excel) { // for reading from excel target
if (user_system == 'windows') {
var workbook_file = input_excel.split(']')[0].slice(1).trim(); input_excel = input_excel.split(']')[1];
var sheet_name = input_excel.split('!')[0].trim(); var cell_range = input_excel.split('!')[1].trim();
workbook_file = abs_file(workbook_file); if (excel_files.indexOf(workbook_file) == -1) excel_files.push(workbook_file);
var fs = require('fs'); if (!fs.exists(workbook_file))
casper.echo('ERROR - cannot find Excel file ' + workbook_file).exit();
var excel_password_code = ''; if (excel_password != '')
excel_password_code = ',,,,"' + excel_password.replace(/\"/g, '\\"') + '"';
var excel_visible_code = 'objExcel.Visible = True'; if (!excel_visible) excel_visible_code = 'objExcel.Visible = False';
var excel_focus_code = ''; if (excel_focus) excel_focus_code = '' +
'CreateObject("WScript.Shell").AppActivate Left(objWorkbook.Name, InStr(objWorkbook.Name, ".") - 1) & " - Excel"\r\n\r\n';
var excel_steps = 'Dim excelFilename, excelSheet\r\nexcelFilename = "' + windows_path(workbook_file) +
'"\r\n\r\n' + 'On Error Resume Next\r\nSet objExcel = GetObject(, "Excel.Application")\r\n' +
'If Err.Number <> 0 Then\r\n\tSet objExcel = CreateObject("Excel.Application")\r\n' +
'End If\r\nOn Error Goto 0\r\n\r\n' + 'Set objWorkbook = objExcel.Workbooks.Open(excelFilename' +
excel_password_code + ')\r\n' + excel_visible_code + '\r\n\r\n' + excel_focus_code +
'excelSheet = "' + sheet_name + '"\r\nOn Error Resume Next\r\nSet targetSheet = Nothing\r\n' +
'Set targetSheet = objWorkbook.Sheets(excelSheet)\r\nOn Error GoTo 0\r\nIf targetSheet Is Nothing Then\r\n\t' +
'WScript.Echo "ERROR - cannot find Excel sheet " & excelSheet\r\nElse\r\n\tobjWorkbook.Sheets(excelSheet).Activate\r\n\t' +
'Dim arrayData, arrayString, rowCount, colCount\r\n\t' +
'rowCount = objWorkbook.Sheets(excelSheet).Range("' +
cell_range + ' " & objWorkbook.Sheets(excelSheet).UsedRange.Address).Rows.Count\r\n\t' +
'colCount = objWorkbook.Sheets(excelSheet).Range("' +
cell_range + ' " & objWorkbook.Sheets(excelSheet).UsedRange.Address).Columns.Count\r\n\t' +
'arrayData = objWorkbook.Sheets(excelSheet).Range("' +
cell_range + ' " & objWorkbook.Sheets(excelSheet).UsedRange.Address).Value\r\n\t' +
'arrayString = ""\r\n\tIf IsArray(arrayData) Then\r\n\t\t' +
'Dim arrayRow, arrayCol\r\n\t\tFor arrayRow = 1 To UBound(arrayData, 1)\r\n\t\t\t' +
'For arrayCol = 1 to UBound(arrayData, 2)\r\n\t\t\t\tarrayString = arrayString & arrayData(arrayRow, arrayCol) & "[EXCEL_DELIMITER]"' +
'\r\n\t\t\tNext\r\n\t\tNext\r\n\t\tarrayString = arrayString & rowCount & "[EXCEL_DELIMITER]" & colCount' +
'\r\n\tElse\r\n\t\tarrayString = arrayData & "[EXCEL_DELIMITER]1[EXCEL_DELIMITER]1"\r\n\tEnd If\r\n\t' +
'WScript.Echo arrayString\r\nEnd If\r\n'; save_text('excel_steps.vbs', excel_steps);
casper.waitForExec('cscript excel_steps.vbs //NoLogo', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
if (excel_result.indexOf('ERROR - cannot find Excel sheet') !== -1) casper.echo(excel_result).exit();
var range_size = excel_range_to_size(cell_range); if (range_size[0] > 1 || range_size[1] > 1)
{excel_result += ' '; excel_result = excel_result.split('[EXCEL_DELIMITER]'); var excel_array = [];
excel_result[excel_result.length - 1] = excel_result[excel_result.length - 1].slice(0, -1);
// special handling with number 1234567 for column and row selection
if (range_size[0] == 1234567) {range_size[0] = excel_result.pop(); range_size[1] = excel_result.pop();}
else if (range_size[1] == 1234567) {range_size[0] = excel_result.pop(); range_size[1] = excel_result.pop();}
else {excel_result.pop(); excel_result.pop();} // remove row and column count data from excel_result
for (row = 0; row < range_size[1]; row++) {excel_array.push(excel_result.splice(0, range_size[0]));}
for (row = 0; row < range_size[1]; row++) for (col = 0; col < range_size[0]; col++) {
if (excel_array[row][col] && !isNaN(excel_array[row][col]) && (Number(excel_array[row][col]).toString() == excel_array[row][col])) excel_array[row][col] = Number(excel_array[row][col]);}
excel_result = excel_array;} else {excel_result = excel_result.split('[EXCEL_DELIMITER]')[0];
if (excel_result && !isNaN(excel_result) && (Number(excel_result).toString() == excel_result)) excel_result = Number(excel_result);}
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else if (user_system == 'mac') {
var workbook_file = input_excel.split(']')[0].slice(1).trim(); input_excel = input_excel.split(']')[1];
var sheet_name = input_excel.split('!')[0].trim(); var cell_range = input_excel.split('!')[1].trim();
workbook_file = abs_file(workbook_file); if (excel_files.indexOf(workbook_file) == -1) excel_files.push(workbook_file);
var fs = require('fs'); if (!fs.exists(workbook_file))
casper.echo('ERROR - cannot find Excel file ' + workbook_file).exit();
var excel_password_code = ''; if (excel_password != '')
excel_password_code = ' password "' + excel_password.replace(/\"/g, '\\"') + '"';
var column_range = cell_range; if (column_range.indexOf(':') == -1) column_range = cell_range + ':' + cell_range;
var excel_visible_code = 'tell application "System Events"\r\n\t\t' +
'set excel_process to first process whose name is "Microsoft Excel"\r\n\t\t' +
'set visible of excel_process to ' + excel_visible.toString() + '\r\n\tend tell\r\n\t';
var excel_focus_code = ''; if (excel_focus) excel_focus_code = 'activate\r\n\t';
var excel_steps = 'tell application "Microsoft Excel"\r\n\t' + excel_focus_code +
'open workbook workbook file name POSIX file "' + workbook_file +
'"' + excel_password_code + '\r\n\t' + excel_visible_code +
'if not exists sheet "' + sheet_name + '" then\r\n\t\t' +
'do shell script "echo ERROR - cannot find Excel sheet ' + sheet_name + '"\r\n\telse\r\n\t\t' +
'select worksheet "' + sheet_name + '"\r\n\t\t' +
'tell range "' + column_range + '" of active sheet\r\n\t\t\t' +
'repeat with i from 1 to (count columns)\r\n\t\t\t\t' +
'autofit column i\r\n\t\t\t' +
'end repeat\r\n\t\t' +
'end tell\r\n\t\t' +
'set row_count to count of rows of range ("' + cell_range + ' " & get address of used range of active sheet)\r\n\t\t' +
'set col_count to count of columns of range ("' + cell_range + ' " & get address of used range of active sheet)\r\n\t\t' +
'set list_data to {} & string value of range ("' + cell_range + ' " & get address of used range of active sheet) ' +
'& row_count & col_count\r\n\tend if\r\nend tell\r\n' + 'set text item delimiters to "[EXCEL_DELIMITER]"\r\n' +
'get list_data as text'; save_text('excel_steps.scpt', excel_steps);
casper.waitForExec('osascript excel_steps.scpt', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
if (excel_result.indexOf('ERROR - cannot find Excel sheet') !== -1) casper.echo(excel_result).exit();
var range_size = excel_range_to_size(cell_range); if (range_size[0] > 1 || range_size[1] > 1)
{excel_result += ' '; excel_result = excel_result.split('[EXCEL_DELIMITER]'); var excel_array = [];
excel_result[excel_result.length - 1] = excel_result[excel_result.length - 1].slice(0, -1);
// special handling with number 1234567 for column and row selection
if (range_size[0] == 1234567) {range_size[0] = excel_result.pop(); range_size[1] = excel_result.pop();}
else if (range_size[1] == 1234567) {range_size[0] = excel_result.pop(); range_size[1] = excel_result.pop();}
else {excel_result.pop(); excel_result.pop();} // remove row and column count data from excel_result
for (row = 0; row < range_size[1]; row++) {excel_array.push(excel_result.splice(0, range_size[0]));}
for (row = 0; row < range_size[1]; row++) for (col = 0; col < range_size[0]; col++) {
if (excel_array[row][col] && !isNaN(excel_array[row][col]) && (Number(excel_array[row][col]).toString() == excel_array[row][col])) excel_array[row][col] = Number(excel_array[row][col]);}
excel_result = excel_array;} else {excel_result = excel_result.split('[EXCEL_DELIMITER]')[0];
if (excel_result && !isNaN(excel_result) && (Number(excel_result).toString() == excel_result)) excel_result = Number(excel_result);}
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else casper.echo('ERROR - unsupported operating system ' + user_system).exit();}
function size_to_excel_range(cell, width, height) { // for converting array to range
var row_start = parseInt(cell.match(/\d+/g)); var row_end = row_start + height - 1;
var col_start = cell.match(/[a-zA-Z]+/g)[0].toUpperCase(); var col_end = col_start;
var first_char = ''; var mid_char = ''; var last_char = '';
if (col_end.length == 1) {first_char = '-'; mid_char = '-'; last_char = col_end;}
else if (col_end.length == 2) {first_char = '-'; mid_char = col_end[0]; last_char = col_end[1];}
else {first_char = col_end[0]; mid_char = col_end[1]; last_char = col_end[2];}
for (count = 0; count < width - 1; count++) {
last_char = String.fromCharCode(last_char.charCodeAt() + 1); if (last_char != '[') continue; else last_char = 'A';
if (mid_char == '-') {mid_char = 'A'; continue;}
else {mid_char = String.fromCharCode(mid_char.charCodeAt() + 1); if (mid_char != '[') continue; else mid_char = 'A';
if (first_char == '-') {first_char = 'A'; continue;}
else first_char = String.fromCharCode(first_char.charCodeAt() + 1);}}
col_end = first_char + mid_char + last_char; col_end = col_end.replace(/-/g,'');
return cell + ':' + col_end + row_end.toString();}
function write_excel(output_excel) { // for writing to excel target
if (user_system == 'windows') {
var workbook_file = output_excel.split(']')[0].slice(1).trim(); output_excel = output_excel.split(']')[1];
var sheet_name = output_excel.split('!')[0].trim(); var cell_range = output_excel.split('!')[1].trim();
cell_range = cell_range.split(':')[0]; // truncate to get starting cell to write various data types
if (!Array.isArray(excel_result)) {
excel_result = 'objWorkbook.Sheets(excelSheet).Range("' + cell_range + '").Value = "' + excel_result + '"\r\n';}
else {var range_size = [excel_result[0].length, excel_result.length];
cell_range = size_to_excel_range(cell_range, range_size[0], range_size[1]);
var array_result = 'Dim arrayData(' + (range_size[1] - 1).toString() + ', ' + (range_size[0] - 1).toString() + ')\r\n';
for (row = 0; row < range_size[1]; row++) {for (col = 0; col < range_size[0]; col++) {
var value = "";
if (typeof excel_result[row][col] !== 'undefined') value = excel_result[row][col].toString();
array_result = array_result +
'arrayData(' + row.toString() + ', ' + col.toString() + ') = "' + value + '"\r\n';}}
array_result += 'objWorkbook.Sheets(excelSheet).Range("' + cell_range + '").Value = arrayData\r\n';
excel_result = array_result;}
workbook_file = abs_file(workbook_file); if (excel_files.indexOf(workbook_file) == -1) excel_files.push(workbook_file);
var excel_password_code = ''; if (excel_password != '')
excel_password_code = ',,,,"' + excel_password.replace(/\"/g, '\\"') + '"';
var excel_visible_code = 'objExcel.Visible = True'; if (!excel_visible) excel_visible_code = 'objExcel.Visible = False';
var excel_focus_code = ''; if (excel_focus) excel_focus_code = '' +
'CreateObject("WScript.Shell").AppActivate Left(objWorkbook.Name, InStr(objWorkbook.Name, ".") - 1) & " - Excel"\r\n\r\n';
var excel_steps = ''; var excel_new_file = ''; var fs = require('fs'); if (!fs.exists(workbook_file))
excel_new_file = 'Set objWorkbook = objExcel.Workbooks.Add\r\nobjWorkbook.SaveAs excelFilename\r\n';
excel_steps = 'Dim excelFilename, excelSheet\r\nexcelFilename = "' + windows_path(workbook_file) +
'"\r\n\r\n' + 'On Error Resume Next\r\nSet objExcel = GetObject(, "Excel.Application")\r\n' +
'If Err.Number <> 0 Then\r\n\tSet objExcel = CreateObject("Excel.Application")\r\n' +
'End If\r\nOn Error Goto 0\r\n\r\n' + excel_new_file +
'Set objWorkbook = objExcel.Workbooks.Open(excelFilename' +
excel_password_code + ')\r\n' + excel_visible_code + '\r\n\r\n' + excel_focus_code +
'excelSheet = "' + sheet_name + '"\r\nOn Error Resume Next\r\nSet targetSheet = Nothing\r\n' +
'Set targetSheet = objWorkbook.Sheets(excelSheet)\r\nOn Error GoTo 0\r\nIf targetSheet Is Nothing Then\r\n\t' +
'objWorkbook.Sheets.Add.Name = excelSheet\r\nEnd If\r\nobjWorkbook.Sheets(excelSheet).Activate\r\n\r\n' + excel_result;
save_text('excel_steps.vbs', excel_steps);
casper.waitForExec('cscript excel_steps.vbs //NoLogo', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else if (user_system == 'mac') {
var workbook_file = output_excel.split(']')[0].slice(1).trim(); output_excel = output_excel.split(']')[1];
var sheet_name = output_excel.split('!')[0].trim(); var cell_range = output_excel.split('!')[1].trim();
cell_range = cell_range.split(':')[0]; // truncate to get starting cell to write various data types
excel_result = JSON.stringify(excel_result).replace(/\[/g,'{').replace(/\]/g,'}')
if (excel_result.charAt(0) == '{' && excel_result.charAt(excel_result.length - 1) == '}')
{var data = JSON.parse(excel_result.replace(/{/g,'[').replace(/}/g,']'));
cell_range = size_to_excel_range(cell_range, data[0].length, data.length);}
workbook_file = abs_file(workbook_file); if (excel_files.indexOf(workbook_file) == -1) excel_files.push(workbook_file);
var excel_password_code = ''; if (excel_password != '')
excel_password_code = ' password "' + excel_password.replace(/\"/g, '\\"') + '"';
var excel_visible_code = 'tell application "System Events"\r\n\t\t' +
'set excel_process to first process whose name is "Microsoft Excel"\r\n\t\t' +
'set visible of excel_process to ' + excel_visible.toString() + '\r\n\tend tell\r\n\t';
var excel_focus_code = ''; if (excel_focus) excel_focus_code = 'activate\r\n\t';
var excel_steps = ''; var fs = require('fs'); if (!fs.exists(workbook_file))
excel_steps = 'tell application "Microsoft Excel"\r\n\t' + excel_focus_code + 'set myWorkbook to make new workbook\r\n\t' +
'save workbook as myWorkbook filename POSIX file "' + workbook_file + '"\r\n\t' + 'end tell\r\n\r\n';
excel_steps += 'tell application "Microsoft Excel"\r\n\t' + excel_focus_code +
'open workbook workbook file name POSIX file "' + workbook_file +
'"' + excel_password_code + '\r\n\t' + excel_visible_code +
'if not exists sheet "' + sheet_name + '" then\r\n\t\t' +
'make new worksheet at end of active workbook with properties {name:"' + sheet_name + '"}\r\n\tend if\r\n\t' +
'select worksheet "' + sheet_name + '"\r\n\t' + 'set value of range "' + cell_range + '" to ' + excel_result + '\r\n' +
'end tell'; save_text('excel_steps.scpt', excel_steps);
casper.waitForExec('osascript excel_steps.scpt', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else casper.echo('ERROR - unsupported operating system ' + user_system).exit();}
// for excel statements - retrieving data for variable on right side of = sign
// broken into 2 functions for excel_result to be usable with CasperJS structure
function excel_retrieve(right_param) { // check OS before starting Excel automation
if (user_system != 'windows' && user_system != 'mac') {excel_result = '';
casper.echo('ERROR - Excel automation only for Windows and Mac').exit();}
if (right_param.match(/\[.*\.(xl.|xl..|xml|csv)\].*![A-Z0-9]*/i) == null)
{excel_result = ''; if (isNaN(right_param)) excel_result = eval(right_param);
else excel_result = right_param;}
else if (excel_result == '[LIVE_MODE]') {excel_result = '';
casper.echo('ERROR - reading from Excel not supported in live mode');}
else {excel_result = ''; read_excel(right_param);}}
// for excel statements - assigning data to variable on left side of = sign
// broken into 2 functions for excel_result to be usable with CasperJS structure
function excel_assign(left_param) {if (left_param.match(/\[.*\.(xl.|xl..|xml|csv)\].*![A-Z0-9]*/i) == null)
eval(left_param + ' = excel_result'); else write_excel(left_param);}
function excel_close() { // for closing excel files opened by TagUI
if (user_system == 'windows') {
var excel_focus_code = ''; if (excel_focus) excel_focus_code = '' +
'CreateObject("WScript.Shell").AppActivate Left(objWorkbook.Name, InStr(objWorkbook.Name, ".") - 1) & " - Excel"\r\n\t\t\t';
var excel_steps = 'Dim excelFilename\r\n'; excel_files.forEach(function(workbook_file) {
excel_steps += 'excelFilename = "' + windows_path(workbook_file) + '"\r\n' + 'On Error Resume Next\r\n' +
'Set objExcel = GetObject(, "Excel.Application")\r\nIf Err.Number = 0 Then\r\n\t' +
'For Each objWorkbook In objExcel.Workbooks\r\n\t\t' +
'If excelFilename = objWorkbook.Path & "\\" & objWorkbook.Name Then\r\n\t\t\t' +
'Set objWorkbook = GetObject(excelFilename)\r\n\t\t\t' + excel_focus_code + 'objWorkbook.Close True\r\n\t\t\t' +
'Exit For\r\n\t\tEnd If\r\n\tNext\r\nEnd If\r\nOn Error Goto 0\r\n';});
save_text('excel_steps.vbs', excel_steps);
casper.waitForExec('cscript excel_steps.vbs //NoLogo', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else if (user_system == 'mac') {
var excel_focus_code = ''; if (excel_focus) excel_focus_code = 'activate\r\n\t';
var excel_steps = ''; excel_files.forEach(function(workbook_file) {
excel_steps += 'tell application "Microsoft Excel"\r\n\t' + excel_focus_code +
'open workbook workbook file name POSIX file "' + workbook_file + '"\r\n\t' +
'close active workbook with saving' + '\r\n' + 'end tell\r\n\r\n';});
save_text('excel_steps.scpt', excel_steps);
casper.waitForExec('osascript excel_steps.scpt', null, function(response) {excel_result = '';
excel_result = (response.data.stdout.trim() || response.data.stderr.trim());
excel_json = response.data;}, function() {this.echo('ERROR - Excel automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else casper.echo('ERROR - unsupported operating system ' + user_system).exit();}
function read_word(input_word) { // for reading from word target
if (user_system == 'windows') {
var word_file = input_word.split(']')[0].slice(1).trim();
word_file = abs_file(word_file); var fs = require('fs'); if (!fs.exists(word_file))
casper.echo('ERROR - cannot find Word file ' + word_file).exit();
var word_steps = 'Set WshShell = WScript.CreateObject("WScript.Shell")\r\n';
word_steps += 'WshShell.Run """' + windows_path(word_file) + '"""\r\nWScript.Sleep 5000\r\n';
word_steps += 'WshShell.SendKeys "^a"\r\nWScript.Sleep 1000\r\n';
word_steps += 'WshShell.SendKeys "^c"\r\nWScript.Sleep 1000\r\n';
word_steps += 'WshShell.SendKeys "%{F4}"\r\nSet objHTML = CreateObject("htmlfile")\r\n';
word_steps += 'WScript.Echo objHTML.ParentWindow.ClipboardData.GetData("text")'; save_text('word_steps.vbs', word_steps);
save_text('word_steps.cmd', '@echo off\r\ncscript word_steps.vbs //NoLogo > word_steps.out 2>&1');
casper.waitForExec('word_steps.cmd', null, function(response) {
word_result = ''; word_result = require('fs').read('word_steps.out').trim();
}, function() {this.echo('ERROR - Word automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else if (user_system == 'mac') {
var word_file = input_word.split(']')[0].slice(1).trim();
word_file = abs_file(word_file); var fs = require('fs'); if (!fs.exists(word_file))
casper.echo('ERROR - cannot find Word file ' + word_file).exit();
var word_steps = 'tell application "Finder" to open POSIX file "' + word_file + '"\r\n';
word_steps += 'delay 5\r\ntell application "System Events"\r\n\t';
word_steps += 'keystroke "a" using {command down}\r\n\tdelay 1\r\n\t';
word_steps += 'keystroke "c" using {command down}\r\n\tdelay 1\r\n\t';
word_steps += 'keystroke "q" using {command down}\r\nend tell\r\n';
word_steps += 'do shell script "pbpaste > word_steps.out 2>&1"'; save_text('word_steps.scpt', word_steps);
casper.waitForExec('osascript word_steps.scpt', null, function(response) {
word_result = ''; word_result = require('fs').read('word_steps.out').trim();
}, function() {this.echo('ERROR - Word automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else casper.echo('ERROR - unsupported operating system ' + user_system).exit();}
function write_word(output_word) { // for writing to word target
casper.echo('ERROR - writing to Word file not supported').exit();}
// for word statements - retrieving data for variable on right side of = sign
// broken into 2 functions for word_result to be usable with CasperJS structure
function word_retrieve(right_param) { // check OS before starting Word automation
if (user_system != 'windows' && user_system != 'mac') {word_result = '';
casper.echo('ERROR - Word automation only for Windows and Mac').exit();}
if (right_param.match(/\[.*\.(doc|docx|docm|dot|dotx)\]/i) == null)
{word_result = ''; word_result = eval(right_param);}
else if (word_result == '[LIVE_MODE]') {word_result = '';
casper.echo('ERROR - reading from Word not supported in live mode');}
else {word_result = ''; read_word(right_param);}}
// for word statements - assigning data to variable on left side of = sign
// broken into 2 functions for word_result to be usable with CasperJS structure
function word_assign(left_param) {if (left_param.match(/\[.*\.(doc|docx|docm|dot|dotx)\]/i) == null)
eval(left_param + ' = word_result'); else write_word(left_param);}
function read_pdf(input_pdf) { // for reading from pdf target
if (user_system == 'windows') {
var pdf_file = input_pdf.split(']')[0].slice(1).trim();
pdf_file = abs_file(pdf_file); var fs = require('fs'); if (!fs.exists(pdf_file))
casper.echo('ERROR - cannot find PDF file ' + pdf_file).exit();
var pdf_steps = 'Set WshShell = WScript.CreateObject("WScript.Shell")\r\n';
pdf_steps += 'WshShell.Run """' + windows_path(pdf_file) + '"""\r\nWScript.Sleep 5000\r\n';
pdf_steps += 'WshShell.SendKeys "^a"\r\nWScript.Sleep 1000\r\n';
pdf_steps += 'WshShell.SendKeys "^c"\r\nWScript.Sleep 1000\r\n';
pdf_steps += 'WshShell.SendKeys "^q"\r\nSet objHTML = CreateObject("htmlfile")\r\n';
pdf_steps += 'WScript.Echo objHTML.ParentWindow.ClipboardData.GetData("text")'; save_text('pdf_steps.vbs', pdf_steps);
save_text('pdf_steps.cmd', '@echo off\r\ncscript pdf_steps.vbs //NoLogo > pdf_steps.out 2>&1');
casper.waitForExec('pdf_steps.cmd', null, function(response) {
pdf_result = ''; pdf_result = require('fs').read('pdf_steps.out').trim();
}, function() {this.echo('ERROR - PDF automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else if (user_system == 'mac') {
var pdf_file = input_pdf.split(']')[0].slice(1).trim();
pdf_file = abs_file(pdf_file); var fs = require('fs'); if (!fs.exists(pdf_file))
casper.echo('ERROR - cannot find PDF file ' + pdf_file).exit();
var pdf_steps = 'tell application "Finder" to open POSIX file "' + pdf_file + '"\r\n';
pdf_steps += 'delay 5\r\ntell application "System Events"\r\n\t';
pdf_steps += 'keystroke "a" using {command down}\r\n\tdelay 1\r\n\t';
pdf_steps += 'keystroke "c" using {command down}\r\n\tdelay 1\r\n\t';
pdf_steps += 'keystroke "q" using {command down}\r\nend tell\r\n';
pdf_steps += 'do shell script "pbpaste > pdf_steps.out 2>&1"'; save_text('pdf_steps.scpt', pdf_steps);
casper.waitForExec('osascript pdf_steps.scpt', null, function(response) {
pdf_result = ''; pdf_result = require('fs').read('pdf_steps.out').trim();
}, function() {this.echo('ERROR - PDF automation exceeded '+(3 * casper.options.waitTimeout/1000).toFixed(1)+'s timeout').exit();},(3 * casper.options.waitTimeout));}
else casper.echo('ERROR - unsupported operating system ' + user_system).exit();}
function write_pdf(output_pdf) { // for writing to pdf target
casper.echo('ERROR - writing to PDF file not supported').exit();}
// for pdf statements - retrieving data for variable on right side of = sign
// broken into 2 functions for pdf_result to be usable with CasperJS structure
function pdf_retrieve(right_param) { // check OS before starting PDF automation
if (user_system != 'windows' && user_system != 'mac') {pdf_result = '';
casper.echo('ERROR - PDF automation only for Windows and Mac').exit();}
if (right_param.match(/\[.*\.pdf\]/i) == null)
{pdf_result = ''; pdf_result = eval(right_param);}
else if (pdf_result == '[LIVE_MODE]') {pdf_result = '';
casper.echo('ERROR - reading from PDF not supported in live mode');}
else {pdf_result = ''; read_pdf(right_param);}}
// for pdf statements - assigning data to variable on left side of = sign
// broken into 2 functions for pdf_result to be usable with CasperJS structure
function pdf_assign(left_param) {if (left_param.match(/\[.*\.pdf\]/i) == null)
eval(left_param + ' = pdf_result'); else write_pdf(left_param);}
// for translating multi-language flows (comments in translate.php)
function translate(script_line,direction,language) {var start_keywords = '|click|rclick|dclick|tap|move|hover|'+
'type|enter|select|choose|read|fetch|show|print|save|echo|dump|write|snap|ask|table|mouse|keyboard|wait|live|'+
'download|upload|load|receive|frame|popup|timeout|api|dom|js|vision|else if|else|if|for|while|check|';
var to_separator_keywords = '|read|fetch|save|load|dump|write|snap|table|download|receive|for|'
var as_separator_keywords = '|type|enter|select|choose|upload|'; var forloop_keywords = '|from|';
var start_conditions_keywords = '|else if|if|for|while|check|'; var start_helper_keywords = '|echo|dump|write|';
var conditions_keywords = '|more than or equals to|more than or equal to|greater than or equals to|greater than or equal to|higher than or equals to|higher than or equal to|less than or equals to|less than or equal to|lesser than or equals to|lesser than or equal to|lower than or equals to|lower than or equal to|more than|greater than|higher than|less than|lesser than|lower than|not equals to|not equal to|equals to|equal to|not contains|not contain|contains|contain|and|or|';
var helper_keywords = '|title()|url()|text()|timer()|count()|present()|visible()|mouse_'+'xy()|mouse_'+'x()|mouse_'+'y()|'; // break up mouse_ helper functions to avoid mistaken triggering by tagui_parse.php as sikuli process needed
var seconds_keywords = '|seconds|second|'; var start_seconds_keywords = '|wait|timeout|';
if (!script_line || script_line == '') return '';
if (!direction || direction == '') return 'ERROR - translation engine direction parameter missing';
if (!language || language == '') return 'ERROR - translation engine language parameter missing';
if (script_line == '' || script_line == '\r\n' || script_line == '\n') return script_line;
var front_script_line_return = ''; if (script_line.charAt(0) == '\n') front_script_line_return = '\n';
var back_script_line_return = ''; if (script_line.substr(-1) == '\n') back_script_line_return = '\n';
direction = direction.toLowerCase();
if (direction !== 'to' && direction !== 'from') return 'ERROR - translation engine direction must be to or from';
if (direction == 'from') {var column_from = 1; var column_to = 0;} else {var column_from = 0; var column_to = 1;}
language = language.toLowerCase(); var language_count = 0;
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var language_file = 'languages' + ds + language + '.csv'; var fs = require('fs');
if (!fs.exists(language_file)) return 'ERROR - translation engine ' + language + '.csv file missing'; else {
var language_raw = fs.read(language_file); if (language_raw.indexOf('\r\n') !== -1)
var language_data = language_raw.split(/\r\n/).map(function(line) {return line.split(',');});
else var language_data = language_raw.split(/\n/).map(function(line) {return line.split(',');});
language_count = language_data.length-1;
if (!language_data[language_count][0] || language_data[language_count][0] == '') language_count--;}
script_line = '[START_OF_LINE]'+script_line.trim()+'[END_OF_LINE]'; var start_word = '[NOT_ASSIGNED]';
for (language_check = 1; language_check <= language_count; language_check++) {
if (start_keywords.indexOf('|'+language_data[language_check][0]+'|') !== -1) {
if (start_word !== '[NOT_ASSIGNED]') continue;
if ((script_line.indexOf('[START_OF_LINE]'+language_data[language_check][column_from]+' ') !== -1) ||
(script_line.indexOf('[START_OF_LINE]'+language_data[language_check][column_from]+'[END_OF_LINE]') !== -1))
start_word = language_data[language_check][0];
var regex = new RegExp('\\[START_OF_LINE\\]'+language_data[language_check][column_from]+' ','g');
script_line = script_line.replace(regex,'[START_OF_LINE]'+language_data[language_check][column_to]+' ');
var regex = new RegExp('\\[START_OF_LINE\\]'+language_data[language_check][column_from]+'\\[END_OF_LINE\\]','g');
script_line = script_line.replace(regex,'[START_OF_LINE]'+language_data[language_check][column_to]+'[END_OF_LINE]');}
else if (conditions_keywords.indexOf('|'+language_data[language_check][0]+'|') !== -1) {
if (start_word == 'check') {var array_script_line = script_line.split('|');
var regex = new RegExp(' '+language_data[language_check][column_from]+' ','g');
array_script_line[0] = array_script_line[0].replace(regex,' '+language_data[language_check][column_to]+' ');
script_line = array_script_line.join('|');}
else if ((start_word !== '[NOT_ASSIGNED]') && (start_conditions_keywords.indexOf('|'+start_word+'|') !== -1))
{var regex = new RegExp(' '+language_data[language_check][column_from]+' ','g');
script_line = script_line.replace(regex,' '+language_data[language_check][column_to]+' ');}}
else if (seconds_keywords.indexOf('|'+language_data[language_check][0]+'|') !== -1) {
if ((start_word !== '[NOT_ASSIGNED]') && (start_seconds_keywords.indexOf('|'+start_word+'|') !== -1))
{var regex = new RegExp(' '+language_data[language_check][column_from]+'\\[END_OF_LINE\\]','g');
script_line = script_line.replace(regex,' '+language_data[language_check][column_to]+'[END_OF_LINE]');}}
else if (forloop_keywords.indexOf('|'+language_data[language_check][0]+'|') !== -1) {
if (start_word == 'for')
{var regex = new RegExp(' '+language_data[language_check][column_from]+' ','g');
script_line = script_line.replace(regex,' '+language_data[language_check][column_to]+' ');}}
else if (language_data[language_check][0] == 'to') {
if ((start_word !== '[NOT_ASSIGNED]') && (to_separator_keywords.indexOf('|'+start_word+'|') !== -1))
{var regex = new RegExp(' '+language_data[language_check][column_from]+' ','g');
script_line = script_line.replace(regex,' '+language_data[language_check][column_to]+' ');}}
else if (language_data[language_check][0] == 'as') {
if ((start_word !== '[NOT_ASSIGNED]') && (as_separator_keywords.indexOf('|'+start_word+'|') !== -1))
{var regex = new RegExp(' '+language_data[language_check][column_from]+' ','g');
script_line = script_line.replace(regex,' '+language_data[language_check][column_to]+' ');}}
else if (helper_keywords.indexOf('|'+language_data[language_check][0]+'|') !== -1) {
if (((start_word !== '[NOT_ASSIGNED]') && (start_conditions_keywords.indexOf('|'+start_word+'|') !== -1))
|| ((start_word !== '[NOT_ASSIGNED]') && (start_helper_keywords.indexOf('|'+start_word+'|') !== -1))
|| (script_line.indexOf('=') !== -1))
{var regex = new RegExp((' '+language_data[language_check][column_from]).replace('(','\\(').replace(')',''),'g');
script_line = script_line.replace(regex,(' '+language_data[language_check][column_to]).replace(')',''));}}}
script_line = script_line.replace('[START_OF_LINE]','').replace('[END_OF_LINE]','');
return front_script_line_return+script_line.trim()+back_script_line_return;}
// for checking if selector is xpath selector
function is_xpath_selector(selector) {if (selector.length == 0) return false;
if ((selector.indexOf('/') == 0) || (selector.indexOf('(') == 0)) return true; return false;}
// for finding best match for given locator
function tx(locator) {if (is_xpath_selector(locator)) return xps666(locator.replace(/'/g,'"'));
if (casper.exists(locator)) return locator; // check for css locator
// first check for exact match then check for containing string
if (casper.exists(xps666('//*[@id="'+locator+'"]'))) return xps666('//*[@id="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@id,"'+locator+'")]'))) return xps666('//*[contains(@id,"'+locator+'")]');
if (casper.exists(xps666('//*[@name="'+locator+'"]'))) return xps666('//*[@name="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@name,"'+locator+'")]'))) return xps666('//*[contains(@name,"'+locator+'")]');
if (casper.exists(xps666('//*[@class="'+locator+'"]'))) return xps666('//*[@class="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@class,"'+locator+'")]'))) return xps666('//*[contains(@class,"'+locator+'")]');
if (casper.exists(xps666('//*[@title="'+locator+'"]'))) return xps666('//*[@title="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@title,"'+locator+'")]'))) return xps666('//*[contains(@title,"'+locator+'")]');
if (casper.exists(xps666('//*[@aria-label="'+locator+'"]'))) return xps666('//*[@aria-label="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@aria-label,"'+locator+'")]'))) return xps666('//*[contains(@aria-label,"'+locator+'")]');
if (casper.exists(xps666('//*[text()="'+locator+'"]'))) return xps666('//*[text()="'+locator+'"]');
if (casper.exists(xps666('//*[contains(text(),"'+locator+'")]'))) return xps666('//*[contains(text(),"'+locator+'")]');
if (casper.exists(xps666('//*[@href="'+locator+'"]'))) return xps666('//*[@href="'+locator+'"]');
if (casper.exists(xps666('//*[contains(@href,"'+locator+'")]'))) return xps666('//*[contains(@href,"'+locator+'")]');
return xps666('/html');}
// for checking if given locator is found
function check_tx(locator) {if (is_xpath_selector(locator))
{if (casper.exists(xps666(locator.replace(/'/g,'"').replace(/\) \&\& \(/g,' and ').replace(/\) \|\| \(/g,' or ')))) return true; else return false;}
if (casper.exists(locator)) return true; // check for css locator
// first check for exact match then check for containing string
if (casper.exists(xps666('//*[@id="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@id,"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[@name="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@name,"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[@class="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@class,"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[@title="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@title,"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[@aria-label="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@aria-label,"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[text()="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(text(),"'+locator+'")]'))) return true;
if (casper.exists(xps666('//*[@href="'+locator+'"]'))) return true;
if (casper.exists(xps666('//*[contains(@href,"'+locator+'")]'))) return true;
return false;}
/**
* Extra TagUI helper methods
*/
// friendlier name to use check_tx() in if condition in flow
function present(element_locator) {if (!element_locator) return false;
if (is_sikuli(element_locator)) {var abs_param = abs_file(element_locator); var fs = require('fs');
if (sikuli_step("present " + abs_param)) return true; else return false;}
else return check_tx(element_locator);}
// present() function that waits until timeout before returning result
function exist(element_identifier) {var exist_timeout = Date.now() + casper.options.waitTimeout;
while (Date.now() < exist_timeout) {if (present(element_identifier)) return true; else sleep(100);}; return false;}
// friendlier name to check element visibility using elementVisible()
function visible(element_locator) {if (!element_locator) return false;
if (is_sikuli(element_locator)) {var abs_param = abs_file(element_locator); var fs = require('fs');
if (sikuli_step("visible " + abs_param)) return true; else return false;}
else {var element_located = tx(element_locator); var element_visible = casper.elementVisible(element_located);
// if tx() returns xps666('/html') means that the element is not found, so set element_visible to false
if (element_located.toString() == xps666('/html').toString()) element_visible = false; return element_visible;}}
// visible() function that waits until timeout before returning result
function appeared(element_identifier) {var appeared_timeout = Date.now() + casper.options.waitTimeout;
while (Date.now() < appeared_timeout) {if (visible(element_identifier)) return true; else sleep(100);}; return false;}
// friendlier name to count elements using countElements()
function count(element_locator) {if (!element_locator) return 0;
var element_located = tx(element_locator); var element_count = casper.countElements(element_located);
// if tx() returns xps666('/html') means that the element is not found, so set element_count to 0
if (element_located.toString() == xps666('/html').toString()) element_count = 0; return element_count;}
// friendlier name to get web page title using getTitle()
function title() {return casper.getTitle();}
// friendlier name to get web page url using getCurrentUrl()
function url() {return casper.getCurrentUrl();}
// friendlier name to get web page text content using evaluate()
function text() {return casper.evaluate(function() {return document.body.innerText || document.body.textContent;});}
function timer() { // return time elapsed in seconds between calls
var time_elapsed = ((Date.now()-timer_start_time)/1000); timer_start_time = Date.now(); return time_elapsed;}
function sleep(ms) { // helper to add delay during loops
var time_now = new Date().getTime(); var time_end = time_now + ms;
while(time_now < time_end) {time_now = new Date().getTime();}}
// return x,y coordinates of mouse cursor as string '(x,y)'
mouse_xy = function() { // use this function declaration style for sikuli detection in tagui_parse.php
sikuli_step('vision xy_mouseLocation = Env.getMouseLocation(); ' +
'xy_x = xy_mouseLocation.getX(); xy_y = xy_mouseLocation.getY(); ' +
"output_sikuli_text('(' + str(xy_x) + ',' + str(xy_y) + ')');");
var xy_result = fetch_sikuli_text(); clear_sikuli_text(); return xy_result;}
// return x coordinate of mouse cursor as integer number
mouse_x = function() { // use this function declaration style for sikuli detection in tagui_parse.php
sikuli_step('vision xy_mouseLocation = Env.getMouseLocation(); output_sikuli_text(str(xy_mouseLocation.getX()));');
var x_result = parseInt(fetch_sikuli_text()); clear_sikuli_text(); return x_result;}
// return y coordinate of mouse cursor as integer number
mouse_y = function() { // use this function declaration style for sikuli detection in tagui_parse.php
sikuli_step('vision xy_mouseLocation = Env.getMouseLocation(); output_sikuli_text(str(xy_mouseLocation.getY()));');
var y_result = parseInt(fetch_sikuli_text()); clear_sikuli_text(); return y_result;}
// get text from clipboard or set text to clipboard
clipboard = function(clipboard_text) { // use this function declaration style for sikuli detection in tagui_parse.php
if (!clipboard_text) {sikuli_step('vision output_sikuli_text(App.getClipboard())');
var clipboard_result = fetch_sikuli_text(); clear_sikuli_text(); return clipboard_result;}
else {vision_step('clipboard_text = ucode("' + escape_bs(clipboard_text) + '")'); // escape_bs() for \n \t etc
sikuli_step('vision App.setClipboard(clipboard_text)');}}
/**
* string cell data sanitiser, returns a CSV formatted string
* @param {string} cell_data
*/
function sanitise_csv_cell(cell_data) {
// ensure numbers are converted to string
cell_data = cell_data.toString()
// Replace all double quotes with 2 double quotes
cell_data = cell_data.replace(/"/g, '\"\"')
var whitespaceCheckRegex = /\s/
// if cell_data has a comma, or new line, or its first or last character is a
// whitespace, then wrap the entire expression in double quotes
if (
cell_data.indexOf(',') >= 0
|| cell_data.indexOf('\n') >= 0
|| whitespaceCheckRegex.test(cell_data.charAt(0))
|| whitespaceCheckRegex.test(cell_data.charAt(cell_data.length - 1))
) {
cell_data = '\"' + cell_data + '\"'
}
return cell_data
}
/**
* Returns a CSV-formatted string that denotes a row in a CSV file
* @param {string[]} row_data a 1-D array of strings denoting data to
* encode as a CSV row
*/
function csv_row(original_row_data) {
var row_data = original_row_data.slice()
// if row_data has at least 1 element, extract and sanitise first element
// else start_element is empty string
var start_element = (row_data.length > 0)
? sanitise_csv_cell(row_data.shift())
: ''
// concat each row_data with a comma
return row_data.reduce(function(accumulator, currentValue) {
return accumulator + ',' + sanitise_csv_cell(currentValue)
}, start_element)
}
// retrieve text between 2 provided anchors in given text content
function get_text(source_text, left_marker, right_marker, optional_count) {
if (!source_text || !left_marker || !right_marker) return '';
var left_position = source_text.indexOf(left_marker); if (left_position == -1) return '';
var right_position = source_text.indexOf(right_marker, left_position+1); if (right_position == -1) return '';
if (optional_count > 1) {var occurrence_count = 2; while(occurrence_count <= optional_count) {occurrence_count++;
left_position = source_text.indexOf(left_marker, right_position+1); if (left_position == -1) return '';
right_position = source_text.indexOf(right_marker, left_position+1); if (right_position == -1) return '';}}
return source_text.slice(left_position + left_marker.length, right_position).trim();}
// return given string after deleting all occurrences of given characters
function del_chars(source_text, characters) {
if (!source_text) return ''; else if (!characters) return source_text;
characters = characters.replace(/\\n/g,'\n').replace(/\\r/g,'\r').replace(/\\t/g,'\t');
characters = characters.replace(/\\f/g,'\f').replace(/\\v/g,'\v').replace(/\\\\/g,'\\');
for (char_counter = 0; char_counter < characters.length; char_counter++) {
if (characters[char_counter] != '\\')
source_text = source_text.replace(new RegExp(characters[char_counter].replace(/[-[\]{}()*+?.,\\^$|]/g, "\\$&"),'g'),'');
else
source_text = source_text.replace(/\\/g,'');}
return source_text;}
// return value of environment variable from operating system
function get_env(name_of_variable) { // if missing or blank name, or invalid variable, '' will be returned
if (!name_of_variable || name_of_variable == '') return '';
var value_of_variable = require('system').env[name_of_variable];
if (value_of_variable == null) return ''; else return value_of_variable;}
// return array of all the files in the given folder
function get_files(folder_path) {if (!folder_path || folder_path == '') return [];
if (!require('fs').isDirectory(abs_file(folder_path))) return [];
var files_array = require('fs').list(abs_file(folder_path));
return files_array.splice(2, files_array.length - 2);}
// for initialising integration with sikuli visual automation
function sikuli_handshake() { // techo('[connecting to sikuli process]');
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\'; clear_sikuli_text();
var fs = require('fs'); fs.write('tagui.sikuli'+ds+'tagui_sikuli.in','','w'); var sikuli_handshake = '';
if (!fs.exists('tagui.sikuli'+ds+'tagui_sikuli.out')) fs.write('tagui.sikuli'+ds+'tagui_sikuli.out','','w');
do {sleep(500); sikuli_handshake = fs.read('tagui.sikuli'+ds+'tagui_sikuli.out').trim();}
while (sikuli_handshake !== '[0] START'); // techo('[connected to sikuli process]');
}
// for passing dynamic inputs to sikuli visual automation
function vision_step(vision_intent) {if (vision_intent.indexOf('vision ') !== 0)
vision_intent = 'vision ' + vision_intent; sikuli_step(vision_intent);}
// for using sikuli visual automation instead of casperjs
function sikuli_step(sikuli_intent) {sikuli_count++;
if (sikuli_count == 1) sikuli_handshake(); // handshake on first call
if (sikuli_intent.indexOf('snap_image()') > -1) {sikuli_intent = sikuli_intent.replace('snap_image()',snap_image());}
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui.sikuli'+ds+'tagui_sikuli.in','['+sikuli_count.toString()+'] '+sikuli_intent,'w');
var sikuli_result = ''; do {sleep(500); sikuli_result = fs.read('tagui.sikuli'+ds+'tagui_sikuli.out').trim();}
while (sikuli_result.indexOf('['+sikuli_count.toString()+'] ') == -1);
if (sikuli_result.indexOf('SUCCESS') !== -1) return true; else return false;}
// for fetching text from sikuli optical character recognition
function fetch_sikuli_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); if (fs.exists('tagui.sikuli'+ds+'tagui_sikuli.txt'))
return fs.read('tagui.sikuli'+ds+'tagui_sikuli.txt').trim(); else return '';}
// for clearing text from sikuli optical character recognition
function clear_sikuli_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui.sikuli'+ds+'tagui_sikuli.txt','','w');}
// for setting timeout in sikuli when looking for ui element
function sikuli_timeout(time_in_seconds) {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); if (fs.exists('tagui.sikuli'+ds+'tagui_sikuli.in'))
{sikuli_step('vision setAutoWaitTimeout(' + time_in_seconds.toString() + ')');
sikuli_step('vision wait_timeout = ' + time_in_seconds.toString());}}
// for initialising integration with R
function r_handshake() { // techo('[connecting to R process]');
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\'; clear_r_text();
var fs = require('fs'); fs.write('tagui_r'+ds+'tagui_r.in','','w'); var r_handshake = '';
if (!fs.exists('tagui_r'+ds+'tagui_r.out')) fs.write('tagui_r'+ds+'tagui_r.out','','w');
do {sleep(100); r_handshake = fs.read('tagui_r'+ds+'tagui_r.out').trim();}
while (r_handshake !== '[0] START'); // techo('[connected to R process]');
}
// R integration for data analytics and machine learning
function r_step(r_intent) {if (r_intent.indexOf('r ') !== 0) r_intent = 'r ' + r_intent; r_count++;
if (r_count == 1) r_handshake(); // handshake on first call
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui_r'+ds+'tagui_r.in','['+r_count.toString()+'] '+r_intent,'w');
var r_step_result = ''; do {sleep(100); r_step_result = fs.read('tagui_r'+ds+'tagui_r.out').trim();}
while (r_step_result.indexOf('['+r_count.toString()+'] ') == -1);
if (r_step_result.indexOf('SUCCESS') !== -1) return true; else return false;}
// for fetching text from R integration execution result
function fetch_r_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); if (fs.exists('tagui_r'+ds+'tagui_r.txt'))
return fs.read('tagui_r'+ds+'tagui_r.txt').trim(); else return '';}
// for clearing text from R integration execution result
function clear_r_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui_r'+ds+'tagui_r.txt','','w');}
// for initialising integration with Python
function py_handshake() { // techo('[connecting to Python process]');
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\'; clear_py_text();
var fs = require('fs'); fs.write('tagui_py'+ds+'tagui_py.in','','w'); var py_handshake = '';
if (!fs.exists('tagui_py'+ds+'tagui_py.out')) fs.write('tagui_py'+ds+'tagui_py.out','','w');
do {sleep(100); py_handshake = fs.read('tagui_py'+ds+'tagui_py.out').trim();}
while (py_handshake !== '[0] START'); // techo('[connected to Python process]');
}
// Python integration for data analytics and machine learning
function py_step(py_intent) {if (py_intent.indexOf('py ') !== 0) py_intent = 'py ' + py_intent; py_count++;
if (py_count == 1) py_handshake(); // handshake on first call
var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui_py'+ds+'tagui_py.in','['+py_count.toString()+'] '+py_intent,'w');
var py_step_result = ''; do {sleep(100); py_step_result = fs.read('tagui_py'+ds+'tagui_py.out').trim();}
while (py_step_result.indexOf('['+py_count.toString()+'] ') == -1);
if (py_step_result.indexOf('SUCCESS') !== -1) return true; else return false;}
// for fetching text from Python integration execution result
function fetch_py_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); if (fs.exists('tagui_py'+ds+'tagui_py.txt'))
return fs.read('tagui_py'+ds+'tagui_py.txt').trim(); else return '';}
// for clearing text from Python integration execution result
function clear_py_text() {var ds; if (flow_path.indexOf('/') !== -1) ds = '/'; else ds = '\\';
var fs = require('fs'); fs.write('tagui_py'+ds+'tagui_py.txt','','w');}
if (chrome_id > 0) { // super large if block to load chrome related functions if chrome or headless option is used
chrome_id = 0; // reset chrome_id from 1 back to 0 to prepare for initial call of chrome_step
// for initialising integration with chrome web browser
function chrome_handshake() { // techo('[connecting to chrome websocket]');
var fs = require('fs'); fs.write('tagui_chrome.in','','w'); var chrome_handshake = '';
if (!fs.exists('tagui_chrome.out')) fs.write('tagui_chrome.out','','w');
do {sleep(100); chrome_handshake = fs.read('tagui_chrome.out').trim();}
while (chrome_handshake !== '[0] START'); // techo('[connected to chrome websocket]');
}
// send websocket message to chrome browser using chrome devtools protocol
// php helper process tagui_chrome.php running to handle this concurrently
function chrome_step(method,params) {chrome_id++;
if (chrome_id == 1) chrome_handshake(); // handshake on first call
var chrome_intent = JSON.stringify({'id': chrome_id, 'method': method, 'params': params});
if (chrome_targetid !== '') chrome_intent = JSON.stringify({'id': chrome_id, 'method': 'Target.sendMessageToTarget', 'params': {'sessionId': chrome_targetid, 'message': chrome_intent}}); // send as message to target if context is popup
var fs = require('fs'); fs.write('tagui_chrome.in','['+chrome_id.toString()+'] '+chrome_intent,'w');
var chrome_result = ''; do {sleep(100); chrome_result = fs.read('tagui_chrome.out').trim();}
while (chrome_result.indexOf('['+chrome_id.toString()+'] ') == -1);
if (chrome_targetid == '') return chrome_result.substring(chrome_result.indexOf('] ')+2); // below for handling popup
else {try {var raw_json_string = JSON.stringify(JSON.parse(chrome_result.substring(chrome_result.indexOf('] ')+2)).params.message); return raw_json_string.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\n/g,"\\n");} catch(e) {return '';}}}
// chrome object for handling integration with chrome or headless chrome
var chrome = new Object(); chrome.mouse = new Object();
// chrome methods as casper methods replacement for chrome integration
chrome.exists = function(selector) { // different handling for xpath and css to support both
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotLength'});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelectorAll(\''+selector+'\').length'});
try {var ws_json = JSON.parse(ws_message); if (ws_json.result.result.value > 0) return true; else return false;}
catch(e) {return false;}};
chrome.elementVisible = function(selector) { // same as chrome.exists, except for checking visibility
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'var e = document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0); var visible = false; if (!e) visible = false; else {var style = window.getComputedStyle(e); visible = style && style.display !== \'none\' && style.visibility !== \'hidden\' && style.opacity !== \'0\';}; visible'});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: 'var e = '+chrome_context+'.querySelector(\''+selector+'\'); var visible = false; if (!e) visible = false; else {var style = window.getComputedStyle(e); visible = style && style.display !== \'none\' && style.visibility !== \'hidden\' && style.opacity !== \'0\';}; visible'});
try {var ws_json = JSON.parse(ws_message); if (ws_json.result.result.value == true)
return ws_json.result.result.value; else return false;}
catch(e) {return false;}};
chrome.countElements = function(selector) { // same as chrome.exists, except element count is returned
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotLength'});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelectorAll(\''+selector+'\').length'});
try {var ws_json = JSON.parse(ws_message); if (ws_json.result.result.value > 0)
return ws_json.result.result.value; else return 0;}
catch(e) {return 0;}};
/* // backup of previous click implementation to experiment with Puppeteer's version
chrome.click = function(selector) { // click by sending click event instead of mouse down/up/click, then focus on element
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).click()'}); chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).focus()'});}
else {chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelector(\''+selector+'\').click()'});
chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelector(\''+selector+'\').focus()'});}}; */
chrome.click = function(selector) { // click using Puppeteer's implementation - see TagUI issue #212
chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);
chrome.mouse.action('mouseMoved',xy.x,xy.y,'none',0);
chrome.mouse.action('mousePressed',xy.x,xy.y,'left',1); chrome.mouse.action('mouseReleased',xy.x,xy.y,'left',1);}
chrome.scrollIntoViewIfNeeded = function(selector) { // helper function to scroll element into view
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).scrollIntoViewIfNeeded()'});}
else {chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelector(\''+selector+'\').scrollIntoViewIfNeeded()'});}}
chrome.mouse.action = function(type,x,y,button,clickCount) { // helper function to send various mouse events
chrome_step('Input.dispatchMouseEvent',{type: type, x: x, y: y, button: button, clickCount: clickCount});};
chrome.mouse.getXY = function(selector) { // helper function to get xy center coordinates of selector
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'var result_bounds = document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).getBoundingClientRect(); var result_xy = {x: Math.round(result_bounds.left + result_bounds.width / 2), y: Math.round(result_bounds.top + result_bounds.height / 2)}; result_xy', returnByValue: true});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: 'var result_bounds = '+chrome_context+'.querySelector(\''+selector+'\').getBoundingClientRect(); var result_xy = {x: Math.round(result_bounds.left + result_bounds.width / 2), y: Math.round(result_bounds.top + result_bounds.height / 2)}; result_xy', returnByValue: true});
try {var ws_json = JSON.parse(ws_message); if (ws_json.result.result.value.x > 0 && ws_json.result.result.value.y > 0)
{if (chrome_context !== 'document') {ws_json.result.result.value.x += frame_step_offset_x; // add offset if in frame
ws_json.result.result.value.y += frame_step_offset_y;}; return ws_json.result.result.value;} else
{if (chrome_context !== 'document') return {x: frame_step_offset_x, y: frame_step_offset_y};
else return {x: 0, y: 0};}} catch(e) {return {x: 0, y: 0};}};
chrome.getRect = function(selector) { // helper function to get rectangle boundary coordinates of selector
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'var result_bounds = document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).getBoundingClientRect(); var result_rect = {top: Math.round(result_bounds.top), left: Math.round(result_bounds.left), width: Math.round(result_bounds.width), height: Math.round(result_bounds.height)}; result_rect', returnByValue: true});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: 'var result_bounds = '+chrome_context+'.querySelector(\''+selector+'\').getBoundingClientRect(); var result_rect = {top: Math.round(result_bounds.top), left: Math.round(result_bounds.left), width: Math.round(result_bounds.width), height: Math.round(result_bounds.height)}; result_rect', returnByValue: true}); try {var ws_json = JSON.parse(ws_message); // check if width and height are valid before returning coordinates
if (ws_json.result.result.value.width > 0 && ws_json.result.result.value.height > 0)
{if (chrome_context !== 'document') {ws_json.result.result.value.left += frame_step_offset_x; // add offset if in frame
ws_json.result.result.value.top += frame_step_offset_y;}; return ws_json.result.result.value;} else
{if (chrome_context !== 'document') return {left: frame_step_offset_x, top: frame_step_offset_y, width: 0, height: 0};
else return {left: 0, top: 0, width: 0, height: 0};}} catch(e) {return {left: 0, top: 0, width: 0, height: 0};}};
chrome.mouse.move = function(selector,y) { // move mouse pointer to center of specified selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mouseMoved',xy.x,xy.y,'none',0);};
chrome.mouse.click = function(selector,y) { // press and release on center of specfied selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mousePressed',xy.x,xy.y,'left',1); chrome.mouse.action('mouseReleased',xy.x,xy.y,'left',1);};
chrome.mouse.doubleclick = function(selector,y) { // double press and release on center of selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mousePressed',xy.x,xy.y,'left',2); chrome.mouse.action('mouseReleased',xy.x,xy.y,'left',2);};
chrome.mouse.rightclick = function(selector,y) { // right click press and release on center of selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mousePressed',xy.x,xy.y,'right',1); chrome.mouse.action('mouseReleased',xy.x,xy.y,'right',1);};
chrome.mouse.down = function(selector,y) { // left press on center of specified selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mousePressed',xy.x,xy.y,'left',1);};
chrome.mouse.up = function(selector,y) { // left release on center of specified selector or point
if (!y) {chrome.scrollIntoViewIfNeeded(selector); var xy = chrome.mouse.getXY(selector);}
else var xy = {x: selector, y: y}; // get coordinates accordingly
chrome.mouse.action('mouseReleased',xy.x,xy.y,'left',1);};
chrome.sendKeys = function(selector,value,options) { // send key strokes to selector, options not implemented
if (value == casper.page.event.key.Enter) value = '\r';
if (value) {value = value.replace(/\[enter\]/g,'\r'); // to cater for [enter] passed in as part of a variable
value = value.replace(/\r\n/g,'\r'); // change \r\n to \r which is the enter key for chrome browser
value = value.replace(/\n/g,'\r');} // change \n to \r which is the enter key for chrome browser
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).focus()'});}
else chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelector(\''+selector+'\').focus()'});
if (options && options.reset == true) // handling for clearing field by checking options.reset
{if ((selector.indexOf('/') == 0) || (selector.indexOf('(') == 0)) // check for xpath selector and handle accordingly
{chrome_step('Runtime.evaluate',{expression: 'var sendKeys_field = document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0); sendKeys_field.value = \'\'; var evt = document.createEvent(\'UIEvents\'); evt.initUIEvent(\'change\', true, true); sendKeys_field.dispatchEvent(evt);'});}
else chrome_step('Runtime.evaluate',{expression: 'var sendKeys_field = '+chrome_context+'.querySelector(\''+selector+'\'); sendKeys_field.value = \'\'; var evt = document.createEvent(\'UIEvents\'); evt.initUIEvent(\'change\', true, true); sendKeys_field.dispatchEvent(evt);'});}
for (var character = 0, length = value.length; character < length; character++) {
chrome_step('Input.dispatchKeyEvent',{type: 'char', text: value[character]});}};
chrome.selectOptionByValue = function(selector,valueToMatch) { // select dropdown option (base on casperjs issue #1390)
chrome.evaluate('function() {var selector = \''+selector+'\'; var valueToMatch = \''+valueToMatch+'\'; var found = false; if ((selector.indexOf(\'/\') == 0) || (selector.indexOf(\'(\') == 0)) var select = document.evaluate(selector,'+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0); else var select = '+chrome_context+'.querySelector(selector); if (valueToMatch == \'[clear]\') valueToMatch = \'\'; Array.prototype.forEach.call(select.children, function(opt, i) {if (!found && ((opt.value == valueToMatch)||(opt.text == valueToMatch))) {select.selectedIndex = i; found = true;}}); var evt = document.createEvent("UIEvents"); evt.initUIEvent("change", true, true); select.dispatchEvent(evt);}');};
chrome.fetchText = function(selector) { // grab text from selector following casperjs logic, but grab only first match
if ((selector.toString().length >= 16) && (selector.toString().substr(0,16) == 'xpath selector: '))
{if (selector.toString().length == 16) selector = ''; else selector = selector.toString().substring(16);
var ws_message = chrome_step('Runtime.evaluate',{expression: 'document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).textContent || document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).innerText || document.evaluate(\''+selector+'\','+chrome_context+',null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0).value || \'\''});}
else var ws_message = chrome_step('Runtime.evaluate',{expression: chrome_context+'.querySelector(\''+selector+'\').textContent || '+chrome_context+'.querySelector(\''+selector+'\').innerText || '+chrome_context+'.querySelector(\''+selector+'\').value || \'\''});
try {var ws_json = JSON.parse(ws_message); if (ws_json.result.result.value)
return ws_json.result.result.value; else return '';} catch(e) {return '';}};
chrome.decode = function(str) { // funtion to convert base64 data to binary string
// used in https://github.com/casperjs/casperjs/blob/master/modules/clientutils.js
if (!str) return ''; // return empty string if somehow null value is passed in
var BASE64_DECODE_CHARS = [
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1];
var c1, c2, c3, c4, i = 0, len = str.length, out = ""; while (i < len) {
do {c1 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];} while (i < len && c1 === -1); if (c1 === -1) {break;}
do {c2 = BASE64_DECODE_CHARS[str.charCodeAt(i++) & 0xff];} while (i < len && c2 === -1); if (c2 === -1) {break;}
out += String.fromCharCode(c1 << 2 | (c2 & 0x30) >> 4);
do {c3 = str.charCodeAt(i++) & 0xff; if (c3 === 61) {return out;} c3 = BASE64_DECODE_CHARS[c3];}
while (i < len && c3 === -1); if (c3 === -1) {break;} out += String.fromCharCode((c2 & 0XF) << 4 | (c3 & 0x3C) >> 2);