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