See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 class H5peditor { 4 5 private static $hasWYSIWYGEditor = array( 6 'H5P.CoursePresentation', 7 'H5P.InteractiveVideo', 8 'H5P.DragQuestion' 9 ); 10 11 public static $styles = array( 12 'libs/darkroom.css', 13 'styles/css/h5p-hub-client.css', 14 'styles/css/fonts.css', 15 'styles/css/application.css', 16 'styles/css/libs/zebra_datepicker.min.css' 17 ); 18 public static $scripts = array( 19 'scripts/h5p-hub-client.js', 20 'scripts/h5peditor.js', 21 'scripts/h5peditor-semantic-structure.js', 22 'scripts/h5peditor-editor.js', 23 'scripts/h5peditor-library-selector.js', 24 'scripts/h5peditor-fullscreen-bar.js', 25 'scripts/h5peditor-form.js', 26 'scripts/h5peditor-text.js', 27 'scripts/h5peditor-html.js', 28 'scripts/h5peditor-number.js', 29 'scripts/h5peditor-textarea.js', 30 'scripts/h5peditor-file-uploader.js', 31 'scripts/h5peditor-file.js', 32 'scripts/h5peditor-image.js', 33 'scripts/h5peditor-image-popup.js', 34 'scripts/h5peditor-av.js', 35 'scripts/h5peditor-group.js', 36 'scripts/h5peditor-boolean.js', 37 'scripts/h5peditor-list.js', 38 'scripts/h5peditor-list-editor.js', 39 'scripts/h5peditor-library.js', 40 'scripts/h5peditor-library-list-cache.js', 41 'scripts/h5peditor-select.js', 42 'scripts/h5peditor-selector-hub.js', 43 'scripts/h5peditor-selector-legacy.js', 44 'scripts/h5peditor-dimensions.js', 45 'scripts/h5peditor-coordinates.js', 46 'scripts/h5peditor-none.js', 47 'scripts/h5peditor-metadata.js', 48 'scripts/h5peditor-metadata-author-widget.js', 49 'scripts/h5peditor-metadata-changelog-widget.js', 50 'scripts/h5peditor-pre-save.js', 51 'ckeditor/ckeditor.js', 52 ); 53 private $h5p, $storage; 54 public $ajax, $ajaxInterface; 55 56 /** 57 * Constructor for the core editor library. 58 * 59 * @param \H5PCore $h5p Instance of core 60 * @param \H5peditorStorage $storage Instance of h5peditor storage interface 61 * @param \H5PEditorAjaxInterface $ajaxInterface Instance of h5peditor ajax 62 * interface 63 */ 64 function __construct($h5p, $storage, $ajaxInterface) { 65 $this->h5p = $h5p; 66 $this->storage = $storage; 67 $this->ajaxInterface = $ajaxInterface; 68 $this->ajax = new H5PEditorAjax($h5p, $this, $storage); 69 } 70 71 /** 72 * Get list of libraries. 73 * 74 * @return array 75 */ 76 public function getLibraries() { 77 if (isset($_POST['libraries'])) { 78 // Get details for the specified libraries. 79 $libraries = array(); 80 foreach ($_POST['libraries'] as $libraryName) { 81 $matches = array(); 82 preg_match_all('/(.+)\s(\d+)\.(\d+)$/', $libraryName, $matches); 83 if ($matches && $matches[1] && $matches[2] && $matches[3]) { 84 $libraries[] = (object) array( 85 'uberName' => $libraryName, 86 'name' => $matches[1][0], 87 'majorVersion' => $matches[2][0], 88 'minorVersion' => $matches[3][0] 89 ); 90 } 91 } 92 } 93 94 $libraries = $this->storage->getLibraries(!isset($libraries) ? NULL : $libraries); 95 96 if ($this->h5p->development_mode & H5PDevelopment::MODE_LIBRARY) { 97 $devLibs = $this->h5p->h5pD->getLibraries(); 98 } 99 100 for ($i = 0, $s = count($libraries); $i < $s; $i++) { 101 if (!empty($devLibs)) { 102 $lid = $libraries[$i]->name . ' ' . $libraries[$i]->majorVersion . '.' . $libraries[$i]->minorVersion; 103 if (isset($devLibs[$lid])) { 104 // Replace library with devlib 105 $isOld = !empty($libraries[$i]->isOld) && $libraries[$i]->isOld === TRUE; 106 $libraries[$i] = (object) array( 107 'uberName' => $lid, 108 'name' => $devLibs[$lid]['machineName'], 109 'title' => $devLibs[$lid]['title'], 110 'majorVersion' => $devLibs[$lid]['majorVersion'], 111 'minorVersion' => $devLibs[$lid]['minorVersion'], 112 'runnable' => $devLibs[$lid]['runnable'], 113 'restricted' => $libraries[$i]->restricted, 114 'tutorialUrl' => $libraries[$i]->tutorialUrl, 115 'metadataSettings' => $devLibs[$lid]['metadataSettings'], 116 ); 117 if ($isOld) { 118 $libraries[$i]->isOld = TRUE; 119 } 120 } 121 } 122 123 // Some libraries rely on an LRS to work and must be enabled manually 124 if (in_array($libraries[$i]->name, array('H5P.Questionnaire', 'H5P.FreeTextQuestion')) && 125 !$this->h5p->h5pF->getOption('enable_lrs_content_types')) { 126 $libraries[$i]->restricted = TRUE; 127 } 128 } 129 130 return $libraries; 131 } 132 133 /** 134 * Get translations for a language for a list of libraries 135 * 136 * @param array $libraries An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion> 137 * @param string $language_code 138 * @return array 139 */ 140 public function getTranslations($libraries, $language_code) { 141 return $this->ajaxInterface->getTranslations($libraries, $language_code); 142 } 143 144 /** 145 * Move uploaded files, remove old files and update library usage. 146 * 147 * @param stdClass $content 148 * @param array $newLibrary 149 * @param array $newParameters 150 * @param array $oldLibrary 151 * @param array $oldParameters 152 */ 153 public function processParameters($content, $newLibrary, $newParameters, $oldLibrary = NULL, $oldParameters = NULL) { 154 $newFiles = array(); 155 $oldFiles = array(); 156 157 // Keep track of current content ID (used when processing files) 158 $this->content = $content; 159 160 // Find new libraries/content dependencies and files. 161 // Start by creating a fake library field to process. This way we get all the dependencies of the main library as well. 162 $field = (object) array( 163 'type' => 'library' 164 ); 165 $libraryParams = (object) array( 166 'library' => H5PCore::libraryToString($newLibrary), 167 'params' => $newParameters 168 ); 169 $this->processField($field, $libraryParams, $newFiles); 170 171 if ($oldLibrary !== NULL) { 172 // Find old files and libraries. 173 $this->processSemantics($oldFiles, $this->h5p->loadLibrarySemantics($oldLibrary['name'], $oldLibrary['majorVersion'], $oldLibrary['minorVersion']), $oldParameters); 174 175 // Remove old files. 176 for ($i = 0, $s = count($oldFiles); $i < $s; $i++) { 177 if (!in_array($oldFiles[$i], $newFiles) && 178 preg_match('/^(\w+:\/\/|\.\.\/)/i', $oldFiles[$i]) === 0) { 179 $this->h5p->fs->removeContentFile($oldFiles[$i], $content); 180 // (optionally we could just have marked them as tmp files) 181 } 182 } 183 } 184 } 185 186 /** 187 * Recursive function that moves the new files in to the h5p content folder and generates a list over the old files. 188 * Also locates all the librares. 189 * 190 * @param array $files 191 * @param array $libraries 192 * @param array $semantics 193 * @param array $params 194 */ 195 private function processSemantics(&$files, $semantics, &$params) { 196 for ($i = 0, $s = count($semantics); $i < $s; $i++) { 197 $field = $semantics[$i]; 198 if (!isset($params->{$field->name})) { 199 continue; 200 } 201 $this->processField($field, $params->{$field->name}, $files); 202 } 203 } 204 205 /** 206 * Process a single field. 207 * 208 * @staticvar string $h5peditor_path 209 * @param object $field 210 * @param mixed $params 211 * @param array $files 212 */ 213 private function processField(&$field, &$params, &$files) { 214 switch ($field->type) { 215 case 'file': 216 case 'image': 217 if (isset($params->path)) { 218 $this->processFile($params, $files); 219 220 // Process original image 221 if (isset($params->originalImage) && isset($params->originalImage->path)) { 222 $this->processFile($params->originalImage, $files); 223 } 224 } 225 break; 226 227 case 'video': 228 case 'audio': 229 if (is_array($params)) { 230 for ($i = 0, $s = count($params); $i < $s; $i++) { 231 $this->processFile($params[$i], $files); 232 } 233 } 234 break; 235 236 case 'library': 237 if (isset($params->library) && isset($params->params)) { 238 $library = H5PCore::libraryFromString($params->library); 239 $semantics = $this->h5p->loadLibrarySemantics($library['machineName'], $library['majorVersion'], $library['minorVersion']); 240 241 // Process parameters for the library. 242 $this->processSemantics($files, $semantics, $params->params); 243 } 244 break; 245 246 case 'group': 247 if (isset($params)) { 248 $isSubContent = isset($field->isSubContent) && $field->isSubContent == TRUE; 249 250 if (count($field->fields) == 1 && !$isSubContent) { 251 $params = (object) array($field->fields[0]->name => $params); 252 } 253 $this->processSemantics($files, $field->fields, $params); 254 } 255 break; 256 257 case 'list': 258 if (is_array($params)) { 259 for ($j = 0, $t = count($params); $j < $t; $j++) { 260 $this->processField($field->field, $params[$j], $files); 261 } 262 } 263 break; 264 } 265 } 266 267 /** 268 * @param mixed $params 269 * @param array $files 270 */ 271 private function processFile(&$params, &$files) { 272 if (preg_match('/^https?:\/\//', $params->path)) { 273 return; // Skip external files 274 } 275 276 // Remove temporary files suffix 277 if (substr($params->path, -4, 4) === '#tmp') { 278 $params->path = substr($params->path, 0, strlen($params->path) - 4); 279 } 280 281 // File could be copied from another content folder. 282 $matches = array(); 283 if (preg_match($this->h5p->relativePathRegExp, $params->path, $matches)) { 284 285 // Create a copy of the file 286 $this->h5p->fs->cloneContentFile($matches[5], $matches[4], $this->content); 287 288 // Update Params with correct filename 289 $params->path = $matches[5]; 290 } 291 else { 292 // Check if file exists in content folder 293 $fileId = $this->h5p->fs->getContentFile($params->path, $this->content); 294 if ($fileId) { 295 // Mark the file as a keeper 296 $this->storage->keepFile($fileId); 297 } 298 else { 299 // File is not in content folder, try to copy it from the editor tmp dir 300 // to content folder. 301 $this->h5p->fs->cloneContentFile($params->path, 'editor', $this->content); 302 // (not removed in case someone has copied it) 303 // (will automatically be removed after 24 hours) 304 } 305 } 306 307 $files[] = $params->path; 308 } 309 310 /** 311 * TODO: Consider moving to core. 312 */ 313 public function getLibraryLanguage($machineName, $majorVersion, $minorVersion, $languageCode) { 314 if ($this->h5p->development_mode & H5PDevelopment::MODE_LIBRARY) { 315 // Try to get language development library first. 316 $language = $this->h5p->h5pD->getLanguage($machineName, $majorVersion, $minorVersion, $languageCode); 317 } 318 319 if (isset($language) === FALSE) { 320 $language = $this->storage->getLanguage($machineName, $majorVersion, $minorVersion, $languageCode); 321 } 322 323 return ($language === FALSE ? NULL : $language); 324 } 325 326 /** 327 * Return all libraries used by the given editor library. 328 * 329 * @param string $machineName Library identfier part 1 330 * @param int $majorVersion Library identfier part 2 331 * @param int $minorVersion Library identfier part 3 332 */ 333 public function findEditorLibraries($machineName, $majorVersion, $minorVersion) { 334 $library = $this->h5p->loadLibrary($machineName, $majorVersion, $minorVersion); 335 $dependencies = array(); 336 $this->h5p->findLibraryDependencies($dependencies, $library); 337 338 // Load addons for wysiwyg editors 339 if (in_array($machineName, self::$hasWYSIWYGEditor)) { 340 $addons = $this->h5p->h5pF->loadAddons(); 341 foreach ($addons as $addon) { 342 $key = 'editor-' . $addon['machineName']; 343 $dependencies[$key]['weight'] = sizeof($dependencies)+1; 344 $dependencies[$key]['type'] = 'editor'; 345 $dependencies[$key]['library'] = $addon; 346 } 347 } 348 349 // Order dependencies by weight 350 $orderedDependencies = array(); 351 for ($i = 1, $s = count($dependencies); $i <= $s; $i++) { 352 foreach ($dependencies as $dependency) { 353 if ($dependency['weight'] === $i && $dependency['type'] === 'editor') { 354 // Only load editor libraries. 355 $dependency['library']['id'] = $dependency['library']['libraryId']; 356 $orderedDependencies[$dependency['library']['libraryId']] = $dependency['library']; 357 break; 358 } 359 } 360 } 361 362 return $orderedDependencies; 363 } 364 365 /** 366 * Get all scripts, css and semantics data for a library 367 * 368 * @param string $machineName Library name 369 * @param int $majorVersion 370 * @param int $minorVersion 371 * @param string $prefix Optional part to add between URL and asset path 372 * @param string $fileDir Optional file dir to read files from 373 * 374 * @return array Libraries that was requested 375 */ 376 public function getLibraryData($machineName, $majorVersion, $minorVersion, $languageCode, $prefix = '', $fileDir = '', $defaultLanguage) { 377 $libraryData = new stdClass(); 378 379 $library = $this->h5p->loadLibrary($machineName, $majorVersion, $minorVersion); 380 381 // Include name and version in data object for convenience 382 $libraryData->name = $machineName; 383 $libraryData->version = (object) array('major' => $majorVersion, 'minor' => $minorVersion); 384 $libraryData->title = $library['title']; 385 386 $libraryData->upgradesScript = $this->h5p->fs->getUpgradeScript($machineName, $majorVersion, $minorVersion); 387 if ($libraryData->upgradesScript !== NULL) { 388 // If valid add URL prefix 389 $libraryData->upgradesScript = $this->h5p->url . $prefix . $libraryData->upgradesScript; 390 } 391 392 $libraries = $this->findEditorLibraries($machineName, $majorVersion, $minorVersion); 393 $libraryData->semantics = $this->h5p->loadLibrarySemantics($machineName, $majorVersion, $minorVersion); 394 $libraryData->language = $this->getLibraryLanguage($machineName, $majorVersion, $minorVersion, $languageCode); 395 $libraryData->defaultLanguage = empty($defaultLanguage) ? NULL : $this->getLibraryLanguage($machineName, $majorVersion, $minorVersion, $defaultLanguage); 396 $libraryData->languages = $this->storage->getAvailableLanguages($machineName, $majorVersion, $minorVersion); 397 398 // Temporarily disable asset aggregation 399 $aggregateAssets = $this->h5p->aggregateAssets; 400 $this->h5p->aggregateAssets = FALSE; 401 // This is done to prevent files being loaded multiple times due to how 402 // the editor works. 403 404 // Get list of JS and CSS files that belongs to the dependencies 405 $files = $this->h5p->getDependenciesFiles($libraries, $prefix); 406 $libraryName = H5PCore::libraryToString(compact('machineName', 'majorVersion', 'minorVersion'), true); 407 if ($this->hasPresave($libraryName) === true) { 408 $this->addPresaveFile($files, $library, $prefix); 409 } 410 $this->storage->alterLibraryFiles($files, $libraries); 411 412 // Restore asset aggregation setting 413 $this->h5p->aggregateAssets = $aggregateAssets; 414 415 // Create base URL 416 $url = $this->h5p->url; 417 418 // Javascripts 419 if (!empty($files['scripts'])) { 420 foreach ($files['scripts'] as $script) { 421 if (preg_match('/:\/\//', $script->path) === 1) { 422 // External file 423 $libraryData->javascript[] = $script->path . $script->version; 424 } 425 else { 426 // Local file 427 $path = $url . $script->path; 428 if (!isset($this->h5p->h5pD)) { 429 $path .= $script->version; 430 } 431 $libraryData->javascript[] = $path; 432 } 433 } 434 } 435 436 // Stylesheets 437 if (!empty($files['styles'])) { 438 foreach ($files['styles'] as $css) { 439 if (preg_match('/:\/\//', $css->path) === 1) { 440 // External file 441 $libraryData->css[] = $css->path . $css->version; 442 } 443 else { 444 // Local file 445 $path = $url . $css->path; 446 if (!isset($this->h5p->h5pD)) { 447 $path .= $css->version; 448 } 449 $libraryData->css[] = $path; 450 } 451 } 452 } 453 454 $translations = array(); 455 // Add translations for libraries. 456 foreach ($libraries as $library) { 457 if (empty($library['semantics'])) { 458 $translation = $this->getLibraryLanguage($library['machineName'], $library['majorVersion'], $library['minorVersion'], $languageCode); 459 460 // If translation was not found, and this is not the English one, try to load 461 // the English translation 462 if ($translation === NULL && $languageCode !== 'en') { 463 $translation = $this->getLibraryLanguage($library['machineName'], $library['majorVersion'], $library['minorVersion'], 'en'); 464 } 465 466 if ($translation !== NULL) { 467 $translations[$library['machineName']] = json_decode($translation); 468 } 469 } 470 } 471 472 $libraryData->translations = $translations; 473 474 return $libraryData; 475 } 476 477 /** 478 * This function will prefix all paths within a CSS file. 479 * Copied from Drupal 6. 480 * 481 * @staticvar type $_base 482 * @param type $matches 483 * @param type $base 484 * @return type 485 */ 486 public static function buildCssPath($matches, $base = NULL) { 487 static $_base; 488 // Store base path for preg_replace_callback. 489 if (isset($base)) { 490 $_base = $base; 491 } 492 493 // Prefix with base and remove '../' segments where possible. 494 $path = $_base . $matches[1]; 495 $last = ''; 496 while ($path != $last) { 497 $last = $path; 498 $path = preg_replace('`(^|/)(?!\.\./)([^/]+)/\.\./`', '$1', $path); 499 } 500 return 'url('. $path .')'; 501 } 502 503 /** 504 * Gets content type cache, applies user specific properties and formats 505 * as camelCase. 506 * 507 * @return array $libraries Cached libraries from the H5P Hub with user specific 508 * permission properties 509 */ 510 public function getUserSpecificContentTypeCache() { 511 $cached_libraries = $this->ajaxInterface->getContentTypeCache(); 512 513 // Check if user has access to install libraries 514 $libraries = array(); 515 foreach ($cached_libraries as &$result) { 516 // Check if user can install content type 517 $result->restricted = !$this->canInstallContentType($result); 518 519 // Formats json 520 $libraries[] = $this->getCachedLibsMap($result); 521 } 522 523 return $libraries; 524 } 525 526 public function canInstallContentType($contentType) { 527 $canInstallAll = $this->h5p->h5pF->hasPermission(H5PPermission::UPDATE_LIBRARIES); 528 $canInstallRecommended = $this->h5p->h5pF->hasPermission(H5PPermission::INSTALL_RECOMMENDED); 529 530 return $canInstallAll || $contentType->is_recommended && $canInstallRecommended; 531 } 532 533 /** 534 * Gets local and external libraries data with metadata to display 535 * all libraries that are currently available for the user. 536 * 537 * @return array $libraries Latest local and external libraries data with 538 * user specific permissions 539 */ 540 public function getLatestGlobalLibrariesData() { 541 $latest_local_libraries = $this->ajaxInterface->getLatestLibraryVersions(); 542 $cached_libraries = $this->getUserSpecificContentTypeCache(); 543 $this->mergeLocalLibsIntoCachedLibs($latest_local_libraries, $cached_libraries); 544 return $cached_libraries; 545 } 546 547 548 /** 549 * Extract library properties from cached library so they are ready to be 550 * returned as JSON 551 * 552 * @param object $cached_library A single library from the content type cache 553 * 554 * @return array A map containing the necessary properties for a cached 555 * library to send to the front-end 556 */ 557 public function getCachedLibsMap($cached_library) { 558 $restricted = isset($cached_library->restricted) ? $cached_library->restricted : FALSE; 559 560 // Add mandatory fields 561 $lib = array( 562 'id' => intval($cached_library->id), 563 'machineName' => $cached_library->machine_name, 564 'majorVersion' => intval( $cached_library->major_version), 565 'minorVersion' => intval($cached_library->minor_version), 566 'patchVersion' => intval($cached_library->patch_version), 567 'h5pMajorVersion' => intval($cached_library->h5p_major_version), 568 'h5pMinorVersion' => intval($cached_library->h5p_minor_version), 569 'title' => $cached_library->title, 570 'summary' => $cached_library->summary, 571 'description' => $cached_library->description, 572 'icon' => $cached_library->icon, 573 'createdAt' => intval($cached_library->created_at), 574 'updatedAt' => intval($cached_library->updated_at), 575 'isRecommended' => $cached_library->is_recommended != 0, 576 'popularity' => intval($cached_library->popularity), 577 'screenshots' => json_decode($cached_library->screenshots), 578 'license' => json_decode($cached_library->license), 579 'owner' => $cached_library->owner, 580 'installed' => FALSE, 581 'isUpToDate' => FALSE, 582 'restricted' => $restricted, 583 'canInstall' => !$restricted 584 ); 585 586 // Add optional fields 587 if (!empty($cached_library->categories)) { 588 $lib['categories'] = json_decode($cached_library->categories); 589 } 590 if (!empty($cached_library->keywords)) { 591 $lib['keywords'] = json_decode($cached_library->keywords); 592 } 593 if (!empty($cached_library->tutorial)) { 594 $lib['tutorial'] = $cached_library->tutorial; 595 } 596 if (!empty($cached_library->example)) { 597 $lib['example'] = $cached_library->example; 598 } 599 600 return $lib; 601 } 602 603 604 /** 605 * Merge local libraries into cached libraries so that local libraries will 606 * get supplemented with the additional info from externally cached libraries. 607 * 608 * Also sets whether a given cached library is installed and up to date with 609 * the locally installed libraries 610 * 611 * @param array $local_libraries Locally installed libraries 612 * @param array $cached_libraries Cached libraries from the H5P hub 613 */ 614 public function mergeLocalLibsIntoCachedLibs($local_libraries, &$cached_libraries) { 615 $can_create_restricted = $this->h5p->h5pF->hasPermission(H5PPermission::CREATE_RESTRICTED); 616 617 // Add local libraries to supplement content type cache 618 foreach ($local_libraries as $local_lib) { 619 $is_local_only = TRUE; 620 $icon_path = NULL; 621 622 // Check if icon is available locally: 623 if ($local_lib->has_icon) { 624 // Create path to icon: 625 $library_folder = H5PCore::libraryToString(array( 626 'machineName' => $local_lib->machine_name, 627 'majorVersion' => $local_lib->major_version, 628 'minorVersion' => $local_lib->minor_version 629 ), TRUE); 630 $icon_path = $this->h5p->h5pF->getLibraryFileUrl($library_folder, 'icon.svg'); 631 } 632 633 foreach ($cached_libraries as &$cached_lib) { 634 // Determine if library is local 635 $is_matching_library = $cached_lib['machineName'] === $local_lib->machine_name; 636 if ($is_matching_library) { 637 $is_local_only = FALSE; 638 639 // Set icon if it exists locally 640 if (isset($icon_path)) { 641 $cached_lib['icon'] = $icon_path; 642 } 643 644 // Set local properties 645 $cached_lib['installed'] = TRUE; 646 $cached_lib['restricted'] = $can_create_restricted ? FALSE 647 : ($local_lib->restricted ? TRUE : FALSE); 648 649 // Set local version 650 $cached_lib['localMajorVersion'] = (int) $local_lib->major_version; 651 $cached_lib['localMinorVersion'] = (int) $local_lib->minor_version; 652 $cached_lib['localPatchVersion'] = (int) $local_lib->patch_version; 653 654 // Determine if library is newer or same as cache 655 $major_is_updated = 656 $cached_lib['majorVersion'] < $cached_lib['localMajorVersion']; 657 658 $minor_is_updated = 659 $cached_lib['majorVersion'] === $cached_lib['localMajorVersion'] && 660 $cached_lib['minorVersion'] < $cached_lib['localMinorVersion']; 661 662 $patch_is_updated = 663 $cached_lib['majorVersion'] === $cached_lib['localMajorVersion'] && 664 $cached_lib['minorVersion'] === $cached_lib['localMinorVersion'] && 665 $cached_lib['patchVersion'] <= $cached_lib['localPatchVersion']; 666 667 $is_updated_library = 668 $major_is_updated || 669 $minor_is_updated || 670 $patch_is_updated; 671 672 if ($is_updated_library) { 673 $cached_lib['isUpToDate'] = TRUE; 674 } 675 } 676 } 677 678 // Add minimal data to display local only libraries 679 if ($is_local_only) { 680 $local_only_lib = array( 681 'id' => (int) $local_lib->id, 682 'machineName' => $local_lib->machine_name, 683 'title' => $local_lib->title, 684 'description' => '', 685 'majorVersion' => (int) $local_lib->major_version, 686 'minorVersion' => (int) $local_lib->minor_version, 687 'patchVersion' => (int) $local_lib->patch_version, 688 'localMajorVersion' => (int) $local_lib->major_version, 689 'localMinorVersion' => (int) $local_lib->minor_version, 690 'localPatchVersion' => (int) $local_lib->patch_version, 691 'canInstall' => FALSE, 692 'installed' => TRUE, 693 'isUpToDate' => TRUE, 694 'owner' => '', 695 'restricted' => $can_create_restricted ? FALSE : 696 ($local_lib->restricted ? TRUE : FALSE) 697 ); 698 699 if (isset($icon_path)) { 700 $local_only_lib['icon'] = $icon_path; 701 } 702 703 $cached_libraries[] = $local_only_lib; 704 } 705 } 706 707 // Restrict LRS dependent content 708 if (!$this->h5p->h5pF->getOption('enable_lrs_content_types')) { 709 foreach ($cached_libraries as &$lib) { 710 if (in_array($lib['machineName'], array('H5P.Questionnaire', 'H5P.FreeTextQuestion'))) { 711 $lib['restricted'] = TRUE; 712 } 713 } 714 } 715 } 716 717 /** 718 * Determine if a library has a presave.js file in the root folder 719 * 720 * @param string $libraryName 721 * @return bool 722 */ 723 public function hasPresave($libraryName){ 724 if( isset($this->h5p->h5pD) ){ 725 $parsedLibrary = H5PCore::libraryFromString($libraryName); 726 if($parsedLibrary !== false){ 727 $machineName = $parsedLibrary['machineName']; 728 $majorVersion = $parsedLibrary['majorVersion']; 729 $minorVersion = $parsedLibrary['minorVersion']; 730 $library = $this->h5p->h5pD->getLibrary($machineName, $majorVersion, $minorVersion); 731 if( !is_null($library)){ 732 return $this->h5p->fs->hasPresave($libraryName, $library['path']); 733 } 734 } 735 } 736 return $this->h5p->fs->hasPresave($libraryName); 737 } 738 739 /** 740 * Adds the path to the presave.js file to the list of dependency assets for the library 741 * 742 * @param array $assets 743 * @param array $library 744 * @param string $prefix 745 */ 746 public function addPresaveFile(&$assets, $library, $prefix = ''){ 747 $path = 'libraries' . '/' . H5PCore::libraryToString($library, true); 748 if( array_key_exists('path', $library)){ 749 $path = $library['path']; 750 } 751 $version = "?ver={$library['majorVersion']}.{$library['minorVersion']}.{$library['patchVersion']}"; 752 if( array_key_exists('version', $library) ){ 753 $version = $library['version']; 754 } 755 756 $assets['scripts'][] = (object) array( 757 'path' => $prefix . '/' . $path . '/' . 'presave.js', 758 'version' => $version, 759 ); 760 } 761 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body