PageSourceSearch

https://meet-attendance-tracker.web.app/script.js

js meet-attendance-tracker.web.app collected 2026-10-03 12:29:36 UTC 50,916 bytes, 1,002 lines download raw bytes

1/* This script is for myreports.html */
2
3let bulkSharedReportsViewId = null;
4
5window.onload = function() {
6  try {
7    let actionToDo = Common.getURLParamValue("actionToDo");
8    if (actionToDo != null && actionToDo == "recoverTodaysMeetings") {
9      Common.openReportRecoveryModal(RECOVER_REPORTS_POPUP_SOURCE_REPORT_GENERATION_FAILED);
10      let reason = Common.getURLParamValue("reason");
11      if(reason !=null && reason && typeof(reason)=='string' && reason.length>0) {
12        LOGGER.log(Level.SEVERE,"Opened autoRecoverReportpopup with reason "+reason,null,reason);
13      }
14    }
15
16    // Pre processing before loaing my reports.
17    localStorage.setItem("googlemeet-attendance-tracker-ext-lastrefreshtime", new Date().getTime().toString()); // This was introduced during auto-backup...current not aware what purpose this is solving
18    bulkSharedReportsViewId = Common.getURLParamValue("vid");
19
20    if (bulkSharedReportsViewId != null) {
21      // Being loaded for a user in shared reports view
22      executeScript(false);
23    } else {
24      // Actual user visiting myreports.html
25      // we should not use this inside window..so passing the first args as null for bind
26      let fastLoadCallbackFunc = executeScript.bind(null, true);
27      Common.bindAuthSession(handleMyReportsPageLoad, true, fastLoadCallbackFunc);
28    }
29  } catch (e) {
30    LOGGER.log(Level.SEVERE, "Exception while loading product page myreports.html", e);
31  }
32}
33
34function handleMyReportsPageLoad(user=null) {
35  try{
36    // In future when user obj is needed..use it from the args and then if required reload the page again with executeScript and try to handle without passing the user obj to executeScript
37  }catch(e){
38    LOGGER.log(Level.SEVERE,"Exception inside handleMyReportsPageLoad",e);
39  }
40}
41
42//global variables
43let attendanceReports;
44let classSelectedToSaveReport="";
45let pageNumber = 1;
46let bulkReportsSelected = [];
47let isBulkSharedReportsView = false;
48
49async function executeScript(canInvokeAutoBackup=false) {
50  try{
51    let contents = null;
52    let publicData = null;
53    if(bulkSharedReportsViewId!=null) {
54      Common.hideNavBarElementsForSharedView("BULK_SHARED_REPORTS", null);
55      let sharedData = (await Common.handleShareAction("GET_PUBLICID_DATA", bulkSharedReportsViewId, false)).data;
56      contents = sharedData.data;
57      publicData = sharedData.public_data;
58      isBulkSharedReportsView = true;
59    } else {
60      contents = localStorage.getItem("googlemeet-attendance-tracker-ext");
61    }
62    if(contents!==null && contents!="[]") {
63      attendanceReports = JSON.parse(contents);
64      document.getElementById("reportCount").innerHTML = attendanceReports.length;
65      let usedStorage = Math.round(Number(attendanceReports.length/600)*100);
66      if(!isBulkSharedReportsView) {
67        let storageUseBarEle = document.getElementById("storageUseBar");
68        if(storageUseBarEle!=null) {
69          storageUseBarEle.style.display = "";
70        }
71      }
72      document.getElementById("progressBarValue").ariaValueNow = usedStorage;
73      document.getElementById("progressBarValue").style.width = `${usedStorage}%`;
74      let isRecoverReportFeatureEnabled = Common.isRecoverReportsFeatureEnabled();
75      let isSharedDataViewedByANewUser = isBulkSharedReportsView && Common.getLocalAttendanceReports()==null;
76      let tableHead =  
77      `
78        <div class="container-fluid">
79          <div class="row justify-content-between">
80            <div>
81              <h3>${isBulkSharedReportsView ? "Shared Meeting Reports," : "Your Recent Meetings,"}</h3>
82            </div>
83            <div class="float-right">
84              <a href="https://chromewebstore.google.com/detail/google-meet-attendance-tr/ldjjokmalaidehbgbifihdfdondjgfha?hl=en&authuser=0" target="_blank" style="margin-right: 10px; text-decoration:none;"><img src="${isSharedDataViewedByANewUser ? "svg/extension.svg" : "svg/share.svg"}" ${isSharedDataViewedByANewUser ? 'height="22px;" width="22px"' : 'height="18px;" width="18px"'} style="margin-bottom:3px; margin-right: 3px;" /> &nbsp;${isSharedDataViewedByANewUser ? "Install Google Meet Attendance Tracker" : "Refer us to your network" } &#128522;</a>
85            </div>
86          </div>
87        </div>
88        <!--Participants search box start-->
89          <nav class="navbar navbar-light bg-light" style="position: sticky; top: 72px;" id="myReportsNav">
90            <div class="form-inline row">
91              <input type="text" autocomplete="off" id="searchReport" onkeyup="searchReport()" class="form-control searchReport-placeholder" placeholder="Search by Meeting Name" aria-label="Username" aria-describedby="basic-addon1" style="width:260px; border-color: #979998; border-radius: 23px;">
92            </div>
93            ${!isRecoverReportFeatureEnabled ? `
94            <a href="backup.html" class="btn btn-info btn-sm ${isBulkSharedReportsView ? "notVisible" : ""}" style="margin-left: -15px; height: 36px;">
95              <img src="svg/backup-restore.svg" style="margin-bottom: 0px; margin-right: 5px;" width="23px;" height="22px;" />
96              Backup/Restore your data
97            </a>
98
99              ` : 
100              `
101            <button id="recoverReportButton" onclick="Common.openReportRecoveryModal()" class="btn-sm attention-btn ${isBulkSharedReportsView ? "notVisible" : ""}" style="display: flex; align-items: center; outline: none;">
102              <img src="svg/thunder-white.svg" style="width:21px; height:21px; padding-left: 1px;" />
103              <span style="padding-left: 3px; padding-right: 11px;">Recover past meeting</span>
104            </button>
105
106              `}
107            <a class="${isBulkSharedReportsView ? "notVisible" : ""}" style="text-decoration: none; margin-right: 100px; margin-left: 20px;" id="autoBackUpToggleElement" ><label style="margin-top: 16px" class="toggle"><input id="autoBackupToggleBtn" type="checkbox"><span class="slider"></span></label><span class="toggle-label"><b style="font-size: 17px;">&nbsp; <span id="autoBackupToggleText">Auto Backup</span></b></span></a>
108            <a class="${isBulkSharedReportsView ? "notVisible" : ""}" style="margin-left: -110px; margin-right: 0px; color: #100d94" id="backupsuggestions"></a>
109            <div id="paginationSwitches" class="${isBulkSharedReportsView ? "notVisible" : ""}">
110              <span id="paginationContent"></span>
111              &nbsp;
112              <button id="paginationPrevious" class="btn btn-sm btn-outline-secondary" data-toggle="tooltip" title="" data-placement="top" >
113                <img src="svg/left-arrow.svg" />
114              </button>
115              &nbsp;
116              <button id="paginationNext" class="btn btn-sm btn-outline-secondary" data-toggle="tooltip" title="" data-placement="top">
117                <img src="svg/right-arrow.svg" />
118              </button>
119            </div>
120         </nav>
121         <div class="bg-light" id="bulkReportsSelectionActions" style="display: none; top: 72px; position: sticky; z-index: 1">
122          <div class="container-fluid">
123            <div class="row">
124            
125              <div style="margin-top: 26px; margin-right: 24px;">
126                <h6>
127                  <span id="numberOfReportsSelected"></span>&nbsp;&nbsp;
128                  <span onclick="removeAllSelectedReports()" onmouseover="this.style.color='#F34A3F'" onmouseout="this.style.color='#F47368'" style="color: #F47368; text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 4px; cursor: pointer; "><img height="19px;" width="19px;" src="svg/red_cross.svg" />clear</span>
129                </h6> 
130              </div>
131            
132              <div id="verticalLineBlukActionsDivider" style="border-left: 1px solid lightgray;"></div>
133
134              <div style="margin-top: 20px; margin-left: 24px;">
135                <button style="width: 110%;" type="button" class="btn btn-info" onclick='Common.handleShareAction("BULK_ATTENDANCE_REPORT",bulkReportsSelected,true)'>
136                  Create link
137                  <img src="svg/link.svg" height="22px;" width="22px;" />
138                </button>
139              </div>
140            
141
142            </div>
143          </div>  
144         </div>
145        <!--Participants search box end-->
146        <table class="table table-hover" id="myReportsMainTable" style="margin-top: 10px;">
147          <thead class="thead-dark" style="position: sticky; top: 140px;">
148            <tr>
149              <th scope="col">S.No</th>
150              <th scope="col" class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">
151                <div style="visibility: hidden;">
152                </div>
153              </th>
154              <th scope="col" style="width: 175px; max-width: 175px; white-space: nowrap; overflow: hidden; text-overflow: clip;" class="text-center">Meeting Name</th>
155              <th scope="col" class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">
156                <svg style="visibility: hidden;" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16"> <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/></svg>
157              </th>
158              <th scope="col" class="text-center">Meeting Date</th>
159              <th scope="col" class="text-center">Report Generated At</th>
160              <th scope="col" class="text-center">Meeting Duration</th>
161              <th scope="col" class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">Share Report</th>
162              <th scope="col" class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">Saved to Class</th>
163              <th scope="col" class="text-center">Total Participants</th>
164              <th scope="col" class="text-center">View Report</th>
165              <th scope="col" class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">Delete Report</th>
166            </tr>
167         </thead>
168         <tbody style="font-size: 20px; display: none;" id="reportsTableBody">
169      `;
170      let tableBody = "";
171      let noReportsDisplayingTemplate = `
172         <div id="noReportFound" class="container" style="display: none; margin-top: 20px;">
173           <div class="text-center">
174             <img src="svg/search.svg" style="height: 25px; width: 25px;" />  
175             <span>
176               <b style="margin-left: 8px;">Unable to find the report you are looking for?</b>
177               <p style="margin-top: 10px;">
178                  1. Try searching for it in the next / previous pages using the 
179                  <button class="btn btn-sm" >
180                    <img src="svg/left-arrow.svg" />
181                  </button>
182                  &nbsp;
183                  <button class="btn btn-sm">
184                    <img src="svg/right-arrow.svg" />
185                  </button>
186                  buttons <i>(present in the middle right corner of the webpage)</i>
187               </p>
188             </span>
189           </div>     
190         </div>
191      `;
192      let tableReportsLoadingTemplate = `
193          <div id="tableReportsLoading" class="container-fluid" style="display: none;">
194            <div class="text-center" style="margin-top: 20px;">
195              <img src="myreports-skeleton.svg" style="width: 100%; height: 100%;"/>
196              <br/>
197              <img src="myreports-skeleton.svg" style="width: 100%; height: 100%;"/>
198              <br/>
199              <img src="myreports-skeleton.svg" style="width: 100%; height: 100%;"/>
200            </div>
201          </div>
202      `;
203      tableBody += "</tbody></table>";
204      tableBody += noReportsDisplayingTemplate;
205      tableBody += tableReportsLoadingTemplate;
206      let tableReport = tableHead+tableBody;
207      // inserting table into myreports.html file
208      document.getElementById("reportDetails").innerHTML = tableReport;
209      // Inject the firstPage reports
210      injectCurrentPageReportsInUI(pageNumber, false);
211      // auto backup toggle button
212      document.getElementById("autoBackupToggleBtn").addEventListener("click",function(){
213          let toggledAutoBackupMode = Common.toggleAutoBackupMode();
214          if(toggledAutoBackupMode) {
215            setTimeout(function(){
216              doAutoBackupFromMyReports();
217            },350);
218          }
219      });
220      try{completeAutoBackupStatus()}catch(ex){LOGGER.log(Level.SEVERE,"Unable to complete autobackup status",ex); console.log("unable to toggle autobackup btn")}; 
221      try{paginateNext()}catch(exx){LOGGER.log(Level.SEVERE,"Exception while trying to add pagination next click event listener",exx);}
222      try{paginatePrevious()}catch(exxx){LOGGER.log(Level.SEVERE,"Exception while trying to add pagination previous click event listener",exxx);}
223      if(canInvokeAutoBackup) {
224        doAutoBackupFromMyReports();
225      } else {
226        showBackUpSuggestions();
227      }
228      if(isBulkSharedReportsView) {
229        try{
230          Common.trackPageViewsForViewID(bulkSharedReportsViewId);
231          Common.hideNavBarElementsForSharedView("BULK_SHARED_REPORTS", publicData);
232          Common.addPopovers();
233        }catch(e){
234          LOGGER.log(Level.SEVERE,"Exception while performing shared view specific changes",e);
235        }
236      }  else {
237        Common.addPopovers();
238        Common.trackNewAttendanceReportGeneration();
239      }
240    } else {  /* *********** Error HTML template *********** */
241      document.getElementById("reportCount").innerHTML = "0";
242      document.getElementById("progressBarValue").ariaValueNow = 0;
243      document.getElementById("progressBarValue").style.width = "0%";
244      // report not found template
245      let reportNotFoundTemplate = 
246      `
247        <div class="text-center" style="margin-bottom: 20px;">
248          <a href="backup.html" style="text-decoration:none;" class="btn btn-info"><img src="svg/restore-data.svg" width="22px;" height="22px;" style="margin-bottom: 3px; margin-right: 5px;"/>Restore your data</a>
249        </div>
250        <h3>Looks like you haven't tracked attendance using our chrome extension !</h3>
251        <p style="margin-top: 20px;">Incase if you feel something is wrong, please follow the below steps:</p>
252        <ol style="font-size: 18px;">
253          <li>If you have a backup click <a href="backup.html" style="text-decoration:none;">here</a> to restore your data</li>
254          <li>Try refreshing this page</li>
255          <li>Read a quick tutorial of <a href="howtouse.html" style="text-decoration: none;">how to use</a> our chrome extension</li>
256          <li>Make sure you use the latest version of chrome browser</li>
257          <li>Do not close google meet tab without genearting the report using our chrome extension, learn more about this <a href="howtouse.html" style="text-decoration: none;">here</a></li>
258          <li>Make sure you computer is connected to internet</li>
259          <li>Make sure you have a high speed internet connection ( atleast 512kbps is recommended )</li>
260          <li>If you are unable to fix any issue please write your queries to: <a href="mailto:[email protected]">[email protected]</a> and <a href="mailto:[email protected]">[email protected]</a> (or) Create a ticket by <b><a href="contactus.html">Clicking here</a></b> </li>
261          </ol>
262        <p style="margin-top: 25px; font-size:20px;"><b>Note: </b>You will be seeing these error messages if you are not a user of our chrome extension</p>
263      `;
264      document.getElementById("reportDetails").innerHTML = reportNotFoundTemplate;
265      try{
266        // If AutoBackup is enabled and there is no attendance reports in myreports then AutoBackup should be stopped.
267        if(Common.isAutoBackupEnabled()) {
268          localStorage.setItem("googlemeet-attendance-tracker-ext-autobackup",false);
269        }
270      }catch(e){
271        LOGGER.log(Level.SEVERE,"Exception while turningoff autobackup for account which has no reports",e);
272      }
273    }
274  }catch(e){
275    LOGGER.log(Level.SEVERE,"High Attention needed, Exception in loading and displaying reports in executebackupscript",e);
276  }
277}
278
279function injectCurrentPageReportsInUI(pageNumber, isAnimationRequired=false) {
280  try{
281    let tableBody = "";
282    document.getElementById("reportsTableBody").style.display = "none";
283    document.getElementById("tableReportsLoading").style.display = "block";
284    let fullAttendanceReportsCopy = JSON.parse(JSON.stringify(attendanceReports));
285    let currentPageReports = Common.getCurrentPageReports(pageNumber, fullAttendanceReportsCopy);
286    if(currentPageReports == null) {
287      LOGGER.log(Level.SEVERE,"Unable to inject reports in page",null,pageNumber,attendanceReports.length);
288      return;
289    }
290    let sNo = (SV.REPORTS_PER_PAGE * (pageNumber-1))+1;
291    const startNum = sNo;
292    let reportNum = startNum;
293    for(attendanceReport of currentPageReports) {
294      let reportCustomDefinitions = Common.getCustomDefinitions(attendanceReport);
295      let isHavingCustomMeetingName = reportCustomDefinitions.CUSTOM_MEETING_NAME;
296      let currMeetingName = isHavingCustomMeetingName ? attendanceReport.meetingName : attendanceReport.meetingCode;
297      let reportIdView = "report-"+String(reportNum)+"-view";
298      let reportIdDelete = "report-"+String(reportNum)+"-delete";
299      let reportIdEdit = "report-"+String(reportNum)+"-edit";
300      let reportIdName = "report-"+String(reportNum)+"-name";
301      let tableId = "table-"+String(reportNum)+"-id";
302      let statusId = "status-"+String(reportNum)+"-id";
303      let selectReportId = "select-"+String(reportNum)+"-report";
304      // For statusHTML we will not read from currentPageReports because, currentPageReports will have only the current x - x+(per page reports) but reportNum will have value based on total attendanceReports count.
305      let statusHTML = attendanceReports[reportNum-1].joiningTime[0] == "reportAddedToClass" ? `<div id="${statusId}" style="color:green;">  <svg data-toggle="tooltip" data-placement="right" title="Succes: This report is added to a class" xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-check-lg" viewBox="0 0 16 16"> <path d="M13.485 1.431a1.473 1.473 0 0 1 2.104 2.062l-7.84 9.801a1.473 1.473 0 0 1-2.12.04L.431 8.138a1.473 1.473 0 0 1 2.084-2.083l4.111 4.112 6.82-8.69a.486.486 0 0 1 .04-.045z"/> </svg> </div>` : `<div class="statusSymbol" id="${statusId}" style="cursor:pointer; color:#ff751f;"> <svg data-toggle="tooltip" data-placement="right" title="Pending: This report is not added to any of the class" xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-exclamation-circle" viewBox="0 0 16 16"> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/> <path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/> </svg> </div>` ;
306      let shareReportId = "shareReport-"+String(reportNum)+"-id";
307      let shareReportHTML = `<div class="statusSymbol" id="${shareReportId}" style="cursor: pointer;" data-toggle="tooltip" data-placement="right" title="Share this report"><img src="svg/share-fill.svg" alt="share_icon"/></div>`;
308      let tableRecord = 
309      `
310        <tr id="${tableId}">
311        <th scope="row">${sNo}</th>
312        <th class="text-center ${isBulkSharedReportsView ? "hidden" : ""}"><div><input style="cursor: pointer;" type="checkbox" id="${selectReportId}"></div></th>
313        <td class="text-center" style="max-width: 175px; white-space: nowrap; overflow: hidden; text-overflow: clip;" contenteditable="false" id="${reportIdName}">${currMeetingName}</td> 
314        <td class="text-center ${isBulkSharedReportsView ? "hidden" : ""}" id="${reportIdEdit}" style="cursor:pointer"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16"> <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/></svg></td>
315        <td class="text-center">${attendanceReport.date}</td>
316        <td class="text-center">${attendanceReport.attendanceStopTime}</td>
317        <td class="text-center">${toTimeFormat(attendanceReport.meetingDuration)}</td>
318        <td class="text-center ${isBulkSharedReportsView ? "hidden" : ""}">${shareReportHTML}</td>      
319        <td class="text-center ${isBulkSharedReportsView ? "hidden" : ""}"> ${statusHTML}</td>      
320        <td class="text-center">${attendanceReport.studentNames.length}</td>
321        <td class="text-center"><button class="btn btn-sm btn-success" id="${reportIdView}">View Report</button></td>
322        <td class="text-center ${isBulkSharedReportsView ? "hidden" : ""}"><button class="btn btn-sm btn-danger" id="${reportIdDelete}">Delete Report</button></td>
323        </tr>
324      `;
325      tableBody += tableRecord;
326      reportNum += 1;
327      sNo += 1;
328    }
329    let tableReport = tableBody;
330    // inserting table into myreports.html file
331    document.getElementById("reportsTableBody").innerHTML = tableReport;
332
333    if(pageNumber == 1 || !isAnimationRequired) {
334      document.getElementById("tableReportsLoading").style.display = "none";
335      document.getElementById("reportsTableBody").style.display = "";
336    } else {
337      let loadingImageTime = pageNumber > 0 && pageNumber <= 2 ? 1200 : pageNumber == 3 ? 600 : 460;
338      setTimeout(function(){
339        document.getElementById("tableReportsLoading").style.display = "none";
340        document.getElementById("reportsTableBody").style.display = "";
341      },loadingImageTime);
342    }
343    try{Common.addToolTips()}catch(toolTipsException){console.log("Unable to attach tooltips")}
344
345    //adding reportView and reportDelete functionalities
346    reportNum=startNum;
347    for(attendanceReport of currentPageReports) {
348      let reportIdView = "report-"+String(reportNum)+"-view";
349      let reportIdDelete = "report-"+String(reportNum)+"-delete";
350      let reportIdEdit = "report-"+String(reportNum)+"-edit";
351      let statusId = "status-"+String(reportNum)+"-id";
352      let selectReportId = "select-"+String(reportNum)+"-report";
353      let shareReportId = "shareReport-"+String(reportNum)+"-id";
354      document.getElementById(reportIdView).addEventListener("click",function(){
355        viewReport(reportIdView);
356      });
357      document.getElementById(reportIdDelete).addEventListener("click",function(){
358        deleteReport(reportIdDelete);
359      });
360      document.getElementById(reportIdEdit).addEventListener("click",function(){
361        toggleEditMeetingName(reportIdEdit);
362      });
363      document.getElementById(statusId).addEventListener("click",function(){
364        let currReportNum = findReportNumber(statusId);
365        if(attendanceReports[currReportNum-1].joiningTime[0] != "reportAddedToClass") {
366          $("#statusUpdateModal").modal("toggle");
367          fillModalBodyContents(statusId);
368        }
369      });
370      document.getElementById(shareReportId).addEventListener("click",async function(){
371        let currReportNum = findReportNumber(shareReportId);
372        await Common.handleShareAction("ATTENDANCE_REPORT",attendanceReports[currReportNum-1], true);
373      });
374      document.getElementById(selectReportId).addEventListener("click",function(){
375        handleBulkReportsSelectedActions();
376      });
377      reportNum += 1;
378    }
379  }catch(e){
380    LOGGER.log(Level.SEVERE,"Exception while injecting reports for current page - High priority",e);
381  }
382}
383
384function paginateNext() {
385  try{
386    let paginateNextEle = document.getElementById("paginationNext");
387    if(paginateNextEle != null) {
388      paginateNextEle.addEventListener("click", function(){
389        resetSearchReport();
390        injectCurrentPageReportsInUI(pageNumber+1, true);
391        pageNumber += 1;
392        Common.trackFeatureUsage(paginate_attendance_report);
393      });
394    }
395  }catch(e){
396    LOGGER.log(Level.SEVERE,"Exception inside paginateNext",e);
397  }
398}
399
400function paginatePrevious() {
401  try{
402    let paginatePrevEle = document.getElementById("paginationPrevious");
403    if(paginatePrevEle != null) {
404      paginatePrevEle.addEventListener("click",function(){
405        resetSearchReport();
406        injectCurrentPageReportsInUI(pageNumber-1, false);
407        pageNumber -= 1;
408        if(pageNumber<=1) {
409          pageNumber = 1;
410        }
411      });
412    }
413  }catch(e){
414    LOGGER.log(Level.SEVERE,"Exception inside paginatePrevious",e);
415  }
416}
417
418function resetSearchReport() {
419  try{
420    let searchReportEle = document.getElementById("searchReport");
421    if(searchReportEle != null) {
422      searchReportEle.value = "";
423      if(!isBulkSharedReportsView) {
424        Common.removeReportNotFoundTemplateInMyReportsTableBody();
425      }
426    }
427  }catch(e){
428    LOGGER.log(Level.SEVERE,"Exception while resetting search",e);
429  }
430}
431
432function handleBulkReportsSelectedActions() {
433  try{
434    let startReportNumForCurrentPage = (SV.REPORTS_PER_PAGE * (pageNumber-1))+1;
435    let endingReportNumForCurrentPage = startReportNumForCurrentPage+SV.REPORTS_PER_PAGE;
436    bulkReportsSelected = [];
437    for(let i=startReportNumForCurrentPage;i<=endingReportNumForCurrentPage;i++) {
438      try{
439        let selectReportId = "select-"+String(i)+"-report";
440        let reportCheckBoxEle = document.getElementById(selectReportId);
441        if(reportCheckBoxEle!=null) {
442          if(reportCheckBoxEle.checked) {
443            let reportNum = findReportNumber(selectReportId);
444            let checkedAttendanceReport = attendanceReports[reportNum-1];
445            bulkReportsSelected.push(checkedAttendanceReport);
446          }
447        }
448      }catch(e){
449        break;
450      }
451    }
452    if(bulkReportsSelected.length>0) {
453      let numberOfReportsSelectedEle = document.getElementById("numberOfReportsSelected");
454      if(numberOfReportsSelectedEle!=null) {
455        numberOfReportsSelectedEle.innerHTML = `<b>${bulkReportsSelected.length}</b> ${bulkReportsSelected.length>1 ? "Reports" : "Report"} Selected.`;
456        let myReportsNav = document.getElementById("myReportsNav");
457        if(myReportsNav!=null && myReportsNav.style.display!="none") {
458          let eleHeight = "62px";
459          try{eleHeight = myReportsNav.getBoundingClientRect().height;eleHeight += "px";}catch(e){}
460          myReportsNav.style.display = "none";
461          let bulkReportsSelectionActionsEle = document.getElementById("bulkReportsSelectionActions");
462          if(bulkReportsSelectionActionsEle!=null) {
463            bulkReportsSelectionActionsEle.style.height = eleHeight;
464            let verticalLineBlukActionsDivider = document.getElementById("verticalLineBlukActionsDivider");
465            if(verticalLineBlukActionsDivider!=null) {
466              verticalLineBlukActionsDivider.style.height = eleHeight;
467              $("#bulkReportsSelectionActions").fadeIn(200);
468            }
469          }
470        }
471      } 
472    } else {
473      if(bulkReportsSelected.length == 0) {
474        let bulkReportsSelectionActionsEle = document.getElementById("bulkReportsSelectionActions");
475        if(bulkReportsSelectionActionsEle!=null) {
476          let myReportsNav = document.getElementById("myReportsNav");
477          if(myReportsNav!=null) {
478            bulkReportsSelectionActionsEle.style.display = "none";
479            $("#myReportsNav").fadeIn(200);
480          }
481        }
482      }
483    }
484  }catch(e){
485    LOGGER.log(Level.SEVERE,"Exception insied handleBulkReportsSelectedActions",e);
486  }
487}
488
489function removeAllSelectedReports() {
490  try{
491    let startReportNumForCurrentPage = (SV.REPORTS_PER_PAGE * (pageNumber-1))+1;
492    let endingReportNumForCurrentPage = startReportNumForCurrentPage+SV.REPORTS_PER_PAGE;
493    for(let i=startReportNumForCurrentPage;i<=endingReportNumForCurrentPage;i++) {
494      try{
495        let selectReportId = "select-"+String(i)+"-report";
496        let reportCheckBoxEle = document.getElementById(selectReportId);
497        if(reportCheckBoxEle!=null) {
498          if(reportCheckBoxEle.checked) {
499            reportCheckBoxEle.checked = false;
500          }
501        }
502      }catch(e){
503        break;
504      }
505    }
506    handleBulkReportsSelectedActions();
507  }catch(e){
508    LOGGER.log(Level.SEVERE,"Exception while removeAllSelectedReports",e);
509  }
510}
511
512
513// incase if a new report is added from another tab then the localStorage must be updated
514window.addEventListener("storage",function(e){ 
515  try{
516    let currentlyModifiedKey = typeof(e.key) == 'string' && e.key.length > 0 ? e.key : null;
517    if(currentlyModifiedKey != null) {
518      if(Common.isOurLocalStorageKey(currentlyModifiedKey)) {
519        if(!Common.isReRenderPopupShownToUser() && Common.isAnyModalOpenInCurrentPage()) {
520            if(currentlyModifiedKey == "googlemeet-attendance-tracker-ext") {
521              Common.checkAndClodsIfAnyModalIsOpen();
522              Common.showReRenderPopup();
523            }
524        }
525        setTimeout(function(){
526          executeScript(false);
527        }, 500);
528      }
529    }
530  }catch(ere) {
531    LOGGER.log(Level.SEVERE,"Exception while re-render due to storage change",ere);
532    Common.showReRenderPopup();
533  }
534});
535
536//functions for deleting and viewing
537
538// view report
539function viewReport(attendanceReport) {
540  try{
541    Common.removeClassName(attendanceReport, "onboard-effectBtn");
542    Common.trackFeatureUsage(view_attendance_report_click);
543    let isReportFoundAndSetInSession = false;
544    reportId = findReportNumber(attendanceReport);
545    let currReportId = 1;
546    for(attendanceReport of attendanceReports) {
547        if(reportId==currReportId) {
548            x = [];
549            x.unshift(attendanceReport);
550            sessionStorage.clear("currReport-googlemeet-attendance-tracker-ext");
551            sessionStorage.setItem("currReport-googlemeet-attendance-tracker-ext",JSON.stringify(x));
552            console.log(currReportId);
553            isReportFoundAndSetInSession = true;
554            break;
555        }
556      currReportId += 1;
557    }
558    if(isReportFoundAndSetInSession) {
559      try {
560        let attendanceReportURL = "attendancereport.html";
561        if(isBulkSharedReportsView) {
562          attendanceReportURL += "?vsrc=myreports";
563        }
564        window.open(attendanceReportURL);
565      } catch(e) {
566        window.location.href = "attendancereport.html";
567      }
568    }
569  }catch(e){
570    LOGGER.log(Level.SEVERE,"Exception while trying to view report",e);
571  }
572}
573
574// delete report
575function deleteReport(attendanceReport) {
576  try{
577    reportNum = findReportNumber(attendanceReport);
578    // deletig the object in localStorage
579    attendanceReports.splice((reportNum-1),1);
580    localStorage.setItem("googlemeet-attendance-tracker-ext",JSON.stringify(attendanceReports));
581    // delete animations
582    let tableId = "#table-"+String(reportNum)+"-id";
583    $(tableId).animate({right: "100%",opacity: "0%"},450,function(){
584      executeScript(false);
585    });
586    Common.trackFeatureUsage(attendance_report_deleted);
587  }catch(e){
588    LOGGER.log(Level.SEVERE,"Exception while deleting a attendance report",e);
589  }
590}
591
592// change report name
593function toggleEditMeetingName(attendanceReport) {
594  try{
595    let reportNum = findReportNumber(attendanceReport);
596    let reportCustomDefinitions = Common.getCustomDefinitions(attendanceReports[reportNum-1]);
597    let isHavingCustomMeetingName = reportCustomDefinitions.CUSTOM_MEETING_NAME;
598    let reportEditId = "report-"+String(reportNum)+"-edit";
599    let reportName = "report-"+String(reportNum)+"-name";
600    let currState = document.getElementById(reportName).contentEditable;
601    if(currState==="true") {
602        let newMeetingName = document.getElementById(reportName).innerText.trim();
603        if(newMeetingName && newMeetingName.length > 0) {
604          document.getElementById(reportName).contentEditable = false;
605          if(isHavingCustomMeetingName) {
606            attendanceReports[reportNum-1].meetingName = newMeetingName;
607          } else {
608            attendanceReports[reportNum-1].meetingCode = newMeetingName;
609          }
610          localStorage.setItem("googlemeet-attendance-tracker-ext",JSON.stringify(attendanceReports));
611          document.getElementById(reportEditId).innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16"> <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/></svg>`;
612          Common.trackFeatureUsage(report_name_changed);
613        } else {
614          alert("Meeting Name cannot be empty");
615          document.getElementById(reportName).focus();
616        }
617    } else {
618        document.getElementById(reportName).contentEditable = true;
619        document.getElementById(reportEditId).innerHTML = `<b style="font-size:14px;color:green">save</b>`;
620        document.getElementById(reportName).focus();
621    }
622  }catch(e){
623    LOGGER.log(Level.SEVERE,"Exception while editing meeting name",e);
624  }
625}
626
627
628// searches Report
629function searchReport() {
630  try {
631    let reportName = document.getElementById("searchReport").value.toUpperCase().trim();
632    if(reportName != null && typeof(reportName)=='string') {
633      let tableRows = document.getElementsByTagName("tr");
634      for(let i=1; i<tableRows.length; i++) {
635        let tableData = tableRows[i].getElementsByTagName("td")[0].innerHTML.toUpperCase();
636        if(tableData.includes(reportName)) {
637          tableRows[i].style.display = "";
638        } else {
639          tableRows[i].style.display = "none";
640        }
641      }
642      if(reportName.trim() != "" && reportName.length > 0) {
643        if(!isBulkSharedReportsView) {
644          Common.addNoReportFoundTemplateInMyReportsTableBody();
645        }
646      } else if(reportName === "") {
647        if(!isBulkSharedReportsView) {
648          Common.removeReportNotFoundTemplateInMyReportsTableBody();
649        }
650      }
651    }
652  }catch(e){
653    LOGGER.log(Level.SEVERE,"Exception while searching attendance report",e);
654  }
655}
656
657 
658// modal body contents
659function fillModalBodyContents(attendanceReport) {
660  try{
661    classSelectedToSaveReport = "";
662    let reportNum = findReportNumber(attendanceReport);
663    let selectedMeetingData = attendanceReports[reportNum-1];
664    console.log(selectedMeetingData)
665    let classData = JSON.parse(localStorage.getItem("googlemeet-attendance-tracker-ext-class"));
666    if(classData == null) {
667      /**
668       * When the classData is null it means user has never accessed myclasses.html,
669       * In below flow we will iterave over the classData, if it is null then it will create exception...so making it as empty array
670       */
671      classData = [];
672    }
673    let modalBodyHTML = 
674    `
675    <div class="row">
676      <div class="col-6">
677        <p style="font-size: 14px;">S.No: <b>${reportNum}</b></p>
678      </div>
679      <div class="col-6">
680        <p style="font-size: 14px; max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">Meeting Name: <b>${selectedMeetingData.meetingCode}</b></p>
681      </div>
682      <div class="col-6">
683        <p style="font-size: 14px;">Meeting Date: <b>${selectedMeetingData.date}</b></p>
684      </div>
685      <div class="col-6">
686        <p style="font-size: 14px;">Report Generated At: <b>${selectedMeetingData.attendanceStopTime}</b></p>
687      </div>
688      <div class="col-6">
689        <p style="font-size: 14px;">Meeting Duration: <b>${toTimeFormat(selectedMeetingData.meetingDuration)}</b></p>
690      </div>
691      <div class="col-6">
692        <p style="font-size: 14px;">Total Participants: <b>${selectedMeetingData.studentNames.length}</b></p>
693      </div>
694    </div>
695    <hr />
696    <div class="row">
697    <div class="col-5">
698      <p style="font-size: 18px; font-weight: 450;">Save this report to: </p>
699    </div>
700    <div class="col-7">
701      <select class="custom-select" onchange="updateClassSelectedToSaveReport()" id="classSelectedInStatusUpdate" >
702        <option disabled selected value>Click here to select a class</option>
703    `;
704    let atleastOneClassIsPresent = false;
705    try{
706      for(classRecord of classData) {
707        let isDuplicateClass = Common.isDuplicateClass(classRecord);
708        let currRecordHTML = `<option ${isDuplicateClass ? "disabled" : ""}>${classRecord.className} ${isDuplicateClass ? "(inactive)" : ""}</option>`;
709        modalBodyHTML += currRecordHTML;
710        atleastOneClassIsPresent = true;
711      }
712    } catch(error){
713      // do nothing
714      LOGGER.log(Level.SEVERE,"Exception while filling modal contents for modal in which we allow saving report to a class",error);
715    }
716    modalBodyHTML += 
717    `</select>
718    </div>
719    </div>
720    <br/>
721    <p id="statusUpdateModalErrorMessage"></p>
722    <hr />
723    <div class="text-center" id="statusUpdateModalFooter">
724          <p style="font-size: 14px;" class="float-left">click <a href="myclasses.html" style="text-decoration: none;">here</a> to create a new class</p>
725          <button type="button" style="max-width: 240px; white-space: nowrap; overflow: hidden; text-overflow: clip;" class="btn btn-info float-right" id="statusUpdateModalSaveButton">Save</button>
726    </div>
727    `;
728    if(atleastOneClassIsPresent) {
729      document.getElementById("statusUpdateModalBody").innerHTML = modalBodyHTML;
730      document.getElementById("statusUpdateModalSaveButton").addEventListener("click",function(){
731        saveReportToSelectedClass(selectedMeetingData, reportNum);
732      });
733      document.getElementById("statusUpdateModalSaveButton").innerHTML = `Save`;
734    } else {
735      let noClassesFoundTemplate = 
736      `
737      <p>You haven't created a class yet !</p>
738      <ul style="line-height: 1.9">
739        <li>Create a class to manage attendance class wise</li>
740        <li>Creating a class helps you find absentees after generating a report every time</li>
741      </ul>
742      <p>Click the below <i><u>Create class </u></i> &nbsp;button to get started.</p>
743      <div class="text-center p-1">
744        <a href="myclasses.html" style="text-decoration:none;"><button style="margin-bottom: 10px; margin-top:10px; letter-spacing: 1px; font-size: 18px;" class="btn btn-info btn-block">Create class</button></a>
745      </div>
746      `;
747      document.getElementById("statusUpdateModalTitle").innerHTML = "No classes found !";
748      document.getElementById("statusUpdateModalBody").innerHTML = noClassesFoundTemplate;
749    }
750  }catch(e){
751    LOGGER.log(Level.SEVERE,"Exception while filling modal body contents -> savereporttoaclass modal",e);
752  }
753}
754
755// updates the class selected to save the report
756function updateClassSelectedToSaveReport() {
757  try{
758    classSelectedToSaveReport = classSelectedInStatusUpdate.value;
759    document.getElementById("statusUpdateModalSaveButton").innerHTML = `Save to " ${classSelectedToSaveReport} "`;
760  }catch(e){
761    LOGGER.log(Level.SEVERE,"Exception in updateClassSelectedToSaveReport",e);
762  }
763}
764
765
766// saves the selected report to the selected class
767function saveReportToSelectedClass(attendanceReport, reportNum) {
768  try{
769    if(classSelectedToSaveReport=="") {
770      document.getElementById("statusUpdateModalErrorMessage").style.color = "red";
771      document.getElementById("statusUpdateModalErrorMessage").innerHTML = "*Error: Select a class from the drop down and try again";
772    } else {
773      document.getElementById("statusUpdateModalErrorMessage").style.color = "green";
774      document.getElementById("statusUpdateModalErrorMessage").innerHTML = "success";
775      let classData = JSON.parse(localStorage.getItem("googlemeet-attendance-tracker-ext-class"));
776      let classRecordFound = false;
777      let classRecordIndex = -1;
778      for(let index=0; index<classData.length; index++) {
779        let classRecord = classData[index];
780        if(classRecord.className == classSelectedToSaveReport && !Common.isDuplicateClass(classRecord)) {
781          // saving data to class
782          classRecordIndex = index;
783          let studentsRawData = classRecord.studentsData;
784          studentsRawData = [...new Set(studentsRawData)]; // Fix to avoid duplicate participants names (for report generated via addon) -> We gave 2 present's for users will same name
785          let studentNamesFromRaw = [];
786          let studentAttendedPeriods = [];
787          let len = 0;
788          // extracting data from class by splitting name and attended periods based on hyphen
789          for(studentRawData of studentsRawData) {
790            let hyphenIndex = studentRawData.lastIndexOf("-");
791            studentNamesFromRaw[len] = studentRawData.substring(0,hyphenIndex);
792            studentAttendedPeriods[len] = Number(studentRawData.substring(hyphenIndex+1));
793            len++;
794          }
795          // giving attendance for current report present students
796          let attendees = attendanceReport.studentNames;
797          for(attendee of attendees) {
798            if(studentNamesFromRaw.includes(attendee)) {
799              let ind = studentNamesFromRaw.indexOf(attendee);
800              studentAttendedPeriods[ind] += 1;
801            } else {
802              studentNamesFromRaw.push(attendee);
803              studentAttendedPeriods.push(1);
804              len++;
805            }
806          }
807          let updatedStudentsRawData = [];
808          for(let i=0; i<len; i++) {
809            updatedStudentsRawData.push((studentNamesFromRaw[i]+"-"+studentAttendedPeriods[i]));
810          }
811          // sort it here
812          updatedStudentsRawData.sort();
813          classData[classRecordIndex].studentsData = updatedStudentsRawData;
814          classData[classRecordIndex].totalReportsAdded = classData[classRecordIndex].totalReportsAdded+1;
815          let date = new Date();
816          let dd = date.getDate();
817          let mm = date.toLocaleString('default', { month: 'short' })
818          let yyyy = date.getFullYear();
819          date = dd+"-"+mm+"-"+yyyy;
820          classData[classRecordIndex].lastReportAddedOn = date+" at "+new Date().toLocaleTimeString();
821          localStorage.setItem("googlemeet-attendance-tracker-ext-class",JSON.stringify(classData));
822          attendanceReports[reportNum-1].joiningTime[0] = "reportAddedToClass";
823          localStorage.setItem("googlemeet-attendance-tracker-ext",JSON.stringify(attendanceReports));
824          document.getElementById("statusUpdateModalErrorMessage").style.color = "green";
825          document.getElementById("statusUpdateModalErrorMessage").innerHTML = "success";
826          console.log(classData[classRecordIndex])
827          executeScript(false);
828          classRecordFound = true;
829          classSelectedToSaveReport = "";
830          $("#statusUpdateModal").modal("toggle");
831          // sweet alert if needed -> goes here
832          Common.trackFeatureUsage(report_added_to_class);
833          break;
834        }
835      }
836      if(!classRecordFound) {
837        document.getElementById("statusUpdateModalErrorMessage").style.color = "red";
838        document.getElementById("statusUpdateModalErrorMessage").innerHTML = `Something went wrong ! please close this popup and try again (or) <span style="color: blue; cursor: pointer; text-decoration: underline" onclick="Common.handleContactSupport(true)">Contact support</span>`;
839      }
840    }
841  }catch(e){
842    LOGGER.log(Level.SEVERE,"Exception while saving report to the selected class",e);
843  }
844}
845
846function showBackUpSuggestions(showLoading) {
847  try{
848    let lastBackUpTimeInMillis = Number(localStorage.getItem("googlemeet-attendance-tracker-ext-lastbackuptime"));
849    let suggestion = "";
850    let suggestionTextColor = "";
851    if(showLoading) {
852      suggestion = `<img style="margin-left: 140px; margin-right: 60px;" src="svg/loading-dots.svg">`;
853      suggestionTextColor = "#013485";
854      fillBackUpSuggestions(suggestion, suggestionTextColor, false);
855    }
856    else if(!isNaN(lastBackUpTimeInMillis) && lastBackUpTimeInMillis == 0) { 
857      suggestion = "<b>Hint: Make a backup of your data frequently</b>";
858      suggestionTextColor = "#013485";
859      fillBackUpSuggestions(suggestion, suggestionTextColor, true);
860    } else if(!isNaN(lastBackUpTimeInMillis) && lastBackUpTimeInMillis!=0 && lastBackUpTimeInMillis > 0) {
861      let currentTimeInMillis = new Date().getTime();
862      let diffDaysCount = Math.floor((currentTimeInMillis-lastBackUpTimeInMillis)/(24*60*60*1000));
863      if(diffDaysCount == 0) {
864        let lastBackUpTime = toTimeFormat(Math.floor((currentTimeInMillis-lastBackUpTimeInMillis)/1000));
865        suggestion = `<b>Your Last Backup was made ${lastBackUpTime} ago</b>`;
866        suggestionTextColor = "green";
867        fillBackUpSuggestions(suggestion, suggestionTextColor, false);
868      } else {
869        suggestion = diffDaysCount==1 ? `<b>Your last backup was made ${diffDaysCount} day ago</b>` : `<b>Caution: Your last backup was made ${diffDaysCount} days ago !</b>`;
870        suggestionTextColor = diffDaysCount==1 ? "#ff751f" : "red";
871        fillBackUpSuggestions(suggestion, suggestionTextColor, true);
872      }
873    }
874
875  }catch(excep) {
876    LOGGER.log(Level.SEVERE,"Something went wrong inside showbackup suggestions",excep);
877    console.log("Something went wrong !");
878  }
879}
880
881function fillBackUpSuggestions(suggestion, suggestionTextColor, isBlinkEffectNeeded) {
882  try{
883    if(isBackupSuggestionsPresentInDom()) {
884      document.getElementById("backupsuggestions").innerHTML = suggestion;
885      document.getElementById("backupsuggestions").style.color = suggestionTextColor;
886      if(isBlinkEffectNeeded) {
887        setTimeout(function(){
888          let blinkCount = 1;
889          let blinkInterval = setInterval(function(){
890            if(isBackupSuggestionsPresentInDom()) {
891              if(blinkCount%2 == 0) {
892                if(isBackupSuggestionsPresentInDom()) {
893                  document.getElementById("backupsuggestions").innerHTML = suggestion;
894                  document.getElementById("backupsuggestions").style.color = suggestionTextColor;
895                }
896              } else {
897                if(isBackupSuggestionsPresentInDom()) {
898                  document.getElementById("backupsuggestions").innerHTML = suggestion;
899                  document.getElementById("backupsuggestions").style.color = "#f8f9fa";
900                }
901              }
902              blinkCount += 1;
903              if(blinkCount > 5) {
904                if(isBackupSuggestionsPresentInDom()) {
905                  document.getElementById("backupsuggestions").innerHTML = suggestion;
906                  document.getElementById("backupsuggestions").style.color = suggestionTextColor;
907                }
908                clearInterval(blinkInterval);
909              }
910            }
911          },100);
912        },750);
913      }
914    }
915  }catch(exce) {
916    LOGGER.log(Level.SEVERE,"Somewhing went wrong while filling autobackup suggestions",exce);
917    console.log("Something went wrong !");
918  }
919}
920
921function doAutoBackupFromMyReports() {
922  try{
923    if(Common.isAutoBackupEnabled() && !Common.isSharedView()) {
924      showBackUpSuggestions(true);
925      Common.performAutoBackup();
926    } else {
927      showBackUpSuggestions();
928    }
929  }catch(e){
930    LOGGER.log(Level.SEVERE,"Exception in doAutoBackupFromMyReports",e);
931  }
932}
933
934function isBackupSuggestionsPresentInDom() {
935  /**
936   * The reason for this method and this checks inside code is because, for some browsers backupsuggestions dom is being null
937   * due to very fastly manipulating the dom for blink effect animation every 100 milliseconds.
938   */
939  try{
940    let backupSuggestionsDom = document.getElementById("backupsuggestions").innerHTML;
941    return backupSuggestionsDom != null ? true : false;
942  }catch(e){
943    // Dont push logs to server -> It will be dumped...some users in some browser there is issue when using setInterval in in very high frequency
944    return false;
945  }
946  return false;
947}
948
949function completeAutoBackupStatus() {
950    try {
951        let localDataForAutoBackUpStatus = localStorage.getItem("googlemeet-attendance-tracker-ext-autobackup");
952        if(localDataForAutoBackUpStatus == null) {
953            localStorage.setItem("googlemeet-attendance-tracker-ext-autobackup",false);
954        }
955        let status = localStorage.getItem("googlemeet-attendance-tracker-ext-autobackup") === "true";
956        let autoBackupToggleEle = document.getElementById("autoBackupToggleBtn");
957        if(autoBackupToggleEle!=null) {
958          autoBackupToggleEle.checked = status;
959          status ? Common.changeAutoBackupToggleMessage("Auto Backup (enabled)") : Common.changeAutoBackupToggleMessage("Auto Backup (disabled)");
960        }
961    }catch(e) {
962        LOGGER.log(Level.SEVERE,"Something went wrong inside completeAutoBackupStatus",e);
963        console.log("completeautobackup api failed due to"+e);
964    }
965}
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981// ## Common API's. Don't write business logic code below this line
982
983// finds the reportId from button id
984function findReportNumber(attendanceReport) {
985  report = attendanceReport.split("-");
986  return Number(report[1]);
987}
988
989// to time hh:mm:ss format
990function toTimeFormat(time)
991{
992    hh = Math.floor(time/3600);
993    time = time - (hh*3600);
994    mm = Math.floor(time/60);
995    time = time - (mm*60); 
996    ss = time;
997    if(hh==0)return mm+" min "+ss+"s";
998    else return hh+" hr "+mm+" min "+ss+"s";
999}
1000
1001
1002// new version #1

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.