From 824c9dc7c6a852e67610329c79a8d378402215d6 Mon Sep 17 00:00:00 2001 From: wildgirl Date: Tue, 18 Apr 2006 18:04:30 +0000 Subject: [PATCH] resource.class.php changes: 1. Added logic to process repository paths. A repository path is marked with a # as the first character of the reference field. 2. Added a new error code for repository items not being deployed / bad reference. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ims.html change: Added a button to link to the repository browser. New files: finder.php – browser for the repository preview.php – cut down display routine from resource.class.php, forces sidemenu etc. repository_deploy.php – deploy for repository items (same results as deploy.php) repository_config.php (repository disabled by default) resize.js - for iframe resizing dummyapi.js - dummy SCORM API (Tom's work, with help from Andy) --- mod/resource/type/ims/deploy.php | 11 +- mod/resource/type/ims/dummyapi.js | 48 +++ mod/resource/type/ims/finder.php | 125 ++++++ mod/resource/type/ims/images/dir.gif | Bin 0 -> 394 bytes mod/resource/type/ims/images/ims.gif | Bin 0 -> 596 bytes mod/resource/type/ims/ims.html | 43 +- mod/resource/type/ims/preview.php | 195 +++++++++ mod/resource/type/ims/repository_config.php | 5 + mod/resource/type/ims/repository_deploy.php | 434 ++++++++++++++++++++ mod/resource/type/ims/resize.js | 78 ++++ mod/resource/type/ims/resource.class.php | 238 ++++++++--- 11 files changed, 1090 insertions(+), 87 deletions(-) create mode 100644 mod/resource/type/ims/dummyapi.js create mode 100644 mod/resource/type/ims/finder.php create mode 100644 mod/resource/type/ims/images/dir.gif create mode 100644 mod/resource/type/ims/images/ims.gif create mode 100644 mod/resource/type/ims/preview.php create mode 100644 mod/resource/type/ims/repository_config.php create mode 100644 mod/resource/type/ims/repository_deploy.php create mode 100644 mod/resource/type/ims/resize.js diff --git a/mod/resource/type/ims/deploy.php b/mod/resource/type/ims/deploy.php index d82d5eeae8..7f94afa0b6 100644 --- a/mod/resource/type/ims/deploy.php +++ b/mod/resource/type/ims/deploy.php @@ -100,6 +100,7 @@ /// Copy files $origin = $CFG->dataroot.'/'.$courseid.'/'.$file; + if (!is_file($origin)) { error (get_string('filenotfound' , 'error', $file)); } @@ -391,7 +392,13 @@ if (empty($obj_resource->href)) { $obj_resource->href = $resource['#']['file']['0']['@']['href']; } - + + /// Some packages are poorly done and use \ in roots. This makes them + /// not display since the URLs are not valid. + if (!empty($obj_resource->href)) { + $obj_resource->href = strtr($obj_resource->href, "\\", '/'); + } + /// Only if the resource has everything if (!empty($obj_resource->identifier) && !empty($obj_resource->href)) { @@ -416,4 +423,4 @@ return $resources; } -?> +?> \ No newline at end of file diff --git a/mod/resource/type/ims/dummyapi.js b/mod/resource/type/ims/dummyapi.js new file mode 100644 index 0000000000..2a956948eb --- /dev/null +++ b/mod/resource/type/ims/dummyapi.js @@ -0,0 +1,48 @@ +/* +* Dummy SCORM API +*/ + +function GenericAPIAdaptor(){ + this.LMSInitialize = LMSInitializeMethod; + this.LMSGetValue = LMSGetValueMethod; + this.LMSSetValue = LMSSetValueMethod; + this.LMSCommit = LMSCommitMethod; + this.LMSFinish = LMSFinishMethod; + this.LMSGetLastError = LMSGetLastErrorMethod; + this.LMSGetErrorString = LMSGetErrorStringMethod; + this.LMSGetDiagnostic = LMSGetDiagnosticMethod; +} +/* +* LMSInitialize. +*/ +function LMSInitializeMethod(parameter){return "true";} +/* +* LMSFinish. +*/ +function LMSFinishMethod(parameter){return "true";} +/* +* LMSCommit. +*/ +function LMSCommitMethod(parameter){return "true";} +/* +* LMSGetValue. +*/ +function LMSGetValueMethod(element){return "";} +/* +* LMSSetValue. +*/ +function LMSSetValueMethod(element, value){return "true";} +/* +* LMSGetLastErrorString +*/ +function LMSGetErrorStringMethod(errorCode){return "No error";} +/* +* LMSGetLastError +*/ +function LMSGetLastErrorMethod(){return "0";} +/* +* LMSGetDiagnostic +*/ +function LMSGetDiagnosticMethod(errorCode){return "No error. No errors were encountered. Successful API call.";} + +var API = new GenericAPIAdaptor; \ No newline at end of file diff --git a/mod/resource/type/ims/finder.php b/mod/resource/type/ims/finder.php new file mode 100644 index 0000000000..125b160bc7 --- /dev/null +++ b/mod/resource/type/ims/finder.php @@ -0,0 +1,125 @@ +repository/$directory"))) die("Can't open directory \"$CFG->repository/$directory\""); + +/// Loops though dir building a list of all relevent entries. Ignores files. +/// Asks for deploy if admin user AND no serialized file found. + while (false != ($filename = readdir($repository_dir))) { + if ($filename != '.' && $filename != '..' && is_dir("$CFG->repository/$directory/$filename")) { + unset($item); + $item->type = ''; + $item->name = 0; + $item->path = "$directory/$filename"; + + /// No manifest => normal, browsable directory. + if (!file_exists("$CFG->repository/$item->path/imsmanifest.xml")) { + $item->type = 'directory'; + $item->name = $filename; + } + /// Manifest, so IMS CP. + else { + if (file_exists("$CFG->repository/$item->path/moodle_inx.ser")) { + $item->type = 'deployed'; + $index = ims_load_serialized_file("$CFG->repository/$item->path/moodle_inx.ser"); + $item->name = $index['title']; + } + else { + $item->type = 'not deployed'; + $item->name = $filename; + } + } + $items[] = $item; + } + } + closedir($repository_dir); + +/// Prints the toolbar. + echo '
'; + ims_print_crumbtrail($directory); + +/// If admin, add extra buttons - redeploy & help. + if (isadmin()) { + echo " | ($strdeployall) "; + helpbutton("deploy", get_string("deployall", "resource"), "resource", true); + } + echo '
'; + +/// Prints the file list from list generated above. + echo '
"; + +/// Print footer and exit. + echo "
"; + exit; + +/// Generates the crumbtrial from $directory. Just splits up on '/'. + function ims_print_crumbtrail($directory) { + $strrepository = get_string('repository','resource'); + + $arr = explode('/', $directory); + $last = array_pop($arr); + if (trim($directory, '/') == '') { + echo $strrepository; + return; + } + else { + $output = "$strrepository » "; + } + $itemdir = ''; + foreach ($arr as $item) { + if ($item == '') continue; + $itemdir .= '/'.$item; + $output .= "$item » "; + } + $output .= $last; + echo $output; + } +?> diff --git a/mod/resource/type/ims/images/dir.gif b/mod/resource/type/ims/images/dir.gif new file mode 100644 index 0000000000000000000000000000000000000000..81230c66f7594e948effdfb459ed68992bb5ddbf GIT binary patch literal 394 zcmV;50d@XINk%w1VGsZi0M!5hR7pvkoSgre0Jm`f`07#r^_j-T#{cC2qk>1#w?zN{ zroEp>d~I$2{@#FqfdAkr#kp(9v#o|-LjS!0>+9?P?u+i%TD6lu|KS|}|IDzXiJXXQ z|Nnc8Yf^k-TJ+5)wv|->_yynJ-}&xts-3K@bs4&_z2MDau8dm$|GbrUZq$JS|NJ}h z-7b1iIRCH!|JV}$|L*zu|HP*x|I7gY@*mXH)YG>nj*gDXz{~&nrMH=Du8wW7jv4>_ zTmS$6A^8La6aYT}EC2ui01yBW000K3z@KnPEE3y#pmxWJR%MW3KcqsIt7Xa6(2k{I5!+46_phn zlMgf#C^-Q)J_MLPp_-d72qq*mEG+~qEHwu-n-i!cCKoj@H6aJHr!N8}0R}w2A-=P= o!U6*hHU>8>Ee{wlFu^Y?3{nOGI5-Xr3?AkZ5-tD~Nk>5dI|bFT&;S4c literal 0 HcmV?d00001 diff --git a/mod/resource/type/ims/images/ims.gif b/mod/resource/type/ims/images/ims.gif new file mode 100644 index 0000000000000000000000000000000000000000..6b387cb99dc51bdd291ac9f3dc7e38dd37d9121f GIT binary patch literal 596 zcmV-a0;~N;Nk%w1VGsZi0Oo%H{QCL;bnF0g-2imq4sFH&gZ=+*ZvVFc0E7Pjr2qhl z{{VdU|7!r$4-fa=)B=S5)Cvsu&A*N)MdO8J%%Y?2^!ZnLgYx(L^QL;lbaVi7;o4_s z_2=gRhX3&9<^X{A|E&P}KRo*K@5pCo{>cFvo&Pd}&)ixN7l7P-G+7OD(9z-W0CV>K zbOHam0PvGX5_sI#tgQdQ0L&B=@vw>i+ywuj0P$fF^ycJ9l+g9AIsa||0EPemdwT(R z?eXX5{r2=Bbj;(hs11w%?^sw$g2}!Q7UJyiTb$4B92fskQ2!GX|Iq;dk&!p8|0o|K9-d0R{U20RMAy0CnZ{W)RM3 zXvcDJOOVjcQc?hN+W>s}?uR|+T^QAz@l?WJxJeXlzU_30QFreoIOrMpZsO7F;qmEju?eetvEeMI}6UECf(3 z41IbrX?|@%PEQC6J^@l+40%F-KXVXg3PTSIa2feHE i6c8Z5j)@D0_Dn&6P{o=Ghy)!$LT5$DlPD1d0suQDLlw#Z literal 0 HcmV?d00001 diff --git a/mod/resource/type/ims/ims.html b/mod/resource/type/ims/ims.html index d99b34a25a..d60619d4fe 100644 --- a/mod/resource/type/ims/ims.html +++ b/mod/resource/type/ims/ims.html @@ -56,20 +56,24 @@ } function optiondeselector () { - currentstate = document.getElementById('menuparam_navigationmenu').value; - if (currentstate == 1) { - document.getElementById('menuparam_tableofcontents').value = 0; - document.getElementById('menuparam_skipsubmenus').value = 1; - document.getElementById('menuparam_navigationupbutton').value = 0; - document.getElementById('menuparam_tableofcontents').disabled = true; - document.getElementById('menuparam_skipsubmenus').disabled = true; - document.getElementById('menuparam_navigationupbutton').disabled = true; - } - else { - document.getElementById('menuparam_tableofcontents').disabled = false; - document.getElementById('menuparam_skipsubmenus').disabled = false; - document.getElementById('menuparam_navigationupbutton').disabled = false; - } + document.getElementById('menuparam_tableofcontents').disabled = false; + document.getElementById('menuparam_skipsubmenus').disabled = false; + document.getElementById('menuparam_navigationupbutton').disabled = false; + + if (document.getElementById('menuparam_navigationmenu').value == 1) { + document.getElementById('menuparam_tableofcontents').value = 0; + document.getElementById('menuparam_skipsubmenus').value = 1; + document.getElementById('menuparam_navigationupbutton').value = 0; + document.getElementById('menuparam_tableofcontents').disabled = true; + document.getElementById('menuparam_skipsubmenus').disabled = true; + document.getElementById('menuparam_navigationupbutton').disabled = true; + } + + if (document.getElementById('menuparam_navigationbuttons').value == 0) { + document.getElementById('menuparam_navigationupbutton').value = 0; + document.getElementById('menuparam_navigationupbutton').disabled = true; + } + } @@ -78,8 +82,11 @@ reference\" alt=\"reference\" />
"; button_to_popup_window ("/files/index.php?id=$form->course&choose=form.reference", "coursefiles", $strchooseafile, 500, 750, $strchooseafile); + if ($CFG->repositoryactivate) button_to_popup_window ("/mod/resource/type/ims/finder.php?directory=", "", $strbrowserepository, 500, 750, "Browse repository"); + ?> @@ -188,7 +195,7 @@ echo "\n"; echo "\n"; - echo 'Navigation Menu: '; + echo get_string('navigationmenu','resource').': '; echo "\n"; echo "\n"; choose_from_menu($yesno, "param_navigationmenu", $form->param_navigationmenu, "", "optiondeselector();"); @@ -209,13 +216,13 @@ echo get_string('navigationbuttons','resource').': '; echo "\n"; echo "\n"; - choose_from_menu($yesno, "param_navigationbuttons", $form->param_navigationbuttons, ""); + choose_from_menu($yesno, "param_navigationbuttons", $form->param_navigationbuttons, "", "optiondeselector();"); echo "\n"; echo "\n"; echo "\n"; echo "\n"; - echo 'Skip Submenu Entries: '; + echo get_string('skipsubmenus','resource').': '; echo "\n"; echo "\n"; choose_from_menu($yesno, "param_skipsubmenus", $form->param_skipsubmenus, ""); @@ -224,7 +231,7 @@ echo "\n"; echo "\n"; - echo 'Navigation \'Up\' Button: '; + echo get_string('navigationup','resource').': '; echo "\n"; echo "\n"; choose_from_menu($yesno, "param_navigationupbutton", $form->param_navigationupbutton, ""); diff --git a/mod/resource/type/ims/preview.php b/mod/resource/type/ims/preview.php new file mode 100644 index 0000000000..c931b919b2 --- /dev/null +++ b/mod/resource/type/ims/preview.php @@ -0,0 +1,195 @@ +repository . '/' . $directory; + +/// Confirm that the IMS package has been deployed. Hash not generated +/// for repository ones. + if (!file_exists($deploydir.'/moodle_inx.ser')) { + $errortext = "Not Deployed"; + print_header(); + print_simple_box_start('center', '60%'); + echo '

