// =========================================================================== // eXe // Copyright 2004-2005, University of Auckland // Copyright 2004-2008 eXe Project, http://eXeLearning.org/ // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // =========================================================================== // This module is for the common Javascript used in all webpages. // Called upon loading the page this function clears the hidden // action and object fields so they can be used by submitLink var objBrowse = navigator.appName; // An array of js strings to evaluate on document load var onLoadHandlers = [clearHidden, window.parent.enableButtons]; var beforeSubmitHandlers = new Array(); // Called on document load function onLoadHandler() { runFuncArray(onLoadHandlers) } curr_edits_math_num = 1 // for unique mimetex images from exemath. will reset to #1 w/ each new edit, // but will create unique math# within each edit session to the previews dir. // Strings to be translated SELECT_AN_IMAGE = "Select an image"; IMAGE_FILES = "Image Files (.jpg, .jpeg, .png, .gif)"; JPEG_FILES = "JPEG Files (.jpg, .jpeg)"; SELECT_A_FILE = "Select a file"; FLASH_MOVIE = "Flash Movie (.flv)"; FLASH_OBJECT = "Flash Object (.swf)"; SELECT_AN_MP3_FILE = "Select an mp3 file"; MP3_AUDIO = "MP3 Audio (.mp3)"; SHOCKWAVE_FILES = "Shockwave Director Files (.dcr)" QUICKTIME_FILES = "Quicktime Files (.mov, .qt, .mpg, .mp3, .mp4, .mpeg)" WINDOWSMEDIA_FILES = "Windows Media Player Files (.avi, .wmv, .wm, .asf, .asx, .wmx, .wvx)" REALMEDIA_AUDIO = "RealMedia Audio Files (.rm, .ra, .ram, .mp3)" SELECT_A_PACKAGE = "Select a package"; YOUR_SCORE_IS = "Your score is "; // Calls function in an array where each 'row' of the array is in the format: // func // or // [func, arg] function runFuncArray(handlers) { for (var i=0; i < handlers.length; i++) { var row = handlers[i] if (typeof row=="function") row() else { // row[0] is a function, row[1] are its args row[0].apply(this, row[1]); } } } // Asks the user for an image, returns the path or an empty string function askUserForImage(multiple) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); if (multiple) { var mode = nsIFilePicker.modeOpenMultiple; } else { var mode = nsIFilePicker.modeOpen; } fp.init(window, SELECT_AN_IMAGE, mode); fp.appendFilter(IMAGE_FILES, "*.jpg; *.jpeg; *.png; *.gif"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { if (multiple) { var result = new String(""); var lastFile = null; var file = null; while (fp.files.hasMoreElements()) { file = fp.files.getNext().QueryInterface(Components.interfaces.nsIFile) if (file == lastFile) { break; } lastFile = file; if (result != "") { result += "&"; } result += escape(file.path); } return result; } else { return fp.file.path; } } else { return "" } } // Asks the user for a media file, returns the path or an empty string function askUserForMedia() { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); var mode = nsIFilePicker.modeOpen; fp.init(window, SELECT_A_FILE, mode); // default filter to ALL: fp.appendFilters(nsIFilePicker.filterAll); // but also add filters for each media type supported by tinyMCE's media plugin: fp.appendFilter(FLASH_OBJECT, "*.swf"); fp.appendFilter(QUICKTIME_FILES, "*.mov; *.qt; *.mpg; *.mp3; *.mp4; *.mpeg"); //fp.appendFilter(SHOCKWAVE_FILES, "*.dcr"); fp.appendFilter(WINDOWSMEDIA_FILES, "*.avi; *.wmv; *.wm; *.asf; *.asx; *.wmx; *.wvx"); fp.appendFilter(REALMEDIA_AUDIO, "*.rm; *.ra; *.ram; *.mp3"); var res = fp.show(); if (res == nsIFilePicker.returnOK) { return fp.file.path; } else { return "" } } // Called by the user to provide an image or flash file name to add to the package function addImage(elementId) { var imagePath = askUserForImage() if (imagePath != "") { var image = document.getElementById('img'+elementId); image.removeAttribute('width'); image.removeAttribute('height'); var path = document.getElementById('path'+elementId); path.value = imagePath; image.src = 'file://'+imagePath; var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) { theForm = document.getElementById('contentForm') } theForm.action.value = "addImage" theForm.object.value = elementId theForm.submit() } } // Called by the user to provide an image feedback to add to a case study idevice question function addFeedbackImage(elementId) { var imagePath = askUserForImage() if (imagePath != "") { var image = document.getElementById('img'+elementId); image.removeAttribute('width'); image.removeAttribute('height'); var path = document.getElementById('path'+elementId); path.value = imagePath; image.src = 'file://'+imagePath; var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) { theForm = document.getElementById('contentForm') } theForm.action.value = "addImage" theForm.object.value = elementId var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); width.value = "100" height.value = "" theForm.submit() changeImageWidth(elementId) theForm.submit() } } // Called by the user to provide an image or flash file name to add to the package function addJpgImage(elementId) { var imagePath = askUserForJpgImage() if (imagePath != "") { var image = document.getElementById('img'+elementId); image.removeAttribute('width'); image.removeAttribute('height'); var path = document.getElementById('path'+elementId); path.value = imagePath; image.src = 'file://'+imagePath; var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) theForm = document.getElementById('contentForm') theForm.action.value = "addJpgImage" theForm.object.value = elementId theForm.submit() } } // Asks the user for a jpg image, returns the path or an empty string function askUserForJpgImage(multiple) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); if (multiple) { var mode = nsIFilePicker.modeOpenMultiple; } else { var mode = nsIFilePicker.modeOpen; } fp.init(window, SELECT_AN_IMAGE, mode); fp.appendFilter(JPEG_FILES, "*.jpg; *.jpeg"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { if (multiple) { var result = new String(""); var lastFile = null; var file = null; while (fp.files.hasMoreElements()) { file = fp.files.getNext().QueryInterface(Components.interfaces.nsIFile) if (file == lastFile) { break; } lastFile = file; if (result != "") { result += "&"; } result += escape(file.path); } return result; } else { return fp.file.path; } } else { return "" } } // Called by the user to provide one or more image files name to add to the package function addGalleryImage(galleryId) { var imagePath = askUserForImage(true); if (imagePath != "") { // Save the change submitLink("gallery.addImage."+imagePath, galleryId, true); } } // Called by the user to change an existing gallery image function changeGalleryImage(galleryId, imageId) { var imagePath = askUserForImage(false) if (imagePath != "") { // Save the change submitLink("gallery.changeImage."+imageId+"."+imagePath, galleryId, true); } } // Called by the tinyMCE (as per the user's request) to provide an // image file name to add to the package's field and idevice function chooseImage_viaTinyMCE(field_name, url, type, win) { var local_imagePath = "" // ask user for image or media, depending on type requested: if (type == "image") { local_imagePath = askUserForImage(false); } else if (type == "media") { local_imagePath = askUserForMedia(); } else if (type == "file") { // new for advlink plugin, to link ANY resource into text: // re-use the Media browser, which defaults to All file types (*.*) local_imagePath = askUserForMedia(); } else if (type == "image2insert" || type == "media2insert" || type == "file2insert") { if (type == "file2insert" && url.indexOf('#') >= 0) { // looks like a link to an internal anchor due to the #, so do // not proceed any further, since there is no more action necessary: return; // UNLESS this causes problems with embedding real filenames w/ #!! // But this will only be for links or filenames typed by hand; // those textlink URLs inserted via its file browser will use // type=file rather than type=file2insert } // new direct insert capabilities, no file browser needed. // just copy the passed-in URL directly, no browser necessary: local_imagePath = url; } win.focus(); // if the user hits CANCEL, then bail "immediately", // i.e., after bringing the tinyMCE image dialog back into focus, above. if (local_imagePath == "") { return; } netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); // UNescape, to remove the %20's for spaces, etc.: var unescaped_local_imagePath = unescape(local_imagePath); var oldImageStr = new String(unescaped_local_imagePath); // and replace path delimiters (':', '\', or '/') or '%', ' ', or '&' // with '_': var RegExp1 = /[\ \\\/\:\%\&]/g; var ReplaceStr1 = new String("_"); var newImageStr = oldImageStr.replace(RegExp1, ReplaceStr1); // For simplicity across various file encoding schemes, etc., // just ensure that the TinyMCE media window also gets a URI safe link, // for doing its showPreview(): early_preview_imageName = encodeURIComponent(newImageStr); // and one more escaping of the '%'s to '_'s, to flatten for simplicity: preview_imageName = early_preview_imageName.replace(RegExp1, ReplaceStr1); full_previewImage_url = "/previews/"+preview_imageName; // pass the file information on to the server, // to copy it into the server's "previews" directory: window.parent.nevow_clientToServerEvent('previewTinyMCEimage', this, '', win, win.name, field_name, unescaped_local_imagePath, preview_imageName) // first, clear out any old value in the tinyMCE image filename field: win.document.forms[0].elements[field_name].value = ""; // PreviewImage is only available for images: if (type == "image") { win.showPreviewImage(" "); } else if (type == "media") { win.generatePreview(" "); } // set the tinyMCE image filename field: win.document.forms[0].elements[field_name].value = full_previewImage_url; // then force its onchange event: // PreviewImage is only available for images: if (type == "image") { win.showPreviewImage(full_previewImage_url); } else if (type == "media") { win.generatePreview(full_previewImage_url); } // this onchange works, but it's dirty because it is hardcoding the // onChange=".." event of that field, and if that were to ever change // in tinyMCE, then this would be out of sync. // and finally, be sure to update the tinyMCE window's image data: if (win.getImageData) { win.getImageData(); } else { if (window.tinyMCE.getImageData) { window.tinyMCE.getImageData(); } } } // Called by the tinyMCE (as per the user's request) to generate an // image file of the specified math (LaTeX source, compiled by mimetex) // to add to the package's field and idevice function makeMathImage_viaTinyMCE(field_name, src_latex, font_size, type, win) { var local_imagePath = "" if (src_latex == "") { return; } // to help unique-ify each previewed math image: var preview_basename = "eXe_LaTeX_math_"+curr_edits_math_num var preview_math_imagefile = preview_basename+".gif" // Simplify the subsequent file-lookup process, by just appending // the ".tex" to the full image name, as such: var preview_math_srcfile = preview_math_imagefile+".tex" curr_edits_math_num += 1 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); // pass the file information on to the server, // to generate the image into the server's "previews" directory: window.parent.nevow_clientToServerEvent('generateTinyMCEmath', this, '', win, win.name, field_name, src_latex, font_size, preview_math_imagefile, preview_math_srcfile) // once the image has been generated, it SHOULD be sitting here: var full_preview_url = "/previews/"+preview_math_imagefile; win.focus(); // clear out any old value in the tinyMCE image filename field: win.document.forms[0].elements[field_name].value = ""; // PreviewImage is only available for images: if (type == "image") { win.showPreviewImage(" "); } // the above two commands are the only way to really // ensure that we can trigger the onchange event below: // set the tinyMCE image filename field: win.document.forms[0].elements[field_name].value = full_preview_url; // then force its onchange event: // PreviewImage is only available for images: if (type == "image") { win.showPreviewImage(full_preview_url); } } function magnifierImageChanged(event) { var id = event.currentTarget.getAttribute('id'); var elementId = id.substring(3, id.length); var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); image.removeAttribute('height'); if (image.width > 700){ image.width = 600 } if (image.width <= 700 && image.width > 300) image.width = image.width * 0.7 if (image.height > 270){ width.value = image.width + 84 }else{ width.value = image.width + 144 } height.value = image.height + 24 if (width.value < 180) width.value = 180 if (height.value < 160) height.value = 160 } function imageChanged(event) { var id = event.currentTarget.getAttribute('id'); var elementId = id.substring(3, id.length); var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); width.value = image.width; height.value = image.height; } function changeImageWidth(elementId) { var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); image.removeAttribute('height'); if (width.value) { image.width = width.value; } else if (image.hasAttribute('src')) { image.removeAttribute('width'); width.value = image.width; } else { width.value = ""; } height.value = image.height; } function changeImageHeight(elementId) { var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); image.removeAttribute('width'); if (height.value) { image.height = height.value; } else if (image.hasAttribute('src')) { image.removeAttribute('height'); height.value = image.height; } else { height.value = ""; } width.value = image.width; } function changeMagnifierImageWidth(elementId) { var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); image.removeAttribute('height'); if (width.value) { image.width = width.value - 84; } else { image.removeAttribute('width'); } if (image.width > 600){ image.removeAttribute('height') image.width = 600; } if (image.height > 270){ width.value = image.width + 84 }else{ width.value = image.width + 144 } height.value = image.height + 24 if (width.value < 180) width.value = 180 if (height.value < 160) height.value = 160 } function changeMagnifierImageHeight(elementId) { var image = document.getElementById('img'+elementId); var width = document.getElementById('width'+elementId); var height = document.getElementById('height'+elementId); image.removeAttribute('width'); if (height.value) { image.height = height.value - 24; } else { image.removeAttribute('height'); } if (image.width > 600){ image.removeAttribute('height'); image.width = 600 } if (image.height > 270){ width.value = image.width + 84 }else{ width.value = image.width + 144 } height.value = image.height + 24 if (width.value < 180) width.value = 180 if (height.value < 160) height.value = 160 } // Called by the user to provide a flash movie file name to add to the package function addFlashMovie(blockId) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init(window, SELECT_A_FILE, nsIFilePicker.modeOpen); fp.appendFilter(FLASH_MOVIE, "*.flv"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { var path = document.getElementById('path'+blockId); path.type = 'text'; path.value = fp.file.path; } } // Called by the user to provide a flash file name to add to the package function addFlash(blockId) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init(window, SELECT_A_FILE, nsIFilePicker.modeOpen); fp.appendFilter(FLASH_OBJECT, "*.swf"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { var path = document.getElementById('path'+blockId); path.type = 'text'; path.value = fp.file.path; } } function addMp3(blockId) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init(window, SELECT_AN_MP3_FILE, nsIFilePicker.modeOpen); fp.appendFilter(MP3_AUDIO, "*.mp3"); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { var path = document.getElementById('path'+blockId); path.type = 'text'; path.value = fp.file.path; } } // Called by the user to provide a package name in order to get the user created idevices // used by idevice editor function addFile(blockId) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init(window, SELECT_A_PACKAGE, nsIFilePicker.modeOpen); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { var path = document.getElementById('path'+blockId); path.value = fp.file.path; } } function uploadFile(blockId) { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var nsIFilePicker = Components.interfaces.nsIFilePicker; var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init(window, SELECT_A_FILE, nsIFilePicker.modeOpen); fp.appendFilters(nsIFilePicker.filterAll); var res = fp.show(); if (res == nsIFilePicker.returnOK) { var path = document.getElementById('path'+blockId); path.value = fp.file.path; } var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) { // try and find the form for the authoring page theForm = document.getElementById('contentForm') } theForm.submit(); } function showMe(ident, w, h) { var elmDiv = document.getElementById('popupmessage'); hideMe(); if (!elmDiv || elmDiv.innerHTML != document.getElementById(ident).innerHTML){ elmDiv = document.createElement('div'); elmDiv.id = 'popupmessage'; elmDiv.className="popupDiv"; var xloc = (xpos+w > 740) ? Math.max(0, xpos-w-15) : xpos; elmDiv.style.cssText = 'position:absolute; left: ' + (xloc) + 'px; top: '+(ypos - h/2) + 'px; width: ' + w + 'px;'; elmDiv.innerHTML = document.getElementById(ident).innerHTML; document.body.appendChild(elmDiv); new dragElement('popupmessage'); } } function hideMe() { var elmDiv = document.getElementById('popupmessage'); if (elmDiv) { // removes the div from the document elmDiv.parentNode.removeChild(elmDiv); } } function updateCoords(e) { if (objBrowse == "Microsoft Internet Explorer") { xpos = e.offsetX; ypos = e.offsetY; } else { xpos = e.pageX; ypos = e.pageY; } } // Called upon loading the page this function clears the hidden // action and object fields so they can be used by submitLink function clearHidden() { var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) { // try and find the form for the authoring page theForm = document.getElementById('contentForm') } theForm.action.value = ""; theForm.object.value = ""; } // Sets the hidden action and object fields, then submits the // contentForm to the server function submitLink(action, object, changed) { var theForm = top["authoringIFrame1"].document.getElementById('contentForm') if (!theForm) { // try and find the form for the authoring page theForm = document.getElementById('contentForm') } theForm.action.value = action; theForm.object.value = object; theForm.isChanged.value = changed; runFuncArray(beforeSubmitHandlers) theForm.submit(); } // Check the user really really wants to do this before submitting function confirmThenSubmitLink(message, action, object, changed) { if (confirm(message)) { submitLink(action, object, changed); } } function getFeedback(optionId, optionsNum, ideviceId, mode) { for (i = 0; i< optionsNum; i++) { if (mode == "multi") id = "sa" + i + "b" +ideviceId else id = "s" + i + "b" +ideviceId if(i == optionId) document.getElementById(id).style.display = "block"; else document.getElementById(id).style.display = "None"; } if (mode == 'truefalse') { document.getElementById("sfbk" + ideviceId).style.display = "block"; } } // Cloze Field Stuff ///////////////////////////////////////////////// // Constants NOT_ATTEMPTED = 0 WRONG = 1 CORRECT = 2 // Functions // Called when a learner types something into a cloze word space function onClozeChange(ele) { var ident = getClozeIds(ele)[0]; var instant = eval(document.getElementById( 'clozeFlag'+ident+'.instantMarking').value); if (instant) { checkAndMarkClozeWord(ele); // Hide the score paragraph if visible var scorePara = document.getElementById('clozeScore' + ident); scorePara.innerHTML = ""; } } // Recieves and marks answers from student function clozeSubmit(ident) { // Mark all of the words showClozeScore(ident, 1); // Hide Submit toggleElementVisible('submit'+ident); // Show Restart toggleElementVisible('restart'+ident); // Show Show Answers Button toggleElementVisible('showAnswersButton'+ident); // Show feedback toggleClozeFeedback(ident); } // Makes cloze idevice like new :) function clozeRestart(ident) { // Hide Feedback toggleClozeFeedback(ident); // Clear the answers (Also hides score) toggleClozeAnswers(ident, true); // Hide Restart toggleElementVisible('restart'+ident); // Hide Show Answers Button toggleElementVisible('showAnswersButton'+ident); // Show Submit toggleElementVisible('submit'+ident); } // Show/Hide all answers in the cloze idevice // 'clear' is an optional argument, that forces all the answers to be cleared // whether they are all finished and correct or not function toggleClozeAnswers(ident, clear){ // See if any have not been answered yet var allCorrect = true; var inputs = getCloseInputs(ident) if (!clear) { for (var i=0; i> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } } while (i < input.length); return output; } // Returns the corrected word or an empty string function checkClozeWord(ele) { var guess = ele.value; // Extract the idevice id and the input number out of the element's id var original = getClozeAnswer(ele); var answer = original; var guess = ele.value var ident = getClozeIds(ele)[0] // Read the flags for checking answers var strictMarking = eval(document.getElementById( 'clozeFlag'+ident+'.strictMarking').value); var checkCaps = eval(document.getElementById( 'clozeFlag'+ident+'.checkCaps').value); if (!checkCaps) { guess = guess.toLowerCase(); answer = original.toLowerCase(); } if (guess == answer) // You are right! return original else if (strictMarking || answer.length <= 4) // You are wrong! return ""; else { // Now use the similarity check algorythm var i = 0; var j = 0; var orders = [[answer, guess], [guess, answer]]; var maxMisses = Math.floor(answer.length / 6) + 1; var misses = 0; if (guess.length <= maxMisses) { misses = Math.abs(guess.length - answer.length); for (i = 0; i < guess.length; i++ ) { if (answer.search(guess[i]) == -1) { misses += 1; } } if (misses <= maxMisses) { return answer; } else { return ""; } } // Iterate through the different orders of checking for (i = 0; i < 2; i++) { var string1 = orders[i][0]; var string2 = orders[i][1]; while (string1) { misses = Math.floor( (Math.abs(string1.length - string2.length) + Math.abs(guess.length - answer.length)) / 2) var max = Math.min(string1.length, string2.length) for (j = 0; j < max; j++) { var a = string2.charAt(j); var b = string1.charAt(j); if (a != b) misses += 1; if (misses > maxMisses) break; } if (misses <= maxMisses) // You are right return answer; string1 = string1.substr(1); } } // You are wrong! return ""; } } // Extracts the idevice id and input id from a javascript element function getClozeIds(ele) { // Extract the idevice id and the input number out of the element's id // id is "clozeBlank%s.%s" % (idevice.id, input number) var id = ele.id.slice(10); var dotindex = id.indexOf('.') var ident = id.slice(0, dotindex) var inputId = id.slice(id.indexOf('.')+1) return [ident, inputId] } // Calculate the score for cloze idevice function showClozeScore(ident, mark) { var score = 0 var div = document.getElementById('cloze' + ident) var inputs = getCloseInputs(ident) for (var i=0; i 0) { var pluginsArrayLength = navigator.plugins.length; // for each plugin... for (pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) { // loop through all desired names and check each against the current plugin name var numFound = 0; for(namesCounter=0; namesCounter < daPlugins.length; namesCounter++) { // if desired plugin name is found in either plugin name or description if( (navigator.plugins[pluginsArrayCounter].name.indexOf(daPlugins[namesCounter]) >= 0) || (navigator.plugins[pluginsArrayCounter].description.indexOf(daPlugins[namesCounter]) >= 0) ) { // this name was found numFound++; } } // now that we have checked all the required names against this one plugin, // if the number we found matches the total number provided then we were successful if(numFound == daPlugins.length) { pluginFound = true; // if we've found the plugin, we can stop looking through at the rest of the plugins break; } } } return pluginFound; } // detectPlugin ///////////////////////////////////////////////