Fix handling youtube player controls
[platform/core/uifw/vc-webview-js.git] / js / vc-webview.js
1 /**
2  *   Copyright 2017 Samsung Electronics Co., Ltd.
3  *
4  *   Licensed under the Flora License, Version 1.1 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://floralicense.org/license/
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16
17 /**
18  * vc-webview.js
19  *
20  *  This source code is a base script of web voice touch.
21  */
22
23  /**
24  * vc_docs holds analysed documents' first hint number and last hint number
25  * @member doc  document elements.
26  * @member start  the first tooltip number in @doc.
27  * @member end  the last tooltip number in @doc.
28  */
29 var vc_docs = [],
30
31 vc_conflict_timer = null,
32
33 /**
34  * vc_conflict_links holds references to links that match the same keyword
35  */
36 vc_conflict_links = [];
37
38 /**
39  * vc_scr holds info about screen and website
40  * @member top  coordinate of the top boundary.
41  * @member left  coordinate of the left boundary.
42  * @member bottom  coordinate of the bottom boundary.
43  * @member right  coordinate of the right boundary.
44  */
45 var vc_scr = {
46         top : 0,
47         left : 0,
48         bottom : window.innerHeight,
49         right : window.innerWidth
50 },
51
52 /**
53  * vc_xpath_query is a query that processes DOM tree to get clickable objects.
54  * It analyses HTML tree as it is XML and returns matching objects in one of selected forms.
55  */
56 vc_xpath_query = ".//xhtml:input[not(@type='hidden')] | .//xhtml:a | .//xhtml:area | .//xhtml:textarea | .//xhtml:button | .//xhtml:*[" +
57         "@role='link' or @role='button' or @role='checkbox' or @role='combobox' or @role='radio'] |" +
58         " .//xhtml:div[contains(@class, 'ui-btn')] | .//xhtml:div[contains(@class, 'sideBarButton')] | .//xhtml:div[contains(@class, 'buttonCaption')]",
59
60 /**
61  * vc_page_hints holds all hints on website
62  */
63 vc_page_hints = [],
64
65 /**
66  * vc_hint_div is a DIV that gathers all hints
67  */
68 vc_hint_div,
69
70 /**
71  * vc_high_div is a DIV that gathers red highlight boxes
72  */
73 vc_high_div,
74
75 /**
76  * vc_hint_num is used to numerate hints from 1 on every screen they're displayed
77  */
78 vc_hint_num,
79
80 /**
81  * vc_visible_hints holds all hints that are currently visible
82  */
83 vc_visible_hints = [],
84
85 /**
86  * vc_bad_iframes holds iframes that should be highlighted with red color
87  */
88 vc_bad_iframes = [],
89
90 /**
91  * vc_log_area is a textarea element for log texts.
92  */
93 vc_log_area = document.createElement('textarea'),
94
95 /**
96  * vc_html_area is a textarea element to read raw source code of html document in TV.
97  */
98 vc_html_area = undefined,
99
100 /**
101  * vc_asr_result is a div element shows the asr result for debugging.
102  */
103 vc_asr_result = undefined,
104
105 /**
106  * vc_rec_result is a div element shows the recognition result of document searching for debugging.
107  */
108 vc_rec_result = undefined,
109
110 /**
111  * vc_flag_log is a flag variable. If it is true, vc_log_area is created. Otherwise, vc_log_area is nothing.
112  */
113 vc_flag_log = false,
114
115 /**
116  * vc_all_elem is a array that includes whole element in html document for text searching.
117  */
118 vc_all_elem = undefined,
119
120 /**
121  * vc_flag_conflict is a flag variable. When multiple elements are selected, it is true. Otherwise, it is false.
122  */
123 vc_flag_conflict = false,
124
125 /**
126  * vc_flag_hint_exist is a flag variable. When tooltips are already exist, it is true. Otherwise, it is false.
127  */
128 vc_flag_hint_exist = false,
129
130 /**
131  * vc_flag_make_tooltip is a flag variable. When creating tooltip is set, it is true. Otherwise, it is false.
132  */
133 vc_flag_make_tooltip = true,
134
135 /**
136  * vc_text_indicators is an array that contains text indicator elements
137  */
138 vc_text_indicators = [],
139
140 /**
141  * vc_made_hint shows the state tooltip making.
142  */
143 vc_made_hint = false,
144
145 /**
146  * vc_tag_index stores index number of the set of tooltips in web page.
147  * this variable prevents making duplicated tooltips.
148  */
149 vc_tag_index = 0;
150
151 /**
152  * prototypes of overridable custom function
153  */
154 function vc_custom_pre_generate_hints() {
155         vc_print_log('No custom script');
156 }
157
158 function vc_custom_pre_show_hints() {
159         vc_print_log('No custom script');
160 }
161
162 function vc_custom_pre_remove_hints() {
163         vc_print_log('No custom script');
164 }
165
166 function vc_custom_pre_hide_hints() {
167         vc_print_log('No custom script');
168 }
169 /* ======================== */
170
171 /**
172  * vc_custom_add_xpath_query functino adds given condition to xpath query
173  *
174  * @param className  the name of the class of DOM elements
175  * @param DOMtype(optional)  the type name of DOM element
176  *
177  * @remind this function must be called in page specific script
178  */
179 function vc_custom_add_xpath_query(className, DOMtype) {
180         if (undefined == DOMtype) {
181                 DOMtype = 'div';
182         }
183
184         vc_xpath_query += " | .//xhtml:" + DOMtype + "[contains(@class, '" + className + "')]";
185 }
186
187 /**
188  * vc_is_child check if element is a child of other element
189  *
190  * @param child  child to check the parent of
191  * @param parent  to test to
192  *
193  * @return true if elements are related, false otherwise
194  */
195 function vc_is_child(child, parent) {
196         var node = child.parentNode;
197         while (node && node != document.body) {
198                 if (node === parent) {
199                         return true;
200                 }
201                 node = node.parentNode;
202         }
203         return false;
204 }
205
206 /**
207  * vc_is_hidden function checks if the element given as parameter is hidden due to its CSS style
208  *
209  * @param elem element to be checked
210  * @param predecessor predecessor of elem to check visibility if elementFromPoint doesn't return elem
211  *
212  * @return true if element is invisible, false otherwise
213  */
214 function vc_is_hidden(elem, predecessor) {
215         if (elem == undefined) {
216                 return true;
217         }
218
219         /* if predecesor is no found assume parent is one */
220         if (!predecessor && elem.parentNode) {
221                 predecessor = elem.parentNode;
222         }
223         /* check visibility in css style */
224         var doc = elem.ownerDocument,
225         win = doc.defaultView,
226         computedStyle = win.getComputedStyle(elem, null);
227
228         if (computedStyle.getPropertyValue('visibility') !== 'visible' || computedStyle.getPropertyValue('display') === 'none') {
229                 return true;
230         }
231
232         /* object is visible check if it is on current screen */
233         var rect = elem.getBoundingClientRect(),
234         x = rect.left + (rect.width / 2),
235         y = rect.top + (rect.height / 2),
236         point;
237
238         if (y < 0 && x >= 0) {
239                 y = 0;
240         } else if (y < 0 && x < 0) {
241                 x = y = 0;
242         } else if (y >= 0 && x < 0) {
243                 x = 0;
244         }
245
246         point = doc.elementFromPoint(x, y);
247         /* if elementFromPoint returns HTMLBodyElement it probably is a scroll left/right list and it is hidden */
248         if (point === doc.body) {
249                 return true;
250         }
251         /* if elementFromPoint returns predecessor it is visible */
252         if (point && predecessor && vc_is_child(point, predecessor)) {
253                 return false;
254         }
255
256         return true;
257 }
258
259 /**
260  * vc_is_visible function checks if the element provided as argument is currently visible on screen
261  *
262  * @param elem  element to be checked
263  * @param scr  screen information
264  * @param isTextLink  determines if the element is text link
265  *
266  * @return true if visible false otherwise
267  */
268 function vc_is_visible(elem, scr, isTextLink) {
269         if (elem == undefined) {
270                 return false;
271         }
272
273         if (!scr) {
274                 scr = {
275                         top : 0,
276                         left : 0,
277                         bottom : window.innerHeight,
278                         right : window.innerWidth
279                 };
280         }
281         // if only two parameters passed to function assume isTextLink is false
282         isTextLink = typeof isTextLink !== 'undefined' ? isTextLink : false;
283
284         var docy = elem.ownerDocument,
285         win = docy.defaultView,
286         computedStyle = win.getComputedStyle(elem, null);
287
288         /* element is not visible if it is fully transparent except select box  */
289         if (parseFloat(computedStyle.getPropertyValue('opacity')) === 0.0) {
290                 return false;
291         }
292
293         var rect = elem.getBoundingClientRect();
294
295         /* element is not visible if it is not on screen */
296         if (!rect || rect.top >= scr.bottom || rect.bottom <= scr.top || rect.left >= scr.right ||
297                 rect.right <= scr.left) {
298                 return false;
299         }
300
301         /* element is not visible if it is hidden and it is not a text hyperlink */
302         if (!isTextLink && vc_is_hidden(elem, null)) {
303                 return false;
304         }
305
306         return true;
307 }
308
309 /**
310  * vc_make_hint procedure creates invisible hint for element provided as argument
311  *
312  * @param elem  element for which hint is to be created
313  * @param child  if child is passed, the hint will be positioned according to position of child
314  */
315 function vc_make_hint(elem, child) {
316         // vc_print_log(elem);
317         if (false == vc_flag_make_tooltip) {
318                 return;
319         }
320
321         var rect;
322
323         rect = child.getBoundingClientRect();
324
325         if (!rect || elem.vc_tag_index == vc_tag_index) {
326                 return;
327         }
328
329         elem.vc_tag_index = vc_tag_index;
330
331         var doc = elem.ownerDocument;
332
333         /** hint object holds clickable element, type of element and created hint (HTMLSpanElement)
334          * @member elem  clickable target element.
335          * @member type  the type of @elem.
336          * @member child  child element of @elem
337          * @member span  tooltip element of @elem
338          */
339         var hint = {
340                 elem : elem,
341                 type : 'normal',
342                 child : child,
343                 span : null
344         };
345
346         if(elem instanceof HTMLAreaElement){
347                 hint.type = 'area';
348         }
349
350         /* not all input objects are supported */
351         if (elem instanceof HTMLInputElement) {
352                 if (elem.type === 'text' || elem.type === 'password' || elem.type === 'datetime' || elem.type === 'email' ||
353                         elem.type === 'search' || elem.type === 'number' || elem.type === 'url') {
354                         hint.type = 'input';
355                 } else if (elem.type !== 'button' && elem.type !== 'submit' && elem.type !== 'color' && elem.type !== 'radio' &&
356                         elem.type !== 'checkbox' && elem.type !== 'file' && elem.type !== 'submit' && elem.type !== 'image') {
357                         return;
358                 }
359         /* consider TextArea element as input element */
360         } else if (elem instanceof HTMLTextAreaElement) {
361                 hint.type = 'input';
362         }
363
364         /** span object is the visual representation of hint */
365         var span = doc.createElement('span');
366         span.id = 'vc_tooltip';
367         span.className = 'vc_number_tag_normal vc_tooltip_' + hint.type;
368
369         if (hint.type == 'input') {
370                 span.classList.add('vc_tip_tier_first');
371         } else if (rect.height > 30) {
372                 span.classList.add('vc_tip_tier_second');
373         } else {
374                 span.classList.add('vc_tip_tier_third');
375         }
376
377         hint.span = span;
378
379         /* appends hint to vc_hint_div container */
380         vc_hint_div.appendChild(hint.span);
381         vc_page_hints.push(hint);
382 }
383
384 /**
385  * nsResolver function that is used for resolving namespace in webpage document
386  *
387  * @param prefix  prefix of the namespace
388  *
389  * @return namespace url
390  */
391 function nsResolver(prefix) {
392         var namespace = {
393                 'xhtml' : 'http://www.w3.org/1999/xhtml' //add other namespaces if needed
394         };
395         return namespace[prefix] || null;
396 }
397
398 /**
399  * vc_generate_hints function creates hints for all clickable elements on web page
400  *
401  * @param win  window element (can be different if we analyse iframe)
402  */
403 function vc_generate_hints(win) {
404         vc_print_log('== start generate hints' + win);
405         vc_tag_index++;
406
407         /* if win is not passed assume the global window variable */
408         if (!win) {
409                 win = window;
410         }
411
412         var doc;
413
414         try {
415                 doc = win.document;
416         } catch (e) {
417                 vc_print_log('== some error occured in win.document' + e);
418                 return;
419         }
420
421         /* Custom pre process to generate hints */
422         vc_custom_pre_generate_hints();
423
424         var start = vc_page_hints.length;
425
426         vc_hint_div = doc.createElement('div');
427         vc_hint_div.id = 'vc_tooltip_area';
428         vc_hint_div.style.display = 'block';
429
430         vc_text_indicators = [];
431
432         /* return result as snapshot not iterator, due to problems with undefined objects */
433         vc_print_log('== start doc.evaluate');
434         var snapshot = doc.evaluate(vc_xpath_query, doc.body, nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
435         vc_print_log('== snapshot length : ' + snapshot.snapshotLength);
436
437         /* set current screen dimensions */
438         vc_scr = {
439                 top : 0,
440                 left : 0,
441                 bottom : win.innerHeight,
442                 right : win.innerWidth
443         };
444
445         /* analyse if a hint is needed for each returned object */
446         for (var i = 0; i < snapshot.snapshotLength; i++) {
447                 var element = snapshot.snapshotItem(i),
448                 rect = element.getBoundingClientRect();
449
450                 vc_made_hint = false;
451                 /* executed very rarely */
452                 if (rect.width === 0 || rect.height === 0) {
453                         for (var j = 0; j < element.childNodes.length; j++) {
454                                 if (element.childNodes[j].nodeType !== 1) {
455                                         continue;
456                                 }
457
458                                 var style = doc.defaultView.getComputedStyle(element.childNodes[j], null);
459                                 if (style && style.getPropertyValue('float') !== 'none' && vc_is_visible(element.childNodes[j], vc_scr)) {
460                                         vc_make_hint(element, element.childNodes[j]);
461                                         vc_made_hint = true;
462                                         break;
463                                 }
464                         }
465
466                         if (vc_made_hint) {
467                                 continue;
468                         }
469                 }
470
471                 if (vc_is_visible(element, vc_scr) && !element.attributes.disabled) {
472                         if ((element instanceof HTMLButtonElement || element.classList.contains('ui-btn') || element.getAttribute('role') == 'button')) {
473                                 if (element.textContent.trim().replace(/[ `~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').length > 0) {
474                                         vc_text_indicators[vc_text_indicators.length] = element;
475                                 } else {
476                                         vc_make_hint(element, element);
477                                         vc_made_hint = true;
478                                 }
479                         } else if (element.getAttribute('role') == 'radio' || element.getAttribute('role') == 'checkbox' || element.getAttribute('role') == 'combobox') {
480                                 vc_make_hint(element, element);
481                                 vc_made_hint = true;
482                         /* if the element is an anchor without text, make hint */
483                         } else if (element instanceof HTMLAnchorElement) {
484                                 if (element.textContent.trim().length > 0) {
485                                         vc_text_indicators[vc_text_indicators.length] = element;
486                                 }
487
488                                 var cStyle = window.getComputedStyle(element, false);
489                                 if (cStyle.backgroundImage !== 'none' && cStyle.backgroundImage !== 'inherit') {
490                                         vc_make_hint(element, element);
491                                         vc_made_hint = true;
492                                 } else if (element.textContent.trim().length == 0) {
493                                         /* if element has child with background or image element*/
494                                         if (!vc_made_hint) {
495                                                 var childs = element.querySelectorAll('*');
496                                                 for (var sp = 0; sp < childs.length; ++sp) {
497                                                         if (vc_is_visible(childs[sp], vc_scr)) {
498                                                                 var cstyle = win.getComputedStyle(childs[sp], false);
499                                                                 if (childs[sp].nodeName == 'IMG' || cstyle.overflow == 'hidden'
500                                                                         || (cstyle.backgroundImage !== 'none' && cstyle.backgroundImage !== 'inherit')) {
501                                                                         vc_make_hint(element, childs[sp]);
502                                                                         vc_made_hint = true;
503                                                                         break;
504                                                                 }
505                                                         }
506                                                 }
507                                         }
508
509                                         if (!vc_made_hint) {
510                                                 vc_make_hint(element, element);
511                                                 vc_made_hint = true;
512                                                 continue;
513                                         }
514                                 } else {
515                                         if (isNaN(element.textContent.trim())) {
516                                                 vc_find_img_element(element, null, element);
517                                         }
518                                 }
519                         } else if (element instanceof HTMLAreaElement || element.nodeName == 'INPUT') {
520                                 vc_make_hint(element, element);
521                         } else {
522                                 vc_find_img_element(element, null, element);
523                                 if (vc_made_hint == false) {
524                                         vc_make_hint(element, element);
525                                 }
526                         }
527                 }
528         }
529
530         /* append whole div with hints to body */
531         if (doc.body) {
532                 doc.body.insertBefore(vc_hint_div, doc.body.firstChild);
533
534                 //append all text indicators to body
535                 vc_docs.push({
536                         doc : doc,
537                         start : start,
538                         end : vc_page_hints.length - 1
539                 });
540         }
541
542         /* analyse iframes of the website */
543         if (win === window) {
544                 var frames = document.querySelectorAll('iframe');
545                 for (var f = 0; f < frames.length; f++) {
546                         var elem;
547                         try {
548                                 elem = frames[f].contentWindow.document;
549                         } catch (e) {
550                                 vc_bad_iframes.push(frames[f]);
551                                 continue;
552                         }
553                         vc_scr = {
554                                 top : 0,
555                                 left : 0,
556                                 bottom : win.innerHeight,
557                                 right : win.innerWidth
558                         };
559                         if (elem == undefined) {
560                                 vc_bad_iframes.push(frames[f]);
561                                 continue;
562                         }
563                         if (elem != undefined && !vc_is_visible(frames[f], vc_scr)) {
564                                 continue;
565                         }
566                         // vc_generate_hints(frames[f].contentWindow);
567                 }
568         }
569
570         vc_flag_hint_exist = true;
571         vc_print_log('== end');
572 }
573
574 /**
575  * vc_find_img_element function find element containing image. if found then call a function to make a tooltip.
576  *
577  * @param elem  element to search for text
578  * @param parent  parent element of the @elem
579  * @param snapshotElem  the first @elem when vc_generate_hints calls this function
580  */
581 function vc_find_img_element(elem, parent, snapshotElem) {
582         if (!vc_made_hint) {
583                 if (elem.nodeType == 1) {
584                         var cStyle = document.defaultView.getComputedStyle(elem, false);
585                         if ((vc_is_visible(elem, vc_scr) && cStyle && cStyle.backgroundImage != 'none' && cStyle.backgroundImage != 'inherit' || elem.nodeName == 'IMG')) {
586                                 vc_make_hint(snapshotElem, elem);
587                                 vc_made_hint = true;
588                                 return;
589                         }
590                 }
591
592                 var children = elem.childNodes;
593                 for (var ch = 0; !vc_made_hint && ch < children.length; ch++) {
594                         vc_find_img_element(children[ch], elem, snapshotElem);
595                 }
596         }
597
598 }
599
600 /**
601  * vc_show_hints function displays hints numbering from 1
602  */
603 function vc_show_hints() {
604         /* Custom pre process to show hints */
605         vc_custom_pre_show_hints();
606
607         if (vc_flag_log == true) {
608                 if (vc_asr_result == undefined) {
609                         vc_asr_result = document.createElement('div');
610                         vc_asr_result.id = 'vc_asr_result';
611                         vc_asr_result.innerHTML = 'ASR Result';
612                         document.body.appendChild(vc_asr_result);
613                 }
614
615                 if (vc_rec_result == undefined) {
616                         vc_rec_result = document.createElement('div');
617                         vc_rec_result.id = 'vc_rec_result';
618                         document.body.appendChild(vc_rec_result);
619                 }
620         }
621
622         vc_hint_num = 1;
623         for (var d = 0; d < vc_docs.length; d++) {
624                 var doc = vc_docs[d];
625                 for (var i = doc.start; i <= doc.end; i++) {
626                         var win = doc.doc.defaultView,
627                         hint = vc_page_hints[i],
628                         rect = hint.child.getClientRects()[0];
629
630                         vc_scr = {
631                                 top : 0,
632                                 left : 0,
633                                 bottom : win.innerHeight,
634                                 right : win.innerWidth
635                         };
636
637                         hint.span.style.display = 'block';
638
639                         if (null == rect) {
640                                 continue;
641                         }
642
643                         var leftPos,
644                         topPos,
645                         position_factor_top,
646                         position_factor_left;
647
648                         if (vc_flag_conflict) {
649                                 position_factor_top = 18;
650                                 position_factor_left = 18;
651                                 hint.span.className = 'vc_text_indicator_conflict_normal vc_tooltip_normal vc_tip_tier_second';
652                         } else {
653                                 position_factor_top = 15;
654                                 position_factor_left = 15;
655                         }
656
657                         if (rect.top < position_factor_top) {
658                                 topPos = win.pageYOffset;
659                         } else {
660                                 topPos = rect.top + win.pageYOffset - position_factor_top;
661                         }
662
663                         if (rect.left < position_factor_left) {
664                                 leftPos = win.pageXOffset;
665                         } else {
666                                 leftPos = rect.left + win.pageXOffset - position_factor_left;
667                         }
668
669                         if (hint.type == 'area') {
670                                 coord = hint.elem.coords.split(',');
671                                 leftPos = parseFloat(leftPos) + parseFloat(coord[0]);
672                                 topPos = parseFloat(topPos) + parseFloat(coord[1]);
673                         }
674                         hint.span.style.top = topPos + 'px';
675                         hint.span.style.left = leftPos + 'px';
676                         hint.span.textContent = vc_hint_num;
677
678                         hint.span.style.display = 'block';
679
680                         if (-1 == vc_visible_hints.indexOf(hint)) {
681                                 vc_visible_hints.push(hint);
682                         }
683
684                         vc_hint_num++;
685                 }
686         }
687
688         // for (var bf = 0; bf < vc_bad_iframes.length; ++bf) {
689         //      vc_result_highlight(vc_bad_iframes[bf]);
690         // }
691 }
692
693 /**
694  * vc_remove_hints function removes all hints in the web page. It deletes both visible and hidden hints
695  */
696 function vc_remove_hints() {
697         /* Custom pre process to remove hints */
698         vc_custom_pre_remove_hints();
699
700         vc_remove_highlight();
701
702         for (var d = 0; d < vc_docs.length; d++) {
703                 var doc = vc_docs[d].doc;
704                 var tooltipArea = doc.querySelector('#vc_tooltip_area');
705                 if (null !== tooltipArea && tooltipArea.parentNode) {
706                         tooltipArea.parentNode.removeChild(tooltipArea);
707                 }
708         }
709         vc_visible_hints = [];
710         vc_page_hints = [];
711         vc_docs = [];
712
713         /** if the rotation occured refresh the window information */
714         vc_scr = {
715                 top : 0,
716                 left : 0,
717                 bottom : window.innerHeight,
718                 right : window.innerWidth
719         };
720
721         vc_hint_div = null;
722         vc_flag_hint_exist = false;
723         vc_flag_conflict = false;
724 }
725
726 /**
727  * vc_hide_hints function hides the hints from the screen. Hints elements still exist
728  */
729 function vc_hide_hints(focusedExist) {
730         /* Custom pre process to hide hints */
731         if (true != focusedExist) {
732                 vc_custom_pre_hide_hints();
733         }
734
735         for (var i = 0; i < vc_visible_hints.length; i++) {
736                 var hint = vc_visible_hints[i];
737                 if (hint.span.classList.contains('vc_tooltip_focus') == false) {
738                         hint.span.style.display = 'none';
739                         hint.span.style.top = 0;
740                         hint.span.style.left = 0;
741                 }
742         }
743 }
744
745 /**
746  * vc_remove_popup function removes popup.
747  * This function is safe to call if the popup doesnt exist.
748  */
749 function vc_remove_popup() {
750         var node = document.querySelector('#vc_popup');
751         if (null !== node && node.parentNode) {
752                 node.parentNode.removeChild(node);
753         }
754 }
755
756 /**
757  * vc_show_popup function displays a floating div over the web page with text in it for timout milliseconds
758  *
759  * @param text  text to be shown on the popup
760  * @param timeout  time for which the popup should be shown in milliseconds. If timeout is 0 popup must be deleted manually
761  */
762 function vc_show_popup(text, timeout) {
763         /* remove any existing popup */
764         vc_remove_popup();
765
766         /* overlay creates a light grey area over the whole website */
767         var overlay = document.createElement('div');
768         overlay.id = 'vc_popup';
769
770         /* vcpopup is the main popup window, that is centered over the overlay */
771         var vcpopup = document.createElement('div');
772         vcpopup.id = 'vc_popup_content';
773
774         /* content is used to display text and center it vertically inside vcpopup */
775         var content = document.createElement('div');
776         content.style.display = 'table-cell';
777         content.style.fontFamily = '"Open Sans", "Helvetica", sans-serif';
778         content.style.verticalAlign = 'middle';
779         content.innerHTML = text;
780
781         vcpopup.appendChild(content);
782         overlay.appendChild(vcpopup);
783         document.body.appendChild(overlay);
784
785         /* if timeout is set to 0, display popup until not deleted manually */
786         if (timeout !== 0) {
787                 setTimeout(function () {
788                         vc_remove_popup();
789                 }, timeout);
790         }
791
792         return;
793 }
794
795 /**
796  * vc_remove_highlight removes highlight from conflicting links
797  *
798  * @param selectedNum  the number of target tooltip
799  */
800 function vc_remove_highlight(selectedNum) {
801         if (selectedNum) {
802                 var high = document.querySelectorAll('#vc_highlight');
803                 for (var cn = 0; cn < high.length; cn++) {
804                         if ((cn + 1) != selectedNum) {
805                                 high[cn].parentNode.removeChild(high[cn]);
806                         }
807                 }
808         } else {
809                 var highlightArea = document.querySelector('#vc_highlight_area');
810                 if (highlightArea) {
811                         highlightArea.parentNode.removeChild(highlightArea);
812                 }
813         }
814 }
815
816 /**
817  * vc_result_highlight creates highlight box over elem
818  *
819  * @param elem  element to be highlighted
820  */
821 function vc_result_highlight(elem) {
822         var doc = elem.ownerDocument,
823         rect;
824
825         if (vc_is_visible(elem) == false && elem.querySelector('img')) {
826                 rect = elem.querySelector('img').getClientRects()[0];
827         } else {
828                 rect = elem.getClientRects()[0];
829         }
830
831         if (!rect) {
832                 return;
833         }
834
835         vc_high_div = document.querySelector('#vc_highlight_area');
836
837         if (!vc_high_div) {
838                 vc_high_div = doc.createElement('div');
839                 vc_high_div.id = 'vc_highlight_area';
840                 doc.body.appendChild(vc_high_div);
841         }
842
843         var high_span = doc.createElement('div');
844         high_span.id = 'vc_highlight';
845
846         /* top left position of the element */
847         var leftPos = (rect.left > vc_scr.left ? rect.left : vc_scr.left);
848         var topPos = (rect.top > vc_scr.top ? rect.top : vc_scr.top);
849
850         /* adjust top left position with page scroll */
851         topPos += window.pageYOffset - 3;
852         leftPos += window.pageXOffset - 3;
853
854         high_span.style.left = leftPos + 'px';
855         high_span.style.top = topPos + 'px';
856         high_span.style.width = rect.width + 'px';
857         high_span.style.height = (rect.height + 6) + 'px';
858
859         /* if element's dimensions are 0x0 create highlight for it's children */
860         if (rect.width === 0 || rect.height === 0) {
861                 var height = topPos + rect.height;
862                 var width = leftPos + rect.width;
863                 for (var i = 0; i < elem.children.length; i++) {
864                         var child = elem.children[i];
865                         var chRect = child.getClientRects()[0];
866                         if (!chRect) {
867                                 continue;
868                         }
869                         if (chRect.top + chRect.height > height) {
870                                 height = chRect.top + chRect.height;
871                         }
872                         if (chRect.left + chRect.width > width) {
873                                 width = chRect.left + chRect.width;
874                         }
875                 }
876                 high_span.style.height = height - topPos + 'px';
877                 high_span.style.width = width - leftPos + 'px';
878         }
879
880         vc_high_div.appendChild(high_span);
881 }
882
883 /**
884  * vc_generate_conflict_hints function creates hints for all conflicting highlighted hints
885  */
886 function vc_generate_conflict_hints() {
887         vc_hint_div = document.querySelector('#vc_tooltip_area');
888
889         if (!vc_hint_div) {
890                 vc_hint_div = document.createElement('div');
891                 vc_hint_div.id = 'vc_tooltip_area';
892                 document.body.insertBefore(vc_hint_div, document.body.firstChild);
893         }
894
895         vc_scr = {
896                 top : 0,
897                 left : 0,
898                 bottom : window.innerHeight,
899                 right : window.innerWidth
900         };
901
902         /* Conflict links */
903         var conflicts = vc_conflict_links;
904
905         for (var i = 0; i < conflicts.length; i++) {
906                 var elem = conflicts[i];
907                 var rect;
908
909                 vc_result_highlight(elem);
910                 if (vc_is_visible(elem, vc_scr) == false && elem.querySelector('img') != null) {
911                         rect = elem.querySelector('img').getClientRects()[0];
912                 } else {
913                         rect = elem.getClientRects()[0];
914                 }
915
916                 if (!rect) {
917                         return;
918                 }
919
920                 var leftPos,
921                 topPos,
922                 position_factor_top = 20, //[TODO]move at proper place
923                 position_factor_left = 28,
924                 hint = {},
925                 span = document.createElement('span');
926                 span.id = 'vc_tooltip';
927
928                 if (rect.top < position_factor_top) {
929                         topPos = window.pageYOffset + 'px';
930                 } else {
931                         topPos = rect.top + window.pageYOffset - position_factor_top + 'px';
932                 }
933
934                 if (rect.left < position_factor_left) {
935                         leftPos = window.pageXOffset + 'px';
936                 } else {
937                         leftPos = rect.left + window.pageXOffset - position_factor_left + 'px';
938                 }
939
940                 /* tooltip style, !please keep styles sorted */
941                 hint.span = span;
942                 hint.span.style.top = topPos;
943                 hint.span.style.left = leftPos;
944                 vc_hint_div.appendChild(hint.span);
945
946                 hint.elem = elem;
947                 hint.child = vc_high_div.childNodes[i];
948                 vc_page_hints[vc_page_hints.length] = hint;
949         }
950
951         vc_docs.push({
952                 doc : document,
953                 start : 0,
954                 end : vc_page_hints.length - 1
955         });
956
957         vc_flag_hint_exist = true;
958         vc_flag_conflict = true;
959         vc_conflict_timer = setTimeout(vc_remove_hints, 5000);
960
961         vc_show_hints();
962 }
963
964 /**
965  * vc_trigger_event function makes custom DOM event
966  *
967  * @param node  target element taking event
968  * @param eventType  type of the custom event
969  */
970 function vc_trigger_event(node, eventType) {
971         try {
972                 var clickEvent = new Event(eventType);
973                 node.dispatchEvent(clickEvent);
974         } catch (e) {
975                 console.log('error ouccured', e);
976         }
977 }
978
979 /**
980  * vc_do_action function creates event for selected element.
981  *
982  * @param targetElem  selected element
983  * @param numberTag  number of selected tooltip
984  * @param value(option)  text entered into selected input element
985  *
986  * @return array including coordinates of the @targetElem and the number of targetElem.
987  */
988 function vc_do_action(targetElem, numberTag, value) {
989         vc_print_log('=== Inside vc_do_action');
990         vc_print_log(targetElem.elem.outerHTML);
991
992         var elem = targetElem.elem,
993         type = targetElem.type,
994         position,
995         effect;
996
997         if (!targetElem) {
998                 return;
999         }
1000
1001         /* Create click effect element */
1002         effect = document.createElement('div');
1003         effect.id = 'vc_click_effect';
1004
1005         if (numberTag != undefined) {
1006                 position = numberTag.getBoundingClientRect();
1007                 effect.style.left = (position.left + (position.width / 2) - 35) + 'px'
1008                 effect.style.top = (position.top + (position.height / 2) - 35) + 'px'
1009
1010                 numberTag.classList.add('vc_tooltip_focus');
1011                 numberTag.style.display = 'block';
1012
1013                 //conflicts
1014                 if (vc_flag_conflict) {
1015                         vc_remove_highlight(numberTag.textContent.trim());
1016                 }
1017                 vc_hide_hints(true);
1018         } else {
1019                 position = elem.getClientRects()[0];
1020                 effect.style.left = (position.left - 35) + 'px'
1021                 effect.style.top = (position.top - 35) + 'px'
1022
1023                 //text indicators
1024                 vc_result_highlight(elem);
1025                 elem.classList.add('vc_text_focus');
1026
1027                 vc_text_indicators[vc_text_indicators.length] = elem;
1028         }
1029
1030         document.body.insertBefore(effect, document.body.firstChild);
1031
1032         /* Occurring events */
1033         try {
1034                 if (type == 'input' && value != undefined) {
1035                         setTimeout(function () {
1036                                 elem.value = value;
1037                                 vc_trigger_event(elem, 'keyup');
1038                                 vc_trigger_event(elem, 'input');
1039                                 try {
1040                                         elem.form.submit();
1041                                 } catch (e) {
1042                                         console.log(e);
1043                                 }
1044
1045                                 document.body.removeChild(effect);
1046                                 vc_remove_hints();
1047                         }, 1500);
1048
1049                         return [0, 0, 0]
1050                 }
1051
1052                 setTimeout(function () {
1053                         if (vc_asr_result != undefined) {
1054                                 vc_asr_result.parentElement.removeChild(vc_asr_result);
1055                                 vc_asr_result = undefined;
1056                         }
1057                         if (vc_rec_result != undefined) {
1058                                 vc_rec_result.parentElement.removeChild(vc_rec_result);
1059                                 vc_rec_result = undefined;
1060                         }
1061
1062                         if (numberTag == undefined) {
1063                                 elem.classList.remove('vc_text_focus');
1064                         }
1065
1066                         document.body.removeChild(effect);
1067                         vc_remove_hints();
1068
1069                         elem.blur();
1070                         elem.focus();
1071
1072                         vc_print_log('=== Click Finish');
1073                 }, 2000);
1074
1075                 var rect = elem.getClientRects()[0],
1076                 x = rect.left + (rect.width / 2),
1077                 y = rect.top + (rect.height / 2);
1078                 if (null == rect) {
1079                         vc_print_log('[ERROR] Target element is not valid')
1080                         return [-1, 0, 0];
1081                 }
1082
1083                 if (x < 0) {
1084                         x = 0;
1085                 }
1086                 if (y < 0) {
1087                         y = 0;
1088                 }
1089                 return [1, x / window.innerWidth, y / window.innerHeight];
1090         } catch (e) {
1091                 console.log(e);
1092                 return [-1, 0, 0];
1093         }
1094 }
1095
1096 /**
1097  * vc_click function triggers click on element connected to cmd and param. Assumption is made that tooltips are numbers!
1098  *
1099  * @param cmd  tooltip tag number from voice-control
1100  * @param param  text parameter from voice-control
1101  */
1102 function vc_click(cmd, param) {
1103         vc_print_log('== start click cmd = ' + cmd + ', param = ' + param + ', visible tags = ' + vc_visible_hints.length);
1104
1105         if (vc_flag_log == true) {
1106                 if (vc_asr_result != undefined) {
1107                         vc_asr_result.innerHTML = param;
1108                 }
1109
1110                 setTimeout(function () {
1111                         if (vc_asr_result != undefined) {
1112                                 vc_asr_result.parentElement.removeChild(vc_asr_result);
1113                                 vc_asr_result = undefined;
1114                         }
1115                         if (vc_rec_result != undefined) {
1116                                 vc_rec_result.parentElement.removeChild(vc_rec_result);
1117                                 vc_rec_result = undefined;
1118                         }
1119                 }, 2500);
1120         }
1121
1122         /* pre-defined rule checker */
1123         if (vc_check_web_control(param) == true) {
1124                 vc_remove_hints();
1125
1126                 return [0, 0, 0];
1127         }
1128
1129         // if cmd has a numerical value
1130         if (isNaN(cmd) == false) {
1131                 vc_print_log('== numbering tag click');
1132
1133                 // when cmd is floating point value without parameter
1134                 // search exactly the same text
1135                 if (Number.isInteger(cmd) == false && param == '') {
1136                         for (var i = 0; i < vc_text_indicators.length; ++i) {
1137                                 if (vc_text_indicators[i].textContent.trim().indexOf(cmd) != -1) {
1138                                         return vc_do_action({
1139                                                 elem : vc_text_indicators[i]
1140                                         });
1141                                 }
1142                         }
1143
1144                         var list = vc_selector([cmd.toString()]);
1145
1146                         for (var i = 0; i < list.length; i++) {
1147                                 if (list[i].childElementCount == 0 && list[i].textContent.trim().indexOf(cmd) != -1) {
1148                                         return vc_do_action({
1149                                                 elem : list[i]
1150                                         });
1151                                 }
1152                         }
1153                 }
1154
1155                 // when cmd is valid integer value
1156                 if (Number.isInteger(cmd) == true && cmd <= vc_visible_hints.length) {
1157                         var hint = vc_visible_hints[cmd - 1];
1158
1159                         // insert text into input element
1160                         if (hint.type === 'input' && param != '') {
1161                                 return vc_do_action(hint, hint.span, param);
1162                         } else if (param == '') {
1163                                 if (!vc_flag_conflict) {
1164                                         vc_conflict_links = [];
1165                                         vc_conflict_links.push(hint.elem);
1166
1167                                         for (var i = 0; i < vc_text_indicators.length; ++i) {
1168                                                 if (vc_text_indicators[i].textContent.trim() == cmd) {
1169                                                         vc_conflict_links.push(vc_text_indicators[i]);
1170                                                 }
1171                                         }
1172
1173                                         if (vc_conflict_links.length > 1) {
1174                                                 vc_remove_hints();
1175                                                 vc_generate_conflict_hints();
1176                                                 return [vc_conflict_links.length, 0, 0];
1177                                         }
1178                                 }
1179
1180                                 return vc_do_action(hint, hint.span);
1181                         }
1182                 }
1183
1184                 // when there is no matched tooltip
1185                 vc_remove_hints();
1186
1187                 return vc_search_text(cmd.toString().concat(' ', param).trim());
1188         } else {
1189                 vc_remove_hints();
1190
1191                 return vc_search_text(param);
1192         }
1193 }
1194
1195 /**
1196  * vc_search_text function search the element that include same text with @param.
1197  *
1198  * @param param  param from voice-control.
1199  */
1200 function vc_search_text(param) {
1201         /* phase 1. search full text in the webpage */
1202         /* first, compare with links in html documents */
1203         vc_print_log('=== start searching(text level)');
1204
1205         if (vc_flag_log == true) {
1206                 vc_rec_result.style.background = 'rgba(0, 200, 100, 1)';
1207         }
1208
1209         vc_scr = {
1210                 top : 0,
1211                 left : 0,
1212                 bottom : window.innerHeight,
1213                 right : window.innerWidth
1214         };
1215
1216         vc_conflict_links = [];
1217
1218         for (var i = 0; i < vc_text_indicators.length; ++i) {
1219                 if (vc_is_visible(vc_text_indicators[i], vc_scr, true) &&
1220                         vc_text_indicators[i].textContent.replace(/[ `~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').toLowerCase().indexOf(param.replace(/ /g, '').toLowerCase()) !== -1) {
1221                         vc_conflict_links.push(vc_text_indicators[i]);
1222                 }
1223         }
1224
1225         if (vc_conflict_links.length == 1) {
1226                 /* if there is one result */
1227                 return vc_do_action({
1228                         elem : vc_conflict_links[0]
1229                 });
1230         } else if (vc_conflict_links.length > 1) {
1231                 vc_generate_conflict_hints();
1232
1233                 return [vc_conflict_links.length, 0, 0];
1234         }
1235
1236         /* second, compare with whole text of elements in html documents */
1237         var resultTokenArr = param.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').split(' '),
1238         el = vc_selector(resultTokenArr),
1239         preStr = '******';
1240
1241         for (var i = 0; el.length > i; i++) {
1242                 var temp = el[i];
1243
1244                 if (temp.childElementCount === 0) {
1245                         var curStr = temp.textContent.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '');
1246                         if (curStr == preStr || vc_is_visible(temp) == false) {
1247                                 continue;
1248                         }
1249
1250                         preStr = curStr;
1251
1252                         vc_conflict_links.push(temp);
1253                 }
1254         }
1255
1256         if (vc_conflict_links.length == 1) {
1257                 return vc_do_action({
1258                         elem : vc_conflict_links[0]
1259                 });
1260         } else if (vc_conflict_links.length > 1) {
1261                 vc_generate_conflict_hints();
1262
1263                 return [vc_conflict_links.length, 0, 0];
1264         } else {
1265                 /*
1266                  * vc_search_word depend on the voice control language.
1267                  * This function increase the accuracy of the searching result using word and letter level searching.
1268                  * If the language is changed, the definition of the function will be changed by reloading the .js file.
1269                  */
1270                 temp = vc_search_word(param, true);
1271                 if (temp != undefined) {
1272                         return vc_do_action({
1273                                 elem : temp
1274                         });
1275                 } else {
1276                         //vc_show_popup('There is no such kind of string.<br>(' + param + ')', 1500);
1277                         vc_remove_hints();
1278
1279                         return [-1, 0, 0];
1280                 }
1281         }
1282 }
1283
1284 /**
1285  * vc_scroll_event_firing function move the scroll.
1286  *
1287  * @param evt  keyword to move the scroll.
1288  */
1289 function vc_scroll_event_firing(evt) {
1290         if (evt == 'DOWN') {
1291                 window.scrollBy(0, 500);
1292         } else if (evt == 'UP') {
1293                 window.scrollBy(0, -500);
1294         } else if (evt == 'TOP') {
1295                 window.scrollTo(0, 0);
1296         }
1297 }
1298
1299 /**
1300  * vc_print_html function print out log on vc_log_area and console for debug.
1301  * If vc_flag_log is not true, then the logs will only print on console.
1302  *
1303  * @param text  log text to print out.
1304  */
1305 function vc_print_log(text) {
1306         var d = new Date();
1307         var time = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + ':' + d.getMilliseconds();
1308         console.log(time, '[', vc_print_log.caller.name, ']', text);
1309
1310         if (vc_flag_log == true) {
1311                 vc_log_area.value += time + ' [' + vc_print_log.caller.name + '] ' + text + '\n';
1312         }
1313 }
1314
1315 /**
1316  * vc_print_html function print out raw source of the html document for debug.
1317  */
1318 function vc_print_html() {
1319         if (vc_html_area == undefined) {
1320                 vc_html_area = document.createElement('textarea');
1321                 vc_html_area.disabled = true;
1322                 vc_html_area.id = 'vc_html_area';
1323
1324                 document.body.appendChild(vc_html_area);
1325
1326                 vc_html_area.value = location.href.toString() + '\n' + document.querySelector('html').innerHTML;
1327         } else {
1328                 document.body.removeChild(vc_html_area);
1329                 vc_html_area = undefined;
1330         }
1331 }
1332
1333 /**
1334  * vc_search_text function is called by voice-control-webview.cpp.
1335  * this function call some group of functions refered to @phase.
1336  *
1337  * @param phase  key value to call a group of functions.
1338  * @param data  function data from voice-control-webview.cpp.
1339  */
1340 function vc_request_action(phase, data) {
1341         vc_print_log('phase :' + phase + ',data :' + data);
1342         if ('SHOW_TOOLTIP' == phase) {
1343                 clearTimeout(vc_conflict_timer);
1344
1345                 /* create & show tooltips to recognize the voice */
1346                 if (!vc_flag_conflict && false == vc_flag_hint_exist) {
1347                         vc_remove_hints();
1348                         vc_generate_hints();
1349                 }
1350                 vc_show_hints();
1351         } else if ('HIDE_TOOLTIP' == phase) {
1352                 /* hide tooltips */
1353                 if (!vc_flag_conflict) {
1354                         vc_hide_hints();
1355                 } else {
1356                         clearTimeout(vc_conflict_timer);
1357                         vc_conflict_timer = setTimeout(vc_remove_hints, 5000);
1358                 }
1359         } else if ('RESULT' == phase) {
1360                 /* do action by the result */
1361                 vc_all_elem = document.querySelectorAll('body *:not(script)');
1362                 var result = vc_correct_parameter(data);
1363
1364                 return vc_click(result.cmd, result.param);
1365         } else if ('REMOVE_TOOLTIP' == phase) {
1366                 clearTimeout(vc_conflict_timer);
1367                 vc_remove_hints();
1368         } else {
1369                 return false;
1370         }
1371         return true;
1372 }
1373
1374 /**
1375  * vc_selector function is a selector function to find the elements include whole text in @strArr.
1376  *
1377  * @param strArr  group of strings to find elements.
1378  *
1379  * ex) vc_selector(['abc', 'def']);
1380  */
1381 function vc_selector(strArr) {
1382         var result = [];
1383         for (var i = 0; i < vc_all_elem.length; i++) {
1384                 var temp = vc_all_elem[i].textContent.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '').toLowerCase();
1385                 var j;
1386
1387                 for (j = 0; j < strArr.length; j++) {
1388                         if (temp.includes(strArr[j].toLowerCase()) == false) {
1389                                 break;
1390                         }
1391                 }
1392
1393                 if (strArr.length == j && vc_is_visible(vc_all_elem[i], null, true)) {
1394                         result.push(vc_all_elem[i]);
1395                 }
1396         }
1397
1398         return result;
1399 }
1400
1401 /**
1402  * vc_get_url_path function returns url path of the view.
1403  *
1404  * @return part of the url(host name + path name). it is used to read page specific script.
1405  */
1406 function vc_get_url_path() {
1407         var hostName = document.location.hostname;
1408         var pathName = document.location.pathname;
1409
1410         pathName = pathName.replace(/\//gi, '.');
1411
1412         return hostName + '/' + pathName;
1413 }
1414
1415 /**
1416  * vc_get_conflict_status function returns the conflict status.
1417  *
1418  * @return 1 if vc_flag_conflict is true. Otherwise 0.
1419  */
1420 function vc_get_conflict_status() {
1421         if (vc_flag_conflict) {
1422                 return 1;
1423         }
1424
1425         return 0;
1426 }
1427
1428 /**
1429  * vc_set_make_tooltip function sets the vc_flag_make_tooltip.
1430  *
1431  * @param makeTooltip  If it is 1, then set vc_flag_make_tooltip as true. Otherwise false.
1432  */
1433 function vc_set_make_tooltip(makeTooltip) {
1434         if (1 == makeTooltip) {
1435                 vc_flag_make_tooltip = true;
1436         } else {
1437                 vc_flag_make_tooltip = false;
1438         }
1439 }
1440
1441 /**
1442  * vc_init function initialize some elements and styles to use voice control.
1443  */
1444 function vc_init() {
1445         /* log element initialize */
1446         if (vc_flag_log) {
1447                 vc_log_area.disabled = true;
1448                 vc_log_area.id = 'vc_log_area';
1449                 vc_log_area.style.visibility = 'hidden';
1450
1451                 document.body.appendChild(vc_log_area);
1452         }
1453
1454         /* add tooltip style element */
1455         var vc_style_node = document.createElement('style');
1456         var vc_style_text = document.createTextNode(
1457                         '#vc_tooltip_area {\
1458                                 left : 0px;\
1459                                 position : absolute;\
1460                                 pointer-events: none;\
1461                                 top : 0px;\
1462                                 z-index : 2147483647;\
1463                         }\
1464                         #vc_html_area, #vc_log_area {\
1465                                 background-color : rgba(0, 0, 0, 0.5) !important;\
1466                                 color : white !important;\
1467                                 font-size : 14px;\
1468                                 height : 600px;\
1469                                 left : 50px;\
1470                                 padding : 10px 10px 10px 10px;\
1471                                 position : fixed;\
1472                                 top : 50px;\
1473                                 width : 800px;\
1474                                 z-index : 2147483647;\
1475                         }\
1476                         #vc_popup_content {\
1477                                 background-color : #87cff7;\
1478                                 bottom : 0px;\
1479                                 border-radius : 20px;\
1480                                 box-shadow : 0 2px 6px rgba(0, 0, 0, 0.3), 0 3px 8px rgba(0, 0, 0, 0.2);\
1481                                 color : white;\
1482                                 display : table;\
1483                                 font-size : 1.5em;\
1484                                 height : 100px;\
1485                                 left : 0px;\
1486                                 line-height : 1.5em;\
1487                                 margin : auto;\
1488                                 opacity : 1;\
1489                                 overflow : hidden;\
1490                                 position : absolute;\
1491                                 right : 0px;\
1492                                 text-align : center;\
1493                                 top : 0px;\
1494                                 width : 500px;\
1495                                 z-index : 2147483647;\
1496                         }\
1497                         #vc_popup {\
1498                                 background-color : rgba(0,0,0,0.2);\
1499                                 bottom : 0px;\
1500                                 left : 0px;\
1501                                 position : fixed;\
1502                                 right : 0px;\
1503                                 top : 0px;\
1504                                 z-index : 2147483647;\
1505                         }\
1506                         #vc_highlight_area {\
1507                                 left : 0px;\
1508                                 position : absolute;\
1509                                 pointer-events: none;\
1510                                 top : 0px;\
1511                                 z-index : 2147483646;\
1512                         }\
1513                         #vc_highlight {\
1514                                 border-radius: 5px;\
1515                                 font-size : 20px;\
1516                                 padding : 0 3px;\
1517                                 position : absolute;\
1518                                 pointer-events: none;\
1519                                 word-break : normal;\
1520                                 background-color: rgba(0, 234, 255, 0.2);\
1521                         }\
1522                         #vc_click_effect {\
1523                                 border-radius: 70px;\
1524                                 width: 70px;\
1525                                 height: 70px;\
1526                                 pointer-events: none;\
1527                                 position: fixed;\
1528                                 z-index : 2147483647;\
1529                                 background: linear-gradient(141deg, rgba(15, 185, 175, 0.6) 0%, rgba(30, 200, 220, 0.6) 51%, rgba(45, 180, 230, 0.6) 75%);\
1530                         }\
1531                         .vc_number_tag_normal {\
1532                                 border : 2px solid;\
1533                                 border-color : rgba(255, 255, 255, 0);\
1534                                 border-radius : 5px;\
1535                                 box-shadow : 0px 2px 2px rgba(0, 0, 0, 0.3);\
1536                                 position: absolute;\
1537                                 pointer-events: none;\
1538                                 text-align: center;\
1539                                 font-family: "Samsung0ne600";\
1540                                 color: #ffffff;\
1541                                 z-index : 2147483647;\
1542                                 word-break : normal;\
1543                         }\
1544                         .vc_text_indicator_conflict_normal {\
1545                                 border: 2px solid;\
1546                                 border-color: rgba(255, 255, 255, 0);\
1547                                 border-radius: 20px;\
1548                                 box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);\
1549                                 position: absolute;\
1550                                 pointer-events: none;\
1551                                 text-align: center;\
1552                                 color: #ffffff;\
1553                                 font-family: "Samsung0ne600";\
1554                                 z-index: 2147483647;\
1555                         }\
1556                         .vc_tooltip_focus {\
1557                                 border-color: rgba(255, 255, 255, 1);\
1558                         }\
1559                         .vc_text_focus {\
1560                                 color: #ff0000 !important;\
1561                                 font-weight: bolder !important;\
1562                         }\
1563                         #vc_asr_result {\
1564                                 background : rgba(0, 0, 0, 0.8);\
1565                                 border-radius : 20px;\
1566                                 color : white;\
1567                                 font-size : 25px;\
1568                                 height : 35px;\
1569                                 padding-top : 10px;\
1570                                 padding-bottom : 10px;\
1571                                 position : absolute;\
1572                                 text-align : center;\
1573                                 top : 10px;\
1574                                 right : 10px;\
1575                                 width : 550px;\
1576                                 z-index : 2147483647;\
1577                         }\
1578                         #vc_rec_result {\
1579                                 border-radius : 40px;\
1580                                 height : 40px;\
1581                                 position : absolute;\
1582                                 top : 17px;\
1583                                 right : 510px;\
1584                                 width : 40px;\
1585                                 z-index : 2147483647;\
1586                         }\
1587                         .vc_tooltip_input {\
1588                                 background-color : rgba(60, 140, 250, 0.75);\
1589                         }\
1590                         .vc_tooltip_normal, .vc_tooltip_area {\
1591                                 background-color : rgba(60, 185, 165, 0.75);\
1592                         }\
1593                         .vc_tip_tier_first {\
1594                                 font-size: 22px;\
1595                                 line-height: 24px;\
1596                                 width: 32px;\
1597                                 height: 26px;\
1598                         }\
1599                         .vc_tip_tier_second {\
1600                                 font-size: 19px;\
1601                                 line-height: 22px;\
1602                                 width: 28px;\
1603                                 height: 22px;\
1604                         }\
1605                         .vc_tip_tier_third {\
1606                                 font-size: 14px;\
1607                                 line-height: 16px;\
1608                                 width: 21px;\
1609                                 height: 16px;\
1610                         }\
1611                         @keyframes vc_tooltip_show {\
1612                                 0% {\
1613                                         opacity: 0;\
1614                                 }\
1615                                 100% {\
1616                                         opacity: 1;\
1617                                 }\
1618                         }\
1619                         @keyframes vc_tooltip_click {\
1620                                 0% {\
1621                                         box-shadow: 0 0 8px 6px rgba(60, 220, 180, 0), 0 0 0px 0px rgba(255,255,255,1), 0 0 0px 0px rgba(60, 220, 180, 0);\
1622                                 }\
1623                                 10% {\
1624                                         box-shadow: 0 0 8px 6px rgba(60, 220, 180, 1), 0 0 3px 5px rgba(255,255,255,1), 0 0 6px 10px rgba(60, 220, 180, 1);\
1625                                 }\
1626                                 100% {\
1627                                         box-shadow: 0 0 8px 6px rgba(60, 220, 180, 0), 0 0 0px 20px rgba(255,255,255,0.5), 0 0 0px 20px rgba(60, 220, 180, 0);\
1628                                 }\
1629                         }\
1630                         @keyframes vc_click_effect {\
1631                                 0% {\
1632                                         transform: scale(0.3, 0.3);\
1633                                         opacity: 0;\
1634                                 }\
1635                                 10% {\
1636                                         transform: scale(0.5, 0.5);\
1637                                         opacity: 0.5;\
1638                                 }\
1639                                 100% {\
1640                                         transform: scale(1, 1);\
1641                                         opacity: 1;\
1642                                 }\
1643                         }');
1644         vc_style_node.appendChild(vc_style_text);
1645         document.head.appendChild(vc_style_node);
1646
1647         var frames = window.frames;
1648
1649         for (var i = 0; i < frames.length; i++) {
1650                 try {
1651                         var doc = frames[i].document;
1652                         var vc_frame_style_node = doc.createElement('style');
1653                         var vc_frame_style_text = doc.createTextNode(vc_style_node.textContent);
1654
1655                         vc_frame_style_node.appendChild(vc_frame_style_text);
1656                         doc.head.appendChild(vc_frame_style_node);
1657                 } catch (e) {
1658                         continue;
1659                 }
1660         }
1661
1662         /* remove indicators on scroll */
1663         window.addEventListener('scroll', function () { //[TODO] need to remove the listener
1664                 vc_remove_hints();
1665         }, false);
1666 }
1667
1668 vc_init();