'.$errortext.'

'; + print_footer(); + exit; + } + +/// Load serialized IMS CP index to memory only once. + if (empty($items)) { + if (!$items = ims_load_serialized_file($deploydir.'/moodle_inx.ser')) { + error (get_string('errorreadingfile', 'error', 'moodle_inx.ser')); + } + } + +/// fast forward to first non-index page + while (empty($items[$page]->href)) $page++; + +/// Select encoding + $encoding = current_charset(); + +/// Select direction + if (get_string('thisdirection') == 'rtl') { + $direction = ' dir="rtl"'; + } else { + $direction = ' dir="ltr"'; + } + +/// The output here + + echo "\n"; + echo "\n"; + echo ''; + echo ''; + echo " + + + + "; + echo "Preview\n"; +/// moodle header + print_header(); +/// content - this produces everything else + +/// adds side navigation bar if needed. must also adjust width of iframe to accomodate + echo "
"; preview_buttons($directory, $items['title']); echo preview_ims_generate_toc($items, $directory); echo "
"; + + $fullurl = "$CFG->repositorywebroot/$directory/".$items[$page]->href; +/// prints iframe filled with $fullurl ;width:".$iframewidth." missing also height=\"420px\" + echo ""; //Content frame +/// moodle footer + echo ""; + + + /*** This function will generate the TOC file for the package + * from an specified parent to be used in the view of the IMS + */ + function preview_ims_generate_toc($items, $directory, $page=0) { + global $CFG; + + $contents = ''; + + /// Configure links behaviour + $fullurl = '?directory='.$directory.'&page='; + + /// Iterate over items to build the menu + $currlevel = 0; + $currorder = 0; + $endlevel = 0; + foreach ($items as $item) { + /// Convert text from UTF-8 to current charset if needed + if (empty($CFG->unicodedb)) { +//// $textlib = textlib_get_instance(); +//// $item->title = $textlib->convert($item->title, 'UTF-8', current_charset()); + } + /// Skip pages until we arrive to $page + if ($item->id < $page) { + continue; + } + /// Arrive to page, we store its level + if ($item->id == $page) { + $endlevel = $item->level; + continue; + } + /// We are after page and inside it (level > endlevel) + if ($item->id > $page && $item->level > $endlevel) { + /// Start Level + if ($item->level > $currlevel) { + $contents .= '
    '; + } + /// End Level + if ($item->level < $currlevel) { + $contents .= '
