PageSourceSearch

https://www.mindko.com/static/js/support/support-features-handler.js

js mindko.com collected 2026-10-01 14:15:38 UTC 18,800 bytes, 593 lines download raw bytes

1// Platform and feature handling
2const PLATFORM_SUPPORT = {
3  limited: [
4    'mcgraw-hill',
5    'cengage-mindtap',
6    'pearson-mylab',
7    'macmillan-learning'
8  ],
9  pending: [
10    'khan-academy',
11    'classmaker',
12    'moodle',
13    'schoology',
14    'edmodo',
15    'myeducator',
16    'exam-builder'
17  ]
18};
19
20const buttonPlatforms = [
21  'canvas-instructure',
22  'brightspace-d2l',
23  'google-classroom-forms',
24  'tophat',
25  'blackboard'
26];
27
28let selectedPlatforms = new Set();
29let selectedFeatures = new Map();
30let selectedPauseDuration = null;
31let additionalFeedback = {
32  issues: new Set(),
33  comments: ''
34};
35
36// Platform handlers
37function handlePlatformSelection(platform) {
38 const button = event.target;
39 const continueBtn = document.querySelector('.cancel-flow-continue');
40 
41 // Don't allow selecting if it's the other-input
42 if (button.classList.contains('other-input')) {
43   return;
44 }
45 
46 if (button.classList.contains('selected')) {
47   button.classList.remove('selected');
48   selectedPlatforms.delete(platform);
49   // Only remove feature selections for the platform being removed
50   selectedFeatures.delete(platform);
51 } else {
52   button.classList.add('selected');
53   if (platform) {
54     selectedPlatforms.add(platform);
55   }
56 }
57 
58 // Update continue button state
59 if (selectedPlatforms.size > 0) {
60   continueBtn.classList.remove('disabled');
61   continueBtn.style.pointerEvents = 'auto';
62 } else {
63   continueBtn.classList.add('disabled');
64   continueBtn.style.pointerEvents = 'none';
65 }
66}
67
68function handleFeatureSelection(platform, feature) {
69 if (!selectedFeatures.has(platform)) {
70   selectedFeatures.set(platform, new Set());
71 }
72 
73 const platformFeatures = selectedFeatures.get(platform);
74 const button = event.target;
75 
76 if (button.classList.contains('selected')) {
77   button.classList.remove('selected');
78   platformFeatures.delete(feature);
79 } else {
80   button.classList.add('selected');
81   platformFeatures.add(feature);
82 }
83 
84 // Clear existing additional feedback when features change
85 additionalFeedback.issues.clear();
86}
87
88function handlePauseSelection(months) {
89 selectedPauseDuration = months;
90 
91 const buttons = document.querySelectorAll('.pause-button');
92 const pauseBtn = document.querySelector('.cancel-flow-pause');
93 const resumeDateSpan = document.querySelector('.resume-date span');
94 
95 if (buttons) {
96   buttons.forEach(btn => btn.classList.remove('selected'));
97   event.target.classList.add('selected');
98 }
99 
100 if (pauseBtn) {
101   pauseBtn.classList.remove('disabled');
102 }
103 
104 if (resumeDateSpan) {
105   const resumeDate = new Date();
106   resumeDate.setMonth(resumeDate.getMonth() + months);
107   const formattedDate = resumeDate.toLocaleDateString('en-US', { 
108     month: 'long', 
109     day: 'numeric', 
110     year: 'numeric' 
111   });
112   resumeDateSpan.textContent = formattedDate;
113 }
114}
115
116function handleReasonSelection(reason) {
117 reasonCancellationTrack(reason);
118 selectedReason = reason;
119 
120 const buttons = document.querySelectorAll('.reason-button');
121 const continueBtn = document.querySelector('.cancel-flow-continue');
122 
123 if (buttons) {
124   buttons.forEach(btn => btn.classList.remove('selected', 'selected-flash'));
125   event.target.classList.add('selected', 'selected-flash');
126 }
127 
128 // Enable continue button when a reason is selected
129 if (continueBtn) {
130   continueBtn.classList.remove('disabled');
131   continueBtn.style.pointerEvents = 'auto';
132 }
133 
134 setTimeout(() => {
135   handleContinue();
136 }, 500);
137}
138
139// Feature generation
140function generateFeatureSections() {
141 const container = document.querySelector('.platform-features-container');
142 container.innerHTML = ''; // Clear existing content
143 
144 // Features to show for each platform
145 const features = ['Text Selection', 'Button', 'Screenshot', 'AI Chat'];
146 
147 // List of platforms with limited support
148 const limitedSupportPlatforms = [
149   'mcgraw-hill',
150   'cengage-mindtap',
151   'pearson-mylab',
152   'macmillan-learning'
153 ];
154 
155 // Create a section for each selected platform
156 selectedPlatforms.forEach(platform => {
157   const section = document.createElement('div');
158   section.className = 'platform-feature-section';
159   section.setAttribute('data-platform', platform);
160   
161   const titleContainer = document.createElement('div');
162   titleContainer.className = 'platform-feature-header';
163   
164   const title = document.createElement('h3');
165   title.className = 'platform-feature-title';
166   const platformName = platform.split('-')
167     .map(word => word.charAt(0).toUpperCase() + word.slice(1))
168     .join(' ');
169   title.textContent = `Platform: ${platformName}`;
170   
171   titleContainer.appendChild(title);
172   
173   // Check platform support status
174   const isLimitedSupport = PLATFORM_SUPPORT.limited.includes(platform.toLowerCase());
175   const isPendingSupport = PLATFORM_SUPPORT.pending.includes(platform.toLowerCase()) || 
176                           (!PLATFORM_SUPPORT.limited.includes(platform.toLowerCase()) && 
177                            !buttonPlatforms.includes(platform.toLowerCase()) &&
178                            platform.toLowerCase() !== 'other');
179
180   if (isLimitedSupport) {
181     const warning = document.createElement('div');
182     warning.className = 'platform-support-warning';
183     warning.innerHTML = `
184       <i class="fas fa-exclamation-circle"></i>
185       <span>Direct support unavailable. Use AI Chat or Web Solver instead.</span>
186       <button onclick="showIncompatibleModal()" class="warning-learn-more">
187         Learn more
188         <i class="fas fa-arrow-right"></i>
189       </button>
190     `;
191     titleContainer.appendChild(warning);
192   } else if (isPendingSupport) {
193     const info = document.createElement('div');
194     info.className = 'platform-support-info';
195     info.innerHTML = `
196       <i class="fas fa-info-circle"></i>
197       <span>Platform not directly supported yet</span>
198       <button onclick="requestPlatformSupport('${platform}')" class="request-platform-button">
199         Request platform
200         <i class="fas fa-arrow-right"></i>
201       </button>
202     `;
203     titleContainer.appendChild(info);
204   }
205   
206   const buttonsContainer = document.createElement('div');
207   buttonsContainer.className = 'feature-buttons';
208   
209   features.forEach(feature => {
210     const button = document.createElement('button');
211     button.className = 'feature-button';
212     const feature_id = feature.toLowerCase().replace(/\s+/g, '_');
213     button.setAttribute('data-feature', feature_id);
214     
215     // Get existing selections for this platform
216     const platformFeatures = selectedFeatures.get(platform) || new Set();
217     
218     // For limited support platforms, pre-select and disable all specified features
219     if (isLimitedSupport && ['Text Selection', 'Button', 'Screenshot'].includes(feature)) {
220      button.classList.add('selected', 'locked');
221      if (!selectedFeatures.has(platform)) {
222        selectedFeatures.set(platform, new Set());
223      }
224      selectedFeatures.get(platform).add(feature);
225    } 
226    // For pending support platforms, only pre-select and disable Button
227    else if (isPendingSupport && feature === 'Button') {
228      button.classList.add('selected', 'locked');
229      if (!selectedFeatures.has(platform)) {
230        selectedFeatures.set(platform, new Set());
231      }
232      selectedFeatures.get(platform).add(feature);
233    }
234    else if (platformFeatures.has(feature)) {
235      // Restore previous selection
236      button.classList.add('selected');
237    }
238     
239     button.textContent = feature;
240     button.addEventListener('click', (e) => {
241       // Prevent deselection of locked features
242       if (!e.target.classList.contains('locked')) {
243         handleFeatureSelection(platform, feature);
244       }
245     });
246     buttonsContainer.appendChild(button);
247   });
248   
249   section.appendChild(titleContainer);
250   section.appendChild(buttonsContainer);
251   container.appendChild(section);
252 });
253}
254
255function generateAdditionalFeedback() {
256 const checkboxGroup = document.querySelector('.checkbox-group');
257 if (!checkboxGroup) return;
258
259 // Store the original base questions (without the category wrapper)
260 const baseQuestions = `
261   <label class="checkbox-label">
262     <input type="checkbox" class="feedback-checkbox" data-issue="response-time">
263     <span>Response times were consistently slow</span>
264   </label>
265   
266   <label class="checkbox-label">
267     <input type="checkbox" class="feedback-checkbox" data-issue="accuracy">
268     <span>Responses weren't accurate enough</span>
269   </label>
270   
271   <label class="checkbox-label">
272     <input type="checkbox" class="feedback-checkbox" data-issue="technical">
273     <span>I experienced technical issues or errors</span>
274   </label>
275   
276   <label class="checkbox-label">
277     <input type="checkbox" class="feedback-checkbox" data-issue="installation">
278     <span>I couldn't install the extension</span>
279   </label>
280   
281   <label class="checkbox-label">
282     <input type="checkbox" class="feedback-checkbox" data-issue="usage">
283     <span>The extension was difficult to use</span>
284   </label>
285 `;
286
287 let additionalQuestions = '';
288
289 // Check if screenshot was manually selected (not auto-selected)
290 const hasScreenshotIssue = Array.from(selectedFeatures.entries()).some(([platform, features]) => {
291   const isLimitedPlatform = [
292     'mcgraw-hill',
293     'cengage-mindtap',
294     'pearson-mylab',
295     'macmillan-learning'
296   ].includes(platform.toLowerCase());
297   
298   return features.has('Screenshot') && !isLimitedPlatform;
299 });
300
301 // Check if button was selected for specific platforms
302 const buttonPlatforms = [
303   'canvas-instructure',
304   'brightspace-d2l',
305   'google-classroom-forms',
306   'tophat',
307   'blackboard'
308 ];
309
310 const hasButtonIssue = Array.from(selectedFeatures.entries()).some(([platform, features]) => 
311   buttonPlatforms.includes(platform.toLowerCase()) && features.has('Button')
312 );
313
314 // Build the complete HTML
315 let allContent = `
316   <div class="feedback-category">
317     <h4 class="feedback-category-title">General Issues</h4>
318     ${baseQuestions}
319   </div>
320 `;
321
322 // Add screenshot-related questions
323 if (hasScreenshotIssue) {
324   allContent += `
325     <div class="feedback-category">
326       <h4 class="feedback-category-title">Screenshot Issues</h4>
327       <label class="checkbox-label">
328         <input type="checkbox" class="feedback-checkbox" data-issue="screenshot-off-topic">
329         <span>The answers were not related to the screenshot content</span>
330       </label>
331       <label class="checkbox-label">
332         <input type="checkbox" class="feedback-checkbox" data-issue="screenshot-no-answer">
333         <span>No answer was provided for the screenshot</span>
334       </label>
335     </div>
336   `;
337 }
338
339 // Add button-related questions
340 if (hasButtonIssue) {
341   // Get the platform name for the title
342   const platformWithButtonIssue = Array.from(selectedFeatures.entries())
343     .find(([platform, features]) => 
344       buttonPlatforms.includes(platform.toLowerCase()) && features.has('Button')
345     )[0];
346   
347   const platformName = platformWithButtonIssue.split('-')
348     .map(word => word.charAt(0).toUpperCase() + word.slice(1))
349     .join(' ');
350
351   allContent += `
352     <div class="feedback-category">
353       <h4 class="feedback-category-title">Button integration issue (${platformName})</h4>
354       
355       <div class="feedback-input-group">
356         <label class="feedback-input-label">
357           Domain
358           <div class="info-tooltip">
359             <i class="fas fa-info-circle"></i>
360             <span class="tooltip-text">The URL where you use the platform (e.g., myschool.instructure.com)</span>
361           </div>
362         </label>
363         <input type="text" 
364           class="feedback-text-input" 
365           placeholder="e.g., myschool.instructure.com"
366           data-issue="platform-domain">
367       </div>
368
369       <div class="feedback-input-group">
370         <label class="feedback-input-label">Question Type Trying to Solve</label>
371         <select class="feedback-select" data-issue="question-type">
372           <option value="">Select question type...</option>
373           <option value="multiple-choice">Multiple Choice</option>
374           <option value="true-false">True/False</option>
375           <option value="fill-blank">Fill in the Blank</option>
376           <option value="matching">Matching</option>
377           <option value="essay">Essay/Open Response</option>
378           <option value="numerical">Numerical/Math</option>
379           <option value="other">Other</option>
380         </select>
381       </div>
382     </div>
383   `;
384 }
385
386 // Update the checkbox group content
387 checkboxGroup.innerHTML = allContent;
388
389 // Reattach event listeners
390 document.querySelectorAll('.feedback-checkbox').forEach(checkbox => {
391   checkbox.addEventListener('change', handleCheckboxChange);
392 });
393}
394
395function handleCheckboxChange(event) {
396  const checkbox = event.target;
397  const issue = checkbox.dataset.issue;
398  
399  if (checkbox.checked) {
400    additionalFeedback.issues.add(issue);
401  } else {
402    additionalFeedback.issues.delete(issue);
403  }
404}
405
406function handleCommentsChange(event) {
407  additionalFeedback.comments = event.target.value.trim();
408}
409
410function transformToInput(button) {
411  button.classList.add('other-input');
412  button.innerHTML = `
413    <input type="text" placeholder="Type platform name..." />
414    <button class="add-button" disabled>Add</button>
415  `;
416  
417  const input = button.querySelector('input');
418  const addButton = button.querySelector('.add-button');
419  
420  input.focus();
421  
422  input.addEventListener('input', () => {
423    addButton.disabled = !input.value.trim();
424  });
425  
426  addButton.addEventListener('click', () => {
427    const platformName = input.value.trim();
428    if (platformName) {
429      // Create new platform button
430      const newButton = document.createElement('button');
431      newButton.className = 'platform-button selected';
432      newButton.setAttribute('data-platform', platformName.toLowerCase().replace(/\s+/g, '-'));
433      newButton.textContent = platformName;
434      
435      // Add random transform
436      const tx = (Math.random() - 0.5) * 20;
437      const ty = (Math.random() - 0.5) * 20;
438      const rot = (Math.random() - 0.5) * 5;
439      newButton.style.setProperty('--tx', `${tx}px`);
440      newButton.style.setProperty('--ty', `${ty}px`);
441      newButton.style.setProperty('--rot', `${rot}deg`);
442      
443      // Add click handler
444      newButton.addEventListener('click', (e) => {
445        handlePlatformSelection(e.target.dataset.platform);
446      });
447      
448      // Insert before the Other button
449      button.parentNode.insertBefore(newButton, button);
450      
451      // Add to selected platforms
452      if (platformName) {
453        selectedPlatforms.add(platformName.toLowerCase().replace(/\s+/g, '-'));
454      }
455      
456      // Reset the input
457      input.value = '';
458      addButton.disabled = true;
459      input.focus();
460    }
461  });
462  
463  // Handle enter key
464  input.addEventListener('keypress', (e) => {
465    if (e.key === 'Enter' && !addButton.disabled) {
466      addButton.click();
467    }
468  });
469}
470
471// Event listeners
472document.addEventListener('DOMContentLoaded', () => {
473  // Platform buttons
474  document.querySelectorAll('.platform-button').forEach(btn => {
475    const tx = (Math.random() - 0.5) * 20;
476    const ty = (Math.random() - 0.5) * 20;
477    const rot = (Math.random() - 0.5) * 5;
478    btn.style.setProperty('--tx', `${tx}px`);
479    btn.style.setProperty('--ty', `${ty}px`);
480    btn.style.setProperty('--rot', `${rot}deg`);
481    
482    btn.addEventListener('click', (e) => {
483      if (e.target.dataset.platform === 'other' && !e.target.classList.contains('other-input')) {
484        transformToInput(e.target);
485      } else {
486        handlePlatformSelection(e.target.dataset.platform);
487      }
488    });
489  });
490  
491  // Pause buttons
492  document.querySelectorAll('.pause-button').forEach(btn => {
493    btn.addEventListener('click', (e) => {
494      handlePauseSelection(parseInt(e.target.dataset.months));
495    });
496  });
497
498  // Reason buttons
499  document.querySelectorAll('.reason-button').forEach(btn => {
500    btn.addEventListener('click', (e) => {
501      handleReasonSelection(e.target.dataset.reason);
502    });
503  });
504
505  // Feature buttons (these are dynamically added, but initial ones)
506  document.querySelectorAll('.feature-button').forEach(btn => {
507    btn.addEventListener('click', (e) => {
508      if (!e.target.classList.contains('locked')) {
509        handleFeatureSelection(e.target.dataset.platform, e.target.textContent);
510      }
511    });
512  });
513
514  // Feedback checkboxes
515  document.querySelectorAll('.feedback-checkbox').forEach(checkbox => {
516    checkbox.addEventListener('change', handleCheckboxChange);
517  });
518
519  // Additional comments textarea
520  const textarea = document.getElementById('additional-comments');
521  if (textarea) {
522    textarea.addEventListener('input', handleCommentsChange);
523  }
524
525  // Feature request textarea
526  const featureRequestTextarea = document.getElementById('feature-request');
527  if (featureRequestTextarea) {
528    featureRequestTextarea.addEventListener('input', handleFeatureRequestChange);
529  }
530
531  // Password inputs
532  const passwordInputs = document.querySelectorAll('.password-input-group input');
533  passwordInputs.forEach(input => {
534    input.addEventListener('input', validatePasswords);
535  });
536});
537
538async function handlePause() {
539  if (selectedPauseDuration) {
540    pauseCancellationTrack(selectedPauseDuration);
541    console.log(`Pausing subscription for ${selectedPauseDuration} months`);
542    const pauseBtn = document.querySelector('.cancel-flow-pause');
543    pauseBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>';
544    pauseBtn.classList.add('disabled');
545
546    const result = await pauseSubscription(selectedPauseDuration);
547
548    // Enable the button and hide the spinner
549    pauseBtn.textContent = "Pause";
550    pauseBtn.classList.remove("disabled");
551    
552    if (result.success === false && result.message === "Paypal") {
553        showPaypalFixModal(result.link);
554    } else if (result.success) {
555        showPauseSuccessModal();
556    } else {
557        showToast(result.message, 'error');
558    }
559  }
560}
561
562
563// Add function to check for incompatible platforms
564function checkIncompatiblePlatforms() {
565  const incompatiblePlatforms = [
566    'mcgraw-hill',
567    'cengage-mindtap',
568    'pearson-mylab',
569    'macmillan-learning'
570  ];
571  
572  const hasIncompatiblePlatform = Array.from(selectedPlatforms)
573    .some(platform => incompatiblePlatforms.includes(platform.toLowerCase()));
574  
575  if (hasIncompatiblePlatform) {
576    showIncompatibleModal();
577  }
578}
579
580// Add modal control functions
581function showIncompatibleModal() {
582  const modal = document.getElementById('incompatible-platforms-modal');
583  if (modal) {
584    modal.style.display = 'flex';
585  }
586}
587
588function closeIncompatibleModal() {
589  const modal = document.getElementById('incompatible-platforms-modal');
590  if (modal) {
591    modal.style.display = 'none';
592  }
593} 

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.