|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00017 require_once($CFG->dirroot.'/mod/scorm/locallib.php'); 00018 00019 if (isset($userdata->status)) { 00020 if (!isset($userdata->{'cmi.exit'}) || (($userdata->{'cmi.exit'} == 'time-out') || ($userdata->{'cmi.exit'} == 'normal'))) { 00021 $userdata->entry = 'ab-initio'; 00022 } else { 00023 if (isset($userdata->{'cmi.exit'}) && (($userdata->{'cmi.exit'} == 'suspend') || ($userdata->{'cmi.exit'} == 'logout'))) { 00024 $userdata->entry = 'resume'; 00025 } else { 00026 $userdata->entry = ''; 00027 } 00028 } 00029 } 00030 if (!isset($currentorg)) { 00031 $currentorg = ''; 00032 } 00033 ?> 00034 00035 // Used need to debug cmi content (if you uncomment this, you must comment the definition inside SCORMapi1_3) 00036 //var cmi = new Object(); 00037 00038 // 00039 // SCORM 1.3 API Implementation 00040 // 00041 function SCORMapi1_3() { 00042 // Standard Data Type Definition 00043 00044 // language key has to be checked for language dependent strings 00045 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', 00046 'ba':'ba', 'be':'be', 'bg':'bg', 'bh':'bh', 'bi':'bi', 'bm':'bm', 'bn':'bn', 'bo':'bo', 'br':'br', 'bs':'bs', 00047 'ca':'ca', 'ce':'ce', 'ch':'ch', 'co':'co', 'cr':'cr', 'cs':'cs', 'cu':'cu', 'cv':'cv', 'cy':'cy', 00048 'da':'da', 'de':'de', 'dv':'dv', 'dz':'dz', 'ee':'ee', 'el':'el', 'en':'en', 'eo':'eo', 'es':'es', 'et':'et', 'eu':'eu', 00049 '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', 00050 'ha':'ha', 'he':'he', 'hi':'hi', 'ho':'ho', 'hr':'hr', 'ht':'ht', 'hu':'hu', 'hy':'hy', 'hz':'hz', 00051 'ia':'ia', 'id':'id', 'ie':'ie', 'ig':'ig', 'ii':'ii', 'ik':'ik', 'io':'io', 'is':'is', 'it':'it', 'iu':'iu', 00052 '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', 00053 'la':'la', 'lb':'lb', 'lg':'lg', 'li':'li', 'ln':'ln', 'lo':'lo', 'lt':'lt', 'lu':'lu', 'lv':'lv', 00054 'mg':'mg', 'mh':'mh', 'mi':'mi', 'mk':'mk', 'ml':'ml', 'mn':'mn', 'mo':'mo', 'mr':'mr', 'ms':'ms', 'mt':'mt', 'my':'my', 00055 'na':'na', 'nb':'nb', 'nd':'nd', 'ne':'ne', 'ng':'ng', 'nl':'nl', 'nn':'nn', 'no':'no', 'nr':'nr', 'nv':'nv', 'ny':'ny', 00056 'oc':'oc', 'oj':'oj', 'om':'om', 'or':'or', 'os':'os', 'pa':'pa', 'pi':'pi', 'pl':'pl', 'ps':'ps', 'pt':'pt', 00057 'qu':'qu', 'rm':'rm', 'rn':'rn', 'ro':'ro', 'ru':'ru', 'rw':'rw', 00058 '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', 00059 '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', 00060 'ug':'ug', 'uk':'uk', 'ur':'ur', 'uz':'uz', 've':'ve', 'vi':'vi', 'vo':'vo', 00061 'wa':'wa', 'wo':'wo', 'xh':'xh', 'yi':'yi', 'yo':'yo', 'za':'za', 'zh':'zh', 'zu':'zu', 00062 'aar':'aar', 'abk':'abk', 'ave':'ave', 'afr':'afr', 'aka':'aka', 'amh':'amh', 'arg':'arg', 'ara':'ara', 'asm':'asm', 'ava':'ava', 'aym':'aym', 'aze':'aze', 00063 'bak':'bak', 'bel':'bel', 'bul':'bul', 'bih':'bih', 'bis':'bis', 'bam':'bam', 'ben':'ben', 'tib':'tib', 'bod':'bod', 'bre':'bre', 'bos':'bos', 00064 'cat':'cat', 'che':'che', 'cha':'cha', 'cos':'cos', 'cre':'cre', 'cze':'cze', 'ces':'ces', 'chu':'chu', 'chv':'chv', 'wel':'wel', 'cym':'cym', 00065 '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', 00066 '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', 00067 'hau':'hau', 'heb':'heb', 'hin':'hin', 'hmo':'hmo', 'hrv':'hrv', 'hat':'hat', 'hun':'hun', 'arm':'arm', 'hye':'hye', 'her':'her', 00068 'ina':'ina', 'ind':'ind', 'ile':'ile', 'ibo':'ibo', 'iii':'iii', 'ipk':'ipk', 'ido':'ido', 'ice':'ice', 'isl':'isl', 'ita':'ita', 'iku':'iku', 00069 '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', 00070 'lat':'lat', 'ltz':'ltz', 'lug':'lug', 'lim':'lim', 'lin':'lin', 'lao':'lao', 'lit':'lit', 'lub':'lub', 'lav':'lav', 00071 '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', 00072 'nau':'nau', 'nob':'nob', 'nde':'nde', 'nep':'nep', 'ndo':'ndo', 'dut':'dut', 'nld':'nld', 'nno':'nno', 'nor':'nor', 'nbl':'nbl', 'nav':'nav', 'nya':'nya', 00073 'oci':'oci', 'oji':'oji', 'orm':'orm', 'ori':'ori', 'oss':'oss', 'pan':'pan', 'pli':'pli', 'pol':'pol', 'pus':'pus', 'por':'por', 'que':'que', 00074 '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', 00075 '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', 00076 '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'}; 00077 00078 var CMIString200 = '^[\\u0000-\\uFFFF]{0,200}$'; 00079 var CMIString250 = '^[\\u0000-\\uFFFF]{0,250}$'; 00080 var CMIString1000 = '^[\\u0000-\\uFFFF]{0,1000}$'; 00081 var CMIString4000 = '^[\\u0000-\\uFFFF]{0,4000}$'; 00082 var CMIString64000 = '^[\\u0000-\\uFFFF]{0,64000}$'; 00083 var CMILang = '^([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?$|^$'; 00084 var CMILangString250 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,250}$)?'; 00085 var CMILangcr = '^((\{lang=([a-zA-Z]{2,3}|i|x)?(\-[a-zA-Z0-9\-]{2,8})?\}))(.*?)$'; 00086 var CMILangString250cr = '^((\{lang=([a-zA-Z]{2,3}|i|x)?(\-[a-zA-Z0-9\-]{2,8})?\})?(.{0,250})?)?$'; 00087 var CMILangString4000 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,4000}$)?'; 00088 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})?)?)?)?)?)?)?)?$'; 00089 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))))?$'; 00090 var CMIInteger = '^\\d+$'; 00091 var CMISInteger = '^-?([0-9]+)$'; 00092 var CMIDecimal = '^-?([0-9]{1,5})(\\.[0-9]{1,18})?$'; 00093 var CMIIdentifier = '^\\S{1,250}[a-zA-Z0-9]$'; 00094 var CMIShortIdentifier = '^[\\w\.]{1,250}$'; 00095 var CMILongIdentifier = '^(?:(?!urn:)\\S{1,4000}|urn:[A-Za-z0-9-]{1,31}:\\S{1,4000})$'; 00096 var CMIFeedback = '^.*$'; // This must be redefined 00097 var CMIIndex = '[._](\\d+).'; 00098 var CMIIndexStore = '.N(\\d+).'; 00099 // Vocabulary Data Type Definition 00100 var CMICStatus = '^completed$|^incomplete$|^not attempted$|^unknown$'; 00101 var CMISStatus = '^passed$|^failed$|^unknown$'; 00102 var CMIExit = '^time-out$|^suspend$|^logout$|^normal$|^$'; 00103 var CMIType = '^true-false$|^choice$|^(long-)?fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$|^other$'; 00104 var CMIResult = '^correct$|^incorrect$|^unanticipated$|^neutral$|^-?([0-9]{1,4})(\\.[0-9]{1,18})?$'; 00105 var NAVEvent = '^previous$|^continue$|^exit$|^exitAll$|^abandon$|^abandonAll$|^suspendAll$|^{target=\\S{0,200}[a-zA-Z0-9]}choice$'; 00106 var NAVBoolean = '^unknown$|^true$|^false$'; 00107 var NAVTarget = '^previous$|^continue$|^choice.{target=\\S{0,200}[a-zA-Z0-9]}$' 00108 // Children lists 00109 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'; 00110 var comments_children = 'comment,timestamp,location'; 00111 var score_children = 'max,raw,scaled,min'; 00112 var objectives_children = 'progress_measure,completion_status,success_status,description,score,id'; 00113 var correct_responses_children = 'pattern'; 00114 var student_data_children = 'mastery_score,max_time_allowed,time_limit_action'; 00115 var student_preference_children = 'audio_level,audio_captioning,delivery_speed,language'; 00116 var interactions_children = 'id,type,objectives,timestamp,correct_responses,weighting,learner_response,result,latency,description'; 00117 // Data ranges 00118 var scaled_range = '-1#1'; 00119 var audio_range = '0#*'; 00120 var speed_range = '0#*'; 00121 var text_range = '-1#1'; 00122 var progress_range = '0#1'; 00123 var learner_response = { 00124 'true-false':{'format':'^true$|^false$', 'max':1, 'delimiter':'', 'unique':false}, 00125 'choice':{'format':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'unique':true}, 00126 'fill-in':{'format':CMILangString250, 'max':10, 'delimiter':'[,]', 'unique':false}, 00127 'long-fill-in':{'format':CMILangString4000, 'max':1, 'delimiter':'', 'unique':false}, 00128 'matching':{'format':CMIShortIdentifier, 'format2':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false}, 00129 'performance':{'format':'^$|'+CMIShortIdentifier, 'format2':CMIDecimal+'|^$|'+CMIShortIdentifier, 'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false}, 00130 'sequencing':{'format':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'unique':false}, 00131 'likert':{'format':CMIShortIdentifier, 'max':1, 'delimiter':'', 'unique':false}, 00132 'numeric':{'format':CMIDecimal, 'max':1, 'delimiter':'', 'unique':false}, 00133 'other':{'format':CMIString4000, 'max':1, 'delimiter':'', 'unique':false} 00134 } 00135 00136 var correct_responses = { 00137 'true-false':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 00138 'format':'^true$|^false$', 00139 'limit':1}, 00140 'choice':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':true, 'duplicate':false, 00141 'format':CMIShortIdentifier}, 00142 // 'fill-in':{'pre':'^(((\{case_matters=(true|false)\})(\{order_matters=(true|false)\})?)|((\{order_matters=(true|false)\})(\{case_matters=(true|false)\})?))(.*?)$', 00143 'fill-in':{'pre':'', 00144 'max':10, 'delimiter':'[,]', 'unique':false, 'duplicate':false, 00145 'format':CMILangString250cr}, 00146 'long-fill-in':{'pre':'^(\{case_matters=(true|false)\})?', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':true, 00147 'format':CMILangString4000}, 00148 'matching':{'pre':'', 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':false, 00149 'format':CMIShortIdentifier, 'format2':CMIShortIdentifier}, 00150 'performance':{'pre':'^(\{order_matters=(true|false)\})?', 00151 'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':false, 00152 'format':'^$|'+CMIShortIdentifier, 'format2':CMIDecimal+'|^$|'+CMIShortIdentifier}, 00153 'sequencing':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':false, 'duplicate':false, 00154 'format':CMIShortIdentifier}, 00155 'likert':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 00156 'format':CMIShortIdentifier, 00157 'limit':1}, 00158 'numeric':{'pre':'', 'max':2, 'delimiter':'[:]', 'unique':false, 'duplicate':false, 00159 'format':CMIDecimal, 00160 'limit':1}, 00161 'other':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false, 00162 'format':CMIString4000, 00163 'limit':1} 00164 } 00165 00166 // The SCORM 1.3 data model 00167 var datamodel = { 00168 'cmi._children':{'defaultvalue':cmi_children, 'mod':'r'}, 00169 'cmi._version':{'defaultvalue':'1.0', 'mod':'r'}, 00170 'cmi.comments_from_learner._children':{'defaultvalue':comments_children, 'mod':'r'}, 00171 'cmi.comments_from_learner._count':{'mod':'r', 'defaultvalue':'0'}, 00172 'cmi.comments_from_learner.n.comment':{'format':CMILangString4000, 'mod':'rw'}, 00173 'cmi.comments_from_learner.n.location':{'format':CMIString250, 'mod':'rw'}, 00174 'cmi.comments_from_learner.n.timestamp':{'format':CMITime, 'mod':'rw'}, 00175 'cmi.comments_from_lms._children':{'defaultvalue':comments_children, 'mod':'r'}, 00176 'cmi.comments_from_lms._count':{'mod':'r', 'defaultvalue':'0'}, 00177 'cmi.comments_from_lms.n.comment':{'format':CMILangString4000, 'mod':'r'}, 00178 'cmi.comments_from_lms.n.location':{'format':CMIString250, 'mod':'r'}, 00179 'cmi.comments_from_lms.n.timestamp':{'format':CMITime, 'mod':'r'}, 00180 'cmi.completion_status':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.completion_status'})?$userdata->{'cmi.completion_status'}:'unknown' ?>', 'format':CMICStatus, 'mod':'rw'}, 00181 'cmi.completion_threshold':{'defaultvalue':<?php echo !empty($userdata->threshold)?'\''.$userdata->threshold.'\'':'null' ?>, 'mod':'r'}, 00182 'cmi.credit':{'defaultvalue':'<?php echo !empty($userdata->credit)?$userdata->credit:'' ?>', 'mod':'r'}, 00183 'cmi.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r'}, 00184 'cmi.exit':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.exit'})?$userdata->{'cmi.exit'}:'' ?>', 'format':CMIExit, 'mod':'w'}, 00185 'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r'}, 00186 'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0'}, 00187 'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 00188 'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'rw'}, 00189 'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0'}, 00190 'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 00191 'cmi.interactions.n.timestamp':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw'}, 00192 'cmi.interactions.n.correct_responses._count':{'defaultvalue':'0', 'pattern':CMIIndex, 'mod':'r'}, 00193 'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'}, 00194 'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 00195 'cmi.interactions.n.learner_response':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'}, 00196 'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'}, 00197 'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'}, 00198 'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'}, 00199 'cmi.launch_data':{'defaultvalue':<?php echo !empty($userdata->datafromlms)?'\''.$userdata->datafromlms.'\'':'null' ?>, 'mod':'r'}, 00200 'cmi.learner_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r'}, 00201 'cmi.learner_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r'}, 00202 'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'}, 00203 'cmi.learner_preference.audio_level':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_level'})?'\''.$userdata->{'cmi.learner_preference.audio_level'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'}, 00204 'cmi.learner_preference.language':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.language'})?'\''.$userdata->{'cmi.learner_preference.language'}.'\'':'\'\'' ?>, 'format':CMILang, 'mod':'rw'}, 00205 'cmi.learner_preference.delivery_speed':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.delivery_speed'})?'\''.$userdata->{'cmi.learner_preference.delivery_speed'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'}, 00206 'cmi.learner_preference.audio_captioning':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_captioning'})?'\''.$userdata->{'cmi.learner_preference.audio_captioning'}.'\'':'\'0\'' ?>, 'format':CMISInteger, 'range':text_range, 'mod':'rw'}, 00207 'cmi.location':{'defaultvalue':<?php echo !empty($userdata->{'cmi.location'})?'\''.$userdata->{'cmi.location'}.'\'':'null' ?>, 'format':CMIString1000, 'mod':'rw'}, 00208 'cmi.max_time_allowed':{'defaultvalue':<?php echo !empty($userdata->attemptAbsoluteDurationLimit)?'\''.$userdata->attemptAbsoluteDurationLimit.'\'':'null' ?>, 'mod':'r'}, 00209 'cmi.mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r'}, 00210 'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r'}, 00211 'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0'}, 00212 'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'}, 00213 'cmi.objectives.n.score._children':{'defaultvalue':score_children, 'pattern':CMIIndex, 'mod':'r'}, 00214 'cmi.objectives.n.score.scaled':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'}, 00215 'cmi.objectives.n.score.raw':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 00216 'cmi.objectives.n.score.min':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 00217 'cmi.objectives.n.score.max':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'}, 00218 'cmi.objectives.n.success_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMISStatus, 'mod':'rw'}, 00219 'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'}, 00220 'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'}, 00221 'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'}, 00222 'cmi.progress_measure':{'defaultvalue':<?php echo !empty($userdata->{'cmi.progress_measure'})?'\''.$userdata->{'cmi.progress_measure'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'}, 00223 'cmi.scaled_passing_score':{'defaultvalue':<?php echo !empty($userdata->{'cmi.scaled_passing_score'})?'\''.$userdata->{'cmi.scaled_passing_score'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'}, 00224 'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'}, 00225 'cmi.score.scaled':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.scaled'})?'\''.$userdata->{'cmi.score.scaled'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'}, 00226 'cmi.score.raw':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.raw'})?'\''.$userdata->{'cmi.score.raw'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'}, 00227 'cmi.score.min':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.min'})?'\''.$userdata->{'cmi.score.min'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'}, 00228 'cmi.score.max':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.max'})?'\''.$userdata->{'cmi.score.max'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'}, 00229 'cmi.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'PT0H0M0S'}, 00230 'cmi.success_status':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.success_status'})?$userdata->{'cmi.success_status'}:'unknown' ?>', 'format':CMISStatus, 'mod':'rw'}, 00231 'cmi.suspend_data':{'defaultvalue':<?php echo !empty($userdata->{'cmi.suspend_data'})?'\''.$userdata->{'cmi.suspend_data'}.'\'':'null' ?>, 'format':CMIString64000, 'mod':'rw'}, 00232 'cmi.time_limit_action':{'defaultvalue':<?php echo !empty($userdata->timelimitaction)?'\''.$userdata->timelimitaction.'\'':'null' ?>, 'mod':'r'}, 00233 'cmi.total_time':{'defaultvalue':'<?php echo !empty($userdata->{'cmi.total_time'})?$userdata->{'cmi.total_time'}:'PT0H0M0S' ?>', 'mod':'r'}, 00234 'adl.nav.request':{'defaultvalue':'_none_', 'format':NAVEvent, 'mod':'rw'} 00235 }; 00236 // 00237 // Datamodel inizialization 00238 // 00239 var cmi = new Object(); 00240 cmi.comments_from_learner = new Object(); 00241 cmi.comments_from_learner._count = 0; 00242 cmi.comments_from_lms = new Object(); 00243 cmi.comments_from_lms._count = 0; 00244 cmi.interactions = new Object(); 00245 cmi.interactions._count = 0; 00246 cmi.learner_preference = new Object(); 00247 cmi.objectives = new Object(); 00248 cmi.objectives._count = 0; 00249 cmi.score = new Object(); 00250 00251 // Navigation Object 00252 var adl = new Object(); 00253 adl.nav = new Object(); 00254 adl.nav.request_valid = new Array(); 00255 00256 for (element in datamodel) { 00257 if (element.match(/\.n\./) == null) { 00258 if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') { 00259 eval(element+' = datamodel["'+element+'"].defaultvalue;'); 00260 } else { 00261 eval(element+' = "";'); 00262 } 00263 } 00264 } 00265 00266 <?php 00267 // reconstitute objectives, comments_from_learner and comments_from_lms 00268 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score')); 00269 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.interactions', array('objectives', 'correct_responses')); 00270 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_learner', array()); 00271 scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_lms', array()); 00272 ?> 00273 00274 if (cmi.completion_status == '') { 00275 cmi.completion_status = 'not attempted'; 00276 } 00277 00278 // 00279 // API Methods definition 00280 // 00281 var Initialized = false; 00282 var Terminated = false; 00283 var diagnostic = ""; 00284 var errorCode = "0"; 00285 00286 function Initialize (param) { 00287 errorCode = "0"; 00288 if (param == "") { 00289 if ((!Initialized) && (!Terminated)) { 00290 Initialized = true; 00291 errorCode = "0"; 00292 <?php 00293 if (scorm_debugging($scorm)) { 00294 echo 'LogAPICall("Initialize", param, "", errorCode);'; 00295 } 00296 ?> 00297 return "true"; 00298 } else { 00299 if (Initialized) { 00300 errorCode = "103"; 00301 } else { 00302 errorCode = "104"; 00303 } 00304 } 00305 } else { 00306 errorCode = "201"; 00307 } 00308 <?php 00309 if (scorm_debugging($scorm)) { 00310 echo 'LogAPICall("Initialize", param, "", errorCode);'; 00311 } 00312 ?> 00313 return "false"; 00314 } 00315 00316 00317 <?php 00318 // pull in the TOC callback 00319 include_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php'); 00320 ?> 00321 00322 00323 function Terminate (param) { 00324 errorCode = "0"; 00325 if (param == "") { 00326 if ((Initialized) && (!Terminated)) { 00327 var AJAXResult = StoreData(cmi,true); 00328 <?php 00329 if (scorm_debugging($scorm)) { 00330 echo 'LogAPICall("Terminate", "AJAXResult", AJAXResult, 0);'; 00331 } 00332 ?> 00333 result = ('true' == AJAXResult) ? 'true' : 'false'; 00334 errorCode = ('true' == result)? '0' : '101'; // General exception for any AJAX fault 00335 <?php 00336 if (scorm_debugging($scorm)) { 00337 echo 'LogAPICall("Terminate", "result", result, errorCode);'; 00338 } 00339 ?> 00340 if ('true' == result) { 00341 Initialized = false; 00342 Terminated = true; 00343 if (adl.nav.request != '_none_') { 00344 switch (adl.nav.request) { 00345 case 'continue': 00346 setTimeout('scorm_get_next();',500); 00347 break; 00348 case 'previous': 00349 setTimeout('scorm_get_prev();',500); 00350 break; 00351 case 'choice': 00352 break; 00353 case 'exit': 00354 break; 00355 case 'exitAll': 00356 break; 00357 case 'abandon': 00358 break; 00359 case 'abandonAll': 00360 break; 00361 } 00362 } else { 00363 if (<?php echo $scorm->auto ?> == 1) { 00364 setTimeout('scorm_get_next();',500); 00365 } 00366 } 00367 // trigger TOC update 00368 var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>¤torg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>"; 00369 YAHOO.util.Connect.asyncRequest('GET', sURL, this.connectPrereqCallback, null); 00370 } else { 00371 diagnostic = "Failure calling the Terminate remote callback: the server replied with HTTP Status " + AJAXResult; 00372 } 00373 return result; 00374 } else { 00375 if (Terminated) { 00376 errorCode = "113"; 00377 } else { 00378 errorCode = "112"; 00379 } 00380 } 00381 } else { 00382 errorCode = "201"; 00383 } 00384 <?php 00385 if (scorm_debugging($scorm)) { 00386 echo 'LogAPICall("Terminate", param, "", errorCode);'; 00387 } 00388 ?> 00389 return "false"; 00390 } 00391 00392 function GetValue (element) { 00393 errorCode = "0"; 00394 diagnostic = ""; 00395 if ((Initialized) && (!Terminated)) { 00396 if (element !="") { 00397 var expression = new RegExp(CMIIndex,'g'); 00398 var elementmodel = String(element).replace(expression,'.n.'); 00399 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") { 00400 if (eval('datamodel["'+elementmodel+'"].mod') != 'w') { 00401 00402 element = String(element).replace(/\.(\d+)\./, ".N$1."); 00403 element = element.replace(/\.(\d+)\./, ".N$1."); 00404 00405 var elementIndexes = element.split('.'); 00406 var subelement = element.substr(0,3); 00407 var i = 1; 00408 while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) { 00409 subelement += '.'+elementIndexes[i++]; 00410 } 00411 00412 if (subelement == element) { 00413 00414 if ((typeof eval(subelement) != "undefined") && (eval(subelement) != null)) { 00415 errorCode = "0"; 00416 <?php 00417 if (scorm_debugging($scorm)) { 00418 echo 'LogAPICall("GetValue", element, eval(element), 0);'; 00419 } 00420 ?> 00421 return eval(element); 00422 } else { 00423 errorCode = "403"; 00424 } 00425 } else { 00426 errorCode = "301"; 00427 } 00428 } else { 00429 //errorCode = eval('datamodel["'+elementmodel+'"].readerror'); 00430 errorCode = "405"; 00431 } 00432 } else { 00433 var childrenstr = '._children'; 00434 var countstr = '._count'; 00435 var parentmodel = ''; 00436 if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) { 00437 parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length); 00438 if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") { 00439 errorCode = "301"; 00440 diagnostic = "Data Model Element Does Not Have Children"; 00441 } else { 00442 errorCode = "401"; 00443 } 00444 } else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) { 00445 parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length); 00446 if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") { 00447 errorCode = "301"; 00448 diagnostic = "Data Model Element Cannot Have Count"; 00449 } else { 00450 errorCode = "401"; 00451 } 00452 } else { 00453 parentmodel = 'adl.nav.request_valid.'; 00454 if (element.substr(0,parentmodel.length) == parentmodel) { 00455 if (element.substr(parentmodel.length).match(NAVTarget) == null) { 00456 errorCode = "301"; 00457 } else { 00458 if (adl.nav.request == element.substr(parentmodel.length)) { 00459 return "true"; 00460 } else if (adl.nav.request == '_none_') { 00461 return "unknown"; 00462 } else { 00463 return "false"; 00464 } 00465 } 00466 } else { 00467 errorCode = "401"; 00468 } 00469 } 00470 } 00471 } else { 00472 errorCode = "301"; 00473 } 00474 } else { 00475 if (Terminated) { 00476 errorCode = "123"; 00477 } else { 00478 errorCode = "122"; 00479 } 00480 } 00481 <?php 00482 if (scorm_debugging($scorm)) { 00483 echo 'LogAPICall("GetValue", element, "", errorCode);'; 00484 } 00485 ?> 00486 return ""; 00487 } 00488 00489 function SetValue (element,value) { 00490 errorCode = "0"; 00491 diagnostic = ""; 00492 if ((Initialized) && (!Terminated)) { 00493 if (element != "") { 00494 var expression = new RegExp(CMIIndex,'g'); 00495 var elementmodel = String(element).replace(expression,'.n.'); 00496 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") { 00497 if (eval('datamodel["'+elementmodel+'"].mod') != 'r') { 00498 if (eval('datamodel["'+elementmodel+'"].format') != 'CMIFeedback') { 00499 expression = new RegExp(eval('datamodel["'+elementmodel+'"].format')); 00500 } else { 00501 // cmi.interactions.n.type depending format accept everything at this stage 00502 expression = new RegExp(CMIFeedback); 00503 } 00504 value = value+''; 00505 var matches = value.match(expression); 00506 if ((matches != null) && ((matches.join('').length > 0) || (value.length == 0))) { 00507 // Value match dataelement format 00508 00509 if (element != elementmodel) { 00510 //This is a dynamic datamodel element 00511 00512 var elementIndexes = element.split('.'); 00513 var subelement = 'cmi'; 00514 var parentelement = 'cmi'; 00515 for (var i=1;(i < elementIndexes.length-1) && (errorCode=="0");i++) { 00516 var elementIndex = elementIndexes[i]; 00517 if (elementIndexes[i+1].match(/^\d+$/)) { 00518 if ((parseInt(elementIndexes[i+1]) > 0) && (elementIndexes[i+1].charAt(0) == 0)) { 00519 // Index has a leading 0 (zero), this is not a number 00520 errorCode = "351"; 00521 } 00522 parentelement = subelement+'.'+elementIndex; 00523 if ((typeof eval(parentelement) == "undefined") || (typeof eval(parentelement+'._count') == "undefined")) { 00524 errorCode="408"; 00525 } else { 00526 if (elementIndexes[i+1] > eval(parentelement+'._count')) { 00527 errorCode = "351"; 00528 diagnostic = "Data Model Element Collection Set Out Of Order"; 00529 } 00530 subelement = subelement.concat('.'+elementIndex+'.N'+elementIndexes[i+1]); 00531 i++; 00532 00533 if (((typeof eval(subelement)) == "undefined") && (i < elementIndexes.length-2)) { 00534 errorCode="408"; 00535 } 00536 } 00537 } else { 00538 subelement = subelement.concat('.'+elementIndex); 00539 } 00540 } 00541 00542 if (errorCode == "0") { 00543 // Till now it's a real datamodel element 00544 00545 element = subelement.concat('.'+elementIndexes[elementIndexes.length-1]); 00546 00547 if ((typeof eval(subelement)) == "undefined") { 00548 switch (elementmodel) { 00549 case 'cmi.objectives.n.id': 00550 if (!duplicatedID(element,parentelement,value)) { 00551 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) { 00552 eval(parentelement+'._count++;'); 00553 eval(subelement+' = new Object();'); 00554 var subobject = eval(subelement); 00555 subobject.success_status = datamodel["cmi.objectives.n.success_status"].defaultvalue; 00556 subobject.completion_status = datamodel["cmi.objectives.n.completion_status"].defaultvalue; 00557 subobject.progress_measure = datamodel["cmi.objectives.n.progress_measure"].defaultvalue; 00558 subobject.score = new Object(); 00559 subobject.score._children = score_children; 00560 subobject.score.scaled = datamodel["cmi.objectives.n.score.scaled"].defaultvalue; 00561 subobject.score.raw = datamodel["cmi.objectives.n.score.raw"].defaultvalue; 00562 subobject.score.min = datamodel["cmi.objectives.n.score.min"].defaultvalue; 00563 subobject.score.max = datamodel["cmi.objectives.n.score.max"].defaultvalue; 00564 } 00565 } else { 00566 errorCode="351"; 00567 diagnostic = "Data Model Element ID Already Exists"; 00568 } 00569 break; 00570 case 'cmi.interactions.n.id': 00571 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) { 00572 eval(parentelement+'._count++;'); 00573 eval(subelement+' = new Object();'); 00574 var subobject = eval(subelement); 00575 subobject.objectives = new Object(); 00576 subobject.objectives._count = 0; 00577 } 00578 break; 00579 case 'cmi.interactions.n.objectives.n.id': 00580 if (typeof eval(parentelement) != "undefined") { 00581 if (!duplicatedID(element,parentelement,value)) { 00582 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) { 00583 eval(parentelement+'._count++;'); 00584 eval(subelement+' = new Object();'); 00585 } 00586 } else { 00587 errorCode="351"; 00588 diagnostic = "Data Model Element ID Already Exists"; 00589 } 00590 } else { 00591 errorCode="408"; 00592 } 00593 break; 00594 case 'cmi.interactions.n.correct_responses.n.pattern': 00595 if (typeof eval(parentelement) != "undefined") { 00596 // Use cmi.interactions.n.type value to check the right dataelement format 00597 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) { 00598 var interactiontype = eval(String(parentelement).replace('correct_responses','type')); 00599 var interactioncount = eval(parentelement+'._count'); 00600 // trap duplicate values, which is not allowed for type choice 00601 if (interactiontype == 'choice') { 00602 for (var i=0; (i < interactioncount) && (errorCode=="0"); i++) { 00603 if (eval(parentelement+'.N'+i+'.pattern') == value) { 00604 errorCode = "351"; 00605 } 00606 } 00607 } 00608 if ((typeof correct_responses[interactiontype].limit == 'undefined') || 00609 (eval(parentelement+'._count') < correct_responses[interactiontype].limit)) { 00610 var nodes = new Array(); 00611 if (correct_responses[interactiontype].delimiter != '') { 00612 nodes = value.split(correct_responses[interactiontype].delimiter); 00613 } else { 00614 nodes[0] = value; 00615 } 00616 if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) { 00617 errorCode = CRcheckValueNodes (element, interactiontype, nodes, value, errorCode); 00618 } else if (nodes.length > correct_responses[interactiontype].max) { 00619 errorCode = "351"; 00620 diagnostic = "Data Model Element Pattern Too Long"; 00621 } 00622 if ((errorCode == "0") && ((correct_responses[interactiontype].duplicate == false) || 00623 (!duplicatedPA(element,parentelement,value))) || (errorCode == "0" && value == "")) { 00624 eval(parentelement+'._count++;'); 00625 eval(subelement+' = new Object();'); 00626 } else { 00627 if (errorCode == "0") { 00628 errorCode="351"; 00629 diagnostic = "Data Model Element Pattern Already Exists"; 00630 } 00631 } 00632 } else { 00633 errorCode="351"; 00634 diagnostic = "Data Model Element Collection Limit Reached"; 00635 } 00636 } else { 00637 errorCode="351"; 00638 diagnostic = "Data Model Element Collection Set Out Of Order"; 00639 } 00640 } else { 00641 errorCode="408"; 00642 } 00643 break; 00644 default: 00645 if ((parentelement != 'cmi.objectives') && (parentelement != 'cmi.interactions') && (typeof eval(parentelement) != "undefined")) { 00646 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) { 00647 eval(parentelement+'._count++;'); 00648 eval(subelement+' = new Object();'); 00649 } else { 00650 errorCode="351"; 00651 diagnostic = "Data Model Element Collection Set Out Of Order"; 00652 } 00653 } else { 00654 errorCode="408"; 00655 } 00656 break; 00657 } 00658 } else { 00659 switch (elementmodel) { 00660 case 'cmi.objectives.n.id': 00661 if (eval(element) != value) { 00662 errorCode = "351"; 00663 diagnostic = "Write Once Violation"; 00664 } 00665 break; 00666 case 'cmi.interactions.n.objectives.n.id': 00667 if (duplicatedID(element,parentelement,value)) { 00668 errorCode = "351"; 00669 diagnostic = "Data Model Element ID Already Exists"; 00670 } 00671 break; 00672 case 'cmi.interactions.n.type': 00673 var subobject = eval(subelement); 00674 subobject.correct_responses = new Object(); 00675 subobject.correct_responses._count = 0; 00676 break; 00677 case 'cmi.interactions.n.learner_response': 00678 if (typeof eval(subelement+'.type') == "undefined") { 00679 errorCode="408"; 00680 } else { 00681 // Use cmi.interactions.n.type value to check the right dataelement format 00682 interactiontype = eval(subelement+'.type'); 00683 var nodes = new Array(); 00684 if (learner_response[interactiontype].delimiter != '') { 00685 nodes = value.split(learner_response[interactiontype].delimiter); 00686 } else { 00687 nodes[0] = value; 00688 } 00689 if ((nodes.length > 0) && (nodes.length <= learner_response[interactiontype].max)) { 00690 expression = new RegExp(learner_response[interactiontype].format); 00691 for (var i=0; (i < nodes.length) && (errorCode=="0"); i++) { 00692 if (typeof learner_response[interactiontype].delimiter2 != 'undefined') { 00693 values = nodes[i].split(learner_response[interactiontype].delimiter2); 00694 if (values.length == 2) { 00695 matches = values[0].match(expression); 00696 if (matches == null) { 00697 errorCode = "406"; 00698 } else { 00699 var expression2 = new RegExp(learner_response[interactiontype].format2); 00700 matches = values[1].match(expression2); 00701 if (matches == null) { 00702 errorCode = "406"; 00703 } 00704 } 00705 } else { 00706 errorCode = "406"; 00707 } 00708 } else { 00709 matches = nodes[i].match(expression); 00710 if (matches == null) { 00711 errorCode = "406"; 00712 } else { 00713 if ((nodes[i] != '') && (learner_response[interactiontype].unique)) { 00714 for (var j=0; (j<i) && (errorCode=="0"); j++) { 00715 if (nodes[i] == nodes[j]) { 00716 errorCode = "406"; 00717 } 00718 } 00719 } 00720 } 00721 } 00722 } 00723 } else if (nodes.length > learner_response[interactiontype].max) { 00724 errorCode = "351"; 00725 diagnostic = "Data Model Element Pattern Too Long"; 00726 } 00727 } 00728 break; 00729 case 'cmi.interactions.n.correct_responses.n.pattern': 00730 subel= subelement.split('.'); 00731 subel1= 'cmi.interactions.'+subel[2]; 00732 00733 if (typeof eval(subel1+'.type') == "undefined") { 00734 errorCode="408"; 00735 } else { 00736 // Use cmi.interactions.n.type value to check the right //dataelement format 00737 var interactiontype = eval(subel1+'.type'); 00738 var interactioncount = eval(parentelement+'._count'); 00739 // trap duplicate values, which is not allowed for type choice 00740 if (interactiontype == 'choice') { 00741 for (var i=0; (i < interactioncount) && (errorCode=="0"); i++) { 00742 if (eval(parentelement+'.N'+i+'.pattern') == value) { 00743 errorCode = "351"; 00744 } 00745 } 00746 } 00747 var nodes = new Array(); 00748 if (correct_responses[interactiontype].delimiter != '') { 00749 nodes = value.split(correct_responses[interactiontype].delimiter); 00750 } else { 00751 nodes[0] = value; 00752 } 00753 00754 if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) { 00755 errorCode = CRcheckValueNodes (element, interactiontype, nodes, value, errorCode); 00756 } else if (nodes.length > correct_responses[interactiontype].max) { 00757 errorCode = "351"; 00758 diagnostic = "Data Model Element Pattern Too Long"; 00759 } 00760 } 00761 break; 00762 } 00763 } 00764 } 00765 } 00766 //Store data 00767 if (errorCode == "0") { 00768 00769 if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") { 00770 range = eval('datamodel["'+elementmodel+'"].range'); 00771 ranges = range.split('#'); 00772 value = value*1.0; 00773 if (value >= ranges[0]) { 00774 if ((ranges[1] == '*') || (value <= ranges[1])) { 00775 eval(element+'=value;'); 00776 errorCode = "0"; 00777 <?php 00778 if (scorm_debugging($scorm)) { 00779 echo 'LogAPICall("SetValue", element, value, errorCode);'; 00780 } 00781 ?> 00782 return "true"; 00783 } else { 00784 errorCode = '407'; 00785 } 00786 } else { 00787 errorCode = '407'; 00788 } 00789 } else { 00790 eval(element+'=value;'); 00791 errorCode = "0"; 00792 <?php 00793 if (scorm_debugging($scorm)) { 00794 echo 'LogAPICall("SetValue", element, value, errorCode);'; 00795 } 00796 ?> 00797 return "true"; 00798 } 00799 } 00800 } else { 00801 errorCode = "406"; 00802 } 00803 } else { 00804 errorCode = "404"; 00805 } 00806 } else { 00807 errorCode = "401" 00808 } 00809 } else { 00810 errorCode = "351"; 00811 } 00812 } else { 00813 if (Terminated) { 00814 errorCode = "133"; 00815 } else { 00816 errorCode = "132"; 00817 } 00818 } 00819 <?php 00820 if (scorm_debugging($scorm)) { 00821 echo 'LogAPICall("SetValue", element, value, errorCode);'; 00822 } 00823 ?> 00824 return "false"; 00825 } 00826 00827 00828 function CRremovePrefixes (node) { 00829 // check for prefixes lang, case, order 00830 // case and then order 00831 var seenOrder = false; 00832 var seenCase = false; 00833 var seenLang = false; 00834 var errorCode = "0"; 00835 while (matches = node.match('^(\{(lang|case_matters|order_matters)=([^\}]+)\})')) { 00836 switch (matches[2]) { 00837 case 'lang': 00838 // check for language prefix on each node 00839 langmatches = node.match(CMILangcr); 00840 if (langmatches != null) { 00841 lang = langmatches[3]; 00842 // check that language string definition is valid 00843 if (lang.length > 0 && lang != undefined) { 00844 if (validLanguages[lang.toLowerCase()] == undefined) { 00845 errorCode = "406"; 00846 } 00847 } 00848 } 00849 seenLang = true; 00850 break; 00851 00852 case 'case_matters': 00853 // check for correct case answer 00854 if (! seenLang && ! seenOrder && ! seenCase) { 00855 if (matches[3] != 'true' && matches[3] != 'false') { 00856 errorCode = "406"; 00857 } 00858 } 00859 seenCase = true; 00860 break; 00861 00862 case 'order_matters': 00863 // check for correct case answer 00864 if (! seenCase && ! seenLang && ! seenOrder) { 00865 if (matches[3] != 'true' && matches[3] != 'false') { 00866 errorCode = "406"; 00867 } 00868 } 00869 seenOrder = true; 00870 break; 00871 00872 default: 00873 break; 00874 } 00875 node = node.substr(matches[1].length); 00876 } 00877 return {'errorCode': errorCode, 'node': node}; 00878 } 00879 00880 00881 function CRcheckValueNodes(element, interactiontype, nodes, value, errorCode) { 00882 expression = new RegExp(correct_responses[interactiontype].format); 00883 for (var i=0; (i < nodes.length) && (errorCode=="0"); i++) { 00884 if (interactiontype.match('^(fill-in|long-fill-in|matching|performance|sequencing)$')) { 00885 result = CRremovePrefixes(nodes[i]); 00886 errorCode = result.errorCode; 00887 nodes[i] = result.node; 00888 } 00889 00890 // check for prefix on each node 00891 if (correct_responses[interactiontype].pre != '') { 00892 matches = nodes[i].match(correct_responses[interactiontype].pre); 00893 if (matches != null) { 00894 nodes[i] = nodes[i].substr(matches[1].length); 00895 } 00896 } 00897 00898 if (correct_responses[interactiontype].delimiter2 != undefined) { 00899 values = nodes[i].split(correct_responses[interactiontype].delimiter2); 00900 if (values.length == 2) { 00901 matches = values[0].match(expression); 00902 if (matches == null) { 00903 errorCode = "406"; 00904 } else { 00905 var expression2 = new RegExp(correct_responses[interactiontype].format2); 00906 matches = values[1].match(expression2); 00907 if (matches == null) { 00908 errorCode = "406"; 00909 } 00910 } 00911 } else { 00912 errorCode = "406"; 00913 } 00914 } else { 00915 matches = nodes[i].match(expression); 00916 //if ((matches == null) || (matches.join('').length == 0)) { 00917 if ((matches == null && value != "")||(matches == null && interactiontype=="true-false")){ 00918 errorCode = "406"; 00919 } else { 00920 // numeric range - left must be <= right 00921 if (interactiontype == 'numeric' && nodes.length > 1) { 00922 if (parseFloat(nodes[0]) > parseFloat(nodes[1])) { 00923 errorCode = "406"; 00924 } 00925 } else { 00926 if ((nodes[i] != '') && (correct_responses[interactiontype].unique)) { 00927 for (var j=0; (j < i) && (errorCode=="0"); j++) { 00928 if (nodes[i] == nodes[j]) { 00929 errorCode = "406"; 00930 } 00931 } 00932 } 00933 } 00934 } 00935 } 00936 } // end of for each nodes 00937 return errorCode; 00938 } 00939 00940 00941 function Commit (param) { 00942 errorCode = "0"; 00943 if (param == "") { 00944 if ((Initialized) && (!Terminated)) { 00945 var AJAXResult = StoreData(cmi,false); 00946 <?php 00947 if (scorm_debugging($scorm)) { 00948 echo 'LogAPICall("Commit", "AJAXResult", AJAXResult, 0);'; 00949 } 00950 ?> 00951 var result = ('true' == AJAXResult) ? 'true' : 'false'; 00952 errorCode = ('true' == result)? '0' : '101'; // General exception for any AJAX fault 00953 <?php 00954 if (scorm_debugging($scorm)) { 00955 echo 'LogAPICall("Commit", "result", result, errorCode);'; 00956 } 00957 ?> 00958 if ('false' == result) { 00959 diagnostic = "Failure calling the Commit remote callback: the server replied with HTTP Status " + AJAXResult; 00960 } 00961 return result; 00962 } else { 00963 if (Terminated) { 00964 errorCode = "143"; 00965 } else { 00966 errorCode = "142"; 00967 } 00968 } 00969 } else { 00970 errorCode = "201"; 00971 } 00972 <?php 00973 if (scorm_debugging($scorm)) { 00974 echo 'LogAPICall("Commit", param, "", errorCode);'; 00975 } 00976 ?> 00977 return "false"; 00978 } 00979 00980 function GetLastError () { 00981 <?php 00982 if (scorm_debugging($scorm)) { 00983 echo 'LogAPICall("GetLastError", "", "", errorCode);'; 00984 } 00985 ?> 00986 return errorCode; 00987 } 00988 00989 function GetErrorString (param) { 00990 if (param != "") { 00991 var errorString = ""; 00992 switch(param) { 00993 case "0": 00994 errorString = "No error"; 00995 break; 00996 case "101": 00997 errorString = "General exception"; 00998 break; 00999 case "102": 01000 errorString = "General Inizialization Failure"; 01001 break; 01002 case "103": 01003 errorString = "Already Initialized"; 01004 break; 01005 case "104": 01006 errorString = "Content Instance Terminated"; 01007 break; 01008 case "111": 01009 errorString = "General Termination Failure"; 01010 break; 01011 case "112": 01012 errorString = "Termination Before Inizialization"; 01013 break; 01014 case "113": 01015 errorString = "Termination After Termination"; 01016 break; 01017 case "122": 01018 errorString = "Retrieve Data Before Initialization"; 01019 break; 01020 case "123": 01021 errorString = "Retrieve Data After Termination"; 01022 break; 01023 case "132": 01024 errorString = "Store Data Before Inizialization"; 01025 break; 01026 case "133": 01027 errorString = "Store Data After Termination"; 01028 break; 01029 case "142": 01030 errorString = "Commit Before Inizialization"; 01031 break; 01032 case "143": 01033 errorString = "Commit After Termination"; 01034 break; 01035 case "201": 01036 errorString = "General Argument Error"; 01037 break; 01038 case "301": 01039 errorString = "General Get Failure"; 01040 break; 01041 case "351": 01042 errorString = "General Set Failure"; 01043 break; 01044 case "391": 01045 errorString = "General Commit Failure"; 01046 break; 01047 case "401": 01048 errorString = "Undefinited Data Model"; 01049 break; 01050 case "402": 01051 errorString = "Unimplemented Data Model Element"; 01052 break; 01053 case "403": 01054 errorString = "Data Model Element Value Not Initialized"; 01055 break; 01056 case "404": 01057 errorString = "Data Model Element Is Read Only"; 01058 break; 01059 case "405": 01060 errorString = "Data Model Element Is Write Only"; 01061 break; 01062 case "406": 01063 errorString = "Data Model Element Type Mismatch"; 01064 break; 01065 case "407": 01066 errorString = "Data Model Element Value Out Of Range"; 01067 break; 01068 case "408": 01069 errorString = "Data Model Dependency Not Established"; 01070 break; 01071 } 01072 <?php 01073 if (scorm_debugging($scorm)) { 01074 echo 'LogAPICall("GetErrorString", param, errorString, 0);'; 01075 } 01076 ?> 01077 return errorString; 01078 } else { 01079 <?php 01080 if (scorm_debugging($scorm)) { 01081 echo 'LogAPICall("GetErrorString", param, "No error string found!", 0);'; 01082 } 01083 ?> 01084 return ""; 01085 } 01086 } 01087 01088 function GetDiagnostic (param) { 01089 if (diagnostic != "") { 01090 <?php 01091 if (scorm_debugging($scorm)) { 01092 echo 'LogAPICall("GetDiagnostic", param, diagnostic, 0);'; 01093 } 01094 ?> 01095 return diagnostic; 01096 } 01097 <?php 01098 if (scorm_debugging($scorm)) { 01099 echo 'LogAPICall("GetDiagnostic", param, param, 0);'; 01100 } 01101 ?> 01102 return param; 01103 } 01104 01105 function duplicatedID (element, parent, value) { 01106 var found = false; 01107 var elements = eval(parent+'._count'); 01108 for (var n=0;(n < elements) && (!found);n++) { 01109 if ((parent+'.N'+n+'.id' != element) && (eval(parent+'.N'+n+'.id') == value)) { 01110 found = true; 01111 } 01112 } 01113 return found; 01114 } 01115 01116 function duplicatedPA (element, parent, value) { 01117 var found = false; 01118 var elements = eval(parent+'._count'); 01119 for (var n=0;(n < elements) && (!found);n++) { 01120 if ((parent+'.N'+n+'.pattern' != element) && (eval(parent+'.N'+n+'.pattern') == value)) { 01121 found = true; 01122 } 01123 } 01124 return found; 01125 } 01126 01127 function getElementModel(element) { 01128 if (typeof datamodel[element] != "undefined") { 01129 return element; 01130 } else { 01131 var expression = new RegExp(CMIIndex,'g'); 01132 var elementmodel = String(element).replace(expression,'.n.'); 01133 if (typeof datamodel[elementmodel] != "undefined") { 01134 return elementmodel; 01135 } 01136 } 01137 return false; 01138 } 01139 01140 function AddTime (first, second) { 01141 <?php 01142 // if (scorm_debugging($scorm)) { 01143 // echo 'alert("AddTime: "+first+" + "+second);'; 01144 // } 01145 ?> 01146 var timestring = 'P'; 01147 var matchexpr = /^P((\d+)Y)?((\d+)M)?((\d+)D)?(T((\d+)H)?((\d+)M)?((\d+(\.\d{1,2})?)S)?)?$/; 01148 var firstarray = first.match(matchexpr); 01149 var secondarray = second.match(matchexpr); 01150 if ((firstarray != null) && (secondarray != null)) { 01151 var firstsecs=0; 01152 if(parseFloat(firstarray[13],10)>0){ firstsecs=parseFloat(firstarray[13],10); } 01153 var secondsecs=0; 01154 if(parseFloat(secondarray[13],10)>0){ secondsecs=parseFloat(secondarray[13],10); } 01155 var secs = firstsecs+secondsecs; //Seconds 01156 var change = Math.floor(secs/60); 01157 secs = Math.round((secs-(change*60))*100)/100; 01158 var firstmins=0; 01159 if(parseInt(firstarray[11],10)>0){ firstmins=parseInt(firstarray[11],10); } 01160 var secondmins=0; 01161 if(parseInt(secondarray[11],10)>0){ secondmins=parseInt(secondarray[11],10); } 01162 var mins = firstmins+secondmins+change; //Minutes 01163 change = Math.floor(mins / 60); 01164 mins = Math.round(mins-(change*60)); 01165 var firsthours=0; 01166 if(parseInt(firstarray[9],10)>0){ firsthours=parseInt(firstarray[9],10); } 01167 var secondhours=0; 01168 if(parseInt(secondarray[9],10)>0){ secondhours=parseInt(secondarray[9],10); } 01169 var hours = firsthours+secondhours+change; //Hours 01170 change = Math.floor(hours/24); 01171 hours = Math.round(hours-(change*24)); 01172 var firstdays=0; 01173 if(parseInt(firstarray[6],10)>0){ firstdays=parseInt(firstarray[6],10); } 01174 var seconddays=0; 01175 if(parseInt(secondarray[6],10)>0){ firstdays=parseInt(secondarray[6],10); } 01176 var days = Math.round(firstdays+seconddays+change); // Days 01177 var firstmonths=0; 01178 if(parseInt(firstarray[4],10)>0){ firstmonths=parseInt(firstarray[4],10); } 01179 var secondmonths=0; 01180 if(parseInt(secondarray[4],10)>0){ secondmonths=parseInt(secondarray[4],10); } 01181 var months = Math.round(firstmonths+secondmonths); 01182 var firstyears=0; 01183 if(parseInt(firstarray[2],10)>0){ firstyears=parseInt(firstarray[2],10); } 01184 var secondyears=0; 01185 if(parseInt(secondarray[2],10)>0){ secondyears=parseInt(secondarray[2],10); } 01186 var years = Math.round(firstyears+secondyears); 01187 } 01188 if (years > 0) { 01189 timestring += years + 'Y'; 01190 } 01191 if (months > 0) { 01192 timestring += months + 'M'; 01193 } 01194 if (days > 0) { 01195 timestring += days + 'D'; 01196 } 01197 if ((hours > 0) || (mins > 0) || (secs > 0)) { 01198 timestring += 'T'; 01199 if (hours > 0) { 01200 timestring += hours + 'H'; 01201 } 01202 if (mins > 0) { 01203 timestring += mins + 'M'; 01204 } 01205 if (secs > 0) { 01206 timestring += secs + 'S'; 01207 } 01208 } 01209 return timestring; 01210 } 01211 01212 function TotalTime() { 01213 var total_time = AddTime(cmi.total_time, cmi.session_time); 01214 return '&'+underscore('cmi.total_time')+'='+encodeURIComponent(total_time); 01215 } 01216 01217 function CollectData(data,parent) { 01218 var datastring = ''; 01219 for (property in data) { 01220 if (typeof data[property] == 'object') { 01221 datastring += CollectData(data[property],parent+'.'+property); 01222 } else { 01223 var element = parent+'.'+property; 01224 var expression = new RegExp(CMIIndexStore,'g'); 01225 var elementmodel = String(element).replace(expression,'.n.'); 01226 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") { 01227 if (eval('datamodel["'+elementmodel+'"].mod') != 'r') { 01228 var elementstring = '&'+underscore(element)+'='+encodeURIComponent(data[property]); 01229 if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") { 01230 if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property] || eval('typeof(datamodel["'+elementmodel+'"].defaultvalue)') != typeof(data[property])) { 01231 datastring += elementstring; 01232 } 01233 } else { 01234 datastring += elementstring; 01235 } 01236 } 01237 } 01238 } 01239 } 01240 return datastring; 01241 } 01242 01243 function StoreData(data,storetotaltime) { 01244 var datastring = ''; 01245 if (storetotaltime) { 01246 if (cmi.mode == 'normal') { 01247 if (cmi.credit == 'credit') { 01248 if ((cmi.completion_threshold != null) && (cmi.progress_measure != null)) { 01249 if (cmi.progress_measure >= cmi.completion_threshold) { 01250 cmi.completion_status = 'completed'; 01251 } else { 01252 cmi.completion_status = 'incomplete'; 01253 } 01254 } 01255 if ((cmi.scaled_passed_score != null) && (cmi.score.scaled != '')) { 01256 if (cmi.score.scaled >= cmi.scaled_passed_score) { 01257 cmi.success_status = 'passed'; 01258 } else { 01259 cmi.success_status = 'failed'; 01260 } 01261 } 01262 } 01263 } 01264 datastring += TotalTime(); 01265 } 01266 datastring += CollectData(data,'cmi'); 01267 var element = 'adl.nav.request'; 01268 var navrequest = eval(element) != datamodel[element].defaultvalue ? '&'+underscore(element)+'='+encodeURIComponent(eval(element)) : ''; 01269 datastring += navrequest; 01270 datastring += '&attempt=<?php echo $attempt ?>'; 01271 datastring += '&scoid=<?php echo $scoid ?>'; 01272 var myRequest = NewHttpReq(); 01273 var result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&a=<?php p($a) ?>&sesskey=<?php echo sesskey() ?>"+datastring); 01274 var results = String(result).split('\n'); 01275 if ((results.length > 2) && (navrequest != '')) { 01276 eval(results[2]); 01277 } 01278 errorCode = results[1]; 01279 return results[0]; 01280 } 01281 01282 this.Initialize = Initialize; 01283 this.Terminate = Terminate; 01284 this.GetValue = GetValue; 01285 this.SetValue = SetValue; 01286 this.Commit = Commit; 01287 this.GetLastError = GetLastError; 01288 this.GetErrorString = GetErrorString; 01289 this.GetDiagnostic = GetDiagnostic; 01290 this.version = '1.0'; 01291 } 01292 01293 var API_1484_11 = new SCORMapi1_3(); 01294 01295 <?php 01296 // pull in the debugging utilities 01297 if (scorm_debugging($scorm)) { 01298 include_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php'); 01299 echo 'AppendToLog("Moodle SCORM 1.3 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);'; 01300 }