diff --git a/locallib.php b/locallib.php index 8210ee36f68244e5c55b1ae203719762fb74de03..71d344bf8be13a6bb14ac3059516b36e64d9589b 100644 --- a/locallib.php +++ b/locallib.php @@ -64,7 +64,7 @@ function pdfannotator_display_embed($pdfannotator, $cm, $course, $file, $page = // Load and execute the javascript files. $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/pdf.js?ver=00002")); $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/textclipper.js")); - $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/index.js?ver=00032")); + $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/index.js?ver=00033")); $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/locallib.js?ver=00005")); // Pass parameters from PHP to JavaScript. @@ -368,233 +368,6 @@ function pdfannotator_file_prepare_draft_area(&$draftitemid, $contextid, $compon return file_rewrite_pluginfile_urls($text, 'draftfile.php', $usercontext->id, 'user', 'draft', $draftitemid, $options); } -/** - * Just like the file_save_draft_area_files core function. - * However, we need to store fileid and commentid in pdfannotator_embeddedfiles - * and add its id into the html code from the corresponding files. - * @return string|null if $text was passed in, the rewritten $text is returned. - * Otherwise NULL. - */ -function pdfannotator_file_save_draft_area_files($draftitemid, $contextid, $component, $filearea, $itemid, array $options=null, $text=null, $forcehttps=false) { - global $USER, $DB; - - // Do not merge files, leave it as it was. - if ($draftitemid === IGNORE_FILE_MERGE) { - // Safely return $text, no need to rewrite pluginfile because this is mostly comming from an external client like the app. - return $text; - } - - $usercontext = context_user::instance($USER->id); - $fs = get_file_storage(); - - $options = (array)$options; - if (!isset($options['subdirs'])) { - $options['subdirs'] = false; - } - if (!isset($options['maxfiles'])) { - $options['maxfiles'] = -1; // unlimited - } - if (!isset($options['maxbytes']) || $options['maxbytes'] == USER_CAN_IGNORE_FILE_SIZE_LIMITS) { - $options['maxbytes'] = 0; // unlimited - } - if (!isset($options['areamaxbytes'])) { - $options['areamaxbytes'] = FILE_AREA_MAX_BYTES_UNLIMITED; // Unlimited. - } - $allowreferences = true; - if (isset($options['return_types']) && !($options['return_types'] & (FILE_REFERENCE | FILE_CONTROLLED_LINK))) { - // we assume that if $options['return_types'] is NOT specified, we DO allow references. - // this is not exactly right. BUT there are many places in code where filemanager options - // are not passed to file_save_draft_area_files() - $allowreferences = false; - } - - // Check if the user has copy-pasted from other draft areas. Those files will be located in different draft - // areas and need to be copied into the current draft area. - $text = file_merge_draft_areas($draftitemid, $usercontext->id, $text, $forcehttps); - - // Check if the draft area has exceeded the authorised limit. This should never happen as validation - // should have taken place before, unless the user is doing something nauthly. If so, let's just not save - // anything at all in the next area. - if (file_is_draft_area_limit_reached($draftitemid, $options['areamaxbytes'])) { - return null; - } - - $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id'); - $oldfiles = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id'); - - // One file in filearea means it is empty (it has only top-level directory '.'). - if (count($draftfiles) > 1 || count($oldfiles) > 1) { - // we have to merge old and new files - we want to keep file ids for files that were not changed - // we change time modified for all new and changed files, we keep time created as is - - $newhashes = array(); - $filecount = 0; - $context = context::instance_by_id($contextid, MUST_EXIST); - foreach ($draftfiles as $file) { - if (!$options['subdirs'] && $file->get_filepath() !== '/') { - continue; - } - if (!$allowreferences && $file->is_external_file()) { - continue; - } - if (!$file->is_directory()) { - // Check to see if this file was uploaded by someone who can ignore the file size limits. - $fileusermaxbytes = get_user_max_upload_file_size($context, $options['maxbytes'], 0, 0, $file->get_userid()); - if ($fileusermaxbytes != USER_CAN_IGNORE_FILE_SIZE_LIMITS - && ($options['maxbytes'] and $options['maxbytes'] < $file->get_filesize())) { - // Oversized file. - continue; - } - if ($options['maxfiles'] != -1 and $options['maxfiles'] <= $filecount) { - // more files - should not get here at all - continue; - } - $filecount++; - } - $newhash = $fs->get_pathname_hash($contextid, $component, $filearea, $itemid, $file->get_filepath(), $file->get_filename()); - $newhashes[$newhash] = $file; - } - - // Loop through oldfiles and decide which we need to delete and which to update. - // After this cycle the array $newhashes will only contain the files that need to be added. - foreach ($oldfiles as $oldfile) { - $oldhash = $oldfile->get_pathnamehash(); - if (!isset($newhashes[$oldhash])) { - // delete files not needed any more - deleted by user - $oldfile->delete(); - continue; - } - - $newfile = $newhashes[$oldhash]; - // Now we know that we have $oldfile and $newfile for the same path. - // Let's check if we can update this file or we need to delete and create. - if ($newfile->is_directory()) { - // Directories are always ok to just update. - } else if (($source = @unserialize($newfile->get_source())) && isset($source->original)) { - // File has the 'original' - we need to update the file (it may even have not been changed at all). - $original = file_storage::unpack_reference($source->original); - if ($original['filename'] !== $oldfile->get_filename() || $original['filepath'] !== $oldfile->get_filepath()) { - // Very odd, original points to another file. Delete and create file. - $oldfile->delete(); - continue; - } - } else { - // The same file name but absence of 'original' means that file was deteled and uploaded again. - // By deleting and creating new file we properly manage all existing references. - $oldfile->delete(); - continue; - } - - // status changed, we delete old file, and create a new one - if ($oldfile->get_status() != $newfile->get_status()) { - // file was changed, use updated with new timemodified data - $oldfile->delete(); - // This file will be added later - continue; - } - - // Updated author - if ($oldfile->get_author() != $newfile->get_author()) { - $oldfile->set_author($newfile->get_author()); - } - // Updated license - if ($oldfile->get_license() != $newfile->get_license()) { - $oldfile->set_license($newfile->get_license()); - } - - // Updated file source - // Field files.source for draftarea files contains serialised object with source and original information. - // We only store the source part of it for non-draft file area. - $newsource = $newfile->get_source(); - if ($source = @unserialize($newfile->get_source())) { - $newsource = $source->source; - } - if ($oldfile->get_source() !== $newsource) { - $oldfile->set_source($newsource); - } - - // Updated sort order - if ($oldfile->get_sortorder() != $newfile->get_sortorder()) { - $oldfile->set_sortorder($newfile->get_sortorder()); - } - - // Update file timemodified - if ($oldfile->get_timemodified() != $newfile->get_timemodified()) { - $oldfile->set_timemodified($newfile->get_timemodified()); - } - - // Replaced file content - if (!$oldfile->is_directory() && - ($oldfile->get_contenthash() != $newfile->get_contenthash() || - $oldfile->get_filesize() != $newfile->get_filesize() || - $oldfile->get_referencefileid() != $newfile->get_referencefileid() || - $oldfile->get_userid() != $newfile->get_userid())) { - $oldfile->replace_file_with($newfile); - } - - // unchanged file or directory - we keep it as is - unset($newhashes[$oldhash]); - } - - // Add fresh file or the file which has changed status - // the size and subdirectory tests are extra safety only, the UI should prevent it - foreach ($newhashes as $file) { - $file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'timemodified'=>time()); - if ($source = @unserialize($file->get_source())) { - // Field files.source for draftarea files contains serialised object with source and original information. - // We only store the source part of it for non-draft file area. - $file_record['source'] = $source->source; - } - - if ($file->is_external_file()) { - $repoid = $file->get_repository_id(); - if (!empty($repoid)) { - $context = context::instance_by_id($contextid, MUST_EXIST); - $repo = repository::get_repository_by_id($repoid, $context); - if (!empty($options)) { - $repo->options = $options; - } - $file_record['repositoryid'] = $repoid; - // This hook gives the repo a place to do some house cleaning, and update the $reference before it's saved - // to the file store. E.g. transfer ownership of the file to a system account etc. - $reference = $repo->reference_file_selected($file->get_reference(), $context, $component, $filearea, $itemid); - - $file_record['reference'] = $reference; - } - } - - // Changes for PDFAnnotator. - $newentry = $fs->create_file_from_storedfile($file_record, $file); - // Checks if the file size exceeds the max size of files in the PDFAnnotator setting. - $maxfilesize = get_config('mod_pdfannotator', 'maxbytes'); - if ($maxfilesize != 0 && $maxfilesize < $newentry->get_filesize()) { - $params = new stdClass(); - $params->filename = $newentry->get_filename(); - $params->filesize = $newentry->get_filesize(); - $params->maxfilesize = $maxfilesize; - throw new Error(get_string('error:maxsizeoffiles', 'mod_pdfannotator', $params)); - } - // Changes for PDFAnnotator. - $embeddedfile_pdfannotator = new stdClass(); - $embeddedfile_pdfannotator->fileid = $newentry->get_id(); - $embeddedfile_pdfannotator->commentid = $itemid; - $embeddedfile_pdfannotator->id = $DB->insert_record('pdfannotator_embeddedfiles', $embeddedfile_pdfannotator); - // Set the sortorder for the mapping with pdfannotator_embeddedfiles table. - $newentry->set_sortorder($embeddedfile_pdfannotator->id); - } - } - - // note: do not purge the draft area - we clean up areas later in cron, - // the reason is that user might press submit twice and they would loose the files, - // also sometimes we might want to use hacks that save files into two different areas - - if (is_null($text)) { - return null; - } else { - return file_rewrite_urls_to_pluginfile($text, $draftitemid, $forcehttps); - } -} - function pdfannotator_get_instance_name($id) { global $DB; diff --git a/shared/index.js b/shared/index.js index 014762ddb1562950cdce5404060c0f4d5a0e4299..8e3a88b1866fe4c3ab5b489cf597221605ddbe4d 100644 --- a/shared/index.js +++ b/shared/index.js @@ -238,9 +238,10 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to if(data.status === "success") { if(deletionInfo) { notification.addNotification({ - message: M.util.get_string('annotationDeleted', 'pdfannotator'), - type: "success" + message: M.util.get_string('annotationDeleted', 'pdfannotator'), + type: "success" }); + setTimeoutNotification(); } var node = document.querySelector('[data-pdf-annotate-id="'+data.deleteannotation+'"]'); if(node){ @@ -251,8 +252,8 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to } } else if (data.status === 'error') { notification.addNotification({ - message: M.util.get_string('deletionForbidden', 'pdfannotator') + data.reason, - type: "error" + message: M.util.get_string('deletionForbidden', 'pdfannotator') + data.reason, + type: "error" }); } @@ -360,6 +361,7 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('commentDeleted', 'pdfannotator'), type: "success" }); + setTimeoutNotification(); // If the predecessor comment was marked as deleted, remove it from DOM as well // (This is currently irrelevant, because we jump back to overview after deletion, but I'd prefer to stay in the thread.) @@ -413,18 +415,13 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('successfullyHidden', 'pdfannotator'), type: "success" }); + setTimeoutNotification(); } else { notification.addNotification({ message: M.util.get_string('error:hideComment','pdfannotator'), type: "error" }); } - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 5000); }); }, /** @@ -450,18 +447,13 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('successfullyRedisplayed', 'pdfannotator'), type: "success" }); + setTimeoutNotification(); } else { notification.addNotification({ message: M.util.get_string('error:redisplayComment','pdfannotator'), type: "error" }); } - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 5000); }); }, @@ -593,12 +585,6 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: message, type: "info" }); - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 3000); } }); }, @@ -951,24 +937,11 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('infonocomments','pdfannotator'), type: "info" }); - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 3000); - } else if(data.status === 'error') { notification.addNotification({ message: M.util.get_string('error:printcomments','pdfannotator'), type: "error" }); - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 3000); } }); } // end of function openCommentsCallback @@ -1639,6 +1612,7 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('successfullyUnsubscribed', 'pdfannotator'), type: "success" }); + setTimeoutNotification() } else if(data.status == 'error') { notification.addNotification({ message: M.util.get_string('error:unsubscribe','pdfannotator'), @@ -1651,11 +1625,12 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to } else { _2.default.getStoreAdapter().subscribeQuestion(RENDER_OPTIONS.documentId, comment.annotation) .then(function(data){ - if(data.status === "success") { + if(data.status === "success") { notification.addNotification({ message: M.util.get_string('successfullySubscribed', 'pdfannotator'), type: "success" }); + setTimeoutNotification(); } else if(data.status == 'error') { notification.addNotification({ message: M.util.get_string('error:subscribe','pdfannotator'), @@ -1669,12 +1644,6 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to comment.issubscribed = !comment.issubscribed; i.toggleClass("fa-bell"); i.toggleClass("fa-bell-slash"); - setTimeout(function () { - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 3000); }); } @@ -1812,6 +1781,7 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('successfullyEdited', 'pdfannotator'), type: "success" }); + setTimeoutNotification(); } else { notification.addNotification({ message: M.util.get_string('error:editComment','pdfannotator'), @@ -2013,13 +1983,6 @@ function startIndex(Y,_cm,_documentObject,_contextId, _userid,_capabilities, _to message: M.util.get_string('error:getComments','pdfannotator'), type: "error" }); - - setTimeout(function(){ - let notificationpanel = document.getElementById("user-notifications"); - while (notificationpanel.hasChildNodes()) { - notificationpanel.removeChild(notificationpanel.firstChild); - } - }, 4000); }); })(); }else{ diff --git a/shared/locallib.js b/shared/locallib.js index bc75be5d828c5c69bad36dc53d8a87d0de36b83e..19ac66904f75d294d1fb547d594de82acc73e90d 100644 --- a/shared/locallib.js +++ b/shared/locallib.js @@ -224,4 +224,13 @@ function checkOnlyOneCheckbox( Y ) { } }); } +} + +function setTimeoutNotification(){ + setTimeout(function(){ + let notificationpanel = document.getElementById("user-notifications"); + while (notificationpanel.hasChildNodes()) { + notificationpanel.removeChild(notificationpanel.firstChild); + } + }, 10000); } \ No newline at end of file diff --git a/version.php b/version.php index 1350aa61f7610854ec3aaf5a4fa92bb36b87c8ed..b0dd6a6880ac0991ad11e46be8233be1ece9f3c2 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'mod_pdfannotator'; -$plugin->version = 2022110200; +$plugin->version = 2022110201; $plugin->release = 'PDF Annotator v1.4 release 11'; $plugin->requires = 2021051700; $plugin->maturity = MATURITY_STABLE;