PageSourceSearch

https://xn--11bp4cjb9b0be1f.xn--h2brj9c/hi/dota.js?1790904156109

js xn--11bp4cjb9b0be1f.xn--h2brj9c collected 2026-10-08 12:40:32 UTC 196,166 bytes, 5,372 lines download raw bytes

1class Devnagri {
2  constructor() {
3    this.arr_nodes = {};
4    this.arr_translated_text = {};
5    this.document_url = "";
6    this.document_url_full = document.URL;
7    this.translation_api_retry_counter = 3;
8    this.missingTranslationPercentageOffsetForRetry = 8;
9    this.apiCounter = 0;
10    this.prevURL = '';
11    this.translationData = {};
12    this.objectMappingapiCounter = 0;
13    this.objectMappingData = {};
14    this.sentenceData = {};
15    this.prevSentenceData = [];
16    this.traversing_completion_timer;
17    this.translation_api_global_data = false;
18    this.translation_api_global_data_by_local_key;
19    this.default_lang_code;
20    this.source_lang_code;
21    this.target_lang_code;
22    this.meta_prefix = "DOTAMETA_";
23    this.webpage_language = (document.documentElement.lang == 'en') ? 'hi' : document.documentElement.lang;   
24    this.api_baseurl = `https://${window.location.hostname}/${this.webpage_language}/dotaapi`;
25    //this.api_baseurl = `http://proxy.devnagri.live/api`;
26    // this.cdn_css_link = "https://cdn.devnagri.com/css/devnagri_dota_mg_dev.css";
27    //this.cdn_css_link = "http://localhost:5500/devnagri_dota_merged_dev.css";
28    this.cdn_css_link =
29      `https://${window.location.hostname}/${this.webpage_language}/dota.css`;
30
31    this.login_api_url = `${this.api_baseurl}/auth/login`;
32    this.status_api_url = `${this.api_baseurl}/status`;
33    this.page_view_api_url = `${this.api_baseurl}/page-views`;
34    this.context_editor_api = `${this.api_baseurl}/save-translations`;
35    this.translation_api_url = "";
36    this.update_api_url = "";
37    this.api_key = "";
38
39    this.page_view_api_count = 0;
40
41    this.subdomainObjectStore;
42    this.lang;
43    this.should_render_ui;
44    this.update_global_data_timeout;
45    this.renderUICounter = 1;
46    this.user_lat = 0;
47    this.user_long = 0;
48    this.user_ip = "";
49    this.db = "";
50
51    this.traverse_whole_dom = true;
52
53    this.requested_domain = "";
54    this.domain = "";
55    this.linkedDomains = [];
56    this.config;
57
58    this.url_object = new URL(document.URL);
59    this.web_owner = false;
60    if (
61      this.url_object.searchParams.has("dota-token") &&
62      this.url_object.searchParams.has("language_code")
63    ) {
64      this.document_url = this.url_object.origin;
65      if (!this.document_url.endsWith("/")) {
66        this.document_url = this.document_url + "/";
67      }
68      this.web_owner = true;
69      this.dota_token = this.url_object.searchParams.get("dota-token");
70      this.selected_lang_code =
71        this.url_object.searchParams.get("language_code");
72    }
73
74    // check if page lang code exist..
75    if (localStorage.getItem("devnagri_source_lang_code")) {
76      this.source_lang_code = localStorage.getItem("devnagri_source_lang_code");
77    } else {
78      this.source_lang_code = "en";
79      localStorage.setItem("devnagri_source_lang_code", this.source_lang_code);
80    }
81    //check if default lang code exist..
82    if (localStorage.getItem("devnagri_default_lang_code")) {
83      this.default_lang_code = localStorage.getItem(
84        "devnagri_default_lang_code"
85      );
86    }
87
88    this.subscription_status_active;
89    this.enable_object_mapping = false;
90    this.subdomain_object_urls_hash_map = {};
91    this.subdomain_object_urls_hash_map_local = {};
92
93    this.enable_blacklist = false;
94    this.blacklist_ids = [];
95    this.blacklist_classes = [];
96
97    this.frame_ids = [
98      "nv_box_content-iframe_22196",
99      "nv_leadform_content-iframe_1810",
100    ];
101
102    this.frames_translation_status_map = {};
103    this.script_type = "live"; // proxy/live
104    this.status_api_global_data = {};
105
106    this.enable_object_mapping = false;
107    this.subdomain_object_urls_hash_map = {};
108    this.subdomain_object_urls_hash_map_local = {};
109
110    this.up_arrow_svg_content = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17px" height="17px" viewBox="0 0 17 17" version="1.1"><defs><filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%"> <feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="mask100"> <g filter="url(#alpha)"><rect x="0" y="0" width="17" height="17" style="fill:rgb(0%,0%,0%);fill-opacity:0.968627;stroke:none;"/> </g></mask><clipPath id="clip100"> <rect x="0" y="0" width="17" height="17"/></clipPath><g id="surface105" clip-path="url(#clip100)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 8.550781 5.761719 C 8.789062 5.746094 9.003906 5.808594 9.195312 5.949219 C 10.910156 7.433594 12.628906 8.910156 14.347656 10.386719 C 14.550781 10.703125 14.550781 11.023438 14.347656 11.339844 C 14.03125 11.644531 13.6875 11.683594 13.3125 11.457031 C 11.765625 10.144531 10.222656 8.824219 8.6875 7.496094 C 7.152344 8.824219 5.609375 10.144531 4.0625 11.457031 C 3.628906 11.707031 3.261719 11.632812 2.957031 11.238281 C 2.828125 10.941406 2.851562 10.65625 3.027344 10.386719 C 4.746094 8.910156 6.464844 7.433594 8.175781 5.949219 C 8.296875 5.867188 8.421875 5.804688 8.550781 5.761719 Z M 8.550781 5.761719 "/></g></defs><g id="surface100"><use xlink:href="#surface105" mask="url(#mask100)"/></g></svg>`;
111    this.devngari_logo_svg_content = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="30px" height="30px" viewBox="0 0 30 30" version="1.1"><defs><filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%"> <feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="mask0"> <g filter="url(#alpha)"><rect x="0" y="0" width="30" height="30" style="fill:rgb(0%,0%,0%);fill-opacity:0.960784;stroke:none;"/> </g></mask><clipPath id="clip1"> <rect x="0" y="0" width="30" height="30"/></clipPath><g id="surface5" clip-path="url(#clip1)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(27.843137%,60.392157%,83.137255%);fill-opacity:1;" d="M 12.679688 -0.0820312 C 14.171875 -0.0820312 15.664062 -0.0820312 17.15625 -0.0820312 C 18.871094 0.238281 20.5 0.839844 22.042969 1.722656 C 22.40625 2.699219 22.601562 3.707031 22.625 4.753906 C 22.519531 6.222656 22.296875 7.667969 21.960938 9.097656 C 15.101562 9.058594 8.253906 9.058594 1.410156 9.097656 C 2.898438 5.191406 5.605469 2.433594 9.53125 0.820312 C 10.578125 0.4375 11.628906 0.136719 12.679688 -0.0820312 Z M 12.679688 -0.0820312 "/></g><mask id="mask1"> <g filter="url(#alpha)"><rect x="0" y="0" width="30" height="30" style="fill:rgb(0%,0%,0%);fill-opacity:0.831373;stroke:none;"/> </g></mask><clipPath id="clip2"> <rect x="0" y="0" width="30" height="30"/></clipPath><g id="surface8" clip-path="url(#clip2)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(27.843137%,60.392157%,83.137255%);fill-opacity:1;" d="M 25.773438 4.835938 C 27.074219 5.988281 27.960938 7.410156 28.425781 9.097656 C 27.390625 9.015625 26.339844 9.015625 25.277344 9.097656 C 25.566406 7.691406 25.730469 6.273438 25.773438 4.835938 Z M 25.773438 4.835938 "/></g><mask id="mask2"> <g filter="url(#alpha)"><rect x="0" y="0" width="30" height="30" style="fill:rgb(0%,0%,0%);fill-opacity:0.956863;stroke:none;"/> </g></mask><clipPath id="clip3"> <rect x="0" y="0" width="30" height="30"/></clipPath><g id="surface11" clip-path="url(#clip3)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(27.843137%,60.392157%,83.137255%);fill-opacity:1;" d="M 28.921875 18.277344 C 26.078125 25.617188 20.664062 29.03125 12.679688 28.523438 C 6.808594 27.28125 2.886719 23.867188 0.910156 18.277344 C 0.507812 17.003906 0.34375 15.695312 0.414062 14.34375 C 0.382812 13.234375 0.492188 12.140625 0.746094 11.066406 C 7.
111652344 10.902344 14.558594 10.847656 21.464844 10.902344 C 21.019531 12.988281 20.523438 15.066406 19.972656 17.132812 C 19.09375 16.082031 18.152344 15.070312 17.15625 14.097656 C 14.941406 12.75 12.675781 12.695312 10.359375 13.933594 C 8.136719 15.09375 6.5625 16.8125 5.636719 19.097656 C 5.613281 22.628906 7.300781 25.007812 10.691406 26.230469 C 12.453125 26.613281 14.109375 26.339844 15.664062 25.410156 C 16.628906 24.671875 17.597656 23.933594 18.5625 23.195312 C 18.4375 23.839844 18.300781 24.496094 18.148438 25.164062 C 18.203125 25.273438 18.257812 25.382812 18.316406 25.492188 C 19.199219 25.875 20.082031 26.257812 20.96875 26.640625 C 22.261719 21.453125 23.535156 16.261719 24.777344 11.066406 C 26.214844 10.847656 27.652344 10.847656 29.089844 11.066406 C 29.339844 12.140625 29.449219 13.234375 29.417969 14.34375 C 29.492188 15.695312 29.324219 17.003906 28.921875 18.277344 Z M 28.921875 18.277344 "/></g><mask id="mask3"> <g filter="url(#alpha)"><rect x="0" y="0" width="30" height="30" style="fill:rgb(0%,0%,0%);fill-opacity:0.956863;stroke:none;"/> </g></mask><clipPath id="clip4"> <rect x="0" y="0" width="30" height="30"/></clipPath><g id="surface14" clip-path="url(#clip4)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(27.843137%,60.392157%,83.137255%);fill-opacity:1;" d="M 14.335938 15.328125 C 16.777344 14.933594 18.324219 15.890625 18.976562 18.195312 C 17.332031 20.972656 15.011719 22.992188 12.015625 24.261719 C 10.820312 24.847656 9.660156 24.792969 8.535156 24.097656 C 7.367188 22.707031 7.230469 21.203125 8.121094 19.589844 C 8.640625 18.695312 9.328125 17.957031 10.195312 17.378906 C 11.496094 16.511719 12.878906 15.832031 14.335938 15.328125 Z M 14.335938 15.328125 "/></g><mask id="mask4"> <g filter="url(#alpha)"><rect x="0" y="0" width="30" height="30" style="fill:rgb(0%,0%,0%);fill-opacity:0.898039;stroke:none;"/> </g></mask><clipPath id="clip5"> <rect x="0" y="0" width="30" height="30"/></clipPath><g id="surface17" clip-path="url(#clip5)"><path style=" stroke:none;fill-rule:evenodd;fill:rgb(17.647059%,49.803922%,72.941176%);fill-opacity:1;" d="M 0.910156 18.277344 C 2.886719 23.867188 6.808594 27.28125 12.679688 28.523438 C 20.664062 29.03125 26.078125 25.617188 28.921875 18.277344 C 27.480469 24.621094 23.558594 28.503906 17.15625 29.917969 C 15.664062 29.917969 14.171875 29.917969 12.679688 29.917969 C 6.277344 28.503906 2.351562 24.621094 0.910156 18.277344 Z M 0.910156 18.277344 "/></g></defs><g id="surface1"><use xlink:href="#surface5" mask="url(#mask0)"/><use xlink:href="#surface8" mask="url(#mask1)"/><use xlink:href="#surface11" mask="url(#mask2)"/><use xlink:href="#surface14" mask="url(#mask3)"/><use xlink:href="#surface17" mask="url(#mask4)"/></g></svg>`;
112    this.edit_button_svg_content = `<svg style="color: #3B85BA;pointer-events: none;" width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-edit-3"><path d="M12 20h9"></path><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path></svg>`;
113    this.seo_button_svg_content = `<svg style="fill: #EF6A16;pointer-events: none;" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 511.999 511.999" style="enable-background:new 0 0 511.999 511.999;" xml:space="preserve"><g><g><path d="M359.409,120.63c-10.387,0-20.155,4.045-27.5,11.391c-3.255,3.254-3.255,8.529-0.001,11.784c3.254,3.253,8.53,3.255,11.783,0.001c4.199-4.198,9.782-6.511,15.718-6.511c12.256,0,22.228,9.971,22.228,22.228v92.642c0,12.256-9.972,22.227-22.228,22.227c-12.256,0-22.228-9.971-22.228-22.227v-87.087c0-4.602-3.729-8.332-8.332-8.332c-4.603,0-8.332,3.731-8.332,8.332v87.087c0,21.445,17.446,38.891,38.892,38.891c21.446,0,38.892-17.446,38.892-38.891v-92.642C398.3,138.076,380.854,120.63,359.409,120.63z"/></g></g><g><g><path d="M283.083,274.391h-46.968v-60.216h29.415c4.603,0,8.332-3.731,8.332-8.332c0-4.602-3.729-8.332-8.332-8.332h-29.415v-60.216h46.968v-0.001c4.603,0,8.332-3.731,8.332-8.332c0-4.601-3.729-8.332-8.332-8.332h-55.3c-4.602,0-8.332,3.731-8.332,8.332v153.761c0,4.602,3.731,8.332,8.332,8.332h55.3c4.603,0,8.332-3.731,8.332-8.332S287.686,274.391,283.083,274.391z"/></g></g><g><g><path d="M149.684,197.51c-10.652,0-19.317-8.667-19.317-19.317v-21.58c0-10.653,8.665-19.318,19.317-19.318c10.652,0,19.318,8.667,19.318,19.318c0,4.602,3.731,8.332,8.332,8.332c4.601,0,8.332-3.731,8.332-8.332c0-19.84-16.141-35.983-35.983-35.983c-19.84,0-35.981,16.142-35.981,35.983v21.58c0,19.84,16.141,35.981,35.981,35.981c10.652,0,19.318,8.667,19.318,19.318v21.58c0,10.652-8.665,19.317-19.318,19.317c-10.652,0-19.317-8.667-19.317-19.317c0-4.602-3.731-8.332-8.332-8.332c-4.601,0-8.332,3.731-8.332,8.332c0,19.84,16.141,35.981,35.981,35.981c19.84,0,35.983-16.141,35.983-35.981v-21.58C185.666,213.652,169.525,197.51,
113149.684,197.51z"/></g></g><g><g><path d="M471.246,24.766H40.754C18.283,24.766,0,43.049,0,65.52v59.227c0,4.602,3.731,8.332,8.332,8.332c4.601,0,8.332-3.731,8.332-8.332V65.52c0-13.284,10.807-24.09,24.09-24.09h430.492c13.284,0,24.09,10.807,24.09,24.09v284.411h-52.21c-4.602,0-8.332,3.731-8.332,8.332s3.731,8.332,8.332,8.332h52.21v15.273c0,13.284-10.807,24.09-24.09,24.09h-155.41H196.164H40.754c-13.284,0-24.09-10.807-24.09-24.09v-15.273h398.688c4.602,0,8.332-3.731,8.332-8.332s-3.731-8.332-8.332-8.332H16.664V152.522c0-4.602-3.731-8.332-8.332-8.332c-4.601,0-8.332,3.73-8.332,8.332V381.87c0,22.472,18.283,40.754,40.754,40.754H183.54l-20.494,47.945h-40.034c-4.602,0-8.332,3.731-8.332,8.332s3.731,8.332,8.332,8.332h265.975c4.602,0,8.332-3.731,8.332-8.332s-3.731-8.332-8.332-8.332h-40.034l-20.494-47.945h142.786c22.472,0,40.754-18.282,40.754-40.754V65.52C512,43.049,493.717,24.766,471.246,24.766z M330.83,470.568H181.17l14.238-33.31h121.185L330.83,470.568z"/></g></g><g><g><path d="M262.924,379.679c-1.914-2.906-5.583-4.299-8.952-3.457c-3.517,0.879-6.116,4.048-6.291,7.67c-0.364,7.534,9.106,11.629,14.33,6.172C264.674,387.282,265.089,382.887,262.924,379.679z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>`;
114    this.close_button_svg_content = `<svg style="fill: #ED2408;pointer-events: none;" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 475.2 475.2" style="enable-background:new 0 0 475.2 475.2;" xml:space="preserve"><g><g><path d="M405.6,69.6C360.7,24.7,301.1,0,237.6,0s-123.1,24.7-168,69.6S0,174.1,0,237.6s24.7,123.1,69.6,168s104.5,69.6,168,69.6s123.1-24.7,168-69.6s69.6-104.5,69.6-168S450.5,114.5,405.6,69.6z M386.5,386.5c-39.8,39.8-92.7,61.7-148.9,61.7s-109.1-21.9-148.9-61.7c-82.1-82.1-82.1-215.7,0-297.8C128.5,48.9,181.4,27,237.6,27s109.1,21.9,148.9,61.7C468.6,170.8,468.6,304.4,386.5,386.5z"/><path d="M342.3,132.9c-5.3-5.3-13.8-5.3-19.1,0l-85.6,85.6L152,132.9c-5.3-5.3-13.8-5.3-19.1,0c-5.3,5.3-5.3,13.8,0,19.1l85.6,85.6l-85.6,85.6c-5.3,5.3-5.3,13.8,0,19.1c2.6,2.6,6.1,4,9.5,4s6.9-1.3,9.5-4l85.6-85.6l85.6,85.6c2.6,2.6,6.1,4,9.5,4c3.5,0,6.9-1.3,9.5-4c5.3-5.3,5.3-13.8,0-19.1l-85.4-85.6l85.6-85.6C347.6,146.7,347.6,138.2,342.3,132.9z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>`;
115    this.save_button_svg_content = `<svg style="fill: #52C7A5;pointer-events: none;"  version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 486 486" style="enable-background:new 0 0 486 486;" xml:space="preserve"><g><g><path d="M473.7,485.75c6.8,0,12.3-5.5,12.3-12.3v-359.8c0-3.6-1.6-7-4.3-9.3L363,2.85c-0.2-0.2-0.4-0.3-0.6-0.4c-0.3-0.2-0.5-0.4-0.8-0.6c-0.4-0.2-0.7-0.4-1.1-0.6c-0.3-0.1-0.6-0.3-0.9-0.4c-0.4-0.2-0.9-0.3-1.3-0.4c-0.3-0.1-0.6-0.2-0.9-0.2c-0.8-0.1-1.5-0.2-2.3-0.2H12.3C5.5,0.05,0,5.55,0,12.35v461.3c0,6.8,5.5,12.3,12.3,12.3h461.4V485.75z M384.5,461.25h-283v-184.1c0-3.7,3-6.6,6.6-6.6h269.8c3.7,0,6.6,3,6.6,6.6V461.25z M161.8,24.45h180.9v127.8c0,0.8-0.6,1.4-1.4,1.4h-178c-0.8,0-1.4-0.7-1.4-1.4V24.45H161.8z M24.6,24.45h112.8v127.8c0,14.3,11.6,25.9,25.9,25.9h178c14.3,0,25.9-11.6,25.9-25.9V38.75l94.2,80.6v341.9H409v-184.1c0-17.2-14-31.1-31.1-31.1H108.1c-17.2,0-31.1,14-31.1,31.1v184.2H24.6V24.45z"/><path d="M227.4,77.65h53.8v32.6c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-44.8c0-6.8-5.5-12.3-12.3-12.3h-66.1c-6.8,0-12.3,5.5-12.3,12.3S220.7,77.65,227.4,77.65z"/><path d="M304.5,322.85h-123c-6.8,0-12.3,5.5-12.3,12.3s5.5,12.3,12.3,12.3h123c6.8,0,12.3-5.5,12.3-12.3S311.3,322.85,304.5,322.85z"/><path d="M304.5,387.75h-123c-6.8,0-12.3,5.5-12.3,12.3s5.5,12.3,12.3,12.3h123c6.8,0,12.3-5.5,12.3-12.3S311.3,387.75,304.5,387.75z"/></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg>`;
116
117    //this.expiry_token_time = localStorage.getItem("devnagri_token_expiry_time");
118    this.edit_mode_enabled = false;
119    this.content_editable = [];
120
121    // meta editor variables
122    this.meta_count = 0;
123    this.metatag_arr = {};
124    this.metatag_arr.TITLE = {
125      tag: "TITLE",
126      engText: document.title,
127      translatedText: document.title,
128    };
129    this.metatag_key = "";
130
131    // sentence merging vars
132    this.enable_sentence_merging = false;
133    this.sentence_merging_initial_url_date = "2025-11-16T06:55:06.113Z";
134    this.sentence_merging_fallback_url_date = "2010-09-14T06:55:06.113Z";
135    this.sentence_nodes = {};
136    this.sentence_nodes_by_orig_text = {}
137    this.sentence_parents = ["P", "LI", "H1", "H2", "H3", "H4", "H5", "H6"];
138    this.sentence_children = ["#TEXT", "SPAN", "STRONG", "B", "I", "BR", "A"];
139
140    this.sentence_merge_separator_send = ' <span class="tag small tag-open tag-close">||</span> ';
141    this.sentence_merge_separator_receive = '<span class="tag small tag-open tag-close">||</span>';
142    // sentence merging vars end
143
144    // private variables for getters and setters
145    this._log_level = 0;
146    this._access_token = "";
147    this._default_lang_code = "";
148    this._selected_lang_code = "";
149    this._lang_status_map;
150    this._expiry_token_time = "";
151
152    this.print = this.print.bind(this);
153    this.initTranslation = this.initTranslation.bind(this);
154    this.startTraversingNow = this.startTraversingNow.bind(this);
155    this.addNodeToArray = this.addNodeToArray.bind(this);
156    this.checkNodeType = this.checkNodeType.bind(this);
157    this.traverseNodes = this.traverseNodes.bind(this);
158    this.checkIfTraversingCompleted =
159      this.checkIfTraversingCompleted.bind(this);
160
161    this.GetTranslationsApi = this.GetTranslationsApi.bind(this);
162
163    this.FormatTranslations = this.FormatTranslations.bind(this);
164    this.updateNodesWithTranslatedText =
165      this.updateNodesWithTranslatedText.bind(this);
166    this.sentenceUpdateApi = this.sentenceUpdateApi.bind(this);
167    this.translate = this.translate.bind(this);
168    this.setTranslatedTextToNode = this.setTranslatedTextToNode.bind(this);
169    this.setTranslatedTextToElement =
170      this.setTranslatedTextToElement.bind(this);
171    this.checkIfStringIsHindi = this.checkIfStringIsHindi.bind(this);
172    this.checkIfStringIsPunjabi = this.checkIfStringIsPunjabi.bind(this);
173    this.checkIfStringIsTamil = this.checkIfStringIsTamil.bind(this);
174    this.checkIfStringIsGujrati = this.checkIfStringIsGujrati.bind(this);
175    this.checkIfStringIsKannad = this.checkIfStringIsKannad.bind(this);
176    this.checkIfStringIsBengali = this.checkIfStringIsBengali.bind(this);
177    this.checkIfStringIsTelugu = this.checkIfStringIsTelugu.bind(this);
178    this.checkIfStringIsMalyalam = this.checkIfStringIsMalyalam.bind(this);
179    this.checkIfStringIsAssamese = this.checkIfStringIsAssamese.bind(this);
180    this.checkIfStringIsOdia = this.checkIfStringIsOdia.bind(this);
181    this.checkIfStringIsArabic = this.checkIfStringIsArabic.bind(this);
182    this.checkIfStringIsJapanese = this.checkIfStringIsJapanese.bind(this);
183    this.checkIfStringIsChinese = this.checkIfStringIsChinese.bind(this);
184    this.checkIfStringIsIndonesian = this.checkIfStringIsIndonesian.bind(this);
185    this.checkIfStringIsUrdu = this.checkIfStringIsUrdu.bind(this);
186
187    this.checkIfStringIsLocal = this.checkIfStringIsLocal.bind(this);
188
189    this.calculateMissingTranslationPercentage =
190      this.calculateMissingTranslationPercentage.bind(this);
191    this.updateGlobalData = this.updateGlobalData.bind(this);
192
193    this.callApiRequest = this.callApiRequest.bind(this);
194    this.authenticate = this.authenticate.bind(this);
195    this.loginApi = this.loginApi.bind(this);
196    this.subscriptionStatusApi = this.subscriptionStatusApi.bind(this);
197    this.get_user_location = this.get_user_location.bind(this);
198    this.openDropdown = this.openDropdown.bind(this);
199    this.openProxyDropdown = this.openProxyDropdown.bind(this);
200    this.setEventHandlerOfProxyDropDown =
201      this.setEventHandlerOfProxyDropDown.bind(this);
202    this.removeInternalLinkFromUrl = this.removeInternalLinkFromUrl.bind(this);
203    this.storeValuesInIndexDB = this.storeValuesInIndexDB.bind(this);
204    this.addValuesInIndexObject = this.addValuesInIndexObject.bind(this);
205    this.getValuesInIndexObject = this.getValuesInIndexObject.bind(this);
206    this.getParticularValueFromIndexDB =
207      this.getParticularValueFromIndexDB.bind(this);
208    this.traverseAndSetTranslationOfWholePage =
209      this.traverseAndSetTranslationOfWholePage.bind(this);
210    this.cleanString = this.cleanString.bind(this);
211    this.cleanExistingTranslationObj =
212      this.cleanExistingTranslationObj.bind(this);
213
214    this.replaceEnglishDomainWithLocalDomain =
215      this.replaceEnglishDomainWithLocalDomain.bind(this);
216
217    this.getLocalObjectUrl = this.getLocalObjectUrl.bind(this);
218    this.getLocalObjectAlt = this.getLocalObjectAlt.bind(this);
219    this.formatUrl = this.formatUrl.bind(this);
220    this.removeTrailingSlashesFromUrl =
221      this.removeTrailingSlashesFromUrl.bind(this);
222    this.domNodeInsertedHandler = this.domNodeInsertedHandler.bind(this);
223    this.translateAllFramesOnPage = this.translateAllFramesOnPage.bind(this);
224    this.cssLinkInjection = this.cssLinkInjection.bind(this);
225    this.isProxy = this.isProxy.bind(this);
226    this.isLiveJs = this.isLiveJs.bind(this);
227
228    this.checkAuthenticationToken = this.checkAuthenticationToken.bind(this);
229
230    this.renderTranslateUI = this.renderTranslateUI.bind(this);
231    this.activeLanguage = this.activeLanguage.bind(this);
232    this.onLangSelection = this.onLangSelection.bind(this);
233    this.removeExistingProxyDropdown =
234      this.removeExistingProxyDropdown.bind(this);
235
236    this.getObjectUrlsApi = this.getObjectUrlsApi.bind(this);
237    this.setDropdownPosition = this.setDropdownPosition.bind(this);
238    this.isTextTranslatedText = this.isTextTranslatedText.bind(this);
239    this.formatTranslationDataByLocalKey =
240      this.formatTranslationDataByLocalKey.bind(this);
241
242    this.isNodeASentence = this.isNodeASentence.bind(this);
243    this.isUrlLangStatusActive = this.isUrlLangStatusActive.bind(this);
244
245
246    this.setTranslatedContentToSentenceParent =
247        this.setTranslatedContentToSentenceParent.bind(this);
248
249    this.setTranslatedTextToSentenceMapChildren =
250        this.setTranslatedTextToSentenceMapChildren.bind(this);
251
252    this.setTranslatedContentToSentenceParent =
253        this.setTranslatedContentToSentenceParent.bind(this);
254
255    this.setTranslatedContentToSentenceNodes =
256        this.setTranslatedContentToSentenceNodes.bind(this);
257
258    this.getSentenceCombinedOriginalText = this.getSentenceCombinedOriginalText.bind(this);
259
260
261  }
262
263  get log_level() {
264    if (this._log_level) {
265      return this._log_level;
266    }
267    const logLevelFromLocalStorage = localStorage.getItem("log_level");
268    if (logLevelFromLocalStorage) {
269      const allowedLevels = [0, 1, 2, 3, 4];
270      if (!allowedLevels.includes(Number(logLevelFromLocalStorage))) {
271        console.warn(
272          `LOG_LEVEL ${logLevelFromLocalStorage} is not valid. Using default value: 0`
273        );
274        return 0;
275      }
276
277      this._log_level = logLevelFromLocalStorage;
278      return logLevelFromLocalStorage;
279    }
280    return 0;
281  }
282
283  set log_level(val) {
284    this._log_level = val;
285    localStorage.setItem("log_level", val);
286  }
287  get access_token() {
288    if (this._access_token) {
289      return this._access_token;
290    }
291    const tokenFromLocalStorage = localStorage.getItem("devnagri_access_token");
292    if (tokenFromLocalStorage) {
293      this._access_token = tokenFromLocalStorage;
294      return tokenFromLocalStorage;
295    }
296    return "";
297  }
298
299  set access_token(val) {
300    this._access_token = val;
301    localStorage.setItem("devnagri_access_token", val);
302  }
303
304  get expiry_token_time() {
305    if (this._expiry_token_time) {
306      return this._expiry_token_time;
307    }
308    const tokenExpiryTimeFromLocalStorage = localStorage.getItem("devnagri_token_expiry_time");
309    if (tokenExpiryTimeFromLocalStorage) {
310      this._expiry_token_time = tokenExpiryTimeFromLocalStorage;
311      return tokenExpiryTimeFromLocalStorage;
312    }
313    return "";
314  }
315
316  set expiry_token_time(val) {
317    this._expiry_token_time = val;
318    localStorage.setItem("devnagri_token_expiry_time", val);
319  }
320
321  get default_lang_code() {
322    if (this._default_lang_code) {
323      return this._default_lang_code;
324    }
325    const codeFromLocalStorage = localStorage.getItem(
326      "devnagri_default_lang_code"
327    );
328    if (codeFromLocalStorage) {
329      this._default_lang_code = codeFromLocalStorage;
330      return codeFromLocalStorage;
331    }
332    return "en";
333  }
334
335  set default_lang_code(val) {
336    this._default_lang_code = val;
337    localStorage.setItem("devnagri_default_lang_code", val);
338  }
339
340  get selected_lang_code() {
341    if (this._selected_lang_code) {
342      return this._selected_lang_code;
343    }
344    const codeFromLocalStorage = localStorage.getItem(
345      "devnagri_selected_lang_code"
346    );
347    if (codeFromLocalStorage) {
348      this._selected_lang_code = codeFromLocalStorage;
349      return codeFromLocalStorage;
350    }
351    return "en";
352  }
353
354  set selected_lang_code(val) {
355    this._selected_lang_code = val;
356    localStorage.setItem("devnagri_selected_lang_code", val);
357  }
358
359  get lang_status_map() {
360    if (this._lang_status_map) {
361      return this._lang_status_map;
362    }
363    const itemFromLocalStorage = localStorage.getItem(
364      "devnagri_lang_status_map"
365    );
366    if (itemFromLocalStorage) {
367      const parsedObj = JSON.parse(itemFromLocalStorage);
368      this._selected_lang_code = parsedObj;
369      return parsedObj;
370    }
371    return {};
372  }
373
374  set lang_status_map(val) {
375    this._lang_status_map = val;
376    localStorage.setItem("devnagri_lang_status_map", JSON.stringify(val));
377  }
378
379  isProxy() {
380    return this.script_type === "proxy";
381  }
382
383  isLiveJs() {
384    return this.script_type === "live";
385  }
386
387  // authenticate user by login and subscription status apis
388  async authenticate(apiKey) {
389    try {
390      let loginPromise = await this.loginApi(this.login_api_url, apiKey);
391      if (loginPromise) {
392        let subscriptionPromise = await this.subscriptionStatusApi(
393          this.status_api_url
394        );
395        if (subscriptionPromise.data.subscription === "ACTIVE") {
396          return subscriptionPromise;
397        }
398      }
399    } catch (err) {}
400  }
401
402  // this function is used for authentication
403  async loginApi(url, apiKey) {
404    try {
405      const res = await fetch(url, {
406        method: "POST",
407        headers: {
408          "Content-Type": "application/json",
409        },
410        body: JSON.stringify({
411          api_key: apiKey,
412        }),
413      });
414      const data = await res.json();
415      if (data.access_token) {
416        this.access_token = data.access_token;
417        let expires_in = new Date().getTime() * 1000 + data.expires_in;
418        this.expiry_token_time = expires_in;
419        if(this.isLiveJs()){
420          if(this.web_owner){
421            this.default_lang_code =  this.url_object.searchParams.get("language_code");
422          }else{
423            if(data.default_lang_code){
424              this.default_lang_code = data.default_lang_code
425            }
426          }
427        }
428        return data;
429      } else {
430        return false;
431      }
432    } catch (err) {
433      throw err;
434    }
435  }
436
437  // this function is used for injecting css link in case of live js
438  cssLinkInjection() {
439    return;
440    let cssFile = document.createElement("link");
441    cssFile.rel = "stylesheet";
442    cssFile.id = "dota_css";
443    cssFile.href = `${this.cdn_css_link}?${+new Date()}`;
444    // cssFile.href = `http://localhost:5500/devnagri_dota_merged_dev.css`;
445
446    document.head.appendChild(cssFile);
447  }
448
449  // wrapper function for api calls to handle auth errors
450  async callApiRequest(reqFunction) {
451    try {
452      return await reqFunction();
453    } catch (error) {
454      // handle auth error
455      if (
456        error &&
457        error.response &&
458        [401, 403, "401", "403"].includes(error.response.status)
459      ) {
460        const authResponse = await this.authenticate(this.api_key);
461        if (authResponse) {
462          return await reqFunction();
463        }
464      } else {
465        throw error;
466      }
467    }
468  }
469
470  // remove nbsp from string
471  replaceNbsps(str) {
472    let re = new RegExp(String.fromCharCode(160), "g");
473    return str.replace(re, " ");
474  }
475
476  formatUrl(url = "") {
477    let trimmedUrl = url.trim();
478    return this.removeTrailingSlashesFromUrl(trimmedUrl);
479  }
480
481  removeTrailingSlashesFromUrl(url) {
482    if (url.endsWith("/")) {
483      return this.removeTrailingSlashesFromUrl(url.slice(0, -1));
484    }
485    return url;
486  }
487
488  isExactMatch(str, match) {
489    return new RegExp(`\\b${this.escapeRegExpMatch(match)}\\b`).test(str)
490  }
491
492  compareArrays = (a, b) => 
493    a.length === b.length && a.every((element, index) => element === b[index]);
494
495  escapeRegExpMatch(s) {
496    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
497  }
498
499  keepOnlyAlphabets(str) {
500    let re = new RegExp(/[^a-zA-Z]/g);
501    return str.replace(re, "");
502  }
503
504  removeExtraSpacesInMiddle(str){
505    if(str){
506      let str1 = str.replace(/(\r\n|\n|\r|\t)/gm, " ");
507      //let str2 = str1.replace(/[^\x20-\x7E]/gmi, "");;
508      let str2 = str1.replace(/[^\x20-\x7E™®©₹]/gmi, "");
509      return str2.replace(/ +/g, ' ');
510    }
511    return str
512  }
513
514
515  cleanString(str = "", trim = true) {
516    let outputString = str;
517    let removeNbspRegEx = new RegExp(String.fromCharCode(160), "g");
518    outputString = outputString.replace(removeNbspRegEx, " ");
519    outputString = outputString.replace(new RegExp("/<!--.*-->/s", "g"), "");
520    outputString = outputString.replace(new RegExp("~<!--(.*?)-->~s", "g"), "");
521    outputString = outputString.replace(new RegExp("~<!--(.*?)-->~s", "g"), "");
522    outputString = outputString.replace(
523      new RegExp("/<!--(.|s)*?-->/", "g"),
524      ""
525    );
526    outputString = outputString.replace(
527      new RegExp("/<!--(.|s)*?-->/", "g"),
528      ""
529    );
530    outputString = outputString.replace("\n", "");
531    outputString = outputString.replace("\r", "");
532    outputString = outputString.replace("\t", "");
533    outputString = outputString.replace("\xc2\xa0", "");
534    outputString = outputString.replace(
535      new RegExp("/^[^a-zA-Z0-9]+$/", "g"),
536      ""
537    );
538    outputString = outputString.replace(new RegExp("/^d+$/", "g"), "");
539    outputString = outputString.replace(
540      new RegExp("/^[^a-zA-Z0-9]+d+$/", "g"),
541      ""
542    );
543    outputString = this.removeExtraSpacesInMiddle(outputString)
544    if (trim) {
545      outputString = outputString.trim();
546    }
547    outputString = outputString.length > 0 ? outputString : "";
548
549    if (isNaN(outputString)) {
550      return outputString;
551    } else {
552      return "";
553    }
554    // return outputString;
555  }
556
557  removeCurrencyFromText(str) {
558    let re = new RegExp(/[0-9.,%k]/g);
559    return str.replace(re, "");
560  }
561
562  removeSpecialCharacters(str) {
563    let re = new RegExp(/[^a-zA-Z0-9]/g);
564    return str.replace(re, "");
565  }
566
567  cleanExistingTranslationObj = (exitingObj) => {
568    const newObj = {};
569    Object.keys(exitingObj).forEach((key) => {
570      newObj[this.cleanString(key)] = exitingObj[key];
571    });
572    return newObj;
573  };
574
575  removeInternalLinkFromUrl(url = "", keepQueryParams = false) {
576    const hashIndex = url.indexOf("#");
577    const questionIndex = url.indexOf("?");
578    const internalLinkExist = hashIndex > 0;
579    const queryExist = questionIndex > 0;
580    const queryIsAfterInternalLink = questionIndex > hashIndex;
581    if (internalLinkExist) {
582      if (keepQueryParams && queryExist && queryIsAfterInternalLink) {
583        return url.slice(0, hashIndex) + url.slice(questionIndex, url.length);
584      }
585
586      return url.slice(0, hashIndex);
587    }
588    return url;
589  }
590
591  // this function is used to add english text as key in object(this.arr_nodes)
592  addNodeToArray(
593    text,
594    node,
595    isNodeASentenceChildren = false,
596    sentenceParentId = "",
597    subSentencePosition,
598    attributeKeyName=""
599  ) {
600
601    if(this.globalCheckIfStringIsLocal(text)){
602      return ;
603    }
604    
605    if (text.includes("img_point_of_sale")) {
606      this.print(3, "IMG NODE in addNodeToArray", {
607        alt: node.alt,
608        cleanString: this.cleanString(text),
609        node,
610        isLocal: this.checkIfStringIsLocal(text),
611        isTranslatedText: this.isTextTranslatedText(text),
612      });
613    }
614    if (this.checkIfStringIsLocal(text)) {
615      return;
616    }
617
618    if (!isNodeASentenceChildren && this.isTextTranslatedText(text)) {
619      return;
620    }
621
622    //For Currency issue https://stage.idfcfirstbank.com/credit-card/classic
623    /*const textWithoutNums = this.removeCurrencyFromText(text);
624
625    if (!textWithoutNums) {
626      return;
627    }
628
629    const textWithoutSpecialChars =
630      this.removeSpecialCharacters(textWithoutNums);
631
632    if (!textWithoutSpecialChars) {
633      return;
634    }*/
635
636    let txt = text.replaceAll("\n", " ");
637    txt = this.replaceNbsps(txt);
638    txt = txt.trim();
639    txt = this.cleanString(txt);
640    let translatedText = this.cleanString(txt);
641
642    if (text.includes("img_point_of_sale")) {
643      this.print(
644        3,
645        "IMG NODE in addNodeToArray",
646        node.alt,
647        this.cleanString(text),
648        node
649      );
650    }
651
652    if (isNodeASentenceChildren) {
653      this.print(
654          3,
655          "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 624 ~ Devnagri ~ isNodeASentenceChildren",
656          isNodeASentenceChildren,
657          sentenceParentId
658      );
659
660      if (
661          this.sentence_nodes[sentenceParentId] &&
662          this.sentence_nodes[sentenceParentId].children
663      ) {
664        this.print(
665            3,
666            "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 624 ~ Devnagri ~ pushing node",
667            node
668        );
669
670        this.sentence_nodes[sentenceParentId] = {
671          children: this.sentence_nodes[sentenceParentId].children.find(item=> (
672              item.subSentencePosition === subSentencePosition ||
673              this.cleanString(item.original_text).toLowerCase()  === this.cleanString(text).toLowerCase() ||
674              this.cleanString(item.translated_text).toLowerCase() ===  this.cleanString(text).toLowerCase().replaceAll(this.sentence_merge_separator_send, this.sentence_merge_separator_receive)
675          )) ? this.sentence_nodes[sentenceParentId].children  :  [
676            ...this.sentence_nodes[sentenceParentId].children,
677            {
678              node,
679              text: this.cleanString(text),
680              translated_text: this.cleanString(text),
681              original_text: text,
682              subSentencePosition: subSentencePosition,
683            },
684          ],
685          parentNode: this.sentence_nodes[sentenceParentId].parentNode,
686        };
687        const combinedOriginalText = this.getSentenceCombinedOriginalText(
688            this.sentence_nodes[sentenceParentId]
689        );
690        this.sentence_nodes[sentenceParentId].original_text =
691            combinedOriginalText;
692
693        const combinedTranslatedText =
694            this.translation_api_global_data[combinedOriginalText];
695
696        if (combinedTranslatedText) {
697          this.sentence_nodes[sentenceParentId].translated_text =
698              combinedTranslatedText;
699
700          this.setTranslatedContentToSentenceParent(
701              this.sentence_nodes[sentenceParentId]
702          );
703        }
704      }
705      return;
706    }
707
708    if (this.translation_api_global_data[this.cleanString(text)]) {
709      translatedText = this.translation_api_global_data[this.cleanString(text)];
710
711      let origText = this.cleanString(text, false);
712      // origText = text.replaceAll("\n", " ");
713      // origText = this.replaceNbsps(origText);
714      const trimmedText = this.cleanString(text);
715      const translatedTextWithSpaces = origText.replace(
716        trimmedText,
717        translatedText
718      );
719      this.setTranslatedTextToElement(node, translatedTextWithSpaces, origText);
720    }
721
722    if (!Object.keys(this.arr_nodes).includes(this.cleanString(txt))) {
723      this.arr_nodes[`${this.cleanString(txt)}`] = {
724        translatedText: translatedText,
725        originalText: this.cleanString(text),
726        nodes: [node],
727        attributeKeyName,
728        ...(isNodeASentenceChildren
729          ? {
730              isNodeASentenceChildren,
731              sentenceParentId: [sentenceParentId],
732              subSentencePosition: [subSentencePosition],
733            }
734          : {}),
735      };
736    } else {
737      // node is already in arr_nodes
738      if (isNodeASentenceChildren) {
739        // text already exists in a node as sentence children
740        if (
741          this.arr_nodes[`${this.cleanString(txt)}`].isNodeASentenceChildren
742        ) {
743          if (
744            !this.arr_nodes[
745              `${this.cleanString(txt)}`
746            ].sentenceParentId.includes(sentenceParentId)
747          ) {
748            this.arr_nodes[`${this.cleanString(txt)}`].sentenceParentId.push(
749              sentenceParentId
750            );
751            this.arr_nodes[`${this.cleanString(txt)}`].subSentencePosition.push(
752              subSentencePosition
753            );
754          }
755        } else {
756          this.arr_nodes[`${this.cleanString(txt)}`].isNodeASentenceChildren =
757            isNodeASentenceChildren;
758          this.arr_nodes[`${this.cleanString(txt)}`].sentenceParentId = [
759            sentenceParentId,
760          ];
761          this.arr_nodes[`${this.cleanString(txt)}`].subSentencePosition = [
762            subSentencePosition,
763          ];
764        }
765      }
766
767      this.arr_nodes[`${this.cleanString(txt)}`].nodes.push(node);
768    }
769  }
770
771  // sentence merging functions
772  getXPathForElement(el, xml) {
773    let xpath = "";
774    let pos, tempitem2;
775
776    while (el !== xml.documentElement) {
777      pos = 0;
778      tempitem2 = el;
779      while (tempitem2) {
780        if (tempitem2.nodeType === 1 && tempitem2.nodeName === el.nodeName) {
781          // If it is ELEMENT_NODE of the same name
782          pos += 1;
783        }
784        tempitem2 = tempitem2.previousSibling;
785      }
786
787      xpath = `*[name()='${el.nodeName}' and namespace-uri()='${
788          el.namespaceURI ?? ""
789      }'][${pos}]/${xpath}`;
790
791      el = el.parentNode;
792    }
793    xpath = `/*[name()='${xml.documentElement.nodeName}' and namespace-uri()='${
794        el.namespaceURI ?? ""
795    }']/${xpath}`;
796    xpath = xpath.replace(/\/$/, "");
797    return xpath;
798  }
799
800  isNodeASentence(node) {
801    if(!this.enable_sentence_merging){
802      return false
803    }
804    let result = true;
805    const parentName = node.nodeName.toUpperCase();
806    if (this.sentence_parents.includes(parentName)) {
807      if (node.childNodes.length > 1) {
808        for (let innerNode of node.childNodes) {
809          const childName = innerNode.nodeName.toUpperCase();
810          if (!this.sentence_children.includes(childName)) {
811            result = false;
812          } else {
813            if (innerNode.childNodes.length > 1) {
814              result = false;
815            }
816          }
817        }
818      } else {
819        result = false;
820      }
821    } else {
822      result = false;
823    }
824    return result;
825  }
826
827  setTranslatedTextToSentenceMapChildren = (sentenceMap) => {
828    const obj = {};
829    Object.entries(sentenceMap).forEach(([key, value]) => {
830      if(this.cleanString(value.original_text) !== this.cleanString(value.translated_text)){
831        let translatedTextsArr = []
832        if(value.translated_text){
833          translatedTextsArr =  value.translated_text.split(this.sentence_merge_separator_receive);
834        }
835
836        const children = value.children.map((child, index) => {
837          child.translated_text = translatedTextsArr[index];
838          return child;
839        });
840        value.children = children;
841      }
842      obj[key] = value;
843    });
844    return obj;
845  };
846
847  setTranslatedTextToSentenceObj = (sentenceObj) => {
848    if(this.cleanString(sentenceObj.original_text) === this.cleanString(sentenceObj.translated_text)){
849      return
850    }
851    this.print(3,"setTranslatedTextToSentenceObj",sentenceObj)
852    let translatedTextsArr = []
853    if(sentenceObj.translated_text){
854      translatedTextsArr =  sentenceObj.translated_text.split(this.sentence_merge_separator_receive);
855    }
856
857    const children = sentenceObj.children.map((child, index) => {
858      child.translated_text = translatedTextsArr[index] ? translatedTextsArr[index] : "";
859      return child;
860    });
861    sentenceObj.children = children;
862    return sentenceObj;
863  };
864
865  setTranslatedContentToSentenceParent(sentenceObj) {
866    const sentenceParent = this.setTranslatedTextToSentenceObj(sentenceObj);
867    this.print(
868        3,
869        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1331 ~ Devnagri ~ setTranslatedContentToSentenceParent ~ sentenceObj",
870        sentenceParent
871    );
872
873    if (
874        sentenceParent &&
875        sentenceParent.children &&
876        Array.isArray(sentenceParent.children) &&
877        sentenceParent.children.length > 0
878    ) {
879      sentenceParent.children.forEach((child) => {
880        this.print(
881            3,
882            "setTranslatedContentToSentenceParent setTranslatedContentToSentenceNodes this.setTranslatedTextToElement",
883            {
884              node: child.node,
885              translated_text: child.translated_text,
886              text: child.text,
887            }
888        );
889        if(child.original_text && !this.isTextTranslatedText(child.original_text)){
890          let origText = this.cleanString(child.original_text, false);
891          const trimmedText = this.cleanString(child.original_text);
892          const translatedTextWithSpaces = origText.replace(
893              trimmedText,
894              child.translated_text
895          );
896          this.setTranslatedTextToElement(
897              child.node,
898              translatedTextWithSpaces,
899              child.original_text,
900          );
901        }
902
903      });
904    }
905  }
906
907  setTranslatedContentToSentenceNodes(sentenceNodes) {
908    Object.values(sentenceNodes).forEach(
909        this.setTranslatedContentToSentenceParent
910    );
911  }
912
913  getSentenceCombinedOriginalText(sentenceNode) {
914    let text = "";
915    sentenceNode.children.forEach((child, index) => {
916      text += `${index > 0 ? this.sentence_merge_separator_send : ""}${
917          child.text
918      }`;
919    });
920    return text;
921  }
922
923  // sentence merging functions end
924
925  // this function is used for handling the nodes text with different-2 cases
926  checkNodeType(
927    node,
928    isNodeASentenceChildren = false,
929    sentenceParentId = "",
930    subSentencePosition
931  ) {
932    if (node.parentElement && node.parentElement.nodeName == "STYLE") {
933      return;
934    }
935
936    switch (node.nodeName) {
937      case "#text": {
938        if (node.textContent.trim().length != 0) {
939          try {
940            let nodeParent = node.parentElement;
941            if (
942              nodeParent &&
943              nodeParent.nodeName.toLowerCase() != "devnagri_text" &&
944              nodeParent.nodeName.toLowerCase() != "title"
945            ) {
946              if (this.web_owner) {
947                let newElement = document.createElement("devnagri_text");
948                newElement.setAttribute("english_text", node.textContent);
949                newElement.textContent = node.textContent;
950                node.replaceWith(newElement);
951                this.addNodeToArray(
952                  node.textContent,
953                  newElement,
954                  isNodeASentenceChildren,
955                  sentenceParentId,
956                  subSentencePosition
957                );
958              } else {
959                // let newElement = document.createElement("devnagri_text");
960                // newElement.setAttribute("english_text", node.textContent);
961                // newElement.textContent = node.textContent;
962                // node.setAttribute("english_text", node.textContent);
963                // node.replaceWith(newElement);
964                // this.addNodeToArray(node.textContent, newElement);
965                this.addNodeToArray(
966                  node.textContent,
967                  node,
968                  isNodeASentenceChildren,
969                  sentenceParentId,
970                  subSentencePosition
971                );
972              }
973            } else {
974              if (
975                node.parentElement &&
976                node.parentElement.nodeName == "TITLE" &&
977                node.textContent == document.title
978              ) {
979                this.addNodeToArray(this.meta_prefix + node.textContent, node);
980                break;
981              }
982              if (node.textContent.trim().length != 0) {
983                this.addNodeToArray(node.textContent, node);
984              }
985            }
986          } catch (error) {
987            let newElement = document.createElement("devnagri_text");
988            newElement.setAttribute("english_text", node.textContent);
989            newElement.textContent = node.textContent;
990            node.replaceWith(newElement);
991            this.addNodeToArray(node.textContent, newElement);
992          }
993        }
994        break;
995      }
996      case "META": {
997        if (
998          (node.name &&
999            [
1000              "DESCRIPTION",
1001              "TITLE",
1002              "KEYWORDS",
1003              "TWITTER:TITLE",
1004              "TWITTER:DESCRIPTION",
1005            ].includes(node.name.toUpperCase())) ||
1006          (node.getAttribute("property") &&
1007            ["OG:TITLE", "OG:DESCRIPTION"].includes(
1008              node.getAttribute("property").toUpperCase()
1009            ))
1010        ) {
1011          if (node.name) {
1012            this.metatag_key = node.nodeName + "-" + node.name;
1013            if (!this.metatag_arr[`${this.metatag_key}`]) {
1014              this.metatag_arr[`${this.metatag_key}`] = {
1015                tag: node.nodeName,
1016                name: node.name,
1017                content: node.content,
1018                engText: node.content,
1019                translatedText: node.content,
1020              };
1021            }
1022          } else if (node.getAttribute("property")) {
1023            this.metatag_key =
1024              node.nodeName + "-" + node.getAttribute("property");
1025            if (!this.metatag_arr[`${this.metatag_key}`]) {
1026              this.metatag_arr[`${this.metatag_key}`] = {
1027                tag: node.nodeName,
1028                property: node.getAttribute("property"),
1029                content: node.content,
1030                engText: node.content,
1031                translatedText: node.content,
1032              };
1033            }
1034          }
1035          this.addNodeToArray(this.meta_prefix + node.content, node);
1036        }
1037        break;
1038      }
1039
1040      case "INPUT": {
1041        if (node.type === "button") {
1042          if (node.value.trim().length != 0) {
1043            this.addNodeToArray(node.value, node);
1044          }
1045        } else {
1046          if (node.type === "submit") {
1047            if (node.value.trim().length != 0) {
1048              this.addNodeToArray(node.value, node);
1049            }
1050          }
1051
1052          if (node.placeholder.trim().length != 0) {
1053            this.addNodeToArray(node.placeholder, node);
1054          }
1055
1056          // if (node.title.trim().length != 0) {
1057          //   this.addNodeToArray(node.title, node);
1058          // }
1059
1060          if (node.type != "hidden" && node.title.trim().length != 0) {
1061            this.addNodeToArray(node.title, node);
1062          }
1063        }
1064
1065        break;
1066      }
1067      case "TEXTAREA": {
1068        if (node.placeholder.trim().length != 0) {
1069          this.addNodeToArray(node.placeholder, node);
1070        }
1071        
1072        if (node.title.trim().length != 0) {
1073          this.addNodeToArray(node.title, node);
1074        }
1075
1076        break;
1077      }
1078      case "IMG": {
1079        if (this.enable_object_mapping) {
1080          if (this.subdomain_object_urls_hash_map_local[node.src]) {
1081            break;
1082          }
1083        }
1084        this.print(3, "IMG Node", node.alt, node);
1085
1086        if (node.alt.trim().length != 0) {
1087          this.addNodeToArray(this.meta_prefix + node.alt, node);
1088        }
1089
1090        if (node.title.trim().length != 0) {
1091          this.addNodeToArray(this.meta_prefix + node.title, node);
1092        }
1093        break;
1094      }
1095      case "SCRIPT": {
1096        break;
1097      }
1098      default: {
1099      }
1100    }
1101    if (node && node.parentElement && node.parentElement.title) {
1102      this.addNodeToArray(node.parentElement.title, node.parentElement, undefined, undefined, undefined, 'title');
1103    }
1104  }
1105
1106  replaceEnglishDomainWithLocalDomain({ url, englishDomain, localDomain }) {
1107    let hrefUrl = url;
1108    if (this.domain && !this.domain.includes("www")) {
1109      // hrefUrl = hrefUrl.replaceAll("https://www.", "https://");
1110      // hrefUrl = hrefUrl.replaceAll("http://www.", "http://");
1111   
1112      if(hrefUrl.includes(this.domain)){
1113        hrefUrl = hrefUrl.replaceAll("https://www.", "https://");
1114        hrefUrl = hrefUrl.replaceAll("http://www.", "http://");
1115      }  
1116
1117    }
1118
1119    const englishDomainWithoutProtocol = englishDomain
1120      .replaceAll("https://", "")
1121      .replaceAll("http://", "");
1122    const localDomainWithoutProtocol = localDomain
1123      .replaceAll("https://", "")
1124      .replaceAll("http://", "");
1125
1126    const secureEnglishDomain = `https://${englishDomainWithoutProtocol}`;
1127    const secureLocalDomain = `https://${localDomainWithoutProtocol}`;
1128
1129    const unsecureEnglishDomain = `http://${englishDomainWithoutProtocol}`;
1130    const unsecureLocalDomain = `http://${localDomainWithoutProtocol}`;
1131    
1132    let hrefUrlSlash = `${hrefUrl}/`;
1133
1134    if (hrefUrlSlash.includes(localDomainWithoutProtocol + "/")) {
1135      return hrefUrl;
1136    }
1137
1138    let newUrl = hrefUrl;
1139    newUrl = newUrl.replaceAll(secureEnglishDomain, secureLocalDomain);
1140    newUrl = newUrl.replaceAll(unsecureEnglishDomain, unsecureLocalDomain);
1141    return newUrl;
1142  }
1143
1144  getLocalObjectUrl(englishUrl) {
1145    return this.subdomain_object_urls_hash_map[this.formatUrl(englishUrl)] &&
1146      this.subdomain_object_urls_hash_map[this.formatUrl(englishUrl)]?.local_url
1147      ? this.subdomain_object_urls_hash_map[englishUrl]?.local_url
1148      : "";
1149  }
1150
1151  getLocalObjectAlt(englishUrl) {
1152    return this.subdomain_object_urls_hash_map[this.formatUrl(englishUrl)] &&
1153      this.subdomain_object_urls_hash_map[this.formatUrl(englishUrl)].alt_text
1154      ? this.subdomain_object_urls_hash_map[englishUrl].alt_text
1155      : "";
1156  }
1157
1158  // this function is used for traversing the HTML dom
1159  traverseNodes(
1160    node,
1161    callback,
1162    isNodeASentenceChildren = false,
1163    sentenceParentId = "",
1164    subSentencePosition
1165  ) {
1166    const blacklistedTags = [
1167      "SCRIPT",
1168      "VIDEO",
1169      "IFRAME",
1170      "STYLE",
1171      "NOSCRIPT",
1172      "LINK",
1173      "SVG",
1174      "RECT",
1175      "PATH",
1176      "G",
1177      "CLIPPATH",
1178    ]; //handling the script tag
1179
1180    if (this.enable_object_mapping) {
1181      if (
1182        node &&
1183        node.nodeName &&
1184        node.nodeName.toUpperCase() === "IMG" &&
1185        node.src
1186      ) {
1187        if (node.src) {
1188          this.print(
1189            3,
1190            "🚀 ~ file: objectEnglishUrl devnagri-dota-merged-client-dev.js ~ line 632 ~ Devnagri ~ traverseNodes ~ node.src",
1191            node.src
1192          );
1193
1194          let localUrl = "";
1195          let objectEnglishUrl = "";
1196          // url is absolute
1197          if (node.src.includes("http")) {
1198            objectEnglishUrl = node.src.replaceAll(
1199              this.requested_domain,
1200              this.domain
1201            );
1202          } else {
1203            objectEnglishUrl = `${this.domain}/${node.src}`;
1204          }
1205          this.print(
1206            3,
1207            "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 640 ~ Devnagri ~ traverseNodes ~ objectEnglishUrl",
1208            objectEnglishUrl
1209          );
1210
1211          localUrl = this.getLocalObjectUrl(objectEnglishUrl);
1212
1213          const localAlt = this.getLocalObjectAlt(objectEnglishUrl);
1214
1215          if (localUrl) {
1216            node.src = localUrl;
1217          }
1218          if (localAlt) {
1219            node.alt = localAlt;
1220          }
1221        }
1222
1223        if (node.getAttribute("srcset")) {
1224          const value = node.getAttribute("srcset");
1225          let valueWithLocalLinks = value;
1226
1227          Object.values(this.subdomain_object_urls_hash_map).forEach(
1228            (object) => {
1229              valueWithLocalLinks = valueWithLocalLinks.replaceAll(
1230                this.formatUrl(object.english_url),
1231                this.formatUrl(object.local_url)
1232              );
1233            }
1234          );
1235          node.setAttribute("srcset", valueWithLocalLinks);
1236        }
1237
1238        if (node.getAttribute("data-lazy-srcset")) {
1239          const value = node.getAttribute("data-lazy-srcset");
1240          let valueWithLocalLinks = value;
1241          Object.values(this.subdomain_object_urls_hash_map).forEach(
1242            (object) => {
1243              valueWithLocalLinks = valueWithLocalLinks.replaceAll(
1244                this.formatUrl(object.english_url),
1245                this.formatUrl(object.local_url)
1246              );
1247            }
1248          );
1249          node.setAttribute("data-lazy-srcset", valueWithLocalLinks);
1250        }
1251        if (node.getAttribute("data-lazy-src")) {
1252          const value = node.getAttribute("data-lazy-src");
1253          let valueWithLocalLinks = value;
1254
1255          Object.values(this.subdomain_object_urls_hash_map).forEach(
1256            (object) => {
1257              valueWithLocalLinks = valueWithLocalLinks.replaceAll(
1258                this.formatUrl(object.english_url),
1259                this.formatUrl(object.local_url)
1260              );
1261            }
1262          );
1263          node.setAttribute("data-lazy-src", valueWithLocalLinks);
1264        }
1265      }
1266    }
1267
1268    if (node && node.nodeName && node.nodeName.toUpperCase() === "A" && node.title)
1269    {
1270      this.addNodeToArray(
1271        node.title,
1272        node
1273      );
1274    }
1275
1276    if (
1277      node &&
1278      node.nodeName &&
1279      node.nodeName.toUpperCase() === "A" &&
1280      node.href
1281    ) {
1282      let localObjectUrl = "";
1283      let objectEnglishUrl = "";
1284      // url is absolute
1285      if (node.href.includes("http")) {
1286        objectEnglishUrl = node.href.replaceAll(
1287          this.requested_domain,
1288          this.domain
1289        );
1290      } else {
1291        objectEnglishUrl = `${this.domain}/${node.href}`;
1292      }
1293      localObjectUrl = this.getLocalObjectUrl(objectEnglishUrl);
1294
1295      if (localObjectUrl) {
1296        node.setAttribute("href", localObjectUrl);
1297      } else {
1298        let localLink = this.replaceEnglishDomainWithLocalDomain({
1299          url: node.href,
1300          englishDomain: this.domain,
1301          localDomain: this.requested_domain,
1302        });
1303	
1304	
1305
1306        if (this.linkedDomains) {
1307          let default_lang_code = this.default_lang_code;
1308          let linkedDomains = [];
1309          for(let linkedDomain of this.linkedDomains){
1310            if(linkedDomain.code == default_lang_code){
1311              linkedDomains.push(linkedDomain);
1312            }
1313          }
1314	  linkedDomains.forEach((linkedDomain) => {
1315            localLink = this.replaceEnglishDomainWithLocalDomain({
1316              url: node.href,
1317              englishDomain: linkedDomain.domain,
1318              localDomain: linkedDomain.subdomain,
1319            });
1320          });
1321        }
1322        if (localLink && localLink !== node.href) {
1323          node.setAttribute("href", localLink);
1324        }
1325      }
1326    }
1327
1328    if(node && node.getAttribute){
1329      if (this.enable_blacklist) {
1330        // node blacklist by class condition
1331        var th = this;
1332        if (
1333          this.blacklist_classes
1334            .map(
1335              (item) =>
1336                node.getAttribute("class") &&
1337                th.isExactMatch(node.getAttribute("class"), item)
1338            )
1339            .some(Boolean)
1340        ) {
1341          this.print(
1342            3,
1343            "ignoring element with classname " + node.getAttribute("class")
1344          );
1345
1346          return;
1347        }
1348
1349        // node blacklist by id condition
1350        if (
1351          node &&
1352          node.getAttribute &&
1353          node.getAttribute("id") &&
1354          this.blacklist_ids.includes(node.getAttribute("id"))
1355        ) {
1356          this.print(
1357            3,
1358            "ignoring element with id " + node.getAttribute("id")
1359          );
1360          return;
1361        }
1362      }
1363    }
1364
1365    if (node.childNodes && node.childNodes.length > 0) {
1366      if (!blacklistedTags.includes(node.nodeName.toUpperCase())) {
1367        if (node.getAttribute("class") === "optionElement") {
1368          return true;
1369        }
1370
1371        if (this.enable_blacklist) {
1372          // node blacklist by class condition
1373          var th = this;
1374          if (
1375            this.blacklist_classes
1376              .map(
1377                (item) =>
1378                  node.getAttribute("class") &&
1379                  th.isExactMatch(node.getAttribute("class"), item)
1380              )
1381              .some(Boolean)
1382          ) {
1383            this.print(
1384              3,
1385              "ignoring element with classname " + node.getAttribute("class")
1386            );
1387
1388            return;
1389          }
1390
1391          // node blacklist by id condition
1392          if (
1393            node &&
1394            node.getAttribute &&
1395            node.getAttribute("id") &&
1396            this.blacklist_ids.includes(node.getAttribute("id"))
1397          ) {
1398            this.print(
1399              3,
1400              "ignoring element with id " + node.getAttribute("id")
1401            );
1402            return;
1403          }
1404        }
1405
1406        if (
1407          node &&
1408          node.getAttribute &&
1409          (node.getAttribute("id") === "devnagri_outermostdiv" ||
1410            node.getAttribute("id") === "devnagri_dropdown" ||
1411            node.getAttribute("id") === "newstab" ||
1412            node.getAttribute("id") === "photostab")
1413        ) {
1414          this.print(3, "ignoring devnagri_outermostdiv");
1415          return;
1416        }
1417
1418        if (this.isNodeASentence(node)) {
1419          const parentId = this.getXPathForElement(node, document);
1420          if (!this.sentence_nodes[parentId]) {
1421            this.sentence_nodes[parentId] = {
1422              parentNode: node,
1423              children: [],
1424            };
1425          }
1426
1427          for (let [index, innerNode] of node.childNodes.entries()) {
1428            this.traverseNodes(
1429                innerNode,
1430                callback,
1431                true,
1432                this.getXPathForElement(node, document),
1433                index
1434            );
1435          }
1436        } else {
1437          for (let innerNode of node.childNodes) {
1438            this.traverseNodes(
1439                innerNode,
1440                callback,
1441                isNodeASentenceChildren,
1442                sentenceParentId,
1443                subSentencePosition
1444            );
1445          }
1446        }
1447      }
1448    } else {
1449      if (callback)
1450        callback(
1451          node,
1452          isNodeASentenceChildren,
1453          sentenceParentId,
1454          subSentencePosition
1455        );
1456    }
1457  }
1458
1459  areAllNodesTranslated(nodesObj) {
1460    let areAllNodesTranslated = true;
1461    Object.keys(nodesObj).forEach((key) => {
1462      if (
1463        nodesObj[key].translatedText === key &&
1464        !this.checkIfStringIsLocal(nodesObj[key].translatedText)
1465      ) {
1466        areAllNodesTranslated = false;
1467        return true;
1468      }
1469    });
1470
1471    return areAllNodesTranslated;
1472  }
1473
1474  async checkIfTraversingCompleted() {
1475    this.print(
1476      3,
1477      "UPDATE CHECK Check if traversing completed or not",
1478      this.translation_api_global_data,
1479      this.arr_nodes
1480    );
1481    await this.updateNodesWithTranslatedText(this.translation_api_global_data);
1482    this.print(
1483      3,
1484      "checkIfTraversingCompleted this.access_token",
1485      this.access_token
1486    );
1487    this.updateGlobalData();
1488  }
1489
1490  // get user's lat long
1491  get_user_location() {
1492    if (navigator.geolocation) {
1493      navigator.geolocation.getCurrentPosition((position) => {
1494        let lat = position.coords.latitude;
1495        let long = position.coords.longitude;
1496        this.user_lat = lat;
1497        this.user_long = long;
1498      });
1499    }
1500  }
1501
1502  formatTranslationDataByLocalKey(translationDataByOrigKey) {
1503    const translationDataObjByLocalKey = {};
1504    for (const [key, value] of Object.entries(translationDataByOrigKey)) {
1505      translationDataObjByLocalKey[value.toLowerCase()] = key;
1506    }
1507    return translationDataObjByLocalKey;
1508  }
1509
1510  splitCompoundSentencesFromTranslationSentences(translationSentences) {
1511    const compoundSentences = [];
1512    const splittedCompoundSentences = [];
1513    translationSentences.forEach((item) => {
1514      if (item.sentence.includes("##{{}}##")) {
1515        compoundSentences.push(item);
1516      }
1517    });
1518
1519    compoundSentences.forEach((item) => {
1520      const splittedSentences = item.sentence.split("##{{}}##");
1521      const splittedTranslation = item.translation.split("##{{}}##");
1522      splittedSentences.forEach((sentence, index) => {
1523        const obj = {
1524          sentence: sentence,
1525          translation: splittedTranslation[index]
1526            ? splittedTranslation[index]
1527            : "",
1528        };
1529        splittedCompoundSentences.push(obj);
1530      });
1531    });
1532
1533    const simpleSentences = translationSentences.filter(
1534      (item) => !item.sentence.includes("##{{}}##")
1535    );
1536    const sentences = simpleSentences.concat(splittedCompoundSentences);
1537    this.print(
1538      3,
1539      "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1145 ~ Devnagri ~ splitCompoundSentencesFromTranslationSentences ~ sentences",
1540      sentences
1541    );
1542    return sentences;
1543  }
1544
1545  // this function is used for calling translate api and here we get specified language text i.e. hindi
1546  async GetTranslationsApi() {
1547    try {
1548      if (this.source_lang_code === this.selected_lang_code) {
1549        return {};
1550      }
1551
1552      if (
1553        this.status_api_global_data &&
1554        this.status_api_global_data.enable_object_mapping
1555      ) {
1556        this.enable_object_mapping = true;
1557        await this.getObjectUrlsApi();
1558      }
1559
1560      const documentUrlWithoutInternalLink = this.removeInternalLinkFromUrl(
1561        this.document_url_full
1562      );
1563
1564      const currentPageUrlObj = new URL(documentUrlWithoutInternalLink);
1565      currentPageUrlObj.searchParams.delete("language_code");
1566      currentPageUrlObj.searchParams.delete("mode");
1567      currentPageUrlObj.searchParams.delete("dota-token");
1568
1569      const translation_api_base_url = `${this.api_baseurl}/translations?language_code=${this.selected_lang_code}&url=${currentPageUrlObj}`;
1570      var translation_api_url = translation_api_base_url;
1571      // +
1572      // "&language_code=" +
1573      // lang_code;
1574      //this.prevURL = this.prevURL ? this.prevURL : currentPageUrlObj;
1575      //console.log("td2", this.prevURL.href);
1576      //console.log("td3", currentPageUrlObj.href);
1577      if(!this.apiCounter && (String(this.prevURL) != String(currentPageUrlObj.href)))
1578      {
1579        this.prevURL = this.prevURL ? this.prevURL : currentPageUrlObj.href;
1580        this.translationData = await this.callApiRequest(async () => {
1581          const res = await fetch(translation_api_url, {
1582            method: "GET",
1583            headers: {
1584              Authorization: `Bearer ${this.access_token}`,
1585            },
1586          });
1587          if (res.status === 401 || res.status === 403) {
1588            throw { response: res };
1589          }
1590          const response = await res.json();
1591          return response;
1592        });
1593        ++this.apiCounter;
1594      }
1595
1596      if (this.translationData.message === "success") {
1597        this.print(3, "Translation Response Received");
1598        this.print(
1599          3,
1600          "Translation Response Received Sentences" +
1601            JSON.stringify(this.translationData.sentences)
1602        );
1603
1604        // sentence merging changes start
1605        if(this.enable_sentence_merging) {
1606          const origSentenceDataMap = await this.FormatTranslations(
1607            this.translationData.sentences
1608          );
1609
1610          this.print(
1611              3,
1612              "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1383 ~ Devnagri ~ GetTranslationsApi ~ origSentenceDataMap",
1613              origSentenceDataMap
1614          );
1615
1616          const sentenceNodesMapByOrigText = {};
1617          Object.entries(this.sentence_nodes).forEach(([key, value]) => {
1618            sentenceNodesMapByOrigText[value.original_text] = Object.assign(
1619                {
1620                  parentId: key,
1621                  translated_text: origSentenceDataMap[value.original_text]
1622                      ? origSentenceDataMap[value.original_text]
1623                      : value.original_text,
1624                },
1625                value
1626            );
1627            this.sentence_nodes[key].translated_text = origSentenceDataMap[
1628                value.original_text
1629                ]
1630                ? origSentenceDataMap[value.original_text]
1631                : value.original_text;
1632          });
1633
1634          this.print(
1635              3,
1636              "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1389 ~ Devnagri ~ GetTranslationsApi ~ sentenceNodesMapByOrigText",
1637              sentenceNodesMapByOrigText
1638          );
1639
1640          this.sentence_nodes_by_orig_text = sentenceNodesMapByOrigText;
1641
1642          this.setTranslatedTextToSentenceMapChildren(
1643              this.sentence_nodes_by_orig_text
1644          );
1645
1646          this.setTranslatedTextToSentenceMapChildren(this.sentence_nodes);
1647
1648          this.setTranslatedContentToSentenceNodes(
1649              this.sentence_nodes
1650          );
1651        }
1652        // sentence merging changes end
1653
1654        this.translation_api_global_data = await this.FormatTranslations(
1655          this.translationData.sentences
1656        );
1657
1658        this.translation_api_global_data_by_local_key =
1659          this.formatTranslationDataByLocalKey(
1660            this.translation_api_global_data
1661          );
1662
1663        if (this.status_api_global_data && !this.status_api_global_data.is_demo) {
1664          //await this.storeValuesInIndexDB(this.translation_api_global_data);
1665        }
1666
1667        await this.updateNodesWithTranslatedText(
1668          this.translation_api_global_data
1669        );
1670      }
1671
1672      return this.translationData;
1673    } catch (error) {
1674      throw error;
1675    }
1676  }
1677
1678  async FormatTranslations(sentences) {
1679    sentences.map((x) => {
1680      this.arr_translated_text[this.cleanString(x.sentence)] = x.translation;
1681    });
1682    return this.arr_translated_text;
1683  }
1684
1685  // print api log to console
1686  print(level, ...data) {
1687    if (level <= this.log_level) {
1688      if (level === 1) {
1689        return console.error(`DevLog-${level} ${new Date()} | `, ...data);
1690      }
1691      if (level === 2) {
1692        return console.warn(`DevLog-${level} ${new Date()} | `, ...data);
1693      }
1694      return console.log(`DevLog-${level} ${new Date()} | `, ...data);
1695    }
1696  }
1697  // this function is used for set the hindi text in object(nodeTextObject)
1698  async updateNodesWithTranslatedText(translationData) {
1699    this.print(3, "Translated Text Updating Started");
1700    let nodesCount = Object.keys(this.arr_nodes).length;
1701    if (!translationData || nodesCount == 0) {
1702      return;
1703    }
1704    let missingTranslations = [];
1705    for (let key of Object.keys(this.arr_nodes)) {
1706      let txtOriginal = key;
1707      if (txtOriginal.startsWith(this.meta_prefix)) {
1708        txtOriginal = txtOriginal.replace(this.meta_prefix, "");
1709      }
1710      if (translationData[txtOriginal] && this.arr_nodes[txtOriginal]) {
1711        this.arr_nodes[txtOriginal].translatedText =
1712            translationData[txtOriginal]
1713
1714      } else {
1715        if (!missingTranslations.includes(key)) {
1716          if (this.cleanString(key).length > 0) {
1717            missingTranslations.push(key);
1718            this.print(
1719              2,
1720              "translation not found for key = '" + this.cleanString(key) + "'"
1721            );
1722          }
1723          // missingTranslations.push(key);
1724        }
1725      }
1726    }
1727
1728    let cleanedMissingTranslation = missingTranslations.map((x) => {
1729      return this.cleanString(x);
1730    });
1731
1732    cleanedMissingTranslation = cleanedMissingTranslation.filter(
1733      (item) => item.length > 1
1734    );
1735
1736    // this.translate(localStorage.getItem("devnagri_default_lang_code"));
1737    this.translate(this.selected_lang_code);
1738
1739    let missingPercentage =
1740      (cleanedMissingTranslation.length * 100) / nodesCount;
1741
1742    this.print(
1743      3,
1744      "translation missing number = " +
1745        cleanedMissingTranslation.length +
1746        " missing percentage = " +
1747        missingPercentage +
1748        " total nodes = " +
1749        nodesCount +
1750        JSON.stringify(cleanedMissingTranslation)
1751    );
1752    // Call Get Api again if missing text percentage is more than 5 %, Can be adjusted as per requirements
1753    if (missingPercentage > this.missingTranslationPercentageOffsetForRetry) {
1754      // There are some pending translation Object in this.arr_nodes, so will call get api after few seconds to get updated text
1755      // call get translation api after 1.5 second
1756      this.translation_api_retry_counter--;
1757      if (this.translation_api_retry_counter > 0) {
1758        setTimeout(async () => {
1759          this.GetTranslationsApi();
1760        }, 1500);
1761      }
1762    }
1763
1764    // if(missingPercentage > 5){
1765    //     this.print(3,"Showing Loader",missingPercentage,this.missingTranslationPercentageOffsetForRetry)
1766    //
1767    //     this.showLoader()
1768    // }else{
1769    //     // this.print(3,"Hiding Loader",missingPercentage,this.missingTranslationPercentageOffsetForRetry)
1770    //     // this.hideLoader()
1771    // }
1772  }
1773
1774  checkIfStringIsHindi(string) {
1775    const regex = /[\u0900-\u097F]/;
1776    return regex.test(string);
1777  }
1778
1779  checkIfStringIsPunjabi(string) {
1780    const regex = /[\u0A00-\u0A7F]/;
1781    return regex.test(string);
1782  }
1783
1784  checkIfStringIsTamil(string) {
1785    const regex = /[\u0B80-\u0BFF]/;
1786    return regex.test(string);
1787  }
1788
1789  checkIfStringIsGujrati(string) {
1790    const regex = /[\u0A80-\u0AFF]/;
1791    return regex.test(string);
1792  }
1793
1794  checkIfStringIsKannad(string) {
1795    const regex = /[\u0C80-\u0CFF]/;
1796    return regex.test(string);
1797  }
1798
1799  checkIfStringIsBengali(string) {
1800    const regex = /[\u0980-\u09FF]/;
1801    return regex.test(string);
1802  }
1803
1804  checkIfStringIsTelugu(string) {
1805    const regex = /[\u0C00-\u0C7F]/;
1806    return regex.test(string);
1807  }
1808
1809  checkIfStringIsMalyalam(string) {
1810    const regex = /[\u0D02-\u0D4D]/;
1811    return regex.test(string);
1812  }
1813
1814  checkIfStringIsAssamese(string) {
1815    const bengaliRegex = /[\u0980-\u09FF]/;
1816    //const tirhutaRegex = /[\u011480-\u0114DF]/;
1817    //return bengaliRegex.test(string) || tirhutaRegex.test(string);
1818    return bengaliRegex.test(string);
1819  }
1820
1821  checkIfStringIsOdia(string) {
1822    const regex = /[\u0B00-\u0B7F]/;
1823    return regex.test(string);
1824  }
1825
1826  checkIfStringIsArabic(string) {
1827    const regex = /[\u0600-\u06FF]/;
1828    return regex.test(string);
1829  }
1830
1831  checkIfStringIsJapanese(string) {
1832    const kanjiRegex = /[\u4E00-\u9FBF]/;
1833    const hiraganaRegex = /[\u3040-\u309F]/;
1834    const katakanaRegex = /[\u30A0-\u30FF]/;
1835
1836    return (
1837      kanjiRegex.test(string) ||
1838      hiraganaRegex.test(string) ||
1839      katakanaRegex.test(string)
1840    );
1841  }
1842
1843  checkIfStringIsChinese(string) {
1844    const regex = /[\u4E00-\u9FFF]/;
1845    return regex.test(string);
1846  }
1847
1848  checkIfStringIsIndonesian(string) {
1849    const regex = /[\u1B00-\u1B7F]/;
1850    return regex.test(string);
1851  }
1852
1853  checkIfStringIsUrdu(string) {
1854    const regex1 = /[\u0600-\u06FF]/;
1855    const regex2 = /[\u0750-\u077F]/;
1856    const regex3 = /[\uFB50-\uFDFF]/;
1857    const regex4 = /[\uFE70-\uFEFF]/;
1858
1859    return (
1860      regex1.test(string) ||
1861      regex2.test(string) ||
1862      regex3.test(string) ||
1863      regex4.test(string)
1864    );
1865  }
1866
1867  checkIfStringIsEnglish(string) {
1868    const regex = /[a-z]/;
1869    return regex.test(string.toLowerCase());
1870  }
1871
1872  checkIfStringIsLocal(string, hinglishResult = false) {
1873    this.print(
1874      4,
1875      "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1217 ~ Devnagri ~ checkIfStringIsLocal ~ string",
1876      this.selected_lang_code,
1877      string
1878    );
1879    if (this.selected_lang_code === this.source_lang_code) {
1880      return false;
1881    }
1882
1883    switch (this.selected_lang_code) {
1884      case "hi": {
1885        return this.checkIfStringIsHindi(string);
1886      }
1887      case "pa": {
1888        return this.checkIfStringIsPunjabi(string);
1889      }
1890      case "ta": {
1891        return this.checkIfStringIsTamil(string);
1892      }
1893      case "gu": {
1894        return this.checkIfStringIsGujrati(string);
1895      }
1896      case "kn": {
1897        return this.checkIfStringIsKannad(string);
1898      }
1899      case "bn": {
1900        return this.checkIfStringIsBengali(string);
1901      }
1902      case "mr": {
1903        return this.checkIfStringIsHindi(string);
1904      }
1905      case "te": {
1906        return this.checkIfStringIsTelugu(string);
1907      }
1908      case "ml": {
1909        return this.checkIfStringIsMalyalam(string);
1910      }
1911      case "as": {
1912        return this.checkIfStringIsAssamese(string);
1913      }
1914      case "or": {
1915        return this.checkIfStringIsOdia(string);
1916      }
1917      case "ar": {
1918        return this.checkIfStringIsArabic(string);
1919      }
1920      case "ja": {
1921        return this.checkIfStringIsJapanese(string);
1922      }
1923      case "zh": {
1924        return this.checkIfStringIsChinese(string);
1925      }
1926      case "id": {
1927        return this.checkIfStringIsIndonesian(string);
1928      }
1929      case "ur": {
1930        return this.checkIfStringIsUrdu(string);
1931      }
1932      case "hi-EN": {
1933        return hinglishResult;
1934      }
1935      default: {
1936        return false;
1937      }
1938    }
1939  }
1940
1941  // indexDb methods start
1942  async storeValuesInIndexDB(textObject) {
1943    let dbReq = indexedDB.open("devnagriTranslationText", 1);
1944    const dbReqPromise = await new Promise((resolve, reject) => {
1945      dbReq.addEventListener("upgradeneeded", (event) => {
1946        this.db = event.target.result;
1947        this.devnagriCreateDataBaseStore = this.db.createObjectStore(
1948          this.subdomainObjectStore,
1949          {
1950            autoIncrement: true,
1951          }
1952        );
1953      });
1954      dbReq.addEventListener("success", async (event) => {
1955        this.db = event.target.result;
1956        await this.addValuesInIndexObject(this.db, textObject);
1957        resolve();
1958      });
1959      dbReq.addEventListener("error", () => {
1960        reject(null);
1961      });
1962    });
1963
1964    return dbReqPromise;
1965  }
1966
1967 /* old code
1968  * async addValuesInIndexObject(db, textObject) {
1969    // // Start a database transaction and get the notes object store
1970    const indexDBValues = await new Promise(async (resolve, reject) => {
1971      this.print(3, "this.subdomainObjectStore", this.subdomainObjectStore);
1972      let tx = await db.transaction([this.subdomainObjectStore], "readwrite");
1973      let store = await tx.objectStore(this.subdomainObjectStore);
1974      for (let key of Object.keys(textObject)) {
1975        await store.put(textObject[key], key);
1976      }
1977
1978      // Wait for the database transaction to complete
1979      tx.oncomplete = function () {};
1980      tx.addEventListener("error", () => {
1981        reject(null);
1982      });
1983      resolve();
1984    });
1985    return indexDBValues;
1986  }
1987*/
1988
1989async addValuesInIndexObject(db, textObject) {
1990    try{
1991      // // Start a database transaction and get the notes object store
1992      const indexDBValues = await new Promise(async (resolve, reject) => {
1993        this.print(3, "this.subdomainObjectStore", this.subdomainObjectStore);
1994        let tx = await db.transaction([this.subdomainObjectStore], "readwrite");
1995        let store = await tx.objectStore(this.subdomainObjectStore);
1996        for (let key of Object.keys(textObject)) {
1997          await store.put(textObject[key], key);
1998        }
1999
2000        // Wait for the database transaction to complete
2001        tx.oncomplete = function () {};
2002        tx.addEventListener("error", () => {
2003          reject(null);
2004        });
2005        resolve();
2006      });
2007      return indexDBValues;
2008    }catch (error) {
2009      this.print(1,"error in addValuesInIndexObject",error)
2010    }
2011  }
2012
2013  async getParticularValueFromIndexDB(text) {
2014    let dbOpenRequest = window.indexedDB.open("devnagriTranslationText", 1);
2015    const obStore = await new Promise((resolve, reject) => {
2016      dbOpenRequest.addEventListener("success", () => {
2017        this.db = dbOpenRequest.result;
2018
2019        var tx = this.db.transaction([this.subdomainObjectStore], "readwrite");
2020
2021        // Wait for the database transaction to complete
2022        tx.oncomplete = function () {
2023          //   this.print(3,"stored note!");
2024        };
2025        tx.onerror = function () {
2026          // this.print(3,
2027          //   " object get value error storing note " + event.target.errorCode
2028          // );
2029        };
2030
2031        var obStore = tx.objectStore(this.subdomainObjectStore);
2032        resolve(obStore);
2033      });
2034      dbOpenRequest.addEventListener("error", () => {
2035        reject(null);
2036      });
2037    });
2038    const translatedText = await new Promise((resolve, reject) => {
2039      if (typeof text == "string") {
2040        var objectStoreRequest = obStore.get(text);
2041
2042        objectStoreRequest.addEventListener("success", () => {
2043          var result = objectStoreRequest.result;
2044          resolve(result);
2045        });
2046        objectStoreRequest.addEventListener("error", () => {
2047          reject(null);
2048        });
2049      } else {
2050        reject(null);
2051      }
2052    });
2053    return translatedText;
2054  }
2055
2056  async getValuesInIndexObject() {
2057    let dbOpenRequest = window.indexedDB.open("devnagriTranslationText", 1);
2058
2059    const obStore = await new Promise(async (resolve, reject) => {
2060      dbOpenRequest.addEventListener("success", async () => {
2061        this.db = dbOpenRequest.result;
2062
2063        var tx = await this.db.transaction(
2064          [this.subdomainObjectStore],
2065          "readwrite"
2066        );
2067
2068        // Wait for the database transaction to complete
2069        tx.oncomplete = function () {
2070          //   this.print(3,"stored note!");
2071        };
2072        tx.onerror = function (event) {
2073          // this.print(3,
2074          //     " object get value error storing note " + event.target.errorCode
2075          // );
2076        };
2077
2078        var obStore = await tx.objectStore(this.subdomainObjectStore);
2079        resolve(obStore);
2080      });
2081      dbOpenRequest.addEventListener("error", () => {
2082        // this.print(3,"error");
2083        reject(null);
2084      });
2085    });
2086
2087    const getAllValuesFromDB = await new Promise(async (resolve, reject) => {
2088      var request = await obStore.openCursor();
2089
2090      request.addEventListener("success", async (event) => {
2091        let cursor = await event.target.result;
2092        if (cursor) {
2093          let key = await cursor.primaryKey;
2094          let value = await cursor.value;
2095          if (this.translation_api_global_data) {
2096            this.translation_api_global_data[this.cleanString(key)] =
2097              await value;
2098            if (Object.keys(this.arr_nodes).includes(this.cleanString(key))) {
2099              this.arr_nodes[`${this.cleanString(key)}`].translatedText =
2100                this.translation_api_global_data[this.cleanString(key)];
2101            }
2102          }
2103          await cursor.continue();
2104        } else {
2105          resolve(request);
2106        }
2107      });
2108      request.addEventListener("error", () => {
2109        // this.print(3,"error");
2110        reject(null);
2111      });
2112    });
2113    return;
2114  }
2115
2116  // indexDb methods end
2117
2118  isTextTranslatedText(text="") {
2119    const textWithoutMeta = text.replace(this.meta_prefix, "");
2120    const textWithReplacedSeperator = textWithoutMeta.replaceAll(this.sentence_merge_separator_send,this.sentence_merge_separator_receive)
2121    if(!textWithReplacedSeperator){
2122      return true
2123    }
2124    if(!this.translation_api_global_data_by_local_key){
2125      return true
2126    }
2127    return !!this.translation_api_global_data_by_local_key[
2128        textWithReplacedSeperator.toLowerCase()
2129        ];
2130  }
2131
2132  //update api function calling
2133  async sentenceUpdateApi() {
2134    try {
2135      this.print(3, "Update Api Started");
2136      this.print(3, "this sentenceUpdateApi", this);
2137      this.print(2, "sentenceUpdateApi this.access_token", this.access_token);
2138      this.print(
2139        3,
2140        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1725 ~ Devnagri ~ sentenceUpdateApi ~ this.arr_nodes",
2141        Object.keys(this.arr_nodes).length
2142      );
2143
2144      let arrSentences = [];
2145
2146      for (let key of Object.keys(this.arr_nodes)) {
2147        if (!arrSentences.includes(this.cleanString(key))) {
2148          arrSentences.push(this.cleanString(key));
2149        }
2150      }
2151
2152      arrSentences = arrSentences.filter(
2153        (sentence) =>
2154          !this.checkIfStringIsLocal(sentence, false) &&
2155          !this.isTextTranslatedText(sentence)
2156      );
2157
2158      const documentUrlWithoutInternalLink = this.removeInternalLinkFromUrl(
2159        this.document_url_full
2160      );
2161
2162      let mergedSentences = []
2163      if(this.enable_sentence_merging){
2164        mergedSentences =Object.values(this.sentence_nodes).map(
2165            (item) => item.original_text
2166        );
2167      }
2168
2169      mergedSentences = mergedSentences.filter(
2170          (sentence) =>
2171              !this.checkIfStringIsLocal(sentence, false)
2172              // &&
2173              // !this.isTextTranslatedText(sentence)
2174      );
2175
2176      const sentences = arrSentences.concat(mergedSentences);
2177      if(!this.compareArrays(this.prevSentenceData, sentences))
2178      {
2179          this.prevSentenceData = sentences;
2180          this.sentenceData = await this.callApiRequest(async () => {
2181          const res = await fetch(this.update_api_url, {
2182            method: "POST",
2183            headers: {
2184              "Content-Type": "application/json",
2185              Authorization: `Bearer ${this.access_token}`,
2186            },
2187            body: JSON.stringify({
2188              url: documentUrlWithoutInternalLink,
2189              language_code: this.default_lang_code,
2190              sentences: sentences,
2191            }),
2192          });
2193          if (res.status === 401 || res.status === 403) {
2194            throw { response: res };
2195          }
2196          const response = await res.json();
2197          return response;
2198        });
2199      }
2200      this.print(3, "Update Api Completed");
2201      return this.sentenceData;
2202    } catch (error) {
2203      throw error;
2204    }
2205  }
2206
2207  // this function is used for setting hindi text in html dom
2208  setTranslatedTextToNode(node) {
2209    node.nodes.forEach((element) => {
2210      const originalText = node.originalText;
2211      const trimmedText = originalText.trim();
2212      const translatedText = node.translatedText;
2213      const translatedTextWithSpaces = originalText.replace(
2214        trimmedText,
2215        translatedText
2216      );
2217
2218      this.setTranslatedTextToElement(
2219        element,
2220        translatedTextWithSpaces,
2221        originalText,
2222        node.disableOrigTextCheck,
2223        node.attributeKeyName
2224      );
2225    });
2226  }
2227
2228  // this function is used for setting hindi text to html dom element
2229  setTranslatedTextToElement(
2230    element,
2231    translatedText,
2232    originalText,
2233    disableOrigTextCheck = false,
2234    attributeKeyName=""
2235  ) {
2236    if (this.selected_lang_code !== this.source_lang_code) {
2237      if (
2238        this.isTextTranslatedText(this.cleanString(originalText)) ||
2239          (
2240              this.isTextTranslatedText(element.textContent) &&
2241              element.nodeName &&
2242              !["META","INPUT","TEXTAREA","IMG"].includes(element.nodeName)
2243          )
2244      ) {
2245        return;
2246      }
2247    }
2248
2249    if(attributeKeyName === "title"){
2250      this.print(3,"setTranslatedTextToElement setting title",{ element,
2251        translatedText,
2252        originalText,
2253        disableOrigTextCheck,
2254        attributeKeyName,
2255        textInNode: element.title
2256      })
2257      if (originalText && element && element.title) {
2258        if (
2259            this.cleanString(element.title.trim().toLowerCase())  === this.cleanString(originalText.trim().toLowerCase())  || disableOrigTextCheck
2260        ) {
2261          element.title = translatedText;
2262        }
2263      }
2264      return
2265    }
2266
2267    if (element.nodeName == "INPUT") {
2268      if (element.type === "button") {
2269        if (element.value === originalText) {
2270          element.value = translatedText;
2271        }
2272      } else {
2273        if (element.type === "submit") {
2274          if (element.value === originalText) {
2275            element.value = translatedText;
2276          }
2277        }
2278
2279        if (element.placeholder === originalText) {
2280          element.placeholder = translatedText;
2281        }
2282
2283        // if (element.title && element.title === originalText) {
2284        //   element.title = translatedText;
2285        // }
2286
2287        if (element.type != "hidden") {
2288          if (element.title && element.title === originalText) {
2289            element.title = translatedText;
2290          }
2291        }
2292      }
2293    } else if (element.nodeName == "META") {
2294      if (
2295        (element.name &&
2296          [
2297            "DESCRIPTION",
2298            "TITLE",
2299            "KEYWORDS",
2300            "TWITTER:TITLE",
2301            "TWITTER:DESCRIPTION",
2302          ].includes(element.name.toUpperCase())) ||
2303        (element.getAttribute("property") &&
2304          ["OG:TITLE", "OG:DESCRIPTION"].includes(
2305            element.getAttribute("property").toUpperCase()
2306          ))
2307      ) {
2308        if (translatedText.startsWith(this.meta_prefix)) {
2309          translatedText = translatedText.replace(this.meta_prefix, "");
2310        }
2311        element.content = translatedText;
2312        // meta editor
2313        if (element.name) {
2314          this.metatag_key = element.nodeName + "-" + element.name;
2315          this.metatag_arr[`${this.metatag_key}`] = {
2316            ...this.metatag_arr[`${this.metatag_key}`],
2317            content: element.content,
2318            translatedText: element.content,
2319          };
2320        } else if (element.getAttribute("property")) {
2321          this.metatag_key =
2322            element.nodeName + "-" + element.getAttribute("property");
2323          this.metatag_arr[`${this.metatag_key}`] = {
2324            ...this.metatag_arr[`${this.metatag_key}`],
2325
2326            content: element.content,
2327            translatedText: element.content,
2328          };
2329        }
2330      }
2331    } else if (element.nodeName == "TEXTAREA") {
2332      if (
2333        element.placeholder &&
2334        element.placeholder.replaceAll("\n", "").trim().toLowerCase() ===
2335          originalText.replaceAll("\n", "").trim().toLowerCase()
2336      ) {
2337        element.placeholder = translatedText;
2338      }
2339      
2340      if (element.title && element.title === originalText) {
2341        element.title = translatedText;
2342      }
2343
2344    } else if (element.nodeName == "IMG") {
2345      if (translatedText.startsWith(this.meta_prefix)) {
2346        translatedText = translatedText.replace(this.meta_prefix, "");
2347      }
2348      if (originalText.startsWith(this.meta_prefix)) {
2349        originalText = originalText.replace(this.meta_prefix, "");
2350      }
2351      if (
2352        element.alt &&
2353        element.alt.replaceAll("\n", "").trim().toLowerCase() ===
2354          originalText.replaceAll("\n", "").trim().toLowerCase()
2355      ) {
2356        element.alt = translatedText;
2357      }
2358
2359      if (
2360        element.title &&
2361        element.title.replaceAll("\n", "").trim().toLowerCase() ===
2362          originalText.replaceAll("\n", "").trim().toLowerCase()
2363      ) {
2364        element.title = translatedText;
2365      }
2366    } else if (element.nodeName == "A") {
2367      //if (element.title && element.title.replaceAll("\n", "").trim().toLowerCase() === originalText.replaceAll("\n", "").trim().toLowerCase()) 
2368      {
2369        element.title = translatedText;
2370      }
2371    } else {
2372      if (translatedText.startsWith(this.meta_prefix)) {
2373        translatedText = translatedText.replace(this.meta_prefix, "");
2374      }
2375      if (originalText.startsWith(this.meta_prefix)) {
2376        originalText = originalText.replace(this.meta_prefix, "");
2377      }
2378
2379      if (
2380        this.cleanString(element.textContent.toLowerCase()) ===
2381          this.cleanString(originalText.toLowerCase()) ||
2382        disableOrigTextCheck ||
2383        this.isLiveJs()
2384      ) {
2385        // to prevent triggering of DOMCharacterDataModified event even if we have english text.
2386        // if(  this.checkIfStringIsHindi(translatedText)){
2387
2388        if (
2389          (this.cleanString(originalText) != this.cleanString(translatedText) &&
2390            this.checkIfStringIsLocal(translatedText, true)) ||
2391          disableOrigTextCheck
2392        ) {
2393          element.textContent = translatedText;
2394        }
2395
2396        // element.textContent = translatedText;
2397      }
2398    }
2399  }
2400
2401  // this function is used for setting hindi text in html dom
2402  translate(langCode) {
2403    this.print(3, "Translation started now - " + langCode);
2404    if (
2405      this.arr_nodes !== "undefined" &&
2406      this.translation_api_global_data != false
2407    ) {
2408      if (langCode != this.source_lang_code) {
2409        //selected language is not the same as page source language
2410        for (let key of Object.keys(this.arr_nodes)) {
2411          this.setTranslatedTextToNode({
2412            ...this.arr_nodes[`${this.cleanString(key)}`],
2413            // disableOrigTextCheck: true,
2414          });
2415        }
2416      } else {
2417        // convert the translation back to the original lanaguage
2418
2419        for (let key of Object.keys(this.arr_nodes)) {
2420          for (let key of Object.keys(this.arr_nodes)) {
2421            this.setTranslatedTextToNode({
2422              ...this.arr_nodes[`${this.cleanString(key)}`],
2423              translatedText: `${this.cleanString(key)}`,
2424              disableOrigTextCheck: true,
2425            });
2426          }
2427        }
2428        // translate sentence nodes back to english
2429        Object.keys(this.sentence_nodes).forEach(key=>{
2430          let children = []
2431          if(this.sentence_nodes[key] && this.sentence_nodes[key].children){
2432            children = this.sentence_nodes[key].children
2433          }
2434          if(children && Array.isArray(children)){
2435            children.forEach(child =>{
2436              const originalText = child.original_text;
2437              if(child.node){
2438                this.setTranslatedTextToNode({
2439                  nodes:[child.node],
2440                  translatedText: `${this.cleanString(originalText)}`,
2441                  disableOrigTextCheck: true,
2442                  originalText:originalText
2443                });
2444              }
2445            })
2446          }
2447        })
2448      }
2449    }
2450    this.metatag_arr.TITLE = {
2451      ...this.metatag_arr.TITLE,
2452      translatedText: document.title,
2453    };
2454  }
2455
2456  // start whole dom translation
2457  startTraversingNow() {
2458    this.print(3, "Traversing Started");
2459    this.traverseNodes(document.head, this.checkNodeType);
2460    this.traverseNodes(document.body, this.checkNodeType);
2461    this.print(3, "Traversing Completed");
2462  }
2463
2464  isUrlLangStatusActive(selected_lang_code) {
2465    const statusMap = this.lang_status_map;
2466    return statusMap[selected_lang_code] === "ACTIVE";
2467  }
2468
2469  //this function is used for checking the status like active,inactive of authentication
2470  async subscriptionStatusApi(status_api_url) {
2471    try {
2472      const res = await fetch(status_api_url, {
2473        method: "POST",
2474        headers: {
2475          "Content-Type": "application/json",
2476          Authorization: `Bearer ${this.access_token}`,
2477        },
2478        body: JSON.stringify({
2479          url: this.document_url_full,
2480          language_code: this.selected_lang_code,
2481          //ip: this.user_ip,
2482          //browser: navigator.userAgent,
2483          //timezone: new Date(),
2484          //referrer: this.document_url,
2485          //browserLanguage: navigator.language,
2486          //sizeScreenWidth: screen.width,
2487          //sizeScreenHeight: screen.height,
2488          //location permission granted here for getting lat and long
2489          //latitude: this.user_lat,
2490          //longitude: this.user_long,
2491        }),
2492      });
2493      if (res.status === 401) {
2494        throw { response: res };
2495      }
2496      const response = await res.json();
2497      this.status_api_global_data = response.data;
2498
2499      // enable sentence merging as per url date start
2500      let urlDate = this.sentence_merging_fallback_url_date
2501      if(this.status_api_global_data.url_date){
2502        urlDate = this.status_api_global_data.url_date
2503      }
2504
2505      if(new Date(urlDate) > new Date(this.sentence_merging_initial_url_date)){
2506        this.print(3,"Enabling sentence merging")
2507        this.enable_sentence_merging = true
2508      }else{
2509        this.print(3,"Disabling sentence merging")
2510        this.enable_sentence_merging = false
2511      }
2512      // enable sentence merging as per url date end
2513
2514      if (response && response.data && response.data.enableLanguageDropdownUI) {
2515        this.should_render_ui = "native";
2516      } else {
2517        this.should_render_ui = "custom";
2518      }
2519
2520      if (
2521        response.data.urlStatusArray &&
2522        Array.isArray(response.data.urlStatusArray)
2523      ) {
2524        const langStatusMap = {};
2525        response.data.urlStatusArray.forEach((item) => {
2526          langStatusMap[item.code] = item.status;
2527        });
2528        this.lang_status_map = langStatusMap;
2529      }
2530
2531      if (
2532        this.isLiveJs() &&
2533        this.status_api_global_data.enableSubdomainRedirect &&
2534        !this.web_owner
2535      ) {
2536        this.selected_lang_code = this.source_lang_code;
2537      }
2538
2539      if (
2540        this.isProxy() &&
2541        this.status_api_global_data.urlStatus === "INACTIVE"
2542      ) {
2543        this.print(2, "Redirecting to ", this.document_url_full);
2544        window.location.replace(this.document_url_full);
2545      }
2546
2547      // if(!this.page_view_api_count && (this.selected_lang_code != this.status_api_global_data.source_lang_code)){
2548      //   Promise.all([
2549      //     this.pageViewsApi(this.page_view_api_url)
2550      //   ]);
2551      // }
2552      // ++this.page_view_api_count;
2553
2554      if (
2555        this.status_api_global_data &&
2556        this.status_api_global_data.enable_object_mapping
2557        // this.isProxy()
2558      ) {
2559        this.enable_object_mapping = true;
2560        await this.getObjectUrlsApi();
2561      }
2562
2563      this.print(
2564        3,
2565        "🚀 ~ file: devnagri-dota-client.js ~ line 1270 ~ Devnagri ~ subscriptionStatusApi ~ response.data",
2566        response.data
2567      );
2568      if (
2569        (this.status_api_global_data.enableSubdomainRedirect ||
2570          this.isProxy()) &&
2571        !this.web_owner
2572      ) {
2573        localStorage.setItem("devnagri_default_lang_code", "en");
2574        localStorage.setItem("devnagri_selected_lang_code", "en");
2575      }
2576      this.lang = response.data.languages;
2577
2578      const enable_exclude_block = response.data
2579        ? !!response.data.enable_exclude_block
2580        : false;
2581
2582      const exclude_blocks =
2583        response.data && response.data.exclude_blocks
2584          ? response.data.exclude_blocks
2585          : [];
2586
2587      this.enable_blacklist = enable_exclude_block;
2588
2589      if (enable_exclude_block) {
2590        let blacklist_data = exclude_blocks.map((item) => item.selector);
2591        this.blacklist_data = blacklist_data;
2592        const id_selectors = blacklist_data.filter((item) =>
2593          item.includes("#")
2594        );
2595        this.blacklist_ids = id_selectors.map((selector) =>
2596          selector.replaceAll("#", "")
2597        );
2598        const class_selectors = blacklist_data.filter((item) =>
2599          item.includes(".")
2600        );
2601        this.blacklist_classes = class_selectors.map((selector) =>
2602          selector.replaceAll(".", "")
2603        );
2604      }
2605
2606      if (this.isProxy()) {
2607        this.linkedDomains = response.data.linked_domains;
2608      }
2609      this.frame_ids = response.data.iframe_ids;
2610      this.frame_ids.forEach(
2611        (frameId) => (this.frames_translation_status_map[frameId] = true)
2612      );
2613      this.setDropdownPosition(response.data.ui_position);
2614
2615      return response;
2616    } catch (err) {
2617      this.print(1,err)
2618      throw err;
2619    }
2620  }
2621
2622  async pageViewsApi(page_view_api_url) {
2623    try {
2624      const res = await fetch(page_view_api_url, {
2625        method: "POST",
2626        headers: {
2627          "Content-Type": "application/json",
2628          Authorization: `Bearer ${this.access_token}`,
2629        },
2630        body: JSON.stringify({
2631          url: this.document_url_full,
2632          language_code: this.selected_lang_code,
2633          ip: this.user_ip,
2634          browser: navigator.userAgent,
2635          timezone: new Date(),
2636          referrer: this.document_url,
2637          browserLanguage: navigator.language,
2638          sizeScreenWidth: screen.width,
2639          sizeScreenHeight: screen.height,
2640          //location permission granted here for getting lat and long
2641          latitude: this.user_lat,
2642          longitude: this.user_long,
2643        }),
2644      });
2645      if (res.status === 401) {
2646        throw { response: res };
2647      }
2648      const response = await res.json();
2649      return response;
2650    } catch (err) {
2651      this.print(1,err)
2652      throw err;
2653    }
2654  }
2655
2656  async traverseAndSetTranslationOfWholePage() {
2657    this.print(3, "traverseNodes Traversing whole dom");
2658    if (this.status_api_global_data && !this.status_api_global_data.is_demo) {
2659      //await this.getValuesInIndexObject();
2660    }
2661    this.startTraversingNow();
2662    this.print(
2663      3,
2664      "traverseAndSetTranslationOfWholePage this.access_token ",
2665      this.access_token
2666    );
2667    await this.checkIfTraversingCompleted();
2668    this.traverse_whole_dom = false;
2669  }
2670
2671  translateAllFramesOnPage() {
2672    const frameElements = document.querySelectorAll("iframe");
2673    frameElements.forEach((element) => {
2674      if (element && element.contentDocument && element.contentDocument.body) {
2675        const frameId = element.getAttribute("id");
2676        if (frameId && this.frame_ids.includes(frameId)) {
2677          if (this.frames_translation_status_map[frameId] === true) {
2678            if (element.contentDocument.body.childElementCount > 0) {
2679              this.print(
2680                3,
2681                "-> Translating IFRAME element.childElementCount",
2682                element.contentDocument.body.childElementCount
2683              );
2684              this.print(
2685                3,
2686                "-> Translating IFRAME element.contentDocument.body",
2687                frameId,
2688                element.contentDocument.body
2689              );
2690
2691              const obj = { target: element.contentDocument.body };
2692              this.domNodeInsertedHandler(obj);
2693              this.frames_translation_status_map[frameId] = false;
2694            }
2695          }
2696        }
2697
2698        // element.contentDocument.addEventListener("DOMNodeInserted",
2699        //     this.domNodeInsertedHandler
2700        // )
2701        // element.contentDocument.body.addEventListener("hover",
2702        //     (event)=>{
2703        //         this.print(3,"IFRAME hover triggered",event.target)
2704        //     }
2705        // )
2706        // element.contentDocument.body.addEventListener("DOMCharacterDataModified", (event) => {
2707        //     this.print(3,"IFRAME DOMCharacterDataModified listener triggered", event.target)
2708        //     const cleanValue = this.cleanString(event.target.textContent);
2709        //     if (cleanValue) {
2710        //         this.traverseNodes(event.target, this.checkNodeType);
2711        //     }
2712        // })
2713        // element.contentDocument.body.addEventListener("DOMContentLoaded",
2714        //     this.domNodeInsertedHandler
2715        // )
2716      }
2717    });
2718  }
2719
2720  async domNodeInsertedHandler(event) {
2721
2722    // if(window.location.pathname == '/covid-19' || window.location.pathname == '/covid-19/'){
2723    //   return;
2724    // }
2725    
2726    this.print(3, "domNodeInsertedHandler called", event.target);
2727    if(event && event.target && event.target.parentElement){
2728      if (this.enable_blacklist) {
2729        const parentElement = event.target.parentElement;
2730        var th = this;
2731        // node blacklist by class condition
2732        if (
2733            this.blacklist_classes
2734                .map(
2735                    (item) =>
2736                        parentElement &&
2737                        parentElement.getAttribute &&
2738                        parentElement.getAttribute("class") &&
2739                        th.isExactMatch(parentElement.getAttribute("class"), item)
2740                )
2741                .some(Boolean)
2742        ) {
2743          this.print(
2744              3,
2745              "ignoring element with classname " +
2746              parentElement.getAttribute("class")
2747          );
2748
2749          return;
2750        }
2751
2752        // node blacklist by id condition
2753        if (
2754            parentElement &&
2755            parentElement.getAttribute &&
2756            parentElement.getAttribute("id") &&
2757            this.blacklist_ids.includes(
2758                parentElement.getAttribute("id")
2759            )
2760        ) {
2761          this.print(
2762              3,
2763              "ignoring element with id " +
2764              parentElement.getAttribute("id")
2765          );
2766          return;
2767        }
2768      }
2769    }
2770    // const frameElements = document.querySelectorAll('iframe');
2771
2772    // frameElements.forEach((element) => {
2773    //     this.print(3,"IFRAME Adding listener to element ", element)
2774    // element.removeEventListener("dblclick",(event)=>{
2775    //     this.print(3,"IFRAME dblclick event triggered")
2776    //     this.domNodeInsertedHandler(event)
2777    // });
2778    // element.click()
2779    // element.removeEventListener("DOMContentLoaded", this.domNodeInsertedHandler);
2780    // element.removeEventListener("load", this.domNodeInsertedHandler);
2781    // element.contentDocument.addEventListener('load',
2782    //     this.domNodeInsertedHandler
2783    // );
2784
2785    // element.style.visibility = "hidden";
2786    //
2787    // setTimeout(()=>{
2788    //     element.style.visibility = "visible";
2789    // },0)
2790
2791    // element.contentDocument.addEventListener('dblclick',
2792    //     this.domNodeInsertedHandler
2793    // );
2794    //
2795    // element.contentDocument.body.addEventListener('dblclick',(event)=>{
2796    //     this.print(3,"IFRAME body dblclick  event triggered",event.target);
2797    // });
2798    // this.print(3,"-> IFRAME element.contentDocument.body", element.contentDocument.body);
2799
2800    // this.domNodeInsertedHandler(element.contentDocument.body)
2801    // element.contentDocument.body.addEventListener('DOMContentLoaded',()=>{
2802    //     this.print(3,"IFRAME body DOMContentLoaded  event triggered");
2803    // });
2804    //
2805    // element.contentDocument.body.addEventListener('load',()=>{
2806    //     this.print(3,"IFRAME body load  event triggered");
2807    // });
2808
2809    // element.contentDocument.addEventListener("DOMCharacterDataModified", (event) => {
2810    //     this.print(3,"IFRAME DOMCharacterDataModified listener triggered", event.target)
2811    //     const cleanValue = this.cleanString(event.target.textContent);
2812    //     if (cleanValue) {
2813    //         this.traverseNodes(event.target, this.checkNodeType);
2814    //     }
2815    // })
2816    //
2817    // element.contentDocument.addEventListener("DOMContentLoaded",
2818    //     this.domNodeInsertedHandler
2819    // )
2820    // element.contentDocument.addEventListener("DOMNodeInserted",(event)=>{
2821    //     this.print(3,"IFRAME DOMNodeInserted listener triggered", event.target)
2822    //     this.domNodeInsertedHandler(event)
2823    // })
2824    // })
2825
2826    const drawingNodes = ["RECT", "PATH", "G", "CLIPPATH"];
2827
2828    if (drawingNodes.includes(event.target.nodeName.toUpperCase())) {
2829      return;
2830    }
2831
2832    const unformattedFullUrl = this.isProxy()
2833      ? document.URL.replaceAll(
2834          this.config.requested_domain,
2835          this.config.domain
2836        )
2837      : document.URL;
2838
2839    const urlObj = new URL(document.URL);
2840    urlObj.searchParams.delete("mode");
2841    urlObj.searchParams.delete("dota-token");
2842    urlObj.searchParams.delete("language_code");
2843
2844    const urlString = urlObj.toString();
2845
2846    // const fullURL = this.isProxy()
2847    //   ? document.URL.replaceAll(
2848    //       this.config.requested_domain,
2849    //       this.config.domain
2850    //     )
2851    //   : document.URL;
2852
2853    const fullURL = this.isProxy()
2854      ? urlString.replaceAll(this.config.requested_domain, this.config.domain)
2855      : urlString;
2856
2857    if (
2858      event.target &&
2859      event.target.parentElement &&
2860      event.target.parentElement.nodeName == "STYLE"
2861    ) {
2862      return;
2863    }
2864
2865    // no need to handle text node as it will be handled by DOMCharacterDataModified event
2866    // if (event.target.nodeName === "#text") {
2867    //   return;
2868    // }
2869
2870    // clear translation data and re traverse whole dom on url change in case of SPA
2871    // this.traverse_whole_dom = true;
2872
2873    this.print(3, "domNodeInsertedHandler urls", {
2874      document_url_full: this.document_url_full,
2875      fullURL,
2876    });
2877
2878    if (this.document_url_full !== unformattedFullUrl) {
2879      // this.showLoader();
2880      this.document_url_full = fullURL;
2881      this.translation_api_url = `${this.api_baseurl}/translations?url=${this.document_url_full}`;
2882
2883      this.arr_nodes = {};
2884      this.sentence_nodes = {}
2885      this.sentence_nodes_by_orig_text = {}
2886
2887      this.document_url = document.URL;
2888      this.translation_api_retry_counter = 1;
2889      this.missingTranslationPercentageOffsetForRetry = 1;
2890      // this.translation_api_global_data = {};
2891      this.traverse_whole_dom = true;
2892      console.time("get_values_from_index_db");
2893      if (this.status_api_global_data && !this.status_api_global_data.is_demo) {
2894        //await this.getValuesInIndexObject();
2895      }
2896
2897      this.GetTranslationsApi();
2898      console.timeEnd("get_values_from_index_db");
2899      // this.startTraversingNow();
2900      // await this.checkIfTraversingCompleted();
2901
2902      if (
2903        this.isProxy() ||
2904        this.status_api_global_data.enableSubdomainRedirect
2905      ) {
2906        this.callApiRequest(() =>
2907          this.subscriptionStatusApi(this.status_api_url)
2908        );
2909      }
2910    }
2911    this.translation_api_retry_counter = 1;
2912    this.missingTranslationPercentageOffsetForRetry = 1;
2913    this.traverseNodes(event.target, this.checkNodeType);
2914    this.print(
2915      3,
2916      "domNodeInsertedHandler this.access_token ",
2917      this.access_token
2918    );
2919    await this.checkIfTraversingCompleted();
2920  }
2921
2922  // this function is used for checking authentication which follows flow like first login,status,renderui and then translation
2923  async checkAuthenticationToken(expiryTime, apiKey) {
2924    this.print(3, "in checkAuthenticationToken", expiryTime);
2925
2926    try {
2927      let date = new Date();
2928      // if there is expiry time
2929      if (expiryTime) {
2930        let currentTime = date.getTime() + 1000 * 1 * 60 * 5; // here we added 5 minute offset, we wil get new auth token 5 minute before it expires
2931        // if there is expiry time which has been expired
2932        if (currentTime > expiryTime) {
2933          console.log("in checkAuthenticationToken expiryTime expired", currentTime, expiryTime); 
2934          localStorage.removeItem("devnagri_token");
2935          localStorage.removeItem("devnagri_token_expiry_time");
2936          // just generating new token
2937          let loginPromise = await this.loginApi(this.login_api_url, apiKey);
2938          if (loginPromise) {
2939            let subscriptionPromise = await this.subscriptionStatusApi(
2940              this.status_api_url
2941            );
2942            this.print(
2943              3,
2944              "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1648 ~ Devnagri ~ checkAuthenticationToken ~ subscriptionPromise",
2945              subscriptionPromise
2946            );
2947            if (this.web_owner) {
2948              if (subscriptionPromise.data.subscription == "ACTIVE") {
2949                this.enable_object_mapping =
2950                  subscriptionPromise.data.subscription.enable_object_mapping;
2951                this.renderTranslateUI();
2952                this.subscription_status_active = true;
2953                this.print(3, "setting this.subscription_status_active", true);
2954                let translationPromise = await this.GetTranslationsApi();
2955              } else {
2956                this.subscription_status_active = false;
2957                this.print(3, "setting this.subscription_status_active", false);
2958              }
2959            } else {
2960              if (subscriptionPromise.data.subscription == "ACTIVE") {
2961                this.renderTranslateUI();
2962                if (subscriptionPromise.data.urlStatus == "ACTIVE") {
2963                  this.enable_object_mapping =
2964                    subscriptionPromise.data.subscription.enable_object_mapping;
2965                  this.subscription_status_active = true;
2966                  this.print(
2967                    3,
2968                    "setting this.subscription_status_active",
2969                    true
2970                  );
2971                  let translationPromise = await this.GetTranslationsApi();
2972                } else {
2973                  this.subscription_status_active = false;
2974                  this.print(
2975                    3,
2976                    "setting this.subscription_status_active",
2977                    false
2978                  );
2979                }
2980              } else {
2981                this.subscription_status_active = false;
2982                this.print(3, "setting this.subscription_status_active", false);
2983              }
2984            }
2985          }
2986        }
2987        // if there is expiry time which has not been expired
2988        else {
2989          let subscriptionPromise = await this.subscriptionStatusApi(
2990            this.status_api_url
2991          );
2992          this.print(
2993            3,
2994            "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1648 ~ Devnagri ~ checkAuthenticationToken ~ subscriptionPromise",
2995            subscriptionPromise
2996          );
2997          if (this.web_owner) {
2998            if (subscriptionPromise.data.subscription == "ACTIVE") {
2999              this.enable_object_mapping =
3000                subscriptionPromise.data.subscription.enable_object_mapping;
3001              this.renderTranslateUI();
3002              this.subscription_status_active = true;
3003              this.print(3, "setting this.subscription_status_active", true);
3004              let translationPromise = await this.GetTranslationsApi();
3005            } else {
3006              this.subscription_status_active = false;
3007              this.print(3, "setting this.subscription_status_active", false);
3008            }
3009          } else {
3010            if (subscriptionPromise.data.subscription == "ACTIVE") {
3011              this.renderTranslateUI();
3012              if (subscriptionPromise.data.urlStatus == "ACTIVE") {
3013                this.enable_object_mapping =
3014                  subscriptionPromise.data.subscription.enable_object_mapping;
3015                this.subscription_status_active = true;
3016                this.print(3, "setting this.subscription_status_active", true);
3017
3018                let translationPromise = await this.GetTranslationsApi();
3019              } else {
3020                this.subscription_status_active = false;
3021                this.print(3, "setting this.subscription_status_active", false);
3022              }
3023            } else {
3024              this.subscription_status_active = false;
3025              this.print(3, "setting this.subscription_status_active", false);
3026            }
3027          }
3028        }
3029      } else {
3030        let currentTime = date.getTime() + 1000 * 1 * 60 * 5;
3031        // if there is no expiry time then here expiry time will be generated
3032        this.print(3, "in checkAuthenticationToken no expiryTime");
3033        console.log("in checkAuthenticationToken no expiryTime", currentTime);
3034
3035        if (localStorage.getItem("devnagri_token")) {
3036          localStorage.removeItem("devnagri_token");
3037        }
3038        if (localStorage.getItem("devnagri_token_expiry_time")) {
3039          localStorage.removeItem("devnagri_token_expiry_time");
3040        }
3041        let loginPromise = await this.loginApi(this.login_api_url, apiKey);
3042        if (loginPromise) {
3043          let subscriptionPromise = await this.subscriptionStatusApi(
3044            this.status_api_url
3045          );
3046          this.print(
3047            3,
3048            "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1648 ~ Devnagri ~ checkAuthenticationToken ~ subscriptionPromise",
3049            subscriptionPromise
3050          );
3051          if (subscriptionPromise.data.subscription == "ACTIVE") {
3052            this.renderTranslateUI();
3053            if (subscriptionPromise.data.urlStatus == "ACTIVE") {
3054              this.subscription_status_active = true;
3055              let translationPromise = await this.GetTranslationsApi();
3056              if (
3057                translationPromise &&
3058                translationPromise.message == "success"
3059              ) {
3060              } else {
3061              }
3062            }
3063          } else if (
3064            subscriptionPromise.data.subscription == "ACTIVE" &&
3065            this.web_owner
3066            // &&
3067            // subscriptionPromise.data.urlStatus != "ACTIVE"
3068          ) {
3069            this.subscription_status_active = true;
3070            this.renderTranslateUI();
3071            let translationPromise = await this.GetTranslationsApi();
3072            if (translationPromise && translationPromise.message == "success") {
3073            } else {
3074            }
3075          }
3076        }
3077      }
3078      // return true;
3079    } catch (err) {
3080      this.print(
3081        3,
3082        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 1738 ~ Devnagri ~ checkAuthenticationToken ~ err",
3083        err.message
3084      );
3085      throw err;
3086    }
3087  }
3088
3089  removeExistingProxyDropdown() {
3090    const dropdownElements = document.getElementsByClassName(
3091      "devnagri_outermostdivclass"
3092    );
3093    this.print(
3094      3,
3095      "removeExistingProxyDropdown proxy dropdownElements",
3096      dropdownElements.length,
3097      dropdownElements
3098    );
3099
3100    if (dropdownElements && dropdownElements[0]) {
3101      dropdownElements[0].remove();
3102      // dropdownElements.forEach(dropdown=>dropdown.remove())
3103    }
3104
3105    // this.print(3,"removeExistingProxyDropdown proxy dropdown", dropdown)
3106    // if(dropdown){
3107    //   dropdown.remove()
3108    // }
3109  }
3110
3111  setDropdownPosition(ui_position) {
3112    this.print(
3113      3,
3114      "🚀 ~ setDropdownPosition file: devnagri-dota-merged-client-dev.js ~ line 1777 ~ Devnagri ~ setDropdownPosition ~ ui_position",
3115      ui_position
3116    );
3117    if (ui_position) {
3118      if (ui_position.right != "") {
3119        this.ui_right = ui_position.right;
3120      } else {
3121        if (!ui_position.left) {
3122          this.ui_right = `3%`;
3123        }
3124      }
3125
3126      if (ui_position.bottom != "") {
3127        this.ui_bottom = ui_position.bottom;
3128      } else {
3129        this.ui_bottom = `4%`;
3130      }
3131
3132      if (ui_position.left != "") {
3133        this.ui_left = ui_position.left;
3134      }
3135    } else {
3136      this.ui_right = `3%`;
3137      this.ui_bottom = `4%`;
3138    }
3139  }
3140
3141  static initializeTranslation(config) {
3142    const devnagri = new Devnagri()
3143    devnagri.initTranslation(config)
3144    return devnagri;
3145  }
3146
3147  async initTranslation(config) {
3148	  
3149    addEventListener('DOMContentLoaded', (event) => {
3150      let favIcons = document.getElementsByTagName("link");
3151      for(let favIcon of favIcons){
3152          //console.log(favIcon.getAttribute("rel"))
3153          if(favIcon.getAttribute("rel") == "shortcut icon"){
3154              //console.log(favIcon.getAttribute("rel"))
3155              let Linkhref = favIcon.getAttribute("href");
3156              favIcon.setAttribute("href" , Linkhref.replace(`${document.documentElement.lang}/`, ""));
3157          }
3158      }
3159
3160      let LakhArray = {"hi": "लाख","pa": "ਲੱਖ","ta": "லட்சம்","gu": "લાખ","bn": "লক্ষ","kn": "ಲಕ್ಷ","mr": "लाख","te": "లక్షలు","ml": "ലക്ഷം","as": "লাখ","or": "ଲକ୍ଷ"};
3161      let LakhContent = document.getElementsByClassName("postfix_name");
3162      let languageCode = document.querySelector("html").getAttribute('lang');
3163      for(let l of LakhContent){
3164          l.innerHTML = ` + ${LakhArray[languageCode]}`;
3165      }
3166
3167      // let LakhContent = document.getElementsByClassName("postfix_name");
3168      // if(LakhContent){
3169      //   if (document.documentElement.lang == "as") {
3170      //     for(let l of LakhContent){
3171      //         l.innerHTML = ` + লাখ`;
3172      //     }
3173      //   }
3174      // }
3175         
3176      // let covid19Icon = document.querySelector(".covid-19-new");
3177      // if(covid19Icon){
3178      //   covid19Icon.getElementsByTagName('a')[0].innerHTML = `<i class="covid-19-icon">Covid-19 in India</i>`;
3179      // }
3180  
3181      // let twitterIcon = document.getElementsByClassName("social-content");
3182      // if(twitterIcon){
3183      //   if (twitterIcon.length > 1) {
3184      //     twitterIcon[1].getElementsByTagName('a')[0].innerHTML = `<i class="twitter-icon"></i>MyGov Twitter`;
3185      //   } else {
3186      //     twitterIcon[0].getElementsByTagName('a')[0].innerHTML = `<i class="twitter-icon"></i>MyGov Twitter`;
3187      //   }
3188      // }
3189    });
3190	  
3191	  
3192    this.print(3, "config: ", config);
3193    const proxy_config_keys = [
3194      // "accessToken",
3195      "domain",
3196      "requested_domain",
3197      "siteUrl",
3198      "linkedDomains",
3199      "existingTranslations",
3200    ];
3201    // at-least one of proxy keys exists in the config object
3202    if (proxy_config_keys.map((key) => config[key]).some(Boolean)) {
3203      this.script_type = "proxy";
3204    }
3205
3206    // for live js mode default lang code will be set in login api
3207    if(this.isProxy()){
3208      if (!config.default_lang_code) {
3209        config.default_lang_code = "en";
3210      }
3211      this.default_lang_code = config.default_lang_code
3212    }
3213
3214    if (!config.ui_mode) {
3215      config.ui_mode = "custom";
3216    }
3217
3218    if (!config.apiKey) {
3219      return;
3220    }
3221    // if (!config.accessToken && this.isProxy()) {
3222    //   return;
3223    // }
3224
3225    // consider ui mode as native in case of context editor.
3226    if (this.web_owner) {
3227      config.ui_mode = "native";
3228    }
3229
3230    if (config.ui_mode) {
3231      this.should_render_ui = config.ui_mode;
3232    }
3233
3234    this.print(3, "isProxy", this.isProxy());
3235
3236    // if(this.isProxy()){
3237    //   requestAnimationFrame(() => {
3238    //     setTimeout(() => {
3239    //       document.addEventListener("DOMContentLoaded",this.removeExistingProxyDropdown)
3240    //     },0);
3241    //   });
3242    //   // this.removeExistingProxyDropdown()
3243    // }
3244
3245    if (!this.access_token) {
3246      await this.loginApi(this.login_api_url, config.apiKey);
3247    }
3248
3249    this.api_key = config.apiKey;
3250
3251    this.document_url = config.domain;
3252
3253    this.document_url_full = this.isProxy()
3254      ? document.URL.replaceAll(config.requested_domain, config.domain)
3255      : document.URL;
3256
3257    this.subdomainObjectStore = this.isProxy()
3258      ? this.default_lang_code
3259      : config.target_lang_code;
3260    this.print(3, "this.subdomainObjectStore", this.subdomainObjectStore);
3261
3262    if (this.isLiveJs() || this.isProxy()) {
3263      if (this.isLiveJs()) {
3264        // if (config.ui_mode.toLowerCase() != "custom") {
3265          this.cssLinkInjection();
3266        // }
3267      }
3268
3269      if (this.isProxy()) {
3270        this.cssLinkInjection();
3271        this.web_owner = false;
3272      }
3273
3274      // this.setDropdownPosition(config.ui_position);
3275
3276      // used selected lang code for because in upper portion of the code we already picked code from query param and assigned it to selected_lang_code
3277      this.default_lang_code = this.web_owner
3278        ? this.selected_lang_code
3279        : this.default_lang_code;
3280      if (this.selected_lang_code === this.source_lang_code) {
3281        this.selected_lang_code = this.default_lang_code;
3282      }
3283      // select by def english
3284      // if (!localStorage.getItem("devnagri_selected_lang_code")) {
3285      //   localStorage.setItem(
3286      //     "devnagri_selected_lang_code",
3287      //     this.source_lang_code
3288      //   );
3289      // }
3290      this.print(3, "before checkAuthenticationToken");
3291      this.print(3, "checkAuthenticationToken", this.checkAuthenticationToken);
3292      const result = await this.checkAuthenticationToken(
3293        this.expiry_token_time,
3294        config.apiKey
3295      );
3296      this.print(3, "after checkAuthenticationToken");
3297
3298      this.print(
3299        3,
3300        "🚀 ~ file: devnagri-dota-client.js ~ line 1710 ~ Devnagri ~ initTranslation ~ this.access_token",
3301        this.access_token
3302      );
3303      this.print(
3304        3,
3305        "🚀 ~ file: devnagri-dota-client.js ~ line 1710 ~ Devnagri ~ initTranslation ~ this.subscription_status_active",
3306        this.subscription_status_active
3307      );
3308      if (this.subscription_status_active) {
3309        // if (
3310        //   this.status_api_global_data &&
3311        //   this.status_api_global_data.enable_object_mapping
3312        //   // this.isProxy()
3313        // ) {
3314        //   await this.getObjectUrlsApi();
3315        // }
3316
3317        this.startTraversingNow();
3318        await this.checkIfTraversingCompleted();
3319        // set text direction rtl for urdu
3320        const rtlLangs = ["ur","ar"]
3321        if (rtlLangs.includes(this.selected_lang_code)) {
3322          console.log("setting text direction rtl for urdu")
3323          document.body.setAttribute("dir", "rtl");
3324        }else{
3325          console.log("setting text direction ltr for other langs");
3326          document.body.setAttribute("dir", "ltr");
3327        }
3328      }
3329    }
3330
3331    // const enableDynamicTranslation = !(config.domain && (config.domain.includes("devnagri") || config.domain.includes("fourtek")))
3332    const enableDynamicTranslation = !config.enable_static_content;
3333    // this.print(3,"-> enableDynamicTranslation", enableDynamicTranslation);
3334
3335    this.enable_object_mapping = config.enable_object_mapping;
3336
3337    this.translation_api_url = `${this.api_baseurl}/translations?rl=${this.document_url_full}`;
3338    this.update_api_url = `${this.api_baseurl}/translations`;
3339
3340    this.target_lang_code = config.target_lang_code;
3341
3342    this.api_key = config.apiKey;
3343    this.translation_api_global_data = this.isProxy()
3344      ? this.cleanExistingTranslationObj(config.existingTranslations)
3345      : {};
3346
3347    if (enableDynamicTranslation) {
3348      if (this.translation_api_global_data) {
3349        if (this.status_api_global_data && !this.status_api_global_data.is_demo) {
3350          //this.storeValuesInIndexDB(this.translation_api_global_data);
3351        }
3352      }
3353    }
3354
3355    if (this.isProxy()) {
3356      this.domain = config.domain;
3357      this.requested_domain = config.requested_domain;
3358      // this.linkedDomains = config.linkedDomains;
3359      this.subdomain_object_urls_hash_map =
3360        config.subdomain_object_urls_hash_map;
3361      // this.enable_blacklist = config.enable_blacklist;
3362      // this.blacklist_classes = config.blacklist_classes;
3363      // this.blacklist_ids = config.blacklist_ids;
3364    }
3365
3366    // if (
3367    //   config.subdomain_object_urls_hash_map &&
3368    //   typeof config.subdomain_object_urls_hash_map === "object"
3369    // ) {
3370    //   const objectsArr = Object.values(config.subdomain_object_urls_hash_map);
3371    //   const localObjectUrlsHashMap = {};
3372    //   objectsArr.forEach((object) => {
3373    //     localObjectUrlsHashMap[object.local_url] = object;
3374    //   });
3375    //   this.subdomain_object_urls_hash_map_local = localObjectUrlsHashMap;
3376    // }
3377
3378    this.config = config;
3379
3380    this.frame_ids.forEach(
3381      (frameId) => (this.frames_translation_status_map[frameId] = true)
3382    );
3383
3384    if (enableDynamicTranslation) {
3385      if (this.isProxy()) {
3386        // document.addEventListener("DOMCharacterDataModified", (event) => {
3387        //   if (!this.edit_mode_enabled) {
3388        //     if (this.source_lang_code === this.selected_lang_code) {
3389        //       return;
3390        //     }
3391        //     if (this.source_lang_code !== this.selected_lang_code) {
3392        //       const cleanValue = this.cleanString(event.target.textContent);
3393        //       if (cleanValue && !this.isTextTranslatedText(cleanValue)) {
3394        //         if (this.enable_blacklist) {
3395        //           const parentElement = event.target.parentElement;
3396        //           var th = this;
3397        //           // node blacklist by class condition
3398        //           if (
3399        //             this.blacklist_classes
3400        //               .map(
3401        //                 (item) =>
3402        //                   parentElement &&
3403        //                   parentElement.getAttribute("class") &&
3404        //                   th.isExactMatch(parentElement.getAttribute("class"), item)
3405        //               )
3406        //               .some(Boolean)
3407        //           ) {
3408        //             this.print(
3409        //               3,
3410        //               "ignoring element with classname " +
3411        //                 parentElement.getAttribute("class")
3412        //             );
3413
3414        //             return;
3415        //           }
3416
3417        //           // node blacklist by id condition
3418        //           if (
3419        //             parentElement &&
3420        //             parentElement.getAttribute &&
3421        //             parentElement.getAttribute("id") &&
3422        //             this.blacklist_ids.includes(
3423        //               parentElement.getAttribute("id")
3424        //             )
3425        //           ) {
3426        //             this.print(
3427        //               3,
3428        //               "ignoring element with id " +
3429        //                 parentElement.getAttribute("id")
3430        //             );
3431        //             return;
3432        //           }
3433        //         }
3434
3435        //         const node = event.target;
3436        //         if(this.enable_sentence_merging && node && node.parentElement && this.isNodeASentence(node.parentElement)){
3437        //           this.traverseNodes(node.parentElement, this.checkNodeType);
3438        //         }else{
3439        //           this.traverseNodes(event.target, this.checkNodeType);
3440        //         }
3441        //       }
3442        //     }
3443        //   }
3444        // });
3445
3446        // Create a MutationObserver instance
3447        const observer = new MutationObserver((mutationsList) => {
3448          for (const mutation of mutationsList) {
3449            if (mutation.type === 'characterData') {
3450              const event = mutation;
3451              if (!this.edit_mode_enabled) {
3452                if (this.source_lang_code === this.selected_lang_code) {
3453                  return;
3454                }
3455                if (this.source_lang_code !== this.selected_lang_code) {
3456                  const cleanValue = this.cleanString(event.target.textContent);
3457                  if (cleanValue && !this.isTextTranslatedText(cleanValue)) {
3458                    if (this.enable_blacklist) {
3459                      const parentElement = event.target.parentElement;
3460                      var th = this;
3461                      // node blacklist by class condition
3462                      if (
3463                        this.blacklist_classes
3464                          .map(
3465                            (item) =>
3466                              parentElement &&
3467                              parentElement.getAttribute("class") &&
3468                              th.isExactMatch(parentElement.getAttribute("class"), item)
3469                          )
3470                          .some(Boolean)
3471                      ) {
3472                        this.print(
3473                          3,
3474                          "ignoring element with classname " +
3475                            parentElement.getAttribute("class")
3476                        );
3477
3478                        return;
3479                      }
3480
3481                      // node blacklist by id condition
3482                      if (
3483                        parentElement &&
3484                        parentElement.getAttribute &&
3485                        parentElement.getAttribute("id") &&
3486                        this.blacklist_ids.includes(
3487                          parentElement.getAttribute("id")
3488                        )
3489                      ) {
3490                        this.print(
3491                          3,
3492                          "ignoring element with id " +
3493                            parentElement.getAttribute("id")
3494                        );
3495                        return;
3496                      }
3497                    }
3498
3499                    const node = event.target;
3500                    if(this.enable_sentence_merging && node && node.parentElement && this.isNodeASentence(node.parentElement)){
3501                      this.traverseNodes(node.parentElement, this.checkNodeType);
3502                    }else{
3503                      this.traverseNodes(event.target, this.checkNodeType);
3504                    }
3505                  }
3506                }
3507              }
3508            }
3509          }
3510        });
3511
3512        // Start observing the document for character data changes
3513        observer.observe(document.body, {
3514          characterData: true,
3515          subtree: true
3516        });
3517      }
3518
3519      // for getting notify dynamic rendering
3520      // document.addEventListener("DOMNodeInserted", (e) => {
3521      //   this.print(3, "DOMNodeInserted");
3522      //   if (!this.edit_mode_enabled) {
3523      //     if (this.source_lang_code === this.selected_lang_code) {
3524      //       return;
3525      //     }
3526      //     if (
3527      //       Object.values(this.frames_translation_status_map).some((val) => val)
3528      //     ) {
3529      //       this.translateAllFramesOnPage();
3530      //     }
3531      //     this.domNodeInsertedHandler(e);
3532      //   }
3533
3534      //   // fix for a tag 
3535      //   if (this.isProxy()) {
3536      //     const aTags = document.getElementsByTagName("a");
3537      //     //Get Language DropDown A Tags
3538      //     const aTagsLanguageSwitcher = document.getElementsByClassName("language-link ");
3539      //     let aTagsLanguageSwitcherArray = [];
3540      //     for(let aTagLS of aTagsLanguageSwitcher){
3541      //       aTagsLanguageSwitcherArray.push(aTagLS.getAttribute("href"));
3542      //     }
3543          
3544	    //     var devnagriLanguageSwitcherArray = [];
3545      //     /* for (let i = 0; i < this.status_api_global_data.subdomains.length; i++) {
3546      //         if(this.status_api_global_data.subdomains[i].code != 'en'){
3547      //           devnagriLanguageSwitcherArray.push(this.status_api_global_data.subdomains[i].subdomain); 
3548      //         }
3549      //     } */
3550
3551          
3552      //     const devnagriLanguageSwitcher = document.querySelectorAll(".devnagri_optionElement a");
3553      //     for(let aTagDLS of devnagriLanguageSwitcher){
3554      //       if(aTagDLS.parentElement.getAttribute("devnagri_lang_code_attribute") != 'en'){
3555      //         devnagriLanguageSwitcherArray.push(aTagDLS.getAttribute("href"));
3556      //       }
3557      //     }
3558
3559      //     for(let aTag of aTags){
3560      //       let href = aTag.getAttribute("href");
3561
3562      //       //Prevent for Language Dropdown
3563      //       if(aTagsLanguageSwitcherArray.includes(href)){
3564      //         continue;
3565      //       }
3566 	  
3567      //       if(devnagriLanguageSwitcherArray.includes(href)){
3568      //         continue;
3569      //       }
3570      //       if(['kn', 'ml', 'ta', 'hi'].includes(document.documentElement.lang)){
3571      //         if(href && !href.includes(`https://${window.location.hostname}/${document.documentElement.lang}`) && href.includes(`https://${window.location.hostname}`)){
3572      //           aTag.setAttribute("href", href.replace(`${this.domain}`, `https://${window.location.hostname}/${document.documentElement.lang}`));
3573      //         }
3574      //         if(href && href[0] == "/"){
3575
3576      //           aTag.setAttribute("href", href.replace(`/`, `https://${window.location.hostname}/${document.documentElement.lang}/`));
3577      //         }
3578      //       }else{
3579      //         if(href && !href.includes(`https://${window.location.hostname}`)){
3580      //           aTag.setAttribute("href", href.replace(`${this.domain}`, `https://${window.location.hostname}`));
3581      //         }
3582      //         if(href && href[0] == "/"){
3583
3584      //           aTag.setAttribute("href", href.replace(`/`, `https://${window.location.hostname}/`));
3585      //         }
3586      //       }
3587      //     }
3588      //   }
3589      // });
3590
3591      // Create a MutationObserver instance
3592      const observer = new MutationObserver((mutationsList) => {
3593        for (const mutation of mutationsList) {
3594          if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
3595            this.print(3, "DOMNodeInserted");
3596            if (!this.edit_mode_enabled) {
3597              if (this.source_lang_code === this.selected_lang_code) {
3598                return;
3599              }
3600              if (Object.values(this.frames_translation_status_map).some((val) 
3600=> val)) {
3601                this.translateAllFramesOnPage();
3602              }
3603              this.domNodeInsertedHandler(mutation);
3604            }
3605
3606            // fix for a tag 
3607            if (this.isProxy()) {
3608              const aTags = document.getElementsByTagName("a");
3609              // Get Language DropDown A Tags
3610              const aTagsLanguageSwitcher = document.getElementsByClassName("language-link ");
3611              let aTagsLanguageSwitcherArray = [];
3612              for (let aTagLS of aTagsLanguageSwitcher) {
3613                aTagsLanguageSwitcherArray.push(aTagLS.getAttribute("href"));
3614              }
3615
3616              var devnagriLanguageSwitcherArray = [];
3617              /* for (let i = 0; i < this.status_api_global_data.subdomains.length; i++) {
3618                  if(this.status_api_global_data.subdomains[i].code != 'en'){
3619                    devnagriLanguageSwitcherArray.push(this.status_api_global_data.subdomains[i].subdomain); 
3620                  }
3621              } */
3622
3623              const devnagriLanguageSwitcher = document.querySelectorAll(".devnagri_optionElement a");
3624              for (let aTagDLS of devnagriLanguageSwitcher) {
3625                if (aTagDLS.parentElement.getAttribute("devnagri_lang_code_attribute") != 'en') {
3626                  devnagriLanguageSwitcherArray.push(aTagDLS.getAttribute("href"));
3627                }
3628              }
3629
3630              for (let aTag of aTags) {
3631                let href = aTag.getAttribute("href");
3632
3633                // Prevent for Language Dropdown
3634                if (aTagsLanguageSwitcherArray.includes(href)) {
3635                  continue;
3636                }
3637
3638                if (devnagriLanguageSwitcherArray.includes(href)) {
3639                  continue;
3640                }
3641                if (['kn', 'ml', 'ta', 'hi'].includes(document.documentElement.lang)) {
3642                  if (href && !href.includes(`https://${window.location.hostname}/${document.documentElement.lang}`) && href.includes(`https://${window.location.hostname}`)) {
3643                    aTag.setAttribute("href", href.replace(`${this.domain}`, `https://${window.location.hostname}/${document.documentElement.lang}`));
3644                  }
3645                  if (href && href[0] == "/") {
3646                    aTag.setAttribute("href", href.replace(`/`, `https://${window.location.hostname}/${document.documentElement.lang}/`));
3647                  }
3648                } else {
3649                  if (href && !href.includes(`https://${window.location.hostname}`)) {
3650                    aTag.setAttribute("href", href.replace(`${this.domain}`, `https://${window.location.hostname}`));
3651                  }
3652                  if (href && href[0] == "/") {
3653                    aTag.setAttribute("href", href.replace(`/`, `https://${window.location.hostname}/`));
3654                  }
3655                }
3656              }
3657            }
3658          }
3659        }
3660      });
3661
3662      // Start observing the document for added nodes
3663      observer.observe(document.body, {
3664        childList: true,
3665        attributes: true,
3666        characterData: true,
3667        subtree: true
3668      });
3669      this.GetTranslationsApi();
3670    }
3671
3672    if (this.isProxy()) {
3673      if (enableDynamicTranslation) {
3674        // this.get_user_location();
3675        await this.callApiRequest(() =>
3676          this.subscriptionStatusApi(this.status_api_url)
3677        );
3678      }
3679    }
3680  }
3681
3682  async delay(ms) {
3683    return new Promise((res) => setTimeout(res, ms));
3684  }
3685
3686  async updateGlobalData() {
3687    if (!this.update_global_data_timeout) {
3688      const self = this;
3689      this.print(3, "updateGlobalData this.access_token", this.access_token);
3690
3691      this.update_global_data_timeout = setTimeout(async () => {
3692        this.print(
3693          3,
3694          "updateGlobalData timeout this.access_token",
3695          self.access_token
3696        );
3697        //if(this.apiCounter <= 1)
3698        {
3699          await this.sentenceUpdateApi();
3700          await this.delay(2000);
3701          await this.GetTranslationsApi();
3702        }
3703        if (this.traverse_whole_dom) {
3704          this.traverseAndSetTranslationOfWholePage();
3705        }
3706        this.update_global_data_timeout = null;
3707      }, 3000);
3708    }
3709  }
3710
3711  async calculateMissingTranslationPercentage() {
3712    let translationData = this.translation_api_global_data;
3713    let nodesCount = Object.keys(this.arr_nodes).length;
3714    if (!translationData || nodesCount == 0) {
3715      return;
3716    }
3717    let missingTranslations = [];
3718    for (let key of Object.keys(this.arr_nodes)) {
3719      let txtOriginal = key;
3720      if (txtOriginal.startsWith(this.meta_prefix)) {
3721        txtOriginal = txtOriginal.replace(this.meta_prefix, "");
3722      }
3723      if (translationData[this.cleanString(txtOriginal)]) {
3724        this.arr_nodes[this.cleanString(key)].translatedText =
3725          translationData[this.cleanString(txtOriginal)];
3726      } else {
3727        if (!missingTranslations.includes(key)) {
3728          missingTranslations.push(key);
3729        }
3730        this.print(
3731          2,
3732          "translation not found for key = '" + key + "'",
3733          translationData
3734        );
3735      }
3736    }
3737
3738    let missingPercentage = (missingTranslations.length * 100) / nodesCount;
3739    this.print(
3740      2,
3741      "translation missing number = " +
3742        missingTranslations.length +
3743        " missing percentage = " +
3744        missingPercentage +
3745        " total nodes = " +
3746        nodesCount
3747    );
3748    return missingPercentage;
3749  }
3750
3751  // Live js methodes
3752  // async checkAuthenticationToken(expiryTime, apiKey) {
3753  //   try {
3754  //     // if there is expiry time
3755  //     if (expiryTime) {
3756  //       let date = new Date();
3757  //       let currentTime = date.getTime() + 1000 * 1 * 60 * 5; // here we added 5 minute offset, we wil get new auth token 5 minute before it expires
3758  //       // if there is expiry time which has been expired
3759  //       if (currentTime > expiryTime) {
3760  //         localStorage.removeItem("devnagri_token");
3761  //         localStorage.removeItem("devnagri_token_expiry_time");
3762  //         // just generating new token
3763  //         let loginPromise = await this.loginApi(this.login_api_url, apiKey);
3764  //         if (loginPromise) {
3765  //           let subscriptionPromise = await this.subscriptionStatusApi(
3766  //             this.status_api_url
3767  //           );
3768  //           if (this.web_owner) {
3769  //             if (subscriptionPromise.data.subscription == "ACTIVE") {
3770  //               this.enable_object_mapping =
3771  //                 subscriptionPromise.data.subscription.enable_object_mapping;
3772  //               this.renderTranslateUI();
3773  //               this.subscription_status_active = true;
3774  //               this.print(3, "setting this.subscription_status_active", true);
3775  //               let translationPromise = await this.GetTranslationsApi();
3776  //             } else {
3777  //               this.subscription_status_active = false;
3778  //               this.print(3, "setting this.subscription_status_active", false);
3779  //             }
3780  //           } else {
3781  //             if (subscriptionPromise.data.subscription == "ACTIVE") {
3782  //               this.renderTranslateUI();
3783
3784  //               if (subscriptionPromise.data.urlStatus == "ACTIVE") {
3785  //                 this.enable_object_mapping =
3786  //                   subscriptionPromise.data.subscription.enable_object_mapping;
3787  //                 this.subscription_status_active = true;
3788  //                 this.print(
3789  //                   3,
3790  //                   "setting this.subscription_status_active",
3791  //                   true
3792  //                 );
3793  //                 let translationPromise = await this.GetTranslationsApi();
3794  //               } else {
3795  //                 this.subscription_status_active = false;
3796  //                 this.print(
3797  //                   3,
3798  //                   "setting this.subscription_status_active",
3799  //                   false
3800  //                 );
3801  //               }
3802  //             } else {
3803  //               this.subscription_status_active = false;
3804  //               this.print(3, "setting this.subscription_status_active", false);
3805  //             }
3806  //           }
3807  //         }
3808  //       }
3809  //       // if there is expiry time which has not been expired
3810  //       else {
3811  //         let subscriptionPromise = await this.subscriptionStatusApi(
3812  //           this.status_api_url
3813  //         );
3814  //         if (this.web_owner) {
3815  //           if (subscriptionPromise.data.subscription == "ACTIVE") {
3816  //             this.enable_object_mapping =
3817  //               subscriptionPromise.data.subscription.enable_object_mapping;
3818  //             this.renderTranslateUI();
3819  //             this.subscription_status_active = true;
3820  //             this.print(3, "setting this.subscription_status_active", true);
3821  //             let translationPromise = await this.GetTranslationsApi();
3822  //           } else {
3823  //             this.subscription_status_active = false;
3824  //             this.print(3, "setting this.subscription_status_active", false);
3825  //           }
3826  //         } else {
3827  //           if (subscriptionPromise.data.subscription == "ACTIVE") {
3828  //             this.renderTranslateUI();
3829  //             if (subscriptionPromise.data.urlStatus == "ACTIVE") {
3830  //               this.enable_object_mapping =
3831  //                 subscriptionPromise.data.subscription.enable_object_mapping;
3832  //               this.subscription_status_active = true;
3833  //               this.print(3, "setting this.subscription_status_active", true);
3834
3835  //               let translationPromise = await this.GetTranslationsApi();
3836  //             } else {
3837  //               this.subscription_status_active = false;
3838  //               this.print(3, "setting this.subscription_status_active", false);
3839  //             }
3840  //           } else {
3841  //             this.subscription_status_active = false;
3842  //             this.print(3, "setting this.subscription_status_active", false);
3843  //           }
3844  //         }
3845  //       }
3846  //     }
3847  //     // if there is no expiry time then here expiry time will be generated
3848  //     else {
3849  //       if (localStorage.getItem("devnagri_token")) {
3850  //         localStorage.removeItem("devnagri_token");
3851  //       }
3852  //       if (localStorage.getItem("devnagri_token_expiry_time")) {
3853  //         localStorage.removeItem("devnagri_token_expiry_time");
3854  //       }
3855  //       let loginPromise = await this.loginApi(this.login_api_url, apiKey);
3856  //       if (loginPromise) {
3857  //         let subscriptionPromise = await this.subscriptionStatusApi(
3858  //           this.status_api_url
3859  //         );
3860  //         if (subscriptionPromise.data.subscription == "ACTIVE") {
3861  //           this.renderTranslateUI();
3862  //           let translationPromise = await this.GetTranslationsApi();
3863  //           if (translationPromise && translationPromise.message == "success") {
3864  //           } else {
3865  //           }
3866  //         } else if (
3867  //           subscriptionPromise.data.subscription == "ACTIVE" &&
3868  //           this.web_owner &&
3869  //           subscriptionPromise.data.urlStatus != "ACTIVE"
3870  //         ) {
3871  //           this.renderTranslateUI();
3872  //           let translationPromise = await this.GetTranslationsApi();
3873  //           if (translationPromise && translationPromise.message == "success") {
3874  //           } else {
3875  //           }
3876  //         }
3877  //       }
3878  //     }
3879  //     return true;
3880  //   } catch (err) {
3881  //     throw err;
3882  //   }
3883  // }
3884
3885  renderTranslateUI() {
3886    this.print(3, "renderTranslateUI", {
3887      should_render_ui: this.should_render_ui,
3888      renderUICounter: this.renderUICounter,
3889    });
3890    // this.removeExistingProxyDropdown();
3891    // if (this.isProxy()) {
3892    //   this.setEventHandlerOfProxyDropDown();
3893    //   return;
3894    // }
3895
3896    if (
3897      this.should_render_ui &&
3898      this.should_render_ui.toLowerCase() === "custom"
3899    ) {
3900      return true;
3901    }
3902
3903    if (this.renderUICounter < 1) {
3904      return true;
3905    }
3906
3907    let outerMostDiv = document.createElement("div");
3908    outerMostDiv.id = "devnagri_outermostdiv";
3909    outerMostDiv.setAttribute("class", "devnagri_outermostdivclass");
3910    let position = "  z-index: 2147483647;position:fixed;";
3911
3912    if (this.ui_bottom) {
3913      position += `bottom:${this.ui_bottom};`;
3914    }
3915    if (this.ui_left) {
3916      position += `left:${this.ui_left};`;
3917    }
3918    if (this.ui_right) {
3919      position += `right:${this.ui_right};`;
3920    }
3921
3922    // if (this.ui_top) {
3923    //   position += `top:${this.ui_top};`;
3924    // }
3925    outerMostDiv.style.cssText = position;
3926
3927    this.initialdiv = document.createElement("div");
3928    this.initialdiv.id = "devnagri_outermostdiv";
3929    this.initialdiv.classList.add("devnagri_open_button");
3930
3931    if (this.web_owner) {
3932      this.WebOwnerEnableButton();
3933    }
3934
3935    let div4 = document.createElement("div");
3936    div4.setAttribute("style", "float:left");
3937
3938    let logo = document.createElement("div");
3939    logo.classList.add("devnagri_logo", "Devnagri-tooltip-toggle-pencil");
3940    logo.id = "devnagri_optionElementt";
3941    logo.setAttribute("style", "background-color:white");
3942    logo.setAttribute("data-tooltip", "Powered By Devnagri");
3943    logo.innerHTML = this.devngari_logo_svg_content;
3944
3945    div4.appendChild(logo);
3946    this.initialdiv.appendChild(div4);
3947    let div5 = document.createElement("div");
3948    div5.setAttribute("style", "float:left");
3949    this.defaultLanguage = document.createElement("h3");
3950    this.defaultLanguage.setAttribute("style", "background-color:white");
3951    this.defaultLanguage.classList.add("devnagri_written_lang");
3952    this.defaultLanguage.id = "devnagri_optionElementt";
3953    this.defaultLanguage.innerText = "";
3954    this.defaultLanguage.onclick = () => this.openDropdown();
3955    div5.appendChild(this.defaultLanguage);
3956    this.initialdiv.appendChild(div5);
3957
3958    let div6 = document.createElement("div");
3959    div6.setAttribute("style", "float:left");
3960    let upArrow = document.createElement("div");
3961    upArrow.classList.add("devnagri_upArrow");
3962    upArrow.id = "devnagri_optionElementt";
3963    upArrow.setAttribute("style", "background-color:white");
3964    upArrow.onclick = () => this.openDropdown();
3965    upArrow.innerHTML = this.up_arrow_svg_content;
3966    div6.appendChild(upArrow);
3967    this.initialdiv.appendChild(div6);
3968
3969    let body = document.getElementsByTagName("body")[0];
3970
3971    if (this.status_api_global_data) {
3972      body.appendChild(this.initialdiv);
3973      if (document.querySelector(".devnagri_owner_button")) {
3974        document.querySelector(".devnagri_owner_button").style.display = "none";
3975      }
3976      if (document.querySelector(".devnagri_vl")) {
3977        document.querySelector(".devnagri_vl").style.display = "none";
3978      }
3979      if (this.default_lang_code == "en") {
3980        if (document.querySelector(".devnagri_owner_button")) {
3981          document.querySelector(".devnagri_owner_button").style.display =
3982            "none";
3983          document.querySelector(".devnagri_vl").style.display = "none";
3984        }
3985      } else {
3986        if (document.querySelector(".devnagri_owner_button")) {
3987          document.querySelector(".devnagri_owner_button").style.display =
3988            "block";
3989        }
3990        if (document.querySelector(".devnagri_vl")) {
3991          document.querySelector(".devnagri_vl").style.display = "block";
3992        }
3993      }
3994    }
3995    outerMostDiv.appendChild(this.initialdiv);
3996    document.body.insertBefore(this.initialdiv, document.body[0]);
3997    let div = document.createElement("div");
3998    div.id = "devnagri_dropdown";
3999    div.className = "devnagri_container";
4000    div.setAttribute("devnagri_option", "devnagri_optionElement");
4001    var ul = document.createElement("ul");
4002    ul.setAttribute("type", "none");
4003    div.appendChild(ul);
4004
4005    var enableSubdomainRedirect =
4006      this.status_api_global_data.enableSubdomainRedirect || this.isProxy();
4007
4008    if (enableSubdomainRedirect && !this.web_owner) {
4009      for (let i = 0; i < this.status_api_global_data.subdomains.length; i++) {
4010        let li = document.createElement("li");
4011
4012/*const isSubfolder = this.status_api_global_data.subdomains[i].subdomain.includes("/")
4013let path = location.pathname
4014
4015if(isSubfolder){
4016  let pathArr = path.split("/")
4017  pathArr.shift();
4018  pathArr.shift();
4019  path = "/" + pathArr.join("/")
4020}*/
4021	//console.log("testing",`${location.protocol}//${this.status_api_global_data.subdomains[i].subdomain}${path}${location.search}`, location, this.status_api_global_data.subdomains[i]) 
4022
4023        let anchorTag = document.createElement("a");
4024        anchorTag.setAttribute("id", "devnagri_subdomain");
4025        /*anchorTag.setAttribute(
4026          "href",
4027          ` ${location.protocol}//${this.status_api_global_data.subdomains[i].subdomain}${location.pathname}${location.search}`
4028        );*/
4029
4030//const isSubfolder = this.status_api_global_data.subdomains[i].subdomain.includes("/")
4031	    const currentSubdomain = this.status_api_global_data.subdomains.find(subdomain => subdomain.code === this.selected_lang_code)
4032        const isSubfolder = currentSubdomain && currentSubdomain.subdomain && currentSubdomain.subdomain.includes("/")
4033//console.log("renderTranslateUI", "currentSubdomain", currentSubdomain, "this.selected_lang_code", this.selected_lang_code);
4034
4035let path = location.pathname
4036
4037if(isSubfolder){
4038  let pathArr = path.split("/")
4039  pathArr.shift();
4040  pathArr.shift();
4041  path = "/" + pathArr.join("/")
4042  
4043anchorTag.setAttribute(
4044          "href",
4045          ` ${location.protocol}//${this.status_api_global_data.subdomains[i].subdomain}${path}${location.search}`)
4046}
4047else
4048{
4049        anchorTag.setAttribute(
4050          "href",
4051          ` ${location.protocol}//${this.status_api_global_data.subdomains[i].subdomain}${location.pathname}${location.search}`
4052        );
4053}
4054        anchorTag.innerHTML = this.status_api_global_data.subdomains[i].name;
4055        li.appendChild(anchorTag);
4056        li.setAttribute("id", "devnagri_li");
4057        li.setAttribute(
4058          "devnagri_lang_code_attribute",
4059          this.status_api_global_data.subdomains[i].code
4060        );
4061        li.setAttribute("class", "devnagri_optionElement");
4062        ul.appendChild(li);
4063      }
4064    } else {
4065      for (let i = 0; i < this.lang.length; i++) {
4066        let li = document.createElement("li");
4067        let splitStr = this.lang[i].name.split("-");
4068        li.setAttribute("id", "devnagri_li");
4069        li.innerHTML = splitStr[splitStr.length - 1].trim();
4070        li.setAttribute("devnagri_lang_code_attribute", this.lang[i].code);
4071        li.setAttribute("class", "devnagri_optionElement");
4072        li.onclick = () => {
4073          this.onLangSelection(this.lang[i].code);
4074        };
4075        ul.appendChild(li);
4076      }
4077    }
4078
4079    outerMostDiv.appendChild(div);
4080    outerMostDiv.appendChild(this.initialdiv);
4081
4082    document.body.insertBefore(outerMostDiv, document.body[1]);
4083
4084    // document.body.insertBefore(div, document.body[1]);
4085    const selected_lang = localStorage.getItem("devnagri_selected_lang_code")
4086      ? localStorage.getItem("devnagri_selected_lang_code")
4087      : this.default_lang_code;
4088
4089    this.activeLanguage(this.selected_lang_code);
4090    --this.renderUICounter;
4091
4092    this.print(3, "renderTranslateUI", {
4093      should_render_ui: this.should_render_ui,
4094      renderUICounter: this.renderUICounter,
4095    });
4096  }
4097
4098  // make avtive lang with blue color
4099  activeLanguage(selected_lang_code) {
4100    if (
4101      this.should_render_ui &&
4102      this.should_render_ui.toLowerCase() === "custom"
4103    ) {
4104      return true;
4105    }
4106    if (
4107      (this.status_api_global_data.enableSubdomainRedirect || this.isProxy()) &&
4108      !this.web_owner
4109    ) {
4110      let x = document.querySelectorAll("#devnagri_li");
4111
4112      for (let i = 0; i < x.length; i++) {
4113        if (
4114          x[i].getAttribute("devnagri_lang_code_attribute") ==
4115          selected_lang_code
4116        ) {
4117          if (x[i].firstChild) {
4118            this.defaultLanguage.innerText = x[i].firstChild.innerText;
4119            x[i].firstChild.setAttribute("style", "color:blue");
4120          }
4121        } else {
4122          if (x[i].firstChild) {
4123            x[i].firstChild.removeAttribute("style");
4124          }
4125        }
4126      }
4127    } else {
4128      let x = document.querySelectorAll("#devnagri_li");
4129      for (let i = 0; i < x.length; i++) {
4130        if (
4131          x[i].getAttribute("devnagri_lang_code_attribute") ==
4132          selected_lang_code
4133        ) {
4134          this.defaultLanguage.innerText = x[i].innerText;
4135          x[i].setAttribute("style", "color:blue");
4136        } else {
4137          x[i].removeAttribute("style");
4138        }
4139      }
4140    }
4141  }
4142
4143  // in context editor when web owner edit anything
4144  DataAttributeDataChangeListioner() {
4145    let element = document.querySelector(".devnagri_unsavedChanges");
4146    if (element) {
4147      element.remove();
4148    }
4149    let divForUnSavedChange = document.createElement("div");
4150    divForUnSavedChange.innerText = "You have unsaved changes";
4151    divForUnSavedChange.classList.add("devnagri_unsavedChanges");
4152    divForUnSavedChange.id = "devnagri_optionElementt";
4153    let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4154    outerMostDiv.appendChild(divForUnSavedChange);
4155    // body.appendChild(divForUnSavedChange);
4156  }
4157
4158  //this will add event listener when web owner edit any text
4159  AddDataAttributeDataChangeListioner() {
4160    if (this.web_owner) {
4161      this.RemoveDataAttributeDataChangeListioner();
4162      window.addEventListener(
4163        "DOMCharacterDataModified",
4164        this.DataAttributeDataChangeListioner
4165      );
4166    }
4167  }
4168  //this will remove event listener
4169  RemoveDataAttributeDataChangeListioner() {
4170    window.removeEventListener(
4171      "DOMCharacterDataModified",
4172      this.DataAttributeDataChangeListioner
4173    );
4174  }
4175  // available languages for dropdpwn when ui_mode is custom
4176  availableLanguages() {
4177    if (
4178      this.should_render_ui &&
4179      this.should_render_ui.toLowerCase() === "custom"
4180    ) {
4181      return true;
4182    }
4183    return this.lang;
4184  }
4185
4186  // toggling(display) language button
4187  openDropdown() {
4188    if (
4189      this.should_render_ui &&
4190      this.should_render_ui.toLowerCase() === "custom"
4191    ) {
4192      return true;
4193    }
4194    let x = document.getElementById("devnagri_dropdown");
4195    if (x && x.style.display === "block") {
4196      x.style.display = "none";
4197    } else {
4198      var width;
4199      let dotaSelectContainer = document.querySelector(".devnagri_open_button");
4200      if (dotaSelectContainer) {
4201        width = dotaSelectContainer.offsetWidth;
4202      }
4203
4204      let dropdownContainer = document.getElementById("devnagri_dropdown");
4205
4206      if (dropdownContainer) {
4207        dropdownContainer.setAttribute("style", `width:${width}px;`);
4208      }
4209      x.style.display = "block";
4210    }
4211  }
4212  // for closing dropdown
4213  closeDropdown() {
4214    if (
4215      this.should_render_ui &&
4216      this.should_render_ui.toLowerCase() === "custom"
4217    ) {
4218      return true;
4219    }
4220    let id = document.getElementById("devnagri_dropdown");
4221    if (id.style.display === "block") {
4222      id.style.display = "none";
4223    }
4224  }
4225  // make avtive lang with blue color
4226  activeLanguage(selected_lang_code) {
4227    if (
4228      this.should_render_ui &&
4229      this.should_render_ui.toLowerCase() === "custom"
4230    ) {
4231      return true;
4232    }
4233    if (
4234      (this.status_api_global_data.enableSubdomainRedirect || this.isProxy()) &&
4235      !this.web_owner
4236    ) {
4237      let x = document.querySelectorAll("#devnagri_li");
4238
4239      for (let i = 0; i < x.length; i++) {
4240        if (
4241          x[i].getAttribute("devnagri_lang_code_attribute") ==
4242          selected_lang_code
4243        ) {
4244          if (x[i].firstChild) {
4245            this.defaultLanguage.innerText = x[i].firstChild.innerText;
4246            x[i].firstChild.setAttribute("style", "color:blue");
4247          }
4248        } else {
4249          if (x[i].firstChild) {
4250            x[i].firstChild.removeAttribute("style");
4251          }
4252        }
4253      }
4254    } else {
4255      let x = document.querySelectorAll("#devnagri_li");
4256      for (let i = 0; i < x.length; i++) {
4257        if (
4258          x[i].getAttribute("devnagri_lang_code_attribute") ==
4259          selected_lang_code
4260        ) {
4261          this.defaultLanguage.innerText = x[i].innerText;
4262          x[i].setAttribute("style", "color:blue");
4263        } else {
4264          x[i].removeAttribute("style");
4265        }
4266      }
4267    }
4268  }
4269
4270  // All below function is used for context editor
4271
4272  // this function will atfirst translate webpage into english language so that english text of every node will be saved in english_att attribute
4273  contentEdit(node) {
4274    switch (node.nodeName) {
4275      case "#text": {
4276        if (node.textContent.trim().length != 0) {
4277          node.english_attr = node.textContent;
4278        }
4279        break;
4280      }
4281
4282      default: {
4283      }
4284    }
4285  }
4286  //  it will create ui button for send,cancel and seo icon
4287  async webOwner() {
4288    let div1 = document.createElement("div");
4289    div1.setAttribute("style", "float:left");
4290    let seo_button = document.createElement("div");
4291    seo_button.classList.add("devnagri_seo");
4292    seo_button.id = "devnagri_seo_button_id";
4293    seo_button.setAttribute("style", "background-color:white");
4294    seo_button.innerHTML = this.seo_button_svg_content;
4295    seo_button.onclick = () => {
4296      this.seo_ui();
4297    };
4298    div1.appendChild(seo_button);
4299    this.initialdiv.insertBefore(div1, this.initialdiv.children[0]);
4300    let div2 = document.createElement("div");
4301    div2.setAttribute("style", "float:left");
4302    let send_button = document.createElement("div");
4303    send_button.classList.add("devnagri_owner_send_button");
4304    send_button.setAttribute("style", "background-color:white");
4305    send_button.id = "devnagri_optionElementt";
4306    send_button.innerHTML = this.save_button_svg_content;
4307
4308    send_button.onclick = () => {
4309      let body = document.getElementsByTagName("body")[0];
4310      this.checkingContentEditable(document.body);
4311      this.print(
4312        3,
4313        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 2631 ~ Devnagri ~ webOwner ~ this.content_editable.length",
4314        this.content_editable.length
4315      );
4316      if (this.content_editable.length && !this.unAuthApiResponse) {
4317        let div = document.createElement("div");
4318        div.classList.add("Devnagri-ring");
4319        div.id = "Devnagri-loader";
4320        let position = "  z-index: 2147483647;position:fixed;";
4321        let bottom;
4322        let right;
4323        let left;
4324        if (this.ui_bottom) {
4325          bottom = parseInt(this.ui_bottom) + 26 + "%";
4326          position = position + `bottom:${bottom};`;
4327        }
4328        if (this.ui_left) {
4329          left = parseInt(this.ui_left) + 7 + "%";
4330          position += `left:${left};`;
4331        }
4332        if (this.ui_right) {
4333          right = parseInt(this.ui_right) + 7 + "%";
4334          position += `right:${right};`;
4335        }
4336        div.style.cssText = position;
4337        let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4338        outerMostDiv.appendChild(div);
4339        // let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4340        // outerMostDiv.appendChild(div);
4341        body.appendChild(div);
4342        this.saveChangesUI();
4343        this.webOwnerSend();
4344      }
4345    };
4346    div2.appendChild(send_button);
4347    this.initialdiv.insertBefore(div2, this.initialdiv.children[1]);
4348    let div3 = document.createElement("div");
4349
4350    div3.setAttribute("style", "float:left");
4351    let cancel_button = document.createElement("div");
4352    cancel_button.classList.add("devnagri_owner_cancel_button");
4353    cancel_button.innerHTML = this.close_button_svg_content;
4354    cancel_button.id = "devnagri_optionElementt";
4355    cancel_button.setAttribute("style", "background-color:white");
4356    cancel_button.onclick = () => this.webOwnerCancel();
4357
4358    div3.appendChild(cancel_button);
4359    this.initialdiv.insertBefore(div3, this.initialdiv.children[2]);
4360    let verticalLineDiv = document.createElement("div");
4361    verticalLineDiv.setAttribute("style", "float:left");
4362    let vl = document.createElement("div");
4363    vl.classList.add("devnagri_vl");
4364    vl.setAttribute("id", "devnagri_vl_seo");
4365    verticalLineDiv.appendChild(vl);
4366    this.initialdiv.insertBefore(verticalLineDiv, this.initialdiv.children[1]);
4367  }
4368
4369  // this will create dynamically ui for seo so that seo thing meta and title can be edited
4370  seo_ui() {
4371    this.seoUI = !this.seoUI;
4372    if (this.seoUI) {
4373    } else {
4374      let tag = document.querySelector(".devnagri_dynamic_container");
4375      tag.remove();
4376      return;
4377    }
4378
4379    let body = document.getElementsByTagName("body")[0];
4380    let mainDiv = document.createElement("div");
4381    mainDiv.classList.add("devnagri_dynamic_container");
4382    body.appendChild(mainDiv);
4383    let div = document.createElement("div");
4384    div.classList.add("dynamic_container");
4385    mainDiv.appendChild(div);
4386    let divForheader = document.createElement("div");
4387    div.appendChild(divForheader);
4388    let h1 = document.createElement("h3");
4389    h1.innerText = this.source_lang_code.toUpperCase();
4390    h1.classList.add("devnagri_h1_eng");
4391    h1.setAttribute("style", "margin-bottom:0");
4392    divForheader.appendChild(h1);
4393    let h2 = document.createElement("h3");
4394    h2.setAttribute("style", "margin-bottom:0");
4395    h2.classList.add("devnagri_h1_def_lang");
4396    h2.innerText =
4397      this.default_lang_code.toUpperCase() + " (Manual Translation)";
4398    let iconForArrow = document.createElement("div");
4399    iconForArrow.classList.add("devnagri_divForArrow");
4400    divForheader.appendChild(iconForArrow);
4401    divForheader.appendChild(h2);
4402
4403    for (let key of Object.keys(this.metatag_arr)) {
4404      let divLabelInput = document.createElement("div");
4405      divLabelInput.classList.add("devnagri_div_lable_input");
4406      let label = document.createElement("label");
4407      label.innerText = key;
4408      label.classList.add("devnagri_label");
4409      let input = document.createElement("textarea");
4410      input.value = this.metatag_arr[`${key}`].engText;
4411      input.rows = 4;
4412      input.cols = 30;
4413      input.placeholder = "english text";
4414      input.setAttribute("disabled", true);
4415      input.classList.add("devnagri_form-control");
4416      let br = document.createElement("br");
4417      divLabelInput.appendChild(label);
4418      divLabelInput.appendChild(br);
4419      let divinput = document.createElement("div");
4420      divLabelInput.appendChild(divinput);
4421      let divforinputandfig = document.createElement("div");
4422      divforinputandfig.setAttribute("style", "float:left");
4423      divforinputandfig.appendChild(input);
4424      divinput.appendChild(divforinputandfig);
4425      let editedinput = document.createElement("textarea");
4426      editedinput.classList.add("devnagri_form-control");
4427      editedinput.value = this.metatag_arr[`${key}`].translatedText;
4428      editedinput.placeholder = "Manual Text";
4429      editedinput.id = "devnagri_textarea";
4430      editedinput.rows = 4;
4431      editedinput.cols = 30;
4432      editedinput.onchange = (e) => {
4433        this.metatag_arr[`${key}`].translatedText = e.target.value;
4434      };
4435      editedinput.style.cssText = `margin-left:15px;`;
4436      let divforinputandfig2 = document.createElement("div");
4437      divforinputandfig2.setAttribute("style", "float:left");
4438      divforinputandfig2.appendChild(editedinput);
4439      divinput.appendChild(divforinputandfig2);
4440      div.appendChild(divLabelInput);
4441    }
4442    let buttonSubmit = document.createElement("div");
4443    buttonSubmit.classList.add("devnagri_seo_submit");
4444    buttonSubmit.setAttribute("style", "background-color:white");
4445    buttonSubmit.onclick = () => {
4446      this.seoUI = !this.seoUI;
4447      this.seoEditedText();
4448      div.remove();
4449      this.AddDataAttributeDataChangeListioner();
4450    };
4451    let buttonCancel = document.createElement("div");
4452    buttonCancel.classList.add("devnagri_seo_cancel");
4453    buttonCancel.setAttribute("style", "background-color:white");
4454    buttonCancel.onclick = () => {
4455      this.seoUI = !this.seoUI;
4456      div.remove();
4457      this.renderUICounter = 0;
4458    };
4459    let divForSendCancel = document.createElement("div");
4460    divForSendCancel.setAttribute(
4461      "style",
4462      "padding: 15px 12px;display: inline-block"
4463    );
4464    divForSendCancel.appendChild(buttonSubmit);
4465    divForSendCancel.appendChild(buttonCancel);
4466    div.appendChild(divForSendCancel);
4467  }
4468
4469  // this function willl call patch api for sending edited meta tag
4470  seoEditedText() {
4471    for (let key of Object.keys(this.metatag_arr)) {
4472      this.content_editable.push({
4473        sentence: this.metatag_arr[`${key}`].engText,
4474        translation: this.metatag_arr[`${key}`].translatedText,
4475      });
4476    }
4477    this.contextEditorPatchApi();
4478    this.content_editable.length = 0;
4479  }
4480
4481  // this function is used for reloading when text is edited but don't want to send text to api
4482  webOwnerCancel() {
4483    location.reload();
4484  }
4485
4486  //this function will will compare the old object with new edited object and then save the edited thext into new object
4487  checkingContentEditable(node) {
4488    //handling the script tag and other unnecessary text
4489    let blacklistedTags = [
4490      "IMG",
4491      "VIDEO",
4492      "IFRAME",
4493      "NOSCRIPT",
4494      "STYLE",
4495      "SCRIPT",
4496    ];
4497
4498    if (node.childNodes && node.childNodes.length > 0) {
4499      if (!blacklistedTags.includes(node.nodeName.toUpperCase())) {
4500        for (let innerNode of node.childNodes) {
4501          this.checkingContentEditable(innerNode);
4502        }
4503      }
4504    } else {
4505      if (
4506        node.parentElement.getAttribute("id") === "devnagri_optionElementt" ||
4507        node.parentElement.getAttribute("class") === "devnagri_optionElement" ||
4508        node.parentElement.getAttribute("devnagri_option") ===
4509          "devnagri_optionElement"
4510      ) {
4511        return true;
4512      } else {
4513        switch (node.nodeName) {
4514          case "#text": {
4515            if (node.textContent.trim().length != 0) {
4516              let txt = node.textContent.replaceAll("\n", " ");
4517              txt = this.replaceNbsps(txt);
4518
4519              txt = txt.trim();
4520
4521              //node.parentElement.setAttribute("english_name", node.textContent);
4522              if (node.parentElement.getAttribute("english_text")) {
4523                var engSentence = node.parentElement
4524                  .getAttribute("english_text")
4525                  .trim();
4526              }
4527              let editedTranslatedText = txt;
4528
4529              if (
4530                this.arr_nodes[`${engSentence}`] &&
4531                editedTranslatedText !==
4532                  this.arr_nodes[`${engSentence}`].translatedText
4533              ) {
4534                this.content_editable.push({
4535                  sentence: engSentence,
4536                  translation: editedTranslatedText,
4537                });
4538              }
4539            }
4540            break;
4541          }
4542
4543          case "SCRIPT": {
4544            break;
4545          }
4546          default: {
4547          }
4548        }
4549      }
4550    }
4551  }
4552
4553  // this function is used for sending the new edited text
4554  async webOwnerSend() {
4555    this.changedContextEditor = true;
4556    if (!localStorage.getItem("devnagri_selected_lang_code")) {
4557    }
4558    this.checkingContentEditable(document.body);
4559    this.content_editable = this.content_editable.filter(
4560      (v, i, a) => a.findIndex((t) => t.sentence === v.sentence) === i
4561    );
4562
4563    var loader = document.getElementById("Devnagri-loader");
4564    var button = document.querySelector(".devnagri_owner_send_button");
4565    if (this.content_editable.length == 0) {
4566      if (loader) {
4567        loader.remove();
4568      }
4569      return;
4570    }
4571    let isSuccess = await this.contextEditorPatchApi(loader);
4572    if (isSuccess && isSuccess.message == "success") {
4573      if (loader) {
4574        loader.remove();
4575      }
4576      for (let i = 0; i < this.content_editable.length; i++) {
4577        this.arr_nodes[`${this.content_editable[i].sentence}`].translatedText =
4578          this.content_editable[i].translation;
4579      }
4580      for (let i = 0; i < this.content_editable.length; i++) {
4581        this.setTranslatedTextToNode({
4582          ...this.arr_nodes[`${this.content_editable[i].sentence}`],
4583          translatedText: this.content_editable[i].translation,
4584        });
4585      }
4586      button.onclick = () => {
4587        if (!localStorage.getItem("devnagri_selected_lang_code")) {
4588          return;
4589        }
4590        this.content_editable.length = 0;
4591        let oldArr = this.content_editable.length;
4592
4593        this.checkingContentEditable(document.body);
4594
4595        if (oldArr != this.content_editable.length) {
4596          let div = document.createElement("div");
4597          div.classList.add("Devnagri-ring");
4598          div.id = "Devnagri-loader";
4599          // let body = document.getElementsByTagName("body")[0];
4600          // body.appendChild(div);
4601          let position = "z-index: 2147483647;position:fixed;";
4602          let bottom;
4603          let right;
4604          let left;
4605          if (this.ui_bottom) {
4606            bottom = parseInt(this.ui_bottom) + 26 + "%";
4607            position = position + `bottom:${bottom};`;
4608          }
4609          if (this.ui_left) {
4610            left = parseInt(this.ui_left) + 7 + "%";
4611            position += `left:${left};`;
4612          }
4613          if (this.ui_right) {
4614            right = parseInt(this.ui_right) + 7 + "%";
4615            position += `right:${right};`;
4616          }
4617          div.style.cssText = position;
4618          let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4619          outerMostDiv.appendChild(div);
4620
4621          this.webOwnerSend();
4622          this.saveChangesUI();
4623        }
4624      };
4625    }
4626  }
4627
4628  extractSentencesFromArrNodes(arr_nodes) {
4629    let arrSentences = [];
4630
4631    for (let key of Object.keys(arr_nodes)) {
4632      if (!arrSentences.includes(this.cleanString(key))) {
4633        arrSentences.push(this.cleanString(key));
4634      }
4635    }
4636
4637    arrSentences = arrSentences.filter(
4638      (sentence) =>
4639        !this.checkIfStringIsLocal(sentence, false) &&
4640        !this.isTextTranslatedText(sentence)
4641    );
4642    return arrSentences;
4643  }
4644
4645  extractSubSentenceNodesFromArrNodes(arr_nodes) {
4646    const subSentenceNodes = {};
4647    Object.entries(arr_nodes).forEach(([key, value]) => {
4648      if (value.isNodeASentenceChildren) {
4649        subSentenceNodes[key] = value;
4650      }
4651    });
4652    return subSentenceNodes;
4653  }
4654
4655  groudSubSentenceNodesByParent(subSentenceNodes) {
4656    const subSentencesGroupedByParent = {};
4657    Object.entries(subSentenceNodes).forEach(([key, value]) => {
4658      value.sentenceParentId.forEach((id) => {
4659        // const obj = JSON.parse(JSON.stringify(value));
4660        const obj = Object.assign({}, value);
4661        obj.sentenceParentId = Array.from(value.sentenceParentId);
4662        obj.subSentencePosition = Array.from(value.subSentencePosition);
4663        obj.nodes = Array.from(value.nodes);
4664        let currentParentIdIndex = obj.sentenceParentId.findIndex(
4665          (item) => item === id
4666        );
4667        if (currentParentIdIndex > -1) {
4668          obj.sentenceParentId = id;
4669          obj.subSentencePosition =
4670            obj.subSentencePosition[currentParentIdIndex];
4671          if (subSentencesGroupedByParent[id]) {
4672            subSentencesGroupedByParent[id].push(obj);
4673          } else {
4674            subSentencesGroupedByParent[id] = [obj];
4675          }
4676        }
4677      });
4678    });
4679    return subSentencesGroupedByParent;
4680  }
4681
4682  // this function will call the save -translation patch api for sending newly added edited text to server
4683  async contextEditorPatchApi(loader) {
4684    try {
4685      // if (!localStorage.getItem("devnagri_token")) {
4686      //   return;
4687      // }
4688
4689      if (!this.access_token) {
4690        return;
4691      }
4692
4693      if (
4694        this.url_object.searchParams.has("dota-token") &&
4695        this.url_object.searchParams.has("language_code")
4696      ) {
4697        this.document_url = this.url_object.origin + this.url_object.pathname;
4698        if (!this.document_url.endsWith("/")) {
4699          this.document_url = this.document_url + "/";
4700        }
4701      }
4702
4703      // sentence breaking prevent changes start
4704      /*
4705      // this.print(3, "this.content_editable", this.content_editable);
4706      const editedSentences = Array.from(this.content_editable);
4707
4708      const editedSentencesMap = {};
4709      editedSentences.forEach((item) => {
4710        editedSentencesMap[item.sentence] = item.translation;
4711      });
4712
4713      const isEditedSentencePartOfSentence = {};
4714
4715      this.print(
4716        3,
4717        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3804 ~ Devnagri ~ contextEditorPatchApi ~ editedSentences",
4718        editedSentences
4719      );
4720
4721      const allSentences = this.extractSentencesFromArrNodes(this.arr_nodes);
4722      this.print(
4723        3,
4724        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3800 ~ Devnagri ~ contextEditorPatchApi ~ allSentences",
4725        allSentences
4726      );
4727
4728      let subSentenceNodes = this.extractSubSentenceNodesFromArrNodes(
4729        this.arr_nodes
4730      );
4731      this.print(
4732        3,
4733        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3804 ~ Devnagri ~ contextEditorPatchApi ~ subSentenceNodes",
4734        subSentenceNodes
4735      );
4736
4737      const parentIdsWithEditedSentence = [];
4738
4739      editedSentences.forEach((sentenceObj) => {
4740        if (subSentenceNodes[sentenceObj.sentence]) {
4741          const parentIds =
4742            subSentenceNodes[sentenceObj.sentence].sentenceParentId;
4743          parentIdsWithEditedSentence.push(...parentIds);
4744          isEditedSentencePartOfSentence[sentenceObj.sentence] = true;
4745        }
4746      });
4747
4748      const subSentencesGroupedByParent =
4749        this.groudSubSentenceNodesByParent(subSentenceNodes);
4750
4751      this.print(
4752        3,
4753        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3806 ~ Devnagri ~ contextEditorPatchApi ~ subSentencesGroupedByParent",
4754        subSentencesGroupedByParent
4755      );
4756
4757      this.print(
4758        3,
4759        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3840 ~ Devnagri ~ Object.entries ~ parentIdsWithEditedSentence",
4760        parentIdsWithEditedSentence
4761      );
4762
4763      const filteredSubSentencesGroupedByParent = {};
4764
4765      Object.entries(subSentencesGroupedByParent).forEach(([key, value]) => {
4766        if (parentIdsWithEditedSentence.includes(key)) {
4767          filteredSubSentencesGroupedByParent[key] = value;
4768        }
4769      });
4770      this.print(
4771        3,
4772        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3838 ~ Devnagri ~ contextEditorPatchApi ~ filteredSubSentencesGroupedByParent",
4773        filteredSubSentencesGroupedByParent
4774      );
4775
4776      const compoundSentences = [];
4777      Object.values(filteredSubSentencesGroupedByParent).forEach((item) => {
4778        const sortedItems = item.sort((a, b) =>
4779          a.subSentencePosition > b.subSentencePosition ? 1 : -1
4780        );
4781
4782        let origText = "";
4783        let transText = "";
4784        sortedItems.forEach((item, index) => {
4785          origText = `${origText}${item.originalText}${
4786            index < sortedItems.length - 1 ? "##{{}}##" : ""
4787          }`;
4788          transText = `${transText}${
4789            editedSentencesMap[item.originalText]
4790              ? editedSentencesMap[item.originalText]
4791              : item.translatedText
4792          }${index < sortedItems.length - 1 ? "##{{}}##" : ""}`;
4793        });
4794
4795        compoundSentences.push({
4796          sentence: origText,
4797          translation: transText,
4798        });
4799      });
4800
4801      this.print(
4802        3,
4803        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3807 ~ Devnagri ~ contextEditorPatchApi ~ compoundSentences",
4804        compoundSentences
4805      );
4806
4807      const simpleSentences = editedSentences.filter(
4808        (item) => !isEditedSentencePartOfSentence[item.sentence]
4809      );
4810      this.print(
4811        3,
4812        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3894 ~ Devnagri ~ contextEditorPatchApi ~ simpleSentences",
4813        simpleSentences
4814      );
4815      */
4816      // sentence breaking prevent changes end
4817
4818      const res = await fetch(this.context_editor_api, {
4819        method: "POST",
4820        headers: {
4821          "Content-Type": "application/json",
4822          Authorization: `Bearer ${this.dota_token}`,
4823        },
4824        body: JSON.stringify({
4825          url: this.document_url,
4826          language_code: this.selected_lang_code,
4827          translations: this.content_editable,
4828        }),
4829      });
4830      if (res.status == 401) {
4831        this.showErrorMessage();
4832        if (loader) {
4833          loader.remove();
4834        }
4835        this.unAuthApiResponse = true;
4836      }
4837      const data = await res.json();
4838      return data;
4839    } catch (error) {
4840      this.print(
4841        1,
4842        "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3851 ~ Devnagri ~ contextEditorPatchApi ~ error",
4843        error
4844      );
4845      throw new Error("save-translation response-> you are unauthorized");
4846    }
4847  }
4848
4849  // this will create ui for unauthorized message
4850  showErrorMessage() {
4851    this.uiErrorContextEditor();
4852  }
4853  // showing unauthorized message
4854  uiErrorContextEditor() {
4855    let element = document.getElementById("devnagri_uiErrorContextEditor");
4856    if (element) {
4857      element.remove();
4858    }
4859    let uiErrorEditor = document.createElement("div");
4860    uiErrorEditor.innerText = "You are unauthorized please use new token";
4861    uiErrorEditor.classList.add("devnagri_uiErrorEditor");
4862    uiErrorEditor.id = "devnagri_uiErrorContextEditor";
4863    let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4864    outerMostDiv.appendChild(uiErrorEditor);
4865  }
4866  saveChangesUI() {
4867    let element = document.querySelector(".devnagri_unsavedChanges");
4868    if (element) {
4869      element.remove();
4870    }
4871    if (!document.getElementById("devnagri_uiErrorContextEditor")) {
4872      let divForUnSavedChange = document.createElement("div");
4873      divForUnSavedChange.innerText = "Changes Saved";
4874      divForUnSavedChange.classList.add("devnagri_savedChanges");
4875      divForUnSavedChange.id = "devnagri_optionElementt";
4876      let outerMostDiv = document.getElementById("devnagri_outermostdiv");
4877      outerMostDiv.appendChild(divForUnSavedChange);
4878      // let body = document.getElementsByTagName("body")[0];
4879      // body.appendChild(divForUnSavedChange);
4880      setTimeout(() => {
4881        let element = document.querySelector(".devnagri_savedChanges");
4882        if (element) {
4883          element.remove();
4884        }
4885      }, 1000);
4886    }
4887  }
4888  contentEditt(node) {
4889    this.edit_mode_enabled = true;
4890    //handling the script tag and other unnecesaary text
4891    let blacklistedTags = [
4892      "IMG",
4893      "VIDEO",
4894      "IFRAME",
4895      "NOSCRIPT",
4896      "STYLE",
4897      "SCRIPT",
4898    ];
4899    if (node.childNodes && node.childNodes.length > 0) {
4900      if (!blacklistedTags.includes(node.nodeName.toUpperCase())) {
4901        for (let innerNode of node.childNodes) {
4902          this.contentEditt(innerNode);
4903        }
4904      }
4905    } else {
4906      if (
4907        node.parentElement.getAttribute("id") === "devnagri_optionElementt" ||
4908        node.parentElement.getAttribute("class") === "devnagri_optionElement" ||
4909        node.parentElement.getAttribute("devnagri_option") ===
4910          "devnagri_optionElement" ||
4911        node.parentElement.getAttribute("id") === "devnagri_seo_button_id"
4912      ) {
4913        return true;
4914      } else {
4915        switch (node.nodeName) {
4916          case "#text": {
4917            if (node.textContent.trim().length != 0) {
4918              if (node.parentElement.nodeName !== "BODY") {
4919                // english_attr atrribute will contains english text for it's corresponding translated text
4920                node.parentElement.setAttribute("contentEditable", "true");
4921              }
4922            }
4923            break;
4924          }
4925          default: {
4926          }
4927        }
4928      }
4929    }
4930  }
4931  //this is used for set contenteditable to false so that it will be not in edited mode
4932  remove_contentEditt(node) {
4933    this.edit_mode_enabled = false;
4934    //handling the script tag and other unnecesaary text
4935    let blacklistedTags = [
4936      "IMG",
4937      "VIDEO",
4938      "IFRAME",
4939      "NOSCRIPT",
4940      "STYLE",
4941      "SCRIPT",
4942    ];
4943
4944    if (node.childNodes && node.childNodes.length > 0) {
4945      if (!blacklistedTags.includes(node.nodeName.toUpperCase())) {
4946        for (let innerNode of node.childNodes) {
4947          this.remove_contentEditt(innerNode);
4948        }
4949      }
4950    } else {
4951      if (
4952        node.parentElement.getAttribute("id") === "devnagri_optionElementt" ||
4953        node.parentElement.getAttribute("class") === "devnagri_optionElement" ||
4954        node.parentElement.getAttribute("devnagri_option") ===
4955          "devnagri_optionElement" ||
4956        node.parentElement.getAttribute("id") === "devnagri_seo_button_id"
4957      ) {
4958        return true;
4959      } else {
4960        switch (node.nodeName) {
4961          case "#text": {
4962            if (node.textContent.trim().length != 0) {
4963              if (node.parentElement.nodeName !== "BODY") {
4964                node.parentElement.setAttribute("contentEditable", "false");
4965              }
4966            }
4967            break;
4968          }
4969
4970          default: {
4971          }
4972        }
4973      }
4974    }
4975  }
4976
4977  //handling click event for editing
4978  handler(e) {
4979    if (
4980      ![
4981        "devnagri_owner_button Devnagri-tooltip-toggle",
4982        "devnagri_owner_send_button",
4983        "devnagri_owner_cancel_button",
4984        "devnagri_open_button",
4985        "devnagri_container",
4986        "devnagri_optionElement",
4987        "devnagri_seo_cancel",
4988        "devnagri_seo_submit",
4989        "devnagri_seo",
4990        "devnagri_logo",
4991        "devnagri_written_lang",
4992        "devnagri_upArrow",
4993        "devnagri_outermostdivclass",
4994      ].includes(e.target.className)
4995    ) {
4996      e.stopPropagation();
4997      e.preventDefault();
4998      e.stopImmediatePropagation();
4999    }
5000  }
5001  //ui for Devnagri website owner button
5002  async WebOwnerEnableButton() {
5003    let div = document.createElement("div");
5004    div.setAttribute("style", "float:left");
5005    let button = document.createElement("div");
5006    button.classList.add("devnagri_owner_button", "Devnagri-tooltip-toggle");
5007    button.id = "devnagri_optionElementt";
5008    button.setAttribute("style", "background-color:white");
5009    button.setAttribute("data-tooltip", "Edit");
5010    button.innerHTML = this.edit_button_svg_content;
5011    button.onclick = () => {
5012      this.closeDropdown();
5013      this.AddDataAttributeDataChangeListioner();
5014      button.remove();
5015      this.contentEditt(document.body);
5016      this.webOwner();
5017      document.addEventListener("click", this.handler, true);
5018    };
5019    div.appendChild(button);
5020    this.initialdiv.appendChild(div);
5021    let verticalLineDiv = document.createElement("div");
5022    verticalLineDiv.setAttribute("style", "float:left");
5023    let vl = document.createElement("div");
5024    vl.setAttribute("id", "devnagri_vl_logo");
5025    vl.classList.add("devnagri_vl");
5026    verticalLineDiv.appendChild(vl);
5027    this.initialdiv.appendChild(verticalLineDiv);
5028  }
5029
5030  async WebOwnerEnableButtonInsert() {
5031    let div = document.createElement("div");
5032    div.setAttribute("style", "float:left");
5033    let button = document.createElement("div");
5034    button.classList.add("devnagri_owner_button", "Devnagri-tooltip-toggle");
5035    button.id = "devnagri_optionElementt";
5036    button.setAttribute("style", "background-color:white");
5037    button.setAttribute("data-tooltip", "Edit");
5038    const clieckHandler = (button.onclick = () => {
5039      this.closeDropdown();
5040      this.AddDataAttributeDataChangeListioner();
5041      button.remove();
5042      document.getElementById("devnagri_vl_logo").remove();
5043      this.contentEditt(document.body);
5044      this.webOwner();
5045      document.addEventListener("click", this.handler, true);
5046    });
5047    div.appendChild(button);
5048    let verticalLineDiv = document.createElement("div");
5049    verticalLineDiv.setAttribute("style", "float:left");
5050    let vl = document.createElement("div");
5051    vl.setAttribute("id", "devnagri_vl_logo");
5052    vl.classList.add("devnagri_vl");
5053    verticalLineDiv.appendChild(vl);
5054    const logoParent = document.querySelector(".devnagri_logo").parentElement;
5055    this.initialdiv.insertBefore(div, logoParent);
5056    this.initialdiv.insertBefore(verticalLineDiv, logoParent);
5057  }
5058
5059  // this function will be used for showing pencil icon
5060  englishSelectShowPencile() {
5061    if (!document.querySelector(".devnagri_owner_button")) {
5062      this.remove_contentEditt(document.body);
5063    }
5064    if (
5065      document.querySelector(".devnagri_owner_button") &&
5066      document.querySelector(".devnagri_owner_button").style.display != "none"
5067    ) {
5068      document.querySelector(".devnagri_owner_button").style.display = "none";
5069      this.contentEdit;
5070      document.querySelector(".devnagri_vl").style.display = "none";
5071    }
5072    if (document.getElementById("devnagri_seo_button_id")) {
5073      document.getElementById("devnagri_seo_button_id").style.display = "none";
5074      document.querySelector(".devnagri_owner_send_button").style.display =
5075        "none";
5076      document.querySelector(".devnagri_owner_cancel_button").style.display =
5077        "none";
5078      let verticalLines = document.getElementsByClassName("devnagri_vl");
5079      for (let i = 0; i < verticalLines.length; i++) {
5080        verticalLines[i].style.display = "none";
5081      }
5082    }
5083  }
5084  // this function will be used for hiding pencil icon
5085  englishSelectHidePencile() {
5086    if (
5087      document.querySelector(".devnagri_owner_button") &&
5088      document.querySelector(".devnagri_owner_button").style.display == "none"
5089    ) {
5090      document.querySelector(".devnagri_owner_button").style.display = "block";
5091      document.querySelector(".devnagri_vl").style.display = "block";
5092    } else if (!document.querySelector(".devnagri_owner_button")) {
5093      if (
5094        document.getElementById("devnagri_seo_button_id") &&
5095        document.getElementById("devnagri_seo_button_id").style.display ==
5096          "block"
5097      ) {
5098        document.getElementById("devnagri_seo_button_id").style.display =
5099          "none";
5100        document.querySelector(".devnagri_owner_send_button").style.display =
5101          "none";
5102        document.querySelector(".devnagri_owner_cancel_button").style.display =
5103          "none";
5104
5105        this.remove_contentEditt(document.body);
5106        this.WebOwnerEnableButtonInsert();
5107        document.querySelector("#devnagri_vl_seo").style.display = "none";
5108        document.querySelector("#devnagri_vl_logo").style.display = "none";
5109      } else {
5110        document.getElementById("devnagri_seo_button_id").style.display =
5111          "none";
5112        document.querySelector(".devnagri_owner_send_button").style.display =
5113          "none";
5114        document.querySelector(".devnagri_owner_cancel_button").style.display =
5115          "none";
5116
5117        this.remove_contentEditt(document.body);
5118        this.WebOwnerEnableButtonInsert();
5119        document.getElementById("devnagri_vl_seo").style.visibility = "hidden";
5120        document.getElementById("devnagri_vl_seo").parentElement.style.width =
5121          "0";
5122
5123        document.getElementById("devnagri_vl_logo").style.visibility = "hidden";
5124        document.getElementById("devnagri_vl_logo").parentElement.style.width =
5125          "0";
5126      }
5127
5128      let verticalLines = document.getElementsByClassName("devnagri_vl");
5129      for (let i = 0; i < verticalLines.length; i++) {
5130        verticalLines[i].style.display = "block";
5131      }
5132    }
5133  }
5134  englishSelectPencile(selected_lang_code) {
5135    if (this.web_owner && selected_lang_code.toLowerCase() == "en") {
5136      // for showing pencil icon
5137      this.englishSelectShowPencile();
5138    } else if (
5139      (document.getElementById("devnagri_seo_button_id") &&
5140        document.getElementById("devnagri_seo_button_id").style.display ==
5141          "none") ||
5142      this.web_owner
5143    ) {
5144      // for hiding pencil icon
5145      this.englishSelectHidePencile();
5146    }
5147  }
5148  // when lang is selected from dropdown then this function will work
5149  async onLangSelection(selected_lang_code) {
5150    if (this.isLiveJs()) {
5151      const old_status = this.subscription_status_active;
5152
5153      this.subscription_status_active =
5154        this.isUrlLangStatusActive(selected_lang_code);
5155      if (!old_status && this.subscription_status_active) {
5156        this.startTraversingNow();
5157        await this.checkIfTraversingCompleted();
5158      }
5159    }
5160
5161    if (this.edit_mode_enabled) {
5162      let element = document.querySelector(".devnagri_unsavedChanges");
5163      if (element) {
5164        element.remove();
5165      }
5166      this.remove_contentEditt(document.body);
5167      if (selected_lang_code !== this.source_lang_code) {
5168        this.onLangSelection(this.source_lang_code);
5169      }
5170      // this.edit_mode_enabled = false;
5171    }
5172
5173    // for showing and hiding pencil icon
5174    this.englishSelectPencile(selected_lang_code);
5175    this.RemoveDataAttributeDataChangeListioner();
5176    let element = document.querySelector(".devnagri_unsavedChanges");
5177    if (element) {
5178      element.remove();
5179    }
5180    // close the UI dropdown
5181    this.closeDropdown();
5182    //set the active lanauge CSS on the dropdown option link
5183    this.activeLanguage(selected_lang_code);
5184
5185    // set text direction rtl for urdu
5186    const rtlLangs = ["ur","ar"]
5187    if (rtlLangs.includes(selected_lang_code)) {
5188      console.log("setting text direction rtl for urdu")
5189      document.body.setAttribute("dir", "rtl");
5190    }else{
5191      console.log("setting text direction ltr for other langs");
5192      document.body.setAttribute("dir", "ltr");
5193    }
5194
5195    var width;
5196    let dotaSelectContainer = document.querySelector(".devnagri_open_button");
5197    if (dotaSelectContainer) {
5198      width = dotaSelectContainer.offsetWidth;
5199    }
5200
5201    let dropdownContainer = document.getElementById("devnagri_dropdown");
5202    if (dropdownContainer) {
5203      dropdownContainer.setAttribute("style", `width:${width}px;`);
5204    }
5205
5206    if (
5207      selected_lang_code === localStorage.getItem("devnagri_source_lang_code")
5208    ) {
5209      this.selected_lang_code = selected_lang_code;
5210      this.default_lang_code = selected_lang_code;
5211      // localStorage.setItem("devnagri_selected_lang_code", selected_lang_code);
5212      // localStorage.setItem("devnagri_default_lang_code", selected_lang_code);
5213      this.translate(selected_lang_code);
5214    } else if (
5215      (this.default_lang_code = selected_lang_code)
5216      // localStorage.getItem("devnagri_default_lang_code") == selected_lang_code
5217    ) {
5218      this.selected_lang_code = selected_lang_code;
5219      this.default_lang_code = selected_lang_code;
5220      // localStorage.setItem("devnagri_selected_lang_code", selected_lang_code);
5221      // localStorage.setItem("devnagri_default_lang_code", selected_lang_code);
5222      // if (
5223      //   this.status_api_global_data &&
5224      //   this.status_api_global_data.enable_object_mapping
5225      // ) {
5226      //   await this.getObjectUrlsApi();
5227      // }
5228      this.GetTranslationsApi().then(() => {
5229        this.translate(selected_lang_code);
5230        this.AddDataAttributeDataChangeListioner();
5231      });
5232    } else if (selected_lang_code !== this.default_lang_code) {
5233      this.default_lang_code = selected_lang_code;
5234      this.selected_lang_code = selected_lang_code;
5235      // localStorage.setItem("devnagri_selected_lang_code", selected_lang_code);
5236      // localStorage.setItem("devnagri_default_lang_code", selected_lang_code);
5237      // if (
5238      //   this.status_api_global_data &&
5239      //   this.status_api_global_data.enable_object_mapping
5240      // ) {
5241      //   await this.getObjectUrlsApi();
5242      // }
5243      this.GetTranslationsApi().then(() => {
5244        this.translate(selected_lang_code);
5245        this.AddDataAttributeDataChangeListioner();
5246      });
5247    }
5248  }
5249  setEventHandlerOfProxyDropDown() {
5250    this.print(3, "setting click listener to language selection dropdown");
5251    let dotaSelectContainer = document.querySelector("#Devnagri_open_button");
5252    let width;
5253    if (dotaSelectContainer && dotaSelectContainer.offsetWidth) {
5254      width = dotaSelectContainer.offsetWidth;
5255    }
5256    let dropdownContainer = document.getElementById("Devnagri_dropdown");
5257    if (dropdownContainer) {
5258      dropdownContainer.setAttribute("style", `width:${width}px;`);
5259    }
5260
5261    const languageWrapper = document.getElementById(
5262      "Devnagri_written_lang_wrapper"
5263    );
5264    if (languageWrapper) {
5265      languageWrapper.removeEventListener("click", this.openProxyDropdown);
5266      languageWrapper.addEventListener("click", this.openProxyDropdown);
5267    }
5268    const arrowWrapper = document.getElementById("Devnagri_arrow_up_wrapper");
5269    if (arrowWrapper) {
5270      arrowWrapper.removeEventListener("click", this.openProxyDropdown);
5271      arrowWrapper.addEventListener("click", this.openProxyDropdown);
5272    }
5273  }
5274
5275  openProxyDropdown() {
5276    let x = document.getElementById("Devnagri_dropdown");
5277    if (x.style.display === "block") {
5278      x.style.display = "none";
5279    } else {
5280      x.style.display = "block";
5281    }
5282  }
5283
5284  async getObjectUrlsApi() {
5285    const langCode = this.selected_lang_code;
5286
5287    const apiUrl = `${this.api_baseurl}/object-mapping?language_code=${langCode}`;
5288    // const res = await fetch(apiUrl, {
5289    //   method: "GET",
5290    //   headers: {
5291    //     Authorization: `Bearer ${this.access_token}`,
5292    //   },
5293    // });
5294    // if (res.status === 401 || res.status === 403) {
5295    //   this.callApiRequest();
5296    // }
5297    // const responseData = await res.json();
5298
5299    if(!this.objectMappingapiCounter)
5300    {
5301      this.objectMappingData = await this.callApiRequest(async () => {
5302        const res = await fetch(apiUrl, {
5303          method: "GET",
5304          headers: {
5305            Authorization: `Bearer ${this.access_token}`,
5306          },
5307        });
5308        if (res.status === 401 || res.status === 403) {
5309          throw { response: res };
5310        }
5311        const response = await res.json();
5312        return response;
5313      });
5314      ++this.objectMappingapiCounter;
5315    }
5316
5317    let objectsArr = [];
5318    if (this.objectMappingData.data && Array.isArray(this.objectMappingData.data)) {
5319      objectsArr = this.objectMappingData.data;
5320    }
5321    const objectsMap = {};
5322    const objectsMapLocal = {};
5323    objectsArr.forEach((object) => {
5324      objectsMap[object.english_url] = object;
5325      objectsMapLocal[object.local_url] = object;
5326    });
5327    this.subdomain_object_urls_hash_map = objectsMap;
5328    this.print(
5329      3,
5330      "🚀 ~ file: devnagri-dota-merged-client-dev.js ~ line 3379 ~ Devnagri ~ getObjectUrlsApi ~ this.subdomain_object_urls_hash_map",
5331      this.subdomain_object_urls_hash_map
5332    );
5333    // this.subdomain_object_urls_hash_map_local = objectsMap;
5334
5335    if (
5336      this.subdomain_object_urls_hash_map &&
5337      typeof this.subdomain_object_urls_hash_map === "object"
5338    ) {
5339      const objectsArr = Object.values(this.subdomain_object_urls_hash_map
5339);
5340      const localObjectUrlsHashMap = {};
5341      objectsArr.forEach((object) => {
5342        localObjectUrlsHashMap[object.local_url] = object;
5343      });
5344      this.subdomain_object_urls_hash_map_local = localObjectUrlsHashMap;
5345    }
5346  }
5347
5348  globalCheckIfStringIsLocal(string) {
5349    if(
5350        this.checkIfStringIsHindi(string) || 
5351        this.checkIfStringIsPunjabi(string) || 
5352        this.checkIfStringIsTamil(string) || 
5353        this.checkIfStringIsGujrati(string) || 
5354        this.checkIfStringIsKannad(string) ||
5355        this.checkIfStringIsBengali(string) ||
5356        this.checkIfStringIsHindi(string) || 
5357        this.checkIfStringIsTelugu(string) || 
5358        this.checkIfStringIsMalyalam(string) || 
5359        this.checkIfStringIsAssamese(string) || 
5360        this.checkIfStringIsOdia(string) || 
5361        this.checkIfStringIsArabic(string) || 
5362        this.checkIfStringIsJapanese(string) || 
5363        this.checkIfStringIsChinese(string) || 
5364        this.checkIfStringIsIndonesian(string) || 
5365        this.checkIfStringIsUrdu(string) 
5366    ){
5367        return true;
5368    }
5369
5370    return false;
5371  }
5372}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.