[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 // This file is part of Moodle - http://moodle.org/ 2 // 3 // Moodle is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, either version 3 of the License, or 6 // (at your option) any later version. 7 // 8 // Moodle is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 15 16 // Used need to debug cmi content (if you uncomment this, you must comment the definition inside SCORMapi1_3) 17 //var cmi = new Object(); 18 19 // 20 // SCORM 1.3 API Implementation 21 // 22 function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg, autocommit) { 23 24 var prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a=" + scormid + "&scoid=" + scoid + "&attempt=" + attempt + "&mode=" + viewmode + "¤torg=" + currentorg + "&sesskey=" + sesskey; 25 var datamodelurl = cfgwwwroot + "/mod/scorm/datamodel.php"; 26 var datamodelurlparams = "id=" + cmid + "&a=" + scormid + "&sesskey=" + sesskey + "&attempt=" + attempt + "&scoid=" + scoid; 27 28 // Standard Data Type Definition 29 30 // language key has to be checked for language dependent strings 31 var validLanguages = {'aa':'aa', 'ab':'ab', 'ae':'ae', 'af':'af', 'ak':'ak', 'am':'am', 'an':'an', 'ar':'ar', 'as':'as', 'av':'av', 'ay':'ay', 'az':'az', 32 'ba':'ba', 'be':'be', 'bg':'bg', 'bh':'bh', 'bi':'bi', 'bm':'bm', 'bn':'bn', 'bo':'bo', 'br':'br', 'bs':'bs', 33 'ca':'ca', 'ce':'ce', 'ch':'ch', 'co':'co', 'cr':'cr', 'cs':'cs', 'cu':'cu', 'cv':'cv', 'cy':'cy', 34 'da':'da', 'de':'de', 'dv':'dv', 'dz':'dz', 'ee':'ee', 'el':'el', 'en':'en', 'eo':'eo', 'es':'es', 'et':'et', 'eu':'eu', 35 'fa':'fa', 'ff':'ff', 'fi':'fi', 'fj':'fj', 'fo':'fo', 'fr':'fr', 'fy':'fy', 'ga':'ga', 'gd':'gd', 'gl':'gl', 'gn':'gn', 'gu':'gu', 'gv':'gv', 36 'ha':'ha', 'he':'he', 'hi':'hi', 'ho':'ho', 'hr':'hr', 'ht':'ht', 'hu':'hu', 'hy':'hy', 'hz':'hz', 37 'ia':'ia', 'id':'id', 'ie':'ie', 'ig':'ig', 'ii':'ii', 'ik':'ik', 'io':'io', 'is':'is', 'it':'it', 'iu':'iu', 38 'ja':'ja', 'jv':'jv', 'ka':'ka', 'kg':'kg', 'ki':'ki', 'kj':'kj', 'kk':'kk', 'kl':'kl', 'km':'km', 'kn':'kn', 'ko':'ko', 'kr':'kr', 'ks':'ks', 'ku':'ku', 'kv':'kv', 'kw':'kw', 'ky':'ky', 39 'la':'la', 'lb':'lb', 'lg':'lg', 'li':'li', 'ln':'ln', 'lo':'lo', 'lt':'lt', 'lu':'lu', 'lv':'lv', 40 'mg':'mg', 'mh':'mh', 'mi':'mi', 'mk':'mk', 'ml':'ml', 'mn':'mn', 'mo':'mo', 'mr':'mr', 'ms':'ms', 'mt':'mt', 'my':'my', 41 'na':'na', 'nb':'nb', 'nd':'nd', 'ne':'ne', 'ng':'ng', 'nl':'nl', 'nn':'nn', 'no':'no', 'nr':'nr', 'nv':'nv', 'ny':'ny', 42 'oc':'oc', 'oj':'oj', 'om':'om', 'or':'or', 'os':'os', 'pa':'pa', 'pi':'pi', 'pl':'pl', 'ps':'ps', 'pt':'pt', 43 'qu':'qu', 'rm':'rm', 'rn':'rn', 'ro':'ro', 'ru':'ru', 'rw':'rw', 44 'sa':'sa', 'sc':'sc', 'sd':'sd', 'se':'se', 'sg':'sg', 'sh':'sh', 'si':'si', 'sk':'sk', 'sl':'sl', 'sm':'sm', 'sn':'sn', 'so':'so', 'sq':'sq', 'sr':'sr', 'ss':'ss', 'st':'st', 'su':'su', 'sv':'sv', 'sw':'sw', 45 'ta':'ta', 'te':'te', 'tg':'tg', 'th':'th', 'ti':'ti', 'tk':'tk', 'tl':'tl', 'tn':'tn', 'to':'to', 'tr':'tr', 'ts':'ts', 'tt':'tt', 'tw':'tw', 'ty':'ty', 46 'ug':'ug', 'uk':'uk', 'ur':'ur', 'uz':'uz', 've':'ve', 'vi':'vi', 'vo':'vo', 47 'wa':'wa', 'wo':'wo', 'xh':'xh', 'yi':'yi', 'yo':'yo', 'za':'za', 'zh':'zh', 'zu':'zu', 48 'aar':'aar', 'abk':'abk', 'ave':'ave', 'afr':'afr', 'aka':'aka', 'amh':'amh', 'arg':'arg', 'ara':'ara', 'asm':'asm', 'ava':'ava', 'aym':'aym', 'aze':'aze', 49 'bak':'bak', 'bel':'bel', 'bul':'bul', 'bih':'bih', 'bis':'bis', 'bam':'bam', 'ben':'ben', 'tib':'tib', 'bod':'bod', 'bre':'bre', 'bos':'bos', 50 'cat':'cat', 'che':'che', 'cha':'cha', 'cos':'cos', 'cre':'cre', 'cze':'cze', 'ces':'ces', 'chu':'chu', 'chv':'chv', 'wel':'wel', 'cym':'cym', 51 'dan':'dan', 'ger':'ger', 'deu':'deu', 'div':'div', 'dzo':'dzo', 'ewe':'ewe', 'gre':'gre', 'ell':'ell', 'eng':'eng', 'epo':'epo', 'spa':'spa', 'est':'est', 'baq':'baq', 'eus':'eus', 'per':'per', 52 'fas':'fas', 'ful':'ful', 'fin':'fin', 'fij':'fij', 'fao':'fao', 'fre':'fre', 'fra':'fra', 'fry':'fry', 'gle':'gle', 'gla':'gla', 'glg':'glg', 'grn':'grn', 'guj':'guj', 'glv':'glv', 53 'hau':'hau', 'heb':'heb', 'hin':'hin', 'hmo':'hmo', 'hrv':'hrv', 'hat':'hat', 'hun':'hun', 'arm':'arm', 'hye':'hye', 'her':'her', 54 'ina':'ina', 'ind':'ind', 'ile':'ile', 'ibo':'ibo', 'iii':'iii', 'ipk':'ipk', 'ido':'ido', 'ice':'ice', 'isl':'isl', 'ita':'ita', 'iku':'iku', 55 'jpn':'jpn', 'jav':'jav', 'geo':'geo', 'kat':'kat', 'kon':'kon', 'kik':'kik', 'kua':'kua', 'kaz':'kaz', 'kal':'kal', 'khm':'khm', 'kan':'kan', 'kor':'kor', 'kau':'kau', 'kas':'kas', 'kur':'kur', 'kom':'kom', 'cor':'cor', 'kir':'kir', 56 'lat':'lat', 'ltz':'ltz', 'lug':'lug', 'lim':'lim', 'lin':'lin', 'lao':'lao', 'lit':'lit', 'lub':'lub', 'lav':'lav', 57 'mlg':'mlg', 'mah':'mah', 'mao':'mao', 'mri':'mri', 'mac':'mac', 'mkd':'mkd', 'mal':'mal', 'mon':'mon', 'mol':'mol', 'mar':'mar', 'may':'may', 'msa':'msa', 'mlt':'mlt', 'bur':'bur', 'mya':'mya', 58 'nau':'nau', 'nob':'nob', 'nde':'nde', 'nep':'nep', 'ndo':'ndo', 'dut':'dut', 'nld':'nld', 'nno':'nno', 'nor':'nor', 'nbl':'nbl', 'nav':'nav', 'nya':'nya', 59 'oci':'oci', 'oji':'oji', 'orm':'orm', 'ori':'ori', 'oss':'oss', 'pan':'pan', 'pli':'pli', 'pol':'pol', 'pus':'pus', 'por':'por', 'que':'que', 60 'roh':'roh', 'run':'run', 'rum':'rum', 'ron':'ron', 'rus':'rus', 'kin':'kin', 'san':'san', 'srd':'srd', 'snd':'snd', 'sme':'sme', 'sag':'sag', 'slo':'slo', 'sin':'sin', 'slk':'slk', 'slv':'slv', 'smo':'smo', 'sna':'sna', 'som':'som', 'alb':'alb', 'sqi':'sqi', 'srp':'srp', 'ssw':'ssw', 'sot':'sot', 'sun':'sun', 'swe':'swe', 'swa':'swa', 61 'tam':'tam', 'tel':'tel', 'tgk':'tgk', 'tha':'tha', 'tir':'tir', 'tuk':'tuk', 'tgl':'tgl', 'tsn':'tsn', 'ton':'ton', 'tur':'tur', 'tso':'tso', 'tat':'tat', 'twi':'twi', 'tah':'tah', 62 'uig':'uig', 'ukr':'ukr', 'urd':'urd', 'uzb':'uzb', 'ven':'ven', 'vie':'vie', 'vol':'vol', 'wln':'wln', 'wol':'wol', 'xho':'xho', 'yid':'yid', 'yor':'yor', 'zha':'zha', 'chi':'chi', 'zho':'zho', 'zul':'zul'}; 63 64 var CMIString200 = '^[\\u0000-\\uFFFF]{0,200}$'; 65 var CMIString250 = '^[\\u0000-\\uFFFF]{0,250}$'; 66 var CMIString1000 = '^[\\u0000-\\uFFFF]{0,1000}$'; 67 var CMIString4000 = '^[\\u0000-\\uFFFF]{0,4000}$'; 68 var CMIString64000 = '^[\\u0000-\\uFFFF]{0,64000}$'; 69 var CMILang = '^([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?$|^$'; 70 var CMILangString250 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,250}$)?'; 71 var CMILangcr = '^((\{lang=([a-zA-Z]{2,3}|i|x)?(\-[a-zA-Z0-9\-]{2,8})?\}))(.*?)$'; 72 var CMILangString250cr = '^((\{lang=([a-zA-Z]{2,3}|i|x)?(\-[a-zA-Z0-9\-]{2,8})?\})?(.{0,250})?)?$'; 73 var CMILangString4000 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,4000}$)?'; 74 var CMITime = '^(19[7-9]{1}[0-9]{1}|20[0-2]{1}[0-9]{1}|203[0-8]{1})((-(0[1-9]{1}|1[0-2]{1}))((-(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1}))(T([0-1]{1}[0-9]{1}|2[0-3]{1})((:[0-5]{1}[0-9]{1})((:[0-5]{1}[0-9]{1})((\\.[0-9]{1,2})((Z|([+|-]([0-1]{1}[0-9]{1}|2[0-3]{1})))(:[0-5]{1}[0-9]{1})?)?)?)?)?)?)?)?$'; 75 var CMITimespan = '^P(\\d+Y)?(\\d+M)?(\\d+D)?(T(((\\d+H)(\\d+M)?(\\d+(\.\\d{1,2})?S)?)|((\\d+M)(\\d+(\.\\d{1,2})?S)?)|((\\d+(\.\\d{1,2})?S))))?$'; 76 var CMIInteger = '^\\d+$'; 77 var CMISInteger = '^-?([0-9]+)$'; 78 var CMIDecimal = '^-?([0-9]{1,5})(\\.[0-9]{1,18})?$'; 79 var CMIIdentifier = '^\\S{1,250}[a-zA-Z0-9]$'; 80 var CMIShortIdentifier = '^[\\w\.]{1,250}$'; 81 var CMILongIdentifier = '^(?:(?!urn:)\\S{1,4000}|urn:[A-Za-z0-9-]{1,31}:\\S{1,4000})$'; 82 var CMIFeedback = '^.*$'; // This must be redefined 83 var CMIIndex = '[._](\\d+).'; 84 var CMIIndexStore = '.N(\\d+).'; 85 // Vocabulary Data Type Definition 86 var CMICStatus = '^completed$|^incomplete$|^not attempted$|^unknown$'; 87 var CMISStatus = '^passed$|^failed$|^unknown$'; 88 var CMIExit = '^time-out$|^suspend$|^logout$|^normal$|^$'; 89 var CMIType = '^true-false$|^choice$|^(long-)?fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$|^other$'; 90 var CMIResult = '^correct$|^incorrect$|^unanticipated$|^neutral$|^-?([0-9]{1,4})(\\.[0-9]{1,18})?$'; 91 var NAVEvent = '^previous$|^continue$|^exit$|^exitAll$|^abandon$|^abandonAll$|^suspendAll$|^\{target=\\S{0,200}[a-zA-Z0-9]\}choice|jump$'; 92 var NAVBoolean = '^unknown$|^true$|^false$'; 93 var NAVTarget = '^previous$|^continue$|^choice.{target=\\S{0,200}[a-zA-Z0-9]}$' 94 // Children lists 95 var cmi_children = '_version,comments_from_learner,comments_from_lms,completion_status,credit,entry,exit,interactions,launch_data,learner_id,learner_name,learner_preference,location,max_time_allowed,mode,objectives,progress_measure,scaled_passing_score,score,session_time,success_status,suspend_data,time_limit_action,total_time'; 96 var comments_children = 'comment,timestamp,location'; 97 var score_children = 'max,raw,scaled,min'; 98 var objectives_children = 'progress_measure,completion_status,success_status,description,score,id'; 99 var correct_responses_children = 'pattern'; 100 var student_data_children = 'mastery_score,max_time_allowed,time_limit_action'; 101 var student_preference_children = 'audio_level,audio_captioning,delivery_speed,language'; 102 var interactions_children = 'id,type,objectives,timestamp,correct_responses,weighting,learner_response,result,latency,description'; 103 // Data ranges 104 var scaled_range = '-1#1'; 105 var audio_range = '0#*'; 106 var speed_range = '0#*'; 107 var text_range = '-1#1'; 108 var progress_range = '0#1'; 109 var learner_response = { 110 'true-false':{'format':'^true$|^false$', 'max':1, 'delimiter':'', 'unique':false}, 111 'choice':{'format':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'unique':true}, 112 'fill-in':{'format':CMILangString250, 'max':10, 'delimiter':'[,]', 'unique':false}, 113 'long-fill-in':{'format':CMILangString4000, 'max':1, 'delimiter':'', 'unique':false}, 114 'matching':{'format':CMIShortIdentifier, 'format2':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false}, 115 'performance':{'format':'^$|' + CMIShortIdentifier, 'format2':CMIDecimal + '|^$|' + CMIShortIdentifier, 'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false}, 116 'sequencing':{'format':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'unique':false}, 117 'likert':{'format':CMIShortIdentifier, 'max':1, 'delimiter':'', 'unique':false}, 118 'numeric':{'format':CMIDecimal, 'max':1, 'delimiter':'', 'unique':false}, 119 'other':{'format':CMIString4000, 'max':1, 'delimiter':'', 'unique':false} 120 } 121 122 var correct_responses = { 123 'true-false':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 124 'format':'^true$|^false$', 125 'limit':1}, 126 'choice':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':true, 'duplicate':false, 127 'format':CMIShortIdentifier}, 128 // 'fill-in':{'pre':'^(((\{case_matters=(true|false)\})(\{order_matters=(true|false)\})?)|((\{order_matters=(true|false)\})(\{case_matters=(true|false)\})?))(.*?)$', 129 'fill-in':{'pre':'', 130 'max':10, 'delimiter':'[,]', 'unique':false, 'duplicate':false, 131 'format':CMILangString250cr}, 132 'long-fill-in':{'pre':'^(\{case_matters=(true|false)\})?', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':true, 133 'format':CMILangString4000}, 134 'matching':{'pre':'', 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':false, 135 'format':CMIShortIdentifier, 'format2':CMIShortIdentifier}, 136 'performance':{'pre':'^(\{order_matters=(true|false)\})?', 137 'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':false, 138 'format':'^$|' + CMIShortIdentifier, 'format2':CMIDecimal + '|^$|' + CMIShortIdentifier}, 139 'sequencing':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':false, 'duplicate':false, 140 'format':CMIShortIdentifier}, 141 'likert':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 142 'format':CMIShortIdentifier, 143 'limit':1}, 144 'numeric':{'pre':'', 'max':2, 'delimiter':'[:]', 'unique':false, 'duplicate':false, 145 'format':CMIDecimal, 146 'limit':1}, 147 'other':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 148 'format':CMIString4000, 149 'limit':1} 150 } 151 152 // The SCORM 1.3 data model 153 // Set up data model for each sco 154 var datamodel = {}; 155 for(scoid in def){ 156 datamodel[scoid] = { 157 'cmi._children':{'defaultvalue':cmi_children, 'mod':'r'}, 158 'cmi._version':{'defaultvalue':'1.0', 'mod':'r'}, 159 'cmi.comments_from_learner._children':{'defaultvalue':comments_children, 'mod':'r'}, 160 'cmi.comments_from_learner._count':{'mod':'r', 'defaultvalue':'0'}, 161 'cmi.comments_from_learner.n.comment':{'format':CMILangString4000, 'mod':'rw'}, 162 'cmi.comments_from_learner.n.location':{'format':CMIString250, 'mod':'rw'}, 163 'cmi.comments_from_learner.n.timestamp':{'format':CMITime, 'mod':'rw'}, 164 'cmi.comments_from_lms._children':{'defaultvalue':comments_children, 'mod':'r'}, 165 'cmi.comments_from_lms._count':{'mod':'r', 'defaultvalue':'0'}, 166 'cmi.comments_from_lms.n.comment':{'format':CMILangString4000, 'mod':'r'}, 167 'cmi.comments_from_lms.n.location':{'format':CMIString250, 'mod':'r'}, 168 'cmi.comments_from_lms.n.timestamp':{'format':CMITime, 'mod':'r'}, 169 'cmi.completion_status':{'defaultvalue':def[scoid]['cmi.completion_status'], 'format':CMICStatus, 'mod':'rw'}, 170 'cmi.completion_threshold':{'defaultvalue':def[scoid]['cmi.completion_threshold'], 'mod':'r'}, 171 'cmi.credit':{'defaultvalue':def[scoid]['cmi.credit'], 'mod':'r'}, 172 'cmi.entry':{'defaultvalue':def[scoid]['cmi.entry'], 'mod':'r'}, 173 'cmi.exit':{'defaultvalue':def[scoid]['cmi.exit'], 'format':CMIExit, 'mod':'w'}, 174 'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r'}, 175 'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0'}, 176 'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 177 'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'rw'}, 178 'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0'}, 179 'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 180 'cmi.interactions.n.timestamp':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw'}, 181 'cmi.interactions.n.correct_responses._count':{'defaultvalue':'0', 'pattern':CMIIndex, 'mod':'r'}, 182 'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'}, 183 'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 184 'cmi.interactions.n.learner_response':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'}, 185 'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'}, 186 'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'}, 187 'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'}, 188 'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.launch_data'], 'mod':'r'}, 189 'cmi.learner_id':{'defaultvalue':def[scoid]['cmi.learner_id'], 'mod':'r'}, 190 'cmi.learner_name':{'defaultvalue':def[scoid]['cmi.learner_name'], 'mod':'r'}, 191 'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'}, 192 'cmi.learner_preference.audio_level':{'defaultvalue':def[scoid]['cmi.learner_preference.audio_level'], 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'}, 193 'cmi.learner_preference.language':{'defaultvalue':def[scoid]['cmi.learner_preference.language'], 'format':CMILang, 'mod':'rw'}, 194 'cmi.learner_preference.delivery_speed':{'defaultvalue':def[scoid]['cmi.learner_preference.delivery_speed'], 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'}, 195 'cmi.learner_preference.audio_captioning':{'defaultvalue':def[scoid]['cmi.learner_preference.audio_captioning'], 'format':CMISInteger, 'range':text_range, 'mod':'rw'}, 196 'cmi.location':{'defaultvalue':def[scoid]['cmi.location'], 'format':CMIString1000, 'mod':'rw'}, 197 'cmi.max_time_allowed':{'defaultvalue':def[scoid]['cmi.max_time_allowed'], 'mod':'r'}, 198 'cmi.mode':{'defaultvalue':def[scoid]['cmi.mode'], 'mod':'r'}, 199 'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r'}, 200 'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0'}, 201 'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 202 'cmi.objectives.n.score._children':{'defaultvalue':score_children, 'pattern':CMIIndex, 'mod':'r'}, 203 'cmi.objectives.n.score.scaled':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'}, 204 'cmi.objectives.n.score.raw':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 205 'cmi.objectives.n.score.min':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 206 'cmi.objectives.n.score.max':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 207 'cmi.objectives.n.success_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMISStatus, 'mod':'rw'}, 208 'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'}, 209 'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'}, 210 'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'}, 211 'cmi.progress_measure':{'defaultvalue':def[scoid]['cmi.progress_measure'], 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'}, 212 'cmi.scaled_passing_score':{'defaultvalue':def[scoid]['cmi.scaled_passing_score'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'}, 213 'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'}, 214 'cmi.score.scaled':{'defaultvalue':def[scoid]['cmi.score.scaled'], 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'}, 215 'cmi.score.raw':{'defaultvalue':def[scoid]['cmi.score.raw'], 'format':CMIDecimal, 'mod':'rw'}, 216 'cmi.score.min':{'defaultvalue':def[scoid]['cmi.score.min'], 'format':CMIDecimal, 'mod':'rw'}, 217 'cmi.score.max':{'defaultvalue':def[scoid]['cmi.score.max'], 'format':CMIDecimal, 'mod':'rw'}, 218 'cmi.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'PT0H0M0S'}, 219 'cmi.success_status':{'defaultvalue':def[scoid]['cmi.success_status'], 'format':CMISStatus, 'mod':'rw'}, 220 'cmi.suspend_data':{'defaultvalue':def[scoid]['cmi.suspend_data'], 'format':CMIString64000, 'mod':'rw'}, 221 'cmi.time_limit_action':{'defaultvalue':def[scoid]['cmi.time_limit_action'], 'mod':'r'}, 222 'cmi.total_time':{'defaultvalue':def[scoid]['cmi.total_time'], 'mod':'r'}, 223 'adl.nav.request':{'defaultvalue':'_none_', 'format':NAVEvent, 'mod':'rw'} 224 }; 225 } 226 227 var cmi, adl; 228 function initdatamodel(scoid){ 229 230 prerequrl = cfgwwwroot + "/mod/scorm/prereqs.php?a=" + scormid + "&scoid=" + scoid + "&attempt=" + attempt + "&mode=" + viewmode + "¤torg=" + currentorg + "&sesskey=" + sesskey; 231 datamodelurlparams = "id=" + cmid + "&a=" + scormid + "&sesskey=" + sesskey + "&attempt=" + attempt + "&scoid=" + scoid; 232 233 // 234 // Datamodel inizialization 235 // 236 cmi = new Object(); 237 cmi.comments_from_learner = new Object(); 238 cmi.comments_from_learner._count = 0; 239 cmi.comments_from_lms = new Object(); 240 cmi.comments_from_lms._count = 0; 241 cmi.interactions = new Object(); 242 cmi.interactions._count = 0; 243 cmi.learner_preference = new Object(); 244 cmi.objectives = new Object(); 245 cmi.objectives._count = 0; 246 cmi.score = new Object(); 247 248 // Navigation Object 249 adl = new Object(); 250 adl.nav = new Object(); 251 adl.nav.request_valid = new Array(); 252 253 for (element in datamodel[scoid]) { 254 if (element.match(/\.n\./) == null) { 255 if ((typeof eval('datamodel["' + scoid + '"]["' + element + '"].defaultvalue')) != 'undefined') { 256 eval(element + ' = datamodel["' + scoid + '"]["' + element + '"].defaultvalue;'); 257 } else { 258 eval(element + ' = "";'); 259 } 260 } 261 } 262 263 eval(cmiobj[scoid]); 264 eval(cmiint[scoid]); 265 eval(cmicommentsuser[scoid]); 266 eval(cmicommentslms[scoid]); 267 268 if (cmi.completion_status == '') { 269 cmi.completion_status = 'not attempted'; 270 } 271 } 272 273 // 274 // API Methods definition 275 // 276 var Initialized = false; 277 var Terminated = false; 278 var diagnostic = ""; 279 var errorCode = "0"; 280 281 function Initialize (param) { 282 scoid = scorm_current_node ? scorm_current_node.scoid : scoid; 283 initdatamodel(scoid); 284 285 errorCode = "0"; 286 if (param == "") { 287 if ((!Initialized) && (!Terminated)) { 288 Initialized = true; 289 errorCode = "0"; 290 if (scormdebugging) { 291 LogAPICall("Initialize", param, "", errorCode); 292 } 293 return "true"; 294 } else { 295 if (Initialized) { 296 errorCode = "103"; 297 } else { 298 errorCode = "104"; 299 } 300 } 301 } else { 302 errorCode = "201"; 303 } 304 if (scormdebugging) { 305 LogAPICall("Initialize", param, "", errorCode); 306 } 307 return "false"; 308 } 309 310 function Terminate (param) { 311 errorCode = "0"; 312 if (param == "") { 313 if ((Initialized) && (!Terminated)) { 314 var AJAXResult = StoreData(cmi,true); 315 if (scormdebugging) { 316 LogAPICall("Terminate", "AJAXResult", AJAXResult, 0); 317 } 318 result = ('true' == AJAXResult) ? 'true' : 'false'; 319 errorCode = ('true' == result) ? '0' : '101'; // General exception for any AJAX fault. 320 if (scormdebugging) { 321 LogAPICall("Terminate", "result", result, errorCode); 322 } 323 if ('true' == result) { 324 Initialized = false; 325 Terminated = true; 326 if (adl.nav.request != '_none_') { 327 switch (adl.nav.request) { 328 case 'continue': 329 setTimeout('mod_scorm_launch_next_sco();',500); 330 break; 331 case 'previous': 332 setTimeout('mod_scorm_launch_prev_sco();',500); 333 break; 334 case 'choice': 335 break; 336 case 'exit': 337 break; 338 case 'exitAll': 339 break; 340 case 'abandon': 341 break; 342 case 'abandonAll': 343 break; 344 } 345 } else { 346 if (scormauto == 1) { 347 setTimeout('mod_scorm_launch_next_sco();',500); 348 } 349 } 350 // trigger TOC update 351 var callback = M.mod_scorm.connectPrereqCallback; 352 YUI().use('io-base', function(Y) { 353 Y.on('io:complete', callback.success, Y); 354 Y.io(prerequrl); 355 }); 356 } else { 357 diagnostic = "Failure calling the Terminate remote callback: the server replied with HTTP Status " + AJAXResult; 358 } 359 return result; 360 } else { 361 if (Terminated) { 362 errorCode = "113"; 363 } else { 364 errorCode = "112"; 365 } 366 } 367 } else { 368 errorCode = "201"; 369 } 370 if (scormdebugging) { 371 LogAPICall("Terminate", param, "", errorCode); 372 } 373 return "false"; 374 } 375 376 function GetValue (element) { 377 errorCode = "0"; 378 diagnostic = ""; 379 if ((Initialized) && (!Terminated)) { 380 if (element != "") { 381 var expression = new RegExp(CMIIndex,'g'); 382 var elementmodel = String(element).replace(expression,'.n.'); 383 if ((typeof eval('datamodel["' + scoid + '"]["' + elementmodel + '"]')) != "undefined") { 384 if (eval('datamodel["' + scoid + '"]["' + elementmodel + '"].mod') != 'w') { 385 386 element = String(element).replace(/\.(\d+)\./, ".N$1."); 387 element = element.replace(/\.(\d+)\./, ".N$1."); 388 389 var elementIndexes = element.split('.'); 390 var subelement = element.substr(0,3); 391 var i = 1; 392 while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) { 393 subelement += '.' + elementIndexes[i++]; 394 } 395 396 if (subelement == element) { 397 398 if ((typeof eval(subelement) != "undefined") && (eval(subelement) != null)) { 399 errorCode = "0"; 400 if (scormdebugging) { 401 LogAPICall("GetValue", element, eval(element), 0); 402 } 403 return eval(element); 404 } else { 405 errorCode = "403"; 406 } 407 } else { 408 errorCode = "301"; 409 } 410 } else { 411 //errorCode = eval('datamodel["' + scoid + '"]["' + elementmodel + '"].readerror'); 412 errorCode = "405"; 413 } 414 } else { 415 var childrenstr = '._children'; 416 var countstr = '._count'; 417 var parentmodel = ''; 418 if (elementmodel.substr(elementmodel.length - childrenstr.length,elementmodel.length) == childrenstr) { 419 parentmodel = elementmodel.substr(0,elementmodel.length - childrenstr.length); 420 if ((typeof eval('datamodel["' + scoid + '"]["' + parentmodel + '"]')) != "undefined") { 421 errorCode = "301"; 422 diagnostic = "Data Model Element Does Not Have Children"; 423 } else { 424 errorCode = "401"; 425 } 426 } else if (elementmodel.substr(elementmodel.length - countstr.length,elementmodel.length) == countstr) { 427 parentmodel = elementmodel.substr(0,elementmodel.length - countstr.length); 428 if ((typeof eval('datamodel["' + scoid + '"]["' + parentmodel + '"]')) != "undefined") { 429 errorCode = "301"; 430 diagnostic = "Data Model Element Cannot Have Count"; 431 } else { 432 errorCode = "401"; 433 } 434 } else { 435 parentmodel = 'adl.nav.request_valid.'; 436 if (element.substr(0,parentmodel.length) == parentmodel) { 437 if (element.substr(parentmodel.length).match(NAVTarget) == null) { 438 errorCode = "301"; 439 } else { 440 if (adl.nav.request == element.substr(parentmodel.length)) { 441 return "true"; 442 } else if (adl.nav.request == '_none_') { 443 return "unknown"; 444 } else { 445 return "false"; 446 } 447 } 448 } else { 449 errorCode = "401"; 450 } 451 } 452 } 453 } else { 454 errorCode = "301"; 455 } 456 } else { 457 if (Terminated) { 458 errorCode = "123"; 459 } else { 460 errorCode = "122"; 461 } 462 } 463 if (scormdebugging) { 464 LogAPICall("GetValue", element, "", errorCode); 465 } 466 return ""; 467 } 468 469 function SetValue (element,value) { 470 errorCode = "0"; 471 diagnostic = ""; 472 if ((Initialized) && (!Terminated)) { 473 if (element != "") { 474 var expression = new RegExp(CMIIndex,'g'); 475 var elementmodel = String(element).replace(expression,'.n.'); 476 if ((typeof eval('datamodel["' + scoid + '"]["' + elementmodel + '"]')) != "undefined") { 477 if (eval('datamodel["' + scoid + '"]["' + elementmodel + '"].mod') != 'r') { 478 if (eval('datamodel["' + scoid + '"]["' + elementmodel + '"].format') != 'CMIFeedback') { 479 expression = new RegExp(eval('datamodel["' + scoid + '"]["' + elementmodel + '"].format')); 480 } else { 481 // cmi.interactions.n.type depending format accept everything at this stage 482 expression = new RegExp(CMIFeedback); 483 } 484 value = value + ''; 485 var matches = value.match(expression); 486 if ((matches != null) && ((matches.join('').length > 0) || (value.length == 0))) { 487 // Value match dataelement format 488 489 if (element != elementmodel) { 490 //This is a dynamic datamodel element 491 492 var elementIndexes = element.split('.'); 493 var subelement = 'cmi'; 494 var parentelement = 'cmi'; 495 for (var i = 1; (i < elementIndexes.length - 1) && (errorCode == "0"); i++) { 496 var elementIndex = elementIndexes[i]; 497 if (elementIndexes[i + 1].match(/^\d+$/)) { 498 if ((parseInt(elementIndexes[i + 1]) > 0) && (elementIndexes[i + 1].charAt(0) == 0)) { 499 // Index has a leading 0 (zero), this is not a number 500 errorCode = "351"; 501 } 502 parentelement = subelement + '.' + elementIndex; 503 if ((typeof eval(parentelement) == "undefined") || (typeof eval(parentelement + '._count') == "undefined")) { 504 errorCode = "408"; 505 } else { 506 if (elementIndexes[i + 1] > eval(parentelement + '._count')) { 507 errorCode = "351"; 508 diagnostic = "Data Model Element Collection Set Out Of Order"; 509 } 510 subelement = subelement.concat('.' + elementIndex + '.N' + elementIndexes[i + 1]); 511 i++; 512 513 if (((typeof eval(subelement)) == "undefined") && (i < elementIndexes.length - 2)) { 514 errorCode = "408"; 515 } 516 } 517 } else { 518 subelement = subelement.concat('.' + elementIndex); 519 } 520 } 521 522 if (errorCode == "0") { 523 // Till now it's a real datamodel element 524 525 element = subelement.concat('.' + elementIndexes[elementIndexes.length - 1]); 526 527 if ((typeof eval(subelement)) == "undefined") { 528 switch (elementmodel) { 529 case 'cmi.objectives.n.id': 530 if (!duplicatedID(element,parentelement,value)) { 531 if (elementIndexes[elementIndexes.length - 2] == eval(parentelement + '._count')) { 532 eval(parentelement + '._count++;'); 533 eval(subelement + ' = new Object();'); 534 var subobject = eval(subelement); 535 subobject.success_status = datamodel[scoid]["cmi.objectives.n.success_status"].defaultvalue; 536 subobject.completion_status = datamodel[scoid]["cmi.objectives.n.completion_status"].defaultvalue; 537 subobject.progress_measure = datamodel[scoid]["cmi.objectives.n.progress_measure"].defaultvalue; 538 subobject.score = new Object(); 539 subobject.score._children = score_children; 540 subobject.score.scaled = datamodel[scoid]["cmi.objectives.n.score.scaled"].defaultvalue; 541 subobject.score.raw = datamodel[scoid]["cmi.objectives.n.score.raw"].defaultvalue; 542 subobject.score.min = datamodel[scoid]["cmi.objectives.n.score.min"].defaultvalue; 543 subobject.score.max = datamodel[scoid]["cmi.objectives.n.score.max"].defaultvalue; 544 } 545 } else { 546 errorCode = "351"; 547 diagnostic = "Data Model Element ID Already Exists"; 548 } 549 break; 550 case 'cmi.interactions.n.id': 551 if (elementIndexes[elementIndexes.length - 2] == eval(parentelement + '._count')) { 552 eval(parentelement + '._count++;'); 553 eval(subelement + ' = new Object();'); 554 var subobject = eval(subelement); 555 subobject.objectives = new Object(); 556 subobject.objectives._count = 0; 557 } 558 break; 559 case 'cmi.interactions.n.objectives.n.id': 560 if (typeof eval(parentelement) != "undefined") { 561 if (!duplicatedID(element,parentelement,value)) { 562 if (elementIndexes[elementIndexes.length - 2] == eval(parentelement + '._count')) { 563 eval(parentelement + '._count++;'); 564 eval(subelement + ' = new Object();'); 565 } 566 } else { 567 errorCode = "351"; 568 diagnostic = "Data Model Element ID Already Exists"; 569 } 570 } else { 571 errorCode = "408"; 572 } 573 break; 574 case 'cmi.interactions.n.correct_responses.n.pattern': 575 if (typeof eval(parentelement) != "undefined") { 576 // Use cmi.interactions.n.type value to check the right dataelement format 577 if (elementIndexes[elementIndexes.length - 2] == eval(parentelement + '._count')) { 578 var interactiontype = eval(String(parentelement).replace('correct_responses','type')); 579 var interactioncount = eval(parentelement + '._count'); 580 // trap duplicate values, which is not allowed for type choice 581 if (interactiontype == 'choice') { 582 for (var i = 0; (i < interactioncount) && (errorCode == "0"); i++) { 583 if (eval(parentelement + '.N' + i + '.pattern') == value) { 584 errorCode = "351"; 585 } 586 } 587 } 588 if ((typeof correct_responses[interactiontype].limit == 'undefined') || 589 (eval(parentelement + '._count') < correct_responses[interactiontype].limit)) { 590 var nodes = new Array(); 591 if (correct_responses[interactiontype].delimiter != '') { 592 nodes = value.split(correct_responses[interactiontype].delimiter); 593 } else { 594 nodes[0] = value; 595 } 596 if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) { 597 errorCode = CRcheckValueNodes (element, interactiontype, nodes, value, errorCode); 598 } else if (nodes.length > correct_responses[interactiontype].max) { 599 errorCode = "351"; 600 diagnostic = "Data Model Element Pattern Too Long"; 601 } 602 if ((errorCode == "0") && ((correct_responses[interactiontype].duplicate == false) || 603 (!duplicatedPA(element,parentelement,value))) || (errorCode == "0" && value == "")) { 604 eval(parentelement + '._count++;'); 605 eval(subelement + ' = new Object();'); 606 } else { 607 if (errorCode == "0") { 608 errorCode = "351"; 609 diagnostic = "Data Model Element Pattern Already Exists"; 610 } 611 } 612 } else { 613 errorCode = "351"; 614 diagnostic = "Data Model Element Collection Limit Reached"; 615 } 616 } else { 617 errorCode = "351"; 618 diagnostic = "Data Model Element Collection Set Out Of Order"; 619 } 620 } else { 621 errorCode = "408"; 622 } 623 break; 624 default: 625 if ((parentelement != 'cmi.objectives') && (parentelement != 'cmi.interactions') && (typeof eval(parentelement) != "undefined")) { 626 if (elementIndexes[elementIndexes.length - 2] == eval(parentelement + '._count')) { 627 eval(parentelement + '._count++;'); 628 eval(subelement + ' = new Object();'); 629 } else { 630 errorCode = "351"; 631 diagnostic = "Data Model Element Collection Set Out Of Order"; 632 } 633 } else { 634 errorCode = "408"; 635 } 636 break; 637 } 638 } else { 639 switch (elementmodel) { 640 case 'cmi.objectives.n.id': 641 if (eval(element) != value) { 642 errorCode = "351"; 643 diagnostic = "Write Once Violation"; 644 } 645 break; 646 case 'cmi.interactions.n.objectives.n.id': 647 if (duplicatedID(element,parentelement,value)) { 648 errorCode = "351"; 649 diagnostic = "Data Model Element ID Already Exists"; 650 } 651 break; 652 case 'cmi.interactions.n.type': 653 var subobject = eval(subelement); 654 subobject.correct_responses = new Object(); 655 subobject.correct_responses._count = 0; 656 break; 657 case 'cmi.interactions.n.learner_response': 658 if (typeof eval(subelement + '.type') == "undefined") { 659 errorCode = "408"; 660 } else { 661 // Use cmi.interactions.n.type value to check the right dataelement format 662 interactiontype = eval(subelement + '.type'); 663 var nodes = new Array(); 664 if (learner_response[interactiontype].delimiter != '') { 665 nodes = value.split(learner_response[interactiontype].delimiter); 666 } else { 667 nodes[0] = value; 668 } 669 if ((nodes.length > 0) && (nodes.length <= learner_response[interactiontype].max)) { 670 expression = new RegExp(learner_response[interactiontype].format); 671 for (var i = 0; (i < nodes.length) && (errorCode == "0"); i++) { 672 if (typeof learner_response[interactiontype].delimiter2 != 'undefined') { 673 values = nodes[i].split(learner_response[interactiontype].delimiter2); 674 if (values.length == 2) { 675 matches = values[0].match(expression); 676 if (matches == null) { 677 errorCode = "406"; 678 } else { 679 var expression2 = new RegExp(learner_response[interactiontype].format2); 680 matches = values[1].match(expression2); 681 if (matches == null) { 682 errorCode = "406"; 683 } 684 } 685 } else { 686 errorCode = "406"; 687 } 688 } else { 689 matches = nodes[i].match(expression); 690 if (matches == null) { 691 errorCode = "406"; 692 } else { 693 if ((nodes[i] != '') && (learner_response[interactiontype].unique)) { 694 for (var j = 0; (j < i) && (errorCode == "0"); j++) { 695 if (nodes[i] == nodes[j]) { 696 errorCode = "406"; 697 } 698 } 699 } 700 } 701 } 702 } 703 } else if (nodes.length > learner_response[interactiontype].max) { 704 errorCode = "351"; 705 diagnostic = "Data Model Element Pattern Too Long"; 706 } 707 } 708 break; 709 case 'cmi.interactions.n.correct_responses.n.pattern': 710 subel = subelement.split('.'); 711 subel1 = 'cmi.interactions.' + subel[2]; 712 713 if (typeof eval(subel1 + '.type') == "undefined") { 714 errorCode = "408"; 715 } else { 716 // Use cmi.interactions.n.type value to check the right //dataelement format 717 var interactiontype = eval(subel1 + '.type'); 718 var interactioncount = eval(parentelement + '._count'); 719 // trap duplicate values, which is not allowed for type choice 720 if (interactiontype == 'choice') { 721 for (var i = 0; (i < interactioncount) && (errorCode == "0"); i++) { 722 if (eval(parentelement + '.N' + i + '.pattern') == value) { 723 errorCode = "351"; 724 } 725 } 726 } 727 var nodes = new Array(); 728 if (correct_responses[interactiontype].delimiter != '') { 729 nodes = value.split(correct_responses[interactiontype].delimiter); 730 } else { 731 nodes[0] = value; 732 } 733 734 if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) { 735 errorCode = CRcheckValueNodes (element, interactiontype, nodes, value, errorCode); 736 } else if (nodes.length > correct_responses[interactiontype].max) { 737 errorCode = "351"; 738 diagnostic = "Data Model Element Pattern Too Long"; 739 } 740 } 741 break; 742 } 743 } 744 } 745 } 746 //Store data 747 if (errorCode == "0") { 748 if (autocommit && !(SCORMapi1_3.timeout)) { 749 SCORMapi1_3.timeout = Y.later(60000, API_1484_11, 'Commit', [""], false); 750 } 751 752 if ((typeof eval('datamodel["' + scoid + '"]["' + elementmodel + '"].range')) != "undefined") { 753 range = eval('datamodel["' + scoid + '"]["' + elementmodel + '"].range'); 754 ranges = range.split('#'); 755 value = value * 1.0; 756 if (value >= ranges[0]) { 757 if ((ranges[1] == '*') || (value <= ranges[1])) { 758 eval(element + '=value;'); 759 errorCode = "0"; 760 if (scormdebugging) { 761 LogAPICall("SetValue", element, value, errorCode); 762 } 763 return "true"; 764 } else { 765 errorCode = '407'; 766 } 767 } else { 768 errorCode = '407'; 769 } 770 } else { 771 eval(element + '=value;'); 772 errorCode = "0"; 773 if (scormdebugging) { 774 LogAPICall("SetValue", element, value, errorCode); 775 } 776 return "true"; 777 } 778 } 779 } else { 780 errorCode = "406"; 781 } 782 } else { 783 errorCode = "404"; 784 } 785 } else { 786 errorCode = "401" 787 } 788 } else { 789 errorCode = "351"; 790 } 791 } else { 792 if (Terminated) { 793 errorCode = "133"; 794 } else { 795 errorCode = "132"; 796 } 797 } 798 if (scormdebugging) { 799 LogAPICall("SetValue", element, value, errorCode); 800 } 801 return "false"; 802 } 803 804 function CRremovePrefixes (node) { 805 // check for prefixes lang, case, order 806 // case and then order 807 var seenOrder = false; 808 var seenCase = false; 809 var seenLang = false; 810 var errorCode = "0"; 811 while (matches = node.match('^(\{(lang|case_matters|order_matters)=([^\}]+)\})')) { 812 switch (matches[2]) { 813 case 'lang': 814 // check for language prefix on each node 815 langmatches = node.match(CMILangcr); 816 if (langmatches != null) { 817 lang = langmatches[3]; 818 // check that language string definition is valid 819 if (lang.length > 0 && lang != undefined) { 820 if (validLanguages[lang.toLowerCase()] == undefined) { 821 errorCode = "406"; 822 } 823 } 824 } 825 seenLang = true; 826 break; 827 828 case 'case_matters': 829 // check for correct case answer 830 if (! seenLang && ! seenOrder && ! seenCase) { 831 if (matches[3] != 'true' && matches[3] != 'false') { 832 errorCode = "406"; 833 } 834 } 835 seenCase = true; 836 break; 837 838 case 'order_matters': 839 // check for correct case answer 840 if (! seenCase && ! seenLang && ! seenOrder) { 841 if (matches[3] != 'true' && matches[3] != 'false') { 842 errorCode = "406"; 843 } 844 } 845 seenOrder = true; 846 break; 847 848 default: 849 break; 850 } 851 node = node.substr(matches[1].length); 852 } 853 return {'errorCode': errorCode, 'node': node}; 854 } 855 856 function CRcheckValueNodes(element, interactiontype, nodes, value, errorCode) { 857 expression = new RegExp(correct_responses[interactiontype].format); 858 for (var i = 0; (i < nodes.length) && (errorCode == "0"); i++) { 859 if (interactiontype.match('^(fill-in|long-fill-in|matching|performance|sequencing)$')) { 860 result = CRremovePrefixes(nodes[i]); 861 errorCode = result.errorCode; 862 nodes[i] = result.node; 863 } 864 865 // check for prefix on each node 866 if (correct_responses[interactiontype].pre != '') { 867 matches = nodes[i].match(correct_responses[interactiontype].pre); 868 if (matches != null) { 869 nodes[i] = nodes[i].substr(matches[1].length); 870 } 871 } 872 873 if (correct_responses[interactiontype].delimiter2 != undefined) { 874 values = nodes[i].split(correct_responses[interactiontype].delimiter2); 875 if (values.length == 2) { 876 matches = values[0].match(expression); 877 if (matches == null) { 878 errorCode = "406"; 879 } else { 880 var expression2 = new RegExp(correct_responses[interactiontype].format2); 881 matches = values[1].match(expression2); 882 if (matches == null) { 883 errorCode = "406"; 884 } 885 } 886 } else { 887 errorCode = "406"; 888 } 889 } else { 890 matches = nodes[i].match(expression); 891 //if ((matches == null) || (matches.join('').length == 0)) { 892 if ((matches == null && value != "") || (matches == null && interactiontype == "true-false")){ 893 errorCode = "406"; 894 } else { 895 // numeric range - left must be <= right 896 if (interactiontype == 'numeric' && nodes.length > 1) { 897 if (parseFloat(nodes[0]) > parseFloat(nodes[1])) { 898 errorCode = "406"; 899 } 900 } else { 901 if ((nodes[i] != '') && (correct_responses[interactiontype].unique)) { 902 for (var j = 0; (j < i) && (errorCode == "0"); j++) { 903 if (nodes[i] == nodes[j]) { 904 errorCode = "406"; 905 } 906 } 907 } 908 } 909 } 910 } 911 } // end of for each nodes 912 return errorCode; 913 } 914 915 function Commit (param) { 916 if (SCORMapi1_3.timeout) { 917 SCORMapi1_3.timeout.cancel(); 918 SCORMapi1_3.timeout = null; 919 } 920 errorCode = "0"; 921 if (param == "") { 922 if ((Initialized) && (!Terminated)) { 923 var AJAXResult = StoreData(cmi,false); 924 if (scormdebugging) { 925 LogAPICall("Commit", "AJAXResult", AJAXResult, 0); 926 } 927 var result = ('true' == AJAXResult) ? 'true' : 'false'; 928 errorCode = ('true' == result) ? '0' : '101'; // General exception for any AJAX fault 929 if (scormdebugging) { 930 LogAPICall("Commit", "result", result, errorCode); 931 } 932 if ('false' == result) { 933 diagnostic = "Failure calling the Commit remote callback: the server replied with HTTP Status " + AJAXResult; 934 } 935 return result; 936 } else { 937 if (Terminated) { 938 errorCode = "143"; 939 } else { 940 errorCode = "142"; 941 } 942 } 943 } else { 944 errorCode = "201"; 945 } 946 if (scormdebugging) { 947 LogAPICall("Commit", param, "", errorCode); 948 } 949 return "false"; 950 } 951 952 function GetLastError () { 953 if (scormdebugging) { 954 LogAPICall("GetLastError", "", "", errorCode); 955 } 956 return errorCode; 957 } 958 959 function GetErrorString (param) { 960 if (param != "") { 961 var errorString = ""; 962 switch(param) { 963 case "0": 964 errorString = "No error"; 965 break; 966 case "101": 967 errorString = "General exception"; 968 break; 969 case "102": 970 errorString = "General Inizialization Failure"; 971 break; 972 case "103": 973 errorString = "Already Initialized"; 974 break; 975 case "104": 976 errorString = "Content Instance Terminated"; 977 break; 978 case "111": 979 errorString = "General Termination Failure"; 980 break; 981 case "112": 982 errorString = "Termination Before Inizialization"; 983 break; 984 case "113": 985 errorString = "Termination After Termination"; 986 break; 987 case "122": 988 errorString = "Retrieve Data Before Initialization"; 989 break; 990 case "123": 991 errorString = "Retrieve Data After Termination"; 992 break; 993 case "132": 994 errorString = "Store Data Before Inizialization"; 995 break; 996 case "133": 997 errorString = "Store Data After Termination"; 998 break; 999 case "142": 1000 errorString = "Commit Before Inizialization"; 1001 break; 1002 case "143": 1003 errorString = "Commit After Termination"; 1004 break; 1005 case "201": 1006 errorString = "General Argument Error"; 1007 break; 1008 case "301": 1009 errorString = "General Get Failure"; 1010 break; 1011 case "351": 1012 errorString = "General Set Failure"; 1013 break; 1014 case "391": 1015 errorString = "General Commit Failure"; 1016 break; 1017 case "401": 1018 errorString = "Undefinited Data Model"; 1019 break; 1020 case "402": 1021 errorString = "Unimplemented Data Model Element"; 1022 break; 1023 case "403": 1024 errorString = "Data Model Element Value Not Initialized"; 1025 break; 1026 case "404": 1027 errorString = "Data Model Element Is Read Only"; 1028 break; 1029 case "405": 1030 errorString = "Data Model Element Is Write Only"; 1031 break; 1032 case "406": 1033 errorString = "Data Model Element Type Mismatch"; 1034 break; 1035 case "407": 1036 errorString = "Data Model Element Value Out Of Range"; 1037 break; 1038 case "408": 1039 errorString = "Data Model Dependency Not Established"; 1040 break; 1041 } 1042 if (scormdebugging) { 1043 LogAPICall("GetErrorString", param, errorString, 0); 1044 } 1045 return errorString; 1046 } else { 1047 if (scormdebugging) { 1048 LogAPICall("GetErrorString", param, "No error string found!", 0); 1049 } 1050 return ""; 1051 } 1052 } 1053 1054 function GetDiagnostic (param) { 1055 if (diagnostic != "") { 1056 if (scormdebugging) { 1057 LogAPICall("GetDiagnostic", param, diagnostic, 0); 1058 } 1059 return diagnostic; 1060 } 1061 if (scormdebugging) { 1062 LogAPICall("GetDiagnostic", param, param, 0); 1063 } 1064 return param; 1065 } 1066 1067 function duplicatedID (element, parent, value) { 1068 var found = false; 1069 var elements = eval(parent + '._count'); 1070 for (var n = 0; (n < elements) && (!found); n++) { 1071 if ((parent + '.N' + n + '.id' != element) && (eval(parent + '.N' + n + '.id') == value)) { 1072 found = true; 1073 } 1074 } 1075 return found; 1076 } 1077 1078 function duplicatedPA (element, parent, value) { 1079 var found = false; 1080 var elements = eval(parent + '._count'); 1081 for (var n = 0; (n < elements) && (!found); n++) { 1082 if ((parent + '.N' + n + '.pattern' != element) && (eval(parent + '.N' + n + '.pattern') == value)) { 1083 found = true; 1084 } 1085 } 1086 return found; 1087 } 1088 1089 function getElementModel(element) { 1090 if (typeof datamodel[scoid][element] != "undefined") { 1091 return element; 1092 } else { 1093 var expression = new RegExp(CMIIndex,'g'); 1094 var elementmodel = String(element).replace(expression,'.n.'); 1095 if (typeof datamodel[scoid][elementmodel] != "undefined") { 1096 return elementmodel; 1097 } 1098 } 1099 return false; 1100 } 1101 1102 function AddTime (first, second) { 1103 var timestring = 'P'; 1104 var matchexpr = /^P((\d+)Y)?((\d+)M)?((\d+)D)?(T((\d+)H)?((\d+)M)?((\d+(\.\d{1,2})?)S)?)?$/; 1105 var firstarray = first.match(matchexpr); 1106 var secondarray = second.match(matchexpr); 1107 if ((firstarray != null) && (secondarray != null)) { 1108 var firstsecs = 0; 1109 if(parseFloat(firstarray[13],10) > 0){ firstsecs = parseFloat(firstarray[13],10); } 1110 var secondsecs = 0; 1111 if(parseFloat(secondarray[13],10) > 0){ secondsecs = parseFloat(secondarray[13],10); } 1112 var secs = firstsecs + secondsecs; //Seconds 1113 var change = Math.floor(secs / 60); 1114 secs = Math.round((secs - (change * 60)) * 100) / 100; 1115 var firstmins = 0; 1116 if(parseInt(firstarray[11],10) > 0){ firstmins = parseInt(firstarray[11],10); } 1117 var secondmins = 0; 1118 if(parseInt(secondarray[11],10) > 0){ secondmins = parseInt(secondarray[11],10); } 1119 var mins = firstmins + secondmins + change; //Minutes 1120 change = Math.floor(mins / 60); 1121 mins = Math.round(mins - (change * 60)); 1122 var firsthours = 0; 1123 if(parseInt(firstarray[9],10) > 0){ firsthours = parseInt(firstarray[9],10); } 1124 var secondhours = 0; 1125 if(parseInt(secondarray[9],10) > 0){ secondhours = parseInt(secondarray[9],10); } 1126 var hours = firsthours + secondhours + change; //Hours 1127 change = Math.floor(hours / 24); 1128 hours = Math.round(hours - (change * 24)); 1129 var firstdays = 0; 1130 if(parseInt(firstarray[6],10) > 0){ firstdays = parseInt(firstarray[6],10); } 1131 var seconddays = 0; 1132 if(parseInt(secondarray[6],10) > 0){ firstdays = parseInt(secondarray[6],10); } 1133 var days = Math.round(firstdays + seconddays + change); // Days 1134 var firstmonths = 0; 1135 if(parseInt(firstarray[4],10) > 0){ firstmonths = parseInt(firstarray[4],10); } 1136 var secondmonths = 0; 1137 if(parseInt(secondarray[4],10) > 0){ secondmonths = parseInt(secondarray[4],10); } 1138 var months = Math.round(firstmonths + secondmonths); 1139 var firstyears = 0; 1140 if(parseInt(firstarray[2],10) > 0){ firstyears = parseInt(firstarray[2],10); } 1141 var secondyears = 0; 1142 if(parseInt(secondarray[2],10) > 0){ secondyears = parseInt(secondarray[2],10); } 1143 var years = Math.round(firstyears + secondyears); 1144 } 1145 if (years > 0) { 1146 timestring += years + 'Y'; 1147 } 1148 if (months > 0) { 1149 timestring += months + 'M'; 1150 } 1151 if (days > 0) { 1152 timestring += days + 'D'; 1153 } 1154 if ((hours > 0) || (mins > 0) || (secs > 0)) { 1155 timestring += 'T'; 1156 if (hours > 0) { 1157 timestring += hours + 'H'; 1158 } 1159 if (mins > 0) { 1160 timestring += mins + 'M'; 1161 } 1162 if (secs > 0) { 1163 timestring += secs + 'S'; 1164 } 1165 } 1166 return timestring; 1167 } 1168 1169 function TotalTime() { 1170 var total_time = AddTime(cmi.total_time, cmi.session_time); 1171 return '&' + underscore('cmi.total_time') + '=' + encodeURIComponent(total_time); 1172 } 1173 1174 function CollectData(data,parent) { 1175 var datastring = ''; 1176 for (property in data) { 1177 if (typeof data[property] == 'object') { 1178 datastring += CollectData(data[property],parent + '.' + property); 1179 } else { 1180 var element = parent + '.' + property; 1181 var expression = new RegExp(CMIIndexStore,'g'); 1182 var elementmodel = String(element).replace(expression,'.n.'); 1183 if ((typeof eval('datamodel["' + scoid + '"]["' + elementmodel + '"]')) != "undefined") { 1184 if (eval('datamodel["' + scoid + '"]["' + elementmodel + '"].mod') != 'r') { 1185 var elementstring = '&' + underscore(element) + '=' + encodeURIComponent(data[property]); 1186 if ((typeof eval('datamodel["' + scoid + '"]["' + elementmodel + '"].defaultvalue')) != "undefined") { 1187 if (eval('datamodel["' + scoid + '"]["' + elementmodel + '"].defaultvalue') != data[property] || eval('typeof(datamodel["' + scoid + '"]["' + elementmodel + '"].defaultvalue)') != typeof(data[property])) { 1188 datastring += elementstring; 1189 } 1190 } else { 1191 datastring += elementstring; 1192 } 1193 } 1194 } 1195 } 1196 } 1197 return datastring; 1198 } 1199 1200 function StoreData(data,storetotaltime) { 1201 var datastring = ''; 1202 if (storetotaltime) { 1203 if (cmi.mode == 'normal') { 1204 if (cmi.credit == 'credit') { 1205 if ((cmi.completion_threshold) && (cmi.progress_measure)) { 1206 if (cmi.progress_measure >= cmi.completion_threshold) { 1207 cmi.completion_status = 'completed'; 1208 } else { 1209 cmi.completion_status = 'incomplete'; 1210 } 1211 } 1212 if ((cmi.scaled_passed_score != null) && (cmi.score.scaled != '')) { 1213 if (cmi.score.scaled >= cmi.scaled_passed_score) { 1214 cmi.success_status = 'passed'; 1215 } else { 1216 cmi.success_status = 'failed'; 1217 } 1218 } 1219 } 1220 } 1221 datastring += TotalTime(); 1222 } 1223 datastring += CollectData(data,'cmi'); 1224 var element = 'adl.nav.request'; 1225 var navrequest = eval(element) != datamodel[scoid][element].defaultvalue ? '&' + underscore(element) + '=' + encodeURIComponent(eval(element)) : ''; 1226 datastring += navrequest; 1227 1228 var myRequest = NewHttpReq(); 1229 result = DoRequest(myRequest, datamodelurl, datamodelurlparams + datastring); 1230 1231 var results = String(result).split('\n'); 1232 if ((results.length > 2) && (navrequest != '')) { 1233 eval(results[2]); 1234 } 1235 errorCode = results[1]; 1236 return results[0]; 1237 } 1238 1239 this.Initialize = Initialize; 1240 this.Terminate = Terminate; 1241 this.GetValue = GetValue; 1242 this.SetValue = SetValue; 1243 this.Commit = Commit; 1244 this.GetLastError = GetLastError; 1245 this.GetErrorString = GetErrorString; 1246 this.GetDiagnostic = GetDiagnostic; 1247 this.version = '1.0'; 1248 } 1249 1250 M.scorm_api = {}; 1251 1252 M.scorm_api.init = function(Y, def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg, autocommit) { 1253 window.API_1484_11 = new SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scormdebugging, scormauto, scormid, cfgwwwroot, sesskey, scoid, attempt, viewmode, cmid, currentorg, autocommit); 1254 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |