[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/scorm/datamodels/ -> scorm_13.js (source)

   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 + "&currentorg=" + 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 + "&currentorg=" + 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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1