1/** 2 * Form iDevice 3 * 4 * Released under Attribution-ShareAlike 4.0 International License. 5 * Author: SDWEB - Innovative Digital Solutions 6 * 7 * License: http://creativecommons.org/licenses/by-sa/4.0/ 8 */ 9var $text = { 10 ideviceClass: 'textIdeviceContent', 11 working: false, 12 durationId: 'textInfoDurationInput', 13 durationTextId: 'textInfoDurationTextInput', 14 participantsId: 'textInfoParticipantsInput', 15 participantsTextId: 'textInfoParticipantsTextInput', 16 mainContentId: 'textTextarea', 17 feedbackTitleId: 'textFeedbackInput', 18 feedbackContentId: 'textFeedbackTextarea', 19 20 defaultBtnFeedbackText: $exe_i18n.showFeedback, 21 22 /** 23 * Engine execution order: 1 24 * Get the base html of the idevice view 25 */ 26 renderView(data, accessibility, template) { 27 const hmltdata = $text.getHTMLView(data); 28 return template.replace('{content}', hmltdata); 29 }, 30 31 getHTMLView(data, pathMedia) { 32 const isInExe = eXe.app.isInExe(); 33 const durationText = isInExe 34 ? c_(data[this.durationTextId]) 35 : data[this.durationTextId]; 36 const participantsText = isInExe 37 ? c_(data[this.participantsTextId]) 38 : data[this.participantsTextId]; 39 40 let infoContentHTML = ''; 41 if (data[this.durationId] || data[this.participantsId]) { 42 infoContentHTML = this.createInfoHTML( 43 data[this.durationId] === '' ? '' : durationText, 44 data[this.durationId], 45 data[this.participantsId] === '' ? '' : participantsText, 46 data[this.participantsId] 47 ); 48 } 49 50 let contentHtml = data[this.mainContentId]; 51 52 const temp = document.createElement('div'); 53 temp.innerHTML = contentHtml; 54 55 const btnDiv = temp.querySelector('.feedback-button'); 56 let buttonFeedBackText = data[this.feedbackTitleId]; 57 if (btnDiv) { 58 const inputEl = btnDiv.querySelector('input.feedbackbutton'); 59 if (inputEl) 60 buttonFeedBackText = isInExe 61 ? c_(inputEl.value) 62 : inputEl.value; 63 btnDiv.remove(); 64 } 65 66 let feedBackHtml = data[this.feedbackContentId] || ''; 67 const fbDiv = temp.querySelector('.feedback.js-feedback'); 68 if (fbDiv) { 69 feedBackHtml = fbDiv.innerHTML; 70 fbDiv.remove(); 71 } 72 73 contentHtml = temp.innerHTML; 74 if (feedBackHtml) { 75 buttonFeedBackText = 76 buttonFeedBackText === '' 77 ? this.defaultBtnFeedbackText 78 : buttonFeedBackText; 79 if (isInExe) buttonFeedBackText = c_(buttonFeedBackText); 80 } 81 82 data['textInfoParticipantsTextInput'] = participantsText; 83 data['textInfoDurationTextInput'] = durationText; 84 data['textTextarea'] = contentHtml; 85 data['textFeedbackInput'] = buttonFeedBackText; 86 data['textFeedbackTextarea'] = feedBackHtml; 87 88 const feedbackContentHTML = 89 feedBackHtml === '' 90 ? '' 91 : this.createFeedbackHTML(buttonFeedBackText, feedBackHtml); 92 const activityContent = 93 infoContentHTML + 94 contentHtml + 95 feedbackContentHTML + 96 `<p class="clearfix"></p>`; 97 98 let htmlContent = `<div class="${this.ideviceClass}">`; 99 htmlContent += this.createMainContent(activityContent); 100 htmlContent += `</div>`; 101 102 return htmlContent; 103 }, 104 105 renderHtmlOldIdevice(data, $node) { 106 // Defensive: ensure $node is a jQuery object 107 if (!$node || !$node.length) return; 108 109 if ( 110 $node.find('.pbl-task-description').length === 1 && 111 (data[this.durationId] || data[this.participantsId]) 112 ) { 113 const durationText = data[this.durationTextId]; 114 const participantsText = data[this.participantsTextId]; 115 const infoContentHTML = this.createInfoHTML( 116 data[this.durationId] === '' ? '' : durationText, 117 data[this.durationId], 118 data[this.participantsId] === '' ? '' : participantsText, 119 data[this.participantsId] 120 ); 121 122 $node.prepend(infoContentHTML); 123 } 124 125 let buttonFeedBackText = data[this.feedbackTitleId] || ''; 126 let feedBackHtml = data[this.feedbackContentId] || ''; 127 const hasFeedbackNode = $node.find('.feedback.js-feedback').length > 0; 128 const hasFeedbackData = !!feedBackHtml; 129 const hasFeedbackButton = $node.find('.feedback-button').length > 0; 130 131 if (hasFeedbackData || hasFeedbackNode) { 132 const $btnDiv = $node.find('.feedback-button'); 133 const hasInput =
134 $btnDiv.find('input.feedbacktooglebutton, input.feedbackbutton') 135 .length > 0; 136 if ($btnDiv.length && !hasInput) { 137 const btnText = buttonFeedBackText 138 ? buttonFeedBackText 139 : this.defaultBtnFeedbackText; 140 $btnDiv.append( 141 `<input type="button" class="feedbacktooglebutton" value="${btnText}" />` 142 ); 143 } else if (!hasFeedbackButton) { 144 const feedbackButtonHTML = ` 145 <div class="iDevice_buttons feedback-button js-required"> 146 <input type="button" class="feedbacktooglebutton" value="${buttonFeedBackText || this.defaultBtnFeedbackText}" /> 147 </div>`; 148 const $activity = $node.find('.exe-text'); 149 if ($activity.length) { 150 $activity.append(feedbackButtonHTML); 151 } else { 152 $node.append(feedbackButtonHTML); 153 } 154 } 155 } 156 157 if (hasFeedbackData && !hasFeedbackNode) { 158 const feedbackContentHTML = `<div class="feedback js-feedback js-hidden">${feedBackHtml}</div>`; 159 const $activity = $node.find('.exe-text'); 160 if ($activity.length) { 161 $activity.append(feedbackContentHTML); 162 } else { 163 $node.append(feedbackContentHTML); 164 } 165 } 166 167 if ($node.find('.clearfix').length === 0) { 168 const $activity = $node.find('.exe-text'); 169 if ($activity.length) { 170 $activity.append('<p class="clearfix"></p>'); 171 } else { 172 $node.append('<p class="clearfix"></p>'); 173 } 174 } 175 }, 176 177 /** 178 * Engine execution order: 2 179 * Add behavior and functionalities 180 */ 181 renderBehaviour(data, accessibility, ideviceId) { 182 const $node = $('#' + data.ideviceId); 183 const isInExe = eXe.app.isInExe(); 184 185 const $btn = $( 186 `#${data.ideviceId} input.feedbackbutton, #${data.ideviceId} input.feedbacktooglebutton` 187 ); 188 if ($btn.length === 1) { 189 const [textA, textB = textA] = $btn.val().split('|'); 190 $btn.val(textA) 191 .attr('data-text-a', textA) 192 .attr('data-text-b', textB); 193 $btn.off('click') 194 .closest('.feedback-button') 195 .removeClass('clearfix'); 196 197 $btn.on('click', function () { 198 if ($text.working) return false; 199 $text.working = true; 200 const btn = $(this); 201 const feedbackEl = btn 202 .closest('.feedback-button') 203 .next('.feedback'); 204 205 if (feedbackEl.is(':visible')) { 206 btn.val(btn.attr('data-text-a')); 207 feedbackEl.fadeOut(() => { 208 $text.working = false; 209 }); 210 } else { 211 btn.val(btn.attr('data-text-b')); 212 feedbackEl.fadeIn(() => { 213 $text.working = false; 214 }); 215 } 216 $exeDevices.iDevice.gamification.math.updateLatex( 217 '.exe-text-template' 218 ); 219 }); 220 } 221 const dataString = $node.html() || ''; 222 if ($exeDevices.iDevice.gamification.math.hasLatex(dataString)) { 223 $exeDevices.iDevice.gamification.math.updateLatex( 224 '.exe-text-template' 225 ); 226 } 227 }, 228 229 replaceResourceDirectoryPaths(newDir, htmlString) { 230 let dir = newDir.trim(); 231 if (!dir.endsWith('/')) dir += '/'; 232 const custom = $('html').is('#exe-index') ? 'custom/' : '../custom/'; 233 234 const parser = new DOMParser(); 235 const doc = parser.parseFromString(htmlString, 'text/html'); 236 doc.querySelectorAll( 237 'img[src], video[src], audio[src], a[href]' 238 ).forEach((el) => { 239 const attr = el.hasAttribute('src') ? 'src' : 'href'; 240 const val = el.getAttribute(attr).trim(); 241 242 if (/^\/?files\//.test(val)) { 243 const filename = val.split('/').pop() || ''; 244 if (val.indexOf('file_manager') === -1) { 245 el.setAttribute(attr, dir + filename); 246 } else { 247 el.setAttribute(attr, custom + filename); 248 } 249 } 250 }); 251 return doc.body.innerHTML; 252 }, 253 254 init(data, accessibility) {}, 255 256 createMainContent(content) { 257 return ` 258 <div class="exe-text-activity"> 259 <div>${content}</div> 260 </div>`; 261 }, 262 263 createInfoHTML( 264 durationText, 265 durationValue, 266 participantsText, 267 participantsValue 268 ) { 269 return ` 270 <dl> 271 <div class="inline"><dt><span title="${durationText}">${durationText}</span></dt><dd>${durationValue}</dd></div> 272 <div class="inline"><dt><span title="${participantsText}">${participantsText}</span></dt><dd>${participantsValue}</dd></div> 273 </dl>`; 274 }, 275 276 createFeedbackHTML(title, content) { 277 return `
278 <div class="iDevice_buttons feedback-button js-required"> 279 <input type="button" class="feedbacktooglebutton" value="${title}"> 280 </div> 281 <div class="feedback js-feedback js-hidden">${content}</div>`; 282 }, 283};
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.