'; + } + /// Add item + $contents .= '
  • '; + if (!empty($item->href)) { + $contents .= ''.$item->title.''; + } else { + $contents .= $item->title; + } + $contents .= '
  • '; + $currlevel = $item->level; + continue; + } + /// We have reached endlevel, exit + if ($item->id > $page && $item->level <= $endlevel) { + break; + } + } + $contents .= ''; + + return $contents; + } + + function preview_buttons($directory, $name) { + $strchoose = get_string('choose','resource'); + $strback = get_string('back','resource'); + + $path = $directory; + $arr = explode('/', $directory); + array_pop($arr); + $directory = implode('/', $arr); + echo ""; + } + +?> \ No newline at end of file diff --git a/mod/resource/type/ims/repository_config.php b/mod/resource/type/ims/repository_config.php new file mode 100644 index 0000000000..76e1ed6c06 --- /dev/null +++ b/mod/resource/type/ims/repository_config.php @@ -0,0 +1,5 @@ +repositoryactivate = false; + $CFG->repository = "C:/public/www/html/ims_repository"; + $CFG->repositorywebroot = "/ims_repository"; +?> \ No newline at end of file diff --git a/mod/resource/type/ims/repository_deploy.php b/mod/resource/type/ims/repository_deploy.php new file mode 100644 index 0000000000..824b88a7ed --- /dev/null +++ b/mod/resource/type/ims/repository_deploy.php @@ -0,0 +1,434 @@ +repository/$file"; + $dir = opendir($dirpath); + while (false != ($filename = readdir($dir))) { + if ($filename != '.' && $filename != '..') { + $path = $dirpath.'/'.$filename; + if (is_dir($path) && file_exists("$path/imsmanifest.xml")) { + if ($all == 'force' || !file_exists("$path/moodle_inx.ser")) { + echo "DEPLOYING $path
    "; + ims_deploy_file($file.'/'.$filename, $all); + } + } + else if (is_dir($path)) { + echo "DEPLOYING $path
    "; + ims_deploy_folder($file.'/'.$filename, $all); + } + else { + echo "WONT DEPLOY $path
    "; + } + } + } + closedir($dir); + } + + function ims_deploy_file($file, $all='') { + global $CFG; + + /// Load request parameters + $resourcedir = "$CFG->repository/$file"; + + /// Get some needed strings + $strdeploy = get_string('deploy','resource'); + + /// + /// Main process, where everything is deployed + /// + + /// Load imsmanifest to memory (instead of using a full parser, + /// we are going to use xmlize intensively (because files aren't too big) + if (!$imsmanifest = ims_file2var ($resourcedir.'/imsmanifest.xml')) { + error (get_string ('errorreadingfile', 'error', 'imsmanifest.xml')); + } + + /// Check if the first line is a proper one, because I've seen some + /// packages with some control characters at the beginning. + $inixml = strpos($imsmanifest, '$item) { + if (!empty($resources[$item->identifierref])) { + $items[$key]->href = $resources[$item->identifierref]; + } else { + $items[$key]->href = ''; + } + } + + /// Create the INDEX (moodle_inx.ser - where the order of the pages are stored serialized) file + $items['title'] = $title; + if (!ims_save_serialized_file($resourcedir.'/moodle_inx.ser', $items)) { + error (get_string('errorcreatingfile', 'error', 'moodle_inx.ser')); + } + + /// No zip so no HASH + + /// End button (go to view mode) + echo '
    '; + print_simple_box(get_string('imspackageloaded', 'resource'), 'center'); + $link = $CFG->wwwroot.'/mod/resource/type/ims/preview.php'; + $options['directory'] = $file; + $label = get_string('viewims', 'resource'); + $method = 'get'; + print_single_button($link, $options, $label, $method); + echo '
    '; + + /// + /// End of main process, where everything is deployed + /// + } +/// +/// Common and useful functions used by the body of the script +/// + + /*** This function will return a tree of manifests (xmlized) as they are + * found and extracted from one manifest file. The first manifest in the + * will be the main one, while the rest will be submanifests. In the + * future (when IMS CP suppors it, external submanifest will be detected + * and retrieved here too). See IMS specs for more info. + */ + function ims_extract_manifests($data) { + + $manifest = new stdClass; //To store found manifests in a tree structure + + /// If there are some manifests + if (!empty($data['manifest'])) { + /// Add manifest to results array + $manifest->data = $data['manifest']; + /// Look for submanifests + $submanifests = ims_extract_submanifests($data['manifest']['#']); + /// Add them as child + if (!empty($submanifests)) { + $manifest->childs = $submanifests; + } + } + /// Return tree of manifests found + return $manifest; + } + + /* This function will search recursively for submanifests returning an array + * containing them (xmlized) following a tree structure. + */ + function ims_extract_submanifests($data) { + + $submanifests = array(); //To store found submanifests + + /// If there are some manifests + if (!empty($data['manifest'])) { + /// Get them + foreach ($data['manifest'] as $submanifest) { + /// Create a new submanifest object + $submanifest_object = new stdClass; + $submanifest_object->data = $submanifest; + /// Look for more submanifests recursively + $moresubmanifests = ims_extract_submanifests($submanifest['#']); + /// Add them to results array + if (!empty($moresubmanifests)) { + $submanifest_object->childs = moresubmanifests; + } + /// Add submanifest object to results array + $submanifests[] = $submanifest_object; + } + } + /// Return array of manifests found + return $submanifests; + } + + /*** This function will return an ordered and nested array of items + * that is a perfect representation of the prefered organization + */ + function ims_process_organizations($data) { + + global $CFG; + + /// Get the default organization + $default_organization = $data['@']['default']; + if ($CFG->debug) print_object('default_organization: '.$default_organization); + + /// Iterate (reverse) over organizations until we find the default one + if (empty($data['#']['organization'])) { /// Verify exists + return false; + } + $count_organizations = count($data['#']['organization']); + if ($CFG->debug) print_object('count_organizations: '.$count_organizations); + + $current_organization = $count_organizations - 1; + while ($current_organization >= 0) { + /// Load organization and check it + $organization = $data['#']['organization'][$current_organization]; + if ($organization['@']['identifier'] == $default_organization) { + $current_organization = -1; //Match, so exit. + } + $current_organization--; + } + + /// At this point we MUST have the final organization + if ($CFG->debug) print_object('final organization: '.$organization['#']['title'][0]['#']); + if (empty($organization)) { + return false; //Error, no organization found + } + + /// Extract items map from organization + $items = $organization['#']['item']; + if (empty($organization['#']['item'])) { /// Verify exists + return false; + } + if (!$itemmap = ims_process_items($items)) { + return false; //Error, no items found + } + return $itemmap; + } + + /*** This function gets the xmlized representation of the items + * and returns an array of items, ordered, with level and info + */ + function ims_process_items($items, $level = 1, $id = 1, $parent = 0) { + global $CFG; + + $itemmap = array(); + + /// Iterate over items from start to end + $count_items = count($items); + if ($CFG->debug) print_object('level '.$level.'-count_items: '.$count_items); + + $current_item = 0; + while ($current_item < $count_items) { + /// Load item + $item = $items[$current_item]; + $obj_item = new stdClass; + $obj_item->title = $item['#']['title'][0]['#']; + $obj_item->identifier = $item['@']['identifier']; + $obj_item->identifierref = $item['@']['identifierref']; + $obj_item->id = $id; + $obj_item->level = $level; + $obj_item->parent = $parent; + /// Only if the item has everything + if (!empty($obj_item->title) && + !empty($obj_item->identifier)) { + /// Add to itemmap + $itemmap[$id] = $obj_item; + if ($CFG->debug) print_object('level '.$level.'-id '.$id.'-parent '.$parent.'-'.$obj_item->title); + /// Counters go up + $id++; + /// Check for subitems recursively + $subitems = $item['#']['item']; + if (count($subitems)) { + /// Recursive call + $subitemmap = ims_process_items($subitems, $level+1, $id, $obj_item->id); + /// Add at the end and counters if necessary + if ($count_subitems = count($subitemmap)) { + foreach ($subitemmap as $subitem) { + /// Add the subitem to the main items array + $itemmap[$subitem->id] = $subitem; + /// Counters go up + $id++; + } + } + } + } + $current_item++; + } + return $itemmap; + } + + /*** This function will load an array of resources to be used later. + * Keys are identifiers + */ + function ims_load_resources($data, $manifest_base, $resources_base) { + global $CFG; + + $resources = array(); + + if (empty($data)) { /// Verify exists + return false; + } + $count_resources = count($data); + if ($CFG->debug) print_object('count_resources: '.$count_resources); + + $current_resource = 0; + while ($current_resource < $count_resources) { + /// Load resource + $resource = $data[$current_resource]; + + /// Create a new object resource + $obj_resource = new stdClass; + $obj_resource->identifier = $resource['@']['identifier']; + $obj_resource->resource_base = $resource['@']['xml:base']; + $obj_resource->href = $resource['@']['href']; + if (empty($obj_resource->href)) { + $obj_resource->href = $resource['#']['file']['0']['@']['href']; + } + + /// Some packages are poorly done and use \ in roots. This makes them + /// not display since the URLs are not valid. + if (!empty($obj_resource->href)) { + $obj_resource->href = strtr($obj_resource->href, "\\", '/'); + } + + /// Only if the resource has everything + if (!empty($obj_resource->identifier) && + !empty($obj_resource->href)) { + /// Add to resources (identifier as key) + /// Depending of $manifest_base, $resources_base and the particular + /// $resource_base variable, concatenate them to build the correct href + $href_base = ''; + if (!empty($manifest_base)) { + $href_base = $manifest_base; + } + if (!empty($resources_base)) { + $href_base .= $resources_base; + } + if (!empty($obj_resource->resource_base)) { + $href_base .= $obj_resource->resource_base; + } + $resources[$obj_resource->identifier] = $href_base.$obj_resource->href; + } + /// Counters go up + $current_resource++; + } + return $resources; + } + + /*** This function finds out the title of the resource from the XML. + * First 2 conditions cover nearly all cases. The third is a fair guess + * if no metadata is supplied. This is eventually saved in the serialized + * hash as $items['title']. + */ + function ims_get_cp_title($xmlobj) { + $md = $xmlobj['manifest']['#']['metadata']['0']['#']; + if (isset($md['imsmd:lom'])) { + return $md['imsmd:lom']['0']['#']['imsmd:general']['0']['#']['imsmd:title']['0']['#']['imsmd:langstring']['0']['#']; + } + else if (isset($md['imsmd:record'])) { + return $md['imsmd:record']['0']['#']['imsmd:general']['0']['#']['imsmd:title']['0']['#']['imsmd:langstring']['0']['#']; + } + else if ($title = $xmlobj['manifest']['#']['organizations']['0']['#']['organization']['0']['#']['title']['0']['#']) { + return $title; + } + else { + return "NO TITLE FOUND"; + } + } +?> \ No newline at end of file diff --git a/mod/resource/type/ims/resize.js b/mod/resource/type/ims/resize.js new file mode 100644 index 0000000000..c181eda81f --- /dev/null +++ b/mod/resource/type/ims/resize.js @@ -0,0 +1,78 @@ +/* + * This script resizes everything to fit the window. Maybe a fixed iframe + * would be better? + */ + +function getElementStyle(obj, prop, cssProp) { + ret = ''; + + if (obj.currentStyle) { + ret = obj.currentStyle[prop]; + } else if (document.defaultView && document.defaultView.getComputedStyle) { + var compStyle = document.defaultView.getComputedStyle(obj, null); + ret = compStyle.getPropertyValue(cssProp); + } + + if (ret == 'auto') ret = '0'; + return ret; +} + +function resizeiframe (hasNav) { + var winWidth = 0, winHeight = 0; + if( typeof( window.innerWidth ) == 'number' ) { + //Non-IE + winWidth = window.innerWidth; + winHeight = window.innerHeight; + } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) { + //IE 6+ in 'standards compliant mode' + winWidth = document.documentElement.clientWidth; + winHeight = document.documentElement.clientHeight; + } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) { + //IE 4 compatible + winWidth = document.body.clientWidth; + winHeight = document.body.clientHeight; + } + + var header = document.getElementById('header'); + var divs = document.getElementsByTagName('div'); + var n = divs.length; + + + var content = document.getElementById('content'); + var headerHeight = 0; + if (content) { + headerHeight = content.offsetTop; + } + + var footer = document.getElementById('footer'); + var imsnavbar = document.getElementById('ims-nav-bar'); + var footerHeight = 0; + var imsnavHeight = 0; + if (footer) { + footerHeight = footer.offsetHeight + parseInt(getElementStyle(footer, 'marginTop', 'margin-top')) + parseInt(getElementStyle(footer, 'marginBottom', 'margin-bottom')); + } + if (imsnavbar) { + imsnavHeight = imsnavbar.offsetHeight; + } + + var topMargin = parseInt(getElementStyle(document.getElementsByTagName('body')[0], 'marginTop', 'margin-top')); + var bottomMargin = parseInt(getElementStyle(document.getElementsByTagName('body')[0], 'marginBottom', 'margin-bottom')); + + var totalHeight = headerHeight + + footerHeight + + imsnavHeight + + topMargin + + bottomMargin; + + if (hasNav == true) { + var iframeWidth = (winWidth - 325)+'px'; + document.getElementById('ims-menudiv').style.height = (winHeight - totalHeight)+'px'; + } + else { + var iframeWidth = '99%'; + } + + document.getElementById('ims-contentframe').style.height = (winHeight - totalHeight)+'px'; + document.getElementById('ims-containerdiv').style.height = (winHeight - totalHeight)+'px'; + document.getElementById('ims-contentframe').style.width = iframeWidth; +} \ No newline at end of file diff --git a/mod/resource/type/ims/resource.class.php b/mod/resource/type/ims/resource.class.php index d349fbb7a0..0d516c876c 100644 --- a/mod/resource/type/ims/resource.class.php +++ b/mod/resource/type/ims/resource.class.php @@ -37,6 +37,7 @@ include_once ($CFG->libdir.'/filelib.php'); +require_once($CFG->dirroot.'/mod/resource/type/ims/repository_config.php'); /** * Extend the base resource class for ims resources @@ -62,6 +63,17 @@ class resource_ims extends resource_base { unset($this->parameters->navigationuparrow); $this->parameters->skipsubmenus = 1; } + + /// Is it in the repository material or not? + $file = $this->resource->reference; + if ($file[0] == '#') { + $this->isrepository = true; + $file = ltrim($file, '#'); + $this->resource->reference = $file; + } + else { + $this->isrepository = false; + } } /*** @@ -72,7 +84,7 @@ class resource_ims extends resource_base { /// set parameter defaults $alltextfield = new stdClass(); $alltextfield->tableofcontents=0; - $alltextfield->navigationbuttons=1; + $alltextfield->navigationbuttons=0; $alltextfield->navigationmenu=1; $alltextfield->skipsubmenus=1; $alltextfield->navigationupbutton=1; @@ -127,36 +139,52 @@ class resource_ims extends resource_base { * 2 = Zip file doesn't exist * 3 = Package not deployed. * 4 = Package has changed since deployed. + * If the IMS CP is one from the central repository, then we instead check + * with the following codes: + * 5 = Not deployed. Since repository is central must be admin to deploy so terminate */ function check4errors($file, $course, $resource) { - global $CFG; - $mimetype = mimeinfo("type", $file); - if ($mimetype != "application/zip") { - return 1; //Error - } - - /// Check if the uploaded file exists - if (!file_exists($CFG->dataroot.'/'.$course->id.'/'.$file)) { - return 2; //Error - } - - /// Calculate the path were the IMS package must be deployed - $deploydir = $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id; - - /// Confirm that the IMS package has been deployed. These files must exist if - /// the package is deployed: moodle_index.ser and moodle_hash.ser - if (!file_exists($deploydir.'/moodle_inx.ser') || - !file_exists($deploydir.'/moodle_hash.ser')) { - return 3; //Error + if ($this->isrepository) { + /// Calculate the path were the IMS package must be deployed + $deploydir = $CFG->repository . $file; + + /// Confirm that the IMS package has been deployed. These files must exist if + /// the package is deployed: moodle_index.ser and moodle_hash.ser + if (!file_exists($deploydir.'/moodle_inx.ser')) { + return 5; //Error + } } - - /// If teacheredit, make, hash check. It's the md5 of the name of the file - /// plus its size and modification date - if (isteacheredit($course->id)) { - if (!$this->checkpackagehash($file, $course, $resource)) { - return 4; + else { + /// Check for zip file type + $mimetype = mimeinfo("type", $file); + if ($mimetype != "application/zip") { + return 1; //Error + } + + /// Check if the uploaded file exists + if (!file_exists($CFG->dataroot.'/'.$course->id.'/'.$file)) { + return 2; //Error + } + + /// Calculate the path were the IMS package must be deployed + $deploydir = $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id; + + + /// Confirm that the IMS package has been deployed. These files must exist if + /// the package is deployed: moodle_index.ser and moodle_hash.ser + if (!file_exists($deploydir.'/moodle_inx.ser') || + !file_exists($deploydir.'/moodle_hash.ser')) { + return 3; //Error + } + + /// If teacheredit, make, hash check. It's the md5 of the name of the file + /// plus its size and modification date + if (isteacheredit($course->id)) { + if (!$this->checkpackagehash($file, $course, $resource)) { + return 4; + } } } @@ -243,20 +271,22 @@ class resource_ims extends resource_base { * Delete all the moddata files for the resource * @param resource object */ - function delete_instance($resource) { - + function delete_instance($resource) { + global $CFG; + + /// Delete moddata resource dir completely unless repository. + if (!$this->isrepository) { + $resource_dir = $CFG->dataroot.'/'.$resource->course.'/'.$CFG->moddata.'/resource/'.$resource->id; + if (file_exists($resource_dir)) { + if (!$status = fulldelete($resource_dir)) { + return false; + } + } + } - /// Delete moddata resource dir completely - $resource_dir = $CFG->dataroot.'/'.$resource->course.'/'.$CFG->moddata.'/resource/'.$resource->id; - if (file_exists($resource_dir)) { - if (!$status = fulldelete($resource_dir)) { - return false; - } - } - - return parent::delete_instance($resource); - } + return parent::delete_instance($resource); + } /** @@ -314,6 +344,8 @@ class resource_ims extends resource_base { $errortext = get_string('packagenotdeplyed','resource'); } else if ($errorcode == 4) { $errortext = get_string('packagechanged','resource'); + } else if ($errorcode == 5) { + $errortext = get_string('packagenotdeplyed','resource'); // no button though since from repository. } } /// Display the error and exit @@ -355,7 +387,12 @@ class resource_ims extends resource_base { /// Load serialized IMS CP index to memory only once. if (empty($items)) { - $resourcedir = $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id; + if (!$this->isrepository) { + $resourcedir = $CFG->dataroot.'/'.$course->id.'/'.$CFG->moddata.'/resource/'.$resource->id; + } + else { + $resourcedir = $CFG->repository . $resource->reference; + } if (!$items = ims_load_serialized_file($resourcedir.'/moodle_inx.ser')) { error (get_string('errorreadingfile', 'error', 'moodle_inx.ser')); } @@ -414,19 +451,76 @@ class resource_ims extends resource_base { echo "\n"; echo ''; echo ''; + if (!empty($this->parameters->navigationmenu)) { + $jsarg = 'true'; + } + else { + $jsarg = 'false'; + } + + /// The dummy LMS API hack to stop some SCORM packages giving errors. + echo ""; + + /// All this sets up script and style stuff to position and + /// resize the menus and stuff. The CSS is here because it + /// differs depending on some php variables. The javascript + /// uses resize.js. + echo " + + + + "; echo "{$course->shortname}: ".strip_tags(format_string($resource->name,true))."\n"; /// moodle header if ($resource->popup) { - print_header($pagetitle, $course->fullname.' : '.$resource->name); + //print_header($pagetitle, $course->fullname.' : '.$resource->name); + print_header(); } else { print_header($pagetitle, $course->fullname, "$this->navigation ".format_string($resource->name), "", "", true, update_module_button($cm->id, $course->id, $this->strresource), navmenu($course, $cm, "parent")); } /// content - this produces everything else $this->print_ims($cm, $course, $items, $resource, $page); - /// moodle footer - print_footer(); + /// moodle footer. no footer if it's in a popup - save space. + if ($resource->popup) { + echo ""; + } + else { + print_footer(); + } - /// log it. clearly only run once. + /// log it. add_to_log($course->id, "resource", "view", "view.php?id={$cm->id}", $resource->id, $cm->id); exit; } @@ -444,12 +538,18 @@ class resource_ims extends resource_base { global $CFG; /// Calculate the file.php correct url - if ($CFG->slasharguments) { - $fileurl = "{$CFG->wwwroot}/file.php/{$course->id}/{$CFG->moddata}/resource/{$resource->id}"; - } else { - $fileurl = "{$CFG->wwwroot}/file.php?file=/{$course->id}/{$CFG->moddata}/resource/{$resource->id}"; + if (!$this->isrepository) { + if ($CFG->slasharguments) { + $fileurl = "{$CFG->wwwroot}/file.php/{$course->id}/{$CFG->moddata}/resource/{$resource->id}"; + } else { + $fileurl = "{$CFG->wwwroot}/file.php?file=/{$course->id}/{$CFG->moddata}/resource/{$resource->id}"; + } + } + else { + $fileurl = $CFG->repositorywebroot . $resource->reference; } + /// Calculate the view.php correct url $viewurl = "view.php?id={$cm->id}&type={$resource->type}&frameset=toc&page="; @@ -493,17 +593,15 @@ class resource_ims extends resource_base { $this->print_nav($items, $resource, $page); } - /// adds side navigation bar if needed. must also adjust width of iframe to accomodate + echo '
    '; + /// adds side navigation bar if needed. must also adjust width of iframe to accomodate if (!empty($this->parameters->navigationmenu)) { - echo "
    "; $this->print_navmenu($items, $resource, $page); echo "
    "; - $iframewidth = "700px"; - } - else { - $iframewidth = "100%"; + echo "
    "; $this->print_navmenu($items, $resource, $page); echo "
    "; } /// prints iframe filled with $fullurl - echo ""; //Content frame + echo ""; //Content frame + echo '
    '; } /// Prints TOC @@ -521,12 +619,12 @@ class resource_ims extends resource_base { /// Prints side navigation menu. This is just the full TOC with no surround. function print_navmenu($items, $resource, $page=0) { - echo ims_generate_toc ($items, $resource, 0); + echo ims_generate_toc ($items, $resource, 0, $page); } /// Prints navigation bar at the top of the page. function print_nav($items, $resource, $page) { - echo '
    '; + echo '
    '; /// Prev button echo ims_get_prev_nav_button ($items, $this, $page); /// Up button @@ -536,7 +634,7 @@ class resource_ims extends resource_base { /// Main TOC button echo ims_get_toc_nav_button ($items, $this, $page); /// Footer - echo '
    '; + echo '
    '; } @@ -690,8 +788,9 @@ class resource_ims extends resource_base { /*** This function will generate the TOC file for the package * from an specified parent to be used in the view of the IMS + * Now hilights 'selected page' also. */ - function ims_generate_toc($items, $resource, $page=0) { + function ims_generate_toc($items, $resource, $page=0, $selected_page = -1) { global $CFG,$SESSION; $contents = ''; @@ -706,8 +805,8 @@ class resource_ims extends resource_base { foreach ($items as $item) { /// Convert text from UTF-8 to current charset if needed if (empty($CFG->unicodedb)) { - $textlib = textlib_get_instance(); - $item->title = $textlib->convert($item->title, 'UTF-8', current_charset()); +//// $textlib = textlib_get_instance(); +//// $item->title = $textlib->convert($item->title, 'UTF-8', current_charset()); } /// Skip pages until we arrive to $page if ($item->id < $page) { @@ -731,7 +830,9 @@ class resource_ims extends resource_base { /// Add item $contents .= '
  • '; if (!empty($item->href)) { + if ($item->id == $selected_page) $contents .= '
    '; $contents .= ''.$item->title.''; + if ($item->id == $selected_page) $contents .= '
    '; } else { $contents .= $item->title; } @@ -753,6 +854,7 @@ class resource_ims extends resource_base { * to show the previous button in the nav frame **/ function ims_get_prev_nav_button ($items, $resource_obj, $page) { + $strprevious = get_string("previous", "resource"); $cm = $resource_obj->cm; $resource = $resource_obj->resource; @@ -767,10 +869,10 @@ class resource_ims extends resource_base { } } - if ($page >= 0 ) { //0 and 1 pages haven't previous - $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\"><<"; + if ($page >= 1 ) { //0 and 1 pages haven't previous + $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\">$strprevious"; } else { - $contents .= '<<'; + $contents .= ''.$strprevious.''; } return $contents; @@ -780,6 +882,7 @@ class resource_ims extends resource_base { * to show the next button in the nav frame **/ function ims_get_next_nav_button ($items, $resource_obj, $page) { + $strnext = get_string("next", "resource"); $cm = $resource_obj->cm; $resource = $resource_obj->resource; @@ -795,9 +898,9 @@ class resource_ims extends resource_base { } if (!empty($items[$page])) { //If the next page exists - $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\">>>"; + $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\">$strnext"; } else { - $contents .= '>>'; + $contents .= ''.$strnext.''; } @@ -808,6 +911,7 @@ class resource_ims extends resource_base { * to show the up button in the nav frame **/ function ims_get_up_nav_button ($items, $resource_obj, $page) { + $strup = get_string("upbutton", "resource"); $cm = $resource_obj->cm; $resource = $resource_obj->resource; @@ -817,9 +921,9 @@ class resource_ims extends resource_base { if (!empty($resource_obj->parameters->navigationupbutton)) { if ($page > 1 && $items[$page]->parent > 0) { //If the page has parent $page = $items[$page]->parent; - $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\">∧"; + $contents .= "id}&type={$resource->type}&page={$page}&frameset=ims\" target=\"_parent\">$strup"; } else { - $contents .= ''; + $contents .= "$strup"; } } return $contents; -- 2.39.5