diff --git a/.gitignore b/.gitignore index 733cee9c9d6d..81929aa66c58 100755 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ /ilias.ini.php /ilias.log /db_template_writer.php -/components/ILIAS/setup_/sql/dbupdate_custom.php +/components/ILIAS/Database/sql/dbupdate_custom.php /install_client.php # Directories diff --git a/README.md b/README.md index 2ebeb496c0d8..6b40284da0a9 100755 --- a/README.md +++ b/README.md @@ -3,24 +3,24 @@ # ILIAS -ILIAS is a powerful Open Source Learning Management System for developing and realising web-based e-learning. The software was developed to reduce the costs of using new media in education and further training and to ensure the maximum level of customer influence in the implementation of the software. ILIAS is published under the General Public Licence and free of charge. +ILIAS is a powerful Open Source Learning Management System for developing and realising web-based e-learning. The software was developed to reduce the costs of using new media in education and further training and to ensure the maximum level of customer influence in the implementation of the software. ILIAS is published under the General Public Licence 3.0 and free of charge. ### Features -[see all features on our official website](https://www.ilias.de/en/about-ilias/) or [read our booklet](http://www.ilias.de/docu/goto_docu_file_1854_download.html) +[Read more about ILIAS features on our official website](https://www.ilias.de/en/about-ilias/) or [have a look in our booklet (de)](https://docu.ilias.de/goto_docu_file_4712_download.html) ### Installation -Installation of ILIAS is well documented on [our official Installation manual](http://www.ilias.de/docu/goto_docu_lm_367.html) and in the documentation contained inside this repo: [/docs/configuration/install.md](/docs/configuration/install.md) +Installation of ILIAS is well documented on [our official Installation manual](https://docu.ilias.de/go/lm/367) and in the documentation contained inside this repo: [/docs/configuration/install.md](/docs/configuration/install.md) ### Plugins -ILIAS can be extended with a lot of Plugins. You find the complete list in the [Plugin Repository](http://www.ilias.de/docu/goto.php?target=cat_1442&client_id=docu) +ILIAS can be extended with a lot of Plugins. You find a list in the [Plugin Data Collection](https://docu.ilias.de/go/dcl/3342) ### Community -We have a big [community](http://www.ilias.de/docu/goto.php?target=cat_1444&client_id=docu) and you can get a member of [ILIAS Society](http://www.ilias.de/docu/goto.php?target=cat_1669&client_id=docu). -You may even join us at one of our regular [ILIAS Conferences](http://www.ilias.de/docu/goto.php?target=cat_2255&client_id=docu). +We have a big [community](https://www.ilias.de/en/ilias-society/) and you can get a member of the [ILIAS Society](https://www.ilias.de/en/join-ilias-society/). +You may even join us at one of our regular [ILIAS Conferences](https://www.ilias-conference.org/en/). ### Development diff --git a/components/ILIAS/ADT/PRIVACY.md b/components/ILIAS/ADT/PRIVACY.md new file mode 100644 index 000000000000..d95ba5b7390f --- /dev/null +++ b/components/ILIAS/ADT/PRIVACY.md @@ -0,0 +1,23 @@ +# ADT Privacy +Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via Pull Request (docs/development/contributing.md#pull-request-to-the-repositories). +## General Information +ADT stands for Advanced Definition Type. +[Please provide a brief description of the component here] + + +## Integrated Services +The Advanced Definition Type component employs the following components, please consult the respective privacy.mds: +- [Please list all components here] + + +## Data being stored +The Advanced Definition Type component itself does not store any personal data. + +## Data being presented +The Advanced Definition Type component itself does not present any personal data. + +## Data being deleted +The Advanced Definition Type component itself does not store or delete any personal data. + +## Data being exported +The Advanced Definition Type component itself does not export any personal data. diff --git a/components/ILIAS/AccessControl/PRIVACY.md b/components/ILIAS/AccessControl/PRIVACY.md index 019288c93dd7..e7a0750a041b 100755 --- a/components/ILIAS/AccessControl/PRIVACY.md +++ b/components/ILIAS/AccessControl/PRIVACY.md @@ -1,8 +1,6 @@ -# Access Control Service Privacy +# AccessControl Privacy -This documentation does not warrant completeness or correctness. Please report any -missing or wrong information using the [ILIAS issue tracker](https://mantis.ilias.de) -or contribute a fix via [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories). +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information by submitting a [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories) or, if you prefer, via the [ILIAS bug tracker](https://mantis.ilias.de). When using the bug tracker, please select the corresponding component in the **Category** field.** ## Data being stored diff --git a/components/ILIAS/Administration/GlobalScreen/classes/AdministrationMainBarProvider.php b/components/ILIAS/Administration/GlobalScreen/classes/AdministrationMainBarProvider.php index 3f9baaa54ae2..660af1b3f27f 100755 --- a/components/ILIAS/Administration/GlobalScreen/classes/AdministrationMainBarProvider.php +++ b/components/ILIAS/Administration/GlobalScreen/classes/AdministrationMainBarProvider.php @@ -225,7 +225,7 @@ private function getGroups(): array // admin menu layout $layout = array( "maintenance" => - array("adma", "serv", "cron", "bnmk", "lngf", "hlps", "wfe", 'fils', 'logs', 'sysc', "recf", "root"), + array("adma", "serv", "cron", "bnmk", "lngf", "hlps", "wfe", 'fils', 'qsts', 'logs', 'sysc', "recf", "root"), "layout_and_navigation" => array("mme", "gsfo", "dshs", "stys", "adve", "stus"), "repository_and_objects" => diff --git a/components/ILIAS/AdministrativeNotification/classes/class.ilADNNotificationUIFormGUI.php b/components/ILIAS/AdministrativeNotification/classes/class.ilADNNotificationUIFormGUI.php index 58c5df07b63b..9bc7c1371fc1 100755 --- a/components/ILIAS/AdministrativeNotification/classes/class.ilADNNotificationUIFormGUI.php +++ b/components/ILIAS/AdministrativeNotification/classes/class.ilADNNotificationUIFormGUI.php @@ -380,7 +380,7 @@ protected function getRoles(int $filter): array { $opt = []; foreach ($this->rbac_review->getRolesByFilter($filter) as $role) { - $opt[(int) $role['obj_id']] = $role['title'] . ' (' . $role['obj_id'] . ')'; + $opt[(int) $role['obj_id']] = (string) $role['title']; } return $opt; diff --git a/components/ILIAS/AdvancedMetaData/PRIVACY.md b/components/ILIAS/AdvancedMetaData/PRIVACY.md index 27292bb1bb08..aef68ffaa631 100644 --- a/components/ILIAS/AdvancedMetaData/PRIVACY.md +++ b/components/ILIAS/AdvancedMetaData/PRIVACY.md @@ -1,4 +1,4 @@ -# AdvancedMetaData +# AdvancedMetaData Privacy Disclaimer: This documentation does not guarantee completeness or correctness. Please report any missing or incorrect information using the ILIAS issue tracker or contribute a fix via Pull Request (docs/development/contributing.md#pull-request-to-the-repositories). ## General Information Advanced Metadata is labeled Custom Metadata in the user interface. @@ -23,4 +23,4 @@ The Advanced Metadata itself does not present any personal data. The Advanced Metadata itself does not store or delete any personal data. ## Data being exported -The Advanced Metadata module itself does not export any personal data. \ No newline at end of file +The Advanced Metadata module itself does not export any personal data. diff --git a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php index 17e200e51cb3..20b4df7c6d8d 100755 --- a/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php +++ b/components/ILIAS/AdvancedMetaData/classes/class.ilAdvancedMDSettingsGUI.php @@ -1363,7 +1363,7 @@ public function saveField(): void $translations->read(); $translations->updateFromForm($field_definition->getFieldId(), $this->active_language, $form); - $this->tpl->setOnScreenMessage('success', $this->lng->txt('save_settings'), true); + $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true); $this->ctrl->redirect($this, "editFields"); } diff --git a/components/ILIAS/AdvancedMetaData/tests/record/ilAdvancedMDRecordObjectOrderingsTest.php b/components/ILIAS/AdvancedMetaData/tests/record/ilAdvancedMDRecordObjectOrderingsTest.php index 0e8dabc23d35..c71bb762def5 100755 --- a/components/ILIAS/AdvancedMetaData/tests/record/ilAdvancedMDRecordObjectOrderingsTest.php +++ b/components/ILIAS/AdvancedMetaData/tests/record/ilAdvancedMDRecordObjectOrderingsTest.php @@ -78,6 +78,6 @@ protected function initRecordSortingDependencies(): void { $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); } } diff --git a/components/ILIAS/AuthShibboleth/resources/shib_logout.php b/components/ILIAS/AuthShibboleth/resources/shib_logout.php index 2207637d7541..034cf0c2f147 100644 --- a/components/ILIAS/AuthShibboleth/resources/shib_logout.php +++ b/components/ILIAS/AuthShibboleth/resources/shib_logout.php @@ -16,162 +16,17 @@ * *********************************************************************/ +// A real Shib-Logout ("front" or "back" channel was never implemented resp. removed in ILIAS, because the front-channel +// also had problems concerning the security. If a logout mechanism is desired, please revisit the feature request +// https://docu.ilias.de/goto_docu_wiki_wpage_4657_1357.html and bring it as a suggestion to the community: +// https://docu.ilias.de/goto.php?target=wiki_5307&client_id=docu#ilPageTocA129 +/** @noRector */ require_once("../vendor/composer/vendor/autoload.php"); ilContext::init(ilContext::CONTEXT_SHIBBOLETH); require_once("../artifacts/bootstrap_default.php"); +entry_point("ILIAS Legacy Initialisation Adapter"); global $DIC; -$q = $DIC->http()->wrapper()->query(); -if ( - $q->has('return') - && $q->has('action') - && $q->retrieve('action', $DIC->refinery()->to()->string()) === 'logout' -) { - entry_point("ILIAS Legacy Initialisation Adapter"); - // Logout out user from application - // Destroy application session/cookie etc - $GLOBALS['DIC']['ilAuthSession']->logout(); - - // Finally, send user to the return URL - ilUtil::redirect($q->retrieve('action', $DIC->refinery()->kindlyTo()->string())); -} - -// Back channel logout // - -// Note: This is the preferred logout channel because it also allows -// administrative logout. However, it requires your application to be -// adapated in the sense that the user's Shibboleth session ID must be -// stored in the application's session data. -// See function LogoutNotification below - -elseif (!empty(file_get_contents('php://input'))) { - ilContext::init(ilContext::CONTEXT_SOAP); - - // Load ILIAS libraries and initialise ILIAS in non-web context - entry_point("ILIAS Legacy Initialisation Adapter"); - - // Set SOAP header - $server = new SoapServer('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '/LogoutNotification.wsdl'); - $server->addFunction("LogoutNotification"); - $server->handle(); -} - -// Return WSDL - -// Note: This is needed for the PHP SoapServer class. -// Since I'm not a web service guru it might be that the code below is not -// absolutely correct but at least it seems to to its job properly when it -// comes to Shibboleth logout - -else { - header('Content-Type: text/xml'); - - $url = filter_var("https://{$_SERVER['HTTP_HOST']}/shib_logout.php", FILTER_SANITIZE_URL); - - echo << - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -WSDL; - exit; -} - -/******************************************************************************/ -/// This function does the actual logout -function LogoutNotification($SessionID): ?\SoapFault -{ - // Delete session of user using $SessionID to locate the user's session file - // on the file system or in the database - // Then delete this entry or record to clear the session - // However, for that to work it is essential that the user's Shibboleth - // SessionID is stored in the user session data! - - global $ilDB; - - $q = "SELECT session_id, data FROM usr_session WHERE expires > 'NOW()'"; - $r = $ilDB->query($q); - - while ($session = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) { - $session_data = unserializesession($session['data']); - // Delete this session entry - if ( - is_array($session_data) - && array_key_exists('shibboleth_session_id', $session_data) - && $session_data['shibboleth_session_id'] === $SessionID - && !ilSession::_destroy($session['session_id'] - ) - ) { - return new SoapFault('LogoutError', 'Could not delete session entry in database.'); - } - } - // If no SoapFault is returned, all is fine - return null; -} - -/******************************************************************************/ -// Deserializes session data and returns it in a hash array of arrays -/** - * @return mixed[] - */ -function unserializesession($serialized_string): array -{ - $variables = []; - $a = preg_split("/(\w+)\|/", (string) $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - $counter = count($a); - for ($i = 0; $i < $counter; $i += 2) { - $variables[$a[$i]] = unserialize($a[$i + 1]); - } - - return ($variables); -} +$GLOBALS['DIC']['ilAuthSession']->logout(); +ilUtil::redirect('login.php'); diff --git a/components/ILIAS/Authentication/classes/Frontend/class.ilAuthFrontend.php b/components/ILIAS/Authentication/classes/Frontend/class.ilAuthFrontend.php index 8423441e903c..472b0723d3ef 100755 --- a/components/ILIAS/Authentication/classes/Frontend/class.ilAuthFrontend.php +++ b/components/ILIAS/Authentication/classes/Frontend/class.ilAuthFrontend.php @@ -404,7 +404,19 @@ protected function handleLoginAttempts(): void $usr_id_candidates = []; foreach (array_filter($auth_modes) as $auth_mode) { if ((int) $auth_mode === ilAuthUtils::AUTH_LOCAL) { - $usr_id_candidates[] = ilObjUser::_lookupId($this->getCredentials()->getUsername()); + $local_usr_id = ilObjUser::_lookupId($this->getCredentials()->getUsername()); + // Mantis #47987: A failed local login must only count against an + // account that can actually be authenticated locally. Without this + // check, external accounts (e.g., Shibboleth/SAML) whose login name + // is entered in the local login form get their login attempts + // incremented and are eventually deactivated - even though a local + // login is impossible for them because "Allow Local Authentication" + // is disabled. This mirrors the gate in ilAuthProviderDatabase. + if (is_int($local_usr_id) && $local_usr_id > 0 && ilAuthUtils::isLocalPasswordEnabledForAuthMode( + (int) ilAuthUtils::_getAuthMode(ilObjUser::_lookupAuthMode($local_usr_id)) + )) { + $usr_id_candidates[] = $local_usr_id; + } continue; } diff --git a/components/ILIAS/BackgroundTasks_/classes/Jobs/class.ilCollectFilesJob.php b/components/ILIAS/BackgroundTasks_/classes/Jobs/class.ilCollectFilesJob.php index 3dae62a64972..ab4901c8a11e 100755 --- a/components/ILIAS/BackgroundTasks_/classes/Jobs/class.ilCollectFilesJob.php +++ b/components/ILIAS/BackgroundTasks_/classes/Jobs/class.ilCollectFilesJob.php @@ -97,21 +97,37 @@ public function run(array $input, Observer $observer): Value foreach ($object_ref_ids as $object_ref_id) { $object = ilObjectFactory::getInstanceByRefId($object_ref_id); + if (!$object instanceof ilObject) { + continue; + } + $object_type = $object->getType(); $object_name = $object->getTitle(); - $object_temp_dir = ""; // empty as content will be added in recurseFolder and getFileDirs + $object_temp_dir = ''; // empty as content will be added in recurseFolder and getFileDirs - if ($object_type === "fold" || $object_type === "crs") { + if (in_array($object_type, ['fold', 'crs', 'grp'], true)) { $num_recursions = 0; - $files_from_folder = $this->recurseFolder($object_ref_id, $object_name, $object_temp_dir, $num_recursions, $initiated_by_folder_action); + $files_from_folder = $this->recurseFolder( + $object_ref_id, + $object_name, + $object_temp_dir, + $num_recursions, + $initiated_by_folder_action + ); $files = array_merge($files, $files_from_folder); - } elseif (($object_type === "file") && (($file_dirs = $this->getFileDirs( - $object_ref_id, - $object_name, - $object_temp_dir - )) !== false)) { - $files[] = $file_dirs; + continue; } + + if ($object_type !== 'file') { + continue; + } + + $file_dirs = $this->getFileDirs($object_ref_id, $object_name, $object_temp_dir); + if (!is_array($file_dirs)) { + continue; + } + + $files[] = $file_dirs; } $this->logger->debug('Collected files:'); $this->logger->dump($files); @@ -154,7 +170,14 @@ private function getFileDirs($a_ref_id, string $a_file_name, string $a_temp_dir) return false; } - $filname_with_suffix = $this->ensureSuffix($a_file_name, $file->getFileExtension()); + // The object title may contain characters which are not allowed in file names: + // "/" would create a directory inside the archive, while "*", "?" and ":" are + // invalid on Windows and prevent the archive from being extracted. They are + // sanitized the same way as the folder names in recurseFolder(). + $filname_with_suffix = $this->ensureSuffix( + ilFileUtils::getASCIIFilename($a_file_name), + $file->getFileExtension() + ); $target_dir = $a_temp_dir . '/' . $filname_with_suffix; @@ -165,7 +188,10 @@ private function getFileDirs($a_ref_id, string $a_file_name, string $a_temp_dir) $target_info = pathinfo($target_dir); $filename = $target_info["filename"]; $extension = isset($target_info["extension"]) ? "." . $target_info["extension"] : ""; - $target_dir = $a_temp_dir . $filename . " (" . ++self::$targets[$target_dir] . ")" . $extension; + // pathinfo() returns the name without its directory, therefore the separator + // has to be added again, just like above + $target_dir = $a_temp_dir . '/' . $filename + . " (" . ++self::$targets[$target_dir] . ")" . $extension; } else { self::$targets[$target_dir] = 0; } diff --git a/components/ILIAS/Badge/PRIVACY.md b/components/ILIAS/Badge/PRIVACY.md new file mode 100644 index 000000000000..658d7fae796b --- /dev/null +++ b/components/ILIAS/Badge/PRIVACY.md @@ -0,0 +1,143 @@ +# Badge Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information by submitting a [Pull Request](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/docs/development/contributing.md#pull-request-to-the-repositories) or, if you prefer, via the [ILIAS bug tracker](https://mantis.ilias.de). When using the bug tracker, please select the corresponding component in the **Category** field.** + + +## General Information + +The Badge service allows the awarding of digital badges to users for various achievements. +Badges can be awarded automatically (triggered by events like course completion) or manually by persons with +appropriate permissions. Users can view and manage their received badges under +**Achievements > Badges**. + +Badge instances are typically managed on **courses** and **groups** (when the badges +feature is activated for the object). Other components can provide badge types via the +badge provider API (e.g. profile badges from the User service). + +Events such as trigger automatic awards: + +- **Learning progress completion** of a course (`Tracking/updateStatus`) +- **Profile updates** for profile badges (`User/afterUpdate`) + +Badges are not awarded retrospectively when settings change; only future actions are +evaluated. + +The Open Badges backpack **export** from ILIAS is no longer supported and has been disabled. +Mozilla has shut down the Open Badges backpack service, and ILIAS has removed the export functionality +(see [Mantis #20124](https://mantis.ilias.de/view.php?id=20124)). + +## Integrated Services + +The Badge component employs the following services (please consult their respective PRIVACY.md files): + +- **[User](../User/PRIVACY.md)**: Stores user references for assignments and triggers + badge evaluation on profile updates. +- **[Tracking](../Tracking/PRIVACY.md)**: Triggers badge awards on learning progress + status changes. +- **[Mail](../Mail/PRIVACY.md)**: Sends email notifications when badges are awarded. + The Mail service is used as a transport channel; badge titles and links are passed + through as message content. +- **[Notifications](../Notifications/PRIVACY.md)**: Sends on-screen notifications when + badges are awarded. +- **[AccessControl](../AccessControl/PRIVACY.md)**: Controls who can manage badges and + view badge assignments. +- **[LearningHistory](../LearningHistory/PRIVACY.md)**: Presents awarded badges in the + user's learning history timeline. +- **[ResourceStorage](../ResourceStorage/PRIVACY.md)**: Stores badge images referenced + by badge definitions. +- **GlobalScreen**: Displays badge notification counters in the main bar. + +## Data being stored + +- **Badge Definition**: Badge instances are stored in the database table `badge_badge`. + This includes title, description, criteria, configuration, and references to the + parent object and badge image. These definitions do not contain personal data by + themselves but may reference user-configured content in their text fields. + +- **Badge Assignment**: When a badge is assigned to a user, the following data is + stored in the database table `badge_user_badge`: + - The user ID of the badge recipient + - The timestamp when the badge was awarded + - The user ID of the person who manually awarded the badge (only for manual awards; + not displayed as a person's name in the user interface) + - A position value (`pos`) controlling visibility and ordering on the user's profile + (`null` = not shown on the public profile) + +- **User Preferences**: The following user preferences are stored via the user + preference system: + - `badge_last_checked`: Timestamp of when the user last viewed their badges + - `badge_mozilla_bp`: Optional email address for badge backpack integration + +- **Static Open Badges Files**: Legacy static JSON files for Open Badges publishing may + exist under the webspace directory `pub_badges/`. These are removed when + assignments or badge definitions are deleted. + +## Data being presented + +- **Personal Badge View**: Each user can view their own badges under + **Achievements > Badges**. This includes badge title, description, image, award date, + and the name of the awarding object (parent repository object). + +- **Public User Profile**: Users can choose which badges are visible on their public + profile (controlled via the `pos` field). Other users who can access the profile see + badge title, image, and awarding object. Only badges with a positive position value + are shown. + +- **Badge Management View**: Persons with **write** permission on a course or group can + access the badge management interface. This view presents: + - Names (firstname, lastname) of users who have been awarded badges + - Login names of badge recipients + - The date when badges were issued + - The badge type and title + - The parent object where the badge was awarded (in container context) + +- **Administration View**: Persons with **read** permission on the Badge + Administration can view all object badges and their assignments across the system. + This includes: + - List of users with badge assignments, showing name, login, badge type, title, and + issue date + - The parent object where the badge was awarded + +- **Badge Award Information**: When viewing a badge in the tile view, the name of the + awarding object is displayed to the badge recipient. The label "awarded by" refers to + the parent object, not to the user who performed a manual award. + +- **Notifications**: When badges are awarded, users receive: + - An **email** containing badge titles and a link to their badge profile + - An **on-screen notification** with badge titles and a link + +- **Learning History**: Awarded badges appear in the user's learning history with badge + title, context object, and timestamp. + +## Data being deleted + +- **User Deletion**: When a user account is deleted, all badge assignments for that + user are automatically deleted (`ilBadgeAssignment::deleteByUserId`). + +- **Badge Deletion**: When a badge definition is deleted, all assignments of that + badge to users and associated static files are automatically deleted. + +- **Manual Removal**: Persons with **write** permission on a repository object can + manually remove badge assignments from individual users via the "Users" tab in badge + management. + +- **Object Deletion**: When a repository object (e.g. course, group) is permanently + deleted, badge definitions in `badge_badge` and their assignments are **not** + automatically cleaned up. The method `ilBadgeAssignment::deleteByParentId` exists + but is not hooked into the object deletion workflow. Orphaned badge definitions may + remain in the database referencing deleted objects. + +## Data being exported + +- **No Export of Assignments**: There is no built-in export functionality for badge + assignment data. + +- **Backpack Export (Disabled)**: Exporting badges to an external Open Badges backpack + is currently disabled. + +- **Backpack Import / Display**: Code for displaying badges from an external Mozilla + Open Badges backpack (using the email stored in `badge_mozilla_bp`) still exists, but + this feature is not actively maintained. + +- **Object Copy**: When a course is copied, badge definitions are cloned to the new + object. User assignments are not copied. diff --git a/components/ILIAS/Badge/classes/Setup/class.ilBadgeTemplatesFilesMigration.php b/components/ILIAS/Badge/classes/Setup/class.ilBadgeTemplatesFilesMigration.php index 25a93f60a0e9..cf1e5599d142 100644 --- a/components/ILIAS/Badge/classes/Setup/class.ilBadgeTemplatesFilesMigration.php +++ b/components/ILIAS/Badge/classes/Setup/class.ilBadgeTemplatesFilesMigration.php @@ -115,6 +115,13 @@ public function step(Environment $environment): void . ' (table: ' . self::TABLE_NAME . ') because no image is set.', true ); + $this->helper->getDatabase()->update( + self::TABLE_NAME, + [ + 'image_rid' => [ilDBConstants::T_TEXT, '-'], + ], + ['id' => [ilDBConstants::T_INTEGER, $id]] + ); } } diff --git a/components/ILIAS/Badge/classes/Setup/class.ilBadgesFilesMigration.php b/components/ILIAS/Badge/classes/Setup/class.ilBadgesFilesMigration.php index d331f24be9c8..3507e40c1350 100644 --- a/components/ILIAS/Badge/classes/Setup/class.ilBadgesFilesMigration.php +++ b/components/ILIAS/Badge/classes/Setup/class.ilBadgesFilesMigration.php @@ -112,6 +112,13 @@ public function step(Environment $environment): void . ' (table: ' . self::TABLE_NAME . ') because no image is set.', true ); + $this->helper->getDatabase()->update( + self::TABLE_NAME, + [ + 'image_rid' => [ilDBConstants::T_TEXT, '-'], + ], + ['id' => [ilDBConstants::T_INTEGER, $id]] + ); } } diff --git a/components/ILIAS/Blog/CHANGELOG.md b/components/ILIAS/Blog/CHANGELOG.md index 48a1c83b8815..3df2ee827bc8 100755 --- a/components/ILIAS/Blog/CHANGELOG.md +++ b/components/ILIAS/Blog/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## ILIAS 12 +- Separated presentation and editing GUI +- Moved month, author and keyword block to separate classes +- Removed all static function declarations (that are not enforced by other components) +- Removed all DIC access outside of constructors + ## ILIAS 11 - Data/Repository/Domain classes for Postings - Refactored news and notification related code diff --git a/components/ILIAS/Blog/Contributor/ContributorGUI.php b/components/ILIAS/Blog/Contributor/ContributorGUI.php new file mode 100644 index 000000000000..c2a277e0581e --- /dev/null +++ b/components/ILIAS/Blog/Contributor/ContributorGUI.php @@ -0,0 +1,262 @@ +gui->ctrl(); + $next_class = $ctrl->getNextClass($this); + $cmd = $ctrl->getCmd("contributors"); + + switch ($next_class) { + case strtolower(\ilRepositorySearchGUI::class): + $rep_search = new \ilRepositorySearchGUI(); + $rep_search->setTitle($this->domain->lng()->txt("blog_add_contributor")); + $rep_search->setCallback($this, 'addContributor', $this->blog->getAllLocalRoles($this->node_id)); + $ctrl->setReturn($this, 'contributors'); + $ctrl->forwardCommand($rep_search); + break; + + default: + if (method_exists($this, $cmd)) { + $this->$cmd(); + } + break; + } + } + + public function contributors(): void + { + $ilTabs = $this->gui->tabs(); + $ilToolbar = $this->gui->toolbar(); + $ilCtrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + $tpl = $this->gui->ui()->mainTemplate(); + + $ilTabs->activateTab("contributors"); + + $local_roles = $this->blog->getAllLocalRoles($this->node_id); + + // add member + ilRepositorySearchGUI::fillAutoCompleteToolbar( + $this, + $ilToolbar, + array( + 'auto_complete_name' => $lng->txt('user'), + 'submit_name' => $lng->txt('add'), + 'add_search' => true, + 'add_from_container' => $this->node_id, + 'user_type' => $local_roles + ), + true + ); + + $other_roles = $this->blog->getRolesWithContributeOrRedact($this->node_id); + if ($other_roles) { + $tpl->setOnScreenMessage('info', sprintf($lng->txt("blog_contribute_other_roles"), implode(", ", $other_roles))); + } + + $table = $this->gui->contributor()->contributorTableBuilder( + $this->blog->getAllLocalRoles($this->node_id), + $this, + "contributors" + )->getTable(); + + if ($table->handleCommand()) { + return; + } + + $tpl->setContent($table->render()); + } + + /** + * Autocomplete submit + */ + public function addUserFromAutoComplete(): void + { + $lng = $this->domain->lng(); + $req = $this->gui->standardRequest(); + + $user_login = $req->getUserLogin(); + $user_type = $req->getUserType(); + + if (trim($user_login) === '') { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt('msg_no_search_string')); + $this->contributors(); + return; + } + $users = explode(',', $user_login); + + $user_ids = array(); + foreach ($users as $user) { + $user_id = ilObjUser::_lookupId($user); + + if (!$user_id) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt('user_not_known')); + $this->contributors(); + return; + } + + $user_ids[] = (int) $user_id; + } + + $this->addContributor($user_ids, $user_type); + } + + /** + * Centralized method to add contributors + */ + public function addContributor( + array $a_user_ids = array(), + ?string $a_user_type = null + ): void { + $ilCtrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + $rbacreview = $this->domain->rbac()->review(); + $rbacadmin = $this->domain->rbac()->admin(); + $a_user_type = (int) $a_user_type; + + if (empty($a_user_ids)) { + $a_user_ids = $this->gui->standardRequest()->getIds(); + } + + if (!count($a_user_ids) || !$a_user_type) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt("no_checkbox")); + $this->contributors(); + return; + } + + // get contributor role + $local_roles = array_keys($this->blog->getAllLocalRoles($this->node_id)); + if (!in_array($a_user_type, $local_roles)) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt("missing_perm")); + $this->contributors(); + return; + } + + foreach ($a_user_ids as $user_id) { + $user_id = (int) $user_id; + $a_user_type = (int) $a_user_type; + if (!$rbacreview->isAssigned($user_id, $a_user_type)) { + $rbacadmin->assignUser($a_user_type, $user_id); + } + } + + $this->gui->ui()->mainTemplate()->setOnScreenMessage('success', $lng->txt("settings_saved"), true); + $ilCtrl->redirect($this, "contributors"); + } + + /** + * Used in ContributorTableBuilder + */ + public function confirmRemoveContributor(array $ids = []): void + { + if (empty($ids)) { + $ids = $this->gui->standardRequest()->getIds(); + } + if (count($ids) === 0) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $this->domain->lng()->txt("select_one"), true); + $this->gui->ctrl()->redirect($this, "contributors"); + } + + $confirm = new ilConfirmationGUI(); + $confirm->setHeaderText($this->domain->lng()->txt('blog_confirm_delete_contributors')); + $confirm->setFormAction($this->gui->ctrl()->getFormAction($this, 'removeContributor')); + $confirm->setConfirm($this->domain->lng()->txt('delete'), 'removeContributor'); + $confirm->setCancel($this->domain->lng()->txt('cancel'), 'contributors'); + + foreach ($ids as $user_id) { + $confirm->addItem( + 'id[]', + (string) $user_id, + \ilUserUtil::getNamePresentation($user_id, false, false, "", true) + ); + } + + $this->gui->ui()->mainTemplate()->setContent($confirm->getHTML()); + } + + public function removeContributor(): void + { + $ilCtrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + $rbacadmin = $this->domain->rbac()->admin(); + + $ids = $this->gui->standardRequest()->getIds(); + + if (count($ids) === 0) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt("select_one"), true); + $ilCtrl->redirect($this, "contributors"); + } + + // get contributor role + $local_roles = array_keys($this->blog->getAllLocalRoles($this->node_id)); + if (!$local_roles) { + $this->gui->ui()->mainTemplate()->setOnScreenMessage('failure', $lng->txt("missing_perm")); + $this->contributors(); + return; + } + + foreach ($ids as $user_id) { + foreach ($local_roles as $role_id) { + $rbacadmin->deassignUser($role_id, $user_id); + } + } + + $this->gui->ui()->mainTemplate()->setOnScreenMessage('success', $lng->txt("settings_saved"), true); + $this->gui->ctrl()->redirect($this, "contributors"); + } + + /** + * Used in ContributorTableBuilder + */ + public function addContributorContainerAction(array $ids = []): void + { + if (empty($ids)) { + $ids = $this->gui->standardRequest()->getIds(); + } + + // This would typically add contributors from a container + // For now, redirecting back to contributors as this seems to be a placeholder action + $this->gui->ctrl()->redirect($this, "contributors"); + } +} diff --git a/components/ILIAS/Blog/Contributor/Service/class.GUIService.php b/components/ILIAS/Blog/Contributor/Service/class.GUIService.php index ef8de2f00f64..8007e5d6d2d8 100755 --- a/components/ILIAS/Blog/Contributor/Service/class.GUIService.php +++ b/components/ILIAS/Blog/Contributor/Service/class.GUIService.php @@ -57,4 +57,15 @@ public function contributorTableBuilder( $parent_cmd ); } + + public function contributorGUI(int $node_id, \ilObjBlog $blog): ContributorGUI + { + return new ContributorGUI( + $this->data_service, + $this->domain_service, + $this->gui, + $node_id, + $blog + ); + } } diff --git a/components/ILIAS/Blog/Editing/EditingGUI.php b/components/ILIAS/Blog/Editing/EditingGUI.php new file mode 100644 index 000000000000..5470bf43c4ff --- /dev/null +++ b/components/ILIAS/Blog/Editing/EditingGUI.php @@ -0,0 +1,314 @@ +blog_request = $gui->standardRequest(); + $this->blog = $parent_gui->getObject(); + $this->blog_settings = $this->domain->blogSettings()->getByObjId($this->blog->getId()); + $this->month = $this->blog_request->getMonth(); + } + + public function executeCommand(): void + { + $next_class = $this->gui->ctrl()->getNextClass($this); + $cmd = $this->gui->ctrl()->getCmd("render"); + + switch ($next_class) { + case strtolower(ilBlogPostingGUI::class): + $this->forwardPosting(); + break; + + default: + $this->$cmd(); + break; + } + } + + protected function getLinkBuilder(): EditingLinkBuilder + { + return $this->gui->navigation()->editingLink(); + } + + protected function forwardPosting(): void + { + $ilCtrl = $this->gui->ctrl(); + $tpl = $this->gui->ui()->mainTemplate(); + $lng = $this->domain->lng(); + $req = $this->gui->standardRequest(); + + $ilCtrl->saveParameter($this, "user_page"); + $tpl->loadStandardTemplate(); + + if (!$this->perm->mayContribute()) { + $tpl->setOnScreenMessage('info', $lng->txt("no_permission")); + return; + } + + $style_sheet_id = $this->content_style_domain->getEffectiveStyleId(); + + $bpost_gui = new ilBlogPostingGUI( + $this->node_id, + $this->perm->getAccessHandler(), + $req->getBlogPage(), + $req->getOldNr(), + $this->blog->getNotesStatus(), + $this->perm->mayEditPosting($req->getBlogPage()), + $style_sheet_id + ); + + $this->parent_gui->setContentStyleSheet(); + + $ilCtrl->setParameterByClass(ilBlogPostingGUI::class, "blpg", $req->getBlogPage()); + $this->gui->tabs()->addNonTabbedLink( + "preview", + $lng->txt("blog_preview"), + $ilCtrl->getLinkTargetByClass(ilBlogPostingGUI::class, "previewFullscreen") + ); + $ilCtrl->setParameterByClass(ilBlogPostingGUI::class, "blpg", ""); + + $ret = $ilCtrl->forwardCommand($bpost_gui); + + if ($ret != "") { + $is_owner = $this->perm->mayContribute(); + $is_active = $bpost_gui->getBlogPosting()->getActive(); + + // do not show inactive postings + $cmd = $ilCtrl->getCmd(); + if (($cmd === "previewFullscreen") + && !$is_owner && !$is_active) { + $ilCtrl->redirect($this->parent_gui, "preview"); + } + + // infos about draft status / snippet + $info = array(); + if (!$is_active) { + $info[] = $lng->txt("blog_draft_info_contributors"); + } + $public_action = false; + if ($cmd !== "history" && $cmd !== "edit" && $is_active && empty($info)) { + $info[] = $lng->txt("blog_new_posting_info"); + $public_action = true; + } + if ($this->blog->getNotesStatus() && + $this->blog_settings->getApproval() && + !$bpost_gui->getBlogPosting()->isApproved()) { + // #9737 + $info[] = $lng->txt("blog_posting_edit_approval_info"); + } + if ($public_action) { + $tpl->setOnScreenMessage('success', implode("
", $info)); + } else { + if (count($info) > 0) { + $tpl->setOnScreenMessage('info', implode("
", $info)); + } + } + + // revert to edit cmd to avoid confusion + $tpl->setContent($ret); + /* + if ($cmd !== "edit") { + $nav = $this->gui->navigation()->sideBar( + $this->perm, + $this->getLinkBuilder() + )->render( + $this->parent_gui, + $this->parent_gui->getItems(), + $is_owner + ); + $tpl->setRightContent($nav); + } else { + $this->gui->tabs()->setBackTarget("", ""); + }*/ + } + + if (!$this->gui->tabs()->back_target) { + $ilCtrl->setParameter($this, "bmn", ""); + $this->gui->tabs()->setBackTarget( + $lng->txt("back"), + $ilCtrl->getLinkTarget($this, "") + ); + } + } + + public function render(): void + { + $tpl = $this->gui->ui()->mainTemplate(); + $ilTabs = $this->gui->tabs(); + $ilCtrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + $ilToolbar = new ilToolbarGUI(); + + if (!$this->parent_gui->checkPermissionBool("read")) { + $tpl->setOnScreenMessage('info', $lng->txt("no_permission")); + return; + } + + $ilTabs->activateTab("content"); + + // toolbar + if ($this->perm->mayContribute()) { + $ilToolbar->setFormAction($ilCtrl->getFormActionByClass(self::class, "createPosting")); + + $title = new ilTextInputGUI($lng->txt("title"), "title"); + $title->setSize(30); + $ilToolbar->addStickyItem($title, true); + $tpl->addOnLoadCode(" + document.getElementById('title').setAttribute('data-blog-input', 'posting-title'); + document.getElementById('title').setAttribute('placeholder', ' '); + "); + + $this->gui->button( + $lng->txt("blog_add_posting"), + "createPosting" + )->submit()->toToolbar(true, $ilToolbar); + + + // #18763 + $items = $this->parent_gui->getItems(); + $keys = array_keys($items); + $first = array_shift($keys); + if ($first != $this->month) { + $ilToolbar->addSeparator(); + + $ilCtrl->setParameter($this->parent_gui, "bmn", $first); + $url = $ilCtrl->getLinkTarget($this->parent_gui, ""); + $ilCtrl->setParameter($this->parent_gui, "bmn", $this->month); + + $ilToolbar->addComponent( + $this->gui->ui()->factory()->button()->standard( + $lng->txt("blog_show_latest"), + $url + ) + ); + } + + // print/pdf + $print_view = $this->parent_gui->getPrintView(); + $modal_elements = $print_view->getModalElements( + $ilCtrl->getLinkTarget( + $this->parent_gui, + "printViewSelection" + ) + ); + $ilToolbar->addSeparator(); + $ilToolbar->addComponent($modal_elements->button); + $ilToolbar->addComponent($modal_elements->modal); + } + + $is_owner = $this->perm->mayContribute(); + + $list_items = $this->parent_gui->getListItems($is_owner); + + $list = $nav = ""; + if ($list_items) { + $list = $this->gui->posting()->postingList( + $this->parent_gui, + $this->perm, + $this->current_month, + $this->node_id, + $this->id_type + )->render( + $list_items, + "preview", + "", + $is_owner + ); + $nav = $this->gui->navigation()->sideBar( + $this->perm, + $this->getLinkBuilder(), + $this->blog_settings, + $this->node_id, + $this->id_type + )->render( + $this->parent_gui, + $this->parent_gui->getItems(), + $is_owner + ); + } + + $this->parent_gui->setContentStyleSheet(); + + $tpl->setContent($ilToolbar->getHTML() . $list); + $tpl->setRightContent($nav); + } + + /** + * Create new posting + */ + public function createPosting(): void + { + $ctrl = $this->gui->ctrl(); + $user = $this->domain->user(); + $mt = $this->gui->ui()->mainTemplate(); + $lng = $this->domain->lng(); + $title = $this->blog_request->getTitle(); + if ($title) { + // create new posting + $posting = new \ilBlogPosting(); + $posting->setTitle($title); + $posting->setBlogId($this->blog->getId()); + $posting->setActive(false); + $posting->setAuthor($user->getId()); + $posting->create(false); + + // switch month list to current month (will include new posting) + $ctrl->setParameter($this, "bmn", date("Y-m")); + + $ctrl->setParameterByClass("ilblogpostinggui", "blpg", $posting->getId()); + $ctrl->redirectByClass("ilblogpostinggui", "edit"); + } else { + $mt->setOnScreenMessage('failure', $lng->txt("msg_no_title"), true); + $ctrl->redirect($this, "render"); + } + } + +} diff --git a/components/ILIAS/Blog/Editing/Service/class.GUIService.php b/components/ILIAS/Blog/Editing/Service/class.GUIService.php new file mode 100644 index 000000000000..48eb53b951dc --- /dev/null +++ b/components/ILIAS/Blog/Editing/Service/class.GUIService.php @@ -0,0 +1,58 @@ +data, + $this->domain, + $this->gui, + $node_id, + $id_type, + $perm, + $month, + $content_style_domain, + $parent_gui + ); + } +} diff --git a/components/ILIAS/Blog/Export/BlogHtmlExport.php b/components/ILIAS/Blog/Export/BlogHtmlExport.php index b94f698f5158..328252e40d0b 100755 --- a/components/ILIAS/Blog/Export/BlogHtmlExport.php +++ b/components/ILIAS/Blog/Export/BlogHtmlExport.php @@ -25,6 +25,8 @@ class BlogHtmlExport { + protected ?\ILIAS\Blog\Settings\Settings $settings; + protected \ILIAS\Blog\InternalGUIService $gui; protected \ILIAS\Blog\Posting\PostingManager $posting_manager; protected \ILIAS\components\Export\HTML\ExportCollector $collector; protected \ilObjBlog $blog; @@ -47,6 +49,7 @@ class BlogHtmlExport public function __construct( \ilObjBlogGUI $blog_gui, + protected bool $is_repository, string $exp_dir, string $sub_dir, bool $set_export_key = true @@ -56,11 +59,15 @@ public function __construct( $this->blog_gui = $blog_gui; /** @var \ilObjBlog $blog */ $blog = $blog_gui->getObject(); + $this->blog = $blog; + + $blog_service = $DIC->blog()->internal(); + $this->gui = $blog_service->gui(); + $this->settings = $blog_service->domain()->blogSettings()->getByObjId($blog->getId()); + $this->collector = $DIC->export()->domain()->html()->collector($blog->getId()); $this->collector->init(); - $this->blog = $blog; - //$this->export_dir = $exp_dir; $this->sub_dir = $sub_dir; $this->target_dir = $exp_dir . "/" . $sub_dir; @@ -81,12 +88,12 @@ public function __construct( } $cs = $DIC->contentStyle(); - if ($this->blog_gui->getIdType() === \ilObject2GUI::REPOSITORY_NODE_ID) { + if ($this->is_repository) { $this->content_style_domain = $cs->domain()->styleForRefId($this->blog->getRefId()); } else { $this->content_style_domain = $cs->domain()->styleForObjId($this->blog->getId()); } - $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); + $this->posting_manager = $blog_service->domain()->posting(); } protected function init(): void { @@ -176,7 +183,17 @@ public function exportHTMLPages( // lists // global nav - $nav = $this->blog_gui->renderNavigation("", "", $a_link_template); + $nav = $this->gui->navigation()->sideBar( + null, + $this->gui->navigation()->exportLink( + $a_link_template, + [] + ), + $this->settings + )->render( + $this->blog_gui, + $this->items + ); // month list $has_index = false; @@ -254,10 +271,16 @@ public function exportHTMLPages( : ""; // posting nav - $nav = $this->blog_gui->renderNavigation( - "", - "", - $a_link_template, + $nav = $this->gui->navigation()->sideBar( + null, + $this->gui->navigation()->exportLink( + $a_link_template, + [] + ), + $this->settings + )->render( + $this->blog_gui, + $this->items, false, $page_id ); @@ -339,8 +362,6 @@ public function buildExportLink( protected function getInitialisedTemplate( string $a_back_url = "" ): \ilGlobalPageTemplate { - global $DIC; - $this->export_util->resetGlobalScreen(); $location_stylesheet = \ilUtil::getStyleSheetLocation(); @@ -350,13 +371,18 @@ protected function getInitialisedTemplate( ); \ilPCQuestion::resetInitialState(); - $tabs = $DIC->tabs(); + $tabs = $this->tabs; $tabs->clearTargets(); $tabs->clearSubTabs(); if ($a_back_url) { $tabs->setBackTarget($this->lng->txt("back"), $a_back_url); } - $tpl = new \ilGlobalPageTemplate($DIC->globalScreen(), $DIC->ui(), $DIC->http()); + + $tpl = new \ilGlobalPageTemplate( + $this->global_screen, + $this->gui->ui(), + $this->gui->http() + ); $this->co_page_html_export->getPreparedMainTemplate($tpl); diff --git a/components/ILIAS/Blog/Export/class.ilBlogDataSet.php b/components/ILIAS/Blog/Export/class.ilBlogDataSet.php index b3aa993583a5..b8f8e9195cbe 100755 --- a/components/ILIAS/Blog/Export/class.ilBlogDataSet.php +++ b/components/ILIAS/Blog/Export/class.ilBlogDataSet.php @@ -44,13 +44,15 @@ public function __construct() { global $DIC; parent::__construct(); + + $blog_service = $DIC->blog()->internal(); + $this->content_style_domain = $DIC ->contentStyle() ->domain(); $this->notes = $DIC->notes(); - $this->reading_time = $DIC->blog()->internal()->domain()->readingTime(); - $this->blog_settings = $DIC->blog()->internal()->domain()->blogSettings(); - $this->service = $DIC->blog()->internal(); + $this->reading_time = $blog_service->domain()->readingTime(); + $this->blog_settings = $blog_service->domain()->blogSettings(); } public function getSupportedVersions(): array @@ -285,7 +287,7 @@ public function readData( // keywords foreach ($this->data as $idx => $item) { - $blog_id = ilBlogPosting::lookupBlogId($item["Id"]); + $blog_id = $this->service->domain()->posting()->lookupBlogId((int) $item["Id"]); $keywords = $this->service->domain()->posting()->getKeywords((int) $blog_id, (int) $item["Id"]); if ($keywords) { foreach ($keywords as $kidx => $keyword) { diff --git a/components/ILIAS/Blog/Export/class.ilBlogExporter.php b/components/ILIAS/Blog/Export/class.ilBlogExporter.php index ca20e3be90f0..4132a223fb5f 100755 --- a/components/ILIAS/Blog/Export/class.ilBlogExporter.php +++ b/components/ILIAS/Blog/Export/class.ilBlogExporter.php @@ -28,16 +28,23 @@ class ilBlogExporter extends ilXmlExporter protected ilBlogDataSet $ds; protected \ILIAS\Style\Content\DomainService $content_style_domain; - public function init(): void + public function __construct() { global $DIC; + parent::__construct(); + $blog_service = $DIC->blog()->internal(); - $this->ds = new ilBlogDataSet(); - $this->ds->setDSPrefix("ds"); $this->content_style_domain = $DIC ->contentStyle() ->domain(); - $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); + $this->posting_manager = $blog_service->domain()->posting(); + } + + + public function init(): void + { + $this->ds = new ilBlogDataSet(); + $this->ds->setDSPrefix("ds"); } public function getXmlExportTailDependencies( diff --git a/components/ILIAS/Blog/Export/class.ilBlogImporter.php b/components/ILIAS/Blog/Export/class.ilBlogImporter.php index 4481de258d39..d0c21290b127 100755 --- a/components/ILIAS/Blog/Export/class.ilBlogImporter.php +++ b/components/ILIAS/Blog/Export/class.ilBlogImporter.php @@ -25,19 +25,23 @@ */ class ilBlogImporter extends ilXmlImporter { + protected \ILIAS\Blog\InternalService $blog_service; protected ilBlogDataSet $ds; protected \ILIAS\Style\Content\DomainService $content_style_domain; - public function init(): void + public function __construct() { global $DIC; - - $this->ds = new ilBlogDataSet(); - $this->ds->setDSPrefix("ds"); $this->content_style_domain = $DIC ->contentStyle() ->domain(); + $this->blog_service = $DIC->blog()->internal(); + } + public function init(): void + { + $this->ds = new ilBlogDataSet(); + $this->ds->setDSPrefix("ds"); $cop_config = $this->getImport()->getConfig("components/ILIAS/COPage"); $cop_config->setUpdateIfExists(true); } @@ -64,7 +68,7 @@ public function finalProcessing( $blp_map = $a_mapping->getMappingsOfEntity("components/ILIAS/COPage", "pg"); foreach ($blp_map as $blp_id) { $blp_id = (int) substr($blp_id, 4); - $blog_id = ilBlogPosting::lookupBlogId($blp_id); + $blog_id = $this->blog_service->domain()->posting()->lookupBlogId($blp_id); ilBlogPosting::_writeParentId("blp", $blp_id, (int) $blog_id); } diff --git a/components/ILIAS/Blog/Navigation/AuthorBlockGUI.php b/components/ILIAS/Blog/Navigation/AuthorBlockGUI.php new file mode 100644 index 000000000000..2ecc6fb64c09 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/AuthorBlockGUI.php @@ -0,0 +1,96 @@ +gui->standardRequest()->getRefId()); + $posting_list = $this->domain->postingList( + $obj_id, + $this->domain->blogSettings()->getByObjId($obj_id), + $show_inactive + ); + $authors = $posting_list->getAuthors(); + + // filter out deleted users + $authors = array_filter($authors, function ($id) { + return \ilObject::_lookupType($id) == "usr"; + }); + + if (count($authors) > 1) { + $list = array(); + foreach ($authors as $user_id) { + if ($user_id) { + $url = $this->link_builder->forAuthor($user_id); + + $base_name = \ilUserUtil::getNamePresentation($user_id); + if (str_starts_with($base_name, "[")) { + $name = \ilUserUtil::getNamePresentation($user_id, true); + $sort = $name; + } else { + $name = \ilUserUtil::getNamePresentation( + $user_id, + true, + false, + "", + false, + true, + false + ); + $name_arr = \ilObjUser::_lookupName($user_id); + $sort = $name_arr["lastname"] . " " . $name_arr["firstname"]; + } + + $idx = trim(strip_tags((string) $sort)) . "///" . $user_id; + $list[$idx] = array($name, $url); + } + } + ksort($list); + + $wtpl = new \ilTemplate("tpl.blog_list_navigation_authors.html", true, true, "components/ILIAS/Blog"); + + $wtpl->setCurrentBlock("author"); + foreach ($list as $author) { + $wtpl->setVariable("TXT_AUTHOR", $author[0]); + $wtpl->setVariable("URL_AUTHOR", $author[1]); + $wtpl->parseCurrentBlock(); + } + + return $wtpl->get(); + } + return ""; + } +} diff --git a/components/ILIAS/Blog/Navigation/KeywordBlockGUI.php b/components/ILIAS/Blog/Navigation/KeywordBlockGUI.php new file mode 100644 index 000000000000..157b4f5590bc --- /dev/null +++ b/components/ILIAS/Blog/Navigation/KeywordBlockGUI.php @@ -0,0 +1,111 @@ +getKeywords($show_inactive, $blpg); + if ($keywords) { + $wtpl = new \ilTemplate("tpl.blog_list_navigation_keywords.html", true, true, "components/ILIAS/Blog"); + + $max = max($keywords); + + $wtpl->setCurrentBlock("keyword"); + foreach ($keywords as $keyword => $counter) { + $url = $this->link_builder->forKeyword($keyword); + + $wtpl->setVariable("TXT_KEYWORD", (string) $keyword); + $wtpl->setVariable("CLASS_KEYWORD", \ilTagging::getRelevanceClass((int) $counter, (int) $max)); + $wtpl->setVariable("URL_KEYWORD", $url); + $wtpl->parseCurrentBlock(); + } + + return $wtpl->get(); + } + return ""; + } + + protected function getKeywords( + bool $show_inactive, + ?int $posting_id = null + ): array { + $keywords = array(); + $posting_manager = $this->domain->posting(); + $obj_id = \ilObject::_lookupObjId($this->gui->standardRequest()->getRefId()); + + if ($posting_id) { + foreach ($posting_manager->getKeywords($obj_id, $posting_id) as $keyword) { + if (isset($keywords[$keyword])) { + $keywords[$keyword]++; + } else { + $keywords[$keyword] = 1; + } + } + } else { + $posting_list = $this->domain->postingList( + $obj_id, + $this->domain->blogSettings()->getByObjId($obj_id), + $show_inactive + ); + $all_items = $posting_list->getPostingsGroupedByMonth(); + foreach ($all_items as $month => $month_items) { + foreach ($month_items as $item) { + $item_id = $item->getId(); + foreach ($posting_manager->getKeywords($obj_id, $item_id) as $keyword) { + if (isset($keywords[$keyword])) { + $keywords[$keyword]++; + } else { + $keywords[$keyword] = 1; + } + } + } + } + } + + $tmp = array(); + foreach ($keywords as $keyword => $counter) { + $tmp[] = array("keyword" => $keyword, "counter" => $counter); + } + $tmp = \ilArrayUtil::sortArray($tmp, "keyword", "ASC"); + + $keywords = array(); + foreach ($tmp as $item) { + $keywords[(string) $item["keyword"]] = $item["counter"]; + } + return $keywords; + } +} diff --git a/components/ILIAS/Blog/Navigation/Link/EditingLinkBuilder.php b/components/ILIAS/Blog/Navigation/Link/EditingLinkBuilder.php new file mode 100644 index 000000000000..932a7e9d554c --- /dev/null +++ b/components/ILIAS/Blog/Navigation/Link/EditingLinkBuilder.php @@ -0,0 +1,49 @@ + [ + \ilObjBlogGUI::class, + EditingGUI::class + ], + self::VIEW_POSTING => [ + \ilObjBlogGUI::class, + EditingGUI::class, + \ilBlogPostingGUI::class + ], + }; + } + + protected function getCmdForView(string $view): string + { + return match ($view) { + self::VIEW_MAIN => "render", + self::VIEW_POSTING => "edit", + }; + } +} diff --git a/components/ILIAS/Blog/Navigation/Link/ExportLinkBuilder.php b/components/ILIAS/Blog/Navigation/Link/ExportLinkBuilder.php new file mode 100644 index 000000000000..feb3706874f4 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/Link/ExportLinkBuilder.php @@ -0,0 +1,65 @@ +template); + } + + public function forMonth(string $month): string + { + return $this->build("m", $month); + } + + public function forPosting(int $posting_id, string $month = ""): string + { + return $this->build("p", (string) $posting_id); + } + + public function forKeyword(string $keyword): string + { + $id = (string) ($this->keyword_map[$keyword] ?? ""); + return $this->build("k", $id); + } + + public function forAuthor(int $user_id): string + { + // Currently not supported in HTML export, but could be added if needed. + return ""; + } + + public function forMainList(): string + { + return "index.html"; + } +} diff --git a/components/ILIAS/Blog/Navigation/Link/LinkBuilder.php b/components/ILIAS/Blog/Navigation/Link/LinkBuilder.php new file mode 100644 index 000000000000..27f231f074b5 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/Link/LinkBuilder.php @@ -0,0 +1,52 @@ +manager->getPermanentLink($posting_id); + } + + public function forKeyword(string $keyword): string + { + // Not supported by permanent links + return ""; + } + + public function forAuthor(int $user_id): string + { + // Not supported by permanent links + return ""; + } + + public function forMainList(): string + { + return $this->manager->getPermanentLink(); + } +} diff --git a/components/ILIAS/Blog/Navigation/Link/PresentationLinkBuilder.php b/components/ILIAS/Blog/Navigation/Link/PresentationLinkBuilder.php new file mode 100644 index 000000000000..afad32ce8ac8 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/Link/PresentationLinkBuilder.php @@ -0,0 +1,123 @@ + [ + \ilObjBlogGUI::class, + PresentationGUI::class + ], + self::VIEW_POSTING => [ + \ilObjBlogGUI::class, + PresentationGUI::class, + \ilBlogPostingGUI::class + ], + }; + } + + protected function getCmdForView(string $view): string + { + return match ($view) { + self::VIEW_MAIN => "preview", + self::VIEW_POSTING => "previewFullscreen", + }; + } + + protected function setParameter( + string $view, + string $par, + string $value + ): void { + $path = $this->getPathForView($view); + $class = end($path); + $this->ctrl->setParameterByClass($class, $par, $value); + } + + protected function getLinkForView(string $view): string + { + return $this->ctrl->getLinkTargetByClass( + $this->getPathForView($view), + $this->getCmdForView($view) + ); + } + + public function forMonth(string $month): string + { + $this->setParameter(self::VIEW_MAIN, self::PAR_MONTH, $month); + $this->setParameter(self::VIEW_MAIN, self::PAR_POSTING, ""); + return $this->getLinkForView(self::VIEW_MAIN); + } + + public function forPosting(int $posting_id, string $month = ""): string + { + $this->setParameter(self::VIEW_POSTING, self::PAR_MONTH, $month); + $this->setParameter(self::VIEW_POSTING, self::PAR_POSTING, (string) $posting_id); + return $this->getLinkForView(self::VIEW_POSTING); + } + + public function forKeyword(string $keyword): string + { + $this->setParameter(self::VIEW_MAIN, self::PAR_KEYWORD, urlencode($keyword)); + $this->setParameter(self::VIEW_MAIN, self::PAR_POSTING, ""); + $link = $this->getLinkForView(self::VIEW_MAIN); + $this->setParameter(self::VIEW_MAIN, self::PAR_KEYWORD, ""); + return $link; + } + + public function forAuthor(int $user_id): string + { + $this->setParameter(self::VIEW_MAIN, self::PAR_AUTHOR, (string) $user_id); + $this->setParameter(self::VIEW_MAIN, self::PAR_POSTING, ""); + $link = $this->getLinkForView(self::VIEW_MAIN); + $this->setParameter(self::VIEW_MAIN, self::PAR_AUTHOR, ""); + return $link; + } + + public function forMainList(): string + { + $this->setParameter(self::VIEW_MAIN, self::PAR_MONTH, ""); + $this->setParameter(self::VIEW_MAIN, self::PAR_POSTING, ""); + return $this->getLinkForView(self::VIEW_MAIN); + } +} diff --git a/components/ILIAS/Blog/Navigation/MonthBlockGUI.php b/components/ILIAS/Blog/Navigation/MonthBlockGUI.php new file mode 100644 index 000000000000..d8f294d1bcb0 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/MonthBlockGUI.php @@ -0,0 +1,204 @@ +link_builder instanceof ExportLinkBuilder; + } + + /** + * @param Posting[][] $items + */ + public function render( + array $items, + bool $show_inactive = false, + int $blpg = 0 + ): string { + $ctrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + $obj_id = \ilObject::_lookupObjId($this->gui->standardRequest()->getRefId()); + $settings = $this->domain->blogSettings()->getByObjId($obj_id); + + if (!$show_inactive) { + $items = $this->domain->postingList($obj_id, $settings, false)->getPostingsGroupedByMonth(); + } + + // list month (incl. postings) + if ($settings->getNavMode() === \ilObjBlog::NAV_MODE_LIST || + $this->isExport()) { + $max_months = $settings->getNavModeListMonths(); + + $wtpl = new \ilTemplate("tpl.blog_list_navigation_by_date.html", true, true, "components/ILIAS/Blog"); + + $ctrl->setParameterByClass(\ilObjBlogGUI::class, "blpg", ""); + + $counter = $mon_counter = $last_year = 0; + foreach ($items as $month => $postings) { + if (!$this->isExport() && $max_months && $mon_counter >= $max_months) { + break; + } + + $add_year = false; + $year = substr((string) $month, 0, 4); + if (!$last_year || $year != $last_year) { + $add_year = true; + $last_year = $year; + } + + $mon_counter++; + + $month_name = \ilCalendarUtil::_numericMonthToString((int) substr((string) $month, 5)); + $month_url = $this->link_builder->forMonth($month); + + if ($mon_counter <= $settings->getNavModeListMonthsWithPostings()) { + if ($add_year) { + $wtpl->setCurrentBlock("navigation_year_details"); + $wtpl->setVariable("YEAR", $year); + $wtpl->parseCurrentBlock(); + } + + foreach ($postings as $id => $posting) { + $caption = $posting->getTitle(); + $url = $this->link_builder->forPosting($posting->getId()); + if (!$posting->isActive()) { + $wtpl->setVariable("NAV_ITEM_DRAFT", $lng->txt("blog_draft")); + } elseif ($settings->getApproval() && !$posting->isApproved()) { + $wtpl->setVariable("NAV_ITEM_APPROVAL", $lng->txt("blog_needs_approval")); + } + + $wtpl->setCurrentBlock("navigation_item"); + $wtpl->setVariable("NAV_ITEM_URL", $url); + $wtpl->setVariable("NAV_ITEM_CAPTION", $caption); + $wtpl->parseCurrentBlock(); + } + + $wtpl->setCurrentBlock("navigation_month_details"); + $wtpl->setVariable("NAV_MONTH", $month_name); + $wtpl->setVariable("URL_MONTH", $month_url); + $wtpl->parseCurrentBlock(); + } + // summarized month + else { + if ($add_year) { + $wtpl->setCurrentBlock("navigation_year"); + $wtpl->setVariable("YEAR", $year); + $wtpl->parseCurrentBlock(); + } + + $wtpl->setCurrentBlock("navigation_month"); + $wtpl->setVariable("MONTH_NAME", $month_name); + $wtpl->setVariable("URL_MONTH", $month_url); + $wtpl->setVariable("MONTH_COUNT", (string) count($postings)); + $wtpl->parseCurrentBlock(); + } + } + $url = $this->link_builder->forMainList(); + + $wtpl->setVariable( + "STARTING_PAGE", + $this->gui->ui()->renderer()->render( + $this->gui->ui()->factory()->link()->standard( + $lng->txt("blog_starting_page"), + $url + ) + ) + ); + $ctrl->setParameterByClass(\ilObjBlogGUI::class, "bmn", $this->gui->standardRequest()->getMonth()); + $ctrl->setParameterByClass(\ilBlogPostingGUI::class, "bmn", ""); + return $wtpl->get(); + } + // single month + else { + $wtpl = new \ilTemplate("tpl.blog_list_navigation_month.html", true, true, "components/ILIAS/Blog"); + + $ctrl->setParameterByClass(\ilObjBlogGUI::class, "blpg", ""); + + $month_options = array(); + foreach ($items as $month => $postings) { + $month_name = $this->gui->presentation()->util()->getMonthPresentation((string) $month); + + $month_options[(string) $month] = $month_name; + + if ($month == $this->gui->standardRequest()->getMonth()) { + $month_url = $this->link_builder->forMonth($month); + + foreach ($postings as $id => $posting) { + $caption = $posting->getTitle(); + $url = $this->link_builder->forPosting($id); + + if (!$posting->isActive()) { + $wtpl->setVariable("NAV_ITEM_DRAFT", $lng->txt("blog_draft")); + } elseif ($settings->getApproval() && !$posting->isApproved()) { + $wtpl->setVariable("NAV_ITEM_APPROVAL", $lng->txt("blog_needs_approval")); + } + + $wtpl->setCurrentBlock("navigation_item"); + $wtpl->setVariable("NAV_ITEM_URL", $url); + $wtpl->setVariable("NAV_ITEM_CAPTION", $caption); + $wtpl->parseCurrentBlock(); + } + + $wtpl->setCurrentBlock("navigation_month_details"); + if ($blpg > 0) { + $wtpl->setVariable("NAV_MONTH", $month_name); + $wtpl->setVariable("URL_MONTH", $month_url); + } + $wtpl->parseCurrentBlock(); + } + } + + /* + if ($blpg === 0) { + $wtpl->setCurrentBlock("option_bl"); + foreach ($month_options as $value => $caption) { + $wtpl->setVariable("OPTION_VALUE", $value); + $wtpl->setVariable("OPTION_CAPTION", $caption); + if ($value == $this->gui->standardRequest()->getMonth()) { + $wtpl->setVariable("OPTION_SEL", ' selected="selected"'); + } + $wtpl->parseCurrentBlock(); + } + + $wtpl->setVariable("FORM_ACTION", $ctrl->getFormActionByClass(\ilObjBlogGUI::class, $list_cmd)); + } + */ + } + $ctrl->setParameterByClass(\ilObjBlogGUI::class, "bmn", $this->gui->standardRequest()->getMonth()); + $ctrl->setParameterByClass(\ilBlogPostingGUI::class, "bmn", ""); + return $wtpl->get(); + } +} diff --git a/components/ILIAS/Blog/Navigation/PresentationHeaderGUI.php b/components/ILIAS/Blog/Navigation/PresentationHeaderGUI.php new file mode 100644 index 000000000000..ee7058843182 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/PresentationHeaderGUI.php @@ -0,0 +1,142 @@ +addHeaderActionForCommand (called in editing, presentation and bloggui) + * -> addHeaderActionForCommandInternal + * -> initHeaderAction + * -> $this->initHeaderAction (ilObjectGUI) + * -> insertHeaderAction + */ +class PresentationHeaderGUI +{ + protected \ilObjUser $user; + + public function __construct( + protected InternalDomainService $domain, + protected InternalGUIService $gui, + protected \ilObjBlog $blog, + protected PermissionManager $perm, + ) { + $this->user = $this->domain->user(); + } + + public function addHeaderAction( + ?\ilObjectListGUI $list_gui + ): void { + $user = $this->domain->user(); + + // notification + if ($user->getId() !== ANONYMOUS_USER_ID) { + $this->insertHeaderAction($list_gui); + } + } + + public function get( + ?\ilObjectListGUI $lg, + int $posting_id = 0 + ): ?ilObjectListGUI { + $ctrl = $this->gui->ctrl(); + $lng = $this->domain->lng(); + if ($posting_id > 0) { + if ($this->blog->getNotesStatus()) { + $lg->enableComments(true); + } + $lg->enableNotes(true); + } + $lg->enableTags(false); + + if (\ilNotification::hasNotification( + \ilNotification::TYPE_BLOG, + $this->user->getId(), + $this->blog->getId() + ) + ) { + $ctrl->setParameterByClass( + PresentationGUI::class, + "ntf", + "1" + ); + $link = $ctrl->getLinkTargetByClass( + PresentationGUI::class, + "setNotification" + ); + $ctrl->setParameter($this, "ntf", ""); + if (\ilNotification::hasOptOut($this->blog->getId())) { + $lg->addCustomCommand($link, "blog_notification_toggle_off"); + } + + $lg->addHeaderIcon( + "not_icon", + \ilUtil::getImagePath("object/notification_on.svg"), + $lng->txt("blog_notification_activated") + ); + } else { + $ctrl->setParameterByClass(PresentationGUI::class, "ntf", 2); + $link = $ctrl->getLinkTargetByClass(PresentationGUI::class, "setNotification"); + $ctrl->setParameterByClass(PresentationGUI::class, "ntf", ""); + $lg->addCustomCommand($link, "blog_notification_toggle_on"); + + $lg->addHeaderIcon( + "not_icon", + \ilUtil::getImagePath("object/notification_off.svg"), + $lng->txt("blog_notification_deactivated") + ); + } + + // #11758 + if ($this->perm->mayContribute()) { + $edit_path = [ + \ilObjBlogGUI::class, + EditingGUI::class + ]; + $ctrl->setParameterByClass(EditingGUI::class, "bmn", ""); + $ctrl->setParameterByClass(EditingGUI::class, "blpg", ""); + $link = $ctrl->getLinkTargetByClass($edit_path, ""); + $lg->addCustomCommand($link, "blog_edit"); // #11868 + + $posting_path = [ + \ilObjBlogGUI::class, + EditingGUI::class, + \ilBlogPostingGUI::class, + ]; + $ctrl->setParameterByClass(\ilObjBlogGUI::class, "blpg", $posting_id); + + if ($posting_id && $this->perm->mayEditPosting($posting_id)) { + $link = $ctrl->getLinkTargetByClass(\ilBlogPostingGUI::class, "edit"); + $lg->addCustomCommand($link, "blog_edit_posting"); + } + } + + $ctrl->setParameterByClass(PresentationGUI::class, "ntf", ""); + + return $lg; + } +} diff --git a/components/ILIAS/Blog/Navigation/Service/class.GUIService.php b/components/ILIAS/Blog/Navigation/Service/class.GUIService.php index e89279158f08..0212241be6a9 100755 --- a/components/ILIAS/Blog/Navigation/Service/class.GUIService.php +++ b/components/ILIAS/Blog/Navigation/Service/class.GUIService.php @@ -22,6 +22,12 @@ use ILIAS\Blog\InternalDomainService; use ILIAS\Blog\InternalGUIService; +use ILIAS\Blog\Permission\PermissionManager; +use ILIAS\Blog\Navigation\Link\PresentationLinkBuilder; +use ILIAS\Blog\Navigation\Link\EditingLinkBuilder; +use ILIAS\Blog\Navigation\Link\ExportLinkBuilder; +use ILIAS\Blog\Navigation\Link\LinkBuilder; +use ILIAS\Blog\Settings\Settings; class GUIService { @@ -37,10 +43,97 @@ public function __construct( } public function toolbarNavigationRenderer( + LinkBuilder $link_builder ): ToolbarNavigationRenderer { return new ToolbarNavigationRenderer( $this->domain, - $this->gui + $this->gui, + $link_builder ); } + + public function monthBlock( + LinkBuilder $link_builder + ): MonthBlockGUI { + return new MonthBlockGUI( + $this->domain, + $this->gui, + $link_builder + ); + } + + public function authorBlock( + LinkBuilder $link_builder + ): AuthorBlockGUI { + return new AuthorBlockGUI( + $this->domain, + $this->gui, + $link_builder + ); + } + + public function keywordBlock( + LinkBuilder $link_builder + ): KeywordBlockGUI { + return new KeywordBlockGUI( + $this->domain, + $this->gui, + $link_builder + ); + } + + public function sideBar( + ?PermissionManager $perm, + LinkBuilder $link_builder, + Settings $settings, + ?int $node_id = null, + int $id_type = \ilObjBlogGUI::REPOSITORY_NODE_ID + ): SideBarGUI { + return new SideBarGUI( + $this->domain, + $this->gui, + $perm, + $link_builder, + $settings, + $node_id, + $id_type + ); + } + + public function presentationHeader( + \ilObjBlog $blog, + PermissionManager $perm, + ): PresentationHeaderGUI { + return new PresentationHeaderGUI( + $this->domain, + $this->gui, + $blog, + $perm + ); + } + + public function presentationLink(): PresentationLinkBuilder + { + return new PresentationLinkBuilder( + $this->gui->ctrl(), + ); + } + + public function editingLink(): EditingLinkBuilder + { + return new EditingLinkBuilder( + $this->gui->ctrl(), + ); + } + + public function exportLink( + string $link_template = "", + array $keyword_map = [] + ): ExportLinkBuilder { + return new ExportLinkBuilder( + $link_template, + $keyword_map + ); + } + } diff --git a/components/ILIAS/Blog/Navigation/SideBarGUI.php b/components/ILIAS/Blog/Navigation/SideBarGUI.php new file mode 100644 index 000000000000..71f594a269c5 --- /dev/null +++ b/components/ILIAS/Blog/Navigation/SideBarGUI.php @@ -0,0 +1,186 @@ +domain = $domain; + $this->gui = $gui; + } + + protected function mayEditPosting(int $blpg): bool + { + if ($this->link_builder instanceof EditingLinkBuilder && + !is_null($this->perm) && + $this->perm->mayEditPosting($blpg)) { + return true; + } + return false; + } + + protected function isExport(): bool + { + return $this->link_builder instanceof ExportLinkBuilder; + } + + protected function isPresentation(): bool + { + return $this->link_builder instanceof PresentationLinkBuilder; + } + + /** + * Build navigation blocks + */ + public function render( + \ilObjBlogGUI $gui_obj, + array $items, + bool $show_inactive = false, + int $blpg = 0 + ): string { + $lng = $this->domain->lng(); + $ui = $this->gui->ui(); + if ($this->settings->getOrder()) { + $order = array_flip($this->settings->getOrder()); + } else { + $order = array( + "navigation" => 0, + "keywords" => 2, + "authors" => 1 + ); + } + + $wtpl = new ilTemplate("tpl.blog_list_navigation.html", true, true, "components/ILIAS/Blog"); + + $blocks = array(); + + // by date + if (count($items)) { + $blocks[$order["navigation"] ?? 0] = array( + $lng->txt("blog_navigation"), + $this->gui->navigation()->monthBlock($this->link_builder)->render( + $items, + $show_inactive, + $blpg + ) + ); + } + + if ($this->settings->getKeywords()) { + // keywords + $may_edit_keywords = ($blpg > 0 && + $this->mayEditPosting($blpg)); + + $keywords = $this->gui->navigation()->keywordBlock($this->link_builder)->render( + $show_inactive, + $blpg + ); + if ($keywords || $may_edit_keywords) { + if (!$keywords) { + $keywords = $lng->txt("blog_no_keywords"); + } + $cmd = null; + $blocks[$order["keywords"] ?? 2] = array( + $lng->txt("blog_keywords"), + $keywords, + $cmd + ? array($cmd, $lng->txt("blog_edit_keywords")) + : null + ); + } + } + + // is not part of (html) export + if (!$this->isExport()) { + // authors + if ($this->id_type === \ilObjBlogGUI::REPOSITORY_NODE_ID && + $this->settings->getAuthors()) { + $authors = $this->gui->navigation()->authorBlock($this->link_builder)->render( + $show_inactive + ); + if ($authors) { + $blocks[$order["authors"] ?? 1] = array($lng->txt("blog_authors"), $authors); + } + } + + // rss + if ($this->settings->getRSS() && + $this->domain->settings()->get('enable_global_profiles') && + $this->isPresentation()) { + // #10827 + $blog_id = (string) $this->node_id; + if ($this->id_type !== \ilObjBlogGUI::WORKSPACE_NODE_ID) { + $blog_id .= "_cll"; + } + $url = ILIAS_HTTP_PATH . "/feed.php?blog_id=" . $blog_id . + "&client_id=" . rawurlencode(CLIENT_ID); + + $wtpl->setVariable("RSS_BUTTON", ilRSSButtonGUI::get(ilRSSButtonGUI::ICON_RSS, $url)); + } + } + + if (count($blocks)) { + $ui_factory = $ui->factory(); + $ui_renderer = $ui->renderer(); + + ksort($blocks); + foreach ($blocks as $block) { + $title = $block[0]; + $content = $block[1]; + + $secondary_panel = $ui_factory->panel()->secondary()->legacy($title, $ui_factory->legacy()->content($content)); + + if (isset($block[2]) && is_array($block[2])) { + $link = $ui_factory->button()->shy($block[2][1], $block[2][0]); + $secondary_panel = $secondary_panel->withFooter($link); + } + + $wtpl->setCurrentBlock("block_bl"); + $wtpl->setVariable("BLOCK", $ui_renderer->render($secondary_panel)); + $wtpl->parseCurrentBlock(); + } + } + + return $wtpl->get(); + } +} diff --git a/components/ILIAS/Blog/Navigation/ToolbarNavigationRenderer.php b/components/ILIAS/Blog/Navigation/ToolbarNavigationRenderer.php index aca2ab2cf074..8ce022685e73 100755 --- a/components/ILIAS/Blog/Navigation/ToolbarNavigationRenderer.php +++ b/components/ILIAS/Blog/Navigation/ToolbarNavigationRenderer.php @@ -24,9 +24,12 @@ use ILIAS\Blog\InternalGUIService; use ILIAS\Blog\Permission\PermissionManager; use ILIAS\Blog\Posting\Posting; +use ILIAS\Blog\Navigation\Link\LinkBuilder; +use ILIAS\Blog\Editing\EditingGUI; class ToolbarNavigationRenderer { + protected Link\EditingLinkBuilder $edit_link_builder; protected array $items; protected InternalGUIService $gui; protected int $portfolio_page; @@ -39,11 +42,13 @@ class ToolbarNavigationRenderer public function __construct( InternalDomainService $domain, - InternalGUIService $gui + InternalGUIService $gui, + protected LinkBuilder $pres_link_builder ) { $this->domain = $domain; $this->gui = $gui; $this->util = $gui->presentation()->util(); + $this->edit_link_builder = $gui->navigation()->editingLink(); } public function renderToolbarNavigation( @@ -62,21 +67,19 @@ public function renderToolbarNavigation( $this->blog_page = $blog_page; $this->portfolio_page = $portfolio_page; - $cmd = "previewFullscreen"; - if ($single_posting) { // single posting view $next_posting = $this->getNextPosting($blog_page); if ($next_posting > 0) { - $this->renderPreviousButton($this->getPostingTarget($next_posting, $cmd)); + $this->renderPreviousButton($this->getPostingTarget($next_posting)); } else { $this->renderPreviousButton(""); } - $this->renderPostingDropdown($cmd); + $this->renderPostingDropdown(); $prev_posting = $this->getPreviousPosting($blog_page); if ($prev_posting > 0) { - $this->renderNextButton($this->getPostingTarget($prev_posting, $cmd)); + $this->renderNextButton($this->getPostingTarget($prev_posting)); } else { $this->renderNextButton(""); } @@ -117,13 +120,7 @@ protected function renderActionDropdown(bool $single_posting): void $ctrl = $this->ctrl; $actions = []; if ($this->blog_access->mayContribute()) { - $ctrl->setParameterByClass(\ilObjBlogGUI::class, "prvm", ""); - - $ctrl->setParameterByClass(\ilObjBlogGUI::class, "bmn", ""); - $ctrl->setParameterByClass(\ilObjBlogGUI::class, "blpg", ""); - $link = $ctrl->getLinkTargetByClass(\ilObjBlogGUI::class, ""); - $ctrl->setParameterByClass(\ilObjBlogGUI::class, "blpg", $this->blog_page); - $ctrl->setParameterByClass(\ilObjBlogGUI::class, "bmn", $this->current_month); + $link = $this->edit_link_builder->forMainList(); $actions[] = $f->button()->shy( $lng->txt("blog_edit"), $link @@ -131,8 +128,7 @@ protected function renderActionDropdown(bool $single_posting): void } if ($single_posting && $this->blog_access->mayContribute() && $this->blog_access->mayEditPosting($this->blog_page)) { - $ctrl->setParameterByClass(\ilBlogPostingGUI::class, "blpg", $this->blog_page); - $link = $ctrl->getLinkTargetByClass(\ilBlogPostingGUI::class, "edit"); + $link = $this->edit_link_builder->forPosting($this->blog_page); $actions[] = $f->button()->shy( $lng->txt("blog_edit_posting"), $link @@ -204,16 +200,14 @@ protected function getPreviousPosting( return $prev_blpg; } - protected function getPostingTarget(int $posting, string $cmd): string + protected function getPostingTarget(int $posting): string { - $this->ctrl->setParameterByClass(\ilBlogPostingGUI::class, "blpg", (string) $posting); - return $this->ctrl->getLinkTargetByClass(\ilBlogPostingGUI::class, $cmd); + return $this->pres_link_builder->forPosting($posting); } protected function getMonthTarget(string $month): string { - $this->ctrl->setParameterByClass(\ilObjBlogGUI::class, "bmn", $month); - return $this->ctrl->getLinkTargetByClass(\ilObjBlogGUI::class, "preview"); + return $this->pres_link_builder->forMonth($month); } protected function renderMonthDropdown(): void @@ -296,7 +290,7 @@ protected function renderNavButton(string $dir, string $href = ""): void $toolbar->addStickyItem($b); } - protected function renderPostingDropdown(string $cmd): void + protected function renderPostingDropdown(): void { $toolbar = $this->gui->toolbar(); $f = $this->gui->ui()->factory(); @@ -321,7 +315,7 @@ protected function renderPostingDropdown(string $cmd): void $label = str_pad("", 12, " ") . $label; $m[] = $f->link()->standard( $label, - $this->getPostingTarget((int) $item->getId(), $cmd) + $this->getPostingTarget((int) $item->getId()) ); } } diff --git a/components/ILIAS/Blog/News/class.NewsManager.php b/components/ILIAS/Blog/News/class.NewsManager.php index b6b863237105..59227a090de8 100644 --- a/components/ILIAS/Blog/News/class.NewsManager.php +++ b/components/ILIAS/Blog/News/class.NewsManager.php @@ -29,11 +29,15 @@ */ class NewsManager { + protected \ILIAS\Blog\Posting\Service\GUIService $posting_gui; + public function __construct( protected InternalDataService $data, protected InternalRepoService $repo, - protected InternalDomainService $domain + protected InternalDomainService $domain, + \ILIAS\Blog\InternalGUIService $gui ) { + $this->posting_gui = $gui->posting(); } /** @@ -110,7 +114,7 @@ public function handle(\ilBlogPosting $page, bool $update = false): void $news_item->setContentTextIsLangVar(false); $news_item->setContent($content); - $snippet = \ilBlogPostingGUI::getSnippet($page->getId()); + $snippet = $this->posting_gui->getSnippet($page->getId()); $news_item->setContentLong($snippet); if (!$news_item->getId()) { diff --git a/components/ILIAS/Blog/PermanentLink/StaticUrlHandler.php b/components/ILIAS/Blog/PermanentLink/StaticUrlHandler.php index f2e3ea3b9f5c..2a0261e113f7 100644 --- a/components/ILIAS/Blog/PermanentLink/StaticUrlHandler.php +++ b/components/ILIAS/Blog/PermanentLink/StaticUrlHandler.php @@ -29,6 +29,15 @@ class StaticURLHandler extends BaseHandler implements Handler { + protected \ILIAS\Blog\InternalService $blog_service; + + public function __construct() + { + global $DIC; + $this->blog_service = $DIC->blog()->internal(); + parent::__construct(); + } + public function getNamespace(): string { return 'blog'; @@ -36,12 +45,11 @@ public function getNamespace(): string public function handle(Request $request, Context $context, Factory $response_factory): Response { - global $DIC; - - $ctrl = $DIC->ctrl(); - $access = $DIC->access(); + $blog_service = $this->blog_service; + $ctrl = $blog_service->gui()->ctrl(); + $access = $blog_service->domain()->access(); $uri = null; - $blog_domain = $DIC->blog()->internal()->domain(); + $blog_domain = $blog_service->domain(); $id = $request->getReferenceId()?->toInt() ?? 0; $additional_params = $request->getAdditionalParameters() ?? []; diff --git a/components/ILIAS/Blog/Permission/BlogCmdPermission.php b/components/ILIAS/Blog/Permission/BlogCmdPermission.php new file mode 100644 index 000000000000..48265179e1c9 --- /dev/null +++ b/components/ILIAS/Blog/Permission/BlogCmdPermission.php @@ -0,0 +1,214 @@ +access = $perm_manager->getAccessHandler(); + } + + public function isCommandPermitted( + string $cmd, // derived or from table + int $node_id, + string $entity, + string $entity_id = "" + ): bool { + switch ($entity) { + case self::BLOG: + return $this->hasBlogCmdPerm($cmd, $node_id); + case self::POSTING: + return $this->hasPostingCmdPerm($cmd, $node_id, (int) $entity_id); + } + return false; + } + + protected function hasBlogCmdPerm(string $cmd, int $node_id): bool + { + // write permission + if (in_array($cmd, [ + "edit", + "createExportFileWithComments", + "createExportFile", + "export", + "contributors", + "addUserFromAutoComplete", + "addContributor", + "confirmRemoveContributor", + "removeContributor", + "setContentStyleSheet", + "exportWithComments" + ])) { + return $this->access->checkAccess("write", "", $node_id); + } + + if (in_array($cmd, [ + "createPosting", + ])) { + return $this->perm_manager->mayContribute(); + } + + // read permission + if (in_array($cmd, [ + "render", "preview", "addToDesk", "removeFromDesk", "renderFullscreen", + "setNotification", + "printViewSelection", "printPostings" + ])) { + return $this->access->checkAccess("read", "", $node_id); + } + + // visible permission + if (in_array($cmd, [ + "infoScreen" + ])) { + return $this->access->checkAccess("visible", "", $node_id); + } + + + return false; + } + + protected function hasPostingCmdPerm(string $cmd, int $node_id, int $posting_id): bool + { + // redact or write permission + if (in_array($cmd, [ + "approve", + "deactivateAdmin" + ])) { + return $this->perm_manager->canApprove($posting_id); + } + + return false; + } + + public function getDefaultCommand(): string + { + if ($this->isClass(\ilObjBlogGUI::class)) { + return "render"; + } + return ""; + } + + public function getRequestEntity(): ?CmdEntity + { + if ($this->isClass(\ilObjBlogGUI::class)) { + + if (in_array($this->ctrl->getCmd(), ["approve", "deactivateAdmin"])) { + $posting_id = $this->request->getApId(); + return $this->cmdEntity( + self::POSTING, + (string) $posting_id + ); + } + return $this->cmdEntity( + self::BLOG + ); + } + return null; + } + + public function getRequestNodeId(): int + { + if ($this->access instanceof \ilWorkspaceAccessHandler) { + return $this->request->getWspId(); + } + return $this->request->getRefId(); + } + + public function isForwardPermitted( + string $from_class, + string $to_class + ): bool { + $node_id = $this->getRequestNodeId(); + $posting_id = $this->request->getBlogPage(); + if ($from_class === \ilObjBlogGUI::class) { + + // visible or read + if ($to_class === \ilCommonActionDispatcherGUI::class) { + return $this->access->checkAccess("visible", "", $node_id) || + $this->access->checkAccess("read", "", $node_id); + } + + // edit permission + if ($to_class === \ilPermissionGUI::class) { + return $this->access->checkAccess("edit_permission", "", $node_id); + } + + // read posting permission + if ($to_class === \ilBlogPostingGUI::class) { + return $this->perm_manager->canReadPosting($posting_id); + } + + // write permission + if (in_array($to_class, [ + \ilExportGUI::class, + \ilRepositorySearchGUI::class, + \ilObjectContentStyleSettingsGUI::class, + \ilObjNotificationSettingsGUI::class, + \ilObjectMetaDataGUI::class, + SettingsGUI::class, + \ILIAS\Blog\Settings\BlockSettingsGUI::class, + \ILIAS\Blog\Editing\EditingGUI::class, + ContributorGUI::class, + ])) { + return $this->access->checkAccess("write", "", $node_id); + } + + // read permission + // note on ilObjectCopyGUI: This class performs the copy permission checks and + // can act on multiple source ids + if (in_array($to_class, [ + \ilObjectCopyGUI::class, + \ilBlogExerciseGUI::class, + \ILIAS\Blog\Presentation\PresentationGUI::class + ])) { + return $this->access->checkAccess("read", "", $node_id); + } + + // visible + if ($to_class === \ilInfoScreenGUI::class) { + return $this->access->checkAccess("visible", "", $node_id); + } + } + return false; + } + +} diff --git a/components/ILIAS/Blog/Permission/PermissionManager.php b/components/ILIAS/Blog/Permission/PermissionManager.php index fcf834b4cd31..d06b34c409c4 100755 --- a/components/ILIAS/Blog/Permission/PermissionManager.php +++ b/components/ILIAS/Blog/Permission/PermissionManager.php @@ -20,8 +20,12 @@ namespace ILIAS\Blog\Permission; +use ILIAS\Blog\InternalDomainService; + class PermissionManager { + protected \ILIAS\Blog\Posting\PostingManager $posting_manager; + protected \ilWorkspaceTree $ws_tree; protected int $owner; protected int $id_type; protected \ilWorkspaceAccessHandler|\ilAccessHandler $access; @@ -29,6 +33,7 @@ class PermissionManager protected int $user_id; public function __construct( + InternalDomainService $domain, \ilWorkspaceAccessHandler|\ilAccessHandler $access_handler, ?int $node_id, int $id_type, @@ -40,6 +45,8 @@ public function __construct( $this->id_type = $id_type; $this->user_id = $user_id; $this->owner = $owner; + $this->ws_tree = new \ilWorkspaceTree($this->owner); + $this->posting_manager = $domain->posting(); } public function canWrite(): bool @@ -108,8 +115,21 @@ public function canManage(): bool public function canReadPosting(int $posting_id): bool { - return ($this->mayContribute() || - \ilBlogPosting::_lookupActive($posting_id, "blp")); + return ( + $this->postingIdMatches($posting_id) && + $this->checkPermissionBool("read") && + ($this->mayContribute() || + \ilBlogPosting::_lookupActive($posting_id, "blp"))); + } + + public function canApprove(int $posting_id): bool + { + if (!$this->postingIdMatches($posting_id)) { + return false; + } + return ($this->checkPermissionBool("redact") || + $this->checkPermissionBool("write") + ); } public function isActive(int $posting_id): bool @@ -117,4 +137,19 @@ public function isActive(int $posting_id): bool return (\ilBlogPosting::_lookupActive($posting_id, "blp")); } + protected function postingIdMatches(int $posting_id): bool + { + if ($this->id_type === \ilObject2GUI::WORKSPACE_NODE_ID) { + $obj_id = $this->ws_tree->lookupObjectId($this->node_id); + } else { + $obj_id = \ilObject::_lookupObjId($this->node_id); + } + return $this->posting_manager->lookupBlogId($posting_id) === $obj_id; + } + + public function getAccessHandler(): \ilAccessHandler|\ilWorkspaceAccessHandler + { + return $this->access; + } + } diff --git a/components/ILIAS/Blog/Posting/PostingList.php b/components/ILIAS/Blog/Posting/PostingList.php new file mode 100644 index 000000000000..72011ae6c3a1 --- /dev/null +++ b/components/ILIAS/Blog/Posting/PostingList.php @@ -0,0 +1,203 @@ + 0) { + return $this->getByAuthor($author_id); + } + if ($keyword !== "") { + return $this->getByKeyword($keyword); + } + + $max = $this->settings->getOverviewPostings(); + if ($month === "" && $max > 0) { + $list_items = []; + $all_items = $this->getPostingsGroupedByMonth(); + foreach ($all_items as $postings) { + foreach ($postings as $id => $item) { + $list_items[$id] = $item; + if (count($list_items) >= $max) { + break(2); + } + } + } + return $list_items; + } + + return $this->getByMonth($month); + } + + /** + * @return Posting[] + */ + protected function getPostings(): array + { + if ($this->postings === null) { + $this->postings = $this->posting_manager->getAllPostings($this->obj_id); + if (!$this->include_inactive) { + $this->postings = array_filter($this->postings, function (Posting $posting) { + return $posting->isActive(); + }); + } + } + return $this->postings; + } + + /** + * @return Posting[] + */ + public function getByMonth(string $month): array + { + $res = []; + foreach ($this->getPostings() as $posting) { + if (substr($posting->getCreated()->get(IL_CAL_DATE), 0, 7) === $month) { + $res[$posting->getId()] = $posting; + } + } + return $res; + } + + /** + * @return Posting[] + */ + public function getByAuthor(int $author_id): array + { + $res = []; + foreach ($this->getPostings() as $posting) { + if ($posting->getAuthor() === $author_id) { + $res[$posting->getId()] = $posting; + continue; + } + foreach (\ilPageObject::getPageContributors("blp", $posting->getId()) as $editor) { + if ((int) $editor["user_id"] === $author_id) { + $res[$posting->getId()] = $posting; + break; + } + } + } + return $res; + } + + /** + * @return Posting[] + */ + public function getByKeyword(string $keyword): array + { + $res = []; + foreach ($this->getPostings() as $posting) { + if (in_array( + $keyword, + $this->posting_manager->getKeywords($this->obj_id, $posting->getId()), + true + )) { + $res[$posting->getId()] = $posting; + } + } + return $res; + } + + /** + * @return array> [month => [posting_id => Posting]] + */ + public function getPostingsGroupedByMonth(): array + { + $items = []; + foreach ($this->getPostings() as $posting) { + $month = substr($posting->getCreated()->get(IL_CAL_DATE), 0, 7); + $items[$month][$posting->getId()] = $posting; + } + return $items; + } + + /** + * @return string[] months (YYYY-MM) + */ + public function getMonthsWithPostings(): array + { + $months = []; + foreach ($this->getPostings() as $posting) { + $month = substr($posting->getCreated()->get(IL_CAL_DATE), 0, 7); + if (!in_array($month, $months, true)) { + $months[] = $month; + } + } + rsort($months); + return $months; + } + + /** + * @return int[] user ids + */ + public function getAuthors(): array + { + $authors = []; + foreach ($this->getPostings() as $posting) { + $author_id = $posting->getAuthor(); + if ($author_id > 0 && !in_array($author_id, $authors, true)) { + $authors[] = $author_id; + } + + foreach (\ilPageObject::getPageContributors("blp", $posting->getId()) as $editor) { + $editor_id = (int) $editor["user_id"]; + if ($editor_id > 0 && !in_array($editor_id, $authors, true)) { + $authors[] = $editor_id; + } + } + } + return $authors; + } + + public function hasAuthorPostings(int $user_id): bool + { + foreach ($this->getPostings() as $posting) { + if ($posting->getAuthor() === $user_id) { + return true; + } + foreach (\ilPageObject::getPageContributors("blp", $posting->getId()) as $editor) { + if ((int) $editor["user_id"] === $user_id) { + return true; + } + } + } + return false; + } +} diff --git a/components/ILIAS/Blog/Posting/PostingListGUI.php b/components/ILIAS/Blog/Posting/PostingListGUI.php new file mode 100644 index 000000000000..fda49602609f --- /dev/null +++ b/components/ILIAS/Blog/Posting/PostingListGUI.php @@ -0,0 +1,350 @@ +notes = $DIC->notes(); + $this->posting_manager = $domain->posting(); + $this->reading_time_manager = $domain->readingTime(); + $this->blog_settings = + $domain->blogSettings()->getByObjId($parent_gui->getObject()->getId()); + $req = $gui->standardRequest(); + $this->blog = $parent_gui->getObject(); + $this->keyword = $req->getKeyword(); + $this->author = $req->getAuthor(); + + } + + public function render( + array $items, + string $a_cmd = "preview", + string $a_link_template = "", + bool $a_show_inactive = false, + string $a_export_directory = "" + ): string { + $lng = $this->domain->lng(); + $ilCtrl = $this->gui->ctrl(); + $ui_factory = $this->gui->ui()->factory(); + $ui_renderer = $this->gui->ui()->renderer(); + + $wtpl = new ilTemplate("tpl.blog_list.html", true, true, "components/ILIAS/Blog"); + + $is_admin = $this->perm->canManage(); + + $last_month = null; + $is_empty = true; + foreach ($items as $item) { + /** @var Posting $item */ + $item_id = $item->getId(); + $author = $item->getAuthor(); + $created = $item->getCreated(); + $approved = $item->isApproved(); + // only published items + $is_active = ilBlogPosting::_lookupActive($item_id, "blp"); + if (!$is_active && !$a_show_inactive) { + continue; + } + + $is_empty = false; + + $month = ""; + if (!$this->keyword && !$this->author) { + $month = substr($created->get(IL_CAL_DATE), 0, 7); + } + + if (!$last_month || $last_month != $month) { + if ($last_month) { + $wtpl->setCurrentBlock("month_bl"); + $wtpl->parseCurrentBlock(); + } + + // title according to current "filter"/navigation + if ($this->keyword) { + $title = $lng->txt("blog_keyword") . ": " . $this->keyword; + } elseif ($this->author) { + $title = $lng->txt("blog_author") . ": " . \ilUserUtil::getNamePresentation($this->author); + } else { + $title = $this->gui->presentation()->util()->getMonthPresentation($month); + $last_month = $month; + } + + $wtpl->setVariable("TXT_CURRENT_MONTH", $title); + } + + if (!$a_link_template) { + $ilCtrl->setParameterByClass("ilblogpostinggui", "bmn", $this->current_month); + $ilCtrl->setParameterByClass("ilblogpostinggui", "blpg", $item_id); + $preview = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", $a_cmd); + } else { + $preview = $this->parent_gui->buildExportLink($a_link_template, "posting", (string) $item_id); + } + $more_link = $preview; + + // actions + $posting_edit = $this->perm->mayEditPosting($item_id, $author); + if (($posting_edit || $is_admin) && !$a_link_template && $a_cmd === "preview") { + $actions = []; + + if ($is_active && $this->blog_settings->getApproval() && !$approved) { + if ($is_admin) { + $ilCtrl->setParameter($this->parent_gui, "apid", $item_id); + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_approve"), + $ilCtrl->getLinkTarget($this->parent_gui, "approve") + ); + $ilCtrl->setParameter($this->parent_gui, "apid", ""); + } + + $wtpl->setVariable("APPROVAL", $lng->txt("blog_needs_approval")); + } + + if ($posting_edit) { + $actions[] = $ui_factory->link()->standard( + $lng->txt("edit_content"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edit") + ); + $more_link = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edit"); + + // #11858 + if ($is_active) { + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_toggle_draft"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deactivatePageToList") + ); + } else { + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_toggle_final"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "activatePageToList") + ); + } + + $actions[] = $ui_factory->link()->standard( + $lng->txt("rename"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edittitle") + ); + + if ($this->blog_settings->getKeywords()) { // #13616 + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_edit_keywords"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "editKeywords") + ); + } + + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_edit_date"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "editdate") + ); + + $actions[] = $ui_factory->link()->standard( + $lng->txt("delete"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deleteBlogPostingConfirmationScreen") + ); + } elseif ($is_admin) { + // #10513 + if ($is_active) { + $ilCtrl->setParameter($this->parent_gui, "apid", $item_id); + $actions[] = $ui_factory->link()->standard( + $lng->txt("blog_toggle_draft_admin"), + $ilCtrl->getLinkTarget($this->parent_gui, "deactivateAdmin") + ); + $ilCtrl->setParameter($this->parent_gui, "apid", ""); + } + + $actions[] = $ui_factory->link()->standard( + $lng->txt("delete"), + $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deleteBlogPostingConfirmationScreen") + ); + } + + $dd = $ui_factory->dropdown()->standard($actions)->withLabel($lng->txt("actions")); + + $wtpl->setCurrentBlock("actions"); + $wtpl->setVariable("ACTION_SELECTOR", $ui_renderer->render($dd)); + $wtpl->parseCurrentBlock(); + } + + // comments + if ($this->blog->getNotesStatus() && !$a_link_template) { + // count (public) notes + $notes_context = $this->notes + ->data() + ->context( + $this->blog->getId(), + (int) $item_id, + "blp" + ); + $count = $this->notes + ->domain() + ->getNrOfCommentsForContext($notes_context); + + if ($a_cmd !== "preview") { + $wtpl->setCurrentBlock("comments"); + $wtpl->setVariable("TEXT_COMMENTS", $lng->txt("blog_comments")); + $wtpl->setVariable("URL_COMMENTS", $preview); + $wtpl->setVariable("COUNT_COMMENTS", $count); + $wtpl->parseCurrentBlock(); + } + } + + // permanent link + if ($this->node_id !== null && + $a_cmd !== "preview") { + if ($this->id_type === ilObjBlogGUI::WORKSPACE_NODE_ID) { + $goto = $this->gui->permanentLink(0, (int) $this->node_id)->getPermanentLink((int) $item_id); + } else { + $goto = $this->gui->permanentLink((int) $this->node_id)->getPermanentLink((int) $item_id); + } + $wtpl->setCurrentBlock("permalink"); + $wtpl->setVariable("URL_PERMALINK", $goto); + $wtpl->setVariable("TEXT_PERMALINK", $lng->txt("blog_link")); + $wtpl->parseCurrentBlock(); + } + + $snippet = $this->gui->posting()->getSnippet( + $item_id, + $this->blog_settings->getAbstractShorten(), + $this->blog_settings->getAbstractShortenLength(), + "…", + $this->blog_settings->getAbstractImage(), + $this->blog_settings->getAbstractImageWidth(), + $this->blog_settings->getAbstractImageHeight(), + $a_export_directory + ); + + if ($snippet) { + $wtpl->setCurrentBlock("more"); + $wtpl->setVariable("URL_MORE", $more_link); + $wtpl->setVariable("TEXT_MORE", $lng->txt("blog_list_more")); + $wtpl->parseCurrentBlock(); + } + + if (!$is_active) { + $wtpl->setCurrentBlock("draft_text"); + $wtpl->setVariable("DRAFT_TEXT", $lng->txt("blog_draft_text")); + $wtpl->parseCurrentBlock(); + $wtpl->setVariable("DRAFT_CLASS", " ilBlogListItemDraft"); + } + + // reading time + $reading_time = $this->reading_time_manager->getReadingTime( + $this->blog->getId(), + $item_id + ); + if (!is_null($reading_time)) { + $lng->loadLanguageModule("copg"); + $wtpl->setCurrentBlock("reading_time"); + $wtpl->setVariable( + "READING_TIME", + $lng->txt("copg_est_reading_time") . ": " . + sprintf($lng->txt("copg_x_minutes"), $reading_time) + ); + $wtpl->parseCurrentBlock(); + } + + $wtpl->setCurrentBlock("posting"); + + $author_str = ""; + if ($this->id_type === ilObjBlogGUI::REPOSITORY_NODE_ID) { + $authors = array(); + + // primary author + if ($author) { + $authors[] = \ilUserUtil::getNamePresentation($author); + } + + // additional editors + foreach (\ilPageObject::getPageContributors("blp", $item_id) as $editor) { + $editor_id = (int) $editor["user_id"]; + if ($editor_id !== $author) { + $authors[] = \ilUserUtil::getNamePresentation($editor_id); + } + } + + if ($authors) { + $author_str = implode(", ", $authors) . " - "; + } + } + + // title + $wtpl->setVariable("URL_TITLE", $preview); + $wtpl->setVariable("TITLE", $item->getTitle()); + + $kw = $this->posting_manager->getKeywords($this->blog->getId(), $item_id); + natcasesort($kw); + $keywords = (count($kw) > 0) + ? "
" . $lng->txt("keywords") . ": " . implode(", ", $kw) + : ""; + + $wtpl->setVariable("DATETIME", $author_str . + ilDatePresentation::formatDate($created) . $keywords); + + // content + $wtpl->setVariable("CONTENT", $snippet); + + $wtpl->parseCurrentBlock(); + } + + // permalink + if ($a_cmd === "previewFullscreen") { + $ref_id = ($this->id_type === ilObjBlogGUI::WORKSPACE_NODE_ID) + ? 0 + : $this->node_id; + $wsp_id = ($this->id_type === ilObjBlogGUI::WORKSPACE_NODE_ID) + ? $this->node_id + : 0; + $this->gui->permanentLink($ref_id, $wsp_id)->setPermanentLink(); + } + + if (!$is_empty || $a_show_inactive) { + return $wtpl->get(); + } + return ""; + } +} diff --git a/components/ILIAS/Blog/Posting/Service/class.GUIService.php b/components/ILIAS/Blog/Posting/Service/class.GUIService.php new file mode 100644 index 000000000000..3c95e5b4fc31 --- /dev/null +++ b/components/ILIAS/Blog/Posting/Service/class.GUIService.php @@ -0,0 +1,103 @@ +data, + $this->domain, + $this->gui, + $parent_gui, + $perm, + $current_month, + $node_id, + $id_type + ); + } + + /** + * Get first text paragraph of page + */ + public function getSnippet( + int $a_id, + bool $a_truncate = false, + int $a_truncate_length = 500, + string $a_truncate_sign = "...", + bool $a_include_picture = false, + int $a_picture_width = 144, + int $a_picture_height = 144, + ?string $a_export_directory = null + ): string { + $bpgui = $this->postingGUI(0, null, $a_id); + return $bpgui->getSnippet( + $a_truncate, + $a_truncate_length, + $a_truncate_sign, + $a_include_picture, + $a_picture_width, + $a_picture_height, + $a_export_directory + ); + } +} diff --git a/components/ILIAS/Blog/Posting/class.ilBlogPosting.php b/components/ILIAS/Blog/Posting/class.ilBlogPosting.php index 9e50d67ba854..e30778d3d707 100755 --- a/components/ILIAS/Blog/Posting/class.ilBlogPosting.php +++ b/components/ILIAS/Blog/Posting/class.ilBlogPosting.php @@ -28,6 +28,7 @@ */ class ilBlogPosting extends ilPageObject { + protected \ILIAS\Blog\Posting\Service\GUIService $posting_gui; protected string $title = ""; protected ?ilDateTime $created = null; protected int $blog_node_id = 0; @@ -45,6 +46,8 @@ public function afterConstructor(): void $this->internal_data = $DIC->blog()->internal()->data(); $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); $this->blog_domain = $DIC->blog()->internal()->domain(); + $this->posting_gui = $DIC->blog()->internal()->gui()->posting(); + } public function getParentType(): string @@ -254,27 +257,6 @@ public function unpublish(): void ); } - public static function lookupBlogId( - int $a_posting_id - ): ?int { - global $DIC; - return $DIC->blog()->internal()->domain()->posting()->lookupBlogId($a_posting_id); - } - - /** - * Checks whether a posting exists - */ - public static function exists( - int $a_blog_id, - int $a_posting_id - ): bool { - global $DIC; - return $DIC->blog()->internal()->domain()->posting()->exists( - $a_blog_id, - $a_posting_id - ); - } - /** * Set blog node id (needed for notification) */ @@ -288,7 +270,7 @@ public function setBlogNodeId( public function getNotificationAbstract(): string { - $snippet = ilBlogPostingGUI::getSnippet($this->getId(), true); + $snippet = $this->posting_gui->getSnippet($this->getId(), true); // making things more readable $snippet = str_replace(array('
', '
', '

', ''), "\n", $snippet); diff --git a/components/ILIAS/Blog/Posting/class.ilBlogPostingGUI.php b/components/ILIAS/Blog/Posting/class.ilBlogPostingGUI.php index 967bf110d875..aac0b5e505e2 100755 --- a/components/ILIAS/Blog/Posting/class.ilBlogPostingGUI.php +++ b/components/ILIAS/Blog/Posting/class.ilBlogPostingGUI.php @@ -44,6 +44,7 @@ class ilBlogPostingGUI extends ilPageObjectGUI protected ilLocatorGUI $locator; protected ilSetting $settings; protected LOMServices $lom_services; + protected ilToolbarGUI $toolbar; protected int $node_id; protected PostingManager $posting_manager; protected ?object $access_handler = null; @@ -114,6 +115,7 @@ public function __construct( $this->notes = $DIC->notes(); $this->profile_gui = $DIC->blog()->internal()->gui()->profile(); $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); + $this->toolbar = $DIC->toolbar(); } public function executeCommand(): string @@ -179,12 +181,11 @@ protected function checkAccess(string $a_cmd): bool public function preview( ?string $a_mode = null ): string { - global $DIC; $ilCtrl = $this->ctrl; $tpl = $this->tpl; $ilSetting = $this->settings; - $toolbar = $DIC->toolbar(); + $toolbar = $this->toolbar; $append = ""; $this->getBlogPosting()->increaseViewCnt(); @@ -597,7 +598,13 @@ public function deactivatePage(bool $a_to_list = false): void $this->ctrl->redirect($this, "edit"); } else { $this->ctrl->setParameterByClass("ilobjbloggui", "blpg", ""); - $this->ctrl->redirectByClass("ilobjbloggui", ""); + $this->ctrl->redirectByClass( + [ + ilObjBlogGUI::class, + \ILIAS\Blog\Editing\EditingGUI::class, + ], + "" + ); } } @@ -619,7 +626,13 @@ public function activatePage(bool $a_to_list = false): void $this->ctrl->redirect($this, "edit"); } else { $this->ctrl->setParameterByClass("ilobjbloggui", "blpg", ""); - $this->ctrl->redirectByClass("ilobjbloggui", ""); + $this->ctrl->redirectByClass( + [ + ilObjBlogGUI::class, + \ILIAS\Blog\Editing\EditingGUI::class, + ], + "" + ); } } @@ -628,9 +641,7 @@ public function activatePage(bool $a_to_list = false): void */ public function editKeywords(): void { - global $DIC; - - $renderer = $DIC->ui()->renderer(); + $renderer = $this->blog_gui->ui()->renderer(); $ilTabs = $this->tabs; $tpl = $this->tpl; @@ -652,9 +663,7 @@ public function editKeywords(): void */ protected function initKeywordsForm(): \ILIAS\UI\Component\Input\Container\Form\Standard { - global $DIC; - - $ui_factory = $DIC->ui()->factory(); + $ui_factory = $this->blog_gui->ui()->factory(); $keywords = $this->posting_manager->getKeywords( $this->getBlogPosting()->getBlogId(), @@ -681,7 +690,7 @@ protected function initKeywordsForm(): \ILIAS\UI\Component\Input\Container\Form\ $input_tag = $input_tag->withValue($keywords); } - $DIC->ctrl()->setParameter( + $this->ctrl->setParameter( $this, 'tags', 'tags_processing' @@ -689,7 +698,7 @@ protected function initKeywordsForm(): \ILIAS\UI\Component\Input\Container\Form\ $section = $ui_factory->input()->field()->section([$input_tag], $this->lng->txt("blog_edit_keywords"), ""); - $form_action = $DIC->ctrl()->getFormAction($this, "saveKeywordsForm"); + $form_action = $this->ctrl->getFormAction($this, "saveKeywordsForm"); return $ui_factory->input()->container()->form()->standard($form_action, ["tags" => $section]); } @@ -707,9 +716,7 @@ protected function getParentObjId(): int public function saveKeywordsForm(): void { - global $DIC; - - $request = $DIC->http()->request(); + $request = $this->blog_gui->http()->request(); $form = $this->initKeywordsForm(); if ($request->getMethod() === "POST" @@ -735,8 +742,7 @@ public function saveKeywordsForm(): void /** * Get first text paragraph of page */ - public static function getSnippet( - int $a_id, + public function getSnippet( bool $a_truncate = false, int $a_truncate_length = 500, string $a_truncate_sign = "...", @@ -745,25 +751,23 @@ public static function getSnippet( int $a_picture_height = 144, ?string $a_export_directory = null ): string { - $bpgui = new self(0, null, $a_id); - // scan the full page for media objects $img = ""; if ($a_include_picture) { - $img = $bpgui->getFirstMediaObjectAsTag($a_picture_width, $a_picture_height, $a_export_directory); + $img = $this->getFirstMediaObjectAsTag($a_picture_width, $a_picture_height, $a_export_directory); } - $bpgui->setRawPageContent(true); - $bpgui->setAbstractOnly(true); + $this->setRawPageContent(true); + $this->setAbstractOnly(true); // #8627: export won't work - should we set offline mode? - $bpgui->setFileDownloadLink("."); - $bpgui->setFullscreenLink("."); - $bpgui->setSourcecodeDownloadScript("."); - $bpgui->setProfileBackUrl("."); + $this->setFileDownloadLink("."); + $this->setFullscreenLink("."); + $this->setSourcecodeDownloadScript("."); + $this->setProfileBackUrl("."); // render without title - $page = $bpgui->showPage(); + $page = $this->showPage(); if ($a_truncate) { $page = ilPageObject::truncateHTML($page, $a_truncate_length, $a_truncate_sign); @@ -808,7 +812,7 @@ protected function getFirstMediaObjectAsTag( // see ilCOPageHTMLExport::exportHTMLMOB() $mob_dir = "./mobs/mm_" . $mob_obj->getId(); } - $mob_res = self::parseImage( + $mob_res = $this->parseImage( $mob_size["width"], $mob_size["height"], $a_width, @@ -831,7 +835,7 @@ protected function getFirstMediaObjectAsTag( return ""; } - protected static function parseImage( + protected function parseImage( int $src_width, int $src_height, int $tgt_width, @@ -876,6 +880,12 @@ protected function showEditToolbar(): void public function finishEditing(): void { $this->ctrl->setParameterByClass("ilobjbloggui", "bmn", ""); - $this->ctrl->redirectByClass("ilobjbloggui", "render"); + $this->ctrl->redirectByClass( + [ + ilObjBlogGUI::class, + \ILIAS\Blog\Editing\EditingGUI::class + ], + "" + ); } } diff --git a/components/ILIAS/Blog/Presentation/PresentationGUI.php b/components/ILIAS/Blog/Presentation/PresentationGUI.php new file mode 100644 index 000000000000..a1999d2f3740 --- /dev/null +++ b/components/ILIAS/Blog/Presentation/PresentationGUI.php @@ -0,0 +1,231 @@ +user = $this->domain->user(); + $this->ctrl = $this->gui->ctrl(); + $this->blog = $this->parent_gui->getObject(); + $this->obj_id = $this->blog->getId(); + $req = $this->gui->standardRequest(); + $this->blpg = $req->getBlogPage(); + $this->user_page = $req->getUserPage(); + $this->ntf = $req->getNotification(); + $this->blog_settings = $domain->blogSettings()->getByObjId($this->obj_id); + $this->nav_renderer = $this->gui->navigation()->toolbarNavigationRenderer( + $this->getLinkBuilder(), + ); + } + + protected function getLinkBuilder(): LinkBuilder + { + return $this->gui->navigation()->presentationLink(); + } + + public function executeCommand(): void + { + $next_class = $this->gui->ctrl()->getNextClass($this); + $cmd = $this->gui->ctrl()->getCmd("preview"); + + switch ($next_class) { + case strtolower(ilBlogPostingGUI::class): + $this->forwardPosting(); + break; + + default: + $this->$cmd(); + break; + } + } + + /** + * Toolbar navigation + */ + public function renderToolbarNavigation( + array $a_items, + bool $single_posting = false + ): void { + $nav_renderer = $this->gui->navigation()->toolbarNavigationRenderer( + $this->getLinkBuilder(), + ); + $nav_renderer->renderToolbarNavigation( + $this->perm, + $a_items, + $this->blpg, + $single_posting, + $this->current_month, + $this->user_page + ); + } + + protected function forwardPosting(): void + { + $ilCtrl = $this->gui->ctrl(); + $req = $this->gui->standardRequest(); + + if ($this->id_type === \ilObjBlogGUI::REPOSITORY_NODE_ID) { + //$this->parent_gui->setLocator(); + } + + $style_sheet_id = $this->content_style_domain->getEffectiveStyleId(); + + $bpost_gui = new ilBlogPostingGUI( + $this->node_id, + $this->perm->getAccessHandler(), + $req->getBlogPage(), + $req->getOldNr(), + $this->blog->getNotesStatus(), + $this->perm->mayEditPosting($req->getBlogPage()), + $style_sheet_id + ); + + $ilCtrl->setParameter($this, "prvm", "fsc"); + + $this->renderToolbarNavigation($this->parent_gui->getItems(), true); + + $ret = $ilCtrl->forwardCommand($bpost_gui); + + if ($ret != "") { + $is_owner = $this->perm->mayContribute(); + $is_active = $bpost_gui->getBlogPosting()->getActive(); + + // do not show inactive postings + $cmd = $ilCtrl->getCmd(); + if (($cmd === "previewFullscreen") + && !$is_owner && !$is_active) { + $ilCtrl->redirect($this->parent_gui, "preview"); + } + + if ($cmd === "previewFullscreen") { + $this->parent_gui->addPresentationHeaderAction(); + $this->parent_gui->filterInactivePostings(); + $nav = $this->gui->navigation()->sideBar( + $this->perm, + $this->getLinkBuilder(), + $this->blog_settings, + $this->node_id, + $this->id_type + )->render( + $this->parent_gui, + $this->parent_gui->getItems(), + ); + $this->parent_gui->renderFullScreen($ret, $nav); + } + } + } + + /** + * Render fullscreen presentation + */ + public function preview(): void + { + $lng = $this->domain->lng(); + $tpl = $this->gui->ui()->mainTemplate(); + + if (!$this->parent_gui->checkPermissionBool("read")) { + $tpl->setOnScreenMessage('info', $lng->txt("no_permission")); + return; + } + + $this->parent_gui->filterInactivePostings(); + + $list_items = $this->parent_gui->getListItems(); + + $list = $nav = ""; + if ($list_items) { + $list = $this->parent_gui->renderList($list_items, "previewFullscreen"); + $nav = $this->gui->navigation()->sideBar( + $this->perm, + $this->getLinkBuilder(), + $this->blog_settings, + $this->node_id, + $this->id_type + )->render( + $this->parent_gui, + $this->parent_gui->getItems(), + ); + $this->renderToolbarNavigation($this->parent_gui->getItems()); + } + + $this->parent_gui->renderFullScreen($list, $nav); + } + + protected function setNotification(): void + { + $ilUser = $this->user; + $ilCtrl = $this->ctrl; + switch ($this->ntf) { + case 1: + \ilNotification::setNotification( + \ilNotification::TYPE_BLOG, + $ilUser->getId(), + $this->obj_id, + false + ); + break; + + case 2: + \ilNotification::setNotification( + \ilNotification::TYPE_BLOG, + $ilUser->getId(), + $this->obj_id, + true + ); + break; + } + + $ilCtrl->redirect($this, ""); + } + +} diff --git a/components/ILIAS/Blog/Presentation/Service/class.GUIService.php b/components/ILIAS/Blog/Presentation/Service/class.GUIService.php index 87ee13853935..8200bc7b70a6 100755 --- a/components/ILIAS/Blog/Presentation/Service/class.GUIService.php +++ b/components/ILIAS/Blog/Presentation/Service/class.GUIService.php @@ -20,24 +20,43 @@ namespace ILIAS\Blog\Presentation; +use ILIAS\Blog\InternalDataService; use ILIAS\Blog\InternalDomainService; use ILIAS\Blog\InternalGUIService; +use ILIAS\Blog\Permission\PermissionManager; class GUIService { - protected InternalGUIService $gui; - protected InternalDomainService $domain; - public function __construct( - InternalDomainService $domain, - InternalGUIService $gui + protected InternalDataService $data, + protected InternalDomainService $domain, + protected InternalGUIService $gui ) { - $this->domain = $domain; - $this->gui = $gui; } public function util(): Util { return new Util(); } + + public function presentationGUI( + \ilObjBlogGUI $parent_gui, + PermissionManager $perm, + \ILIAS\Style\Content\Object\ObjectFacade $content_style_domain, + string $current_month, + ?int $node_id = null, + int $id_type = \ilObjBlogGUI::REPOSITORY_NODE_ID + ): PresentationGUI { + return new PresentationGUI( + $this->data, + $this->domain, + $this->gui, + $parent_gui, + $perm, + $content_style_domain, + $current_month, + $node_id, + $id_type + ); + } } diff --git a/components/ILIAS/Blog/RSS/RSSGUI.php b/components/ILIAS/Blog/RSS/RSSGUI.php index 8ed3896f0d09..bd54c3a326e5 100644 --- a/components/ILIAS/Blog/RSS/RSSGUI.php +++ b/components/ILIAS/Blog/RSS/RSSGUI.php @@ -1,6 +1,20 @@

"); + $snippet = strip_tags($this->gui->posting()->getSnippet($id), "

"); $snippet = str_replace("&", "&", $snippet); $snippet = ""; diff --git a/components/ILIAS/Blog/Service/class.InternalDomainService.php b/components/ILIAS/Blog/Service/class.InternalDomainService.php index 55b2141439c3..cebf650819bd 100755 --- a/components/ILIAS/Blog/Service/class.InternalDomainService.php +++ b/components/ILIAS/Blog/Service/class.InternalDomainService.php @@ -77,6 +77,7 @@ public function perm( int $owner ): PermissionManager { return new PermissionManager( + $this, $access_handler, $node_id, $id_type, @@ -114,12 +115,26 @@ public function posting(): PostingManager ); } + public function postingList( + int $obj_id, + Settings\Settings $settings, + bool $include_inactive = true + ): Posting\PostingList { + return new Posting\PostingList( + $obj_id, + $this->posting(), + $settings, + $include_inactive + ); + } + public function news(): NewsManager { return self::$instance["news"] ??= new NewsManager( $this->data, $this->repo, - $this + $this, + $this->dic->blog()->internal()->gui() ); } diff --git a/components/ILIAS/Blog/Service/class.InternalGUIService.php b/components/ILIAS/Blog/Service/class.InternalGUIService.php index 3d616e8ef350..b368756a485f 100755 --- a/components/ILIAS/Blog/Service/class.InternalGUIService.php +++ b/components/ILIAS/Blog/Service/class.InternalGUIService.php @@ -25,6 +25,9 @@ use ILIAS\PermanentLink\PermanentLinkManager; use ILIAS\Blog\ReadingTime\GUIService; use ILIAS\Blog\RSS\RSSGUI; +use ILIAS\Blog\Posting\Service\GUIService as PostingGUIService; +use ILIAS\Blog\Permission\BlogCmdPermission; +use ILIAS\Blog\Permission\PermissionManager; class InternalGUIService { @@ -42,15 +45,26 @@ public function __construct( public function navigation(): Navigation\GUIService { - return new Navigation\GUIService( + return self::$instance["navigation"] ?? + self::$instance["navigation"] = new Navigation\GUIService( + $this->domain_service, + $this + ); + } + + public function presentation(): Presentation\GUIService + { + return self::$instance["presentation"] ??= new Presentation\GUIService( + $this->data_service, $this->domain_service, $this ); } - public function presentation(): Presentation\GUIService + public function editing(): Editing\GUIService { - return new Presentation\GUIService( + return self::$instance["editing"] ??= new Editing\GUIService( + $this->data_service, $this->domain_service, $this ); @@ -66,11 +80,12 @@ public function standardRequest(): StandardGUIRequest public function contributor(): Contributor\GUIService { - return new Contributor\GUIService( - $this->data_service, - $this->domain_service, - $this - ); + return self::$instance["contributor"] ?? + self::$instance["contributor"] = new Contributor\GUIService( + $this->data_service, + $this->domain_service, + $this + ); } public function exercise(): Exercise\GUIService @@ -114,6 +129,15 @@ public function readingTime(): GUIService ); } + public function posting(): PostingGUIService + { + return self::$instance["posting"] ??= new PostingGUIService( + $this->data_service, + $this->domain_service, + $this + ); + } + public function rss(): RSSGUI { return self::$instance["rss"] ??= new RSSGUI( @@ -122,4 +146,15 @@ public function rss(): RSSGUI $this ); } + + public function cmdPerm(PermissionManager $blog_access): BlogCmdPermission + { + return new BlogCmdPermission( + $this->domain_service->lng(), + $blog_access, + $this->ui()->mainTemplate(), + $this->ctrl(), + $this->standardRequest() + ); + } } diff --git a/components/ILIAS/Blog/Tasks/classes/class.ilBlogDraftsDerivedTaskProvider.php b/components/ILIAS/Blog/Tasks/classes/class.ilBlogDraftsDerivedTaskProvider.php index 800be9b2ff13..49f0c0a3c3aa 100755 --- a/components/ILIAS/Blog/Tasks/classes/class.ilBlogDraftsDerivedTaskProvider.php +++ b/components/ILIAS/Blog/Tasks/classes/class.ilBlogDraftsDerivedTaskProvider.php @@ -37,8 +37,9 @@ public function __construct( ) { global $DIC; - $this->gui = $DIC->blog()->internal()->gui(); - $this->domain = $DIC->blog()->internal()->domain(); + $service = $DIC->blog()->internal(); + $this->gui = $service->gui(); + $this->domain = $service->domain(); $this->taskService = $taskService; $this->accessHandler = $accessHandler; $this->lng = $lng; diff --git a/components/ILIAS/Blog/classes/class.ilBlogNewsRendererGUI.php b/components/ILIAS/Blog/classes/class.ilBlogNewsRendererGUI.php index 3275e896e556..32dfa9f6ddc2 100755 --- a/components/ILIAS/Blog/classes/class.ilBlogNewsRendererGUI.php +++ b/components/ILIAS/Blog/classes/class.ilBlogNewsRendererGUI.php @@ -18,17 +18,21 @@ declare(strict_types=1); -/** - * Blog news renderer - * @author Alexander Killing - */ class ilBlogNewsRendererGUI extends ilNewsDefaultRendererGUI { - public function getObjectLink(): string + protected \ILIAS\Blog\InternalGUIService $blog_gui; + + public function __construct() { global $DIC; + parent::__construct(); + $service = $DIC->blog()->internal(); + $this->blog_gui = $service->gui(); + } - $pl = $DIC->blog()->internal()->gui()->permanentLink($this->getNewsRefId()); + public function getObjectLink(): string + { + $pl = $this->blog_gui->permanentLink($this->getNewsRefId()); $n = $this->getNewsItem(); $posting_id = 0; diff --git a/components/ILIAS/Blog/classes/class.ilObjBlog.php b/components/ILIAS/Blog/classes/class.ilObjBlog.php index 27da54a1f0b0..90092326f992 100755 --- a/components/ILIAS/Blog/classes/class.ilObjBlog.php +++ b/components/ILIAS/Blog/classes/class.ilObjBlog.php @@ -44,8 +44,9 @@ public function __construct( ) { global $DIC; + $service = $DIC->blog()->internal(); $this->notes_service = $DIC->notes(); - $this->settings_manager = $DIC->blog()->internal()->domain()->blogSettings(); + $this->settings_manager = $service->domain()->blogSettings(); parent::__construct($a_id, $a_reference); $this->rbac_review = $DIC->rbac()->review(); @@ -57,7 +58,7 @@ public function __construct( if ($this->getId() > 0) { $this->blog_settings = $this->settings_manager->getByObjId($this->getId()); } - $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); + $this->posting_manager = $service->domain()->posting(); } protected function initType(): void diff --git a/components/ILIAS/Blog/classes/class.ilObjBlogGUI.php b/components/ILIAS/Blog/classes/class.ilObjBlogGUI.php index 08e5be07df37..7688978f71c8 100755 --- a/components/ILIAS/Blog/classes/class.ilObjBlogGUI.php +++ b/components/ILIAS/Blog/classes/class.ilObjBlogGUI.php @@ -30,19 +30,25 @@ use ILIAS\Blog\Settings\Settings; use ILIAS\Blog\ReadingTime\ReadingTimeManager; use ILIAS\Blog\Posting\PostingManager; +use ILIAS\Blog\Contributor\ContributorGUI; +use ILIAS\Blog\Editing\EditingGUI; /** - * @ilCtrl_Calls ilObjBlogGUI: ilBlogPostingGUI, ilWorkspaceAccessGUI + * @ilCtrl_Calls ilObjBlogGUI: ilWorkspaceAccessGUI * @ilCtrl_Calls ilObjBlogGUI: ilInfoScreenGUI, ilNoteGUI, ilCommonActionDispatcherGUI - * @ilCtrl_Calls ilObjBlogGUI: ilPermissionGUI, ilObjectCopyGUI, ilRepositorySearchGUI + * @ilCtrl_Calls ilObjBlogGUI: ilPermissionGUI, ilObjectCopyGUI * @ilCtrl_Calls ilObjBlogGUI: ilExportGUI, ilObjectContentStyleSettingsGUI, ilBlogExerciseGUI, ilObjNotificationSettingsGUI * @ilCtrl_Calls ilObjBlogGUI: ilObjectMetaDataGUI * @ilCtrl_Calls ilObjBlogGUI: ILIAS\Blog\Settings\SettingsGUI * @ilCtrl_Calls ilObjBlogGUI: ILIAS\Blog\Settings\BlockSettingsGUI + * @ilCtrl_Calls ilObjBlogGUI: ILIAS\Blog\Contributor\ContributorGUI + * @ilCtrl_Calls ilObjBlogGUI: ILIAS\Blog\Editing\EditingGUI + * @ilCtrl_Calls ilObjBlogGUI: ILIAS\Blog\Presentation\PresentationGUI */ class ilObjBlogGUI extends ilObject2GUI implements ilDesktopItemHandling { protected PostingManager $posting_manager; + protected \ILIAS\Blog\Permission\BlogCmdPermission $cmd_perm; protected ?Settings $blog_settings = null; protected ProfileGUI $profile_gui; protected ProfileAdapter $profile; @@ -69,11 +75,9 @@ class ilObjBlogGUI extends ilObject2GUI implements ilDesktopItemHandling protected int $old_nr = 0; protected int $ppage = 0; protected int $user_page = 0; - protected string $prvm; //preview mode (fsc|emb) protected int $ntf = 0; protected int $apid = 0; protected string $new_type = ""; - protected bool $disable_notes = false; protected ContextServices $tool_context; protected \ILIAS\DI\UIServices $ui; protected \ILIAS\Style\Content\GUIService $content_style_gui; @@ -85,7 +89,6 @@ public function __construct( int $a_parent_node_id = 0 ) { global $DIC; - // other services $cs = $DIC->contentStyle(); $this->tool_context = $DIC->globalScreen()->tool()->context(); @@ -103,6 +106,7 @@ public function __construct( $this->rbac_review = $domain->rbac()->review(); $this->rbacadmin = $domain->rbac()->admin(); $this->lng = $domain->lng(); + $this->posting_manager = $domain->posting(); $gui = $service->gui(); $this->gui = $gui; @@ -123,8 +127,6 @@ public function __construct( $this->ppage = $req->getPPage(); $this->user_page = $req->getUserPage(); $this->new_type = $req->getNewType(); - $this->prvm = $req->getPreviewMode(); - $this->ntf = $req->getNotification(); $this->apid = $req->getApId(); $this->month = $req->getMonth(); $this->keyword = $req->getKeyword(); @@ -134,14 +136,23 @@ public function __construct( $blog_page = $this->blog_request->getBlogPage(); if ($blog_page > 0 && - ilBlogPosting::lookupBlogId($blog_page) !== $this->object->getId()) { + $this->posting_manager->lookupBlogId($blog_page) !== $this->object->getId()) { throw new ilException("Posting ID does not match blog."); } - $this->posting_manager = $DIC->blog()->internal()->domain()->posting(); - $blog_id = 0; if ($this->object) { + $this->content_style_gui = $cs->gui(); + if (is_object($this->object)) { + if ($this->id_type !== self::REPOSITORY_NODE_ID) { + $this->content_style_domain = $cs->domain()->styleForObjId($this->object->getId()); + } else { + $this->content_style_domain = $cs->domain()->styleForRefId($this->object->getRefId()); + } + $this->blog_settings = + $domain->blogSettings()->getByObjId($this->object->getId()); + } + // gather postings by month $this->items = $this->buildPostingList($this->object->getId()); if ($this->items) { @@ -158,18 +169,6 @@ public function __construct( } $this->lng->loadLanguageModule("blog"); - $this->ctrl->saveParameter($this, "prvm"); - - $this->content_style_gui = $cs->gui(); - if (is_object($this->object)) { - if ($this->id_type !== self::REPOSITORY_NODE_ID) { - $this->content_style_domain = $cs->domain()->styleForObjId($this->object->getId()); - } else { - $this->content_style_domain = $cs->domain()->styleForRefId($this->object->getRefId()); - } - $this->blog_settings = - $domain->blogSettings()->getByObjId($this->object->getId()); - } $this->reading_time_gui = $gui->readingTime()->settingsGUI($blog_id); $this->reading_time_manager = $domain->readingTime(); @@ -184,6 +183,7 @@ public function __construct( ); $this->profile = $domain->profile(); $this->profile_gui = $gui->profile(); + $this->cmd_perm = $gui->cmdPerm($this->perm); } public function getType(): string @@ -266,12 +266,15 @@ protected function setTabs(): void $ilHelp->setScreenIdComponent("blog"); - if ($this->checkPermissionBool("read")) { + if ($this->perm->mayContribute()) { $this->ctrl->setParameterByClass(self::class, "bmn", null); $this->tabs_gui->addTab( "content", $lng->txt("content"), - $this->ctrl->getLinkTarget($this, "") + $this->ctrl->getLinkTargetByClass( + EditingGUI::class, + "" + ) ); } if ($this->checkPermissionBool("read")) { @@ -296,7 +299,7 @@ protected function setTabs(): void $this->tabs_gui->addTab( "contributors", $lng->txt("blog_contributors"), - $this->ctrl->getLinkTarget($this, "contributors") + $this->ctrl->getLinkTargetByClass(ContributorGUI::class, "contributors") ); } @@ -322,7 +325,13 @@ protected function setTabs(): void $this->tabs_gui->addNonTabbedLink( "preview", $lng->txt("blog_preview"), - $this->ctrl->getLinkTarget($this, "preview") + $this->ctrl->getLinkTargetByClass( + [ + self::class, + \ILIAS\Blog\Presentation\PresentationGUI::class + ], + "preview" + ) ); } parent::setTabs(); @@ -343,144 +352,20 @@ public function executeCommand(): void $this->triggerAssignmentTool(); } - $cmd = $ilCtrl->getCmd(); - // add entry to navigation history if (($this->id_type === self::REPOSITORY_NODE_ID) && !$this->getCreationMode() && $this->getAccessHandler()->checkAccess("read", "", $this->node_id)) { // see #22067 - $link = $ilCtrl->getLinkTargetByClass(["ilrepositorygui", "ilObjBlogGUI"], "preview"); + $link = $ilCtrl->getLinkTargetByClass([ + ilRepositoryGUI::class, + ilObjBlogGUI::class, + \ILIAS\Blog\Presentation\PresentationGUI::class + ], "preview"); $ilNavigationHistory->addItem($this->node_id, $link, "blog"); } switch ($next_class) { - case 'ilblogpostinggui': - $this->ctrl->saveParameter($this, "user_page"); - $tpl->loadStandardTemplate(); - - if (!$this->checkPermissionBool("read")) { - $this->tpl->setOnScreenMessage('info', $lng->txt("no_permission")); - return; - } - - // #9680 - if ($this->id_type === self::REPOSITORY_NODE_ID) { - $this->setLocator(); - } - - $style_sheet_id = $this->content_style_domain->getEffectiveStyleId(); - - $bpost_gui = new ilBlogPostingGUI( - $this->node_id, - $this->getAccessHandler(), - $this->blpg, - $this->old_nr, - ($this->object->getNotesStatus() && !$this->disable_notes), - $this->perm->mayEditPosting($this->blpg), - $style_sheet_id - ); - - // keep preview mode through notes gui (has its own commands) - switch ($cmd) { - // blog preview - case "previewFullscreen": - $ilCtrl->setParameter($this, "prvm", "fsc"); - break; - - default: - $this->setContentStyleSheet(); - - - $this->ctrl->setParameterByClass("ilblogpostinggui", "blpg", $this->blpg); - $this->tabs_gui->addNonTabbedLink( - "preview", - $lng->txt("blog_preview"), - $this->ctrl->getLinkTargetByClass("ilblogpostinggui", "previewFullscreen") - ); - $this->ctrl->setParameterByClass("ilblogpostinggui", "blpg", ""); - break; - } - - // keep preview mode through notes gui - if ($this->prvm) { - $cmd = "previewFullscreen"; - } - if ($cmd === "previewFullscreen") { - $this->renderToolbarNavigation($this->items, true); - } - $ret = $ilCtrl->forwardCommand($bpost_gui); - if (!$ilTabs->back_target) { - $ilCtrl->setParameter($this, "bmn", ""); - $ilTabs->setBackTarget( - $lng->txt("back"), - $ilCtrl->getLinkTarget($this, "") - ); - } - - if ($ret != "") { - // $is_owner = $this->object->getOwner() == $ilUser->getId(); - $is_owner = $this->perm->mayContribute(); - $is_active = $bpost_gui->getBlogPosting()->getActive(); - - // do not show inactive postings - if (($cmd === "previewFullscreen") - && !$is_owner && !$is_active) { - $this->ctrl->redirect($this, "preview"); - } - - switch ($cmd) { - // blog preview - case "previewFullscreen": - $this->addHeaderActionForCommand($cmd); - $this->filterInactivePostings(); - $nav = $this->renderNavigation("preview", $cmd); - $this->renderFullScreen($ret, $nav); - break; - - default: - // infos about draft status / snippet - $info = array(); - if (!$is_active) { - // single author blog (owner) in personal workspace - if ($this->id_type === self::WORKSPACE_NODE_ID) { - $info[] = $lng->txt("blog_draft_info"); - } else { - $info[] = $lng->txt("blog_draft_info_contributors"); - } - } - $public_action = false; - if ($cmd !== "history" && $cmd !== "edit" && $is_active && empty($info)) { - $info[] = $lng->txt("blog_new_posting_info"); - $public_action = true; - } - if ($this->blog_settings->getApproval() && !$bpost_gui->getBlogPosting()->isApproved()) { - // #9737 - $info[] = $lng->txt("blog_posting_edit_approval_info"); - } - if ($public_action) { - $this->tpl->setOnScreenMessage('success', implode("
", $info)); - } else { - if (count($info) > 0) { - $this->tpl->setOnScreenMessage('info', implode("
", $info)); - } - } - - // revert to edit cmd to avoid confusion - $tpl->setContent($ret); - if ($cmd !== "edit") { - $this->addHeaderActionForCommand("render"); - $nav = $this->renderNavigation("render", $cmd, "", $is_owner); - $tpl->setRightContent($nav); - } else { - $this->tabs->setBackTarget("", ""); - } - break; - } - } - break; - case "ilinfoscreengui": $this->prepareOutput(); - $this->addHeaderActionForCommand("render"); $this->infoScreenForward(); break; @@ -492,35 +377,35 @@ public function executeCommand(): void $gui = ilCommonActionDispatcherGUI::getInstanceFromAjaxCall(); $gui->enableCommentsSettings(false); $this->prepareOutput(); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); break; case "ilpermissiongui": $this->prepareOutput(); $ilTabs->activateTab("id_permissions"); $perm_gui = new ilPermissionGUI($this); - $this->ctrl->forwardCommand($perm_gui); + $this->cmd_perm->forwardPermitted($this, $perm_gui); break; case "ilobjectcopygui": $this->prepareOutput(); $cp = new ilObjectCopyGUI($this); $cp->setType("blog"); - $this->ctrl->forwardCommand($cp); + $this->cmd_perm->forwardPermitted($this, $cp); break; - case 'ilrepositorysearchgui': + case strtolower(\ilRepositorySearchGUI::class): + $this->checkPermission("write"); $this->prepareOutput(); $ilTabs->activateTab("contributors"); - $rep_search = new ilRepositorySearchGUI(); - $rep_search->setTitle($this->lng->txt("blog_add_contributor")); - $rep_search->setCallback($this, 'addContributor', $this->object->getAllLocalRoles($this->node_id)); - $this->ctrl->setReturn($this, 'contributors'); - $this->ctrl->forwardCommand($rep_search); + $this->cmd_perm->forwardPermitted($this, $this->gui->contributor()->contributorGUI($this->node_id, $this->object)); break; case 'ilexportgui': - $this->showExportGUI(); + $this->prepareOutput(); + $this->tabs->activateTab("export"); + $exp_gui = new ilExportGUI($this); + $this->cmd_perm->forwardPermitted($this, $exp_gui); break; case "ilobjectcontentstylesettingsgui": @@ -544,14 +429,14 @@ public function executeCommand(): void $this->object->getId() ); } - $this->ctrl->forwardCommand($settings_gui); + $this->cmd_perm->forwardPermitted($this, $settings_gui); break; case "ilblogexercisegui": $this->ctrl->setReturn($this, "render"); $gui = $this->gui->exercise()->ilBlogExerciseGUI($this->node_id); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); break; case 'ilobjnotificationsettingsgui': @@ -559,7 +444,7 @@ public function executeCommand(): void $ilTabs->activateTab("settings"); $this->setSettingsSubTabs("notifications"); $gui = new ilObjNotificationSettingsGUI($this->object->getRefId()); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); break; case strtolower(ilObjectMetaDataGUI::class): @@ -567,7 +452,7 @@ public function executeCommand(): void $this->prepareOutput(); $ilTabs->activateTab("meta_data"); $gui = new ilObjectMetaDataGUI($this->object, null, null, $this->call_by_reference); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); break; case strtolower(SettingsGUI::class): @@ -579,7 +464,46 @@ public function executeCommand(): void $this->obj_id, $this->id_type === self::REPOSITORY_NODE_ID ); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); + break; + + case strtolower(\ILIAS\Blog\Editing\EditingGUI::class): + $this->prepareOutput(); + $this->addHeaderAction(); + $gui = $this->gui->editing()->editingGUI( + $this->node_id, + $this->id_type, + $this->perm, + $this->month, + $this->content_style_domain, + $this + ); + $this->cmd_perm->forwardPermitted($this, $gui); + break; + + case strtolower(\ILIAS\Blog\Presentation\PresentationGUI::class): + $this->prepareOutput(); + $this->initHeaderAction(null, null, true); + $gui = $this->gui->presentation()->presentationGUI( + $this, + $this->perm, + $this->content_style_domain, + $this->month, + $this->node_id, + $this->id_type, + ); + $this->cmd_perm->forwardPermitted($this, $gui); + break; + + case strtolower(ContributorGUI::class): + $this->checkPermission("write"); + $this->prepareOutput(); + $ilTabs->activateTab("contributors"); + $gui = $this->gui->contributor()->contributorGUI( + $this->node_id, + $this->object + ); + $this->cmd_perm->forwardPermitted($this, $gui); break; case strtolower(\ILIAS\Blog\Settings\BlockSettingsGUI::class): @@ -591,35 +515,26 @@ public function executeCommand(): void $this->obj_id, $this->id_type === self::REPOSITORY_NODE_ID ); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); + break; + + case "ilworkspaceaccessgui": + $this->checkPermission("write"); + parent::executeCommand(); break; default: - if ($cmd !== "gethtml") { - // desktop item handling, must be toggled before header action - if ($cmd === "addToDesk" || $cmd === "removeFromDesk") { - $this->{$cmd . "Object"}(); - if ($this->prvm) { - $cmd = "preview"; - } else { - $cmd = "render"; - } - // $ilCtrl->setCmd($cmd); - } - $this->addHeaderActionForCommand($cmd); + // desktop item handling, must be toggled before header action + $cmd = $ilCtrl->getCmd(); + //$this->addHeaderActionForCommand($cmd); + $this->prepareOutput(); + if ($this->cmd_perm->classImplementsMethodDirectly(get_class($this), $cmd)) { + $cmd = $this->cmd_perm->getPermittedCommand(); } - parent::executeCommand(); + $this->$cmd(); } } - protected function showExportGUI(): void - { - $this->prepareOutput(); - $this->tabs->activateTab("export"); - $exp_gui = new ilExportGUI($this); - $this->ctrl->forwardCommand($exp_gui); - } - protected function createExportFileWithComments(): void { $this->buildExportFile(true); @@ -695,194 +610,28 @@ public function infoScreenForward(): void // standard meta data $info->addMetaDataSections($this->object->getId(), 0, $this->object->getType()); - $this->ctrl->forwardCommand($info); - } - - /** - * Create new posting - */ - public function createPosting(): void - { - $ilCtrl = $this->ctrl; - $ilUser = $this->user; - - $title = $this->blog_request->getTitle(); - if ($title) { - // create new posting - $posting = new ilBlogPosting(); - $posting->setTitle($title); - $posting->setBlogId($this->object->getId()); - $posting->setActive(false); - $posting->setAuthor($ilUser->getId()); - $posting->create(false); - - // switch month list to current month (will include new posting) - $ilCtrl->setParameter($this, "bmn", date("Y-m")); - - $ilCtrl->setParameterByClass("ilblogpostinggui", "blpg", $posting->getId()); - $ilCtrl->redirectByClass("ilblogpostinggui", "edit"); - } else { - $this->tpl->setOnScreenMessage('failure', $this->lng->txt("msg_no_title"), true); - $ilCtrl->redirect($this, "render"); - } - } - - /** - * Render object context - */ - public function render(): void - { - $tpl = $this->tpl; - $ilTabs = $this->tabs; - $ilCtrl = $this->ctrl; - $lng = $this->lng; - $ilToolbar = new ilToolbarGUI(); - - if (!$this->checkPermissionBool("read")) { - $this->tpl->setOnScreenMessage('info', $lng->txt("no_permission")); - return; - } - - $ilTabs->activateTab("content"); - - // toolbar - if ($this->perm->mayContribute()) { - $ilToolbar->setFormAction($ilCtrl->getFormAction($this, "createPosting")); - - $title = new ilTextInputGUI($lng->txt("title"), "title"); - $title->setSize(30); - $ilToolbar->addStickyItem($title, true); - $tpl->addOnLoadCode(" - document.getElementById('title').setAttribute('data-blog-input', 'posting-title'); - document.getElementById('title').setAttribute('placeholder', ' '); - "); - - $this->gui->button( - $lng->txt("blog_add_posting"), - "createPosting" - )->submit()->toToolbar(true, $ilToolbar); - - // #18763 - $keys = array_keys($this->items); - $first = array_shift($keys); - if ($first != $this->month) { - $ilToolbar->addSeparator(); - - $ilCtrl->setParameter($this, "bmn", $first); - $url = $ilCtrl->getLinkTarget($this, ""); - $ilCtrl->setParameter($this, "bmn", $this->month); - - $this->gui->link( - $lng->txt("blog_show_latest"), - $url - )->emphasised()->toToolbar(true, $ilToolbar); - } - - // print/pdf - $print_view = $this->getPrintView(); - $modal_elements = $print_view->getModalElements( - $this->ctrl->getLinkTarget( - $this, - "printViewSelection" - ) - ); - $ilToolbar->addSeparator(); - $ilToolbar->addComponent($modal_elements->button); - $ilToolbar->addComponent($modal_elements->modal); - } - - // $is_owner = ($this->object->getOwner() == $ilUser->getId()); - $is_owner = $this->perm->mayContribute(); - - $list_items = $this->getListItems($is_owner); - - $list = $nav = ""; - if ($list_items) { - $list = $this->renderList($list_items, "preview", "", $is_owner); - $nav = $this->renderNavigation("render", "edit", "", $is_owner); - } - - $this->setContentStyleSheet(); - - $tpl->setContent($ilToolbar->getHTML() . $list); - $tpl->setRightContent($nav); + $this->cmd_perm->forwardPermitted($this, $info); } /** * Filter blog postings by month, keyword or author */ - protected function getListItems( + public function getListItems( bool $a_show_inactive = false ): array { - if ($this->author) { - $list_items = array(); - foreach ($this->items as $month => $items) { - foreach ($items as $id => $item) { - /** @var \ILIAS\Blog\Posting\Posting $item */ - $author_id = $item->getAuthor(); - $editors = []; - foreach (\ilPageObject::getPageContributors("blp", $item->getId()) as $editor) { - if ($editor["user_id"] != $author_id) { - $editors[] = (int) $editor["user_id"]; - } - } - if ($author_id === $this->author || in_array($this->author, $editors, true)) { - $list_items[$id] = $item; - } - } - } - } elseif ($this->keyword) { - $list_items = $this->filterItemsByKeyword($this->items, $this->keyword); - } else { - $max = $this->blog_settings->getOverviewPostings(); - if ($this->month_default && $max) { - $list_items = array(); - foreach ($this->items as $month => $postings) { - foreach ($postings as $id => $item) { - if (!$a_show_inactive && - !ilBlogPosting::_lookupActive($id, "blp")) { - continue; - } - $list_items[$id] = $item; - - if (count($list_items) >= $max) { - break(2); - } - } - } - } else { - $list_items = $this->items[$this->month] ?? []; - } - } - return $list_items; + return $this->getListItemsInternal($a_show_inactive); } - /** - * Render fullscreen presentation - */ - public function preview(): void - { - $lng = $this->lng; - $toolbar = $this->toolbar; - - if (!$this->checkPermissionBool("read")) { - $this->tpl->setOnScreenMessage('info', $lng->txt("no_permission")); - return; - } - - $this->filterInactivePostings(); - - $list_items = $this->getListItems(); - - $list = $nav = ""; - if ($list_items) { - $list = $this->renderList($list_items, "previewFullscreen"); - $nav = $this->renderNavigation("preview", "previewFullscreen"); - $this->renderToolbarNavigation($this->items); - } - - $this->renderFullScreen($list, $nav); + protected function getListItemsInternal( + bool $a_show_inactive = false + ): array { + return $this->domain->postingList($this->obj_id, $this->blog_settings, $a_show_inactive) + ->getPostingsForView( + $this->author ?? 0, + $this->keyword ?? "", + $this->month ?? "" + ); } /** @@ -935,7 +684,7 @@ public function renderFullScreen( $this->ctrl->setParameterByClass("ilblogpostinggui", "blpg", $this->blpg); $back = $this->ctrl->getLinkTargetByClass("ilblogpostinggui", "preview"); } - $this->ctrl->setParameter($this, "prvm", $this->prvm); + //$this->ctrl->setParameter($this, "prvm", $this->prvm); } $back_caption = $this->lng->txt("blog_back_to_blog_owner"); @@ -1037,33 +786,13 @@ public function renderFullscreenHeader( protected function buildPostingList( int $a_obj_id ): array { - $author_found = false; - - $items = array(); - foreach ($this->posting_manager->getAllPostings($a_obj_id) as $posting) { - // author filter pre-check - if ($this->author) { - $author_id = $posting->getAuthor(); - $editors = []; - foreach (\ilPageObject::getPageContributors("blp", $posting->getId()) as $editor) { - if ($editor["user_id"] != $author_id) { - $editors[] = (int) $editor["user_id"]; - } - } - if ($author_id === $this->author || in_array($this->author, $editors, true)) { - $author_found = true; - } - } - - $month = substr($posting->getCreated()->get(IL_CAL_DATE), 0, 7); - $items[$month][$posting->getId()] = $posting; - } + $posting_list = $this->domain->postingList($a_obj_id, $this->blog_settings); - if ($this->author && !$author_found) { + if ($this->author && !$posting_list->hasAuthorPostings($this->author)) { $this->author = null; } - return $items; + return $posting_list->getPostingsGroupedByMonth(); } /** @@ -1076,885 +805,137 @@ public function renderList( bool $a_show_inactive = false, string $a_export_directory = "" ): string { - $lng = $this->lng; - $ilCtrl = $this->ctrl; - $ilUser = $this->user; - $ui_factory = $this->ui->factory(); - $ui_renderer = $this->ui->renderer(); - - $wtpl = new ilTemplate("tpl.blog_list.html", true, true, "components/ILIAS/Blog"); - - $is_admin = $this->perm->canManage(); - - $last_month = null; - $is_empty = true; - foreach ($items as $item) { - /** @var \ILIAS\Blog\Posting\Posting $item */ - $item_id = $item->getId(); - $author = $item->getAuthor(); - $created = $item->getCreated(); - $approved = $item->isApproved(); - // only published items - $is_active = ilBlogPosting::_lookupActive($item_id, "blp"); - if (!$is_active && !$a_show_inactive) { - continue; - } - - $is_empty = false; + return $this->gui->posting()->postingList( + $this, + $this->perm, + $this->month, + $this->node_id, + $this->id_type, + )->render( + $items, + $a_cmd, + $a_link_template, + $a_show_inactive, + $a_export_directory + ); + } - $month = ""; - if (!$this->keyword && !$this->author) { - $month = substr($created->get(IL_CAL_DATE), 0, 7); - } + public function buildExportLink( + string $a_template, + string $a_type, + string $a_id + ): string { + return $this->buildExportLinkInternal($a_template, $a_type, $a_id); + } - if (!$last_month || $last_month != $month) { - if ($last_month) { - $wtpl->setCurrentBlock("month_bl"); - $wtpl->parseCurrentBlock(); - } + protected function buildExportLinkInternal( + string $a_template, + string $a_type, + string $a_id + ): string { + $blog_export = new BlogHtmlExport( + $this, + $this->id_type === self::REPOSITORY_NODE_ID, + "", + "" + ); + return $blog_export->buildExportLink($a_template, $a_type, $a_id, $this->getKeywords(false)); + } - // title according to current "filter"/navigation - if ($this->keyword) { - $title = $lng->txt("blog_keyword") . ": " . $this->keyword; - } elseif ($this->author) { - $title = $lng->txt("blog_author") . ": " . $this->profile_gui->getNamePresentation($this->author); + /** + * Get keywords for single posting or complete blog + */ + public function getKeywords( + bool $a_show_inactive, + ?int $a_posting_id = null + ): array { + $keywords = array(); + if ($a_posting_id) { + foreach ($this->posting_manager->getKeywords($this->obj_id, $a_posting_id) as $keyword) { + if (isset($keywords[$keyword])) { + $keywords[$keyword]++; } else { - $title = $this->gui->presentation()->util()->getMonthPresentation($month); - $last_month = $month; + $keywords[$keyword] = 1; } - - $wtpl->setVariable("TXT_CURRENT_MONTH", $title); - } - - if (!$a_link_template) { - $ilCtrl->setParameterByClass("ilblogpostinggui", "bmn", $this->month); - $ilCtrl->setParameterByClass("ilblogpostinggui", "blpg", $item_id); - $preview = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", $a_cmd); - } else { - $preview = $this->buildExportLink($a_link_template, "posting", (string) $item_id); } - $more_link = $preview; - - // actions - $posting_edit = $this->perm->mayEditPosting($item_id, $author); - if (($posting_edit || $is_admin) && !$a_link_template && $a_cmd === "preview") { - $actions = []; - - if ($is_active && $this->blog_settings->getApproval() && !$approved) { - if ($is_admin) { - $ilCtrl->setParameter($this, "apid", $item_id); - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_approve"), - $ilCtrl->getLinkTarget($this, "approve") - ); - $ilCtrl->setParameter($this, "apid", ""); + } else { + foreach ($this->items as $month => $items) { + foreach ($items as $item) { + /** @var \ILIAS\Blog\Posting\Posting $item */ + $item_id = $item->getId(); + if ($a_show_inactive || ilBlogPosting::_lookupActive($item_id, "blp")) { + foreach ($this->posting_manager->getKeywords($this->obj_id, $item_id) as $keyword) { + if (isset($keywords[$keyword])) { + $keywords[$keyword]++; + } else { + $keywords[$keyword] = 1; + } + } } - - $wtpl->setVariable("APPROVAL", $lng->txt("blog_needs_approval")); } + } + } - if ($posting_edit) { - $actions[] = $ui_factory->link()->standard( - $lng->txt("edit_content"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edit") - ); - $more_link = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edit"); + // #15881 + $tmp = array(); + foreach ($keywords as $keyword => $counter) { + $tmp[] = array("keyword" => $keyword, "counter" => $counter); + } + $tmp = ilArrayUtil::sortArray($tmp, "keyword", "ASC"); - // #11858 - if ($is_active) { - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_toggle_draft"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deactivatePageToList") - ); - } else { - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_toggle_final"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "activatePageToList") - ); - } + $keywords = array(); + foreach ($tmp as $item) { + $keywords[(string) $item["keyword"]] = $item["counter"]; + } + return $keywords; + } - $actions[] = $ui_factory->link()->standard( - $lng->txt("rename"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edittitle") - ); + /** + * Build export file + */ + public function buildExportFile( + bool $a_include_comments = false, + bool $print_version = false + ): BlogHtmlExport { + $type = "html"; + $format = explode("_", $this->blog_request->getFormat()); + if (($format[1] ?? "") === "comments" || $a_include_comments) { + $a_include_comments = true; + $type = "html_comments"; + } - if ($this->blog_settings->getKeywords()) { // #13616 - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_edit_keywords"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "editKeywords") - ); - } - - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_edit_date"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "editdate") - ); - - $actions[] = $ui_factory->link()->standard( - $lng->txt("delete"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deleteBlogPostingConfirmationScreen") - ); - } elseif ($is_admin) { - // #10513 - if ($is_active) { - $ilCtrl->setParameter($this, "apid", $item_id); - $actions[] = $ui_factory->link()->standard( - $lng->txt("blog_toggle_draft_admin"), - $ilCtrl->getLinkTarget($this, "deactivateAdmin") - ); - $ilCtrl->setParameter($this, "apid", ""); - } - - $actions[] = $ui_factory->link()->standard( - $lng->txt("delete"), - $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "deleteBlogPostingConfirmationScreen") - ); - } - - $dd = $ui_factory->dropdown()->standard($actions)->withLabel($this->lng->txt("actions")); - - $wtpl->setCurrentBlock("actions"); - $wtpl->setVariable("ACTION_SELECTOR", $ui_renderer->render($dd)); - $wtpl->parseCurrentBlock(); - } - - // comments - if ($this->object->getNotesStatus() && !$a_link_template && !$this->disable_notes) { - // count (public) notes - $notes_context = $this->notes - ->data() - ->context( - $this->obj_id, - (int) $item_id, - "blp" - ); - $count = $this->notes - ->domain() - ->getNrOfCommentsForContext($notes_context); - - if ($a_cmd !== "preview") { - $wtpl->setCurrentBlock("comments"); - $wtpl->setVariable("TEXT_COMMENTS", $lng->txt("blog_comments")); - $wtpl->setVariable("URL_COMMENTS", $preview); - $wtpl->setVariable("COUNT_COMMENTS", $count); - $wtpl->parseCurrentBlock(); - } - } - - // permanent link - if ($this->node_id !== null && - $a_cmd !== "preview") { - if ($this->id_type === self::WORKSPACE_NODE_ID) { - $goto = $this->gui->permanentLink(0, (int) $this->node_id)->getPermanentLink((int) $item_id); - } else { - $goto = $this->gui->permanentLink((int) $this->node_id)->getPermanentLink((int) $item_id); - } - $wtpl->setCurrentBlock("permalink"); - $wtpl->setVariable("URL_PERMALINK", $goto); - $wtpl->setVariable("TEXT_PERMALINK", $lng->txt("blog_link")); - $wtpl->parseCurrentBlock(); - } - - $snippet = ilBlogPostingGUI::getSnippet( - $item_id, - $this->blog_settings->getAbstractShorten(), - $this->blog_settings->getAbstractShortenLength(), - "…", - $this->blog_settings->getAbstractImage(), - $this->blog_settings->getAbstractImageWidth(), - $this->blog_settings->getAbstractImageHeight(), - $a_export_directory - ); - - if ($snippet) { - $wtpl->setCurrentBlock("more"); - $wtpl->setVariable("URL_MORE", $more_link); - $wtpl->setVariable("TEXT_MORE", $lng->txt("blog_list_more")); - $wtpl->parseCurrentBlock(); - } - - - - if (!$is_active) { - $wtpl->setCurrentBlock("draft_text"); - $wtpl->setVariable("DRAFT_TEXT", $lng->txt("blog_draft_text")); - $wtpl->parseCurrentBlock(); - $wtpl->setVariable("DRAFT_CLASS", " ilBlogListItemDraft"); - } - - // reading time - $reading_time = $this->reading_time_manager->getReadingTime( - $this->object->getId(), - $item_id - ); - if (!is_null($reading_time)) { - $this->lng->loadLanguageModule("copg"); - $wtpl->setCurrentBlock("reading_time"); - $wtpl->setVariable( - "READING_TIME", - $this->lng->txt("copg_est_reading_time") . ": " . - sprintf($this->lng->txt("copg_x_minutes"), $reading_time) - ); - $wtpl->parseCurrentBlock(); - } - - $wtpl->setCurrentBlock("posting"); - - $author_str = ""; - if ($this->id_type === self::REPOSITORY_NODE_ID) { - $authors = array(); - - // primary author - if ($author) { - $authors[] = $this->profile_gui->getNamePresentation($author); - } - - // additional editors - foreach (\ilPageObject::getPageContributors("blp", $item_id) as $editor) { - $editor_id = (int) $editor["user_id"]; - if ($editor_id !== $author) { - $authors[] = $this->profile_gui->getNamePresentation($editor_id); - } - } - - if ($authors) { - $author_str = implode(", ", $authors) . " - "; - } - } - - // title - $wtpl->setVariable("URL_TITLE", $preview); - $wtpl->setVariable("TITLE", $item->getTitle()); - - $kw = $this->posting_manager->getKeywords($this->obj_id, $item_id); - natcasesort($kw); - $keywords = (count($kw) > 0) - ? "
" . $this->lng->txt("keywords") . ": " . implode(", ", $kw) - : ""; - - $wtpl->setVariable("DATETIME", $author_str . - ilDatePresentation::formatDate($created) . $keywords); - - // content - $wtpl->setVariable("CONTENT", $snippet); - - $wtpl->parseCurrentBlock(); - } - - // permalink - if ($a_cmd === "previewFullscreen") { - $ref_id = ($this->id_type === self::WORKSPACE_NODE_ID) - ? 0 - : $this->node_id; - $wsp_id = ($this->id_type === self::WORKSPACE_NODE_ID) - ? $this->node_id - : 0; - $this->gui->permanentLink($ref_id, $wsp_id)->setPermanentLink(); - } - - if (!$is_empty || $a_show_inactive) { - return $wtpl->get(); - } - return ""; - } - - /** - * Build export link - */ - protected function buildExportLink( - string $a_template, - string $a_type, - string $a_id - ): string { - $blog_export = new BlogHtmlExport($this, "", ""); - return $blog_export->buildExportLink($a_template, $a_type, $a_id, $this->getKeywords(false)); - } - - - /** - * Build navigation by date block - */ - protected function renderNavigationByDate( - array $a_items, - string $a_list_cmd = "render", - string $a_posting_cmd = "preview", - ?string $a_link_template = null, - bool $a_show_inactive = false, - int $a_blpg = 0 - ): string { - $ilCtrl = $this->ctrl; - - $blpg = ($a_blpg > 0) - ? $a_blpg - : $this->blpg; - - - // gather page active status - foreach ($a_items as $month => $postings) { - foreach (array_keys($postings) as $id) { - $active = ilBlogPosting::_lookupActive($id, "blp"); - if (!$a_show_inactive && !$active) { - unset($a_items[$month][$id]); - } - } - if (!count($a_items[$month])) { - unset($a_items[$month]); - } - } - - // list month (incl. postings) - if ($this->blog_settings->getNavMode() === ilObjBlog::NAV_MODE_LIST || $a_link_template) { - $max_months = $this->blog_settings->getNavModeListMonths(); - - $wtpl = new ilTemplate("tpl.blog_list_navigation_by_date.html", true, true, "components/ILIAS/Blog"); - - $ilCtrl->setParameter($this, "blpg", ""); - - $counter = $mon_counter = $last_year = 0; - foreach ($a_items as $month => $postings) { - if (!$a_link_template && $max_months && $mon_counter >= $max_months) { - break; - } - - $add_year = false; - $year = substr($month, 0, 4); - if (!$last_year || $year != $last_year) { - // #13562 - $add_year = true; - $last_year = $year; - } - - $mon_counter++; - - $month_name = ilCalendarUtil::_numericMonthToString((int) substr($month, 5)); - if (!$a_link_template) { - $ilCtrl->setParameter($this, "bmn", $month); - $month_url = $ilCtrl->getLinkTarget($this, $a_list_cmd); - } else { - $month_url = $this->buildExportLink($a_link_template, "list", (string) $month); - } - - // list postings for month - //if($counter < $max_detail_postings) - if ($mon_counter <= $this->blog_settings->getNavModeListMonthsWithPostings()) { - if ($add_year) { - $wtpl->setCurrentBlock("navigation_year_details"); - $wtpl->setVariable("YEAR", $year); - $wtpl->parseCurrentBlock(); - } - - foreach ($postings as $id => $posting) { - //if($max_detail_postings && $counter >= $max_detail_postings) - //{ - // break; - //} - - $counter++; - - $caption = /* ilDatePresentation::formatDate($posting["created"], IL_CAL_DATETIME). - ", ".*/ $posting->getTitle(); - - if (!$a_link_template) { - $ilCtrl->setParameterByClass("ilblogpostinggui", "bmn", $month); - $ilCtrl->setParameterByClass("ilblogpostinggui", "blpg", $id); - $url = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", $a_posting_cmd); - } else { - $url = $this->buildExportLink($a_link_template, "posting", (string) $id); - } - - if (!$posting->isActive()) { - $wtpl->setVariable("NAV_ITEM_DRAFT", $this->lng->txt("blog_draft")); - } elseif ($this->blog_settings->getApproval() && !$posting->isApproved()) { - $wtpl->setVariable("NAV_ITEM_APPROVAL", $this->lng->txt("blog_needs_approval")); - } - - $wtpl->setCurrentBlock("navigation_item"); - $wtpl->setVariable("NAV_ITEM_URL", $url); - $wtpl->setVariable("NAV_ITEM_CAPTION", $caption); - $wtpl->parseCurrentBlock(); - } - - $wtpl->setCurrentBlock("navigation_month_details"); - $wtpl->setVariable("NAV_MONTH", $month_name); - $wtpl->setVariable("URL_MONTH", $month_url); - } - // summarized month - else { - if ($add_year) { - $wtpl->setCurrentBlock("navigation_year"); - $wtpl->setVariable("YEAR", $year); - $wtpl->parseCurrentBlock(); - } - - $wtpl->setCurrentBlock("navigation_month"); - $wtpl->setVariable("MONTH_NAME", $month_name); - $wtpl->setVariable("URL_MONTH", $month_url); - $wtpl->setVariable("MONTH_COUNT", count($postings)); - } - $wtpl->parseCurrentBlock(); - } - if (!$a_link_template) { - $this->ctrl->setParameterByClass(self::class, "bmn", null); - $url = $this->ctrl->getLinkTargetByClass(self::class, $a_list_cmd); - } else { - $url = "index.html"; - } - - $wtpl->setVariable( - "STARTING_PAGE", - $this->ui->renderer()->render( - $this->ui->factory()->link()->standard( - $this->lng->txt("blog_starting_page"), - $url - ) - ) - ); - } - // single month - else { - $wtpl = new ilTemplate("tpl.blog_list_navigation_month.html", true, true, "components/ILIAS/Blog"); - - $ilCtrl->setParameter($this, "blpg", ""); - - $month_options = array(); - foreach ($a_items as $month => $postings) { - $month_name = $this->gui->presentation()->util()->getMonthPresentation($month); - - $month_options[$month] = $month_name; - - if ($month == $this->month) { - if (!$a_link_template) { - $ilCtrl->setParameter($this, "bmn", $month); - $month_url = $ilCtrl->getLinkTarget($this, $a_list_cmd); - } else { - $month_url = $this->buildExportLink($a_link_template, "list", (string) $month); - } - - foreach ($postings as $id => $posting) { - $caption = /* ilDatePresentation::formatDate($posting["created"], IL_CAL_DATETIME). - ", ".*/ $posting["title"]; - - if (!$a_link_template) { - $ilCtrl->setParameterByClass("ilblogpostinggui", "bmn", $month); - $ilCtrl->setParameterByClass("ilblogpostinggui", "blpg", $id); - $url = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", $a_posting_cmd); - } else { - $url = $this->buildExportLink($a_link_template, "posting", (string) $id); - } - - if (!$posting->isActive()) { - $wtpl->setVariable("NAV_ITEM_DRAFT", $this->lng->txt("blog_draft")); - } elseif ($this->blog_settings->getApproval() && !$posting["approved"]) { - $wtpl->setVariable("NAV_ITEM_APPROVAL", $this->lng->txt("blog_needs_approval")); - } - - $wtpl->setCurrentBlock("navigation_item"); - $wtpl->setVariable("NAV_ITEM_URL", $url); - $wtpl->setVariable("NAV_ITEM_CAPTION", $caption); - $wtpl->parseCurrentBlock(); - } - - $wtpl->setCurrentBlock("navigation_month_details"); - if ($blpg > 0) { - $wtpl->setVariable("NAV_MONTH", $month_name); - $wtpl->setVariable("URL_MONTH", $month_url); - } - $wtpl->parseCurrentBlock(); - } - } - - if ($blpg === 0) { - $wtpl->setCurrentBlock("option_bl"); - foreach ($month_options as $value => $caption) { - $wtpl->setVariable("OPTION_VALUE", $value); - $wtpl->setVariable("OPTION_CAPTION", $caption); - if ($value == $this->month) { - $wtpl->setVariable("OPTION_SEL", ' selected="selected"'); - } - $wtpl->parseCurrentBlock(); - } - - $wtpl->setVariable("FORM_ACTION", $ilCtrl->getFormAction($this, $a_list_cmd)); - } - } - $ilCtrl->setParameter($this, "bmn", $this->month); - $ilCtrl->setParameterByClass("ilblogpostinggui", "bmn", ""); - return $wtpl->get(); - } - - /** - * Build navigation by keywords block - */ - protected function renderNavigationByKeywords( - string $a_list_cmd = "render", - bool $a_show_inactive = false, - string $a_link_template = "", - int $a_blpg = 0 - ): string { - $ilCtrl = $this->ctrl; - - $blpg = ($a_blpg > 0) - ? $a_blpg - : $this->blpg; - - $keywords = $this->getKeywords($a_show_inactive, $blpg); - if ($keywords) { - $wtpl = new ilTemplate("tpl.blog_list_navigation_keywords.html", true, true, "components/ILIAS/Blog"); - - $max = max($keywords); - - $wtpl->setCurrentBlock("keyword"); - foreach ($keywords as $keyword => $counter) { - if (!$a_link_template) { - $ilCtrl->setParameter($this, "kwd", urlencode((string) $keyword)); // #15885 - $url = $ilCtrl->getLinkTarget($this, $a_list_cmd); - $ilCtrl->setParameter($this, "kwd", ""); - } else { - $url = $this->buildExportLink($a_link_template, "keyword", (string) $keyword); - } - - $wtpl->setVariable("TXT_KEYWORD", $keyword); - $wtpl->setVariable("CLASS_KEYWORD", ilTagging::getRelevanceClass($counter, $max)); - $wtpl->setVariable("URL_KEYWORD", $url); - $wtpl->parseCurrentBlock(); - } - - return $wtpl->get(); - } - return ""; - } - - protected function renderNavigationByAuthors( - array $a_items, - string $a_list_cmd = "render", - bool $a_show_inactive = false - ): string { - $ilCtrl = $this->ctrl; - - $authors = array(); - foreach ($a_items as $month => $items) { - foreach ($items as $item) { - /** @var \ILIAS\Blog\Posting\Posting $item */ - $item_id = $item->getId(); - if (($a_show_inactive || ilBlogPosting::_lookupActive($item_id, "blp"))) { - $author_id = $item->getAuthor(); - if ($author_id) { - $authors[] = $author_id; - } - foreach (\ilPageObject::getPageContributors("blp", $item_id) as $editor) { - $editor_id = (int) $editor["user_id"]; - if ($editor_id !== $author_id) { - $authors[] = $editor_id; - } - } - } - } - } - - $authors = array_unique($authors); - - // filter out deleted users - $authors = array_filter($authors, function ($id) { - return ilObject::_lookupType($id) == "usr"; - }); - - if (count($authors) > 1) { - $list = array(); - foreach ($authors as $user_id) { - if ($user_id) { - $ilCtrl->setParameter($this, "ath", $user_id); - $url = $ilCtrl->getLinkTarget($this, $a_list_cmd); - $ilCtrl->setParameter($this, "ath", ""); - - $base_name = ilUserUtil::getNamePresentation($user_id); - if (str_starts_with($base_name, "[")) { - $name = ilUserUtil::getNamePresentation($user_id, true); - $sort = $name; - } else { - $name = ilUserUtil::getNamePresentation( - $user_id, - true, - false, - "", - false, - true, - false - ); - $name_arr = ilObjUser::_lookupName($user_id); - $sort = $name_arr["lastname"] . " " . $name_arr["firstname"]; - } - - $idx = trim(strip_tags($sort)) . "///" . $user_id; // #10934 - $list[$idx] = array($name, $url); - } - } - ksort($list); - - $wtpl = new ilTemplate("tpl.blog_list_navigation_authors.html", true, true, "components/ILIAS/Blog"); - - $wtpl->setCurrentBlock("author"); - foreach ($list as $author) { - $wtpl->setVariable("TXT_AUTHOR", $author[0]); - $wtpl->setVariable("URL_AUTHOR", $author[1]); - $wtpl->parseCurrentBlock(); - } - - return $wtpl->get(); - } - return ""; - } - - /** - * Toolbar navigation - */ - public function renderToolbarNavigation( - array $a_items, - bool $single_posting = false - ): void { - $nav_renderer = $this->gui->navigation()->toolbarNavigationRenderer(); - $nav_renderer->renderToolbarNavigation( - $this->perm, - $a_items, - $this->blpg, - $single_posting, - $this->month, - $this->user_page - ); - } - - /** - * Build navigation blocks - */ - public function renderNavigation( - string $a_list_cmd = "render", - string $a_posting_cmd = "preview", - ?string $a_link_template = null, - bool $a_show_inactive = false, - int $a_blpg = 0 - ): string { - $ilSetting = $this->settings; - $a_items = $this->items; - $blpg = ($a_blpg > 0) - ? $a_blpg - : $this->blpg; - - if ($this->blog_settings->getOrder()) { - $order = array_flip($this->blog_settings->getOrder()); - } else { - $order = array( - "navigation" => 0 - ,"keywords" => 2 - ,"authors" => 1 - ); - } - - $wtpl = new ilTemplate("tpl.blog_list_navigation.html", true, true, "components/ILIAS/Blog"); - - $blocks = array(); - - // by date - if (count($a_items)) { - $blocks[$order["navigation"] ?? 0] = array( - $this->lng->txt("blog_navigation"), - $this->renderNavigationByDate($a_items, $a_list_cmd, $a_posting_cmd, $a_link_template, $a_show_inactive, $a_blpg) - ); - } - - if ($this->blog_settings->getKeywords()) { - // keywords - $may_edit_keywords = ($blpg > 0 && - $this->perm->mayEditPosting($blpg) && - $a_list_cmd !== "preview" && - $a_list_cmd !== "gethtml" && - !$a_link_template); - $keywords = $this->renderNavigationByKeywords($a_list_cmd, $a_show_inactive, (string) $a_link_template, $a_blpg); - if ($keywords || $may_edit_keywords) { - if (!$keywords) { - $keywords = $this->lng->txt("blog_no_keywords"); - } - $cmd = null; - $blocks[$order["keywords"] ?? 2] = array( - $this->lng->txt("blog_keywords"), - $keywords, - $cmd - ? array($cmd, $this->lng->txt("blog_edit_keywords")) - : null - ); - } - } - - // is not part of (html) export - if (!$a_link_template) { - // authors - if ($this->id_type === self::REPOSITORY_NODE_ID && - $this->blog_settings->getAuthors()) { - $authors = $this->renderNavigationByAuthors($a_items, $a_list_cmd, $a_show_inactive); - if ($authors) { - $blocks[$order["authors"] ?? 1] = array($this->lng->txt("blog_authors"), $authors); - } - } - - // rss - if ($this->blog_settings->getRSS() && - $ilSetting->get('enable_global_profiles') && - $a_list_cmd === "preview") { - // #10827 - $blog_id = $this->node_id; - if ($this->id_type !== self::WORKSPACE_NODE_ID) { - $blog_id .= "_cll"; - } - $url = ILIAS_HTTP_PATH . "/feed.php?blog_id=" . $blog_id . - "&client_id=" . rawurlencode(CLIENT_ID); - - $wtpl->setVariable("RSS_BUTTON", ilRSSButtonGUI::get(ilRSSButtonGUI::ICON_RSS, $url)); - } - } - - if (count($blocks)) { - global $DIC; - - $ui_factory = $DIC->ui()->factory(); - $ui_renderer = $DIC->ui()->renderer(); - - ksort($blocks); - foreach ($blocks as $block) { - $title = $block[0]; - - $content = $block[1]; - - $secondary_panel = $ui_factory->panel()->secondary()->legacy($title, $ui_factory->legacy()->content($content)); - - if (isset($block[2]) && is_array($block[2])) { - $link = $ui_factory->button()->shy($block[2][1], $block[2][0]); - $secondary_panel = $secondary_panel->withFooter($link); - } - - $wtpl->setCurrentBlock("block_bl"); - $wtpl->setVariable("BLOCK", $ui_renderer->render($secondary_panel)); - $wtpl->parseCurrentBlock(); - } - } - - return $wtpl->get(); - } - - /** - * Get keywords for single posting or complete blog - */ - public function getKeywords( - bool $a_show_inactive, - ?int $a_posting_id = null - ): array { - $keywords = array(); - if ($a_posting_id) { - foreach ($this->posting_manager->getKeywords($this->obj_id, $a_posting_id) as $keyword) { - if (isset($keywords[$keyword])) { - $keywords[$keyword]++; - } else { - $keywords[$keyword] = 1; - } - } - } else { - foreach ($this->items as $month => $items) { - foreach ($items as $item) { - /** @var \ILIAS\Blog\Posting\Posting $item */ - $item_id = $item->getId(); - if ($a_show_inactive || ilBlogPosting::_lookupActive($item_id, "blp")) { - foreach ($this->posting_manager->getKeywords($this->obj_id, $item_id) as $keyword) { - if (isset($keywords[$keyword])) { - $keywords[$keyword]++; - } else { - $keywords[$keyword] = 1; - } - } - } - } - } - } - - // #15881 - $tmp = array(); - foreach ($keywords as $keyword => $counter) { - $tmp[] = array("keyword" => $keyword, "counter" => $counter); - } - $tmp = ilArrayUtil::sortArray($tmp, "keyword", "ASC"); - - $keywords = array(); - foreach ($tmp as $item) { - $keywords[(string) $item["keyword"]] = $item["counter"]; - } - return $keywords; - } - - /** - * Build export file - */ - public function buildExportFile( - bool $a_include_comments = false, - bool $print_version = false - ): BlogHtmlExport { - $type = "html"; - $format = explode("_", $this->blog_request->getFormat()); - if (($format[1] ?? "") === "comments" || $a_include_comments) { - $a_include_comments = true; - $type = "html_comments"; - } - - // create export file - //ilExport::_createExportDirectory($this->object->getId(), $type, "blog"); - //$exp_dir = ilExport::_getExportDirectory($this->object->getId(), $type, "blog"); + // create export file + //ilExport::_createExportDirectory($this->object->getId(), $type, "blog"); + //$exp_dir = ilExport::_getExportDirectory($this->object->getId(), $type, "blog"); $subdir = $this->object->getType() . "_" . $this->object->getId(); if ($print_version) { $subdir .= "print"; } - $blog_export = new BlogHtmlExport($this, "", $subdir); + $blog_export = new BlogHtmlExport( + $this, + $this->id_type === self::REPOSITORY_NODE_ID, + "", + $subdir + ); $blog_export->setPrintVersion($print_version); $blog_export->includeComments($a_include_comments); $blog_export->exportHTML(); return $blog_export; } - public function getNotesSubId(): int - { - return $this->blpg; - } - public function disableNotes(bool $a_value = false): void + public function addPresentationHeaderAction(): void { - $this->disable_notes = $a_value; - } - - protected function addHeaderActionForCommand( - string $a_cmd - ): void { - $ilUser = $this->user; - $ilCtrl = $this->ctrl; - // preview? - if ($a_cmd === "preview" || $a_cmd === "previewFullscreen" || $this->prvm) { - // notification - if ($ilUser->getId() !== ANONYMOUS_USER_ID) { - if (!$this->prvm) { - $ilCtrl->setParameter($this, "prvm", "fsc"); - } - $this->insertHeaderAction($this->initHeaderAction(null, null, true)); - if (!$this->prvm) { - $ilCtrl->setParameter($this, "prvm", ""); - } - } - } else { - $this->addHeaderAction(); - } + $this->insertHeaderAction($this->initHeaderAction(null, null, true)); } protected function initHeaderAction( ?string $sub_type = null, ?int $sub_id = null, - bool $is_preview = false + bool $presenation = false ): ?ilObjectListGUI { - $ilUser = $this->user; - $ilCtrl = $this->ctrl; if (!$this->obj_id) { return null; } @@ -1970,83 +951,13 @@ protected function initHeaderAction( } $lg->enableComments(false); $lg->enableNotes(false); - - if ($is_preview) { - if ($this->blpg > 0) { - if (($this->object->getNotesStatus() && !$this->disable_notes)) { - $lg->enableComments(true); - } - $lg->enableNotes(true); - } - $lg->enableTags(false); - - if (ilNotification::hasNotification(ilNotification::TYPE_BLOG, $ilUser->getId(), $this->obj_id)) { - $ilCtrl->setParameter($this, "ntf", 1); - $link = $ilCtrl->getLinkTarget($this, "setNotification"); - $ilCtrl->setParameter($this, "ntf", ""); - if (ilNotification::hasOptOut($this->obj_id)) { - $lg->addCustomCommand($link, "blog_notification_toggle_off"); - } - - $lg->addHeaderIcon( - "not_icon", - ilUtil::getImagePath("object/notification_on.svg"), - $this->lng->txt("blog_notification_activated") - ); - } else { - $ilCtrl->setParameter($this, "ntf", 2); - $link = $ilCtrl->getLinkTarget($this, "setNotification"); - $ilCtrl->setParameter($this, "ntf", ""); - $lg->addCustomCommand($link, "blog_notification_toggle_on"); - - $lg->addHeaderIcon( - "not_icon", - ilUtil::getImagePath("object/notification_off.svg"), - $this->lng->txt("blog_notification_deactivated") - ); - } - - // #11758 - if ($this->perm->mayContribute()) { - $ilCtrl->setParameter($this, "prvm", ""); - - $ilCtrl->setParameter($this, "bmn", ""); - $ilCtrl->setParameter($this, "blpg", ""); - $link = $ilCtrl->getLinkTarget($this, ""); - $ilCtrl->setParameter($this, "blpg", $sub_id); - $ilCtrl->setParameter($this, "bmn", $this->month); - $lg->addCustomCommand($link, "blog_edit"); // #11868 - - if ($sub_id && $this->perm->mayEditPosting($sub_id)) { - $link = $ilCtrl->getLinkTargetByClass("ilblogpostinggui", "edit"); - $lg->addCustomCommand($link, "blog_edit_posting"); - } - - $ilCtrl->setParameter($this, "prvm", "fsc"); - } - - $ilCtrl->setParameter($this, "ntf", ""); + if (!$presenation) { + return $lg; } - - return $lg; - } - - protected function setNotification(): void - { - $ilUser = $this->user; - $ilCtrl = $this->ctrl; - - switch ($this->ntf) { - case 1: - ilNotification::setNotification(ilNotification::TYPE_BLOG, $ilUser->getId(), $this->obj_id, false); - break; - - case 2: - ilNotification::setNotification(ilNotification::TYPE_BLOG, $ilUser->getId(), $this->obj_id, true); - break; - } - - $ilCtrl->redirect($this, "preview"); + return $this->gui->navigation()->presentationHeader( + $this->object, + $this->perm, + )->get($lg, $this->blpg); } /** @@ -2067,7 +978,16 @@ public static function lookupSubObjectTitle( /** * Filter inactive items from items list */ - protected function filterInactivePostings(): void + public function checkPermissionBool( + string $perm, + string $cmd = "", + string $type = "", + ?int $ref_id = null + ): bool { + return parent::checkPermissionBool($perm, $cmd, $type, $ref_id); + } + + public function filterInactivePostings(): void { foreach ($this->items as $month => $postings) { foreach ($postings as $id => $item) { @@ -2126,212 +1046,15 @@ public function approve(): void $this->tpl->setOnScreenMessage('success', $this->lng->txt("settings_saved"), true); } - $this->ctrl->redirect($this, "render"); - } - - - // - // contributors - // - - public function contributors(): void - { - $ilTabs = $this->tabs; - $ilToolbar = $this->toolbar; - $ilCtrl = $this->ctrl; - $lng = $this->lng; - $tpl = $this->tpl; - - if (!$this->checkPermissionBool("write")) { - return; - } - - $ilTabs->activateTab("contributors"); - - $local_roles = $this->object->getAllLocalRoles($this->node_id); - - // add member - ilRepositorySearchGUI::fillAutoCompleteToolbar( - $this, - $ilToolbar, - array( - 'auto_complete_name' => $lng->txt('user'), - 'submit_name' => $lng->txt('add'), - 'add_search' => true, - 'add_from_container' => $this->node_id, - 'user_type' => $local_roles - ), - true + $this->ctrl->redirectByClass( + [ + ilObjBlogGUI::class, + EditingGUI::class, + ], + "" ); - - $other_roles = $this->object->getRolesWithContributeOrRedact($this->node_id); - if ($other_roles) { - $this->tpl->setOnScreenMessage('info', sprintf($lng->txt("blog_contribute_other_roles"), implode(", ", $other_roles))); - } - - $table = $this->gui->contributor()->contributorTableBuilder( - $this->object->getAllLocalRoles($this->node_id), - $this, - "contributors" - )->getTable(); - - if ($table->handleCommand()) { - return; - } - - $tpl->setContent($table->render()); } - /** - * Autocomplete submit - */ - public function addUserFromAutoComplete(): void - { - $lng = $this->lng; - - $user_login = $this->blog_request->getUserLogin(); - $user_type = $this->blog_request->getUserType(); - - if (trim($user_login) === '') { - $this->tpl->setOnScreenMessage('failure', $lng->txt('msg_no_search_string')); - $this->contributors(); - return; - } - $users = explode(',', $user_login); - - $user_ids = array(); - foreach ($users as $user) { - $user_id = ilObjUser::_lookupId($user); - - if (!$user_id) { - $this->tpl->setOnScreenMessage('failure', $lng->txt('user_not_known')); - $this->contributors(); - return; - } - - $user_ids[] = (int) $user_id; - } - - $this->addContributor($user_ids, $user_type); - } - - /** - * Centralized method to add contributors - */ - public function addContributor( - array $a_user_ids = array(), - ?string $a_user_type = null - ): void { - $ilCtrl = $this->ctrl; - $lng = $this->lng; - $rbacreview = $this->rbac_review; - $rbacadmin = $this->rbacadmin; - $a_user_type = (int) $a_user_type; - - if (!$this->checkPermissionBool("write")) { - return; - } - - if (!count($a_user_ids) || !$a_user_type) { - $this->tpl->setOnScreenMessage('failure', $lng->txt("no_checkbox")); - $this->contributors(); - return; - } - - // get contributor role - $local_roles = array_keys($this->object->getAllLocalRoles($this->node_id)); - if (!in_array($a_user_type, $local_roles)) { - $this->tpl->setOnScreenMessage('failure', $lng->txt("missing_perm")); - $this->contributors(); - return; - } - - foreach ($a_user_ids as $user_id) { - $user_id = (int) $user_id; - $a_user_type = (int) $a_user_type; - if (!$rbacreview->isAssigned($user_id, $a_user_type)) { - $rbacadmin->assignUser($a_user_type, $user_id); - } - } - - $this->tpl->setOnScreenMessage('success', $lng->txt("settings_saved"), true); - $ilCtrl->redirect($this, "contributors"); - } - - /** - * Used in ContributorTableBuilder - */ - public function confirmRemoveContributor(array $ids = []): void - { - if (empty($ids)) { - $ids = $this->blog_request->getIds(); - } - if (count($ids) === 0) { - $this->tpl->setOnScreenMessage('failure', $this->lng->txt("select_one"), true); - $this->ctrl->redirect($this, "contributors"); - } - - $confirm = new ilConfirmationGUI(); - $confirm->setHeaderText($this->lng->txt('blog_confirm_delete_contributors')); - $confirm->setFormAction($this->ctrl->getFormAction($this, 'removeContributor')); - $confirm->setConfirm($this->lng->txt('delete'), 'removeContributor'); - $confirm->setCancel($this->lng->txt('cancel'), 'contributors'); - - foreach ($ids as $user_id) { - $confirm->addItem( - 'id[]', - (string) $user_id, - $this->profile_gui->getNamePresentation($user_id, false, "", true) - ); - } - - $this->tpl->setContent($confirm->getHTML()); - } - - public function removeContributor(): void - { - $ilCtrl = $this->ctrl; - $lng = $this->lng; - $rbacadmin = $this->rbacadmin; - - $ids = $this->blog_request->getIds(); - - if (count($ids) === 0) { - $this->tpl->setOnScreenMessage('failure', $lng->txt("select_one"), true); - $ilCtrl->redirect($this, "contributors"); - } - - // get contributor role - $local_roles = array_keys($this->object->getAllLocalRoles($this->node_id)); - if (!$local_roles) { - $this->tpl->setOnScreenMessage('failure', $lng->txt("missing_perm")); - $this->contributors(); - return; - } - - foreach ($ids as $user_id) { - foreach ($local_roles as $role_id) { - $rbacadmin->deassignUser($role_id, $user_id); - } - } - - $this->tpl->setOnScreenMessage('success', $lng->txt("settings_saved"), true); - $this->ctrl->redirect($this, "contributors"); - } - - /** - * Used in ContributorTableBuilder - */ - public function addContributorContainerAction(array $ids = []): void - { - if (empty($ids)) { - $ids = $this->blog_request->getIds(); - } - - // This would typically add contributors from a container - // For now, redirecting back to contributors as this seems to be a placeholder action - $this->ctrl->redirect($this, "contributors"); - } public function deactivateAdmin(): void { diff --git a/components/ILIAS/Blog/classes/class.ilObjBlogListGUI.php b/components/ILIAS/Blog/classes/class.ilObjBlogListGUI.php index 6212950298f3..e34cf3507a32 100755 --- a/components/ILIAS/Blog/classes/class.ilObjBlogListGUI.php +++ b/components/ILIAS/Blog/classes/class.ilObjBlogListGUI.php @@ -27,6 +27,14 @@ class ilObjBlogListGUI extends ilObjectListGUI { private ?Modal $comment_modal = null; + protected \ILIAS\Blog\InternalService $blog_service; + + public function __construct(int $context = self::CONTEXT_REPOSITORY) + { + global $DIC; + parent::__construct($context); + $this->blog_service = $DIC->blog()->internal(); + } public function init(): void { @@ -69,12 +77,10 @@ public function insertCommand( string $cmd = "", string $onclick = "" ): void { - global $DIC; + $blog_service = $this->blog_service; $tpl = $this->ui->mainTemplate(); - $export_possible = $DIC->blog() - ->internal() - ->domain() + $export_possible = $blog_service->domain() ->export() ->isCommentsExportPossible($this->obj_id); if ($cmd === "export" @@ -141,4 +147,26 @@ public function getModalTemplate(): array return $modalt; } + public function getCommandLink(string $cmd): string + { + switch ($cmd) { + case "render": + $this->ctrl->setParameterByClass(ilObjBlogGUI::class, "ref_id", $this->ref_id); + return $this->ctrl->getLinkTargetByClass( + [ilObjBlogGUI::class, \ILIAS\Blog\Editing\EditingGUI::class], + "" + ); + break; + case "preview": + $this->ctrl->setParameterByClass(ilObjBlogGUI::class, "ref_id", $this->ref_id); + return $this->ctrl->getLinkTargetByClass( + [ilObjBlogGUI::class, \ILIAS\Blog\Presentation\PresentationGUI::class], + "" + ); + break; + } + return parent::getCommandLink($cmd); + } + + } diff --git a/components/ILIAS/BookingManager/BookingProcess/class.ProcessUtilGUI.php b/components/ILIAS/BookingManager/BookingProcess/class.ProcessUtilGUI.php index 584281ab09f1..3f24055f45a6 100755 --- a/components/ILIAS/BookingManager/BookingProcess/class.ProcessUtilGUI.php +++ b/components/ILIAS/BookingManager/BookingProcess/class.ProcessUtilGUI.php @@ -37,6 +37,8 @@ class ProcessUtilGUI protected InternalGUIService $gui; protected InternalDomainService $domain; protected object $parent_gui; + protected \ilLanguage $lng; + protected \ilGlobalTemplateInterface $tpl; public function __construct( InternalDomainService $domain_service, @@ -53,6 +55,8 @@ public function __construct( $this->ctrl = $this->gui->ctrl(); $this->request = $this->gui->standardRequest(); $this->objects_manager = $domain_service->objects($pool->getId()); + $this->lng = $domain_service->lng(); + $this->tpl = $this->gui->mainTemplate(); } // Back to parent @@ -72,6 +76,11 @@ public function back(): void return; } + if ($retCmd === 'render') { + $this->redirectToRender(); + return; + } + if ($retCmd !== "") { $this->ctrl->redirectByClass(get_class($this->parent_gui), $retCmd); } else { @@ -126,38 +135,50 @@ protected function checkPermission(string $a_perm) : void public function handleBookingSuccess( int $a_obj_id, string $post_info_cmd, - ?array $a_rsv_ids = null + ?array $a_rsv_ids = null, + ?string $message = null ): void { - $this->log->debug("handleBookingSuccess"); - $main_tpl = $this->gui->mainTemplate(); - $ctrl = $this->gui->ctrl(); - $lng = $this->domain->lng(); - $request = $this->gui->standardRequest(); - - $main_tpl->setOnScreenMessage('success', $lng->txt('book_reservation_confirmed'), true); + $this->log->debug('handleBookingSuccess'); + $this->tpl->setOnScreenMessage( + 'success', + $message ?: $this->lng->txt('book_reservation_confirmed'), + true + ); + + $this->redirectToReturnCmdIfAsynchronous(); + $this->redirectToBookingInformationIfAvailable($a_obj_id, $post_info_cmd, $a_rsv_ids); + $this->redirectToRender(); + } - // show post booking information? + public function redirectToBookingInformationIfAvailable(int $a_obj_id, string $post_info_cmd, ?array $a_rsv_ids = null): void + { $obj = new \ilBookingObject($a_obj_id); - $pfile = $this->objects_manager->getBookingInfoFilename($a_obj_id); - $ptext = $obj->getPostText(); - - if (trim($ptext) || $pfile) { - if (count($a_rsv_ids)) { - $ctrl->setParameter( - $this->parent_gui, - 'rsv_ids', - implode(";", $a_rsv_ids) - ); - } - $ctrl->redirect($this->parent_gui, $post_info_cmd); - } else { - if ($ctrl->isAsynch()) { - $this->gui->send(""); - } else { - $this->back(); - } + if (trim($obj->getPostText()) === '' && $this->objects_manager->getBookingInfoFilename($a_obj_id) === '') { + return; } + + $a_rsv_ids ??= []; + if ($a_rsv_ids !== []) { + $this->ctrl->setParameter($this->parent_gui, 'rsv_ids', implode(';', $a_rsv_ids)); + } + $this->ctrl->redirect($this->parent_gui, $post_info_cmd); + } + + private function redirectToReturnCmdIfAsynchronous(): void + { + if (!$this->ctrl->isAsynch()) { + return; + } + + $this->gui->send( + "" + ); + } + + private function redirectToRender(): void + { + $this->ctrl->saveParameterByClass(\ilObjBookingPoolGUI::class, 'ref_id'); + $this->ctrl->redirectByClass(\ilObjBookingPoolGUI::class, 'render'); } /** @@ -168,107 +189,205 @@ public function displayPostInfo( int $user_id, string $file_deliver_cmd ): void { - $this->log->debug("displayPostInfo"); - $main_tpl = $this->gui->mainTemplate(); - $ctrl = $this->gui->ctrl(); - $lng = $this->domain->lng(); - $id = $book_obj_id; - $request = $this->gui->standardRequest(); + $this->log->debug('displayPostInfo'); + $booking_ids = $this->request->getReservationIdsFromString(); - if (!$id) { + $objects_with_periods = $this->resolveObjectsWithPeriodsForPostInfo( + $book_obj_id, + $user_id, + $booking_ids + ); + + if ($objects_with_periods === []) { + $this->ctrl->redirect($this->parent_gui, 'back'); return; } - $rsv_ids = $request->getReservationIdsFromString(); + $booking_objects = []; + $booking_info_filenames = []; - $tmp = []; - if ($rsv_ids === [] && $request->getReservationId() !== '') { - $reservationIdParts = explode('_', $request->getReservationId()); + $objects_with_info = []; + foreach ($objects_with_periods as $object_id => $periods) { + $booking_objects[$object_id] = new \ilBookingObject($object_id); + $booking_info_filenames[$object_id] = trim($this->objects_manager->getBookingInfoFilename($object_id)); - $user_id = (int) ($reservationIdParts[1] ?? 0); - $from = (int) ($reservationIdParts[2] ?? 0); - - if ($from > time()) { - $to = (int) ($reservationIdParts[3] ?? 0); - $tmp["$from-" . ($to + 1)] = 1; + if ( + trim($booking_objects[$object_id]->getPostText()) === '' + && $booking_info_filenames[$object_id] === '' + ) { + continue; } - $rsv_ids = [0]; + + $objects_with_info[$object_id] = $periods; } - // placeholder + if ($objects_with_info === []) { + $this->ctrl->redirect($this->parent_gui, 'back'); + return; + } - $book_ids = \ilBookingReservation::getObjectReservationForUser($id, $user_id); - foreach ($book_ids as $book_id) { - if (in_array($book_id, $rsv_ids) || count($rsv_ids) === 0) { - $obj = new \ilBookingReservation($book_id); - $from = $obj->getFrom(); - $to = $obj->getTo(); - if ($from > time()) { - $tmp[$from . "-" . $to + 1] = $tmp[$from . "-" . $to + 1] ?? 0; - $tmp[$from . "-" . $to + 1]++; - } + $template = new \ilTemplate( + 'tpl.booking_reservation_post.html', + true, + true, + 'components/ILIAS/BookingManager/BookingProcess' + ); + $multiple_objects = count($objects_with_info) > 1; + $submit_url = $this->ctrl->getLinkTarget($this->parent_gui, 'back'); + + foreach ($objects_with_info as $object_id => $periods) { + $booking_object = $booking_objects[$object_id]; + $post_text = trim($booking_object->getPostText()); + + $template->setCurrentBlock('info_block'); + $title = $multiple_objects + ? sprintf($this->lng->txt('book_post_booking_information_for'), $booking_object->getTitle()) + : $this->lng->txt('book_post_booking_information'); + $template->setVariable('TITLE', $title); + + if ($post_text !== '') { + $post_text = str_replace( + ['[OBJECT]', '[PERIOD]'], + [$booking_object->getTitle(), implode('
', $periods)], + $post_text + ); + $template->setVariable('POST_TEXT', nl2br($post_text)); } + + if ($booking_info_filenames[$object_id] === '') { + $template->parseCurrentBlock(); + continue; + } + + $this->ctrl->setParameter($this->parent_gui, 'object_id', $object_id); + $url = $this->ctrl->getLinkTarget($this->parent_gui, $file_deliver_cmd); + $this->ctrl->clearParameterByClass($this->parent_gui::class, 'object_id'); + + $template->setCurrentBlock('download'); + $template->setVariable('DOWNLOAD', $this->lng->txt('download')); + $template->setVariable('URL_FILE', $url); + $template->setVariable('TXT_FILE', $booking_info_filenames[$object_id]); + $template->parseCurrentBlock(); + $template->setCurrentBlock('info_block'); + + $template->parseCurrentBlock(); } - $olddt = \ilDatePresentation::useRelativeDates(); - \ilDatePresentation::setUseRelativeDates(false); + $template->setCurrentBlock('submit'); + $template->setVariable('TXT_SUBMIT', $this->lng->txt('ok')); + $template->setVariable('URL_SUBMIT', $submit_url); + $template->parseCurrentBlock(); - $period = array(); - ksort($tmp); - foreach ($tmp as $time => $counter) { - $time = explode("-", $time); - $time = \ilDatePresentation::formatPeriod( - new \ilDateTime($time[0], IL_CAL_UNIX), - new \ilDateTime($time[1], IL_CAL_UNIX) - ); - if ($counter > 1) { - $time .= " (" . $counter . ")"; + $this->tpl->setContent($template->get()); + } + + /** + * @return array + */ + protected function resolveObjectsWithPeriodsForPostInfo( + int $book_obj_id, + int $user_id, + array $booking_ids + ): array { + if ($booking_ids !== []) { + return $this->resolvePeriodsFromReservationIds($booking_ids); + } + + if ($book_obj_id <= 0) { + return []; + } + + $period_slots = []; + if ($this->request->getReservationId() !== '') { + $reservation_id_parts = explode('_', $this->request->getReservationId()); + $user_id = (int) ($reservation_id_parts[1] ?? 0); + $from = (int) ($reservation_id_parts[2] ?? 0); + + if ($from > time()) { + $to = (int) ($reservation_id_parts[3] ?? 0); + $period_slots["$from-$to"] = 1; } - $period[] = $time; + $booking_ids = [0]; } - $book_id = array_shift($book_ids); - \ilDatePresentation::setUseRelativeDates($olddt); + $book_ids = \ilBookingReservation::getObjectReservationForUser($book_obj_id, $user_id); + foreach ($book_ids as $book_id) { + if (!in_array($book_id, $booking_ids, true) && $booking_ids !== []) { + continue; + } - /* - #23578 since Booking pool participants. - $obj = new ilBookingReservation($book_id); - if ($obj->getUserId() != $ilUser->getId()) - { - return; + $reservation = new \ilBookingReservation($book_id); + $from = $reservation->getFrom(); + $to = $reservation->getTo(); + if ($from > time()) { + $key = "$from-$to"; + $period_slots[$key] = ($period_slots[$key] ?? 0) + 1; + } } - */ - $obj = new \ilBookingObject($id); - $pfile = $this->objects_manager->getBookingInfoFilename($id); - $ptext = $obj->getPostText(); + return $period_slots === [] + ? [] + : [$book_obj_id => $this->formatPeriodSlots($period_slots)]; + } - $mytpl = new \ilTemplate('tpl.booking_reservation_post.html', true, true, 'components/ILIAS/BookingManager/BookingProcess'); - $mytpl->setVariable("TITLE", $lng->txt('book_post_booking_information')); + /** + * @param string[] $booking_ids + * @return array + */ + protected function resolvePeriodsFromReservationIds(array $booking_ids): array + { + $period_slots_by_object = []; - if ($ptext) { - // placeholder - $ptext = str_replace( - ["[OBJECT]", "[PERIOD]"], - [$obj->getTitle(), implode("
", $period)], - $ptext - ); + foreach ($booking_ids as $booking_id) { + $booking_id = (int) $booking_id; + if ($booking_id <= 0) { + continue; + } - $mytpl->setVariable("POST_TEXT", nl2br($ptext)); + $reservation = new \ilBookingReservation($booking_id); + $object_id = $reservation->getObjectId(); + $key = "{$reservation->getFrom()}-{$reservation->getTo()}"; + $period_slots_by_object[$object_id][$key] = ($period_slots_by_object[$object_id][$key] ?? 0) + 1; } - if ($pfile) { - $url = $ctrl->getLinkTarget($this->parent_gui, $file_deliver_cmd); + $objects_with_periods = []; + foreach ($period_slots_by_object as $object_id => $period_slots) { + $objects_with_periods[$object_id] = $this->formatPeriodSlots($period_slots); + } + + ksort($objects_with_periods); + + return $objects_with_periods; + } + + /** + * @param array $period_slots + * @return string[] + */ + protected function formatPeriodSlots(array $period_slots): array + { + $olddt = \ilDatePresentation::useRelativeDates(); + \ilDatePresentation::setUseRelativeDates(false); - $mytpl->setVariable("DOWNLOAD", $lng->txt('download')); - $mytpl->setVariable("URL_FILE", $url); - $mytpl->setVariable("TXT_FILE", $pfile); + $period = []; + ksort($period_slots); + foreach ($period_slots as $time => $counter) { + $time_parts = explode('-', $time); + $formatted = \ilDatePresentation::formatPeriod( + new \ilDateTime((int) $time_parts[0], IL_CAL_UNIX), + new \ilDateTime((int) $time_parts[1], IL_CAL_UNIX) + ); + + if ($counter > 1) { + $formatted .= " ($counter)"; + } + + $period[] = $formatted; } - $mytpl->setVariable("TXT_SUBMIT", $lng->txt('ok')); - $mytpl->setVariable("URL_SUBMIT", $ctrl->getLinkTarget($this->parent_gui, "back")); + \ilDatePresentation::setUseRelativeDates($olddt); - $main_tpl->setContent($mytpl->get()); + return $period; } /** diff --git a/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithScheduleGUI.php b/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithScheduleGUI.php index 79fe039b102f..696d42e5edc0 100755 --- a/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithScheduleGUI.php +++ b/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithScheduleGUI.php @@ -514,12 +514,13 @@ protected function bookAvailableItems(?int $recurrence = null, ?ilDateTime $unti $until, $message ); - if (count($booked) > 0) { - $this->util_gui->handleBookingSuccess($obj_id, "displayPostInfo", $booked); - } else { - $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed'), true); - $this->util_gui->back(); + if ($booked !== []) { + $this->util_gui->handleBookingSuccess($obj_id, 'displayPostInfo', $booked); + return; } + + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed'), true); + $this->util_gui->back(); } protected function getBookAvailableTarget( diff --git a/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithoutScheduleGUI.php b/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithoutScheduleGUI.php index 384cb89f4dbc..1922cdee8e80 100755 --- a/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithoutScheduleGUI.php +++ b/components/ILIAS/BookingManager/BookingProcess/class.ilBookingProcessWithoutScheduleGUI.php @@ -285,12 +285,12 @@ public function saveMultipleBookings(): void { $participants = $this->book_request->getParticipants(); $object_id = $this->book_request->getObjectId(); - if (count($participants) > 0 && $object_id > 0) { + if ($participants !== [] && $object_id > 0) { $this->book_obj_id = $object_id; } else { $this->util_gui->back(); } - $rsv_ids = array(); + $rsv_ids = []; foreach ($participants as $id) { if (!$this->access->canManageReservationForUser($this->pool->getRefId(), $id)) { $this->showNoPermission(); @@ -305,24 +305,29 @@ public function saveMultipleBookings(): void ); } - if (count($rsv_ids)) { - $this->tpl->setOnScreenMessage('success', "booking_multiple_succesfully"); - } else { - $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed_overbooked'), true); + if ($rsv_ids !== []) { + $this->util_gui->handleBookingSuccess( + $object_id, + 'displayPostInfo', + $rsv_ids, + $this->lng->txt('booking_multiple_succesfully') + ); + return; } + + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed_overbooked'), true); $this->util_gui->back(); } - // // Step 2: Confirmation // // Book object - either of type or specific - for given dates - public function confirmedBooking($message = ""): bool + public function confirmedBooking($message = ''): void { $success = false; - $rsv_ids = array(); + $rsv_ids = []; if ($this->book_obj_id > 0) { $object_id = $this->book_obj_id; @@ -349,12 +354,12 @@ public function confirmedBooking($message = ""): bool } if ($success) { - $this->util_gui->handleBookingSuccess($success, "displayPostInfo", $rsv_ids); - } else { - $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed'), true); - $this->ctrl->redirect($this, 'book'); + $this->util_gui->handleBookingSuccess($success, 'displayPostInfo', $rsv_ids); + return; } - return true; + + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('book_reservation_failed'), true); + $this->ctrl->redirect($this, 'book'); } public function displayPostInfo(): void diff --git a/components/ILIAS/BookingManager/BookingProcess/templates/default/tpl.booking_reservation_post.html b/components/ILIAS/BookingManager/BookingProcess/templates/default/tpl.booking_reservation_post.html index 53621b1bdba5..c54fee6730f1 100755 --- a/components/ILIAS/BookingManager/BookingProcess/templates/default/tpl.booking_reservation_post.html +++ b/components/ILIAS/BookingManager/BookingProcess/templates/default/tpl.booking_reservation_post.html @@ -1,3 +1,4 @@ +

{TITLE}

@@ -13,9 +14,10 @@

{TITLE}

- -
\ No newline at end of file +
+ + + + diff --git a/components/ILIAS/BookingManager/BookingService/class.ilBookingGatewayGUI.php b/components/ILIAS/BookingManager/BookingService/class.ilBookingGatewayGUI.php index c6ad0f1f3255..ee95ae9ed325 100755 --- a/components/ILIAS/BookingManager/BookingService/class.ilBookingGatewayGUI.php +++ b/components/ILIAS/BookingManager/BookingService/class.ilBookingGatewayGUI.php @@ -174,7 +174,11 @@ public function executeCommand(): void case "ilbookingreservationsgui": $this->showPoolSelector("ilbookingreservationsgui"); $this->setSubTabs("reservations"); - $res_gui = new ilBookingReservationsGUI($this->pool, $this->help, $this->obj_id); + $res_gui = new ilBookingReservationsGUI( + $this->pool, + $this->help, + ilObject::_lookupType($this->obj_id) !== 'crs' ? $this->obj_id : null + ); $this->ctrl->forwardCommand($res_gui); break; diff --git a/components/ILIAS/BookingManager/Objects/ObjectEvent.php b/components/ILIAS/BookingManager/Objects/ObjectEvent.php new file mode 100644 index 000000000000..f51b65947bf1 --- /dev/null +++ b/components/ILIAS/BookingManager/Objects/ObjectEvent.php @@ -0,0 +1,48 @@ +getId(); + } catch (ilObjectTypeMismatchException) { + continue; + } + + foreach (ilBookingObject::getList($pool_id) as $booking_object) { + $booking_object_id = $booking_object['booking_object_id'] ?? null; + if ($booking_object_id === null) { + continue; + } + + (new ilBookingObject($booking_object_id))->deleteReservationsAndCalEntries($booking_object_id); + } + } + } +} diff --git a/components/ILIAS/BookingManager/Objects/class.ilBookBookingInfoStakeholder.php b/components/ILIAS/BookingManager/Objects/class.ilBookBookingInfoStakeholder.php index 54413bf58529..bae67fbdfaf3 100755 --- a/components/ILIAS/BookingManager/Objects/class.ilBookBookingInfoStakeholder.php +++ b/components/ILIAS/BookingManager/Objects/class.ilBookBookingInfoStakeholder.php @@ -33,6 +33,11 @@ public function getOwnerOfNewResources(): int return $this->default_owner; } + public function getConsumerNameForPresentation(): string + { + return parent::getConsumerNameForPresentation() . '/BookingInfo'; + } + public function canBeAccessedByCurrentUser(ResourceIdentification $identification): bool { global $DIC; diff --git a/components/ILIAS/BookingManager/Objects/class.ilBookObjectInfoStakeholder.php b/components/ILIAS/BookingManager/Objects/class.ilBookObjectInfoStakeholder.php index bcc4b6fac7d3..3b4efb35302f 100755 --- a/components/ILIAS/BookingManager/Objects/class.ilBookObjectInfoStakeholder.php +++ b/components/ILIAS/BookingManager/Objects/class.ilBookObjectInfoStakeholder.php @@ -34,6 +34,11 @@ public function getOwnerOfNewResources(): int return $this->default_owner; } + public function getConsumerNameForPresentation(): string + { + return parent::getConsumerNameForPresentation() . '/ObjectInfo'; + } + public function canBeAccessedByCurrentUser(ResourceIdentification $identification): bool { global $DIC; diff --git a/components/ILIAS/BookingManager/Reservations/class.ilBookingReservationsGUI.php b/components/ILIAS/BookingManager/Reservations/class.ilBookingReservationsGUI.php index a633795ca9cb..adacb94570a2 100755 --- a/components/ILIAS/BookingManager/Reservations/class.ilBookingReservationsGUI.php +++ b/components/ILIAS/BookingManager/Reservations/class.ilBookingReservationsGUI.php @@ -40,7 +40,7 @@ class ilBookingReservationsGUI protected array $raw_post_data; protected StandardGUIRequest $book_request; protected ilBookingHelpAdapter $help; - protected int $context_obj_id; + protected ?int $context_obj_id; protected ilCtrl $ctrl; protected ilGlobalTemplateInterface $tpl; protected ilLanguage $lng; @@ -53,7 +53,7 @@ class ilBookingReservationsGUI protected int $booked_user; protected ilUIService $ui_service; - public function __construct(ilObjBookingPool $pool, ilBookingHelpAdapter $help, int $context_obj_id = 0) + public function __construct(ilObjBookingPool $pool, ilBookingHelpAdapter $help, ?int $context_obj_id = null) { global $DIC; @@ -202,7 +202,7 @@ public function log(): void $this->access->canManageAllReservations($this->ref_id) || $this->pool->hasPublicLog(), $this->ui_service->filter()->getData($bookings_table->getFilter()) ?? [], null, - $this->context_obj_id > 0 ? [$this->context_obj_id] : null + $this->context_obj_id !== null ? [$this->context_obj_id] : null ); $reservations_table->getExportMode() > 0 && $reservations_table->exportData($reservations_table->getExportMode(), true); } diff --git a/components/ILIAS/BookingManager/Service/class.InternalDomainService.php b/components/ILIAS/BookingManager/Service/class.InternalDomainService.php index 2b59b3ad4a11..ab2fb7defe18 100755 --- a/components/ILIAS/BookingManager/Service/class.InternalDomainService.php +++ b/components/ILIAS/BookingManager/Service/class.InternalDomainService.php @@ -20,6 +20,7 @@ namespace ILIAS\BookingManager; +use ILIAS\BookingManager\Objects\ObjectEvent; use ILIAS\DI\Container; use ILIAS\Repository\GlobalDICDomainServices; use ILIAS\BookingManager\BookingProcess\BookingProcessManager; @@ -128,6 +129,11 @@ public function userEvent(): UserEvent return self::$instances["user_event"] ??= new UserEvent($this); } + public function objectEvent(): ObjectEvent + { + return new ObjectEvent(); + } + public function bookingSettings(): SettingsManager { return self::$instances["settings"] ??= new SettingsManager( diff --git a/components/ILIAS/BookingManager/classes/class.ilBookingManagerAppEventListener.php b/components/ILIAS/BookingManager/classes/class.ilBookingManagerAppEventListener.php index de3c29c33729..39344fef5569 100644 --- a/components/ILIAS/BookingManager/classes/class.ilBookingManagerAppEventListener.php +++ b/components/ILIAS/BookingManager/classes/class.ilBookingManagerAppEventListener.php @@ -42,6 +42,14 @@ public static function handleEvent( break; } break; + case "components/ILIAS/ILIASObject": + switch ($a_event) { + case "toTrash": + case "delete": + $DIC->bookingManager()->internal()->domain()->objectEvent()->handleDeletion([$a_parameter["ref_id"]]); + break; + } + break; } } } diff --git a/components/ILIAS/BookingManager/module.xml b/components/ILIAS/BookingManager/module.xml index a5f775ba7db2..a981b186622d 100755 --- a/components/ILIAS/BookingManager/module.xml +++ b/components/ILIAS/BookingManager/module.xml @@ -5,7 +5,7 @@ cat crs @@ -17,6 +17,7 @@ + diff --git a/components/ILIAS/BookingManager/src/BookableItem/Table/Action/BookableItemTableBookAction.php b/components/ILIAS/BookingManager/src/BookableItem/Table/Action/BookableItemTableBookAction.php index c0ae73b87720..ca6a4468b19d 100644 --- a/components/ILIAS/BookingManager/src/BookableItem/Table/Action/BookableItemTableBookAction.php +++ b/components/ILIAS/BookingManager/src/BookableItem/Table/Action/BookableItemTableBookAction.php @@ -21,6 +21,8 @@ namespace ILIAS\BookingManager\BookableItem\Table\Action; use ilBookingObjectGUI; +use ilBookingProcessWithScheduleGUI; +use ilBookingProcessWithoutScheduleGUI; use ilBookingReservation; use ilCtrlInterface; use ilDatePresentation; @@ -43,8 +45,6 @@ use ilBookingObject; use ILIAS\BookingManager\BookingProcess\BookingProcessManager; use ilObjUser; -use DateTimeZone; -use DateTime; class BookableItemTableBookAction implements TableAction { @@ -290,6 +290,7 @@ public function onSubmit( $booked_total = 0; $unavailable = []; + $booking_ids = []; foreach ($data as $object_id => $section) { $message = $section['message'] ?? ''; @@ -318,6 +319,9 @@ public function onSubmit( if ($booked !== []) { $booked_total += count($booked); + foreach ($booked as $booking_id) { + $booking_ids[] = $booking_id; + } continue; } @@ -347,6 +351,15 @@ public function onSubmit( $this->lng->txt('book_reservation_confirmed'), true ); + + $booking_process_gui_class = $this->pool->getScheduleType() === ilObjBookingPool::TYPE_FIX_SCHEDULE + ? ilBookingProcessWithScheduleGUI::class + : ilBookingProcessWithoutScheduleGUI::class; + + $this->ctrl->setParameterByClass($booking_process_gui_class, 'rsv_ids', implode(';', array_unique($booking_ids))); + $this->ctrl->setParameterByClass($booking_process_gui_class, 'returnCmd', 'render'); + $this->ctrl->redirectByClass($booking_process_gui_class, 'displayPostInfo'); + return null; } $this->ctrl->redirectByClass(ilBookingObjectGUI::class, 'render'); diff --git a/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingTableActionsFactory.php b/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingTableActionsFactory.php index 44502a36de95..c3ba8b9cf3f6 100644 --- a/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingTableActionsFactory.php +++ b/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingTableActionsFactory.php @@ -23,6 +23,7 @@ use ilCtrlInterface; use ilGlobalTemplateInterface; use ILIAS\BookingManager\Access\AccessManager; +use ILIAS\BookingManager\Bookings\Table\Action\BookingsTableBookingInformationAction; use ILIAS\BookingManager\Bookings\Table\Action\BookingsTableCancelAction; use ILIAS\BookingManager\Bookings\Table\Action\BookingsTableDeleteAction; use ILIAS\BookingManager\Bookings\Table\Action\BookingsTableMailAction; @@ -44,6 +45,8 @@ class BookingTableActionsFactory implements TableActionsFactory public const string ACTION_MAIL = 'mail'; + public const string ACTION_BOOKING_INFORMATION = 'booking_information'; + public function __construct( protected readonly ilCtrlInterface $ctrl, protected readonly ilLanguage $lng, @@ -73,6 +76,7 @@ public function getTableActions(): TableActions self::ACTION_CANCEL => $this->getCancelAction(), self::ACTION_DELETE => $this->getDeleteAction(), self::ACTION_MAIL => $this->getMailAction(), + self::ACTION_BOOKING_INFORMATION => $this->getBookingInformationAction(), ] ); } @@ -124,4 +128,16 @@ protected function getMailAction(): BookingsTableMailAction $this->bookings ); } + + protected function getBookingInformationAction(): BookingsTableBookingInformationAction + { + return new BookingsTableBookingInformationAction( + $this->ui_factory, + $this->lng, + $this->http, + $this->tpl, + $this->ctrl, + $this->bookings + ); + } } diff --git a/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingsTableBookingInformationAction.php b/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingsTableBookingInformationAction.php new file mode 100644 index 000000000000..793cbecddfc0 --- /dev/null +++ b/components/ILIAS/BookingManager/src/Booking/Table/Action/BookingsTableBookingInformationAction.php @@ -0,0 +1,130 @@ +ui_factory->table()->action()->standard( + $this->lng->txt($this->getActionLabel()), + $url_builder + ->withParameter($action_token, $this->getActionId()) + ->withParameter($action_type_token, 'booking_information'), + $row_id_token + ); + } + + public function onExecute( + URLBuilder $url_builder, + URLBuilderToken $row_id_token, + URLBuilderToken $action_token, + URLBuilderToken $action_type_token + ): mixed { + $row_parameters = $this->http->resolveRowParameters($row_id_token->getName()); + if ($row_parameters === HttpService::ALL_OBJECTS) { + $selected_ids = null; + } elseif (is_string($row_parameters)) { + $selected_ids = [$row_parameters]; + } else { + $selected_ids = $row_parameters; + } + + $reservation_ids = $this->resolveRecords($selected_ids); + + if ($reservation_ids === []) { + $this->tpl->setOnScreenMessage( + ilGlobalTemplateInterface::MESSAGE_TYPE_FAILURE, + $this->lng->txt('no_valid_selection'), + true + ); + return null; + } + + $this->ctrl->setParameterByClass( + ilBookingReservationsGUI::class, + 'rsv_ids', + implode(';', $reservation_ids) + ); + $this->ctrl->redirectByClass(ilBookingReservationsGUI::class, 'displayPostInfo'); + return null; + } + + /** + * @return int[] + */ + protected function resolveRecords(?array $selected_ids = null): array + { + return array_map( + 'intval', + $selected_ids ?? array_keys($this->bookings) + ); + } +} diff --git a/components/ILIAS/COPage/Editor/Server/class.UIWrapper.php b/components/ILIAS/COPage/Editor/Server/class.UIWrapper.php index 2378e21ae1ec..3b9a9268f63d 100755 --- a/components/ILIAS/COPage/Editor/Server/class.UIWrapper.php +++ b/components/ILIAS/COPage/Editor/Server/class.UIWrapper.php @@ -248,8 +248,9 @@ public function getRenderedAdapterForm( } $html = $form->render(); $tag = "button"; + /* not necessary, since top buttons have been removed in general for forms $del_count = $in_modal ? 2 : 1; - $html = preg_replace("#\\<" . $tag . "([^>]*)btn-default(.*)/" . $tag . ">#iUs", "", $html, $del_count); + $html = preg_replace("#\\<" . $tag . "([^>]*)btn-default(.*)/" . $tag . ">#iUs", "", $html, $del_count);*/ $footer_pos = stripos($html, "il-standard-form-footer"); if (!is_int($footer_pos)) { $footer_pos = stripos($html, "c-form__footer"); diff --git a/components/ILIAS/COPage/Link/LinkManager.php b/components/ILIAS/COPage/Link/LinkManager.php index 45730995d62d..46daf805e495 100755 --- a/components/ILIAS/COPage/Link/LinkManager.php +++ b/components/ILIAS/COPage/Link/LinkManager.php @@ -248,7 +248,7 @@ public function moveIntLinks( ($area["Type"] ?? "") == "StructureObject") { $t = $area["Target"] ?? ""; $tid = \ilInternalLink::_extractObjIdOfTarget($t); - if ($a_from_to[$tid] > 0) { + if (($a_from_to[$tid] ?? 0) > 0) { $correction_needed = true; } } diff --git a/components/ILIAS/COPage/PC/Paragraph/class.ilPCParagraph.php b/components/ILIAS/COPage/PC/Paragraph/class.ilPCParagraph.php index 0bdc6aa230c5..d97d0541b79b 100755 --- a/components/ILIAS/COPage/PC/Paragraph/class.ilPCParagraph.php +++ b/components/ILIAS/COPage/PC/Paragraph/class.ilPCParagraph.php @@ -1076,6 +1076,9 @@ public static function xml2output( $rtype = ($target[count($target) - 2] ?? ""); $target_type = $rtype; } + if ($target_type === "") { + $target_type = "obj"; + } $a_text = preg_replace('~~i', "[iln " . $inst_str . "$target_type=\"" . $target_id . "\"" . $tframestr . "]", $a_text); break; @@ -1567,6 +1570,12 @@ public static function handleAjaxContent( */ public static function handleAjaxContentPost(string $text): string { + // #48126 + $text = str_replace( + ["<li/>"], + ["<li> </li>"], + $text + ); $text = str_replace( array("<ul>", "</ul>"), array("", ""), diff --git a/components/ILIAS/COPage/PC/Plugged/class.ilPCPlugged.php b/components/ILIAS/COPage/PC/Plugged/class.ilPCPlugged.php index eda6c95e3e42..222339732985 100755 --- a/components/ILIAS/COPage/PC/Plugged/class.ilPCPlugged.php +++ b/components/ILIAS/COPage/PC/Plugged/class.ilPCPlugged.php @@ -354,7 +354,7 @@ public function getJavascriptFiles(string $a_mode): array foreach ($this->component_factory->getActivePluginsInSlot("pgcp") as $plugin) { $plugin->setPageObj($this->getPage()); - $pl_dir = $plugin->getDirectory(); + $pl_dir = $plugin->getRelativeDirectory(); $pl_js_files = $plugin->getJavascriptFiles($a_mode); foreach ($pl_js_files as $pl_js_file) { @@ -376,7 +376,7 @@ public function getCssFiles(string $a_mode): array foreach ($this->component_factory->getActivePluginsInSlot("pgcp") as $plugin) { $plugin->setPageObj($this->getPage()); - $pl_dir = $plugin->getDirectory(); + $pl_dir = $plugin->getRelativeDirectory(); $pl_css_files = $plugin->getCssFiles($a_mode); foreach ($pl_css_files as $pl_css_file) { diff --git a/components/ILIAS/COPage/PC/Question/class.ilPCQuestionGUI.php b/components/ILIAS/COPage/PC/Question/class.ilPCQuestionGUI.php index 16d8755a5f9a..f78c49b27f54 100755 --- a/components/ILIAS/COPage/PC/Question/class.ilPCQuestionGUI.php +++ b/components/ILIAS/COPage/PC/Question/class.ilPCQuestionGUI.php @@ -206,7 +206,7 @@ public function create(): void { global $ilCtrl, $ilTabs; - $ilTabs->setTabActive('question'); + $ilTabs->setTabActive('edit_question'); $this->content_obj = new ilPCQuestion($this->getPage()); $this->content_obj->create($this->pg_obj, $this->hier_id); @@ -257,7 +257,7 @@ public function edit(): void $ilTabs = $this->tabs; $q_id = ""; - $ilTabs->setTabActive('question'); + $ilTabs->setTabActive('edit_question'); if ($this->getSelfAssessmentMode()) { // behaviour in content pages, e.g. scorm $q_ref = $this->content_obj->getQuestionReference(); @@ -384,7 +384,7 @@ public function setTabs(): void } $ilTabs->addTarget( - "question", + "edit_question", $ilCtrl->getLinkTarget($this, "edit"), array("editQuestion", "save", "cancel", "addSuggestedSolution", "cancelExplorer", "linkChilds", "removeSuggestedSolution", diff --git a/components/ILIAS/COPage/Page/class.PageCommandActionHandler.php b/components/ILIAS/COPage/Page/class.PageCommandActionHandler.php index 018d7fdc46a1..feb1801a63ca 100755 --- a/components/ILIAS/COPage/Page/class.PageCommandActionHandler.php +++ b/components/ILIAS/COPage/Page/class.PageCommandActionHandler.php @@ -184,7 +184,7 @@ protected function dragDropCommand(array $body): Server\Response $source = explode(":", $source); $target = explode(":", $target); - $updated = $page->moveContentAfter($source[0], $target[0], $source[1], $target[1]); + $updated = $page->moveContentAfter($source[0], $target[0], $source[1] ?? '', $target[1] ?? ''); return $this->sendPage($updated); } diff --git a/components/ILIAS/COPage/classes/class.ilPageObject.php b/components/ILIAS/COPage/classes/class.ilPageObject.php index 9bdd0fb89a41..3c9e94b76095 100755 --- a/components/ILIAS/COPage/classes/class.ilPageObject.php +++ b/components/ILIAS/COPage/classes/class.ilPageObject.php @@ -75,7 +75,7 @@ abstract class ilPageObject public string $xml = ""; public string $encoding = ""; public DomNode $node; - public string $cur_dtd = "ilias_pg_9.dtd"; + public string $cur_dtd = "ilias_pg_12.dtd"; public bool $contains_int_link = false; public bool $needs_parsing = false; public string $parent_type = ""; @@ -960,7 +960,7 @@ public function getLanguageVariablesXML(int $style_id = 0): string "table", "table_cell"] as $type) { $dummy_pc->getCharacteristicsOfCurrentStyle([$type]); foreach ($dummy_pc->getCharacteristics() as $char => $txt) { - $xml .= ""; + $xml .= $this->getCharacteristicLangVarXML($type, $char, $txt); } } $type = "media_cont"; @@ -968,14 +968,14 @@ public function getLanguageVariablesXML(int $style_id = 0): string $dummy_pc->setStyleId($style_id); $dummy_pc->getCharacteristicsOfCurrentStyle([$type]); foreach ($dummy_pc->getCharacteristics() as $char => $txt) { - $xml .= ""; + $xml .= $this->getCharacteristicLangVarXML($type, $char, $txt); } foreach (["text_block", "heading1", "heading2", "heading3"] as $type) { $dummy_pc = new ilPCParagraphGUI($this, null, ""); $dummy_pc->setStyleId($style_id); $dummy_pc->getCharacteristicsOfCurrentStyle([$type]); foreach ($dummy_pc->getCharacteristics() as $char => $txt) { - $xml .= ""; + $xml .= $this->getCharacteristicLangVarXML($type, $char, $txt); } } foreach ($lang_vars as $lang_var) { @@ -996,9 +996,18 @@ protected function getLangVarXML(string $var): string ); } + protected function getCharacteristicLangVarXML(string $type, string $char, string $txt): string + { + return $this->getLangVarXMLForValue( + "char_" . $type . "_" . $char, + $txt + ); + } + protected function getLangVarXMLForValue(string $var, string $val): string { - $val = str_replace('"', """, $val); + $var = htmlspecialchars($var, ENT_XML1 | ENT_QUOTES, 'UTF-8'); + $val = htmlspecialchars($val, ENT_XML1 | ENT_QUOTES, 'UTF-8'); return ""; } diff --git a/components/ILIAS/COPage/classes/class.ilPageObjectGUI.php b/components/ILIAS/COPage/classes/class.ilPageObjectGUI.php index e933fc001306..281d723f630e 100755 --- a/components/ILIAS/COPage/classes/class.ilPageObjectGUI.php +++ b/components/ILIAS/COPage/classes/class.ilPageObjectGUI.php @@ -913,7 +913,7 @@ public function executeCommand(): string break; case "ilquestioneditgui": - $this->setQEditTabs("question"); + $this->setQEditTabs("edit_question"); $edit_gui = new ilQuestionEditGUI(); $edit_gui->setPageConfig($this->getPageConfig()); $edit_gui->setSelfAssessmentEditingMode(true); @@ -930,6 +930,7 @@ public function executeCommand(): string // load required lang mods $this->lng->loadLanguageModule("assessment"); + $this->lng->loadLanguageModule('qsts'); // set context tabs $questionGUI = assQuestionGUI::_getQuestionGUI( @@ -991,7 +992,7 @@ public function setQEditTabs(string $a_active): void $this->ctrl->setParameterByClass("ilquestioneditgui", "q_id", $this->requested_q_id); $this->tabs_gui->addTab( - "question", + "edit_question", $this->lng->txt("question"), $this->ctrl->getLinkTargetByClass("ilquestioneditgui", "editQuestion") ); @@ -1706,7 +1707,8 @@ public function setEditMode(): void public function setDefaultLinkXml(): void { $this->page_linker->setProfileBackUrl($this->getProfileBackUrl()); - $this->page_linker->setOffline($this->getOutputMode() == self::OFFLINE); + // prevent to run into ctrl issues in copy background process + $this->page_linker->setOffline($this->getOutputMode() == self::OFFLINE || !ilContext::supportsRedirects()); $this->setLinkXml($this->page_linker->getLinkXML($this->getPageObject()->getInternalLinks())); } @@ -1723,7 +1725,8 @@ public function getProfileBackUrl(): string return $this->profile_back_url; } if ($this->getOutputMode() === self::OFFLINE || - $this->getOutputMode() === self::PRINTING) { + $this->getOutputMode() === self::PRINTING || + !ilContext::supportsRedirects()) { return ""; } return $this->ctrl->getLinkTargetByClass(strtolower(get_class($this)), "preview"); diff --git a/components/ILIAS/COPage/classes/class.ilQuestionExporter.php b/components/ILIAS/COPage/classes/class.ilQuestionExporter.php index ec9c2baf51b0..62c5505f4f2a 100755 --- a/components/ILIAS/COPage/classes/class.ilQuestionExporter.php +++ b/components/ILIAS/COPage/classes/class.ilQuestionExporter.php @@ -62,6 +62,7 @@ public function __construct(bool $a_preview_mode = false) $this->lng = $lng; $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $this->inst_id = IL_INST_ID; diff --git a/components/ILIAS/COPage/code_maintenance.json b/components/ILIAS/COPage/code_maintenance.json new file mode 100644 index 000000000000..d5f1f74400c3 --- /dev/null +++ b/components/ILIAS/COPage/code_maintenance.json @@ -0,0 +1,30 @@ +{ + "issues": [ + { + "title": "Static Method Declarations", + "desc": "The component declares > 100 static methods that reduce dependency management capabilities and testability. The goal is to reduce this number significantly.", + "min": "2000", + "max": "10000", + "funding": [ + { + "release": "12", + "amount": "2000", + "summary": "The number of static methods has been reduced to 70." + } + ] + }, + { + "title": "Large Classes", + "desc": "The component includes > 20 code classes with > 500 lines of code each. This usually violates single responsibility principles and makes the code harder to read and test. The goal is to reduce this number significantly.", + "min": "2000", + "max": "10000", + "funding": [ + { + "release": "12", + "amount": "3000", + "summary": "The number of large classes been reduced to 15." + } + ] + } + ] +} diff --git a/components/ILIAS/COPage/css/content_base.css b/components/ILIAS/COPage/css/content_base.css index ff752cb79828..26afe4c29ff3 100755 --- a/components/ILIAS/COPage/css/content_base.css +++ b/components/ILIAS/COPage/css/content_base.css @@ -22,8 +22,13 @@ white-space: normal; } .ilTinyMenuSection > div.dropdown:nth-child(1) > ul.dropdown-menu { - right:auto; - left:0; + right: auto; + left: 0; +} + +/* #47866 */ +.ilTinyMenuSection > div.dropdown:nth-child(4) > ul.dropdown-menu { + right: auto; } /* see #41844 and #46127 */ @@ -252,4 +257,4 @@ button.copg-add.dropdown-toggle.btn:focus-visible { .il-copg-mob-fullscreen { height: calc(90vh - 160px); -} \ No newline at end of file +} diff --git a/components/ILIAS/COPage/tests/COPageTestBase.php b/components/ILIAS/COPage/tests/COPageTestBase.php index 5374c397ec61..2fb339a2675c 100755 --- a/components/ILIAS/COPage/tests/COPageTestBase.php +++ b/components/ILIAS/COPage/tests/COPageTestBase.php @@ -130,6 +130,12 @@ protected function setUp(): void $refinery_mock ); + $ini_reader_mock = $this->createStub(ilIniFile::class); + $this->setGlobalVariable( + "ilIliasIniFile", + $ini_reader_mock + ); + $this->pc_cnt = 1; } diff --git a/components/ILIAS/COPage/tests/PageObjectTest.php b/components/ILIAS/COPage/tests/PageObjectTest.php index 4c3471bbea03..cb1fc82df12c 100755 --- a/components/ILIAS/COPage/tests/PageObjectTest.php +++ b/components/ILIAS/COPage/tests/PageObjectTest.php @@ -114,4 +114,31 @@ public function testGeneratePCId(): void strlen($id) ); } + + public function testGetLangVarXMLForValueEscapesXMLSpecialCharacters(): void + { + $page = new ilUnitTestPageObject(0); + + $this->assertSame( + '', + $page->getLangVarXMLForValueForTesting( + 'some&', + 'one & two \' three " four < five >' + ) + ); + } + + public function testGetCharacteristicLangVarXMLForValueEscapesXMLSpecialCharacters(): void + { + $page = new ilUnitTestPageObject(0); + + $this->assertSame( + '', + $page->getCharacteristicLangVarXMLForTesting( + 'text_block', + 'My&Class', + 'one & two \' three " four < five >' + ) + ); + } } diff --git a/components/ILIAS/COPage/tests/class.ilUnitTestPageObject.php b/components/ILIAS/COPage/tests/class.ilUnitTestPageObject.php index f6d95447a5f6..1b8c21219463 100755 --- a/components/ILIAS/COPage/tests/class.ilUnitTestPageObject.php +++ b/components/ILIAS/COPage/tests/class.ilUnitTestPageObject.php @@ -40,4 +40,14 @@ public function update(bool $a_validate = true, bool $a_no_history = false): arr { return true; } + + public function getLangVarXMLForValueForTesting(string $var, string $val): string + { + return $this->getLangVarXMLForValue($var, $val); + } + + public function getCharacteristicLangVarXMLForTesting(string $type, string $char, string $txt): string + { + return $this->getCharacteristicLangVarXML($type, $char, $txt); + } } diff --git a/components/ILIAS/COPage/xsl/page.xsl b/components/ILIAS/COPage/xsl/page.xsl index 5d368b5851b4..a65096ff4909 100755 --- a/components/ILIAS/COPage/xsl/page.xsl +++ b/components/ILIAS/COPage/xsl/page.xsl @@ -2543,6 +2543,27 @@ Comment to have separate iframe ending tag + + + + + + + + + + + + + + + attributes + + + Comment to have separate embed ending tag + + +
@@ -2737,27 +2758,6 @@
- - - - - - - - - - - - - - attributes - - - Comment to have separate embed ending tag - - - - {{{{{No Media Type}}}}} @@ -3721,6 +3721,13 @@ + + [[[LEGACY_ANSWER_FORM_TEXT_]]] + + + [[[ANSWER_FORM_]]] + + diff --git a/components/ILIAS/Calendar/classes/ConsultationHours/BookingTableGUI.php b/components/ILIAS/Calendar/classes/ConsultationHours/BookingTableGUI.php index 594321c5c83f..ff028eb872d0 100644 --- a/components/ILIAS/Calendar/classes/ConsultationHours/BookingTableGUI.php +++ b/components/ILIAS/Calendar/classes/ConsultationHours/BookingTableGUI.php @@ -207,15 +207,15 @@ protected function getColumns(): array 'booking_participant' => $this->ui_factory ->table() ->column() - ->linkListing($this->lng->txt('cal_ch_booking_participants')), + ->listing($this->lng->txt('cal_ch_booking_participants')), 'booking_comment' => $this->ui_factory ->table() ->column() - ->linkListing($this->lng->txt('cal_ch_booking_col_comments')), + ->listing($this->lng->txt('cal_ch_booking_col_comments')), 'booking_location' => $this->ui_factory ->table() ->column() - ->linkListing($this->lng->txt('cal_ch_target_object')) + ->listing($this->lng->txt('cal_ch_target_object')) ]; } diff --git a/components/ILIAS/Calendar/classes/class.ilCalendarUserSettings.php b/components/ILIAS/Calendar/classes/class.ilCalendarUserSettings.php index 21c4269d1fe8..b7cf132393c1 100755 --- a/components/ILIAS/Calendar/classes/class.ilCalendarUserSettings.php +++ b/components/ILIAS/Calendar/classes/class.ilCalendarUserSettings.php @@ -210,7 +210,7 @@ protected function read(): void { $this->timezone = (string) $this->user->getTimeZone(); $this->export_tz_type = (int) ( - ($this->user->getPref('export_tz_type') !== false) ? + ($this->user->getPref('export_tz_type') !== null) ? $this->user->getPref('export_tz_type') : $this->export_tz_type ); @@ -218,7 +218,7 @@ protected function read(): void $this->user->getDateFormat() ); $this->time_format = (int) $this->user->getTimeFormat(); - if (($weekstart = $this->user->getPref('weekstart')) === false) { + if (($weekstart = $this->user->getPref('weekstart')) === null) { $weekstart = $this->settings->getDefaultWeekStart(); } $this->calendar_selection_type = (int) $this->user->getPref('calendar_selection_type') ? diff --git a/components/ILIAS/Calendar/tests/ilCalendarRecurrenceCalculationTest.php b/components/ILIAS/Calendar/tests/ilCalendarRecurrenceCalculationTest.php index 4843f9a6e9cf..5c2d9d1934c0 100755 --- a/components/ILIAS/Calendar/tests/ilCalendarRecurrenceCalculationTest.php +++ b/components/ILIAS/Calendar/tests/ilCalendarRecurrenceCalculationTest.php @@ -298,18 +298,15 @@ protected function initDependencies(): void $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); - $this->setGlobalVariable('lng', $this->createMock(ilLanguage::class)); - $this->setGlobalVariable('ilErr', $this->createMock(ilErrorHandling::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); + $this->setGlobalVariable('lng', $this->createStub(ilLanguage::class)); + $this->setGlobalVariable('ilErr', $this->createStub(ilErrorHandling::class)); - $logger = $this->getMockBuilder(ilLogger::class) + $logger = $this->getStubBuilder(ilLogger::class) ->disableOriginalConstructor() - ->getMock(); + ->getStub(); - $logger_factory = $this->getMockBuilder(ilLoggerFactory::class) - ->disableOriginalConstructor() - ->onlyMethods(['getComponentLogger']) - ->getMock(); + $logger_factory = $this->createStub(ilLoggerFactory::class); $logger_factory->method('getComponentLogger')->willReturn($logger); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); } diff --git a/components/ILIAS/Category/Permission/CategoryCmdPermission.php b/components/ILIAS/Category/Permission/CategoryCmdPermission.php new file mode 100644 index 000000000000..fd08a2a9e766 --- /dev/null +++ b/components/ILIAS/Category/Permission/CategoryCmdPermission.php @@ -0,0 +1,169 @@ +hasCatCmdPerm($cmd, $node_id); + } + return false; + } + + protected function hasCatCmdPerm(string $cmd, int $node_id): bool + { + // administrate users + if (in_array($cmd, [ + "resetFilter", "applyFilter", "listUsers", "addUserAutoComplete", "performDeleteUsers", + "deleteUsers", "assignRoles", "assignSave" + ])) { + return $this->access->checkAccess("cat_administrate_users", "", $node_id); + } + + // write permission + if (in_array($cmd, [ + "editInfo", "updateInfo", "update" + ])) { + return $this->access->checkAccess("write", "", $node_id); + } + + // read permission + if (in_array($cmd, [ + "render", "view", "showTaxAsSideBlock", "hideTaxAsSideBlock" + ])) { + return $this->access->checkAccess("read", "", $node_id); + } + + // visible permission + if (in_array($cmd, [ + "infoScreen" + ])) { + return $this->access->checkAccess("visible", "", $node_id); + } + + + return false; + } + + public function getDefaultCommand(): string + { + if ($this->isClass(\ilObjCategoryGUI::class)) { + return "render"; + } + return ""; + } + + public function getRequestEntity(): ?CmdEntity + { + if ($this->isClass(\ilObjCategoryGUI::class)) { + return $this->cmdEntity( + self::CAT + ); + } + return null; + } + + public function getRequestNodeId(): int + { + return $this->request->getRefId(); + } + + public function isForwardPermitted( + string $from_class, + string $to_class + ): bool { + $node_id = $this->getRequestNodeId(); + if ($from_class === \ilObjCategoryGUI::class) { + + // write permission + if (in_array($to_class, [ + \ilRepositoryTrashGUI::class, + \ilContainerFilterAdminGUI::class, + \ilObjectContentStyleSettingsGUI::class, + \ilDidacticTemplateGUI::class, + \ilExportGUI::class, + \ilObjectTranslationGUI::class, + \ilTaxonomySettingsGUI::class, + \ilObjectMetaDataGUI::class, + \ilContainerNewsSettingsGUI::class, + ])) { + return $this->access->checkAccess("write", "", $node_id); + } + + // administration users + if (in_array($to_class, [ + \ilObjUserGUI::class, + \ilObjUserFolderGUI::class, + \ilUserTableGUI::class, + ])) { + return $this->access->checkAccess("cat_administrate_users", "", $node_id); + } + + // edit permission + if ($to_class === \ilPermissionGUI::class) { + return $this->access->checkAccess("edit_permission", "", $node_id); + } + + // read permission + // note on ilObjectCopyGUI: This class performs the copy permission checks and + // can act on multiple source ids + if ($to_class === \ilObjectCopyGUI::class) { + return $this->access->checkAccess("read", "", $node_id); + } + + // visible or read + if ($to_class === \ilCommonActionDispatcherGUI::class) { + return $this->access->checkAccess("visible", "", $node_id) || + $this->access->checkAccess("read", "", $node_id); + } + + // visible + if ($to_class === \ilInfoScreenGUI::class) { + return $this->access->checkAccess("visible", "", $node_id); + } + } + return false; + } + +} diff --git a/components/ILIAS/Category/Service/class.InternalGUIService.php b/components/ILIAS/Category/Service/class.InternalGUIService.php index 9f441dfe5e99..e550bdb848a1 100755 --- a/components/ILIAS/Category/Service/class.InternalGUIService.php +++ b/components/ILIAS/Category/Service/class.InternalGUIService.php @@ -23,6 +23,7 @@ use ILIAS\DI; use ILIAS\Repository; use ILIAS\Catgory\AssignRoleTableBuilder; +use ILIAS\Category\Permission\CategoryCmdPermission; /** * @author Alexander Killing @@ -69,4 +70,15 @@ public function assignedRoleTableBuilder( $parent_cmd ); } + + public function cmdPerm(): CategoryCmdPermission + { + return new CategoryCmdPermission( + $this->domain_service->lng(), + $this->domain_service->access(), + $this->ui()->mainTemplate(), + $this->ctrl(), + $this->standardRequest() + ); + } } diff --git a/components/ILIAS/Category/classes/class.StandardGUIRequest.php b/components/ILIAS/Category/classes/class.StandardGUIRequest.php index ca4fbccb264d..6ac38410bd7a 100755 --- a/components/ILIAS/Category/classes/class.StandardGUIRequest.php +++ b/components/ILIAS/Category/classes/class.StandardGUIRequest.php @@ -93,4 +93,9 @@ public function getTaxId(): int return $this->int("cat_tax_id"); } + public function getItemRefId(): int + { + return $this->int("item_ref_id"); + } + } diff --git a/components/ILIAS/Category/classes/class.ilObjCategoryGUI.php b/components/ILIAS/Category/classes/class.ilObjCategoryGUI.php index e8cbcab694dd..f6d19d89c6e2 100755 --- a/components/ILIAS/Category/classes/class.ilObjCategoryGUI.php +++ b/components/ILIAS/Category/classes/class.ilObjCategoryGUI.php @@ -40,6 +40,7 @@ class ilObjCategoryGUI extends ilContainerGUI implements \ILIAS\Taxonomy\Setting public const CONTAINER_SETTING_TAXBLOCK = "tax_sblock_"; protected \ILIAS\Category\InternalDomainService $cat_domain; protected \ILIAS\Category\InternalGUIService $cat_gui; + protected \ILIAS\Category\Permission\CategoryCmdPermission $cmd_perm; protected \ILIAS\Taxonomy\Service $taxonomy; protected ilNavigationHistory $nav_history; @@ -96,6 +97,7 @@ public function __construct( $this->taxonomy = $DIC->taxonomy(); $this->cat_gui = $DIC->category()->internal()->gui(); $this->cat_domain = $DIC->category()->internal()->domain(); + $this->cmd_perm = $DIC->category()->internal()->gui()->cmdPerm(); } public function executeCommand(): void @@ -113,7 +115,7 @@ public function executeCommand(): void case strtolower(ilRepositoryTrashGUI::class): $ru = new ilRepositoryTrashGUI($this); $this->ctrl->setReturn($this, 'trash'); - $this->ctrl->forwardCommand($ru); + $this->cmd_perm->forwardPermitted($this, $ru); break; case "ilobjusergui": @@ -134,7 +136,7 @@ public function executeCommand(): void ); } $this->gui_obj->setCreationMode($this->creation_mode); - $this->ctrl->forwardCommand($this->gui_obj); + $this->cmd_perm->forwardPermitted($this, $this->gui_obj); $ilTabs->clearTargets(); $ilTabs->setBackTarget($this->lng->txt('backto_lua'), $this->ctrl->getLinkTarget($this, 'listUsers')); @@ -152,7 +154,7 @@ public function executeCommand(): void ); $this->gui_obj->setUserOwnerId($this->cat_request->getRefId()); $this->gui_obj->setCreationMode($this->creation_mode); - $this->ctrl->forwardCommand($this->gui_obj); + $this->cmd_perm->forwardPermitted($this, $this->gui_obj); $ilTabs->clearTargets(); $ilTabs->setBackTarget($this->lng->txt('backto_lua'), $this->ctrl->getLinkTarget($this, 'listUsers')); @@ -176,10 +178,11 @@ public function executeCommand(): void $this->prepareOutput(); $this->tabs_gui->setTabActive('perm_settings'); $perm_gui = new ilPermissionGUI($this); - $this->ctrl->forwardCommand($perm_gui); + $this->cmd_perm->forwardPermitted($this, $perm_gui); break; case 'ilinfoscreengui': + $this->checkPermission("visible"); if ($this->info_screen_enabled) { $this->prepareOutput(); $this->infoScreen(); @@ -201,11 +204,10 @@ public function executeCommand(): void $cp = new ilObjectCopyGUI($this); $cp->setType('cat'); - $this->ctrl->forwardCommand($cp); + $this->cmd_perm->forwardPermitted($this, $cp); break; case "ilobjectcontentstylesettingsgui": - $this->checkPermission("write"); $this->setTitleAndDescription(); $this->showContainerPageTabs(); $settings_gui = $this->content_style_gui @@ -213,26 +215,26 @@ public function executeCommand(): void null, $this->object->getRefId() ); - $this->ctrl->forwardCommand($settings_gui); + $this->cmd_perm->forwardPermitted($this, $settings_gui); break; case 'ilusertablegui': $u_table = new ilUserTableGUI($this, "listUsers"); $u_table->initFilter(); $this->ctrl->setReturn($this, 'listUsers'); - $this->ctrl->forwardCommand($u_table); + $this->cmd_perm->forwardPermitted($this, $u_table); break; case "ilcommonactiondispatchergui": $this->prepareOutput(); $gui = ilCommonActionDispatcherGUI::getInstanceFromAjaxCall(); - $this->ctrl->forwardCommand($gui); + $this->cmd_perm->forwardPermitted($this, $gui); break; case 'ildidactictemplategui': $this->ctrl->setReturn($this, 'edit'); $did = new ilDidacticTemplateGUI($this, $this->getDidacticTemplateIdFromQuery()); - $this->ctrl->forwardCommand($did); + $this->cmd_perm->forwardPermitted($this, $did); break; case 'ilexportgui': @@ -240,7 +242,7 @@ public function executeCommand(): void $this->tabs_gui->setTabActive('export'); $exp = new ilExportGUI($this); $exp->addFormat('xml'); - $this->ctrl->forwardCommand($exp); + $this->cmd_perm->forwardPermitted($this, $exp); break; case strtolower(TranslationGUI::class): @@ -261,11 +263,11 @@ public function executeCommand(): void $this->refinery, $this->toolbar ); - $this->ctrl->forwardCommand($transgui); + $this->cmd_perm->forwardPermitted($this, $transgui); break; case strtolower(ilTaxonomySettingsGUI::class): - $this->checkPermissionBool("write"); + $this->checkPermission("write"); $this->prepareOutput(); $this->setEditTabs("taxonomy"); $tax_gui = $this->taxonomy->gui()->getSettingsGUI( @@ -274,14 +276,13 @@ public function executeCommand(): void true, $this ); - $this->ctrl->forwardCommand($tax_gui); + $this->cmd_perm->forwardPermitted($this, $tax_gui); break; case 'ilobjectmetadatagui': - $this->checkPermissionBool("write"); $this->prepareOutput(); $this->tabs_gui->activateTab('meta_data'); - $this->ctrl->forwardCommand($this->getObjectMetadataGUI()); + $this->cmd_perm->forwardPermitted($this, $this->getObjectMetadataGUI()); break; case "ilcontainernewssettingsgui": @@ -291,15 +292,14 @@ public function executeCommand(): void $this->tabs_gui->activateSubTab('obj_news_settings'); $news_set_gui = new ilContainerNewsSettingsGUI($this); $news_set_gui->setHideByDate(true); - $this->ctrl->forwardCommand($news_set_gui); + $this->cmd_perm->forwardPermitted($this, $news_set_gui); break; case 'ilcontainerfilteradmingui': - $this->checkPermissionBool("write"); $this->prepareOutput(); $this->setEditTabs($active_tab = "settings_filter"); $this->tabs_gui->activateTab('settings'); - $this->ctrl->forwardCommand(new ilContainerFilterAdminGUI($this)); + $this->cmd_perm->forwardPermitted($this, new ilContainerFilterAdminGUI($this)); break; default: @@ -332,6 +332,15 @@ public function executeCommand(): void } $cmd .= "Object"; $this->tabs_gui->activateTab("view_content"); // see #19868 + + if ($this->cmd_perm->classImplementsMethodDirectly(get_class($this), $cmd)) { + $cmd = $this->cmd_perm->getPermittedCommand(); + if ($cmd === "") { + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('permission_denied'), true); + self::_gotoRepositoryRoot(); + } + $cmd .= "Object"; + } $this->$cmd(); break; @@ -683,7 +692,7 @@ public function infoScreen(): string // forward the command if ($ilCtrl->getNextClass() === "ilinfoscreengui") { - $ilCtrl->forwardCommand($info); + $this->cmd_perm->forwardPermitted($this, $info); } else { return $ilCtrl->getHTML($info); } diff --git a/components/ILIAS/Certificate/tests/ilCertificateDateHelperTest.php b/components/ILIAS/Certificate/tests/ilCertificateDateHelperTest.php index d5a5e0396a95..fb967bb230ad 100644 --- a/components/ILIAS/Certificate/tests/ilCertificateDateHelperTest.php +++ b/components/ILIAS/Certificate/tests/ilCertificateDateHelperTest.php @@ -48,6 +48,7 @@ class_exists('ilDateTime'); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); $this->setGlobalVariable('lng', $this->getSystemLanguageMock()); $this->setGlobalVariable('ilUser', $this->getUserMock()); + $this->setGlobalVariable('ilIliasIniFile', $this->createMock(ilIniFile::class)); $this->current_time = time(); } diff --git a/components/ILIAS/Chatroom/PRIVACY.md b/components/ILIAS/Chatroom/PRIVACY.md new file mode 100644 index 000000000000..cdf243338811 --- /dev/null +++ b/components/ILIAS/Chatroom/PRIVACY.md @@ -0,0 +1,153 @@ +# Chatroom Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any +> missing or incorrect information via [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories).** + +## General Information + +The Chatroom component provides real-time text-based communication within ILIAS. It consists of +two interconnected parts: a PHP backend that manages room configuration, user connections, bans, +and message history via the ILIAS database, and a Node.js chat server that handles real-time +message delivery via WebSocket connections. The Node.js server also manages On-Screen Chat (OSC) +conversations, which enable direct messaging between users outside of chatroom objects. + +Several features affect the scope of personal data processing: + +- **Chat history**: When enabled per room (via the "Enable History" setting), session records are + created that log user connection and disconnection times. When disabled, no session records are + persisted. +- **Custom usernames**: When enabled per room, users may choose a display name different from their + real name. When disabled, the user's public name is used automatically. +- **On-Screen Chat (OSC)**: When enabled globally, direct conversations between users are stored in + separate database tables (`osc_conversation`, `osc_messages`, `osc_activity`). Users control + their participation via the `chat_osc_accept_msg` preference. +- **Message history display**: A per-room setting controls how many past messages are shown when a + user enters a room. +- **Periodic cleanup**: The Node.js server includes a timed process that deletes old chat messages, + OSC messages, OSC conversations, and OSC activity records based on a configured age threshold. + +## Integrated Components + +- The Chatroom component employs the following components, please consult the respective + PRIVACY.md files: + - [AccessControl](../../ILIAS/AccessControl/PRIVACY.md) – manages permissions for chatroom access, + moderation, and settings. + - User – resolves user names and profile information for display in the chat. The Chatroom + component listens to the User component's `deleteUser` event to clean up ban records. + - [Notifications](../../ILIAS/Notifications/PRIVACY.md) – delivers on-screen notifications for chat + invitations. + - ILIASObject – the Object service stores the account which created a chatroom object and + its timestamps. + - [InfoScreen](../../ILIAS/InfoScreen/PRIVACY.md) – provides the info screen tab for chatroom objects. + - OnScreenChat – manages direct messaging conversations between users. The Chatroom component + provides user settings for On-Screen Chat participation. + - [Export](../../ILIAS/Export/PRIVACY.md) – provides the export framework. Chatroom objects can be + exported as XML including message history. + - [Mail](../../ILIAS/Mail/PRIVACY.md) – used for sending chat invitation notifications via email. + +## Data being stored + +- **User ID of connected users**: When a user enters a chatroom, their **user ID** is stored in + the `chatroom_users` table together with the **room ID** and a **connection timestamp**. This + tracks which users are currently connected to which rooms. +- **User data of connected users**: A JSON object containing the user's **login name**, **user ID**, + and **profile picture visibility** preference is stored in the `userdata` column of the + `chatroom_users` table. This data is used to display connected users in the chat interface. +- **Session records**: When chat history is enabled for a room and a user disconnects, a session + record is written to the `chatroom_sessions` table containing the **user ID**, **user data** + (login name, user ID), **connection timestamp**, and **disconnection timestamp**. This enables + the history feature to reconstruct who was present during a conversation. +- **Message history**: Chat messages are stored in the `chatroom_history` table as JSON objects + containing the **sender's user ID**, the **sender's username**, the **message content**, and + a **timestamp**. Private messages additionally contain the **recipient's user ID** and + **username**. This persists the conversation for history viewing and export. +- **Ban records**: When a user is banned from a chatroom, the `chatroom_bans` table stores the + banned **user ID**, the **actor ID** (user who performed the ban), a **timestamp**, and an + optional **remark** text. This enforces and documents the ban. +- **On-Screen Chat conversations**: The `osc_conversation` table stores a **conversation ID**, + participant data (including **user IDs** and names as JSON), and a group flag. This enables + direct messaging between users. +- **On-Screen Chat messages**: The `osc_messages` table stores a **message ID**, **conversation + ID**, **sender user ID**, **message content**, and a **timestamp**. This persists direct messages. +- **On-Screen Chat activity**: The `osc_activity` table stores a **conversation ID**, **user ID**, + **timestamp**, and a **closed flag**. This tracks when users last interacted with a conversation. +- **User preference -- accept On-Screen Chat messages** (`chat_osc_accept_msg`): Stores whether + the user accepts direct messages from other users. Displayed on the user's Privacy Settings page. +- **User preference -- broadcast typing** (`chat_broadcast_typing`): Stores whether the user's + typing activity is broadcast to other participants in real time. Displayed on the user's + Privacy Settings page. +- **User preference -- browser notifications** (`chat_osc_browser_notifications`): Stores whether + the user receives browser notifications for On-Screen Chat messages. +- **User preference -- hide automatic messages** (`chat_hide_automsg_{room_id}`): Stores per room + whether the user has chosen to hide system-generated messages (join/leave notices). +- **User preference -- invitation notification mute timestamp** (`chatinv_nc_muted_until`): Stores + a timestamp indicating when the user last dismissed chat invitation notifications. + +## Data being presented + +- **Each user** can view: + - the list of currently connected users in a chatroom (username and profile picture). + - their own and other users' public chat messages, including sender username, message content, + and timestamp. + - private messages they have sent or received. + - their own On-Screen Chat conversations and messages (when OSC is enabled). +- **Each user** can view the chat history (when the "Enable History" setting is active for the + room), filtered by date range. The history shows message content and sender usernames. +- **Persons with the "moderate" permission** can additionally: + - view the list of banned users, including **login name**, **first name**, **last name**, + **ban timestamp**, and the **name of the person who performed the ban**. + - kick users from the chatroom. + - ban users from the chatroom. + - clear the entire message history of a room. +- **Persons with the "Write" permission** can: + - edit chatroom settings, including enabling or disabling chat history. + - access the export tab. +- Whether a user's profile picture is shown or an anonymous avatar depends on the + **profile picture visibility** setting chosen by the user upon entering the room (or + automatically set when custom usernames are disabled). +- Whether other users are visible for direct messaging depends on each user's + **`chat_osc_accept_msg`** preference. + +## Data being deleted + +- **When a user disconnects from a chatroom**: Their entry in `chatroom_users` is deleted. If chat + history is enabled, a session record is created in `chatroom_sessions` before deletion. +- **When a chatroom object is deleted from trash** by a person with appropriate permissions: All + related data is deleted, including: + - all user connection records from `chatroom_users` + - all message history from `chatroom_history` + - all ban records from `chatroom_bans` + - all session records from `chatroom_sessions` + - the room settings from `chatroom_settings` +- **When the message history is cleared** by a person with the "moderate" permission: All entries + in `chatroom_history` for that room are deleted. Session records in `chatroom_sessions` with a + disconnection time in the past are also deleted. +- **When a ban is lifted** by a person with the "moderate" permission: The ban record is deleted + from `chatroom_bans`. +- **When a user account is deleted**: The Chatroom component listens to the User component's + `deleteUser` event and deletes all ban records for that user from `chatroom_bans`. **Residual + data**: Other personal data referencing the deleted user may persist: + - Messages sent by the deleted user remain in `chatroom_history` with the original user ID + and username embedded in the JSON message body. + - Session records in `chatroom_sessions` may retain the deleted user's ID and username. + - If the deleted user was the actor who banned another user, the `actor_id` field in + `chatroom_bans` retains their user ID. + - On-Screen Chat data in `osc_conversation`, `osc_messages`, and `osc_activity` may retain + references to the deleted user's ID. +- **Periodic cleanup by the Node.js server**: Old chat messages in `chatroom_history`, OSC messages + in `osc_messages`, OSC conversations in `osc_conversation`, and OSC activity records in + `osc_activity` are deleted based on a configured age threshold. +- **User preferences** (`chat_osc_accept_msg`, `chat_broadcast_typing`, `chat_osc_browser_notifications`, + `chat_hide_automsg_*`, `chatinv_nc_muted_until`) are deleted when the user account is deleted, + as they are stored in the user preferences system. + +## Data being exported + +- Chatroom objects can be exported as XML via the ILIAS export framework. The export includes room + settings and the full message history. Message history entries contain the **message content** + (including sender username and user ID embedded in JSON) and **timestamps**. The export is + available to persons with the "Write" permission. +- The chat history can be exported as an HTML file for a selected date range by any user with the + "read" permission (when the "Enable History" setting is active). The HTML export contains + **sender usernames** and **message content**. +- There is no dedicated personal data export for individual users' chat participation records. diff --git a/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php b/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php index 1cabac44eaff..167582786681 100755 --- a/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php +++ b/components/ILIAS/Component/classes/Setup/class.ilComponentDefinitionsStoredObjective.php @@ -143,7 +143,6 @@ public function write(): void new \ilBadgeDefinitionProcessor($db), new \ilCOPageDefinitionProcessor($db), new \ilComponentInfoDefinitionProcessor(), - new \ilLoggingDefinitionProcessor($db), new \ILIAS\Cron\Setup\DefinitionProcessor( $db, $settings_factory->settingsFor(), diff --git a/components/ILIAS/Component/classes/class.ilPlugin.php b/components/ILIAS/Component/classes/class.ilPlugin.php index c44dc9c177f9..ccdd3b2424c8 100755 --- a/components/ILIAS/Component/classes/class.ilPlugin.php +++ b/components/ILIAS/Component/classes/class.ilPlugin.php @@ -123,10 +123,14 @@ public function getDirectory(): string public function getRelativeDirectory(): string { + $path = $this->getPluginInfo()->getPath(); + return str_replace( ILIAS_ABSOLUTE_PATH . "/public/", "", - realpath($this->getPluginInfo()->getPath()) + // realpath only resolves symlinks here, the path itself is already normalized. + // It returns false for a plugin which is not installed, keep the path in that case. + realpath($path) ?: $path ); } diff --git a/components/ILIAS/Component/classes/class.ilPluginInfo.php b/components/ILIAS/Component/classes/class.ilPluginInfo.php index 731e2a30c987..a00f929ab35b 100755 --- a/components/ILIAS/Component/classes/class.ilPluginInfo.php +++ b/components/ILIAS/Component/classes/class.ilPluginInfo.php @@ -111,13 +111,39 @@ public function getType(): string public function getPath(): string { - return implode('/', [ - ilComponentRepository::PLUGIN_BASE_PATH, - $this->getType(), - $this->getComponent()->getName(), - $this->getPluginSlot()->getName(), - $this->getName() - ]); + return $this->normalizePath( + implode('/', [ + ilComponentRepository::PLUGIN_BASE_PATH, + $this->getType(), + $this->getComponent()->getName(), + $this->getPluginSlot()->getName(), + $this->getName() + ]) + ); + } + + /** + * Resolves "." and ".." segments without touching the file system, so it also works + * for plugins which are not installed (yet). + * + * ilComponentRepository::PLUGIN_BASE_PATH is built from __DIR__ and therefore carries + * a "../../../.." which would otherwise end up in every path handed out to a plugin. + */ + protected function normalizePath(string $path): string + { + $segments = []; + foreach (explode('/', $path) as $segment) { + if ($segment === '' || $segment === '.') { + continue; + } + if ($segment === '..' && $segments !== [] && end($segments) !== '..') { + array_pop($segments); + continue; + } + $segments[] = $segment; + } + + return (str_starts_with($path, '/') ? '/' : '') . implode('/', $segments); } public function getClassName(): string diff --git a/components/ILIAS/Component/docs/component-bootstrap-migration.md b/components/ILIAS/Component/docs/component-bootstrap-migration.md new file mode 100644 index 000000000000..893c33388f5e --- /dev/null +++ b/components/ILIAS/Component/docs/component-bootstrap-migration.md @@ -0,0 +1,707 @@ +# How to migrate to the component bootstrap mechanism + +This document describes how an ILIAS component can be migrated from the legacy initialisation to the new component +bootstrap mechanism. Its purpose is to aid developers and +[authorities who sign off on code changes](../../../../docs/development/maintenance.md#authorities) who are tasked with +the migration of their component to this new mechanism, or want to introduce new ones while the "component revision" +big project is still ongoing. + +The described practises and required steps for a successful migration are put in two categories: one category is for +instructions, those are patterns, steps and practises which must be followed to the best of each individuals ability; +the other category is for recommendations, which should be considered by each individual but are shaped by personal +preference and might not be suitable for all components. + +More information about the component revision and the new repository- and component-structure can be found here: + +* [Repository- and component-structure](../../../../docs/development/components-and-directories.md) +* [Component Revision (Big Project)](https://docu.ilias.de/go/wiki/wpage_7295_1357) + +## Instructions + +This chapter holds instructions which must be followed to the best of each developers ability. + +### Starting point (and bad practices) + +The current state of most ILIAS components – former modules and services – is heavily reliant on the global dependency +injection container (known as `global $DIC`), which is used in any place at any time to service-locate something from +somewhere. What we are trying to say here is that most of the components do not yet fully embrace dependency injection +(DI) like its meant to be and therefore don't use it to its full potential. While the first part of the previous +sentence may be achieved more easily, the latter is still not fulfilled by the sheer implementation of injecting +something into something else. It needs to be refined in most cases; we must not simply inject entire subsystems of +ILIAS if we are only going to use a few aspects of it. DI needs careful consideration and the migration towards the +component bootstrap mechanism is the ideal time to reconsider how your objects and facilities are managed – internally +but also externally. + +```php +class InternalThingy +{ + // this is not real DI, we still need to service-locate: + public function __construct(\ILIAS\DI\Container $dic) + { + $this->dep1 = $dic->user(); + } +} +``` + +Having said that, in addition to the above ILIAS components its facilities are also initialised inside +`ilInitialisation` which belongs to the Init component. There are currently two main practises being used to initialise +a component as a whole: + +- The entire initialisation code is implemented inside the `ilInitialisation` class directly and is invoked at the right +time given the right circumstances (context and availability of dependencies). +- The initialisation code is implemented in a dedicated class, which receives the current dependency injection container +as an argument. The classes then initialise and expose stuff by defining it as an offset inside the container. + +Both practices end up in a similar result, where facilities which are required/used by other components are exposed +inside an instance of the `ILIAS\DI\Container` which is globally available. **We frequently observe that internal +facilities are also exposed inside the container, even though other components should not use it directly.** This has +already led to many locations where some specific offset of the container is accessed directly, without the +`ILIAS\DI\Container` offering a concrete method to fetch it (or its entry point). This is not properly encapsulated and +makes other components rely on internal implementation details, which may not be known or considered during a possible +refactoring. This is another thing which is best improved during the migration of a component. + +```php +public function init(\ILIAS\DI\Container $dic): void +{ + $dic['public.thingy'] = static fn () => new PublicThingy( + $dic['internal.thingy'], + ); + // this is still public, any component can access this offset: + $dic['internal.thingy'] = static fn () => new InternalThingy( + $dic->user() + ); +} +``` + +The way the initialisation is currently orchestrated, mainly because often times it is unclear what dependency is +available at what time, we have embraced a pattern which allows the lazy-loading of objects, where instances are not +created immediately, but are wrapped inside an anonymous function / arrow function / first class function and stored in +the `ILIAS\DI\Container` instead. This way, if an actual instance of a service is requested by accessing the offset, it +triggers sort of a chain reaction where the functions are invoked recursively because dependencies are also fetched from +the same container. This pattern is still used inside the new bootstrap mechanism for the same reason, while determining +the appropriate order of dependencies during build-time (amongst some other things). + +At this point you should have a vague (or clear if we did a good job here) picture about what patterns have been used, +which mostly avoid proper DI and expose more functionality than probably necessary during the initialisation of +components. You should also know where to find most of this code, so we have established your starting point. + +### New component wiring and proper encapsulation + +The component bootstrap mechanism offers a total of +[four different ways to wire components](../../../../docs/development/components-and-directories.md#types-of-dependencies-and-integration-strategies) +with one another. Please take a look at the linked document before starting your work on the migration of a component. +In the previous chapter we have explained how some components expose more functionality to the rest of the system than +probably necessary. These new initialisation and integration strategies offer a great way to properly encapsulate your +component from the rest of the system and define precise ways of interactions. + +```php +class SomeComponent implements Component +{ + // types of dependencies and integration strategies: + public function init( + array | \ArrayAccess &$define, + array | \ArrayAccess &$implement, + array | \ArrayAccess &$use, + array | \ArrayAccess &$contribute, + array | \ArrayAccess &$seek, + array | \ArrayAccess &$provide, + array | \ArrayAccess &$pull, + array | \ArrayAccess &$internal, + ) : void { + } +} +``` + +There are also a lot of classes where an exact instance of something is exposed globally. This may make sense for some +things, but there are a lot of things which could highly benefit from refactoring into subsystems. For this we recommend +to implement the facade pattern, for which in a first step one must extract an interface from the existing class, so we +can later on swap out its parts without breaking the consumers and migrate this gradually if need be. + +We also do not or rarely use namespaces. This was mostly due to the fact that `ilCtrl` did not support this, this has +been fixed in the meantime though. So, same goes here as well, now is the best time to embrace namespaces as well. + +### What needs to be touched? + +Since there are multiple places and components which need to be touched, especially if your component happens to utilise +a lot of other components which are unmigrated yet, it makes sense to iterate over the most common ones (abstract ones +but also concrete ones) in this chapter. + +- `\ilInitialisation` and optionally your wrapper (like `Init\Dependencies\InitHttpServices`): to take a look at your +initialisation and operate it out of its old place (and improve it!). +- Your component class (`.php`): to implement the initialisation using the new dependency types and +integration strategies. +- Other's component classes: there are two scenarios in which other components need to be touched as well. Its important +we do this, because if we simply move the initialisation code to the new system and solely rely on the compatibility +layer explained in the next chapter, we will break the whole system once we remove the layer when every component is +migrated. Scenarios: + - a) the other component is unmigrated and needs a compatibility layer for the new system + - b) the component being migrated was already touched during the migration of another and it contains a compatibility + layer already. Now you can amend the usage inside the other component and drop the layer if it was the only usage. + - c) there are scalar dependencies, like an object-id (as `int`) passed to the constructor. The new system does not + support such trivial wiring, it needs to be remodeled and put behind an abstraction layer. This layer potentially + needs implementation in another component than yours. The chapter on established patterns will tell you more about it. +- Your component entry points: because there is a new way of doing things, you will need to migrate your endpoints as +well. Since a few components already migrated, its very possible that this is already done. If not, check out the entry +points chapter for guidance. + +### Setting clear boundaries! + +That's not just important in real life, but also for this project and during a migration of an ILIAS component. If you +are migrating a component to the bootstrap mechanism, you will quickly notice how you depend on A which in turn depends +on B which yet again depends on C and D, who both depend on E, F and G – all of which are not migrated. If you would +migrate such a component and migrate all facilities of different components which are needed at some point in your +component, you would probably complete half the component revision for all of us. I mean, feel free to do so, we would +all highly appreciate this ofc, but in reality this will most likely not be possible =). + +For this reason its important to set clear boundaries. What components should be migrated at the same time highly +depends on the concrete scenario. Maybe you have been contracted to migrate all of your components, so the components of +yours depending on one another can probably be migrated in one go. However, lets assume for this chapter you are +migrating exactly one component and one component only. In this scenario, you will most likely run into some kind of +dependency on another part of the system. If this part is not yet migrated, we need to introduce a compatibility layer +so you can continue with your work and make the component compatible with the unmigrated part of the system. + +This is achieved by using the proxy pattern which hides the fact a component may not be migrated yet. It mimics the +behaviour of the facility in question, while it delegates all logic to the unmigrated implementation. This is important +because during the build process of ILIAS we need some bare-minimum implementation of some facility, so it can produce +the bootstrap artifact and dependency graph correctly. How this is achieved is explained in one of the following +chapters. + +### Contributing public assets + +During the first iteration of the component revision we have moved the publicly available assets into a dedicated folder +named `public/`. This is primarily done for security reasons but it also gives us a good grasp over what assets and +access to business logic is actually provided to the client (browser). + +This directory is managed by the Component ILIAS component and is (currently) rebuilt every time the application is +built. To contribute your assets to this directory you need to follow the code snippet below. It utilises the "seek" and +"contribute" integration strategy of the component wiring, where the responsible machinery seeks for implementations of +a given interface by looking for explicit contributions of it. + +```php +class SomeComponent implements Component +{ + public function init( + // ... + array | \ArrayAccess &$contribute, + // ... + ) : void { + // contribute a different public asset like so: + $contribute[Component\Resource\PublicAsset::class] = fn() => + new Component\Resource\ComponentJS($this, "js/SomeFunctionality.js"); + $contribute[Component\Resource\PublicAsset::class] = fn() => + new Component\Resource\ComponentCSS($this, "css/some-stylesheet.css"); + $contribute[Component\Resource\PublicAsset::class] = fn() => + new Component\Resource\NodeModule("@vendor/library/dist/index.js"); + } +} +``` + +Make sure your assets are in the right place; the machinery will look in `/resources/` for it. Inspect the +respective kind of asset implementation for a more detailed location. If you need to provide an endpoint (like +`ilias.php`), check out the corresponding chapter of this guide. + +### Backwards compatibility + +At this point it might have occurred to you, that we live in an entirely new and different world now, and asked +yourself how you make things available for the unmigrated part of the system. If that's not the case, don't worry, we +will explain it to you anyways. This chapter covers how we maintain backwards compatibility during the gradual +migration of ILIAS components during the progression of the "component revision" big project. + +As mentioned above, the bootstrap mechanism is something completely different than how we previously managed things. The +bootstrap mechanism creates an artifact during build-time, which contains a compiled script where all dependencies are +initialised in the appropriate order and fashion, while the types of dependencies and different integration strategies +are respected. This means, after migrating a component and removing its initialisation from `ilInitialisation`, calling +`ilInitialisation::initILIAS()` is no longer an option. + +Since we do not want to maintain a duplicate initialisation for the same component, only to provide it for migrated and +unmigrated components at the same time, we have introduced a legacy initialisation bridge. This is a structured way to +expose migrated components and its facilities inside the legacy environment. While this adds some overhead, it is the +appropriate tool for the job and exposes the true ugliness of the service locator in the first place. Here's what you +do: + +```php +// step 1: migrate your component and implement its initialisation: +class SomeComponent implements Component +{ + public function init( + array | \ArrayAccess &$define, + array | \ArrayAccess &$implement, + // ... + ) : void { + // stumble over some legacy thing which is required by unmigrated components: + $define[] = LegacyThingyInterface::class; + $implement[LegacyThingyInterface::class] = static fn() => new SomeLegacyThingy(); + } +} + +// step 2: find the \ILIAS\Init\AllModernComponents class and extend it: +class AllModernComponents implements EntryPoint +{ + // use DI to retrieve your implementation inside the bridge: + public function __construct( + protected LegacyThingyInterface $legacy_thingy, + ) { + } + + // the method you are looking for in order to 'bridge' them: + protected function populateComponentsInLegacyEnvironment(\Pimple\Container $DIC): void + { + // expose your implementation using its legacy offset: + $DIC['public.legacy_offset'] = fn() => $this->legacy_thingy; + } +} + +// step 3: create the wiring between the legacy initialisation and your component: +class Init implements Component +{ + public function init( + // ... + array | \ArrayAccess &$use, + array | \ArrayAccess &$contribute, + // ... + ) : void { + $contribute[Component\EntryPoint::class] = static fn() => + new AllModernComponents( + // inject your implementation into the bridge using DI: + $use[LegacyThingyInterface::class], + ); + } +} +``` + +Thats it. Obviously the list of components and the list of properties of the bridge above is already quite long and will +become very long in the end. But this actually shows us the unfiltered and complete list of dependencies which are used +throughout the system. + +### Combining old with new in endpoints + +Now for those of you who provide endpoints to the system, like the famous `ilias.php`, there is a new way to initialise +ILIAS and make your endpoint viable. + +There is a new interface called `\ILIAS\Component\EntryPoint`, which is used to define entry-points of the system. This +is important, because your endpoint should most likely interact with these things. While an endpoint is contributed to +the system using an `\ILIAS\Component\Resource\Endpoint` (public asset) class, your implementation is actually decoupled from all +this. It will be a 'standalone' PHP script, which needs to take care of the proper initialisation (if this is what you +need). We cannot use some fancy mechanic here, because the script is the starting point of the whole system. We cannot +inject stuff because its a simple PHP script which is responsible to kick-off the whole thing. Thats why in this chapter +we show you how to implement and contribute your endpoint and initialise ILIAS properly so the old unmigrated components +work amongst the new migrated components all the same. + +```php +class SomeComponent implements Component +{ + public function init( + // ... + array | \ArrayAccess &$contribute, + // ... + ) : void { + // contribute your endpoint to the system: + $contribute[Component\Resource\PublicAsset::class] = static fn() => + new Component\Resource\Endpoint($this, "endpoint.php"); + } +} +``` + +Make sure your endpoint is in the right place; ILIAS will look inside `/resources/` for it. Inside your +actual endpoint (the PHP script), you must implement the following lines if you want to initialise ILIAS: + +```php +// load composer's autoloader: +require_once __DIR__ . '/../vendor/composer/vendor/autoload.php'; +// include the artifact produced by the component bootstrap mechanism: +require_once __DIR__ . '/../artifacts/bootstrap_default.php'; +// enter the \ILIAS\Init\AllModernComponents entry point like so: +entry_point('ILIAS Legacy Initialisation Adapter'); + +// after this, our legacy service-locator should be ready: +/** @var $DIC \ILIAS\DI\Container */ +global $DIC; +// $DIC->ctrl()->callBaseClass(); +``` + +For someone who is interested in implementing their own entry-point, which e.g. does not fully initialise ILIAS or +performs entirely different actions, you can update the code above in a way, where `entry_point(...)` is provided with +the name returned by `ILIAS\Component\EntryPoint::getName()`. The function itself is loaded by the bootstrap artifact +and provides the way of entering one of the existing entry points of the system. + +### Newly established patterns + +The following patterns have emerged during the first migrations. The ones that need more than a sentence are described +in a dedicated sub-chapter below: + +- Backwards compatibility layer, explained by the previous chapter. +- Proxy pattern for unmigrated components, compatibility layer between migrated/unmigrated. +- Scalar dependencies put behind configuration interfaces, defined and used by the requiring system, implemented by the +providing system. +- Split read and write access to functionality on a programming level already (interfaces). + +The following are not patterns in the strict sense, but conventions you should follow nonetheless: + +- `static fn` vs `fn`: think about when to use which one, the smaller scope improves performance. +- Avoid anonymous classes. Introduce dedicated classes, even for the most trivial interface implementations, and don't +be lazy about it. There is currently one known exception where this is hard to avoid, see the caveat on the dependence +on artifacts below. +- Avoid constants. They are global state and we really don't want global state; use the configuration interfaces +described below instead. Be aware that this is the target state and not something every migration can fully achieve +today: a number of constants defined by `ilInitialisation` (`ILIAS_ABSOLUTE_PATH`, `ILIAS_DATA_DIR`, `CLIENT_ID`, …) +are currently still the only way to obtain these values during early bootstrap, before the services that would replace +them are wired. Do not introduce new ones, and replace the existing ones wherever the wiring already allows it. + +#### Proxy pattern for a compatibility layer + +Assume the following scenario for the code example below: + +- Component A is being migrated +- Component A has dependency on Component B (the B class) +- Component B is not migrated + +The procedure we currently established is the following: + +- Because we do not want to or have the capacity or authority to migrate the other component (B) we depend on, we set a +clear boundary here. We achieve this by looking into what is actually used by our component (A) and extract a new +interface from this (if there isn't one we should use instead). +- Assume the B class is not namespaced and abstracted in any way yet and lives within the `classes/` folder, we will +want to extract an interface, ideally with the required functionality only, from this class and implement it inside the +`src/` directory. The B class then implements this new interface, which allows us to create the proxy now. If there +already is a usable interface we can use, this step can be skipped ofc. +- The proxy is a bare-minimum implementation of this interface, which delegates all method calls directly to the actual +B class, which is retrieved by `global $DIC`. This works because the proxy does not require a constructor, which +makes it compatible with the build and bootstrap process without `$DIC`, while it is still functional in the web context +because its legacy implementation will be invoked at a later point which initialises the B class in this container. + + +```php +// ComponentB/classes/B.php: +class B +{ + public function functionality(): void + { + // ... + } +} + +// ComponentB/src/BInterface.php: +interface BInterface +{ + public function functionality(): void; +} + +// ComponentB/src/BLegacyProxy.php: +final class BLegacyProxy implements BInterface +{ + public function functionality(): void + { + // delegate actual call to the appropriate B class + global $DIC; + $DIC->B()->functionality(); + } +} + +// ComponentB/ComponentB.php +class ComponentB implements Component +{ + public function init( + array | \ArrayAccess &$define, + array | \ArrayAccess &$implement, + // ... + ) : void { + // define the abstraction, make it known to the system: + $define[] = BInterface::class; + // implement the abstraction using the legacy proxy, so other components can use it: + $implement[BInterface::class] = static fn() => new BLegacyProxy(); + } +} +``` + +```php +// ComponentA/ComponentA.php +class ComponentA implements Component +{ + public function init( + // ... + array | \ArrayAccess &$use, + // ... + array | \ArrayAccess &$internal, + ) : void { + // use the legacy proxy implementation here: + $internal[A::class] = static fn() => new A($use[BInterface::class]); + } +} +``` + +#### Abstraction of scalar data-types + +In some cases there will be dependencies to scalar data-types. For these cases we need an established pattern, which +will be covered in this chapter, because the new component bootstrap mechanism prefers to work with classes rather than +arbitrary offsets which hold an anonymous function returning some hardcoded value. + +While the primary target of this abstraction may be for scalar data-types, it can also +be applied to other scenarios, where a more complex object is passed along. When and when not to use this pattern may +differ across contexts, but as a rule of thumb this pattern should not be used for more complex things than data- +transfer-objects (DTO). There could be exceptions to this where some sort of builder pattern is applied to create a +service, but this should be very limited; we ought follow correctness on construction to the best of our ability. + +We currently address this problem by looking at it from a configuration perspective. In most cases, such scalar or +trivial object data-types are used during initialisation for configuring the behaviour of some implementation. A good +example for this are INI-values, which are set by system administrators. But these can also be currently hard-coded +values like the `UI\Component\Progress\AsyncRefreshInterval`, where this is still a configuration for which we currently +do not provide any interaction. + +This is a good time to think about coupling, especially because there is one caveat which needs to be considered here: +**Configuration values MUST NOT be accessed inside the constructor, ever**. The bootstrap mechanism will not be able to +build its artifact if your object depends on the implementation of something else, because the wiring does not exist at +this point. Therefore, we recommend to introduce dedicated configuration interfaces that will return exactly what is +needed by an appropriate getter – ideally without any arguments. Why is this actually a blessing in disguise? So glad +you ask, because this pattern will ultimately loosen the coupling between your component and another, by hiding the +mechanism which is ultimately used to retrieve the desired value. This will make it very easy to switch mechanism, +location or even underlying business logic in order to retrieve this value, without ever having to touch your component +again. This refactoring could even be tackled by someone else entirely, because you have just decoupled your component +so kindly. + +Let's say you have something like this inside your legacy initialisation: + +```php +// SomeComponent/src/SomeService.php: +class SomeService +{ + public function __construct( + protected readonly int $some_config_value, + ) { + } + + public function functionality(): void + { + $this->some_config_value; //... + } +} + +$some_config_value = 0; // possibly retrieved by $DIC as well though +$DIC['some_component.some_service'] = static fn($DIC) => new SomeService($some_config_value); +``` + +Then you would refactor it according to the pattern to the following structure: + +```php +// SomeComponent/src/SomeService.php: +class SomeService +{ + public function __construct( + protected SomeConfigInterface $some_config, + ) { + } + + public function functionality(): void + { + // notice how retrieval is deferred now, do not store in property please! + $this->some_config->getValue(); + } +} + +// SomeComponent/src/SomeConfigInterface.php: +interface SomeConfigInterface +{ + public function getValue(): int; +} + +// SomeComponent/SomeComponent.php: +class SomeComponent implements Component +{ + // types of dependencies and integration strategies: + public function init( + array | \ArrayAccess &$define, + // ... + array | \ArrayAccess &$use, + // ... + array | \ArrayAccess &$internal, + ) : void { + // define a new interface for your configuration and make it known to the system: + $define[] = SomeConfigInterface::class; + // use the implementation made by some other component for your config: + $internal[SomeService::class] = static fn() => new SomeService($use[SomeConfigInterface::class]); + } +} + +// OtherComponent/OtherComponent.php: +class OtherComponent implements Component +{ + // types of dependencies and integration strategies: + public function init( + // ... + array | \ArrayAccess &$implement, + // ... + ) : void { + // implement the defined interface of SomeComponent to provide its value: + $implement[SomeConfigInterface::class] = static fn() => new SomeConfig(); + } +} + +// OtherComponent/src/SomeConfig.php: +class SomeConfig implements SomeConfigInterface +{ + // ... +} +``` + +As you can see we make use of the "define", "implement" and "use" component wiring. We define an interface for the +configuration put over the scalar or trivial object data-types and use it for the initialisation. Then we search for an +appropriate component to implement this defined interface, which may be the same component ofc, and add its +implementation in the right place. + +**In many cases this will be a legacy-proxy as well, described in the previous chapter, who delegates the method call in +the web context to some method of `$DIC`.** + +#### Restricted access on a programming level + +According to the interface segregation principle, an object should only rely on methods it also really needs. In ILIAS +most of the time an entire service is simply injected with all of its functionality for free. This is a bad habit; as +already explained inside the chapter that gives an overview of the current situation, we should be more cautious when +implementing our DI. Doing proper DI can already limit the set of available methods and narrow the used +methods down to the actually used ones quite a bit. However, we noticed that many places could benefit from a +segregation of their methods that mutate stuff and methods that only return some calculated result. + +Doing so will allow us to restrict access to functionality on a programming level already. Assume we have the following +object without any abstraction: + +```php +class GodObjectThatDoesItAll +{ + public function setValueX(mixed $x): void + { + // ... + } + + public function getValueX(): mixed + { + // ... + } + // ... +} +``` + +We could introduce separate interfaces for our getters and setters here, or in a more abstract sense one for the +methods mutating state and another for the ones only reading it. The object could stay the same, we only need to +extract interfaces of the corresponding methods. The migration to the new component bootstrap mechanism is a great time +to think about this as well, especially if we need to introduce a new abstraction layer anyways, i.e. due to the need +of a legacy-proxy. + +```php +interface WriteActions +{ + public function setValueX(mixed $x): void; + // ... +} + +interface ReadActions +{ + public function getValueX(): mixed; + // ... +} + +class GodObjectThatDoesItAll implements WriteActions, ReadActions +{ + // ... +} +``` + +This also pairs well with the configuration pattern we have established as an abstraction layer put over the scalar and +trivial object data-types during initialisation. + +### Known caveats + +This chapter holds a list of known caveats which should ideally be updated anytime some new issue is discovered that +does not only concern one concrete component. These are things like missing concepts, patterns or issues with existing +ones from this document. + +- Migration of controllers: `ilCtrl` is very old-fashioned and is not yet migrated to the bootstrap mechanism itself. +This creates a problem for any component that offers functionality via GUI (the browser) and relies on the `ilCtrl` +for routing – which ofc are all. This means we need to find a viable solution for this fast, otherwise only components +formerly known as services will be able to migrate to this mechanism. This should also be a memento to the fact that we +need a more modern routing, which should be tackled by the progression of the +["static routing" big project](https://docu.ilias.de/go/wiki/wpage_8780_1357), which aims for a solution where routes +and corresponding logic are determined at build-time and stored in some kind of artifact, which should make it possible +to generate proper wiring between components and use proper DI as well. +- Context-specific logic: using the legacy initialisation it was possible to define very granularly in what context what +things should be initialised. With the new bootstrap mechanism this is a tiny bit more cumbersome, because we actually +don't differentiate between these contexts anymore. Everything is determined during build-time and different artifacts +are produced for different contexts instead. What the implications of this are is unknown at the moment. This is +probably something we need to analyse and discuss when first components that heavily rely on this mechanic are migrated. +- Dependence on artifacts: currently one needs to use `BuildArtifactObjective::PATH()` to get the path of an artifact +for its inclusion. We currently lack a facility which properly manages this stuff and can provide artifact paths / data +in a structured manner. This leads to potential anonymous classes or artifacts which cannot yet be properly injected. We +probably need to find a solution for this in early stages of this project too. +- Purged `public` directory: the current machinery which manages what assets will ultimately end up in our isolated web +root directory currently purges all files and moves contributed assets into the directory every time the application is +built. This makes it impractical for system administrators who need/want to provide additional assets to this directory, +like a `robots.txt` or if some other application potentially runs there (in a sub directory for example). We probably +want to create some sort of diff which we then compare in order to update only the changed files and basically not purge +the entire directory on every build. +- Contribute configuration screens: we currently lack a sophisticated concept or integration mechanism for components to +contribute configuration screen. A first step will be to migrate the main menu orchestrated by the GlobalScreen so these +entries can be collected inside the bootstrap mechanism and used by both ILIAS and third-party components. In the long +run we may want to improve this concept so dedicated routes/configurations/storage mechanisms can be contributed. +- Contribute translations: the Language component still relies on translation files inside the `./lang` directory. While +this mechanism still works for ILIAS components, third-party components will run into issues because they can no longer +contribute translations of their own. This will best be tackled by splitting up the translation files to their +respective components, so they can be contributed to the system using the appropriate tooling, which would also work for +third-party components. +- Refactorings initiated by single persons/institutions: there will be many use-cases where one person or institution +tackles a migration of some component or specific mechanism, where it will most likely be expected that usages inside +other components are amended. This will lead to a lot of cases where the best-practices described by this guideline will +become a huge overhead. We need to define how we should treat these cases and how the expected workload should be shared +between initiators and consumers of something. It could be that we have to establish special practises for individual +refactorings, all of which SHOULD be documented here to maintain an overview. + +### The process as a whole + +> **TODO:** this chapter has not been written yet. It is meant to describe how a migration works in terms of process, +> not in terms of actual implementation. We will provide a guide or a separate document about this in a later +> iteration. + +The questions it needs to answer: + +- who acquires funding? +- who is responsible for a concrete migration? +- who is responsible for all migrations (as an overview)? +- who is authoring the migration? +- who is reviewing the result of a migration (QA)? +- who needs to give approval and when? +- how should the result be published? + +## Recommendations + +This chapter contains recommendations which should be considered when migrating a component. These are shaped by +preference, but they still might add something valuable to your component as well. + +### Fully qualified domain names (FQDN) + +The larger a component initialisation becomes, the longer, wider and more cumbersome becomes the list of internal and +external facilities needed. The UI framework is a great example for this. In order for everybody to easily understand +and see what facilities are used in what locations, it is highly recommended to work with FQDNs only and access them +using the `::class` constant. This is great for two reasons: + +- we no longer need a `use` statement and prevent possible naming conflicts that would require aliased imports (`as`) +- we can always see directly from which exact location a facility is used and can tell whether its internal or external. + +### Consistency for discoverability + +Since it will become increasingly important to know what other ILIAS components offer what facilities, and even more +importantly what facilities are only defined but require 'external' implementation, its important to get a quick grasp +over the most important requirements each initialisation has to the system. Thats why it makes sense to streamline this +as good as possible, so this task which is repeated often, is made easy. Thats why it is recommended to follow the order +of parameters as listed by the `Component::init()` method when defining/exposing/setting its facilities into the +appropriate container to achieve its desired goal. + +## I don't understand this and/or need help + +If you feel like you don't fully understand any of the above aspects, or you do and have some constructive criticism +about it, or you simply need some help because there is an edge case or something else we haven't thought about +happening inside your component – contact us. + +Who are we you ask? While the brains behind the conceptual work and the first iteration of the component revision was +Richard Klees (from concepts and training gmbh), Thibeau Fuhrer and Fabian Schmid (from sr solutions ag) have taken over +his work and authorities of the Component ILIAS component, since he has left the ILIAS community. + +Feel free to contact us on Discord, via Email, or simply ping us on GitHub: + +- Thibeau Fuhrer +- Fabian Schmid diff --git a/components/ILIAS/Component/tests/Setup/ilComponentBuildPluginInfoObjectiveTest.php b/components/ILIAS/Component/tests/Setup/ilComponentBuildPluginInfoObjectiveTest.php index 796fc69ea884..1c5d86a2468d 100755 --- a/components/ILIAS/Component/tests/Setup/ilComponentBuildPluginInfoObjectiveTest.php +++ b/components/ILIAS/Component/tests/Setup/ilComponentBuildPluginInfoObjectiveTest.php @@ -139,14 +139,14 @@ public function testPluginsAdded(): void public function testScanDir(): void { // Use the component directory without artifacts, because this should be mostly stable. - $expected = ["Component.php", "PRIVACY.md", "README.md", "ROADMAP.md", "classes", "exceptions", "maintenance.json", "service.xml", "src", "tests"]; + $expected = ["Component.php", "PRIVACY.md", "README.md", "ROADMAP.md", "classes", "exceptions", "maintenance.json", "service.xml", "src", "tests", "docs"]; $actual = array_values( array_diff( $this->builder->_scanDir(__DIR__ . "/../.."), ["artifacts", ".DS_Store"] // .DS_Store is a macOS artifact which is not relevant for the test. ) ); - $this->assertEquals($expected, $actual); + $this->assertEqualsCanonicalizing($expected, $actual); } public function testIsDir(): void diff --git a/components/ILIAS/Component/tests/ilPluginInfoTest.php b/components/ILIAS/Component/tests/ilPluginInfoTest.php index 7a4a5606a0fd..eb403b059d97 100755 --- a/components/ILIAS/Component/tests/ilPluginInfoTest.php +++ b/components/ILIAS/Component/tests/ilPluginInfoTest.php @@ -251,11 +251,20 @@ public static function versionCompliance(): array public function testGetPath(): void { $this->assertEquals( - ilComponentRepository::PLUGIN_BASE_PATH . "/Type1/Module1/Slot1/Plugin1", + dirname(__DIR__, 4) . "/public/Customizing/global/plugins/Type1/Module1/Slot1/Plugin1", $this->plugin->getPath() ); } + /** + * ilComponentRepository::PLUGIN_BASE_PATH is built from __DIR__, the "../../../.." it + * carries must not show up in the path handed out to a plugin. See 0046652. + */ + public function testGetPathIsNormalized(): void + { + $this->assertStringNotContainsString('..', $this->plugin->getPath()); + } + public function testGetClassName(): void { $this->assertEquals( diff --git a/components/ILIAS/Container/Content/ObjectiveView/class.ilContainerObjectiveGUI.php b/components/ILIAS/Container/Content/ObjectiveView/class.ilContainerObjectiveGUI.php index 311e6fad7a19..70cb1bed03b6 100755 --- a/components/ILIAS/Container/Content/ObjectiveView/class.ilContainerObjectiveGUI.php +++ b/components/ILIAS/Container/Content/ObjectiveView/class.ilContainerObjectiveGUI.php @@ -474,77 +474,7 @@ protected function buildObjectiveMap(): array */ protected function addItemDetails(ilObjectListGUI $a_item_list_gui, array $a_item): void { - $lng = $this->lng; - $ilCtrl = $this->ctrl; $ilUser = $this->user; - $item_ref_id = $a_item["ref_id"]; - if (is_array($this->objective_map)) { - $details = []; - if (isset($this->objective_map["material"][$item_ref_id])) { - // #12965 - foreach ($this->objective_map["material"][$item_ref_id] as $objective_id) { - $ilCtrl->setParameterByClass('ilcourseobjectivesgui', 'objective_id', $objective_id); - $url = $ilCtrl->getLinkTargetByClass(['illoeditorgui', 'ilcourseobjectivesgui'], 'edit'); - $ilCtrl->setParameterByClass('ilcourseobjectivesgui', 'objective_id', ''); - - $details[] = [ - 'desc' => $lng->txt('crs_loc_tab_materials') . ': ', - 'target' => '_top', - 'link' => $url, - 'name' => $this->objective_map["names"][$objective_id] - ]; - } - } - if (($this->objective_map["test_i"] ?? 0) == $item_ref_id) { - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 1); - $details[] = [ - 'desc' => '', - 'target' => '_top', - 'link' => $ilCtrl->getLinkTargetByClass('illoeditorgui', 'testOverview'), - 'name' => $lng->txt('crs_loc_tab_itest') - ]; - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 0); - } - if (($this->objective_map["test_q"] ?? 0) == $item_ref_id) { - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 2); - $details[] = [ - 'desc' => '', - 'target' => '_top', - 'link' => $ilCtrl->getLinkTargetByClass('illoeditorgui', 'testOverview'), - 'name' => $lng->txt('crs_loc_tab_qtest') - ]; - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 0); - } - - // #15367 - if (is_array($this->objective_map["test_ass"][$item_ref_id] ?? false)) { - foreach ($this->objective_map["test_ass"][$item_ref_id] as $type => $items) { - if ($type == ilLOSettings::TYPE_TEST_INITIAL) { - $caption = $lng->txt('crs_loc_tab_itest'); - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 1); - } else { - $caption = $lng->txt('crs_loc_tab_qtest'); - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 2); - } - foreach ($items as $objtv_title) { - $details[] = [ - 'desc' => '', - 'target' => '_top', - 'link' => $ilCtrl->getLinkTargetByClass('illoeditorgui', 'testsOverview'), - 'name' => $caption . " (" . $this->lng->txt("crs_loc_learning_objective") . ": " . $objtv_title . ")" - ]; - } - $ilCtrl->setParameterByClass('illoeditorgui', 'tt', 0); - } - } - - if (count($details)) { - $a_item_list_gui->enableItemDetailLinks(true); - $a_item_list_gui->setItemDetailLinks($details, $lng->txt('crs_loc_settings_tbl') . ': '); - } else { - $a_item_list_gui->enableItemDetailLinks(false); - } - } // order if ($this->getContainerGUI()->isActiveOrdering()) { diff --git a/components/ILIAS/Container/MemberView/class.ilMemberViewSettings.php b/components/ILIAS/Container/MemberView/class.ilMemberViewSettings.php index 56c95c9b71ae..d978ca4ebc74 100755 --- a/components/ILIAS/Container/MemberView/class.ilMemberViewSettings.php +++ b/components/ILIAS/Container/MemberView/class.ilMemberViewSettings.php @@ -180,15 +180,6 @@ protected function read(): void $this->active = true; $this->container = (int) ilSession::get(self::SESSION_MEMBER_VIEW_CONTAINER); $this->container_items = $this->tree->getSubTreeIds($this->getContainer()); - - // deactivate if out of scope - if ( - $this->getCurrentRefId() && - !in_array($this->getCurrentRefId(), $this->container_items) && - $this->getCurrentRefId() !== $this->getContainer() - ) { - $this->deactivate(); - } } } diff --git a/components/ILIAS/Container/Page/class.ilContainerPageConfig.php b/components/ILIAS/Container/Page/class.ilContainerPageConfig.php index a66c96abc490..9992d2f49097 100755 --- a/components/ILIAS/Container/Page/class.ilContainerPageConfig.php +++ b/components/ILIAS/Container/Page/class.ilContainerPageConfig.php @@ -36,7 +36,9 @@ public function init(): void $this->setEnableInternalLinks(true); $this->setIntLinkHelpDefaultType("RepositoryItem"); $this->setEnablePCType("FileList", false); - $this->setEnablePCType("Map", true); + if (ilMapUtil::isActivated()) { + $this->setEnablePCType("Map", true); + } $this->setEnablePCType("Resources", true); $this->setMultiLangSupport(true); $this->setSinglePageMode(true); diff --git a/components/ILIAS/Container/classes/class.ilContainerGUI.php b/components/ILIAS/Container/classes/class.ilContainerGUI.php index c586c22e00dd..dd5555cdb029 100755 --- a/components/ILIAS/Container/classes/class.ilContainerGUI.php +++ b/components/ILIAS/Container/classes/class.ilContainerGUI.php @@ -180,6 +180,14 @@ public function executeCommand(): void } } + protected function checkTrashAccess() + { + if (!in_array('ilAdministrationGUI', $this->ctrl->getCurrentClassPath())) { + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('msg_no_perm_read'), true); + parent::_gotoRepositoryRoot(); + } + } + protected function getEditFormValues(): array { $values = parent::getEditFormValues(); @@ -2532,6 +2540,7 @@ protected function saveSortingSettings(ilPropertyFormGUI $form): void */ public function trashObject(): void { + $this->checkTrashAccess(); $this->checkPermission("write"); $tpl = $this->tpl; @@ -2552,16 +2561,19 @@ public function trashObject(): void public function trashApplyFilterObject(): void { + $this->checkTrashAccess(); $this->trashHandleFilter(true, false); } public function trashResetFilterObject(): void { + $this->checkTrashAccess(); $this->trashHandleFilter(false, true); } protected function trashHandleFilter(bool $action_apply, bool $action_reset): void { + $this->checkTrashAccess(); $trash_table = new ilTrashTableGUI($this, 'trash', $this->object->getRefId()); $trash_table->init(); $trash_table->resetOffset(); @@ -2584,6 +2596,7 @@ public function removeFromSystemObject(): void protected function restoreToNewLocationObject(?ilPropertyFormGUI $form = null): void { + $this->checkTrashAccess(); $this->tabs_gui->activateTab('trash'); $ru = new ilRepositoryTrashGUI($this); @@ -2595,6 +2608,7 @@ protected function restoreToNewLocationObject(?ilPropertyFormGUI $form = null): */ public function undeleteObject(): void { + $this->checkTrashAccess(); $ru = new ilRepositoryTrashGUI($this); $ru->restoreObjects( $this->requested_ref_id, @@ -2605,6 +2619,7 @@ public function undeleteObject(): void public function confirmRemoveFromSystemObject(): void { + $this->checkTrashAccess(); $lng = $this->lng; $this->checkPermission("write"); if (count($this->std_request->getTrashIds()) == 0) { diff --git a/components/ILIAS/ContentPage/PRIVACY.md b/components/ILIAS/ContentPage/PRIVACY.md new file mode 100644 index 000000000000..cf9b1c0cb1ef --- /dev/null +++ b/components/ILIAS/ContentPage/PRIVACY.md @@ -0,0 +1,107 @@ +# Content Page Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories).** + + +## General Information + +The Content Page component provides a standalone content page object for use in the +repository. It allows the creation of rich-text content pages using the ILIAS page editor (COPage). +Content Pages can be placed in categories, courses, groups, and folders. + +The Content Page component itself does not store personal data. Its two database tables +(`content_page_data` and `content_page_metrics`) contain only object-level configuration +(stylesheet reference) and computed page metrics (estimated reading time per language), neither of +which includes user IDs or other personal data. All personal data handling – including learning +progress tracking, page edit history, notes, and metadata authorship – is delegated to the +respective integrated components listed below. + +A global administration setting controls whether the estimated **reading time** is displayed to +users in repository listings. This setting does not affect personal data, as reading time is a +property of the page content, not of individual users. + +## Integrated Components + +- The Content Page component employs the following components, please consult the respective + PRIVACY.md files: + - [COPage](../../ILIAS/COPage/PRIVACY.md) — provides the page editor and page rendering engine. The + COPage component manages the page content, its edit history, and internal media objects. + - [MetaData](../../ILIAS/MetaData/PRIVACY.md) — stores metadata (e.g., author information) associated + with the Content Page object. + - [AccessControl](../../ILIAS/AccessControl/PRIVACY.md) — manages permissions for reading, editing, and + administering Content Page objects. + - [Export](../../ILIAS/Export/PRIVACY.md) — provides the XML export functionality for Content Page + objects, including page content, metadata, and styles. + - [InfoScreen](../../ILIAS/InfoScreen/PRIVACY.md) — renders the Info tab, which may display metadata + and allows private notes. The Info tab can be enabled or disabled per Content Page. + - [Notes](../../ILIAS/Notes/PRIVACY.md) — enables private notes for users on the Content Page Info + screen. + - [KioskMode](../../ILIAS/KioskMode/PRIVACY.md) — provides an embedded presentation mode used when a + Content Page is viewed inside a course or learning sequence context. + - [Style](../../ILIAS/Style/Content/PRIVACY.md) — manages content styles applied to the Content Page. No personal data is handled by + the Style component in this context. + - ILIASObject — the Object service stores the account which created the Content Page object + and its timestamps. + - Tracking — tracks user progress on Content Page objects. Supports three modes: + deactivated, manual completion, and content visited. In manual mode, users can toggle their + completion status. In content-visited mode, progress is recorded automatically when the page + is viewed. + - [Container](../../ILIAS/Container/PRIVACY.md) — used to store per-object settings such as Info tab visibility via container + settings. + +## Data being stored + +The Content Page component itself does not store personal data. Its database tables contain only: + +- `content_page_data`: the **Content Page ID** and a **stylesheet** reference (integer). No user + IDs or personal information. +- `content_page_metrics`: the **Content Page ID**, **page ID**, **language**, and computed + **reading time** in minutes. No user IDs or personal information. + +All personal data storage (such as learning progress records, page edit history, notes, and object +ownership) is handled by the integrated components listed above. + +## Data being presented + +- **Each user** with the "Read" permission can view the page content of the Content Page. +- **Each user** with the "Read" permission has their learning progress tracked automatically + when the Content Page uses the "content visited" learning progress mode. +- **Persons with the "Write" permission** can access the page editor to edit content, change + settings (title, description, online status, Info tab visibility), manage content styles, + manage translations, edit metadata, and access the export tab. +- **Persons with access to the Learning Progress** (as determined by + `ilLearningProgressAccess::checkAccess`) can view the Learning Progress tab, which may display + user names and completion statuses. The presentation of this data is handled by the + LearningProgress component. +- **Persons with the "Edit Permission" permission** can manage the permissions tab. +- If the **Info tab** is enabled (configurable per Content Page), persons with the "Visible" or + "Read" permission can access it. The Info tab may display metadata and allows private notes + (handled by the InfoScreen and Notes components). + +The Content Page component does not directly display user names, login names, or other personal +identifiers in its own user interface. Any such presentation occurs through delegated components +(e.g., LearningProgress, COPage, Notes). + +## Data being deleted + +- **When a Content Page object is deleted from trash**: all data in `content_page_data` and + `content_page_metrics` for that object is deleted. The associated page object is deleted via + the COPage component. Metadata, learning progress records, and other associated data managed + by integrated components are deleted according to their own lifecycle rules. +- **When a Content Page object is moved to trash**: the object becomes inaccessible but its data + remains in the database until the trash is emptied manually or by a cron job. +- **When a user account is deleted**: the Content Page component does not store user IDs, so no + data within its own tables is affected. Learning progress records, notes, and other + user-specific data associated with the Content Page are handled by the respective integrated + components. + +The Content Page component does not implement its own user-specific deletion methods (such as +`deleteByUserId`), as it does not store personal data. + +## Data being exported + +- **Persons with the "Write" permission** can export a Content Page object via the Export tab. + The XML export includes the Content Page's title, description, and Info tab visibility setting. + It also includes dependent data from integrated components: page content (COPage), metadata + (MetaData), content styles (Style), and common object data (ILIASObject). The export does not + include learning progress records or user-specific data. diff --git a/components/ILIAS/Course/classes/Grouping/Table/GroupingHandler.php b/components/ILIAS/Course/classes/Grouping/Table/GroupingHandler.php index 97984f5fcfe3..7df6dd0e8543 100755 --- a/components/ILIAS/Course/classes/Grouping/Table/GroupingHandler.php +++ b/components/ILIAS/Course/classes/Grouping/Table/GroupingHandler.php @@ -95,7 +95,7 @@ protected function buildColumns(): array self::COL_DESCRIPTION => $f->text($this->lng->txt('description'))->withIsSortable(true), self::COL_SOURCE => $f->link($this->lng->txt('groupings_source'))->withIsSortable(true), self::COL_UNIQUE_FIELD => $f->text($this->lng->txt('unambiguousness'))->withIsSortable(true), - self::COL_ASSIGNED_OBJS => $f->linkListing($this->lng->txt('groupings_assigned_obj_' . $type))->withIsSortable(true) + self::COL_ASSIGNED_OBJS => $f->listing($this->lng->txt('groupings_assigned_obj_' . $type))->withIsSortable(true) ]; } diff --git a/components/ILIAS/Course/classes/Objectives/class.ilCourseObjectiveQuestionAssignmentTableGUI.php b/components/ILIAS/Course/classes/Objectives/class.ilCourseObjectiveQuestionAssignmentTableGUI.php index 2a1900f9bd6a..a4e433952c4b 100755 --- a/components/ILIAS/Course/classes/Objectives/class.ilCourseObjectiveQuestionAssignmentTableGUI.php +++ b/components/ILIAS/Course/classes/Objectives/class.ilCourseObjectiveQuestionAssignmentTableGUI.php @@ -92,7 +92,7 @@ protected function fillRow(array $a_set): void if ($sub_data['qst_txt']) { $txt = $sub_data['qst_txt']; if ($sub_data['qst_points']) { - $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $txt .= (' (' . $sub_data['qst_points'] . ' ' . $this->lng->txt('points') . ')'); } diff --git a/components/ILIAS/Course/classes/Objectives/class.ilLOEditorGUI.php b/components/ILIAS/Course/classes/Objectives/class.ilLOEditorGUI.php index 112e9dcc87a1..e3794aae4f5c 100755 --- a/components/ILIAS/Course/classes/Objectives/class.ilLOEditorGUI.php +++ b/components/ILIAS/Course/classes/Objectives/class.ilLOEditorGUI.php @@ -55,6 +55,7 @@ class ilLOEditorGUI protected Factory $refinery; protected ilUIServices $ui_services; protected ilDBInterface $db; + protected ilAccess $access; private int $test_type = self::TEST_TYPE_UNDEFINED; @@ -80,6 +81,7 @@ public function __construct(ilObjCourseGUI $parent_gui) $this->refinery = $DIC->refinery(); $this->ui_services = $DIC->ui(); $this->db = $DIC->database(); + $this->access = $DIC->access(); } public function executeCommand(): void @@ -87,7 +89,9 @@ public function executeCommand(): void $next_class = $this->ctrl->getNextClass($this); $cmd = $this->ctrl->getCmd(); - + if (!$this->access->checkAccess('write', '', $this->getParentObject()->getRefId())) { + throw new \ilPermissionException($this->lng->txt("permission_denied")); + } $this->setTabs(); switch ($next_class) { diff --git a/components/ILIAS/Course/classes/class.ilCourseParticipantsTableGUI.php b/components/ILIAS/Course/classes/class.ilCourseParticipantsTableGUI.php index 47663169ca2e..396b55a71b17 100755 --- a/components/ILIAS/Course/classes/class.ilCourseParticipantsTableGUI.php +++ b/components/ILIAS/Course/classes/class.ilCourseParticipantsTableGUI.php @@ -38,6 +38,7 @@ class ilCourseParticipantsTableGUI extends ilParticipantTableGUI protected ilRbacReview $rbacReview; protected ilObjUser $user; protected Profile $profile; + protected \ILIAS\Refinery\Factory $refinery; protected array $cached_user_names = []; public function __construct( @@ -72,6 +73,7 @@ public function __construct( $this->rbacReview = $DIC->rbac()->review(); $this->user = $DIC->user(); $this->profile = $DIC['user']->getProfile(); + $this->refinery = $DIC->refinery(); $this->setId('crs_' . $this->getRepositoryObject()->getId()); parent::__construct($a_parent_obj, 'participants'); @@ -146,7 +148,12 @@ protected function fillRow(array $a_set): void { $this->tpl->setVariable('VAL_ID', $a_set['usr_id']); $this->tpl->setVariable('VAL_NAME', $a_set['lastname'] . ', ' . $a_set['firstname']); - $this->tpl->setVariable('SELECT_PARTICIPANT', $this->lng->txt("select") . ' ' . $a_set['lastname'] . ', ' . $a_set['firstname']); + $this->tpl->setVariable( + 'SELECT_PARTICIPANT', + $this->refinery->encode()->htmlAttributeValue()->transform( + "{$this->lng->txt('select')} {$a_set['lastname']}, {$a_set['firstname']}" + ) + ); if ( !$this->access->checkAccessOfUser($a_set['usr_id'], 'read', '', $this->getRepositoryObject()->getRefId()) && diff --git a/components/ILIAS/Course/classes/class.ilCourseXMLParser.php b/components/ILIAS/Course/classes/class.ilCourseXMLParser.php index 2bd8bcb96c4d..e4801811407b 100755 --- a/components/ILIAS/Course/classes/class.ilCourseXMLParser.php +++ b/components/ILIAS/Course/classes/class.ilCourseXMLParser.php @@ -635,6 +635,10 @@ public function handlerEndTag($a_xml_parser, string $a_name): void $this->course_obj->setTimingMode((int) $this->cdata); break; + case 'AboStatus': + $this->course_obj->setAboStatus((int) $this->cdata); + break; + case 'StatusDetermination': $this->course_obj->setStatusDetermination((int) $this->cdata); break; diff --git a/components/ILIAS/Course/classes/class.ilCourseXMLWriter.php b/components/ILIAS/Course/classes/class.ilCourseXMLWriter.php index d8a715295b82..39465de484c2 100755 --- a/components/ILIAS/Course/classes/class.ilCourseXMLWriter.php +++ b/components/ILIAS/Course/classes/class.ilCourseXMLWriter.php @@ -334,6 +334,8 @@ public function __buildSetting(): void $this->xmlElement('TimingMode', null, $this->course_obj->getTimingMode()); } + $this->xmlElement('AboStatus', null, $this->course_obj->getAboStatus() ? 1 : 0); + $this->xmlElement('TutorialSupportBlock', [ 'active' => $this->course_obj->getTutorialSupportBlockSettingValue() ]); diff --git a/components/ILIAS/Course/classes/class.ilObjCourseGUI.php b/components/ILIAS/Course/classes/class.ilObjCourseGUI.php index 8ff7f3897435..9a4e1a2b3831 100755 --- a/components/ILIAS/Course/classes/class.ilObjCourseGUI.php +++ b/components/ILIAS/Course/classes/class.ilObjCourseGUI.php @@ -644,6 +644,7 @@ public function updateInfoObject(): void public function updateObject(): void { + $this->checkPermission('write'); $obj_service = $this->getObjectService(); $setting = $this->settings; @@ -913,6 +914,7 @@ protected function confirmLPSync(): void protected function setLPSyncObject(): void { + $this->checkPermission('write'); $this->object->setStatusDetermination(ilObjCourse::STATUS_DETERMINATION_LP); $this->object->update(); $this->object->syncMembersStatusWithLP(); @@ -922,6 +924,7 @@ protected function setLPSyncObject(): void public function editObject(?ilPropertyFormGUI $form = null): void { + $this->checkPermission('write'); $this->setSubTabs('properties'); $this->tabs_gui->setSubTabActive('general'); @@ -2210,6 +2213,7 @@ public function executeCommand(): void break; case "ilcertificategui": + $this->checkPermission('write'); $this->tabs_gui->activateTab("settings"); $this->setSubTabs("properties"); $this->tabs_gui->activateSubTab('certificate'); @@ -2544,12 +2548,13 @@ public static function _goto($a_target, string $a_add = ""): void public function editMapSettingsObject(): void { + $this->checkPermission('write'); + $this->setSubTabs("properties"); $this->tabs_gui->activateTab('settings'); $this->tabs_gui->activateSubTab('crs_map_settings'); - if (!ilMapUtil::isActivated() || - !$this->access->checkAccess("write", "", $this->object->getRefId())) { + if (!ilMapUtil::isActivated()) { return; } @@ -2599,6 +2604,8 @@ public function editMapSettingsObject(): void */ public function saveMapSettingsObject(): void { + $this->checkPermission('write'); + $location = []; if ($this->http->wrapper()->post()->has('location')) { $custom_transformer = $this->refinery->custom()->transformation( @@ -2723,6 +2730,7 @@ public function setContentSubTabs(): void public function askResetObject(): void { + $this->checkPermission('write'); //$this->tpl->setOnScreenMessage('question', $this->lng->txt('crs_objectives_reset_sure')); $confirm = new ilConfirmationGUI(); $confirm->setHeaderText($this->lng->txt('crs_objectives_reset_sure')); @@ -2734,6 +2742,7 @@ public function askResetObject(): void public function resetObject(): void { + $this->checkPermission('write'); $usr_results = new ilLOUserResults($this->object->getId(), $GLOBALS['DIC']['ilUser']->getId()); $usr_results->delete(); ilLOTestRun::deleteRuns( diff --git a/components/ILIAS/Course/tests/Certificate/ilCertificateCourseLearningProgressEvaluationTest.php b/components/ILIAS/Course/tests/Certificate/ilCertificateCourseLearningProgressEvaluationTest.php index 81a0145f0368..30027795dc33 100755 --- a/components/ILIAS/Course/tests/Certificate/ilCertificateCourseLearningProgressEvaluationTest.php +++ b/components/ILIAS/Course/tests/Certificate/ilCertificateCourseLearningProgressEvaluationTest.php @@ -43,7 +43,7 @@ class ilCertificateCourseLearningProgressEvaluationTest extends TestCase { public function testOnlyOneCourseIsCompletedOnLPChange(): void { - $templateRepository = $this->getMockBuilder(ilCertificateTemplateRepository::class)->getMock(); + $templateRepository = $this->createStub(ilCertificateTemplateRepository::class); $templateRepository->method('fetchActiveCertificateTemplatesForCoursesWithDisabledLearningProgress') ->willReturn( @@ -79,9 +79,7 @@ public function testOnlyOneCourseIsCompletedOnLPChange(): void ] ); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createStub(ilSetting::class); $consecutive_get = [ ['cert_subitems_5', '[10,20]'], @@ -97,8 +95,7 @@ function (string $k) use (&$consecutive_get): string { } ); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); $consecutive_lookup = [10, 20, 10, 50]; $objectHelper @@ -112,8 +109,7 @@ function (int $id) use (&$consecutive_lookup): int { } ); - $statusHelper = $this->getMockBuilder(ilCertificateLPStatusHelper::class) - ->getMock(); + $statusHelper = $this->createStub(ilCertificateLPStatusHelper::class); $consecutive_status = [ [100, ilLPStatus::LP_STATUS_COMPLETED_NUM], @@ -132,8 +128,7 @@ function (int $id) use (&$consecutive_status): int { } ); - $trackingHelper = $this->getMockBuilder(ilCertificateObjUserTrackingHelper::class) - ->getMock(); + $trackingHelper = $this->createStub(ilCertificateObjUserTrackingHelper::class); $trackingHelper->method('enabledLearningProgress')->willReturn(true); $evaluation = new CertificateCourseLearningProgressEvaluation( @@ -151,7 +146,7 @@ function (int $id) use (&$consecutive_status): int { public function testAllCoursesAreCompletedOnLPChange(): void { - $templateRepository = $this->getMockBuilder(ilCertificateTemplateRepository::class)->getMock(); + $templateRepository = $this->createStub(ilCertificateTemplateRepository::class); $templateRepository->method('fetchActiveCertificateTemplatesForCoursesWithDisabledLearningProgress') ->willReturn( @@ -187,13 +182,9 @@ public function testAllCoursesAreCompletedOnLPChange(): void ] ); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createStub(ilSetting::class); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createStub(ilSetting::class); $consecutive_get = [ ['cert_subitems_5', '[10,20]'], @@ -209,8 +200,7 @@ function (string $k) use (&$consecutive_get): string { } ); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); $consecutive_lookup = [ [10, 100], @@ -229,8 +219,7 @@ function (int $id) use (&$consecutive_lookup): int { } ); - $statusHelper = $this->getMockBuilder(ilCertificateLPStatusHelper::class) - ->getMock(); + $statusHelper = $this->createStub(ilCertificateLPStatusHelper::class); $consecutive_status = [ [100, ilLPStatus::LP_STATUS_COMPLETED_NUM], @@ -250,8 +239,7 @@ function (int $id) use (&$consecutive_status): int { } ); - $trackingHelper = $this->getMockBuilder(ilCertificateObjUserTrackingHelper::class) - ->getMock(); + $trackingHelper = $this->createStub(ilCertificateObjUserTrackingHelper::class); $trackingHelper->method('enabledLearningProgress')->willReturn(false); $evaluation = new CertificateCourseLearningProgressEvaluation( @@ -270,7 +258,7 @@ function (int $id) use (&$consecutive_status): int { public function testNoSubitemDefinedForEvaluation(): void { - $templateRepository = $this->getMockBuilder(ilCertificateTemplateRepository::class)->getMock(); + $templateRepository = $this->createStub(ilCertificateTemplateRepository::class); $templateRepository->method('fetchActiveCertificateTemplatesForCoursesWithDisabledLearningProgress') ->willReturn( @@ -306,9 +294,7 @@ public function testNoSubitemDefinedForEvaluation(): void ] ); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createStub(ilSetting::class); $consecutive_get = [ 'cert_subitems_5', @@ -325,14 +311,11 @@ function (string $k) use (&$consecutive_get) { } ); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); - $statusHelper = $this->getMockBuilder(ilCertificateLPStatusHelper::class) - ->getMock(); + $statusHelper = $this->createStub(ilCertificateLPStatusHelper::class); - $trackingHelper = $this->getMockBuilder(ilCertificateObjUserTrackingHelper::class) - ->getMock(); + $trackingHelper = $this->createStub(ilCertificateObjUserTrackingHelper::class); $trackingHelper->method('enabledLearningProgress')->willReturn(false); $evaluation = new CertificateCourseLearningProgressEvaluation( @@ -397,7 +380,7 @@ public function testRetrievingCertificateTemplatesForCoursesWorksAsExpectedWhenU bool $isGlobalLpEnabled, array $template_recods ): void { - $statement = $database = $this->getMockBuilder(ilDBStatement::class)->getMock(); + $statement = $database = $this->createStub(ilDBStatement::class); $i = 0; $database->method('fetch')->willReturnCallback(static function () use (&$i, $template_recods): ?array { $result = $template_recods[$i] ?? null; @@ -424,13 +407,9 @@ public function testRetrievingCertificateTemplatesForCoursesWorksAsExpectedWhenU return $statement->fetch(PDO::FETCH_ASSOC); }); - $logger = $this->getMockBuilder(ilLogger::class) - ->disableOriginalConstructor() - ->getMock(); + $logger = $this->createStub(ilLogger::class); - $objectDataCache = $this->getMockBuilder(ilObjectDataCache::class) - ->disableOriginalConstructor() - ->getMock(); + $objectDataCache = $this->createStub(ilObjectDataCache::class); $repository = new ilCertificateTemplateDatabaseRepository( $database, @@ -446,7 +425,7 @@ public function testRetrievingCertificateTemplatesForCoursesWorksAsExpectedWhenU public function testRetrievingCertificateTemplatesForCoursesWillBeCachedWhenCachingRepositoryIsUsed(): void { - $wrappedTemplateRepository = $this->getMockBuilder(ilCertificateTemplateRepository::class)->getMock(); + $wrappedTemplateRepository = $this->createMock(ilCertificateTemplateRepository::class); $wrappedTemplateRepository ->expects($this->exactly(2)) ->method('fetchActiveCertificateTemplatesForCoursesWithDisabledLearningProgress') diff --git a/components/ILIAS/Course/tests/Certificate/ilCertificateSettingsCourseFormRepositoryTest.php b/components/ILIAS/Course/tests/Certificate/ilCertificateSettingsCourseFormRepositoryTest.php index ad1bb9001ef2..bfafafbd1112 100644 --- a/components/ILIAS/Course/tests/Certificate/ilCertificateSettingsCourseFormRepositoryTest.php +++ b/components/ILIAS/Course/tests/Certificate/ilCertificateSettingsCourseFormRepositoryTest.php @@ -42,67 +42,41 @@ class ilCertificateSettingsCourseFormRepositoryTest extends TestCase { public function testSaveSettings(): void { - $object = $this->getMockBuilder(ilObjCourse::class) - ->disableOriginalConstructor() - ->getMock(); + $object = $this->createMock(ilObjCourse::class); $object ->expects($this->atLeastOnce()) ->method('getId') ->willReturn(100); - $language = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->getMock(); + $language = $this->createStub(ilLanguage::class); - $controller = $this->getMockBuilder(ilCtrlInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $controller = $this->createStub(ilCtrlInterface::class); - $access = $this->getMockBuilder(ilAccess::class) - ->disableOriginalConstructor() - ->getMock(); + $access = $this->createStub(ilAccess::class); - $toolbar = $this->getMockBuilder(ilToolbarGUI::class) - ->disableOriginalConstructor() - ->getMock(); + $toolbar = $this->createStub(ilToolbarGUI::class); - $placeholderDescriptionObject = $this->getMockBuilder(ilCertificatePlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $placeholderDescriptionObject = $this->createStub(ilCertificatePlaceholderDescription::class); - $settingsFormFactory = $this->getMockBuilder(ilCertificateSettingsFormRepository::class) - ->disableOriginalConstructor() - ->getMock(); + $settingsFormFactory = $this->createStub(ilCertificateSettingsFormRepository::class); - $trackingHelper = $this->getMockBuilder(ilCertificateObjUserTrackingHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $trackingHelper = $this->createStub(ilCertificateObjUserTrackingHelper::class); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); - $lpHelper = $this->getMockBuilder(ilCertificateObjectLPHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $lpHelper = $this->createStub(ilCertificateObjectLPHelper::class); - $lpMock = $this->getMockBuilder(ilObjectLP::class) - ->disableOriginalConstructor() - ->getMock(); + $lpMock = $this->createStub(ilObjectLP::class); $lpMock->method('getCurrentMode') ->willReturn(100); $lpHelper->method('getInstance')->willReturn($lpMock); - $tree = $this->getMockBuilder(ilTree::class) - ->disableOriginalConstructor() - ->getMock(); + $tree = $this->createStub(ilTree::class); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createMock(ilSetting::class); $setting ->expects($this->atLeastOnce()) @@ -130,38 +104,24 @@ public function testSaveSettings(): void public function testFetchFormFieldData(): void { - $object = $this->getMockBuilder(ilObjCourse::class) - ->disableOriginalConstructor() - ->getMock(); + $object = $this->createMock(ilObjCourse::class); $object ->expects($this->atLeastOnce()) ->method('getId') ->willReturn(100); - $language = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->getMock(); + $language = $this->createStub(ilLanguage::class); - $controller = $this->getMockBuilder(ilCtrlInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $controller = $this->createStub(ilCtrlInterface::class); - $access = $this->getMockBuilder(ilAccess::class) - ->disableOriginalConstructor() - ->getMock(); + $access = $this->createStub(ilAccess::class); - $toolbar = $this->getMockBuilder(ilToolbarGUI::class) - ->disableOriginalConstructor() - ->getMock(); + $toolbar = $this->createStub(ilToolbarGUI::class); - $placeholderDescriptionObject = $this->getMockBuilder(ilCertificatePlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $placeholderDescriptionObject = $this->createStub(ilCertificatePlaceholderDescription::class); - $settingsFormFactory = $this->getMockBuilder(ilCertificateSettingsFormRepository::class) - ->disableOriginalConstructor() - ->getMock(); + $settingsFormFactory = $this->createMock(ilCertificateSettingsFormRepository::class); $settingsFormFactory ->expects($this->atLeastOnce()) @@ -173,25 +133,15 @@ public function testFetchFormFieldData(): void ] ); - $trackingHelper = $this->getMockBuilder(ilCertificateObjUserTrackingHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $trackingHelper = $this->createStub(ilCertificateObjUserTrackingHelper::class); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); - $lpHelper = $this->getMockBuilder(ilCertificateObjectLPHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $lpHelper = $this->createStub(ilCertificateObjectLPHelper::class); - $tree = $this->getMockBuilder(ilTree::class) - ->disableOriginalConstructor() - ->getMock(); + $tree = $this->createStub(ilTree::class); - $setting = $this->getMockBuilder(ilSetting::class) - ->disableOriginalConstructor() - ->getMock(); + $setting = $this->createMock(ilSetting::class); $setting ->expects($this->atLeastOnce()) diff --git a/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderDescriptionTest.php b/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderDescriptionTest.php index cc9d9cf6f1ca..6d425368b41a 100644 --- a/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderDescriptionTest.php +++ b/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderDescriptionTest.php @@ -35,21 +35,14 @@ class ilCoursePlaceholderDescriptionTest extends TestCase { public function testPlaceholderGetHtmlDescription(): void { - $languageMock = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->onlyMethods(['txt', 'loadLanguageModule']) - ->getMock(); + $languageMock = $this->createStub(ilLanguage::class); - $templateMock = $this->getMockBuilder(ilTemplate::class) - ->disableOriginalConstructor() - ->getMock(); + $templateMock = $this->createStub(ilTemplate::class); $templateMock->method('get') ->willReturn(''); - $userDefinePlaceholderMock = $this->getMockBuilder(ilUserDefinedFieldsPlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $userDefinePlaceholderMock = $this->createStub(ilUserDefinedFieldsPlaceholderDescription::class); $userDefinePlaceholderMock->method('createPlaceholderHtmlDescription') ->willReturn(''); @@ -57,9 +50,7 @@ public function testPlaceholderGetHtmlDescription(): void $userDefinePlaceholderMock->method('getPlaceholderDescriptions') ->willReturn([]); - $customUserPlaceholderObject = $this->getMockBuilder(ilObjectCustomUserFieldsPlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $customUserPlaceholderObject = $this->createStub(ilObjectCustomUserFieldsPlaceholderDescription::class); $customUserPlaceholderObject->method('getPlaceholderDescriptions') ->willReturn([ @@ -70,9 +61,7 @@ public function testPlaceholderGetHtmlDescription(): void $customUserPlaceholderObject->method('createPlaceholderHtmlDescription') ->willReturn(''); - $profile = $this->getMockBuilder(Profile::class) - ->disableOriginalConstructor() - ->getMock(); + $profile = $this->createStub(Profile::class); $placeholderDescriptionObject = new CoursePlaceholderDescription(200, null, $languageMock, $userDefinePlaceholderMock, $customUserPlaceholderObject, $profile); @@ -83,18 +72,13 @@ public function testPlaceholderGetHtmlDescription(): void public function testPlaceholderDescriptions(): void { - $languageMock = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->onlyMethods(['txt']) - ->getMock(); + $languageMock = $this->createMock(ilLanguage::class); $languageMock->expects($this->exactly(3)) ->method('txt') ->willReturn('Something translated'); - $defaultPlaceholder = $this->getMockBuilder(ilDefaultPlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $defaultPlaceholder = $this->createStub(ilDefaultPlaceholderDescription::class); $defaultPlaceholder->method('getPlaceholderDescriptions') ->willReturn( @@ -104,9 +88,7 @@ public function testPlaceholderDescriptions(): void ] ); - $customUserPlaceholderObject = $this->getMockBuilder(ilObjectCustomUserFieldsPlaceholderDescription::class) - ->disableOriginalConstructor() - ->getMock(); + $customUserPlaceholderObject = $this->createStub(ilObjectCustomUserFieldsPlaceholderDescription::class); $customUserPlaceholderObject->method('getPlaceholderDescriptions') ->willReturn( @@ -116,9 +98,7 @@ public function testPlaceholderDescriptions(): void ] ); - $profile = $this->getMockBuilder(Profile::class) - ->disableOriginalConstructor() - ->getMock(); + $profile = $this->createStub(Profile::class); $placeholderDescriptionObject = new CoursePlaceholderDescription(200, $defaultPlaceholder, $languageMock, null, $customUserPlaceholderObject, $profile); diff --git a/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderValuesTest.php b/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderValuesTest.php index 1b35ce01374a..ddad122a9ff0 100644 --- a/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderValuesTest.php +++ b/components/ILIAS/Course/tests/Certificate/ilCoursePlaceholderValuesTest.php @@ -67,43 +67,33 @@ protected function setGlobalVariable(string $name, $value): void public function testGetPlaceholderValues(): void { - $customUserFieldsPlaceholderValues = $this->getMockBuilder(ilObjectCustomUserFieldsPlaceholderValues::class) - ->disableOriginalConstructor() - ->getMock(); + $customUserFieldsPlaceholderValues = $this->createStub(ilObjectCustomUserFieldsPlaceholderValues::class); $customUserFieldsPlaceholderValues->method('getPlaceholderValues') ->willReturn([]); - $defaultPlaceholderValues = $this->getMockBuilder(ilDefaultPlaceholderValues::class) - ->disableOriginalConstructor() - ->getMock(); + $defaultPlaceholderValues = $this->createStub(ilDefaultPlaceholderValues::class); $defaultPlaceholderValues->method('getPlaceholderValues') ->willReturn([]); - $language = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->getMock(); + $language = $this->createStub(ilLanguage::class); $language->method('txt') ->willReturn('Something'); - $objectMock = $this->getMockBuilder(ilObjCourse::class) - ->disableOriginalConstructor() - ->getMock(); + $objectMock = $this->createStub(ilObjCourse::class); $objectMock->method('getTitle') ->willReturn('Some Title'); - $obj_translation = $this->getMockBuilder(ilObjectTranslations::class) - ->disableOriginalConstructor() - ->getMock(); + $obj_translation = $this->createStub(ilObjectTranslations::class); - $german = $this->createMock(ilObjectTranslationLanguage::class); + $german = $this->createStub(ilObjectTranslationLanguage::class); $german->method('getLanguageCode') ->willReturn('de'); - $english = $this->createMock(ilObjectTranslationLanguage::class); + $english = $this->createStub(ilObjectTranslationLanguage::class); $english->method('getLanguageCode') ->willReturn('en'); @@ -116,12 +106,9 @@ public function testGetPlaceholderValues(): void $objectMock->method('getObjectTranslation') ->willReturn($obj_translation); - $user_object = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user_object = $this->createStub(ilObjUser::class); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); $objectHelper->method('getInstanceByObjId') ->willReturnMap( [ @@ -130,21 +117,17 @@ public function testGetPlaceholderValues(): void ] ); - $participantsHelper = $this->getMockBuilder(CertificateParticipantsHelper::class) - ->getMock(); + $participantsHelper = $this->createStub(CertificateParticipantsHelper::class); $participantsHelper->method('getDateTimeOfPassed') ->willReturn('2018-09-10'); - $ilUtilHelper = $this->getMockBuilder(ilCertificateUtilHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $ilUtilHelper = $this->createStub(ilCertificateUtilHelper::class); $ilUtilHelper->method('prepareFormOutput') ->willReturn('Some Title'); - $ilDateHelper = $this->getMockBuilder(ilCertificateDateHelper::class) - ->getMock(); + $ilDateHelper = $this->createStub(ilCertificateDateHelper::class); $ilDateHelper->method('formatDate') ->willReturn('2018-09-10'); @@ -152,8 +135,7 @@ public function testGetPlaceholderValues(): void $ilDateHelper->method('formatDateTime') ->willReturn('2018-09-10 10:32:00'); - $database = $this->getMockBuilder(ilDBInterface::class) - ->getMock(); + $database = $this->createStub(ilDBInterface::class); $this->setGlobalVariable('ilDB', $database); $this->setGlobalVariable('lng', $language); @@ -181,9 +163,7 @@ public function testGetPlaceholderValues(): void public function testGetPreviewPlaceholderValues(): void { - $customUserFieldsPlaceholderValues = $this->getMockBuilder(ilObjectCustomUserFieldsPlaceholderValues::class) - ->disableOriginalConstructor() - ->getMock(); + $customUserFieldsPlaceholderValues = $this->createStub(ilObjectCustomUserFieldsPlaceholderValues::class); $customUserFieldsPlaceholderValues->method('getPlaceholderValuesForPreview') ->willReturn( @@ -193,9 +173,7 @@ public function testGetPreviewPlaceholderValues(): void ] ); - $defaultPlaceholderValues = $this->getMockBuilder(ilDefaultPlaceholderValues::class) - ->disableOriginalConstructor() - ->getMock(); + $defaultPlaceholderValues = $this->createStub(ilDefaultPlaceholderValues::class); $defaultPlaceholderValues->method('getPlaceholderValuesForPreview') ->willReturn( @@ -205,29 +183,23 @@ public function testGetPreviewPlaceholderValues(): void ] ); - $language = $this->getMockBuilder(ilLanguage::class) - ->disableOriginalConstructor() - ->getMock(); + $language = $this->createStub(ilLanguage::class); $language->method('txt') ->willReturn('Something'); - $objectMock = $this->getMockBuilder(ilObjCourse::class) - ->disableOriginalConstructor() - ->getMock(); + $objectMock = $this->createStub(ilObjCourse::class); $objectMock->method('getTitle') ->willReturn('SomeTitle'); - $obj_translation = $this->getMockBuilder(ilObjectTranslations::class) - ->disableOriginalConstructor() - ->getMock(); + $obj_translation = $this->createStub(ilObjectTranslations::class); - $german = $this->createMock(ilObjectTranslationLanguage::class); + $german = $this->createStub(ilObjectTranslationLanguage::class); $german->method('getLanguageCode') ->willReturn('de'); - $english = $this->createMock(ilObjectTranslationLanguage::class); + $english = $this->createStub(ilObjectTranslationLanguage::class); $english->method('getLanguageCode') ->willReturn('en'); @@ -240,26 +212,21 @@ public function testGetPreviewPlaceholderValues(): void $objectMock->method('getObjectTranslation') ->willReturn($obj_translation); - $objectHelper = $this->getMockBuilder(ilCertificateObjectHelper::class) - ->getMock(); + $objectHelper = $this->createStub(ilCertificateObjectHelper::class); $objectHelper->method('getInstanceByObjId') ->willReturn($objectMock); - $participantsHelper = $this->getMockBuilder(CertificateParticipantsHelper::class) - ->getMock(); + $participantsHelper = $this->createStub(CertificateParticipantsHelper::class); - $utilHelper = $this->getMockBuilder(ilCertificateUtilHelper::class) - ->disableOriginalConstructor() - ->getMock(); + $utilHelper = $this->createStub(ilCertificateUtilHelper::class); $utilHelper->method('prepareFormOutput') ->willReturnCallback(function ($input) { return $input; }); - $database = $this->getMockBuilder(ilDBInterface::class) - ->getMock(); + $database = $this->createStub(ilDBInterface::class); $this->setGlobalVariable('ilDB', $database); $this->setGlobalVariable('lng', $language); diff --git a/components/ILIAS/Course/tests/Timings/ilTimingAcceptedTest.php b/components/ILIAS/Course/tests/Timings/ilTimingAcceptedTest.php index 3664ec6b90f3..5e9be896bd63 100755 --- a/components/ILIAS/Course/tests/Timings/ilTimingAcceptedTest.php +++ b/components/ILIAS/Course/tests/Timings/ilTimingAcceptedTest.php @@ -71,6 +71,6 @@ protected function initDependencies(): void { $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); } } diff --git a/components/ILIAS/Course/tests/ilCourseMailTemplateTutorContextTest.php b/components/ILIAS/Course/tests/ilCourseMailTemplateTutorContextTest.php index 9a4de1467e9b..550b2ea5ef67 100755 --- a/components/ILIAS/Course/tests/ilCourseMailTemplateTutorContextTest.php +++ b/components/ILIAS/Course/tests/ilCourseMailTemplateTutorContextTest.php @@ -32,8 +32,8 @@ protected function setUp(): void $this->dic_backup = is_object($DIC) ? clone $DIC : $DIC; $DIC = new Container(); - $DIC['ilObjDataCache'] = $this->createMock(ilObjectDataCache::class); - $DIC['ilDB'] = $this->createMock(ilDBInterface::class); + $DIC['ilObjDataCache'] = $this->createStub(ilObjectDataCache::class); + $DIC['ilDB'] = $this->createStub(ilDBInterface::class); } protected function tearDown(): void diff --git a/components/ILIAS/Cron/README.md b/components/ILIAS/Cron/README.md index 48455e007f83..af5e500b2562 100755 --- a/components/ILIAS/Cron/README.md +++ b/components/ILIAS/Cron/README.md @@ -22,8 +22,7 @@ described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). To give more control of if and when cron-jobs are executed to administrators a 2nd implementation of cron-jobs has been added to ILIAS 4.4+. All existing cron-jobs have been migrated and thus moved to their respective modules -and services. The top-level directory "cron/" will probably be kept because of cron.php but should otherwise be empty -at some point. +and services. The CLI entry point for executing cron-jobs is `cli/cron.php`. ### Providing a Cron-Job @@ -176,11 +175,13 @@ So as mentioned above the cron-tab can safely be set to every few minutes. In order to execute the cron job manager, the following command MUST be used: ```shell -/usr/bin/php [PATH_TO_ILIAS]/cron/cron.php run-jobs run-jobs +/usr/bin/php [PATH_TO_ILIAS]/cli/cron.php run-jobs ``` The `` MUST be a valid (but arbitrary) user account of the ILIAS installation. -The `` MUST be the client id of the ILIAS installation. + +The system crontab SHOULD invoke this command every few minutes. Individual cron-jobs +are then executed according to their configured schedule. ## Permission Context diff --git a/components/ILIAS/Cron/src/CLI/Commands/RunActiveJobsCommand.php b/components/ILIAS/Cron/src/CLI/Commands/RunActiveJobsCommand.php index 2cc1449d3238..67dd4da0da0b 100644 --- a/components/ILIAS/Cron/src/CLI/Commands/RunActiveJobsCommand.php +++ b/components/ILIAS/Cron/src/CLI/Commands/RunActiveJobsCommand.php @@ -40,7 +40,6 @@ protected function configure(): void $this->setDescription('Runs cron jobs depending on the respective schedule'); $this->addArgument('user', InputArgument::REQUIRED, 'The ILIAS user the script is executed with'); - $this->addArgument('client_id', InputArgument::REQUIRED, 'The ILIAS client_id'); } protected function execute(InputInterface $input, OutputInterface $output): int @@ -48,7 +47,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->style = new SymfonyStyle($input, $output); $cron = new \ILIAS\Cron\CLI\StartUp( - $input->getArgument('client_id'), $input->getArgument('user') ); diff --git a/components/ILIAS/Cron/src/CLI/StartUp.php b/components/ILIAS/Cron/src/CLI/StartUp.php index 5cde824c3c69..4f7ffb2ff841 100644 --- a/components/ILIAS/Cron/src/CLI/StartUp.php +++ b/components/ILIAS/Cron/src/CLI/StartUp.php @@ -28,16 +28,12 @@ class StartUp private bool $is_authenticated = false; public function __construct( - private readonly string $client, private readonly string $username, ?\ilAuthSession $authSession = null ) { /** @noRector */ \ilContext::init(\ilContext::CONTEXT_CRON); - // TODO @see mantis 20371: To get rid of this, the authentication service has to provide a mechanism to pass the client_id - $_GET['client_id'] = $this->client; - require_once __DIR__ . '/../../../../../artifacts/bootstrap_default.php'; entry_point('ILIAS Legacy Initialisation Adapter'); diff --git a/components/ILIAS/Dashboard/PRIVACY.md b/components/ILIAS/Dashboard/PRIVACY.md new file mode 100644 index 000000000000..9358db08c33e --- /dev/null +++ b/components/ILIAS/Dashboard/PRIVACY.md @@ -0,0 +1,124 @@ +# Dashboard Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories).** + + +## General Information + +The Dashboard is the central landing page after login. It aggregates personal data from various +ILIAS components and presents it in configurable blocks: Favourites (selected items), My Memberships, +Recommended Content, Learning Sequences, and Study Programmes. The Dashboard itself stores a small +amount of personal data (favourites and view preferences). All other personal data shown on the +Dashboard is managed by the respective integrated components. + +The Favourites feature can be globally enabled or disabled via the Repository settings +(`rep_favourites`). When disabled, no favourites data presented. Similarly, +the "My Memberships" view can be globally toggled (`mmbr_my_crs_grp`). The Achievements area +(learning history, competences, learning progress, badges, certificates) is accessible from the +Dashboard but each sub-feature has its own activation setting. + +Whether a user can switch between list and tile presentation depends on the "change_presentation" +permission on the Dashboard Settings administration object. + +## Integrated Components + +- The Dashboard component employs the following components, please consult the respective + PRIVACY.md files: + - [AccessControl](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/AccessControl/PRIVACY.md) - manages permissions for Dashboard + administration and the "change_presentation" permission. + - [Notes](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Notes/PRIVACY.md) - the Dashboard can display personal notes and comments + if enabled in the settings. + - [News](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/News/PRIVACY.md) - the Dashboard side panel can display news items for + the user. + - [Mail](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Mail/PRIVACY.md) - the Dashboard side panel can display a mail block + showing recent messages. + - [Contact](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Contact/PRIVACY.md) - the Dashboard forwards to the contact/buddy list + interface. + - [COPage](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/COPage/PRIVACY.md) - the Dashboard supports customizable page content + per language via the COPage service. + - Badge - badge information is accessible via the Achievements + area on the Dashboard. + - [Skill](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Skill/PRIVACY.md) - personal skills are accessible via the Achievements + area on the Dashboard. + - [Certificate](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Certificate/PRIVACY.md) - user certificates are accessible via the + Achievements area on the Dashboard. + - [StudyProgramme](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/StudyProgramme/PRIVACY.md) - study programme progress is shown + in a dedicated Dashboard view. + - [LearningSequence](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/LearningSequence/PRIVACY.md) - learning sequences are shown + in a dedicated Dashboard view. + - [Repository](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Repository/PRIVACY.md) - the Favourites feature references repository + objects and checks access permissions through the Repository. + - [Group](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Group/PRIVACY.md) - memberships in groups are listed in the "My Memberships" + view. Users can unsubscribe from groups via the Dashboard. + - Calendar - the Dashboard side panel can display a calendar block. Calendar has no + PRIVACY.md yet. + - User - the Dashboard accesses user preference data for sorting and presentation + settings. + - Tracking - the Dashboard preloads learning progress status for listed items. + Tracking has no PRIVACY.md yet. + - [LearningHistory](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/LearningHistory/PRIVACY.md) - the Achievements area provides access to the learning history. + - Course - memberships in courses are listed in the "My Memberships" view. Users can + unsubscribe from courses via the Dashboard. Course has no PRIVACY.md yet. + +## Data being stored + +- **User ID of the favourites owner**: When a user adds a repository object to their favourites, + the **user ID** is stored together with the **reference ID** of the object and its **type** in + the `desktop_item` table. This links each user to the objects they have marked as favourites. +- **Reference ID of the favourited object**: The **item_id** (reference ID) of the repository + object is stored in the `desktop_item` table to identify which object the user has favourited. +- **Object type of the favourited object**: The **type** of the favourited repository object is + stored in the `desktop_item` table to enable type-based filtering when retrieving favourites. +- **Presentation preference**: Each user's chosen presentation mode (list or tile) per Dashboard + view is stored as a **user preference** with the key `pd_view_pres_{view}`. +- **Sorting preference**: Each user's chosen sorting mode per Dashboard view is stored as a + **user preference** with the key `pd_order_items_{view}`. +- **Manual sort order data**: When a user selects manual sorting, the custom order of items is + stored as a **user preference** with the key `pd_order_data_{view}_{mode}` in JSON format. + +## Data being presented + +- **Each user** can view their own Dashboard, including: + - their own favourited repository objects (title, type icon, description, parent location). + - their own course and group memberships (title, type, description, period dates). + - their recommended content, learning sequences, and study programme items. +- **Each user** can manage their own favourites by adding or removing items. They can also + unsubscribe from courses and groups directly from the "My Memberships" view, provided they + have the "leave" permission on the respective object. +- **Persons with the "change_presentation" permission** on the Dashboard Settings administration + object can switch between all enabled modes. Users without this permission see + only the default presentation mode configured by a person with the "Edit Settings" permission. +- **Persons with the "read" permission** on the Dashboard Settings administration object can + view the Dashboard configuration, including which views are enabled and their sorting and + presentation defaults. +- **Persons with the "write" permission** on the Dashboard Settings administration object can + modify Dashboard configuration, including enabling or disabling views (Favourites, Memberships, + Study Programmes, Learning Sequences), enabling and setting default sorting and presentation modes, and + configuring side panel modules (Calendar, News, Mail, Tasks). + +## Data being deleted + +- **When a user removes a single favourite**: The corresponding entry (user ID, item reference ID, + type) is deleted from the `desktop_item` table. +- **When a user removes multiple favourites at once**: Each selected entry is deleted from the + `desktop_item` table. +- **When a repository object is deleted**: All favourite entries referencing that object are removed + from the `desktop_item` table via `removeFavouritesOfRefId()`, removing the association for all + users who had favourited that object. +- **When a user account is deleted**: The Dashboard listens for the `deleteUser` event from the + User service. Upon receiving it, all entries in the `desktop_item` table belonging to that user + are deleted. Additionally, a database update step ensures orphaned entries (where the + user no longer exists in `usr_data`) are cleaned up. +- **When a user unsubscribes from a course or group via the Dashboard**: The user's membership is + removed from the respective course or group. This is handled by the Course or Group component, + not by the Dashboard itself. The Dashboard only triggers the action if the user has the "leave" + permission. +- **User preferences**: When a user account is deleted, user preferences (presentation mode, + sorting mode, manual sort data) are deleted together with the user account by the User component. + +## Data being exported + +- The Dashboard component does not provide any dedicated export functionality for personal data. +- Favourites data is not included in any XML or file-based export. +- Data presented on the Dashboard (e.g., course memberships, learning progress, badges) is managed + and potentially exported by the respective integrated components. diff --git a/components/ILIAS/DataCollection/classes/Fields/Base/class.ilDclBaseRecordFieldModel.php b/components/ILIAS/DataCollection/classes/Fields/Base/class.ilDclBaseRecordFieldModel.php index 7b0098a58d19..925196938e72 100755 --- a/components/ILIAS/DataCollection/classes/Fields/Base/class.ilDclBaseRecordFieldModel.php +++ b/components/ILIAS/DataCollection/classes/Fields/Base/class.ilDclBaseRecordFieldModel.php @@ -295,10 +295,10 @@ public function getSortingValue(bool $link = true) public function addHiddenItemsToConfirmation(ilConfirmationGUI $confirmation) { if (!is_array($this->getValue())) { - $confirmation->addHiddenItem('field_' . $this->field->getId(), (string) $this->getValue()); + $confirmation->addHiddenItem('field_' . $this->field->getId(), htmlspecialchars((string) $this->getValue())); } else { foreach ($this->getValue() as $key => $value) { - $confirmation->addHiddenItem('field_' . $this->field->getId() . "[$key]", (string) $value); + $confirmation->addHiddenItem('field_' . $this->field->getId() . "[$key]", htmlspecialchars((string) $value)); } } } diff --git a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextFieldModel.php b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextFieldModel.php index 9e0fd02ac6a1..69c0d86fbd71 100755 --- a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextFieldModel.php +++ b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextFieldModel.php @@ -46,8 +46,8 @@ public function checkValidityFromForm(ilPropertyFormGUI &$form, ?int $record_id) { if ($this->getProperty(ilDclBaseFieldModel::PROP_URL)) { $value = [ - 'link' => $form->getInput("field_" . $this->getId()), 'title' => $form->getInput("field_" . $this->getId() . "_title"), + 'link' => $form->getInput("field_" . $this->getId()), ]; } else { $value = $form->getInput('field_' . $this->getId()); diff --git a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php index 63ee41fde0c1..09d956f935c7 100755 --- a/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php +++ b/components/ILIAS/DataCollection/classes/Fields/Text/class.ilDclTextRecordFieldModel.php @@ -26,8 +26,8 @@ public function setValueFromForm(ilPropertyFormGUI $form): void { if ($this->getField()->hasProperty(ilDclBaseFieldModel::PROP_URL)) { $value = [ - "link" => $form->getInput("field_" . $this->getField()->getId()), "title" => $form->getInput("field_" . $this->getField()->getId() . '_title'), + "link" => $form->getInput("field_" . $this->getField()->getId()), ]; } else { $value = $form->getInput("field_" . $this->getField()->getId()); @@ -116,7 +116,7 @@ public function getValueFromExcel(ilExcel $excel, int $row, int $col) if ($excel->getCell(1, $col + 1) == $this->getField()->getTitle() . '_title') { $title = $excel->getCell($row, $col + 1); } - $value = ['link' => $value, 'title' => $title]; + $value = ['title' => $title, 'link' => $value]; } if ($value) { diff --git a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps10.php b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps10.php index b530c8186c50..b4b6d9a2a69e 100644 --- a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps10.php +++ b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps10.php @@ -56,4 +56,31 @@ public function step_1(): void ['text_area'] ); } + + public function step_2(): void + { + $stmt = $this->db->queryF( + 'SELECT il_dcl_stloc1_value.* FROM il_dcl_stloc1_value ' . + 'INNER JOIN il_dcl_record_field ON il_dcl_record_field.id = il_dcl_stloc1_value.record_field_id ' . + 'INNER JOIN il_dcl_field ON il_dcl_field.id = il_dcl_record_field.field_id ' . + 'WHERE il_dcl_field.datatype_id = %s AND il_dcl_stloc1_value.value LIKE %s', + [ilDBConstants::T_INTEGER, ilDBConstants::T_TEXT], + [ilDclDatatype::INPUTFORMAT_TEXT, "{%"] + ); + + while ($row = $this->db->fetchAssoc($stmt)) { + $old = json_decode($row['value'], true); + if (isset($old['title']) && isset($old['link'])) { + $value = json_encode([ + 'title' => $old['title'], + 'link' => $old['link'], + ]); + $this->db->update( + 'il_dcl_stloc1_value', + ['value' => [ilDBConstants::T_TEXT, $value]], + ['id' => [ilDBConstants::T_INTEGER, $row['id']]], + ); + } + } + } } diff --git a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps11.php b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps11.php index 2dbfac2e9d34..205e78dc715e 100644 --- a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps11.php +++ b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps11.php @@ -119,4 +119,43 @@ public function step_4(): void $this->db->addPrimaryKey('il_dcl_notification', ['obj_id', 'usr_id', 'setting']); } } + + public function step_5(): void + { + $stmt = $this->db->queryF( + 'SELECT * FROM page_object INNER JOIN il_dcl_tableview ON page_id = id WHERE rendered_content IS NOT NULL AND parent_type = %s', + [ilDBConstants::T_TEXT], + [ilDclDetailedViewDefinition::PARENT_TYPE] + ); + + while ($row = $this->db->fetchAssoc($stmt)) { + $tableview = new ilDclTableView((int) $row['page_id']); + $content = $row['content']; + $rendered_content = $row['rendered_content']; + + foreach (['id', 'create_date', 'last_update', 'owner', 'last_edit_by'] as $field) { + $content = str_replace('[' . $field . ']', '[[' . $field . ']]', $content); + $content = str_replace('[[[' . $field . ']]]', '[[' . $field . ']]', $content); + $rendered_content = str_replace('[' . $field . ']', '[[' . $field . ']]', $rendered_content); + $rendered_content = str_replace('[[[' . $field . ']]]', '[[' . $field . ']]', $rendered_content); + } + + $sub_stmt = $this->db->queryF( + 'SELECT * FROM il_dcl_field WHERE table_id = %s', + [ilDBConstants::T_INTEGER], + [(int) $row['table_id']] + ); + while ($field = $this->db->fetchAssoc($sub_stmt)) { + $old = ['[' . $field['title'] . ']','[dclrefln field="' . $field['title'] . '"][/dclrefln]' ]; + $content = str_replace($old, '[[' . $field['id'] . ']]', $content); + $rendered_content = str_replace($old, '[[' . $field['id'] . ']]', $rendered_content); + } + + $this->db->manipulateF( + 'UPDATE page_object SET content = %s, rendered_content = %s WHERE page_id = %s', + [ilDBConstants::T_TEXT, ilDBConstants::T_TEXT, ilDBConstants::T_INTEGER], + [$content, $rendered_content, (int) $row['page_id']] + ); + } + } } diff --git a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps9.php b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps9.php index 1ec4c0435b1f..625fe0d6a2c3 100755 --- a/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps9.php +++ b/components/ILIAS/DataCollection/classes/Setup/class.ilDataCollectionDBUpdateSteps9.php @@ -313,41 +313,7 @@ public function step_17(): void public function step_18(): void { - $stmt = $this->db->queryF( - 'SELECT * FROM page_object INNER JOIN il_dcl_tableview ON page_id = id WHERE rendered_content IS NOT NULL AND parent_type = %s', - [ilDBConstants::T_TEXT], - [ilDclDetailedViewDefinition::PARENT_TYPE] - ); - - while ($row = $this->db->fetchAssoc($stmt)) { - $tableview = new ilDclTableView((int) $row['page_id']); - $content = $row['content']; - $rendered_content = $row['rendered_content']; - - foreach (['id', 'create_date', 'last_update', 'owner', 'last_edit_by'] as $field) { - $content = str_replace('[' . $field . ']', '[[' . $field . ']]', $content); - $content = str_replace('[[[' . $field . ']]]', '[[' . $field . ']]', $content); - $rendered_content = str_replace('[' . $field . ']', '[[' . $field . ']]', $rendered_content); - $rendered_content = str_replace('[[[' . $field . ']]]', '[[' . $field . ']]', $rendered_content); - } - - $sub_stmt = $this->db->queryF( - 'SELECT * FROM il_dcl_field WHERE table_id = %s', - [ilDBConstants::T_INTEGER], - [(int) $row['table_id']] - ); - while ($field = $this->db->fetchAssoc($sub_stmt)) { - $old = ['[' . $field['title'] . ']','[dclrefln field="' . $field['title'] . '"][/dclrefln]' ]; - $content = str_replace($old, '[[' . $field['id'] . ']]', $content); - $rendered_content = str_replace($old, '[[' . $field['id'] . ']]', $rendered_content); - } - - $this->db->manipulateF( - 'UPDATE page_object SET content = %s, rendered_content = %s WHERE page_id = %s', - [ilDBConstants::T_TEXT, ilDBConstants::T_TEXT, ilDBConstants::T_INTEGER], - [$content, $rendered_content, (int) $row['page_id']] - ); - } + //Moved to ILIAS 11 } public function step_19(): void diff --git a/components/ILIAS/Database/classes/PDO/ilDBPdo.php b/components/ILIAS/Database/classes/PDO/ilDBPdo.php index 276f9f8da593..108dfaeb1194 100755 --- a/components/ILIAS/Database/classes/PDO/ilDBPdo.php +++ b/components/ILIAS/Database/classes/PDO/ilDBPdo.php @@ -102,7 +102,7 @@ protected function getAttributes(): array { return [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, + PDO\Mysql::ATTR_USE_BUFFERED_QUERY => true, PDO::ATTR_TIMEOUT => 300 * 60, ]; } diff --git a/components/ILIAS/Database/classes/Setup/ilDatabaseSetupConfig.php b/components/ILIAS/Database/classes/Setup/ilDatabaseSetupConfig.php index 06d7b651fcb2..226b7d2f0213 100755 --- a/components/ILIAS/Database/classes/Setup/ilDatabaseSetupConfig.php +++ b/components/ILIAS/Database/classes/Setup/ilDatabaseSetupConfig.php @@ -24,7 +24,7 @@ class ilDatabaseSetupConfig implements Config { public const DEFAULT_COLLATION = "utf8_general_ci"; - public const DEFAULT_PATH_TO_DB_DUMP = "./components/ILIAS/setup_/sql/ilias3.sql"; + public const DEFAULT_PATH_TO_DB_DUMP = "./components/ILIAS/Database/sql/ilias3.sql"; protected string $type; diff --git a/components/ILIAS/Database/classes/ilDBUpdate.php b/components/ILIAS/Database/classes/ilDBUpdate.php index 3ada9b047045..926a6fa0df31 100755 --- a/components/ILIAS/Database/classes/ilDBUpdate.php +++ b/components/ILIAS/Database/classes/ilDBUpdate.php @@ -250,7 +250,7 @@ private function readCustomUpdatesInfo(bool $a_force = false): void } $this->custom_updates_setting = new ilSetting(); - $custom_updates_file = $this->PATH . './components/ILIAS/setup_/sql/dbupdate_custom.php'; + $custom_updates_file = $this->PATH . './components/ILIAS/Database/sql/dbupdate_custom.php'; if (is_file($custom_updates_file)) { $this->custom_updates_content = @file($custom_updates_file); $this->custom_updates_current_version = (int) $this->custom_updates_setting->get('db_version_custom', '0'); diff --git a/components/ILIAS/setup_/sql/ilias3.sql b/components/ILIAS/Database/sql/ilias3.sql similarity index 100% rename from components/ILIAS/setup_/sql/ilias3.sql rename to components/ILIAS/Database/sql/ilias3.sql diff --git a/components/ILIAS/DidacticTemplate/tests/ilDidacticTemplatePatternTest.php b/components/ILIAS/DidacticTemplate/tests/ilDidacticTemplatePatternTest.php index d5ff54cb3a20..ef23377e9d88 100755 --- a/components/ILIAS/DidacticTemplate/tests/ilDidacticTemplatePatternTest.php +++ b/components/ILIAS/DidacticTemplate/tests/ilDidacticTemplatePatternTest.php @@ -74,16 +74,11 @@ protected function initPatternDependencies(): void $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); - $logger = $this->getMockBuilder(ilLogger::class) - ->disableOriginalConstructor() - ->getMock(); + $logger = $this->createStub(ilLogger::class); - $logger_factory = $this->getMockBuilder(ilLoggerFactory::class) - ->disableOriginalConstructor() - ->onlyMethods(['getComponentLogger']) - ->getMock(); + $logger_factory = $this->createStub(ilLoggerFactory::class); $logger_factory->method('getComponentLogger')->willReturn($logger); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); } diff --git a/components/ILIAS/EmployeeTalk/PRIVACY.md b/components/ILIAS/EmployeeTalk/PRIVACY.md new file mode 100644 index 000000000000..08f28738a96e --- /dev/null +++ b/components/ILIAS/EmployeeTalk/PRIVACY.md @@ -0,0 +1,186 @@ +# EmployeeTalk Privacy + +**Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing +or incorrect information via [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories).** + +## Integrated Components + +The **EmployeeTalk** component integrates various ILIAS components. Please consult the respective privacy documentation: + +- [OrgUnit](../OrgUnit/PRIVACY.md) provides information about accounts' assignment to **organisational units**, + what accounts they have authority over, and which permissions this authority grants them via + the **position access** mechanism. +- [AdvancedMetadata](../AdvancedMetaData/PRIVACY.md) provides **custom metadata sets** that can be + attached to talk templates, and filled out for talks. +- **Calendar** is used to add talks as appointments to personal calendars. +- [Mail](../Mail/PRIVACY.md) is used to send notifications about talks. +- **User** handles **account identification**, provides names, logins, and email addresses from the **personal profile data** of accounts, + as well as their **personal preferences**, and is used to register a 'User action'. +- **ILIASObject**, [Container](../Container/PRIVACY.md), and **Tree** are used + to handle the hierarchy of template administration, templates, talk series, + and talks, as well as their owners, titles, and descriptions. +- [AccessControl](../AccessControl/PRIVACY.md) is used to check role-based permissions. +- [Staff](../MyStaff/PRIVACY.md) is used to check access via **OrgUnit** positions to the talk views within + the 'Organisation' main menu entry. +- [InfoScreen](../InfoScreen/PRIVACY.md) to offer an 'Info'-tab in templates, + the template administration, and in talks. + +## General Information + +Talks carry a 'location' field (handled by **EmployeeTalk** itself), +a title and description (handled by **ILIASObject**), +as well as further fields from attached **Custom Metadata** +sets (if configured). The latter are intended to be used as minutes for +the talks. All of these fields are filled out manually, but are likely +to contain personal data of at least the employee involved in the talk. + +Note that talks share their title with the series they are a part of. +The title is stored redundantly, again by **ILIASObject**. + +### Access to Talks + +Access in **EmployeeTalk** depends mostly on the position access configuration +of **OrgUnit**, and its concept of authority. The corresponding permissions in the +**OrgUnit** position administration are 'Read access talk appointments', +'Create talk appointments / edit talk appointments that you have created yourself', +and 'Edit Talk appointments', and relate to access to talks as follows: + +- **Create:** The current account has the 'Create talk appointments / edit talk appointments that you have created yourself' + permission over the employee. Access to the creation dialogue is granted if + the account has any position with that permission. +- **Read:** Does not affect whether a talk is shown in the [talk list](#talk-list). + The current account is either superior or employee of the talk, or they have the + 'Read access talk appointments' permission over the employee. +- **Edit:** The current account is either superior of the talk, or they have the + 'Edit Talk appointments' permission over the employee. If the setting + 'Lock the editing of all appointments in this series' is enabled in + the series, only the superior can edit. +- **Delete:** The current account is superior of the talk and has read-access to the talk template + administration via RBAC (AccessControl), or they have the global 'Administrator' role. + +Note that the root account can always access every talk, and can always create +a talk. If position access for 'Employee Talks' is deactivated, only the root +account can access and create talks. + +## Data being stored + +**EmployeeTalk** itself stores the following data for each talk: + +- **Superior** and **Employee** of the talk, by their user ID. +- **Start Date** and **End Date** of the talk, including whether it is an all day event. +- **Location** of the talk. +- Whether the talk has been **completed** already. + +## Data being presented + +### Talk List + +A list of talks is offered under the same main menu entry as the various +views of the **Staff** component, and is available +under similar conditions: 'Enable Main Menu Entry' must be +enabled in the **OrgUnit** settings, and the current account must have +at least one of the 'Employee Talk' position access permissions over at least one account under their authority. + +The list contains all talks where the current account, or an account they +have the 'Read access talk appointments' permission over, is superior +or employee. The following data is shown for every talk: + +- **Title** of the talk. +- **Superior** and **Employee** of the talk, by their login. If the corresponding + user ID doesn't exist, for example because the account was deleted, 'Unknown User' + is shown instead +- **Start Date** and **End Date** of the talk, with time if applicable. +- Completion **Status** of the talk. + +Aside from the main talk list, an account-specific talk list is +offered. It is identical to the main list (in content and conditions of +access), except that it only contains talks where the selected +account is employee. It is only available under the additional condition +that the current user has authority over the selected user. + +From the talk lists, talks can be created if the current account +has [create access](#access-to-talks). There, an autocomplete +is offered when typing in the employee. Suggestions are only shown +after at least three letters are already entered, and only +accounts which the current account can [create talks for](#access-to-talks) +are shown. + +### Talk + +In the talks themselves, in addition what is included in the +[talk list](#talk-list), the following data is shown: + +- **Title** and **Description** of the talk. +- **Location** of the talk. +- The attached **Custom Metadata** fields. +- The **Info**-tab of the talk. There the superior of the talk + is listed as its **owner**, but only to accounts with the global + 'Administrator' role (and the superior themselves). They are identified via their **login**. + If their personal profile is published via the User component, + their **first name**, **last name**, and a **link to their profile** are + also shown. + +This data is available to accounts with [read or edit access](#access-to-talks) +to the talk. Accounts with the latter can also edit these fields +(except for **Superior** and **Employee**, which can't be changed at all). + +Additionally, editing the talk allows enabling the setting +'Lock the editing of all appointments in this series', with which +one can prevent editing of talks in the same series by anyone +but the superior themselves. + +### Calendar Appointments + +The employee and superior of a talk have the talk as an appointment +in their personal calendar, only accessible by them, with the following data: + +- **Superior** and **Employee** of the talk, by first and last name. + If the account's profile is published via the **User** component, + their personal profile is linked. +- **Date and Time of the last change** of the talk's date and time. + +Additionally, the [talk](#talk) itself is linked. + +### Notifications + +When a talk (series) is created, deleted, or its settings or dates changed, +a system notification is sent to the employee, with the superior in CC. +This notification includes the following data: + +- **Title** and **Description** of the talks. +- **Location** of the talks. +- **Superior** of the talks by full name, including title if available, + as given by the **User** component. +- **Start Date** and **End Date** of the talks, with time if applicable. + +The notification also includes a link to the first [talk](#talk) in the series. Attached +to the notification is an ics-file, which includes in addition to the above: + +- **Employee** of the talks by full name, including title if available, + as given by the **User** component. + +With the ics-file, the talk series can be imported as events into external +calendar applications. + +## Data being deleted + +Talks can be deleted via the [talk list](#talk-list) (both main +and account-specific), by accounts with [delete access](#access-to-talks). + +Talks circumvent the trash, they are always removed permanently +from the system. When a talk is deleted, the [data stored](#data-being-stored) +by the component itself is deleted, as well as the corresponding +data handled by **ILIASObject**, and the appointments in personal +calendars. + +When the last talk in a series is deleted, the series is deleted +along with it. + +Note that deletion of an account does not trigger the deletion of +talks with that account as superior or employee. Their user ID +is stored with those talks until the talks are deleted. + +## Data being exported + +[Notifications](#notifications) about talks include ics-files as +attachments, see above for details. diff --git a/components/ILIAS/EmployeeTalk/classes/Talk/class.ilEmployeeTalkAppointmentGUI.php b/components/ILIAS/EmployeeTalk/classes/Talk/class.ilEmployeeTalkAppointmentGUI.php index 5fe1af5663db..3d3e754e819f 100755 --- a/components/ILIAS/EmployeeTalk/classes/Talk/class.ilEmployeeTalkAppointmentGUI.php +++ b/components/ILIAS/EmployeeTalk/classes/Talk/class.ilEmployeeTalkAppointmentGUI.php @@ -46,6 +46,7 @@ final class ilEmployeeTalkAppointmentGUI implements ControlFlowCommandHandler private Refinery $refinery; private ilTabsGUI $tabs; protected NotificationHandlerInterface $notif_handler; + private ilTree $tree; private ilObjEmployeeTalk $talk; public function __construct( @@ -56,6 +57,7 @@ public function __construct( Refinery $refinery, ilTabsGUI $tabs, NotificationHandlerInterface $notif_handler, + ilTree $tree, ilObjEmployeeTalk $talk ) { $this->template = $template; @@ -65,6 +67,7 @@ public function __construct( $this->refinery = $refinery; $this->tabs = $tabs; $this->notif_handler = $notif_handler; + $this->tree = $tree; $this->talk = $talk; $this->language->loadLanguageModule('cal'); @@ -534,7 +537,10 @@ private function getPendingTalksInSeries(ilObjEmployeeTalkSeries $series): array private function deleteTalks(array $talks): void { foreach ($talks as $talk) { + $ref_id = $talk->getRefId(); + $node_data = $this->tree->getNodeData($talk->getRefId()); $talk->delete(); + $this->tree->deleteNode($node_data['tree'], $ref_id); } } diff --git a/components/ILIAS/EmployeeTalk/classes/Talk/class.ilObjEmployeeTalkGUI.php b/components/ILIAS/EmployeeTalk/classes/Talk/class.ilObjEmployeeTalkGUI.php index 96d014ec8df9..caa7f9a29375 100755 --- a/components/ILIAS/EmployeeTalk/classes/Talk/class.ilObjEmployeeTalkGUI.php +++ b/components/ILIAS/EmployeeTalk/classes/Talk/class.ilObjEmployeeTalkGUI.php @@ -144,6 +144,7 @@ public function executeCommand(): void $this->refinery, $this->tabs_gui, $this->notif_handler, + $this->tree, $this->object ); $this->ctrl->forwardCommand($appointmentGUI); @@ -224,17 +225,20 @@ public function confirmedDeleteObject(): void return; } + $ref_ids = []; if ($this->post_wrapper->has("interruptive_items")) { - $ref_id = $this->post_wrapper->retrieve( + $ref_ids = $this->post_wrapper->retrieve( "interruptive_items", $this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->int()) ); - $saved_post = array_unique(array_merge(ilSession::get('saved_post') ?? [], $ref_id)); - ilSession::set('saved_post', $saved_post); + } + + if ($ref_ids === []) { + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('no_checkbox'), true); + $this->redirectToParentGUI(); } $ru = new ilRepositoryTrashGUI($this); - $ref_ids = ilSession::get("saved_post"); $talks = []; foreach ($ref_ids as $refId) { diff --git a/components/ILIAS/Exercise/Submission/SubmissionManager.php b/components/ILIAS/Exercise/Submission/SubmissionManager.php index d17a454deb79..9993180d3256 100644 --- a/components/ILIAS/Exercise/Submission/SubmissionManager.php +++ b/components/ILIAS/Exercise/Submission/SubmissionManager.php @@ -621,10 +621,24 @@ protected function copySubmissionFilesToDir( \ilFileUtils::makeDirParents($dir); $file = $dir . DIRECTORY_SEPARATOR . $targetfile; if (!is_null($stream)) { - file_put_contents( - $file, - $stream->getContents() - ); + $source_stream = $stream->detach(); + if (!is_resource($source_stream)) { + throw new \RuntimeException('Unable to read submission stream.'); + } + + $target_stream = fopen($file, 'wb'); + if ($target_stream === false) { + throw new \RuntimeException("Unable to open file for writing: $file"); + } + + try { + stream_copy_to_stream( + $source_stream, + $target_stream + ); + } finally { + fclose($target_stream); + } } // unzip blog/portfolio diff --git a/components/ILIAS/Exercise/Submission/class.SubmissionRepository.php b/components/ILIAS/Exercise/Submission/class.SubmissionRepository.php index 2471253c9fe4..aa007f778438 100755 --- a/components/ILIAS/Exercise/Submission/class.SubmissionRepository.php +++ b/components/ILIAS/Exercise/Submission/class.SubmissionRepository.php @@ -464,12 +464,22 @@ public function addZipUpload( $this->log->debug("6"); $stream = $this->irss->stream($rid); + $unzip = $DIC->archives()->unzip($stream); + + // an archive beyond the extraction limits yields no streams at all, so it has to be + // rejected explicitly instead of being stored as an empty submission + if (!$unzip->isWithinLimits()) { + throw new ilExcTooManyFilesSubmittedException( + "The submitted ZIP exceeds the configured extraction limits." + ); + } + if ($remaining_allowed !== -1 && - $remaining_allowed < $DIC->archives()->unzip($stream)->getAmountOfFiles()) { + $remaining_allowed < $unzip->getAmountOfFiles()) { throw new ilExcTooManyFilesSubmittedException("Too many files submitted."); } - foreach ($DIC->archives()->unzip($stream)->getFileStreams() as $stream) { + foreach ($unzip->getFileStreams() as $stream) { $this->log->debug("7"); $rid = $this->irss->importStream( $stream, diff --git a/components/ILIAS/Exercise/Submission/class.ilExSubmissionFileGUI.php b/components/ILIAS/Exercise/Submission/class.ilExSubmissionFileGUI.php index 5031b34c3194..b4c1e66967eb 100755 --- a/components/ILIAS/Exercise/Submission/class.ilExSubmissionFileGUI.php +++ b/components/ILIAS/Exercise/Submission/class.ilExSubmissionFileGUI.php @@ -270,10 +270,10 @@ protected function getUploadForm(): \ILIAS\Repository\Form\FormAdapterGUI "deliver", $this->lng->txt("files"), $this->handleUploadResult(...), - "mep_id", + "filename", "", $max_file - ); + )->required(true); return $form_adapter; } @@ -282,30 +282,40 @@ protected function handleUploadResult( \ILIAS\FileUpload\DTO\UploadResult $result ): \ILIAS\FileUpload\Handler\BasicHandlerResult { $title = $result->getName(); - - //$this->submission->addFileUpload($result); - $subm = $this->domain->submission($this->assignment->getId()); - $subm->addUpload( - $this->user->getid(), - $result, - $title - ); - + if ($result->isOK()) { + $subm = $this->domain->submission($this->assignment->getId()); + $subm->addUpload( + $this->user->getId(), + $result, + $title + ); + return new \ILIAS\FileUpload\Handler\BasicHandlerResult( + 'filename', + \ILIAS\FileUpload\Handler\HandlerResult::STATUS_OK, + $title, + '' + ); + } return new \ILIAS\FileUpload\Handler\BasicHandlerResult( '', - \ILIAS\FileUpload\Handler\HandlerResult::STATUS_OK, - $title, - '' + \ILIAS\FileUpload\Handler\HandlerResult::STATUS_FAILED, + '', + $result->getStatus()->getMessage() ); } public function addUploadObject(): void { $ilCtrl = $this->ctrl; - $this->tpl->setOnScreenMessage('success', $this->lng->txt("file_added"), true); - $this->handleNewUpload(); - - $ilCtrl->redirect($this, "submissionScreen"); + $mt = $this->gui->ui()->mainTemplate(); + $form = $this->getUploadForm(); + if ($form->isValid()) { + $this->tpl->setOnScreenMessage('success', $this->lng->txt("file_added"), true); + $this->handleNewUpload(); + $ilCtrl->redirect($this, "submissionScreen"); + } else { + $mt->setContent($form->render()); + } } diff --git a/components/ILIAS/Exercise/Submission/class.ilExerciseSubmissionFeedbackGUI.php b/components/ILIAS/Exercise/Submission/class.ilExerciseSubmissionFeedbackGUI.php index fd7958d69f36..4c7b397f3f72 100644 --- a/components/ILIAS/Exercise/Submission/class.ilExerciseSubmissionFeedbackGUI.php +++ b/components/ILIAS/Exercise/Submission/class.ilExerciseSubmissionFeedbackGUI.php @@ -135,17 +135,21 @@ protected function validateAndSubmitFeedbackForm(): void $ass_id = $request->getAssId(); $ass = $this->domain->assignment()->getAssignment($ass_id); $comment = $form->getData("comment"); - $member_status = $ass->getMemberStatus($user_id); - $member_status->setComment($comment); - $member_status->setFeedback(true); - $member_status->update(); - if (trim($comment) !== '' && trim($comment) !== '0') { - $this->notification->sendFeedbackNotification( - $ass_id, - [$user_id], - "", - true - ); + $submission = new ilExSubmission($ass, $user_id); + $user_ids = $submission->getUserIds(); + foreach ($user_ids as $user_id) { + $member_status = $ass->getMemberStatus($user_id); + $member_status->setComment($comment); + $member_status->setFeedback(true); + $member_status->update(); + if (trim($comment) !== '' && trim($comment) !== '0') { + $this->notification->sendFeedbackNotification( + $ass_id, + [$user_id], + "", + true + ); + } } $cmd = $request->getParticipantId() ? "showParticipant" diff --git a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileManager.php b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileManager.php index 3f3d1e45a94a..a3b8f05fa5b7 100755 --- a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileManager.php +++ b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileManager.php @@ -69,6 +69,8 @@ public function getStakeholder(): ResourceStakeholder public function addObserver(): void { + $log = $this->domain->log(); + $log->debug("------------- addObserver ---------------"); $this->domain->resourceStorage()->events()->attach( $this->file_observer, Event::COLLECTION_RESOURCE_ADDED @@ -78,6 +80,7 @@ public function addObserver(): void public function sendNotification(string $rcid, string $rid): void { $log = $this->domain->log(); + $log->debug("------------- sendNotification ---------------"); $log->debug("Ass id: " . $this->ass_id); $exc_id = \ilExAssignment::lookupExerciseId($this->ass_id); @@ -91,21 +94,26 @@ public function sendNotification(string $rcid, string $rid): void $log->debug("Get notification"); $notification = $this->domain->notification($ref_id); $log->debug("Get participant"); + // this might be a team id (or a user id) $part_id = $this->repo->getParticipantIdForRcid($this->ass_id, $rcid); + // this is a user id (might be first from team) + $user_id = $this->repo->getUserIdForRcid($this->ass_id, $rcid); $log->debug("Get filename"); - $filename = $this->repo->getFilenameForRid($this->ass_id, $part_id, $rid); + $filename = $this->repo->getFilenameForRid($this->ass_id, $user_id, $rid); $log->debug("Get assignment"); $ass = new \ilExAssignment($this->ass_id); $log->debug("Get submission"); - $submission = new \ilExSubmission($ass, $part_id); + $log->debug("Part id: " . $part_id); + $log->debug("User id: " . $user_id); + $submission = new \ilExSubmission($ass, $user_id); $feedback_id = $submission->getFeedbackId(); $noti_rec_ids = $submission->getUserIds(); $log->debug("Feedback id: " . $feedback_id); if ($feedback_id) { if ($noti_rec_ids) { - foreach ($noti_rec_ids as $user_id) { - $member_status = $ass->getMemberStatus($user_id); + foreach ($noti_rec_ids as $note_user_id) { + $member_status = $ass->getMemberStatus($note_user_id); $member_status->setFeedback(true); $member_status->update(); } @@ -177,27 +185,27 @@ public function deleteCollection(int $participant_id): void ); } - public function getFiles(int $participant_id): array + public function getFiles(int $user_id): array { $files = []; - if ($this->repo->hasCollection($this->ass_id, $participant_id)) { + if ($this->repo->hasCollection($this->ass_id, $user_id)) { $files = array_map(function (ResourceInformation $info): string { return $info->getTitle(); - }, iterator_to_array($this->repo->getCollectionResourcesInfo($this->ass_id, $participant_id))); + }, iterator_to_array($this->repo->getCollectionResourcesInfo($this->ass_id, $user_id))); } return $files; } - public function deliver(int $participant_id, string $file): void + public function deliver(int $user_id, string $file): void { $assignment = $this->domain->assignment()->getAssignment($this->ass_id); if ($assignment->notStartedYet()) { return; } - if ($this->repo->hasCollection($this->ass_id, $participant_id)) { + if ($this->repo->hasCollection($this->ass_id, $user_id)) { // IRSS - $this->repo->deliverFile($this->ass_id, $participant_id, $file); + $this->repo->deliverFile($this->ass_id, $user_id, $file); } } diff --git a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepository.php b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepository.php index 53db9beb92bc..01b0acc01b36 100755 --- a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepository.php +++ b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepository.php @@ -102,10 +102,10 @@ public function count(int $ass_id, int $user_id): int return 0; } - public function deliverFile($ass_id, $participant_id, $file): void + public function deliverFile($ass_id, $user_id, $file): void { /** @var ResourceInformation $info */ - foreach ($this->getCollectionResourcesInfo($ass_id, $participant_id) as $info) { + foreach ($this->getCollectionResourcesInfo($ass_id, $user_id) as $info) { if ($file === $info->getTitle()) { $this->wrapper->deliverFile($info->getRid()); } @@ -113,9 +113,9 @@ public function deliverFile($ass_id, $participant_id, $file): void throw new \ilExerciseException("Resource $file not found."); } - public function getFilenameForRid(int $ass_id, int $part_id, string $rid): string + public function getFilenameForRid(int $ass_id, int $user_id, string $rid): string { - foreach ($this->getCollectionResourcesInfo($ass_id, $part_id) as $info) { + foreach ($this->getCollectionResourcesInfo($ass_id, $user_id) as $info) { if ($rid === $info->getRid()) { return $info->getTitle(); } @@ -135,6 +135,11 @@ public function getParticipantIdForRcid(int $ass_id, string $rcid): int return (int) ($rec["usr_id"] ?? 0); } + public function getUserIdForRcid(int $ass_id, string $rcid): int + { + return $this->getParticipantIdForRcid($ass_id, $rcid); + } + /** * @return \Iterator */ diff --git a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepositoryInterface.php b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepositoryInterface.php index 6c73ef068813..f5a8a997c740 100755 --- a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepositoryInterface.php +++ b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileRepositoryInterface.php @@ -46,6 +46,6 @@ public function deleteCollection( public function getParticipantIdForRcid(int $ass_id, string $rcid): int; - public function getFilenameForRid(int $ass_id, int $part_id, string $rid): string; + public function getFilenameForRid(int $ass_id, int $user_id, string $rid): string; } diff --git a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileTeamRepository.php b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileTeamRepository.php index 319e09d3e608..18f2313bd025 100755 --- a/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileTeamRepository.php +++ b/components/ILIAS/Exercise/TutorFeedbackFile/TutorFeedbackFileTeamRepository.php @@ -24,6 +24,7 @@ use ILIAS\ResourceStorage\Collection\ResourceCollection; use ILIAS\ResourceStorage\Stakeholder\ResourceStakeholder; use ILIAS\Repository\IRSS\ResourceInformation; +use ilLoggerFactory; class TutorFeedbackFileTeamRepository implements TutorFeedbackFileRepositoryInterface { @@ -53,6 +54,20 @@ protected function getTeamId(int $ass_id, int $user_id): int return 0; } + protected function getOneUserIdOfTeam(int $ass_id, int $team_id): int + { + $set = $this->db->queryF( + "SELECT user_id FROM il_exc_team " . + " WHERE ass_id = %s AND id = %s", + ["integer", "integer"], + [$ass_id, $team_id] + ); + if ($rec = $this->db->fetchAssoc($set)) { + return (int) $rec["user_id"]; + } + return 0; + } + public function createCollection(int $ass_id, int $user_id): void { $team_id = $this->getTeamId($ass_id, $user_id); @@ -83,6 +98,12 @@ public function getParticipantIdForRcid(int $ass_id, string $rcid): int return (int) ($rec["id"] ?? 0); } + public function getUserIdForRcid(int $ass_id, string $rcid): int + { + $team_id = $this->getParticipantIdForRcid($ass_id, $rcid); + return $this->getOneUserIdOfTeam($ass_id, $team_id); + } + public function getIdStringForAssIdAndUserId(int $ass_id, int $user_id): string { @@ -123,10 +144,10 @@ public function count(int $ass_id, int $user_id): int return 0; } - public function deliverFile($ass_id, $participant_id, $file): void + public function deliverFile($ass_id, $user_id, $file): void { /** @var ResourceInformation $info */ - foreach ($this->getCollectionResourcesInfo($ass_id, $participant_id) as $info) { + foreach ($this->getCollectionResourcesInfo($ass_id, $user_id) as $info) { if ($file === $info->getTitle()) { $this->wrapper->deliverFile($info->getRid()); } @@ -134,11 +155,10 @@ public function deliverFile($ass_id, $participant_id, $file): void throw new \ilExerciseException("Resource $file not found."); } - public function getFilenameForRid(int $ass_id, int $part_id, string $rid): string + public function getFilenameForRid(int $ass_id, int $user_id, string $rid): string { - foreach ($this->getCollectionResourcesInfo($ass_id, $part_id) as $info) { + foreach ($this->getCollectionResourcesInfo($ass_id, $user_id) as $info) { if ($rid === $info->getRid()) { - $this->wrapper->deliverFile($info->getRid()); return $info->getTitle(); } } diff --git a/components/ILIAS/Export/tests/DataSet/DataSetImportParserTest.php b/components/ILIAS/Export/tests/DataSet/DataSetImportParserTest.php index 6c30008ddb48..be2aa03e54a7 100755 --- a/components/ILIAS/Export/tests/DataSet/DataSetImportParserTest.php +++ b/components/ILIAS/Export/tests/DataSet/DataSetImportParserTest.php @@ -39,8 +39,8 @@ protected function tearDown(): void public function testInstanceAndParseValidXML(): void { - $map_mock = $this->createMock(ilImportMapping::class); - $ds_mock = $this->createMock(ilDataSet::class); + $map_mock = $this->createStub(ilImportMapping::class); + $ds_mock = $this->createStub(ilDataSet::class); $parser = new ilDataSetImportParser( "ent", "1.0.0", diff --git a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Link/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Link/HandlerTest.php index 955084a0be16..07d3259baaca 100644 --- a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Link/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Link/HandlerTest.php @@ -35,10 +35,10 @@ public function testExportHandlerPublicAccessLink(): void $reference_id = 1; $uri_mock = $this->createMock(Uri::class); $uri_mock->expects($this->once())->method("__toString")->willReturn($download_url); - $reference_id_mock = $this->createMock(ReferenceId::class); + $reference_id_mock = $this->createStub(ReferenceId::class); $reference_id_mock->method("toInt")->willReturn($reference_id); $reference_id_mock->method("toObjectId")->willThrowException(new Exception("unexpected conversion to object id")); - $static_url_wrapper_mock = $this->createMock(ilExportHandlerPublicAccessLinkStaticURLWrapperInterface::class); + $static_url_wrapper_mock = $this->createStub(ilExportHandlerPublicAccessLinkStaticURLWrapperInterface::class); $static_url_wrapper_mock->method("withStaticURL")->willThrowException(new Exception("unexpected overwrite of static URL service object")); $static_url_wrapper_mock->method("buildDownloadURI")->willReturn($uri_mock); try { diff --git a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Element/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Element/HandlerTest.php index 49cdf36e4932..1c91863bd821 100644 --- a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Element/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Element/HandlerTest.php @@ -31,17 +31,17 @@ class HandlerTest extends TestCase { public function testExportHandlerPublicAccessRepositoryElement(): void { - $object_id_mock_01 = $this->createMock(ObjectId::class); + $object_id_mock_01 = $this->createStub(ObjectId::class); $object_id_mock_01->method("toInt")->willReturn(20); $object_id_mock_01->method("toReferenceIds")->willThrowException(new Exception("unexpected reference id access")); - $values_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryValuesInteface::class); + $values_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryValuesInteface::class); $values_mock->method("isValid")->willReturn(true); $values_mock->method("getIdentification")->willReturn("id"); $values_mock->method("withIdentification")->willThrowException(new Exception("unexpected id overwrite")); $values_mock->method("getExportOptionId")->willReturn("exp_id"); $values_mock->method("withExportOptionId")->willThrowException(new Exception("unexpected exp id overwrite")); $values_mock->method("getLastModified")->willThrowException(new Exception("unexpected last modified access")); - $values_not_storable_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryValuesInteface::class); + $values_not_storable_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryValuesInteface::class); $values_not_storable_mock->method("isValid")->willReturn(false); $values_not_storable_mock->method("getIdentification")->willThrowException(new Exception("unexpected id access")); $values_not_storable_mock->method("withIdentification")->willThrowException(new Exception("unexpected id overwrite")); @@ -54,11 +54,11 @@ public function testExportHandlerPublicAccessRepositoryElement(): void $values_not_storable_mock->method("equals")->willReturnMap([ [$values_mock, false], [$values_not_storable_mock, true] ]); - $key_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock->method("isValid")->willReturn(true); $key_mock->method("getObjectId")->willReturn($object_id_mock_01); $key_mock->method("withObjectId")->willThrowException(new Exception("unexpected object id overwrite")); - $key_not_storable_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_not_storable_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_not_storable_mock->method("isValid")->willReturn(false); $key_not_storable_mock->method("getObjectId")->willThrowException(new Exception("unexpected object id access")); $key_not_storable_mock->method("withObjectId")->willThrowException(new Exception("unexpected object id overwrite")); diff --git a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/HandlerTest.php index 06d1a5ba19f3..b1d662559831 100644 --- a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/HandlerTest.php @@ -44,31 +44,31 @@ public function testExportHandlerPublicAccessRepository(): void { $this->repository_elements = []; - $object_id_mock_01 = $this->createMock(ObjectId::class); + $object_id_mock_01 = $this->createStub(ObjectId::class); $object_id_mock_01->method("toInt")->willReturn(1); $object_id_mock_01->method("toReferenceIds")->willThrowException(new UnexpectedValueException("unexpected method call")); - $object_id_mock_02 = $this->createMock(ObjectId::class); + $object_id_mock_02 = $this->createStub(ObjectId::class); $object_id_mock_02->method("toInt")->willReturn(2); $object_id_mock_02->method("toReferenceIds")->willThrowException(new UnexpectedValueException("unexpected method call")); - $object_id_mock_03 = $this->createMock(ObjectId::class); + $object_id_mock_03 = $this->createStub(ObjectId::class); $object_id_mock_03->method("toInt")->willReturn(3); $object_id_mock_03->method("toReferenceIds")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_mock_01 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_01 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_01->method("getObjectId")->willReturn($object_id_mock_01); $key_mock_01->method("withObjectId")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_mock_01->method("equals")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_mock_01->method("isValid")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_mock_02 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_02 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_02->method("getObjectId")->willReturn($object_id_mock_02); $key_mock_02->method("withObjectId")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_mock_02->method("equals")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_mock_02->method("isValid")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_mock_03 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_03 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_03->method("getObjectId")->willReturn($object_id_mock_03); $key_mock_03->method("withObjectId")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_mock_03->method("equals")->willThrowException(new UnexpectedValueException("unexpected method call")); @@ -80,7 +80,7 @@ public function testExportHandlerPublicAccessRepository(): void $element_mock_01->method("withValues")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_mock_01->method("withKey")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_mock_01->method("isStorable")->willReturn(true); - $element_mock_01->method("equals")->with($element_mock_01)->willReturn(true); + $element_mock_01->expects($this->atLeastOnce())->method("equals")->with($element_mock_01)->willReturn(true); $element_mock_02 = $this->createMock(ilExportHandlerPublicAccessRepositoryElementInterface::class); $element_mock_02->method("getValues")->willThrowException(new UnexpectedValueException("unexpected method call")); @@ -88,17 +88,9 @@ public function testExportHandlerPublicAccessRepository(): void $element_mock_02->method("withValues")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_mock_02->method("withKey")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_mock_02->method("isStorable")->willReturn(true); - $element_mock_02->method("equals")->with($element_mock_02)->willReturn(true); + $element_mock_02->expects($this->atLeastOnce())->method("equals")->with($element_mock_02)->willReturn(true); - $element_not_storable_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryElementInterface::class); - $element_not_storable_mock->method("getValues")->willThrowException(new UnexpectedValueException("unexpected method call")); - $element_not_storable_mock->method("getKey")->willReturn($key_mock_03); - $element_not_storable_mock->method("withValues")->willThrowException(new UnexpectedValueException("unexpected method call")); - $element_not_storable_mock->method("withKey")->willThrowException(new UnexpectedValueException("unexpected method call")); - $element_not_storable_mock->method("isStorable")->willReturn(false); - $element_not_storable_mock->method("equals")->with($element_not_storable_mock)->willReturn(true); - - $key_collection_01_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); + $key_collection_01_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); # next, rewind are void $key_collection_01_mock->method("key")->willReturn(0, 1); $key_collection_01_mock->method("valid")->willReturn(true, false); @@ -106,7 +98,7 @@ public function testExportHandlerPublicAccessRepository(): void $key_collection_01_mock->method("current")->willReturn($key_mock_01); $key_collection_01_mock->method("withElement")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_collection_02_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); + $key_collection_02_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); # next, rewind are void $key_collection_02_mock->method("key")->willReturn(0, 1); $key_collection_02_mock->method("valid")->willReturn(true, false); @@ -114,7 +106,7 @@ public function testExportHandlerPublicAccessRepository(): void $key_collection_02_mock->method("current")->willReturn($key_mock_02); $key_collection_02_mock->method("withElement")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_collection_03_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); + $key_collection_03_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); # next, rewind are void $key_collection_03_mock->method("key")->willReturn(0, 1); $key_collection_03_mock->method("valid")->willReturn(true, false); @@ -122,7 +114,7 @@ public function testExportHandlerPublicAccessRepository(): void $key_collection_03_mock->method("current")->willReturn($key_mock_03); $key_collection_03_mock->method("withElement")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_collection_all_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); + $key_collection_all_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); # next, rewind are void $key_collection_all_mock->method("key")->willReturn(0, 1, 2); $key_collection_all_mock->method("valid")->willReturn(true, true, false); @@ -130,7 +122,7 @@ public function testExportHandlerPublicAccessRepository(): void $key_collection_all_mock->method("current")->willReturn($key_mock_01, $key_mock_02); $key_collection_all_mock->method("withElement")->willThrowException(new UnexpectedValueException("unexpected method call")); - $key_collection_empty_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); + $key_collection_empty_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyCollectionInterface::class); # next, rewind are void $key_collection_empty_mock->method("key")->willReturn(0); $key_collection_empty_mock->method("valid")->willReturn(false); @@ -142,11 +134,11 @@ public function testExportHandlerPublicAccessRepository(): void [$key_mock_03, $key_collection_03_mock], ]); - $key_factory_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyFactoryInterface::class); + $key_factory_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyFactoryInterface::class); $key_factory_mock->method("handler")->willThrowException(new UnexpectedValueException("unexpected method call")); $key_factory_mock->method("collection")->willReturn($key_collection_empty_mock); - $db_wrapper_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryDBWrapperInterface::class); + $db_wrapper_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryDBWrapperInterface::class); $db_wrapper_mock->method("storeElement")->willReturnCallback(function ($x) { $this->mockDBWrapperStore($x); }); @@ -219,13 +211,13 @@ public function testExportHandlerPublicAccessRepository(): void } protected function mockDBWrapperStore( - ilExportHandlerPublicAccessRepositoryElementInterface&MockObject $element_mock + ilExportHandlerPublicAccessRepositoryElementInterface $element_mock ): void { $this->repository_elements[] = $element_mock; } protected function mockDBWrapperRemoveByKeyCollection( - ilExportHandlerPublicAccessRepositoryKeyCollectionInterface&MockObject $key_collection_mock + ilExportHandlerPublicAccessRepositoryKeyCollectionInterface $key_collection_mock ): void { $ids = []; for ($i = 0; $i < count($key_collection_mock); $i++) { @@ -241,8 +233,8 @@ protected function mockDBWrapperRemoveByKeyCollection( } protected function mockDBWrapperGetElementsByKeyCollection( - ilExportHandlerPublicAccessRepositoryKeyCollectionInterface&MockObject $key_collection_mock - ): ilExportHandlerPublicAccessRepositoryElementCollectionInterface&MockObject { + ilExportHandlerPublicAccessRepositoryKeyCollectionInterface $key_collection_mock + ): ilExportHandlerPublicAccessRepositoryElementCollectionInterface { $elements = []; for ($i = 0; $i < $key_collection_mock->count(); $i++) { $current = $key_collection_mock->current(); @@ -252,7 +244,7 @@ protected function mockDBWrapperGetElementsByKeyCollection( } } } - $element_collection_mock = $this->createMock(ilExportHandlerPublicAccessRepositoryElementCollectionInterface::class); + $element_collection_mock = $this->createStub(ilExportHandlerPublicAccessRepositoryElementCollectionInterface::class); $element_collection_mock->method("withElement")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_collection_mock->method("key")->willThrowException(new UnexpectedValueException("unexpected method call")); $element_collection_mock->method("next")->willThrowException(new UnexpectedValueException("unexpected method call")); diff --git a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/Collection.php b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/Collection.php index c7408b11b632..8522332a6889 100644 --- a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/Collection.php +++ b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/Collection.php @@ -30,24 +30,24 @@ class Collection extends TestCase { public function testExportHandlerPublicAccessRepositoryKeyCollection(): void { - $object_id_mock_01 = $this->createMock(ObjectId::class); + $object_id_mock_01 = $this->createStub(ObjectId::class); $object_id_mock_01->method("toInt")->willReturn(1); $object_id_mock_01->method("toReferenceIds")->willThrowException(new Exception("unexpected access of reference ids")); - $object_id_mock_02 = $this->createMock(ObjectId::class); + $object_id_mock_02 = $this->createStub(ObjectId::class); $object_id_mock_02->method("toInt")->willReturn(2); $object_id_mock_02->method("toReferenceIds")->willThrowException(new Exception("unexpected access of reference ids")); - $object_id_mock_03 = $this->createMock(ObjectId::class); + $object_id_mock_03 = $this->createStub(ObjectId::class); $object_id_mock_03->method("toInt")->willReturn(3); $object_id_mock_03->method("toReferenceIds")->willThrowException(new Exception("unexpected access of reference ids")); - $key_mock_01 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_01 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_01->method("isValid")->willReturn(true); $key_mock_01->method("getObjectId")->willReturn($object_id_mock_01); $key_mock_01->method("withObjectId")->willThrowException(new Exception("unexpected overwrite of object id")); - $key_mock_02 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_02 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_02->method("isValid")->willReturn(true); $key_mock_02->method("getObjectId")->willReturn($object_id_mock_02); $key_mock_02->method("withObjectId")->willThrowException(new Exception("unexpected overwrite of object id")); - $key_mock_03 = $this->createMock(ilExportHandlerPublicAccessRepositoryKeyInterface::class); + $key_mock_03 = $this->createStub(ilExportHandlerPublicAccessRepositoryKeyInterface::class); $key_mock_03->method("isValid")->willReturn(true); $key_mock_03->method("getObjectId")->willReturn($object_id_mock_03); $key_mock_03->method("withObjectId")->willThrowException(new Exception("unexpected overwrite of object id")); diff --git a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/HandlerTest.php index 587742a9f1e5..f0099fbee61c 100644 --- a/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/PublicAccess/Repository/Key/HandlerTest.php @@ -32,13 +32,13 @@ class HandlerTest extends TestCase public function testExportHandlerPublicAccessRepositoryKey(): void { $object_id = 2; - $object_id_mock = $this->createMock(ObjectId::class); + $object_id_mock = $this->createStub(ObjectId::class); $object_id_mock->method("toInt")->willReturn($object_id); $object_id_mock->method("toReferenceIds")->willThrowException(new Exception("unexpected access of reference ids")); - $object_id_invalid_mock = $this->createMock(ObjectId::class); + $object_id_invalid_mock = $this->createStub(ObjectId::class); $object_id_invalid_mock->method('toInt')->willReturn(ilExportHandlerPublicAccessRepositoryKeyInterface::EMPTY_OBJECT_ID); $object_id_invalid_mock->method("toReferenceIds")->willThrowException(new Exception("toReferenceIds should not be called")); - $df_factory_wrapper_mock = $this->createMock(ilExportHandlerDataFactoryWrapperInterface::class); + $df_factory_wrapper_mock = $this->createStub(ilExportHandlerDataFactoryWrapperInterface::class); $df_factory_wrapper_mock->method('objId')->willReturn($object_id_invalid_mock); try { $key = new ilExportHandlerPublicAccessRepositoryKey($df_factory_wrapper_mock); diff --git a/components/ILIAS/Export/tests/ExportHandler/Repository/Element/CollectionTest.php b/components/ILIAS/Export/tests/ExportHandler/Repository/Element/CollectionTest.php index ff41f6e268f8..e7a228cb4916 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Repository/Element/CollectionTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/Repository/Element/CollectionTest.php @@ -34,21 +34,21 @@ public function testExportHandlerRepositoryElementCollection(): void $date_1 = new DateTimeImmutable('2020-01-01'); $date_2 = new DateTimeImmutable('2020-01-02'); $date_3 = new DateTimeImmutable('2020-01-03'); - $values_mock_01 = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $values_mock_01 = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $values_mock_01->method("getCreationDate")->willReturn($date_1); - $values_mock_02 = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $values_mock_02 = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $values_mock_02->method("getCreationDate")->willReturn($date_2); - $values_mock_03 = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $values_mock_03 = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $values_mock_03->method("getCreationDate")->willReturn($date_2); - $values_mock_04 = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $values_mock_04 = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $values_mock_04->method("getCreationDate")->willReturn($date_3); - $element_mock_01 = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_mock_01 = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_mock_01->method('getValues')->willReturn($values_mock_01); - $element_mock_02 = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_mock_02 = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_mock_02->method('getValues')->willReturn($values_mock_02); - $element_mock_03 = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_mock_03 = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_mock_03->method('getValues')->willReturn($values_mock_03); - $element_mock_04 = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_mock_04 = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_mock_04->method('getValues')->willReturn($values_mock_04); $element_mock_01->method("equals")->willReturnMap([ [$element_mock_01, true], [$element_mock_02, false], diff --git a/components/ILIAS/Export/tests/ExportHandler/Repository/Element/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/Repository/Element/HandlerTest.php index d42b88463b10..b90e9b636c0c 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Repository/Element/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/Repository/Element/HandlerTest.php @@ -37,31 +37,31 @@ class HandlerTest extends TestCase public function testExportHandlerRepositoryElement(): void { $resouce_id_serialized = "keykeykey"; - $object_id_mock = $this->createMock(ObjectId::class); - $key_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $object_id_mock = $this->createStub(ObjectId::class); + $key_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $key_mock->method("isCompleteKey")->willReturn(true); $key_mock->method("isObjectIdKey")->willReturn(false); $key_mock->method("isResourceIdKey")->willReturn(false); $key_mock->method("getResourceIdSerialized")->willReturn($resouce_id_serialized); $key_mock->method("getObjectId")->willReturn($object_id_mock); - $date_time_mock = $this->createMock(DateTimeImmutable::class); - $value_mock = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $date_time_mock = $this->createStub(DateTimeImmutable::class); + $value_mock = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $value_mock->method("isValid")->willReturn(true); $value_mock->method("getOwnerId")->willReturn(1); $value_mock->method("getCreationDate")->willReturn($date_time_mock); $irss_wrapper_mock = $this->createMock(ilExportHandlerRepositoryElementIRSSWrapperInterface::class); - $irss_wrapper_mock->method("withResourceIdSerialized")->with($resouce_id_serialized)->willReturn($irss_wrapper_mock); - $irss_wrapper_factory_mock = $this->createMock(ilExportHandlerRepositoryElementIRSSWrapperFactoryInterface::class); + $irss_wrapper_mock->expects($this->atLeastOnce())->method("withResourceIdSerialized")->with($resouce_id_serialized)->willReturn($irss_wrapper_mock); + $irss_wrapper_factory_mock = $this->createStub(ilExportHandlerRepositoryElementIRSSWrapperFactoryInterface::class); $irss_wrapper_factory_mock->method("handler")->willReturn($irss_wrapper_mock); $irss_info_wrapper_mock = $this->createMock(ilExportHandlerRepositoryElementIRSSInfoWrapperInterface::class); - $irss_info_wrapper_mock->method("withResourceIdSerialized")->with($resouce_id_serialized)->willReturn($irss_info_wrapper_mock); - $irss_info_wrapper_factory_mock = $this->createMock(ilExportHandlerRepositoryElementIRSSInfoWrapperFactoryInterface::class); + $irss_info_wrapper_mock->expects($this->atLeastOnce())->method("withResourceIdSerialized")->with($resouce_id_serialized)->willReturn($irss_info_wrapper_mock); + $irss_info_wrapper_factory_mock = $this->createStub(ilExportHandlerRepositoryElementIRSSInfoWrapperFactoryInterface::class); $irss_info_wrapper_factory_mock->method("handler")->willReturn($irss_info_wrapper_mock); try { - $element = (new ilExportHandlerRepositoryElement( + $element = new ilExportHandlerRepositoryElement( $irss_wrapper_factory_mock, $irss_info_wrapper_factory_mock - )) + ) ->withKey($key_mock) ->withValues($value_mock); $element_not_storable_0 = new ilExportHandlerRepositoryElement( diff --git a/components/ILIAS/Export/tests/ExportHandler/Repository/Handler.php b/components/ILIAS/Export/tests/ExportHandler/Repository/Handler.php index ce2f4ce0452e..60e44c0afc20 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Repository/Handler.php +++ b/components/ILIAS/Export/tests/ExportHandler/Repository/Handler.php @@ -47,35 +47,35 @@ public function testExportHandlerRepository(): void $resource_id_serialized = "rid"; $owner_id = 6; $creation_date = new DateTimeImmutable(); - $element_collection_mock01 = $this->createMock(ilExportHandlerRepositoryElementCollectionInterface::class); - $stakeholder_mock = $this->createMock(ilExportHandlerRepositoryStakeholderInterface::class); + $element_collection_mock01 = $this->createStub(ilExportHandlerRepositoryElementCollectionInterface::class); + $stakeholder_mock = $this->createStub(ilExportHandlerRepositoryStakeholderInterface::class); $stakeholder_mock->method("getOwnerId")->willReturn($owner_id); $stakeholder_mock->method("withOwnerId")->willThrowException(new Exception("owner id changed")); $this->repository_elements = []; - $object_id_mock01 = $this->createMock(ObjectId::class); + $object_id_mock01 = $this->createStub(ObjectId::class); $object_id_mock01->method("toInt")->willReturn(1); $object_id_mock01->method("toReferenceIds")->willThrowException(new Exception("unexpected method call")); - $key_complete_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $key_complete_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $key_complete_mock->method("withObjectId")->with($object_id_mock01)->willReturn($key_complete_mock); $key_complete_mock->method("withResourceIdSerialized")->with($resource_id_serialized)->willReturn($key_complete_mock); $key_complete_mock->method("getObjectId")->willReturn($object_id_mock01); $key_complete_mock->method("getResourceIdSerialized")->willReturn($resource_id_serialized); - $key_obj_id_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $key_obj_id_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $key_obj_id_mock->method("withObjectId")->with($object_id_mock01)->willReturn($key_obj_id_mock); $key_obj_id_mock->method("withResourceIdSerialized")->with($resource_id_serialized)->willReturn($key_complete_mock); $key_obj_id_mock->method("getObjectId")->willReturn($object_id_mock01); $key_obj_id_mock->method("getResourceIdSerialized")->willThrowException(new Exception("resource id not set")); - $key_res_id_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $key_res_id_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $key_res_id_mock->method("withObjectId")->with($object_id_mock01)->willReturn($key_complete_mock); $key_res_id_mock->method("withResourceIdSerialized")->with($resource_id_serialized)->willReturn($key_res_id_mock); $key_res_id_mock->method("getObjectId")->willThrowException(new Exception("obj id not set")); $key_res_id_mock->method("getResourceIdSerialized")->willReturn($resource_id_serialized); - $key_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $key_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $key_mock->method("withObjectId")->with($object_id_mock01)->willReturn($key_obj_id_mock); $key_mock->method("withResourceIdSerialized")->with($resource_id_serialized)->willReturn($key_res_id_mock); $key_mock->method("getObjectId")->willThrowException(new Exception("obj id not set")); $key_mock->method("getResourceIdSerialized")->willThrowException(new Exception("resource id not set")); - $key_collection_with_element_mock = $this->createMock(ilExportHandlerRepositoryKeyCollectionInterface::class); + $key_collection_with_element_mock = $this->createStub(ilExportHandlerRepositoryKeyCollectionInterface::class); $key_collection_with_element_mock->method("withElement")->willThrowException(new Exception("to many keys added to collection")); $key_collection_with_element_mock->method("current")->willReturn($key_complete_mock); $key_collection_with_element_mock->method("key")->willReturn(0, 1); @@ -83,7 +83,7 @@ public function testExportHandlerRepository(): void # rewind() does not return anything $key_collection_with_element_mock->method("valid")->willReturn(true, false); $key_collection_with_element_mock->method("count")->willReturn(1); - $key_collection_mock01 = $this->createMock(ilExportHandlerRepositoryKeyCollectionInterface::class); + $key_collection_mock01 = $this->createStub(ilExportHandlerRepositoryKeyCollectionInterface::class); $key_collection_mock01->method("withElement")->with($key_complete_mock)->willReturn($key_collection_with_element_mock); $key_collection_mock01->method("withElement")->with($key_mock)->willThrowException(new Exception("key incomplete")); $key_collection_mock01->method("withElement")->with($key_obj_id_mock)->willThrowException(new Exception("key incomplete")); @@ -94,39 +94,39 @@ public function testExportHandlerRepository(): void # rewind() does not return anything $key_collection_mock01->method("valid")->willReturn(false); $key_collection_mock01->method("count")->willReturn(0); - $key_factory_mock = $this->createMock(ilExportHandlerRepositoryKeyFactoryInterface::class); + $key_factory_mock = $this->createStub(ilExportHandlerRepositoryKeyFactoryInterface::class); $key_factory_mock->method("handler")->willReturn($key_mock); $key_factory_mock->method("collection")->willReturn($key_collection_mock01); - $export_info_mock = $this->createMock(ilExportHandlerExportInfoInterface::class); - $irss_wrapper_mock = $this->createMock(ilExportHandlerRepositoryIRSSWrapperInterface::class); + $export_info_mock = $this->createStub(ilExportHandlerExportInfoInterface::class); + $irss_wrapper_mock = $this->createStub(ilExportHandlerRepositoryIRSSWrapperInterface::class); $irss_wrapper_mock->method('createEmptyContainer')->with($export_info_mock, $stakeholder_mock)->willReturn($resource_id_serialized); $irss_wrapper_mock->method("getCreationDate")->with($resource_id_serialized)->willReturn($creation_date); - $value_mock = $this->createMock(ilExportHandlerRepositoryValuesInterface::class); + $value_mock = $this->createStub(ilExportHandlerRepositoryValuesInterface::class); $value_mock->method("withOwnerId")->with($owner_id)->willReturn($value_mock); $value_mock->method("withCreationDate")->with($creation_date)->willReturn($value_mock); $value_mock->method("getOwnerId")->willReturn($owner_id); $value_mock->method("getCreationDate")->willReturn($creation_date); - $values_factory_mock = $this->createMock(ilExportHandlerRepositoryValuesFactoryInterface::class); + $values_factory_mock = $this->createStub(ilExportHandlerRepositoryValuesFactoryInterface::class); $values_factory_mock->method("handler")->willReturn($value_mock); - $element_complete_mock = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_complete_mock = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_complete_mock->method("isStorable")->willReturn(true); $element_complete_mock->method("withKey")->with($key_mock)->willReturn($element_complete_mock); $element_complete_mock->method("withValues")->with($value_mock)->willReturn($element_complete_mock); - $element_w_key_mock = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_w_key_mock = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_w_key_mock->method("isStorable")->willReturn(false); $element_w_key_mock->method("withKey")->with($key_mock)->willReturn($element_w_key_mock); $element_w_key_mock->method("withValues")->with($value_mock)->willReturn($element_complete_mock); - $element_w_values_mock = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_w_values_mock = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_w_values_mock->method("isStorable")->willReturn(false); $element_w_values_mock->method("withKey")->with($key_mock)->willReturn($element_complete_mock); $element_w_values_mock->method("withValues")->with($value_mock)->willReturn($element_w_values_mock); - $element_emtpy_mock = $this->createMock(ilExportHandlerRepositoryElementInterface::class); + $element_emtpy_mock = $this->createStub(ilExportHandlerRepositoryElementInterface::class); $element_emtpy_mock->method("isStorable")->willReturn(false); $element_emtpy_mock->method("withKey")->with($key_mock)->willReturn($element_w_key_mock); $element_emtpy_mock->method("withValues")->with($value_mock)->willReturn($element_w_values_mock); - $element_factory_mock = $this->createMock(ilExportHandlerRepositoryElementFactoryInterface::class); + $element_factory_mock = $this->createStub(ilExportHandlerRepositoryElementFactoryInterface::class); $element_factory_mock->method("handler")->willReturn($element_emtpy_mock); - $db_wrapper_mock = $this->createMock(ilExportHandlerRepositoryDBWrapperInterface::class); + $db_wrapper_mock = $this->createStub(ilExportHandlerRepositoryDBWrapperInterface::class); $db_wrapper_mock->method("getElements")->with($key_collection_mock01)->willReturnCallback(function ($x) { return $this->mockDBWrapperGetElements($x); }); diff --git a/components/ILIAS/Export/tests/ExportHandler/Repository/Key/CollectionTest.php b/components/ILIAS/Export/tests/ExportHandler/Repository/Key/CollectionTest.php index 72c7fa9534d3..747fb5b0690c 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Repository/Key/CollectionTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/Repository/Key/CollectionTest.php @@ -30,19 +30,19 @@ class CollectionTest extends TestCase { public function testExportHandlerRepositoryKeyCollection(): void { - $object_id_mock_01 = $this->createMock(ObjectId::class); + $object_id_mock_01 = $this->createStub(ObjectId::class); $object_id_mock_01->method('toInt')->willReturn(1); - $object_id_mock_02 = $this->createMock(ObjectId::class); + $object_id_mock_02 = $this->createStub(ObjectId::class); $object_id_mock_02->method('toInt')->willReturn(2); - $object_id_mock_03 = $this->createMock(ObjectId::class); + $object_id_mock_03 = $this->createStub(ObjectId::class); $object_id_mock_03->method('toInt')->willReturn(3); - $element_1_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $element_1_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $element_1_mock->method('getResourceIdSerialized')->willReturn('r1'); $element_1_mock->method('getObjectId')->willReturn($object_id_mock_01); - $element_2_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $element_2_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $element_2_mock->method('getResourceIdSerialized')->willReturn('r2'); $element_2_mock->method('getObjectId')->willReturn($object_id_mock_02); - $element_3_mock = $this->createMock(ilExportHandlerRepositoryKeyInterface::class); + $element_3_mock = $this->createStub(ilExportHandlerRepositoryKeyInterface::class); $element_3_mock->method('getResourceIdSerialized')->willReturn('r3'); $element_3_mock->method('getObjectId')->willReturn($object_id_mock_03); $empty_collection = new ilExportHandlerRepositoryKeyCollection(); diff --git a/components/ILIAS/Export/tests/ExportHandler/Repository/Key/HandlerTest.php b/components/ILIAS/Export/tests/ExportHandler/Repository/Key/HandlerTest.php index 8a9c48a34129..4267caa22237 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Repository/Key/HandlerTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/Repository/Key/HandlerTest.php @@ -32,13 +32,13 @@ class HandlerTest extends TestCase public function testExportHandlerRepositoryKey(): void { $resource_identification = "abc"; - $object_id_mock = $this->createMock(ObjectId::class); + $object_id_mock = $this->createStub(ObjectId::class); $object_id_mock->method('toInt')->willReturn(123); $object_id_mock->method("toReferenceIds")->willThrowException(new Exception("toReferenceIds should not be called")); - $object_id_invalid_mock = $this->createMock(ObjectId::class); + $object_id_invalid_mock = $this->createStub(ObjectId::class); $object_id_invalid_mock->method('toInt')->willReturn(ilExportHandlerRepositoryKeyInterface::EMPTY_OBJECT_ID); $object_id_invalid_mock->method("toReferenceIds")->willThrowException(new Exception("toReferenceIds should not be called")); - $df_factory_wrapper_mock = $this->createMock(ilExportHandlerDataFactoryWrapperInterface::class); + $df_factory_wrapper_mock = $this->createStub(ilExportHandlerDataFactoryWrapperInterface::class); $df_factory_wrapper_mock->method('objId')->willReturn($object_id_invalid_mock); try { $repository_key_empty = new ilExportHandlerRepositoryKey( diff --git a/components/ILIAS/Export/tests/ExportHandler/Table/RowId/CollectionTest.php b/components/ILIAS/Export/tests/ExportHandler/Table/RowId/CollectionTest.php index 76fc2d8c8f3a..76bd0b275d0a 100644 --- a/components/ILIAS/Export/tests/ExportHandler/Table/RowId/CollectionTest.php +++ b/components/ILIAS/Export/tests/ExportHandler/Table/RowId/CollectionTest.php @@ -29,15 +29,15 @@ class CollectionTest extends TestCase { public function testExportHandlerTableRowIdCollection(): void { - $table_row_id_mock_1 = $this->createMock(ilExportHandlerTableRowIdInterface::class); + $table_row_id_mock_1 = $this->createStub(ilExportHandlerTableRowIdInterface::class); $table_row_id_mock_1->method('getFileIdentifier')->willReturn("1"); $table_row_id_mock_1->method('getExportOptionId')->willReturn("e"); $table_row_id_mock_1->method('getCompositId')->willReturn("e:1"); - $table_row_id_mock_2 = $this->createMock(ilExportHandlerTableRowIdInterface::class); + $table_row_id_mock_2 = $this->createStub(ilExportHandlerTableRowIdInterface::class); $table_row_id_mock_2->method('getFileIdentifier')->willReturn("2"); $table_row_id_mock_2->method('getExportOptionId')->willReturn("e"); $table_row_id_mock_2->method('getCompositId')->willReturn("e:2"); - $table_row_id_mock_3 = $this->createMock(ilExportHandlerTableRowIdInterface::class); + $table_row_id_mock_3 = $this->createStub(ilExportHandlerTableRowIdInterface::class); $table_row_id_mock_3->method('getFileIdentifier')->willReturn("3"); $table_row_id_mock_3->method('getExportOptionId')->willReturn("e"); $table_row_id_mock_3->method('getCompositId')->willReturn("e:3"); diff --git a/components/ILIAS/Export/tests/ImportHandler/File/HandlerTest.php b/components/ILIAS/Export/tests/ImportHandler/File/HandlerTest.php index 1e9928b297d3..ea3086e3497f 100755 --- a/components/ILIAS/Export/tests/ImportHandler/File/HandlerTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/File/HandlerTest.php @@ -35,15 +35,15 @@ public function testFileHandler(): void . 'B' . DIRECTORY_SEPARATOR . 'C'; $file_path = $file_dir . DIRECTORY_SEPARATOR . $file_name; - $namespaces = $this->createMock(ilFileNamespaceCollection::class); + $namespaces = $this->createStub(ilFileNamespaceCollection::class); - $namespace = $this->createMock(ilFileNamespaceFactory::class); - $namespace->expects($this->any())->method('collection')->willReturn($namespaces); + $namespace = $this->createStub(ilFileNamespaceFactory::class); + $namespace->method('collection')->willReturn($namespaces); - $file_info = $this->createMock(SplFileInfo::class); - $file_info->expects($this->any())->method('getFilename')->willReturn($file_name); - $file_info->expects($this->any())->method('getRealPath')->willReturn(false); - $file_info->expects($this->any())->method('getPath')->willReturn($file_dir); + $file_info = $this->createStub(SplFileInfo::class); + $file_info->method('getFilename')->willReturn($file_name); + $file_info->method('getRealPath')->willReturn(false); + $file_info->method('getPath')->willReturn($file_dir); $file_handler = new ilFileHandler($namespace); $file_handler = $file_handler->withFileInfo($file_info); diff --git a/components/ILIAS/Export/tests/ImportHandler/File/Namespace/CollectionTest.php b/components/ILIAS/Export/tests/ImportHandler/File/Namespace/CollectionTest.php index 0f0b0d2e69ff..7e57a77ca727 100755 --- a/components/ILIAS/Export/tests/ImportHandler/File/Namespace/CollectionTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/File/Namespace/CollectionTest.php @@ -29,7 +29,7 @@ class CollectionTest extends TestCase { protected function setUp(): void { - $namespace_1 = $this->createMock(ilFileNamespaceHandler::class); + $namespace_1 = $this->createStub(ilFileNamespaceHandler::class); } /** @@ -55,24 +55,24 @@ protected function checkCollection( public function testCollection(): void { - $namespace_1 = $this->createMock(ilFileNamespaceHandler::class); - $namespace_1->expects($this->any())->method('getNamespace')->willReturn('namespace_1'); - $namespace_1->expects($this->any())->method('getPrefix')->willReturn('prefix_1'); + $namespace_1 = $this->createStub(ilFileNamespaceHandler::class); + $namespace_1->method('getNamespace')->willReturn('namespace_1'); + $namespace_1->method('getPrefix')->willReturn('prefix_1'); - $namespace_2 = $this->createMock(ilFileNamespaceHandler::class); - $namespace_2->expects($this->any())->method('getNamespace')->willReturn('namespace_2'); - $namespace_2->expects($this->any())->method('getPrefix')->willReturn('prefix_2'); + $namespace_2 = $this->createStub(ilFileNamespaceHandler::class); + $namespace_2->method('getNamespace')->willReturn('namespace_2'); + $namespace_2->method('getPrefix')->willReturn('prefix_2'); - $namespace_3 = $this->createMock(ilFileNamespaceHandler::class); - $namespace_3->expects($this->any())->method('getNamespace')->willReturn('namespace_3'); - $namespace_3->expects($this->any())->method('getPrefix')->willReturn('prefix_3'); + $namespace_3 = $this->createStub(ilFileNamespaceHandler::class); + $namespace_3->method('getNamespace')->willReturn('namespace_3'); + $namespace_3->method('getPrefix')->willReturn('prefix_3'); - $collection_one_element = (new ilFileNamespaceCollection()) + $collection_one_element = new ilFileNamespaceCollection() ->withElement($namespace_1); - $collection_two_elements = (new ilFileNamespaceCollection()) + $collection_two_elements = new ilFileNamespaceCollection() ->withElement($namespace_1) ->withElement($namespace_2); - $collection_three_elements = (new ilFileNamespaceCollection()) + $collection_three_elements = new ilFileNamespaceCollection() ->withElement($namespace_1) ->withElement($namespace_2) ->withElement($namespace_3); diff --git a/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/Attribute/ilCollectionTest.php b/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/Attribute/ilCollectionTest.php index 89884d765755..601eb8f7c158 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/Attribute/ilCollectionTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/Attribute/ilCollectionTest.php @@ -30,31 +30,31 @@ class ilCollectionTest extends TestCase { public function testNodeInfoAttributeCollection(): void { - $logger = $this->createMock(ilLogger::class); - $node_info = $this->createMock(ilXMLFileNodeInfoDOMNodeHandler::class); - $node_info->expects($this->any())->method('getValueOfAttribute')->willReturnMap([ + $logger = $this->createStub(ilLogger::class); + $node_info = $this->createStub(ilXMLFileNodeInfoDOMNodeHandler::class); + $node_info->method('getValueOfAttribute')->willReturnMap([ ['key1', 'val1'], ['key2', 'val2'], ['key3', 'val3'], ]); - $node_info->expects($this->any())->method('hasAttribute')->willReturnMap([ + $node_info->method('hasAttribute')->willReturnMap([ ['key1', true], ['key2', true], ['key3', true], ['key4', false] ]); - $pair1 = $this->createMock(ilXMLFileNodeInfoAttributePair::class); - $pair1->expects($this->any())->method('getKey')->willReturn('key1'); - $pair1->expects($this->any())->method('getValue')->willReturn('val1'); - $pair2 = $this->createMock(ilXMLFileNodeInfoAttributePair::class); - $pair2->expects($this->any())->method('getKey')->willReturn('key2'); - $pair2->expects($this->any())->method('getValue')->willReturn('val2'); - $pair3 = $this->createMock(ilXMLFileNodeInfoAttributePair::class); - $pair3->expects($this->any())->method('getKey')->willReturn('key3'); - $pair3->expects($this->any())->method('getValue')->willReturn('val3'); - $pair4 = $this->createMock(ilXMLFileNodeInfoAttributePair::class); - $pair4->expects($this->any())->method('getKey')->willReturn('key4'); - $pair4->expects($this->any())->method('getValue')->willReturn('val4'); + $pair1 = $this->createStub(ilXMLFileNodeInfoAttributePair::class); + $pair1->method('getKey')->willReturn('key1'); + $pair1->method('getValue')->willReturn('val1'); + $pair2 = $this->createStub(ilXMLFileNodeInfoAttributePair::class); + $pair2->method('getKey')->willReturn('key2'); + $pair2->method('getValue')->willReturn('val2'); + $pair3 = $this->createStub(ilXMLFileNodeInfoAttributePair::class); + $pair3->method('getKey')->willReturn('key3'); + $pair3->method('getValue')->willReturn('val3'); + $pair4 = $this->createStub(ilXMLFileNodeInfoAttributePair::class); + $pair4->method('getKey')->willReturn('key4'); + $pair4->method('getValue')->willReturn('val4'); $collection = (new ilXMLFileNodeInfoAttributeCollection($logger)) ->withElement($pair1) diff --git a/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/ilCollectionTest.php b/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/ilCollectionTest.php index a5418672e3e2..4975007eb24e 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/ilCollectionTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Parser/NodeInfo/ilCollectionTest.php @@ -28,9 +28,9 @@ class ilCollectionTest extends TestCase { public function testNodeInfoCollection(): void { - $node1 = $this->createMock(Handler::class); - $node2 = $this->createMock(Handler::class); - $node3 = $this->createMock(Handler::class); + $node1 = $this->createStub(Handler::class); + $node2 = $this->createStub(Handler::class); + $node3 = $this->createStub(Handler::class); $collection = new Collection(); $collection = $collection->withElement($node1); diff --git a/components/ILIAS/Export/tests/ImportHandler/Path/HandlerTest.php b/components/ILIAS/Export/tests/ImportHandler/Path/HandlerTest.php index 01a96908b221..4576efc267e7 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Path/HandlerTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Path/HandlerTest.php @@ -33,15 +33,15 @@ protected function setUp(): void public function testPath(): void { - $node1 = $this->createMock(ilSimpleFilePathNode::class); - $node1->expects($this->any())->method('toString')->willReturn('Node1'); - $node1->expects($this->any())->method('requiresPathSeparator')->willReturn(true); - $node2 = $this->createMock(ilSimpleFilePathNode::class); - $node2->expects($this->any())->method('toString')->willReturn('Node2'); - $node2->expects($this->any())->method('requiresPathSeparator')->willReturn(true); - $node3 = $this->createMock(ilSimpleFilePathNode::class); - $node3->expects($this->any())->method('toString')->willReturn('Node3'); - $node3->expects($this->any())->method('requiresPathSeparator')->willReturn(true); + $node1 = $this->createStub(ilSimpleFilePathNode::class); + $node1->method('toString')->willReturn('Node1'); + $node1->method('requiresPathSeparator')->willReturn(true); + $node2 = $this->createStub(ilSimpleFilePathNode::class); + $node2->method('toString')->willReturn('Node2'); + $node2->method('requiresPathSeparator')->willReturn(true); + $node3 = $this->createStub(ilSimpleFilePathNode::class); + $node3->method('toString')->willReturn('Node3'); + $node3->method('requiresPathSeparator')->willReturn(true); $nodes = [$node1, $node2, $node3]; $path = new ilFilePathHandler(); diff --git a/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilAttributeTest.php b/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilAttributeTest.php index ca10dc89ac3f..07b1fec260ed 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilAttributeTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilAttributeTest.php @@ -33,8 +33,8 @@ protected function setUp(): void public function testAttributeTest(): void { - $comp = $this->createMock(ilFilePathComparisonHandler::class); - $comp->expects($this->any())->method('toString')->willReturn('<3'); + $comp = $this->createStub(ilFilePathComparisonHandler::class); + $comp->method('toString')->willReturn('<3'); $node = new ilAttributeFilePathNode(); $node2 = $node diff --git a/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilIndexTest.php b/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilIndexTest.php index 30928d8bd86c..58c848d2c10f 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilIndexTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Path/Node/ilIndexTest.php @@ -28,8 +28,8 @@ class ilIndexTest extends TestCase { public function testIndexNode(): void { - $comp = $this->createMock(ilFilePathComparisonHandler::class); - $comp->expects($this->any())->method('toString')->willReturn('<3'); + $comp = $this->createStub(ilFilePathComparisonHandler::class); + $comp->method('toString')->willReturn('<3'); $node = new ilIndexFilePathNode(); $node2 = $node->withIndex(20); diff --git a/components/ILIAS/Export/tests/ImportHandler/Validation/Set/HandlerTest.php b/components/ILIAS/Export/tests/ImportHandler/Validation/Set/HandlerTest.php index 3c006a39774a..af82994e243e 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Validation/Set/HandlerTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Validation/Set/HandlerTest.php @@ -30,9 +30,9 @@ class HandlerTest extends TestCase { public function testFileValidationSetHandler(): void { - $xsd_file = $this->createMock(ilXSDFileHandler::class); - $xml_file = $this->createMock(ilXMLFileHandler::class); - $file_path = $this->createMock(ilFilePathHandler::class); + $xsd_file = $this->createStub(ilXSDFileHandler::class); + $xml_file = $this->createStub(ilXMLFileHandler::class); + $file_path = $this->createStub(ilFilePathHandler::class); $set = (new ilFileValidationSetHandler()) ->withFilePathHandler($file_path) diff --git a/components/ILIAS/Export/tests/ImportHandler/Validation/Set/ilCollectionTest.php b/components/ILIAS/Export/tests/ImportHandler/Validation/Set/ilCollectionTest.php index b2e6e03c4163..bfe9fbd51dfe 100755 --- a/components/ILIAS/Export/tests/ImportHandler/Validation/Set/ilCollectionTest.php +++ b/components/ILIAS/Export/tests/ImportHandler/Validation/Set/ilCollectionTest.php @@ -28,9 +28,9 @@ class ilCollectionTest extends TestCase { public function testSetCollection(): void { - $set1 = $this->createMock(ilFileValidationSetHandler::class); - $set2 = $this->createMock(ilFileValidationSetHandler::class); - $set3 = $this->createMock(ilFileValidationSetHandler::class); + $set1 = $this->createStub(ilFileValidationSetHandler::class); + $set2 = $this->createStub(ilFileValidationSetHandler::class); + $set3 = $this->createStub(ilFileValidationSetHandler::class); $sets = [$set1, $set2, $set3]; $collection = (new ilFileValidationSetCollection()) diff --git a/components/ILIAS/Export/tests/ilExportOptionsTest.php b/components/ILIAS/Export/tests/ilExportOptionsTest.php index 8f6ef139f280..57a27e5a557a 100755 --- a/components/ILIAS/Export/tests/ilExportOptionsTest.php +++ b/components/ILIAS/Export/tests/ilExportOptionsTest.php @@ -66,6 +66,6 @@ protected function initDependencies(): void $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); } } diff --git a/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_10_0.xsd b/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_10_0.xsd index ab429d0a8838..bf730646101b 100644 --- a/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_10_0.xsd +++ b/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_10_0.xsd @@ -65,6 +65,7 @@ + diff --git a/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_11_0.xsd b/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_11_0.xsd index 8e6a17884708..96da01a10ceb 100644 --- a/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_11_0.xsd +++ b/components/ILIAS/Export/xml/SchemaValidation/ilias_crs_11_0.xsd @@ -30,6 +30,7 @@ + diff --git a/components/ILIAS/Export/xml/SchemaValidation/ilias_md_10_0.xsd b/components/ILIAS/Export/xml/SchemaValidation/ilias_md_10_0.xsd index df685edf75cd..fccfea2a4956 100644 --- a/components/ILIAS/Export/xml/SchemaValidation/ilias_md_10_0.xsd +++ b/components/ILIAS/Export/xml/SchemaValidation/ilias_md_10_0.xsd @@ -197,7 +197,7 @@ - + @@ -215,7 +215,7 @@ - + diff --git a/components/ILIAS/Export/xml/SchemaValidation/ilias_ws_crs_11_0.xsd b/components/ILIAS/Export/xml/SchemaValidation/ilias_ws_crs_11_0.xsd index fb932d8455ac..f008415cfc04 100755 --- a/components/ILIAS/Export/xml/SchemaValidation/ilias_ws_crs_11_0.xsd +++ b/components/ILIAS/Export/xml/SchemaValidation/ilias_ws_crs_11_0.xsd @@ -70,6 +70,7 @@ + diff --git a/components/ILIAS/Export/xml/ilias_pg_12.dtd b/components/ILIAS/Export/xml/ilias_pg_12.dtd new file mode 100755 index 000000000000..64e6145fe231 --- /dev/null +++ b/components/ILIAS/Export/xml/ilias_pg_12.dtd @@ -0,0 +1,572 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/ILIAS/File/classes/Setup/Database/V11/FileObjectRBACDatabaseSteps.php b/components/ILIAS/File/classes/Setup/Database/V11/FileObjectRBACDatabaseSteps.php new file mode 100644 index 000000000000..5ab80d3a6a80 --- /dev/null +++ b/components/ILIAS/File/classes/Setup/Database/V11/FileObjectRBACDatabaseSteps.php @@ -0,0 +1,78 @@ + + */ +class FileObjectRBACDatabaseSteps implements ilDatabaseUpdateSteps +{ + private const string OBSOLETE_OPERATION = 'view_content'; + + private ?ilDBInterface $database = null; + + public function prepare(ilDBInterface $db): void + { + $this->database = $db; + } + + /** + * @description remove the obsolete "view_content" operation of older releases + */ + public function step_1(): void + { + $ops_id = $this->database->fetchAssoc( + $this->database->queryF( + "SELECT ops_id FROM rbac_operations WHERE operation = %s", + ['text'], + [self::OBSOLETE_OPERATION] + ) + )['ops_id'] ?? null; + + if ($ops_id === null) { + return; + } + + // This operation has been superseded by "file_view_content". The permission + // assignments are stored for that operation, therefore nothing has to be + // migrated here and the obsolete operation can simply be dropped. + $this->database->manipulateF( + 'DELETE FROM rbac_ta WHERE ops_id = %s', + ['integer'], + [$ops_id] + ); + + $this->database->manipulateF( + 'DELETE FROM rbac_templates WHERE ops_id = %s', + ['integer'], + [$ops_id] + ); + + $this->database->manipulateF( + 'DELETE FROM rbac_operations WHERE ops_id = %s', + ['integer'], + [$ops_id] + ); + } +} diff --git a/components/ILIAS/File/classes/Setup/class.ilFileObjectAgent.php b/components/ILIAS/File/classes/Setup/class.ilFileObjectAgent.php index 352d5e3e2d40..35ca1f663530 100755 --- a/components/ILIAS/File/classes/Setup/class.ilFileObjectAgent.php +++ b/components/ILIAS/File/classes/Setup/class.ilFileObjectAgent.php @@ -28,6 +28,7 @@ use ILIAS\Setup\Config; use ILIAS\Refinery\Factory; use ILIAS\File\Icon\ilObjFileDefaultIconsObjective; +use ILIAS\File\Setup\Database\V11\FileObjectRBACDatabaseSteps; /** * @author Thibeau Fuhrer @@ -66,6 +67,9 @@ public function getUpdateObjective(?Config $config = null): Objective new ilFileObjectSettingsUpdatedObjective(), new ilFileObjectRBACDatabase( new ilFileObjectRBACDatabaseSteps() + ), + new ilDatabaseUpdateStepsExecutedObjective( + new FileObjectRBACDatabaseSteps() ) ); } diff --git a/components/ILIAS/File/classes/class.ilFileXMLParser.php b/components/ILIAS/File/classes/class.ilFileXMLParser.php index 44f6f10df3ad..f45f56a94f6b 100755 --- a/components/ILIAS/File/classes/class.ilFileXMLParser.php +++ b/components/ILIAS/File/classes/class.ilFileXMLParser.php @@ -240,7 +240,28 @@ public function handlerEndTag($a_xml_parser, string $a_name): void $baseDecodedFilename = ilFileUtils::ilTempnam(); if ($this->mode === ilFileXMLParser::$CONTENT_COPY) { - $this->tmpFilename = $this->getImportDirectory() . "/" . self::normalizeRelativePath($this->cdata); + // SECURITY (ILIAS10-025): COPY mode is only valid inside a trusted + // import/zip context where setImportDirectory() has been called. + // A null import directory produces an absolute attacker-controlled + // path -> arbitrary file read as www-data. + $importDir = $this->getImportDirectory(); + if ($importDir === null || $importDir === '') { + throw new ilFileException( + 'COPY mode requires a sandboxed import directory.', + ilFileException::$ID_MISMATCH + ); + } + $rel = self::normalizeRelativePath($this->cdata); + $base = realpath($importDir); + $resolved = realpath($importDir . '/' . $rel); + if ($base === false || $resolved === false + || !str_starts_with($resolved, $base . DIRECTORY_SEPARATOR)) { + throw new ilFileException( + 'COPY mode path must stay within the import directory.', + ilFileException::$ID_MISMATCH + ); + } + $this->tmpFilename = $resolved; } // begin-patch fm elseif ($this->mode === ilFileXMLParser::$CONTENT_REST) { $storage = new ilRestFileStorage(); diff --git a/components/ILIAS/File/classes/class.ilObjFileGUI.php b/components/ILIAS/File/classes/class.ilObjFileGUI.php index cfb6377acc61..6cf454c8e37c 100755 --- a/components/ILIAS/File/classes/class.ilObjFileGUI.php +++ b/components/ILIAS/File/classes/class.ilObjFileGUI.php @@ -997,7 +997,13 @@ public function buildInfoScreen(bool $kiosk_mode): ilInfoScreenGUI } } - $info->hideFurtherSections(false); + // only the kiosk mode is meant to be that lean: outside of it the sections added + // while rendering, e.g. the read statistics of ilInfoScreenGUI::addObjectSections(), + // would be hidden without any way to unfold them, + // see https://mantis.ilias.de/view.php?id=45051 + if ($kiosk_mode) { + $info->hideFurtherSections(false); + } return $info; } diff --git a/components/ILIAS/FileDelivery/classes/FileDeliveryTypes/PHPChunked.php b/components/ILIAS/FileDelivery/classes/FileDeliveryTypes/PHPChunked.php index 5e44b465127c..7e209b22f824 100755 --- a/components/ILIAS/FileDelivery/classes/FileDeliveryTypes/PHPChunked.php +++ b/components/ILIAS/FileDelivery/classes/FileDeliveryTypes/PHPChunked.php @@ -106,9 +106,10 @@ public function deliver(string $path_to_file, bool $file_marked_to_delete): void * (mediatype = mimetype) * as well as a boundry header to indicate the various chunks of data. */ - $response = $this->httpService->response()->withHeader("Accept-Ranges", "0-$length"); + $response = $this->httpService->response()->withHeader(ResponseHeader::ACCEPT_RANGES, 'bytes'); $this->httpService->saveResponse($response); $server = $this->httpService->request()->getServerParams(); + $is_partial = false; // header('Accept-Ranges: bytes'); // multipart/byteranges // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 @@ -159,6 +160,7 @@ public function deliver(string $path_to_file, bool $file_marked_to_delete): void $end = $c_end; $length = $end - $start + 1; // Calculate new content length fseek($fp, (int) $start); + $is_partial = true; $response = $this->httpService->response()->withStatus(206); @@ -166,7 +168,10 @@ public function deliver(string $path_to_file, bool $file_marked_to_delete): void } // fim do if // Notify the client the byte range we'll be outputting - $response = $this->httpService->response()->withHeader(ResponseHeader::CONTENT_RANGE, "bytes $start-$end/$size")->withHeader(ResponseHeader::CONTENT_LENGTH, $length); + $response = $this->httpService->response()->withHeader(ResponseHeader::CONTENT_LENGTH, (string) $length); + if ($is_partial) { + $response = $response->withHeader(ResponseHeader::CONTENT_RANGE, "bytes $start-$end/$size"); + } $this->httpService->saveResponse($response); diff --git a/components/ILIAS/FileServices/classes/StorageService/class.ilFileServicesPolicy.php b/components/ILIAS/FileServices/classes/StorageService/class.ilFileServicesPolicy.php index 372fc90119cf..7a3b8e7960a0 100755 --- a/components/ILIAS/FileServices/classes/StorageService/class.ilFileServicesPolicy.php +++ b/components/ILIAS/FileServices/classes/StorageService/class.ilFileServicesPolicy.php @@ -73,8 +73,11 @@ public function ascii(string $filename): string $ascii_filename = preg_replace('/[\x7f-\xff]/', '_', (string) $ascii_filename); // OS do not allow the following characters in filenames: \/:*?"<>| + // control characters are replaced as well: they are invisible in the title, but + // break paths and HTTP headers built from it, see + // https://mantis.ilias.de/view.php?id=30709 $ascii_filename = preg_replace( - '/[:\x5c\/\*\?\"<>\|]/', + '/[\x00-\x1f:\x5c\/\*\?\"<>\|]/', '_', (string) $ascii_filename ); diff --git a/components/ILIAS/FileServices/classes/class.ilFileUtils.php b/components/ILIAS/FileServices/classes/class.ilFileUtils.php index 4760da13e857..f1999a68082d 100755 --- a/components/ILIAS/FileServices/classes/class.ilFileUtils.php +++ b/components/ILIAS/FileServices/classes/class.ilFileUtils.php @@ -408,7 +408,7 @@ public static function moveUploadedFile( $target_filename = ilFileUtils::getValidFilename($target_filename); - // Make sure the target is in a valid subfolder. (e.g. no uploads to ilias/setup_/....) + // Make sure the target is in a valid subfolder. (e.g. no uploads to ilias/Setup/....) [$target_filesystem, $target_dir] = self::sanitateTargetPath($a_target); $upload = $DIC->upload(); diff --git a/components/ILIAS/FileServices/tests/ilServicesFileServicesTest.php b/components/ILIAS/FileServices/tests/ilServicesFileServicesTest.php index d5963a5bff18..5297fbae3a58 100755 --- a/components/ILIAS/FileServices/tests/ilServicesFileServicesTest.php +++ b/components/ILIAS/FileServices/tests/ilServicesFileServicesTest.php @@ -204,4 +204,30 @@ public function testFileNamePolicyOnDownloading(): void $this->assertSame('oeoeoeoeoeoeoeoeoe.pdf', $policy->prepareFileNameForConsumer('ööööööööö.pdf')); $this->assertSame('ueueueueueueueueue.pdf', $policy->prepareFileNameForConsumer('üüüüüüüüü.pdf')); } + + /** + * Control characters must not survive, they are invisible in the title but break + * paths and HTTP headers built from it, see https://mantis.ilias.de/view.php?id=30709 + */ + public function testFileNamePolicyRemovesControlCharacters(): void + { + $settings = $this->createMock(ilFileServicesSettings::class); + + $settings->expects($this->atLeastOnce()) + ->method('getBlackListedSuffixes') + ->willReturn([]); + + $settings->expects($this->atLeastOnce()) + ->method('getWhiteListedSuffixes') + ->willReturn(['pdf']); + + $policy = new ilFileServicesPolicy($settings); + + $this->assertSame( + 'KW 49 _ SW 5 - Halbschnitt __Vollschnitt', + $policy->ascii('KW 49 / SW 5 - Halbschnitt /' . chr(0x0b) . 'Vollschnitt') + ); + $this->assertSame('2._Shipflow Einstieg', $policy->ascii("2.\tShipflow Einstieg")); + $this->assertSame('report__.pdf', $policy->ascii("report\r\n.pdf")); + } } diff --git a/components/ILIAS/Filesystem/README.md b/components/ILIAS/Filesystem/README.md index 895f4851afcd..25f1916e74fc 100755 --- a/components/ILIAS/Filesystem/README.md +++ b/components/ILIAS/Filesystem/README.md @@ -629,6 +629,37 @@ foreach ($finder->files()->size('> 1Mi') as $metadata) { } ``` +### Limiting + +The result set can be limited to a fixed number of entries by calling `limit()`. +The limit is applied to the final result set (after filtering and optional sorting). + +```php +filesystem()->web(); +$finder = $web->finder(); + +foreach ($finder->files()->sortByName()->limit(5) as $metadata) { +} +``` + +### Existence Check + +If you only need to know whether the current finder criteria matches at least one item, +you can call `hasAny()`. This avoids counting the full result set. + +```php +filesystem()->web(); +$finder = $web->finder(); + +if ($finder->files()->in(['my/path'])->hasAny()) { + // at least one matching file exists +} +``` + ### Sorting The found `Metadata` can be sorted by time (see: `\ILIAS\Filesystem\Provider\FileReadAccess::getTimestamp`), diff --git a/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php b/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php index 0b10cad78fa9..d08e0daee0fb 100755 --- a/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php +++ b/components/ILIAS/Filesystem/classes/class.ilFileSystemCleanTempDirCron.php @@ -159,12 +159,68 @@ public function run(): JobResult } } + $corrupted_paths = $this->reportCorruptedPaths(); + $num_folders = count($deleted_folders); $num_files = count($deleted_files); + $num_corrupted = count($corrupted_paths); + + $message = $num_folders . " folders and " . $num_files . " files have been deleted."; + if ($num_corrupted > 0) { + $message .= " " . $num_corrupted . " path(s) could not be processed and must be removed manually," + . " see the log for details."; + } $result = new JobResult(); - $result->setMessage($num_folders . " folders and " . $num_files . " files have been deleted."); + $result->setMessage($message); $result->setStatus(JobResult::STATUS_OK); return $result; } + + /** + * Paths containing control characters (e.g. a tab or a line break) are rejected by the + * path normalizer of the filesystem. They can neither be listed nor deleted through it, + * which is why they are skipped silently during the cleanup above. Report them, so they + * can be removed manually. + * + * @return string[] the reported paths + */ + private function reportCorruptedPaths(): array + { + try { + $contents = $this->filesystem->listContents("", true); + } catch (Throwable $t) { + // the cleanup itself already succeeded, this report must never fail the job + $this->logger->error( + "Cron Job \"Clean temp directory\" could not look for corrupted paths" + . " due to the following exception: " . $t->getMessage() + ); + return []; + } + + $corrupted_paths = []; + foreach ($contents as $metadata) { + $path = $metadata->getPath(); + if (preg_match('#\p{C}#u', $path) !== 1) { + continue; + } + + // everything below an already reported path shares its unusable prefix, + // reporting the topmost path of such a subtree is sufficient + foreach ($corrupted_paths as $reported_path) { + if (str_starts_with($path, $reported_path . '/')) { + continue 2; + } + } + + $corrupted_paths[] = $path; + $this->logger->error( + "Cron Job \"Clean temp directory\" cannot delete \"" . $path + . "\" because its path contains characters which are rejected by the filesystem." + . " Please remove it manually." + ); + } + + return $corrupted_paths; + } } diff --git a/components/ILIAS/Filesystem/src/Finder/Comparator/BaseComparator.php b/components/ILIAS/Filesystem/src/Finder/Comparator/BaseComparator.php index 42c85057463c..1b4e85d1923e 100755 --- a/components/ILIAS/Filesystem/src/Finder/Comparator/BaseComparator.php +++ b/components/ILIAS/Filesystem/src/Finder/Comparator/BaseComparator.php @@ -20,13 +20,6 @@ namespace ILIAS\Filesystem\Finder\Comparator; -use InvalidArgumentException; - -/** - * Class Base - * @package ILIAS\Filesystem\Finder\Comparator - * @author Michael Jansen - */ abstract class BaseComparator { private string $target = ''; @@ -53,8 +46,8 @@ public function setOperator(string $operator): void $operator = '=='; } - if (!in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { - throw new InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); + if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='], true)) { + throw new \InvalidArgumentException(\sprintf('Invalid operator "%s".', $operator)); } $this->operator = $operator; diff --git a/components/ILIAS/Filesystem/src/Finder/Comparator/DateComparator.php b/components/ILIAS/Filesystem/src/Finder/Comparator/DateComparator.php index cf0c18df006b..d9fd7603ded6 100755 --- a/components/ILIAS/Filesystem/src/Finder/Comparator/DateComparator.php +++ b/components/ILIAS/Filesystem/src/Finder/Comparator/DateComparator.php @@ -20,27 +20,19 @@ namespace ILIAS\Filesystem\Finder\Comparator; -use Exception; -use InvalidArgumentException; - -/** - * Class DateComparator - * @package ILIAS\Filesystem\Finder\Comparator - * @author Michael Jansen - */ class DateComparator extends BaseComparator { public function __construct(string $test) { if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) { - throw new InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test)); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a date test.', $test)); } try { - $date = new \DateTime($matches[2]); + $date = new \DateTimeImmutable($matches[2]); $target = $date->format('U'); - } catch (Exception) { - throw new InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); + } catch (\Throwable) { + throw new \InvalidArgumentException(\sprintf('"%s" is not a valid date.', $matches[2])); } $operator = $matches[1] ?? '=='; diff --git a/components/ILIAS/Filesystem/src/Finder/Comparator/NumberComparator.php b/components/ILIAS/Filesystem/src/Finder/Comparator/NumberComparator.php index 04072a0d010d..526035f06584 100755 --- a/components/ILIAS/Filesystem/src/Finder/Comparator/NumberComparator.php +++ b/components/ILIAS/Filesystem/src/Finder/Comparator/NumberComparator.php @@ -20,24 +20,17 @@ namespace ILIAS\Filesystem\Finder\Comparator; -use InvalidArgumentException; - -/** - * Class NumberComparator - * @package ILIAS\Filesystem\Finder\Comparator - * @author Michael Jansen - */ class NumberComparator extends BaseComparator { public function __construct(string $test) { if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) { - throw new InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test)); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a number test.', $test)); } $target = $matches[2]; if (!is_numeric($target)) { - throw new InvalidArgumentException(sprintf('Invalid number "%s".', $target)); + throw new \InvalidArgumentException(\sprintf('Invalid number "%s".', $target)); } if (isset($matches[3])) { diff --git a/components/ILIAS/Filesystem/src/Finder/Finder.php b/components/ILIAS/Filesystem/src/Finder/Finder.php index 6e9f7a365638..c4998b844b6c 100755 --- a/components/ILIAS/Filesystem/src/Finder/Finder.php +++ b/components/ILIAS/Filesystem/src/Finder/Finder.php @@ -20,55 +20,30 @@ namespace ILIAS\Filesystem\Finder; -use ILIAS\Filesystem\Finder\Iterator\FileTypeFilterIterator; -use ILIAS\Filesystem\Finder\Comparator\NumberComparator; -use ILIAS\Filesystem\Finder\Comparator\DateComparator; -use ILIAS\Filesystem\Finder\Iterator\RecursiveDirectoryIterator; -use ILIAS\Filesystem\Finder\Iterator\ExcludeDirectoryFilterIterator; -use ILIAS\Filesystem\Finder\Iterator\DepthRangeFilterIterator; -use ILIAS\Filesystem\Finder\Iterator\DateRangeFilterIterator; -use ILIAS\Filesystem\Finder\Iterator\SizeRangeFilterIterator; -use AppendIterator; -use ArrayIterator; -use Closure; -use Countable; use ILIAS\Filesystem\DTO\Metadata; use ILIAS\Filesystem\Filesystem; -use ILIAS\Filesystem\MetadataType; -use InvalidArgumentException; -use Iterator as PhpIterator; -use IteratorAggregate; -use LogicException; -use RecursiveIteratorIterator; use ILIAS\Filesystem\Finder\Iterator\SortableIterator; +use ILIAS\Filesystem\Finder\Iterator\LazyIterator; /** - * Class Finder * Port of the Symfony2 bundle to work with the ILIAS FileSystem abstraction - * @package ILIAS\Filesystem\Finder - * @see : https://github.com/symfony/finder - * @author Michael Jansen + * @see https://github.com/symfony/finder + * @implements \IteratorAggregate */ -final class Finder implements IteratorAggregate, Countable +final class Finder implements \IteratorAggregate, \Countable { - /** - * @var int - */ private const IGNORE_VCS_FILES = 1; - /** - * @var int - */ private const IGNORE_DOT_FILES = 2; - /** @var string[] */ + /** @var list */ private array $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg']; - /** @var PhpIterator[] */ + /** @var list<\Iterator> */ private array $iterators = []; - /** @var string[] */ + /** @var list */ protected array $dirs = []; - /** @var string[] */ + /** @var list */ private array $exclude = []; - private int $ignore = 0; - private int $mode = FileTypeFilterIterator::ALL; + private int $ignore; + private int $mode = Iterator\FileTypeFilterIterator::ALL; private bool $reverseSorting = false; /** @var Comparator\DateComparator[] */ private array $dates = []; @@ -78,8 +53,9 @@ final class Finder implements IteratorAggregate, Countable private array $depths = []; /** @var int|Closure */ private $sort = SortableIterator::SORT_BY_NONE; + private ?int $limit = null; - public function __construct(private Filesystem $filesystem) + public function __construct(private readonly Filesystem $filesystem) { $this->ignore = self::IGNORE_VCS_FILES | self::IGNORE_DOT_FILES; } @@ -87,7 +63,7 @@ public function __construct(private Filesystem $filesystem) public function files(): self { $clone = clone $this; - $clone->mode = FileTypeFilterIterator::ONLY_FILES; + $clone->mode = Iterator\FileTypeFilterIterator::ONLY_FILES; return $clone; } @@ -95,7 +71,7 @@ public function files(): self public function directories(): self { $clone = clone $this; - $clone->mode = FileTypeFilterIterator::ONLY_DIRECTORIES; + $clone->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES; return $clone; } @@ -103,20 +79,20 @@ public function directories(): self public function allTypes(): self { $clone = clone $this; - $clone->mode = FileTypeFilterIterator::ALL; + $clone->mode = Iterator\FileTypeFilterIterator::ALL; return $clone; } /** - * @param string[] $directories - * @throws InvalidArgumentException + * @param list $directories + * @throws \InvalidArgumentException */ public function exclude(array $directories): self { array_walk($directories, static function ($directory): void { - if (!is_string($directory)) { - throw new InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class)); + if (!\is_string($directory)) { + throw new \InvalidArgumentException(\sprintf('Invalid directory given: %s', $directory::class)); } }); @@ -127,14 +103,14 @@ public function exclude(array $directories): self } /** - * @param string[] $directories - * @throws InvalidArgumentException + * @param list $directories + * @throws \InvalidArgumentException */ public function in(array $directories): self { array_walk($directories, static function ($directory): void { - if (!is_string($directory)) { - throw new InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class)); + if (!\is_string($directory)) { + throw new \InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class)); } }); @@ -158,7 +134,7 @@ public function in(array $directories): self public function depth(string|int $level): self { $clone = clone $this; - $clone->depths[] = new NumberComparator((string) $level); + $clone->depths[] = new Comparator\NumberComparator((string) $level); return $clone; } @@ -181,7 +157,7 @@ public function depth(string|int $level): self public function date(string $date): self { $clone = clone $this; - $clone->dates[] = new DateComparator($date); + $clone->dates[] = new Comparator\DateComparator($date); return $clone; } @@ -201,12 +177,12 @@ public function date(string $date): self */ public function size(string|int|array $sizes): self { - $sizes = is_array($sizes) ? $sizes : [$sizes]; + $sizes = \is_array($sizes) ? $sizes : [$sizes]; $clone = clone $this; foreach ($sizes as $size) { - $clone->sizes[] = new NumberComparator((string) $size); + $clone->sizes[] = new Comparator\NumberComparator((string) $size); } return $clone; @@ -220,6 +196,35 @@ public function reverseSorting(): self return $clone; } + public function limit(int $limit): self + { + if ($limit < 0) { + throw new \InvalidArgumentException('Limit must be greater than or equal to 0.'); + } + + $clone = clone $this; + $clone->limit = $limit; + + return $clone; + } + + /** + * Checks whether at least one entry matches the current finder criteria. + */ + public function hasAny(): bool + { + $clone = clone $this; + $clone->sort = SortableIterator::SORT_BY_NONE; + $clone->reverseSorting = false; + $clone->limit = 1; + + foreach ($clone->getIterator() as $_) { + return true; + } + + return false; + } + public function ignoreVCS(bool $ignoreVCS): self { $clone = clone $this; @@ -233,14 +238,14 @@ public function ignoreVCS(bool $ignoreVCS): self } /** - * @param string[] $pattern - * @throws InvalidArgumentException + * @param list $pattern + * @throws \InvalidArgumentException */ public function addVCSPattern(array $pattern): self { array_walk($pattern, static function ($p): void { - if (!is_string($p)) { - throw new InvalidArgumentException(sprintf('Invalid pattern given: %s', $p::class)); + if (!\is_string($p)) { + throw new \InvalidArgumentException(\sprintf('Invalid pattern given: %s', $p::class)); } }); @@ -259,7 +264,7 @@ public function addVCSPattern(array $pattern): self * The anonymous function receives two Metadata instances to compare. * This can be slow as all the matching files and directories must be retrieved for comparison. */ - public function sort(Closure $closure): self + public function sort(\Closure $closure): self { $clone = clone $this; $clone->sort = $closure; @@ -270,9 +275,9 @@ public function sort(Closure $closure): self public function sortByName(bool $useNaturalSort = false): self { $clone = clone $this; - $clone->sort = SortableIterator::SORT_BY_NAME; + $clone->sort = Iterator\SortableIterator::SORT_BY_NAME; if ($useNaturalSort) { - $clone->sort = SortableIterator::SORT_BY_NAME_NATURAL; + $clone->sort = Iterator\SortableIterator::SORT_BY_NAME_NATURAL; } return $clone; @@ -281,7 +286,7 @@ public function sortByName(bool $useNaturalSort = false): self public function sortByType(): self { $clone = clone $this; - $clone->sort = SortableIterator::SORT_BY_TYPE; + $clone->sort = Iterator\SortableIterator::SORT_BY_TYPE; return $clone; } @@ -289,117 +294,121 @@ public function sortByType(): self public function sortByTime(): self { $clone = clone $this; - $clone->sort = SortableIterator::SORT_BY_TIME; + $clone->sort = Iterator\SortableIterator::SORT_BY_TIME; return $clone; } /** * Appends an existing set of files/directories to the finder. - * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. - * @throws InvalidArgumentException when the given argument is not iterable + * The set can be another {@see Finder}, an {@see \Iterator}, an {@see \IteratorAggregate}, or even a plain array. + * @param iterable $iterator + * @throws \InvalidArgumentException when the given argument is not iterable */ public function append(iterable $iterator): self { $clone = clone $this; - - if ($iterator instanceof IteratorAggregate) { - $clone->iterators[] = $iterator->getIterator(); - } elseif ($iterator instanceof PhpIterator) { - $clone->iterators[] = $iterator; - } elseif (is_iterable($iterator)) { - $it = new ArrayIterator(); - foreach ($iterator as $file) { - if ($file instanceof MetadataType) { - $it->append($file); - } else { - throw new InvalidArgumentException( - 'Finder::append() method wrong argument type in passed iterator.' - ); - } - } - $clone->iterators[] = $it; - } else { - throw new InvalidArgumentException('Finder::append() method wrong argument type.'); - } + $clone->iterators[] = $iterator; return $clone; } private function searchInDirectory(string $dir): \Traversable { + $exclude = $this->exclude; + if (self::IGNORE_VCS_FILES === (self::IGNORE_VCS_FILES & $this->ignore)) { - $this->exclude = array_merge($this->exclude, $this->vcsPatterns); + $exclude = array_merge($exclude, $this->vcsPatterns); } - $iterator = new RecursiveDirectoryIterator($this->filesystem, $dir); + $iterator = new Iterator\RecursiveDirectoryIterator($this->filesystem, $dir); - if ($this->exclude) { - $iterator = new ExcludeDirectoryFilterIterator($iterator, $this->exclude); + if ($exclude) { + $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, ...$exclude); } - $iterator = new RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); + $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); if ($this->depths) { - $iterator = new DepthRangeFilterIterator($iterator, $this->depths); + $iterator = new Iterator\DepthRangeFilterIterator($iterator, ...$this->depths); } if ($this->mode !== 0) { - $iterator = new FileTypeFilterIterator($iterator, $this->mode); + $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); } if ($this->dates) { - $iterator = new DateRangeFilterIterator($this->filesystem, $iterator, $this->dates); + $iterator = new Iterator\DateRangeFilterIterator($this->filesystem, $iterator, ...$this->dates); } if ($this->sizes) { - $iterator = new SizeRangeFilterIterator($this->filesystem, $iterator, $this->sizes); - } - - if ($this->sort || $this->reverseSorting) { - $iteratorAggregate = new SortableIterator( - $this->filesystem, - $iterator, - $this->sort, - $this->reverseSorting - ); - $iterator = $iteratorAggregate->getIterator(); + $iterator = new Iterator\SizeRangeFilterIterator($this->filesystem, $iterator, ...$this->sizes); } return $iterator; } /** - * @inheritdoc - * @return PhpIterator|Metadata[] - * @throws LogicException + * @return \Iterator + * @throws \LogicException */ - #[\ReturnTypeWillChange] public function getIterator(): \Iterator { if ([] === $this->dirs && [] === $this->iterators) { - throw new LogicException('You must call one of in() or append() methods before iterating over a Finder.'); + throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); + } + + if ($this->limit === 0) { + return new \EmptyIterator(); } if (1 === count($this->dirs) && [] === $this->iterators) { - return $this->searchInDirectory($this->dirs[0]); + $iterator = $this->searchInDirectory($this->dirs[0]); + } else { + $iterator = new \AppendIterator(); + foreach ($this->dirs as $dir) { + $iterator->append(new \IteratorIterator(new LazyIterator(fn() => $this->searchInDirectory($dir)))); + } + + foreach ($this->iterators as $it) { + $iterator->append( + new \IteratorIterator( + new LazyIterator( + static function () use ($it) { + foreach ($it as $key => $value) { + yield $key => $value; + } + } + ) + ) + ); + } + } + + if ($this->sort || $this->reverseSorting) { + $iterator = (new SortableIterator( + $this->filesystem, + $iterator, + $this->sort, + $this->reverseSorting + ))->getIterator(); } - $iterator = new AppendIterator(); - foreach ($this->dirs as $dir) { - $iterator->append($this->searchInDirectory($dir)); + if ($this->limit === 0) { + return new \EmptyIterator(); } - foreach ($this->iterators as $it) { - $iterator->append($it); + if ($this->limit !== null) { + $iterator = new \LimitIterator( + $iterator instanceof \Iterator ? $iterator : new \IteratorIterator($iterator), + 0, + $this->limit + ); } return $iterator; } - /** - * @inheritdoc - */ public function count(): int { return iterator_count($this->getIterator()); diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/DateRangeFilterIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/DateRangeFilterIterator.php index 93f28d70759c..7b8cc792068d 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/DateRangeFilterIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/DateRangeFilterIterator.php @@ -20,48 +20,31 @@ namespace ILIAS\Filesystem\Finder\Iterator; -use FilterIterator; use ILIAS\Filesystem\Filesystem; use ILIAS\Filesystem\Finder\Comparator\DateComparator; use ILIAS\Filesystem\DTO\Metadata; -use InvalidArgumentException; -use Iterator as PhpIterator; /** - * Class DateRangeFilterIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @extends \FilterIterator */ -class DateRangeFilterIterator extends FilterIterator +class DateRangeFilterIterator extends \FilterIterator { - /** @var DateComparator[] */ - private array $comparators = []; + /** @var list */ + private array $comparators; /** - * @param PhpIterator $iterator The Iterator to filter - * @param DateComparator[] $comparators An array of DateComparator instances - * @throws InvalidArgumentException + * @param \Iterator $iterator The Iterator to filter */ - public function __construct(private Filesystem $filesystem, PhpIterator $iterator, array $comparators) - { - array_walk($comparators, static function ($comparator): void { - if (!($comparator instanceof DateComparator)) { - throw new InvalidArgumentException( - sprintf( - 'Invalid comparator given: %s', - $comparator::class - ) - ); - } - }); + public function __construct( + private readonly Filesystem $filesystem, + \Iterator $iterator, + DateComparator ...$comparators + ) { $this->comparators = $comparators; parent::__construct($iterator); } - /** - * @inheritdoc - */ public function accept(): bool { /** @var Metadata $metadata */ diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/DepthRangeFilterIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/DepthRangeFilterIterator.php index e4000f2542d8..20d7d0f100c6 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/DepthRangeFilterIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/DepthRangeFilterIterator.php @@ -21,36 +21,21 @@ namespace ILIAS\Filesystem\Finder\Iterator; use ILIAS\Filesystem\Finder\Comparator\NumberComparator; -use InvalidArgumentException; -use RecursiveIteratorIterator; /** - * Class DepthRangeFilterIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @template-covariant TKey + * @template-covariant TValue + * @extends \FilterIterator */ class DepthRangeFilterIterator extends \FilterIterator { - private int $minDepth = 0; + private int $minDepth; /** - * DepthRangeFilterIterator constructor. - * @param NumberComparator[] $comparators - * @throws InvalidArgumentException + * @param \RecursiveIteratorIterator<\RecursiveIterator> $iterator The iterator to filter */ - public function __construct(RecursiveIteratorIterator $iterator, array $comparators) + public function __construct(\RecursiveIteratorIterator $iterator, NumberComparator ...$comparators) { - array_walk($comparators, static function ($comparator): void { - if (!($comparator instanceof NumberComparator)) { - throw new InvalidArgumentException( - sprintf( - 'Invalid comparator given: %s', - $comparator::class - ) - ); - } - }); - $minDepth = 0; $maxDepth = PHP_INT_MAX; @@ -79,9 +64,6 @@ public function __construct(RecursiveIteratorIterator $iterator, array $comparat parent::__construct($iterator); } - /** - * @inheritdoc - */ public function accept(): bool { return $this->getInnerIterator()->getDepth() >= $this->minDepth; diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/ExcludeDirectoryFilterIterator.php index a79baddf4506..c3089be0bd8d 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -20,37 +20,25 @@ namespace ILIAS\Filesystem\Finder\Iterator; -use FilterIterator; use ILIAS\Filesystem\DTO\Metadata; -use InvalidArgumentException; -use Iterator as PhpIterator; -use RecursiveIterator; /** - * Class ExcludeDirectoryFilterIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @extends \FilterIterator + * @implements \RecursiveIterator */ -class ExcludeDirectoryFilterIterator extends FilterIterator implements RecursiveIterator +class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator { private bool $isRecursive; - /** @var string[] */ + /** @var array */ private array $excludedDirs = []; private string $excludedPattern = ''; /** - * @param PhpIterator $iterator The Iterator to filter - * @param string[] $directories An array of directories to exclude - * @throws InvalidArgumentException + * @param \Iterator $iterator The Iterator to filter */ - public function __construct(private PhpIterator $iterator, array $directories) + public function __construct(private readonly \Iterator $iterator, string ...$directories) { - array_walk($directories, static function ($directory): void { - if (!is_string($directory)) { - throw new InvalidArgumentException(sprintf('Invalid directory given: %s', $directory::class)); - } - }); - $this->isRecursive = $iterator instanceof RecursiveIterator; + $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = []; foreach ($directories as $directory) { @@ -69,9 +57,6 @@ public function __construct(private PhpIterator $iterator, array $directories) parent::__construct($iterator); } - /** - * @inheritdoc - */ public function accept(): bool { /** @var Metadata $metadata */ @@ -91,20 +76,14 @@ public function accept(): bool return true; } - /** - * @inheritdoc - */ public function hasChildren(): bool { return $this->isRecursive && $this->iterator->hasChildren(); } - /** - * @inheritdoc - */ - public function getChildren(): \ILIAS\Filesystem\Finder\Iterator\ExcludeDirectoryFilterIterator + public function getChildren(): self { - $children = new self($this->iterator->getChildren(), []); + $children = new self($this->iterator->getChildren()); $children->excludedDirs = $this->excludedDirs; $children->excludedPattern = $this->excludedPattern; diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/FileTypeFilterIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/FileTypeFilterIterator.php index 18cc3d828b8c..c296a97335e8 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/FileTypeFilterIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/FileTypeFilterIterator.php @@ -21,12 +21,9 @@ namespace ILIAS\Filesystem\Finder\Iterator; use ILIAS\Filesystem\DTO\Metadata; -use Iterator as PhpIterator; /** - * Class FileTypeFilterIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @extends \FilterIterator */ class FileTypeFilterIterator extends \FilterIterator { @@ -35,17 +32,14 @@ class FileTypeFilterIterator extends \FilterIterator public const ONLY_DIRECTORIES = 2; /** - * @param PhpIterator $iterator The Iterator to filter - * @param int $mode The mode (self::ALL or self::ONLY_FILES or self::ONLY_DIRECTORIES) + * @param \Iterator $iterator The Iterator to filter + * @param int $mode The mode (self::ALL or self::ONLY_FILES or self::ONLY_DIRECTORIES) */ - public function __construct(PhpIterator $iterator, private int $mode) + public function __construct(\Iterator $iterator, private int $mode) { parent::__construct($iterator); } - /** - * @inheritdoc - */ public function accept(): bool { /** @var Metadata $metadata */ @@ -53,9 +47,15 @@ public function accept(): bool if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $metadata->isFile()) { return false; } + if (self::ONLY_FILES !== (self::ONLY_FILES & $this->mode)) { return true; } - return !$metadata->isDir(); + + if (!$metadata->isDir()) { + return true; + } + + return false; } } diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/LazyIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/LazyIterator.php new file mode 100644 index 000000000000..b63b599d22fc --- /dev/null +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/LazyIterator.php @@ -0,0 +1,36 @@ +iterator_factory = $iterator_factory(...); + } + + public function getIterator(): \Traversable + { + yield from ($this->iterator_factory)(); + } +} diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/RecursiveDirectoryIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/RecursiveDirectoryIterator.php index 65e428123c31..d2744f7fece5 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/RecursiveDirectoryIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/RecursiveDirectoryIterator.php @@ -21,81 +21,70 @@ namespace ILIAS\Filesystem\Finder\Iterator; use ILIAS\Filesystem\DTO\Metadata; +use ILIAS\Filesystem\Exception\DirectoryNotFoundException; use ILIAS\Filesystem\Filesystem; /** - * Class RecursiveDirectoryIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @implements \RecursiveIterator */ class RecursiveDirectoryIterator implements \RecursiveIterator { - /** @var Metadata[] */ - protected array $files = []; + /** @var array */ + private array $files = []; - /** - * RecursiveDirectoryIterator constructor. - */ - public function __construct(private Filesystem $filesystem, protected string $dir) - { + public function __construct( + private readonly Filesystem $filesystem, + private readonly string $dir + ) { } /** - * @inheritdoc + * @return non-empty-string|null */ - public function key(): int|string + public function key(): string|null { return key($this->files); } - /** - * @inheritdoc - */ public function next(): void { next($this->files); } - /** - * @inheritdoc - */ - public function current(): bool|Metadata + public function current(): Metadata|false { return current($this->files); } - /** - * @inheritdoc - */ public function valid(): bool { return current($this->files) instanceof Metadata; } - /** - * @inheritdoc - */ public function rewind(): void { - $contents = $this->filesystem->listContents($this->dir, false); - $this->files = array_combine( - array_map(static fn(Metadata $metadata): string => $metadata->getPath(), $contents), - $contents - ); + $this->files = []; + + try { + $contents = $this->filesystem->listContents($this->dir, false); + } catch (DirectoryNotFoundException) { + // A directory which cannot be listed, e.g. because its path is rejected by the + // path normalizer, is treated as empty. Otherwise a single unusable directory + // would abort the traversal of the whole tree. + return; + } + + foreach ($contents as $metadata) { + $this->files[$metadata->getPath()] = $metadata; + } } - /** - * @inheritdoc - */ public function hasChildren(): bool { return $this->current()->isDir(); } - /** - * @inheritdoc - */ - public function getChildren(): \ILIAS\Filesystem\Finder\Iterator\RecursiveDirectoryIterator + public function getChildren(): self { return new self($this->filesystem, $this->current()->getPath()); } diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/SizeRangeFilterIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/SizeRangeFilterIterator.php index 83e3d2bc97ce..7099d7198fb7 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/SizeRangeFilterIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/SizeRangeFilterIterator.php @@ -24,44 +24,28 @@ use ILIAS\Filesystem\Filesystem; use ILIAS\Filesystem\DTO\Metadata; use ILIAS\Filesystem\Finder\Comparator\NumberComparator; -use InvalidArgumentException; -use Iterator as PhpIterator; /** - * Class SizeRangeFilterIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @extends \FilterIterator */ class SizeRangeFilterIterator extends \FilterIterator { - /** @var NumberComparator[] */ - private array $comparators = []; + /** @var list */ + private array $comparators; /** - * @param PhpIterator $iterator The Iterator to filter - * @param NumberComparator[] $comparators An array of NumberComparator instances - * @throws InvalidArgumentException + * @param \Iterator $iterator The Iterator to filter */ - public function __construct(private Filesystem $filesystem, PhpIterator $iterator, array $comparators) - { - array_walk($comparators, static function ($comparator): void { - if (!($comparator instanceof NumberComparator)) { - throw new InvalidArgumentException( - sprintf( - 'Invalid comparator given: %s', - $comparator::class - ) - ); - } - }); + public function __construct( + private readonly Filesystem $filesystem, + \Iterator $iterator, + NumberComparator ...$comparators + ) { $this->comparators = $comparators; parent::__construct($iterator); } - /** - * @inheritdoc - */ public function accept(): bool { /** @var Metadata $metadata */ diff --git a/components/ILIAS/Filesystem/src/Finder/Iterator/SortableIterator.php b/components/ILIAS/Filesystem/src/Finder/Iterator/SortableIterator.php index 4e038c59f4af..30291fd07254 100755 --- a/components/ILIAS/Filesystem/src/Finder/Iterator/SortableIterator.php +++ b/components/ILIAS/Filesystem/src/Finder/Iterator/SortableIterator.php @@ -20,20 +20,13 @@ namespace ILIAS\Filesystem\Finder\Iterator; -use ArrayIterator; use ILIAS\Filesystem\DTO\Metadata; use ILIAS\Filesystem\Filesystem; -use InvalidArgumentException; -use IteratorAggregate; -use Traversable; -use Closure; /** - * Class SortableIterator - * @package ILIAS\Filesystem\Finder\Iterator - * @author Michael Jansen + * @implements \IteratorAggregate */ -class SortableIterator implements IteratorAggregate +class SortableIterator implements \IteratorAggregate { public const SORT_BY_NONE = 0; public const SORT_BY_NAME = 1; @@ -41,19 +34,20 @@ class SortableIterator implements IteratorAggregate public const SORT_BY_NAME_NATURAL = 4; public const SORT_BY_TIME = 5; - /** @var callable|Closure|int */ + /** @var callable(Metadata, Metadata): int|Closure(Metadata, Metadata): int|int */ private $sort; /** - * Sortable constructor. - * @param int|callable|Closure $sort - * @param bool $reverseOrder + * @param \Traversable $iterator + * @param int|callable(Metadata, Metadata): int|Closure(Metadata, Metadata): int $sort + * @param bool $reverseOrder + * @throws \InvalidArgumentException */ public function __construct( - private Filesystem $filesystem, - private Traversable $iterator, + private readonly Filesystem $filesystem, + private readonly \Traversable $iterator, $sort, - $reverseOrder = false + bool $reverseOrder = false ) { $order = $reverseOrder ? -1 : 1; @@ -94,34 +88,43 @@ public function __construct( }; } elseif (self::SORT_BY_NONE === $sort) { $this->sort = $order; - } elseif (is_callable($sort)) { + } elseif (\is_callable($sort)) { $this->sort = $sort; if ($reverseOrder) { $this->sort = static fn(Metadata $left, Metadata $right): int|float => -$sort($left, $right); } } else { - throw new InvalidArgumentException( + throw new \InvalidArgumentException( 'The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.' ); } } - /** - * @inheritdoc - */ public function getIterator(): \Traversable { if (1 === $this->sort) { - return $this->iterator; + yield from $this->iterator; + return; + } + + $keys = []; + $values = []; + foreach ($this->iterator as $key => $value) { + $keys[] = $key; + $values[] = $value; } - $array = iterator_to_array($this->iterator, true); if (-1 === $this->sort) { - $array = array_reverse($array); - } else { - uasort($array, $this->sort); + for ($i = \count($values) - 1; $i >= 0; --$i) { + yield $keys[$i] => $values[$i]; + } + return; } - return new ArrayIterator($array); + uasort($values, $this->sort); + + foreach ($values as $i => $v) { + yield $keys[$i] => $v; + } } } diff --git a/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemDirectoryAccess.php b/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemDirectoryAccess.php index 5e96d12bf8fc..6ee322a623bd 100755 --- a/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemDirectoryAccess.php +++ b/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemDirectoryAccess.php @@ -25,6 +25,7 @@ use ILIAS\Filesystem\Exception\IOException; use ILIAS\Filesystem\Provider\DirectoryAccess; use ILIAS\Filesystem\Visibility; +use League\Flysystem\CorruptedPathDetected; use League\Flysystem\FilesystemOperator; use League\Flysystem\UnableToRetrieveMetadata; use League\Flysystem\UnableToCreateDirectory; @@ -53,7 +54,14 @@ public function __construct( public function hasDir(string $path): bool { - return $this->flysystem_operator->directoryExists($path); + try { + return $this->flysystem_operator->directoryExists($path); + } catch (CorruptedPathDetected) { + // Paths containing funky whitespace (e.g. a tab or a line break) are rejected + // by the path normalizer. Such a path can never be a usable directory, but it + // must not abort the caller either, since these paths do occur on disk. + return false; + } } /** diff --git a/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemFileAccess.php b/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemFileAccess.php index 7e3396bad1a5..a241691804a6 100755 --- a/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemFileAccess.php +++ b/components/ILIAS/Filesystem/src/Provider/FlySystem/FlySystemFileAccess.php @@ -26,6 +26,7 @@ use ILIAS\Filesystem\Exception\IOException; use ILIAS\Filesystem\Provider\FileAccess; use ILIAS\Filesystem\Visibility; +use League\Flysystem\CorruptedPathDetected; use League\Flysystem\FilesystemException; use League\Flysystem\FilesystemOperator; use League\Flysystem\UnableToRetrieveMetadata; @@ -68,7 +69,14 @@ public function read(string $path): string public function has(string $path): bool { - return $this->flysystem_operator->has($path); + try { + return $this->flysystem_operator->has($path); + } catch (CorruptedPathDetected) { + // Paths containing funky whitespace (e.g. a tab or a line break) are rejected + // by the path normalizer. Such a path can never be read, but it must not abort + // the caller either, since these paths do occur on disk. + return false; + } } public function getMimeType(string $path): string diff --git a/components/ILIAS/Filesystem/src/Stream/Streams.php b/components/ILIAS/Filesystem/src/Stream/Streams.php index 81f55368948b..c9674633f9d7 100755 --- a/components/ILIAS/Filesystem/src/Stream/Streams.php +++ b/components/ILIAS/Filesystem/src/Stream/Streams.php @@ -83,16 +83,24 @@ public static function ofReattachableResource($resource): ReattachableStream public static function ofFileInsideZIP(string $path_to_zip, string $path_inside_zip): ZIPStream { - // we try to open the zip file with the path inside the zip file, once with a leading slash and once without - try { - $resource = @fopen('zip://' . $path_to_zip . '#/' . $path_inside_zip, 'rb'); - } catch (\Throwable) { - $resource = null; - } - try { - $resource = $resource ?: @fopen('zip://' . $path_to_zip . '#' . $path_inside_zip, 'rb'); - } catch (\Throwable) { - $resource = null; + // Entries are stored relative since Mantis 45580 / 47237, therefore that variant + // is tried first. Containers written before still hold entries with a leading + // slash, they are covered by the second candidate. If a container holds both + // variants of a file, the relative one is the up to date one (Mantis 48047): + // the ZIP stream wrapper matches names literally, so the entry we do not ask for + // is never returned by accident. + $relative_path = ltrim($path_inside_zip, '/'); + $resource = null; + + foreach ([$relative_path, '/' . $relative_path] as $candidate) { + try { + $resource = @fopen('zip://' . $path_to_zip . '#' . $candidate, 'rb') ?: null; + } catch (\Throwable) { + $resource = null; + } + if ($resource !== null) { + break; + } } if (!is_resource($resource)) { diff --git a/components/ILIAS/Filesystem/src/Util/Archive/Archives.php b/components/ILIAS/Filesystem/src/Util/Archive/Archives.php index 55095fa3c624..3cc25bde885e 100755 --- a/components/ILIAS/Filesystem/src/Util/Archive/Archives.php +++ b/components/ILIAS/Filesystem/src/Util/Archive/Archives.php @@ -94,6 +94,10 @@ protected function mergeUnzipOptions(?UnzipOptions $unzip_options): UnzipOptions return $this->unzip_options ->withOverwrite($unzip_options->isOverwrite()) - ->withDirectoryHandling($unzip_options->getDirectoryHandling()); + ->withDirectoryHandling($unzip_options->getDirectoryHandling()) + ->withMaxAmountOfEntries($unzip_options->getMaxAmountOfEntries()) + ->withMaxUncompressedSize($unzip_options->getMaxUncompressedSize()) + ->withMaxCompressionRatio($unzip_options->getMaxCompressionRatio()) + ->withRatioCheckMinUncompressedSize($unzip_options->getRatioCheckMinUncompressedSize()); } } diff --git a/components/ILIAS/Filesystem/src/Util/Archive/PathHelper.php b/components/ILIAS/Filesystem/src/Util/Archive/PathHelper.php index 7551b01041f0..3ce48812882c 100755 --- a/components/ILIAS/Filesystem/src/Util/Archive/PathHelper.php +++ b/components/ILIAS/Filesystem/src/Util/Archive/PathHelper.php @@ -76,7 +76,11 @@ protected function normalizePath($path, $separator = '\\/'): string $path = $realpath; } - $normalized = preg_replace('#\p{C}+|^\./#u', '', (string) $path); + // only NUL bytes are removed here: $path points to an existing location in the file + // system and control characters such as \x0b are valid parts of a directory name. + // Removing them would make the path point to nothing, see + // https://mantis.ilias.de/view.php?id=30709 + $normalized = preg_replace('#\x00+|^\./#', '', (string) $path); $normalized = preg_replace('#/\.(?=/)|^\./|\./$#', '', (string) $normalized); $regex = '#\/*[^/\.]+/\.\.#Uu'; diff --git a/components/ILIAS/Filesystem/src/Util/Archive/Unzip.php b/components/ILIAS/Filesystem/src/Util/Archive/Unzip.php index 9a06e213a021..3874b15c0539 100755 --- a/components/ILIAS/Filesystem/src/Util/Archive/Unzip.php +++ b/components/ILIAS/Filesystem/src/Util/Archive/Unzip.php @@ -40,6 +40,7 @@ class Unzip protected bool $error_reading_zip = false; protected string $path_to_zip; private int $amount_of_entries = 0; + private ?bool $within_limits = null; public function __construct( protected UnzipOptions $options, @@ -74,7 +75,7 @@ protected function pathToStreamGenerator(): \Closure */ public function getPaths(): \Generator { - if (!$this->error_reading_zip) { + if (!$this->error_reading_zip && $this->isWithinLimits()) { for ($i = 0, $i_max = $this->amount_of_entries; $i < $i_max; $i++) { $path = $this->zip->getNameIndex($i, \ZipArchive::FL_UNCHANGED); if ($this->isPathIgnored($path, $this->options)) { @@ -192,12 +193,68 @@ public function hasMultipleRootEntriesInZip(): bool return false; } + /** + * Guards against decompression bombs by checking the archive metadata (entry count, total + * uncompressed size and the uncompressed/compressed ratio) before any data is handed out. + * The sizes are read from the central directory via statIndex(); a crafted archive that lies + * about these sizes fails during the subsequent extraction anyway. + * + * An archive that exceeds the limits behaves like an empty one: extract() returns false and + * all generators (getPaths(), getFiles(), getStreams(), getFileStreams(), ...) yield nothing. + * Callers that consume the streams themselves should ask this method first, so they can tell + * a rejected archive from an empty one and report it to the user. + */ + public function isWithinLimits(): bool + { + return $this->within_limits ??= $this->calculateIsWithinLimits(); + } + + private function calculateIsWithinLimits(): bool + { + $max_entries = $this->options->getMaxAmountOfEntries(); + if ($max_entries > UnzipOptions::UNLIMITED && $this->amount_of_entries > $max_entries) { + return false; + } + + $total_compressed = 0; + $total_uncompressed = 0; + for ($i = 0; $i < $this->amount_of_entries; $i++) { + $stat = $this->zip->statIndex($i, \ZipArchive::FL_UNCHANGED); + if ($stat === false) { + continue; + } + $total_compressed += max(0, (int) ($stat['comp_size'] ?? 0)); + $total_uncompressed += max(0, (int) ($stat['size'] ?? 0)); + } + + $max_uncompressed = $this->options->getMaxUncompressedSize(); + if ($max_uncompressed > UnzipOptions::UNLIMITED && $total_uncompressed > $max_uncompressed) { + return false; + } + + $max_ratio = $this->options->getMaxCompressionRatio(); + if ( + $max_ratio > UnzipOptions::UNLIMITED + && $total_compressed > 0 + && $total_uncompressed > $this->options->getRatioCheckMinUncompressedSize() + && ($total_uncompressed / $total_compressed) > $max_ratio + ) { + return false; + } + + return true; + } + public function extract(): bool { if ($this->error_reading_zip) { return false; } + if (!$this->isWithinLimits()) { + return false; + } + $destination_path = $this->options->getZipOutputPath(); if ($destination_path === null) { return false; diff --git a/components/ILIAS/Filesystem/src/Util/Archive/UnzipOptions.php b/components/ILIAS/Filesystem/src/Util/Archive/UnzipOptions.php index 7910a3b4b7fc..7d28e8717965 100755 --- a/components/ILIAS/Filesystem/src/Util/Archive/UnzipOptions.php +++ b/components/ILIAS/Filesystem/src/Util/Archive/UnzipOptions.php @@ -25,9 +25,45 @@ */ final class UnzipOptions extends Options { + /** + * @description Disables a numeric limit (ratio, entry-count or size). A value of 0 means "no limit". + */ + public const UNLIMITED = 0; + + /** + * @description Reject archives whose overall uncompressed/compressed ratio exceeds this value. + * A deflate decompression bomb reaches ~1000:1, while legitimate archives (already compressed + * media, office documents, ...) stay well below 100:1. + */ + public const DEFAULT_MAX_COMPRESSION_RATIO = 100; + + /** + * @description The ratio check is only applied once the total uncompressed size exceeds this + * floor, so small but highly compressible archives are never rejected. + */ + public const DEFAULT_RATIO_CHECK_MIN_UNCOMPRESSED_SIZE = 33554432; // 32 MiB + + /** + * @description Reject archives with more than this many entries (entry-count bomb). + */ + public const DEFAULT_MAX_AMOUNT_OF_ENTRIES = 100000; + + /** + * @description Reject archives whose total uncompressed size exceeds this value. Without an + * absolute ceiling the ratio alone allows DEFAULT_MAX_COMPRESSION_RATIO times the upload limit + * to be written, which grows with post_max_size. 4 GiB is the point where an archive requires + * Zip64; legitimate ILIAS imports stay well below it. Installations that really do import + * larger archives can raise or disable the limit per call. + */ + public const DEFAULT_MAX_UNCOMPRESSED_SIZE = 4294967296; // 4 GiB + protected ?string $zip_output_path = null; private bool $flat = false; private bool $overwrite = false; + private int $max_compression_ratio = self::DEFAULT_MAX_COMPRESSION_RATIO; + private int $ratio_check_min_uncompressed_size = self::DEFAULT_RATIO_CHECK_MIN_UNCOMPRESSED_SIZE; + private int $max_amount_of_entries = self::DEFAULT_MAX_AMOUNT_OF_ENTRIES; + private int $max_uncompressed_size = self::DEFAULT_MAX_UNCOMPRESSED_SIZE; public function getZipOutputPath(): ?string { @@ -53,4 +89,52 @@ public function withOverwrite(bool $overwrite): self return $clone; } + public function getMaxCompressionRatio(): int + { + return $this->max_compression_ratio; + } + + public function withMaxCompressionRatio(int $max_compression_ratio): self + { + $clone = clone $this; + $clone->max_compression_ratio = max(self::UNLIMITED, $max_compression_ratio); + return $clone; + } + + public function getRatioCheckMinUncompressedSize(): int + { + return $this->ratio_check_min_uncompressed_size; + } + + public function withRatioCheckMinUncompressedSize(int $ratio_check_min_uncompressed_size): self + { + $clone = clone $this; + $clone->ratio_check_min_uncompressed_size = max(0, $ratio_check_min_uncompressed_size); + return $clone; + } + + public function getMaxAmountOfEntries(): int + { + return $this->max_amount_of_entries; + } + + public function withMaxAmountOfEntries(int $max_amount_of_entries): self + { + $clone = clone $this; + $clone->max_amount_of_entries = max(self::UNLIMITED, $max_amount_of_entries); + return $clone; + } + + public function getMaxUncompressedSize(): int + { + return $this->max_uncompressed_size; + } + + public function withMaxUncompressedSize(int $max_uncompressed_size): self + { + $clone = clone $this; + $clone->max_uncompressed_size = max(self::UNLIMITED, $max_uncompressed_size); + return $clone; + } + } diff --git a/components/ILIAS/Filesystem/tests/Finder/FinderTest.php b/components/ILIAS/Filesystem/tests/Finder/FinderTest.php index ea428fe2914f..95b07854befb 100755 --- a/components/ILIAS/Filesystem/tests/Finder/FinderTest.php +++ b/components/ILIAS/Filesystem/tests/Finder/FinderTest.php @@ -18,13 +18,11 @@ declare(strict_types=1); -use PHPUnit\Framework\MockObject\MockObject; -use ILIAS\Filesystem\DTO\Metadata; -use PHPUnit\Framework\Attributes\Depends; use ILIAS\Data\DataSize; use ILIAS\Filesystem; use ILIAS\Filesystem\Finder\Finder; use ILIAS\Filesystem\MetadataType; +use PHPUnit\Framework\Attributes\Depends; use PHPUnit\Framework\TestCase; /** @@ -33,23 +31,20 @@ */ class FinderTest extends TestCase { - /** - * @throws ReflectionException - */ - private function getFlatFileSystemStructure(): MockObject + private function getFlatFileSystemStructure(): Filesystem\Filesystem&\PHPUnit\Framework\MockObject\MockObject { $fileSystem = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); $metadata = [ - new Metadata('file_1.txt', MetadataType::FILE), - new Metadata('file_2.mp3', MetadataType::FILE), - new Metadata('dir_1', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('file_1.txt', MetadataType::FILE), + new Filesystem\DTO\Metadata('file_2.mp3', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1', MetadataType::DIRECTORY), ]; $fileSystem ->expects($this->atLeast(1)) ->method('listContents') - ->willReturnCallback(function ($path) use ($metadata): array { + ->willReturnCallback(function ($path) use ($metadata) { if ('/' === $path) { return $metadata; } @@ -60,34 +55,31 @@ private function getFlatFileSystemStructure(): MockObject return $fileSystem; } - /** - * @throws ReflectionException - */ - private function getNestedFileSystemStructure(): MockObject + private function getNestedFileSystemStructure(): Filesystem\Filesystem&\PHPUnit\Framework\MockObject\MockObject { $fileSystem = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); $rootMetadata = [ - new Metadata('file_1.txt', MetadataType::FILE), - new Metadata('file_2.mp3', MetadataType::FILE), - new Metadata('dir_1', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('file_1.txt', MetadataType::FILE), + new Filesystem\DTO\Metadata('file_2.mp3', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1', MetadataType::DIRECTORY), ]; $level1Metadata = [ - new Metadata('dir_1/file_3.log', MetadataType::FILE), - new Metadata('dir_1/file_4.php', MetadataType::FILE), - new Metadata('dir_1/dir_1_1', MetadataType::DIRECTORY), - new Metadata('dir_1/dir_1_2', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('dir_1/file_3.log', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/file_4.php', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/dir_1_1', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('dir_1/dir_1_2', MetadataType::DIRECTORY), ]; $level11Metadata = [ - new Metadata('dir_1/dir_1_1/file_5.cpp', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/dir_1_1/file_5.cpp', MetadataType::FILE), ]; $level12Metadata = [ - new Metadata('dir_1/dir_1_2/file_6.py', MetadataType::FILE), - new Metadata('dir_1/dir_1_2/file_7.cpp', MetadataType::FILE), - new Metadata('dir_1/dir_1_2/dir_1_2_1', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('dir_1/dir_1_2/file_6.py', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/dir_1_2/file_7.cpp', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/dir_1_2/dir_1_2_1', MetadataType::DIRECTORY), ]; $fileSystem @@ -98,6 +90,54 @@ private function getNestedFileSystemStructure(): MockObject $level1Metadata, $level11Metadata, $level12Metadata + ) { + if ('/' === $path) { + return $rootMetadata; + } + if ('dir_1' === $path) { + return $level1Metadata; + } elseif ('dir_1/dir_1_1' === $path) { + return $level11Metadata; + } elseif ('dir_1/dir_1_2' === $path) { + return $level12Metadata; + } + + return []; + }); + + return $fileSystem; + } + + /** + * A directory whose path is rejected by the path normalizer cannot be listed, + * listContents() reports it as not found. See 0047398. + */ + private function getNestedFileSystemStructureWithAnUnlistableDirectory( + ): Filesystem\Filesystem&\PHPUnit\Framework\MockObject\MockObject { + $fileSystem = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); + + $rootMetadata = [ + new Filesystem\DTO\Metadata('file_1.txt', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1', MetadataType::DIRECTORY), + ]; + + $level1Metadata = [ + new Filesystem\DTO\Metadata('dir_1/file_2.log', MetadataType::FILE), + new Filesystem\DTO\Metadata('dir_1/dir_1_1', MetadataType::DIRECTORY), + new Filesystem\DTO\Metadata('dir_1/dir_1_2', MetadataType::DIRECTORY), + ]; + + $level12Metadata = [ + new Filesystem\DTO\Metadata('dir_1/dir_1_2/file_3.py', MetadataType::FILE), + ]; + + $fileSystem + ->expects($this->atLeast(1)) + ->method('listContents') + ->willReturnCallback(function ($path) use ( + $rootMetadata, + $level1Metadata, + $level12Metadata ): array { if ('/' === $path) { return $rootMetadata; @@ -106,7 +146,9 @@ private function getNestedFileSystemStructure(): MockObject return $level1Metadata; } if ('dir_1/dir_1_1' === $path) { - return $level11Metadata; + throw new Filesystem\Exception\DirectoryNotFoundException( + "Directory \"$path\" not found." + ); } if ('dir_1/dir_1_2' === $path) { return $level12Metadata; @@ -118,9 +160,6 @@ private function getNestedFileSystemStructure(): MockObject return $fileSystem; } - /** - * @throws ReflectionException - */ public function testFinderWillFindNoFilesOrFoldersInAnEmptyDirectory(): void { $fileSystem = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); @@ -134,9 +173,6 @@ public function testFinderWillFindNoFilesOrFoldersInAnEmptyDirectory(): void $this->assertEmpty(iterator_count($finder)); } - /** - * @throws ReflectionException - */ public function testFinderWillFindFilesAndFoldersInFlatStructure(): void { $finder = (new Finder($this->getFlatFileSystemStructure()))->in(['/']); @@ -146,9 +182,6 @@ public function testFinderWillFindFilesAndFoldersInFlatStructure(): void $this->assertCount(2, $finder->files()); } - /** - * @throws ReflectionException - */ public function testFinderWillFindFilesAndFoldersInNestedStructure(): void { $finder = (new Finder($this->getNestedFileSystemStructure()))->in(['/']); @@ -158,9 +191,17 @@ public function testFinderWillFindFilesAndFoldersInNestedStructure(): void $this->assertCount(7, $finder->files()); } - /** - * @throws ReflectionException - */ + public function testFinderWillSkipDirectoriesWhichCannotBeListed(): void + { + $finder = (new Finder($this->getNestedFileSystemStructureWithAnUnlistableDirectory()))->in(['/']); + + // the unlistable directory itself is still reported by its parent, only its + // content is missing, the traversal of the remaining tree continues + $this->assertCount(6, $finder); + $this->assertCount(3, $finder->directories()); + $this->assertCount(3, $finder->files()); + } + public function testFinderWillFindFilesAndFoldersForACertainDirectoryDepth(): void { $finder = (new Finder($this->getNestedFileSystemStructure()))->in(['/']); @@ -196,9 +237,6 @@ public function testFinderWillFindFilesAndFoldersForACertainDirectoryDepth(): vo $this->assertCount(3, $exactlyLevel2Finder->files()); } - /** - * @throws ReflectionException - */ public function testFinderWillNotSearchInExcludedFolders(): void { $finder = (new Finder($this->getNestedFileSystemStructure()))->in(['/']); @@ -214,12 +252,9 @@ public function testFinderWillNotSearchInExcludedFolders(): void $this->assertCount(6, $finderWithMultipleExcludedDirs->files()); } - /** - * @throws ReflectionException - */ public function testFinderWillFilterFilesAndFoldersByCreationTimestamp(): Filesystem\Filesystem { - $now = new \DateTimeImmutable('2019-03-30 13:00:00'); + $now = new DateTimeImmutable('2019-03-30 13:00:00'); $fs = $this->getNestedFileSystemStructure(); $fs->method('has')->willReturn(true); @@ -227,15 +262,17 @@ public function testFinderWillFilterFilesAndFoldersByCreationTimestamp(): Filesy $fs ->expects($this->atLeast(1)) ->method('getTimestamp') - ->willReturnCallback(fn($path): \DateTimeImmutable => match ($path) { - 'file_1.txt' => $now, - 'file_2.mp3' => $now->modify('+1 hour'), - 'dir_1/file_3.log' => $now->modify('+2 hour'), - 'dir_1/file_4.php' => $now->modify('+3 hour'), - 'dir_1/dir_1_1/file_5.cpp' => $now->modify('+4 hour'), - 'dir_1/dir_1_2/file_6.py' => $now->modify('+5 hour'), - 'dir_1/dir_1_2/file_7.cpp' => $now->modify('+6 hour'), - default => new \DateTimeImmutable('now'), + ->willReturnCallback(function ($path) use ($now): DateTimeImmutable { + return match ($path) { + 'file_1.txt' => $now, + 'file_2.mp3' => $now->modify('+1 hour'), + 'dir_1/file_3.log' => $now->modify('+2 hour'), + 'dir_1/file_4.php' => $now->modify('+3 hour'), + 'dir_1/dir_1_1/file_5.cpp' => $now->modify('+4 hour'), + 'dir_1/dir_1_2/file_6.py' => $now->modify('+5 hour'), + 'dir_1/dir_1_2/file_7.cpp' => $now->modify('+6 hour'), + default => new DateTimeImmutable('now'), + }; }); $finder = (new Finder($fs))->in(['/']); @@ -253,9 +290,6 @@ public function testFinderWillFilterFilesAndFoldersByCreationTimestamp(): Filesy return $fs; } - /** - * @throws ReflectionException - */ public function testFinderWillFilterFilesBySize(): void { $fs = $this->getNestedFileSystemStructure(); @@ -263,15 +297,17 @@ public function testFinderWillFilterFilesBySize(): void $fs->expects($this->atLeast(1)) ->method('getSize') - ->willReturnCallback(fn($path): DataSize => match ($path) { - 'file_1.txt' => new DataSize(PHP_INT_MAX, DataSize::Byte), - 'file_2.mp3' => new DataSize(1024, DataSize::Byte), - 'dir_1/file_3.log' => new DataSize(1024 * 1024 * 1024, DataSize::Byte), - 'dir_1/file_4.php' => new DataSize(1024 * 1024 * 127, DataSize::Byte), - 'dir_1/dir_1_1/file_5.cpp' => new DataSize(1024 * 7, DataSize::Byte), - 'dir_1/dir_1_2/file_6.py' => new DataSize(1024 * 100, DataSize::Byte), - 'dir_1/dir_1_2/file_7.cpp' => new DataSize(1, DataSize::Byte), - default => new DataSize(0, DataSize::Byte), + ->willReturnCallback(function ($path): DataSize { + return match ($path) { + 'file_1.txt' => new DataSize(PHP_INT_MAX, DataSize::Byte), + 'file_2.mp3' => new DataSize(1024, DataSize::Byte), + 'dir_1/file_3.log' => new DataSize(1024 * 1024 * 1024, DataSize::Byte), + 'dir_1/file_4.php' => new DataSize(1024 * 1024 * 127, DataSize::Byte), + 'dir_1/dir_1_1/file_5.cpp' => new DataSize(1024 * 7, DataSize::Byte), + 'dir_1/dir_1_2/file_6.py' => new DataSize(1024 * 100, DataSize::Byte), + 'dir_1/dir_1_2/file_7.cpp' => new DataSize(1, DataSize::Byte), + default => new DataSize(0, DataSize::Byte), + }; }); $finder = (new Finder($fs))->in(['/']); @@ -303,7 +339,7 @@ public function testSortingWorksAsExpected(Filesystem\Filesystem $fs): void $this->assertEquals('dir_1', $finder->sortByType()->getIterator()->current()->getPath()); $this->assertEquals('file_2.mp3', $finder->sortByType()->reverseSorting()->getIterator()->current()->getPath()); - $customSortFinder = $finder->sort(function (Metadata $left, Metadata $right): int { + $customSortFinder = $finder->sort(function (Filesystem\DTO\Metadata $left, Filesystem\DTO\Metadata $right): int { if ('dir_1/dir_1_1/file_5.cpp' === $left->getPath()) { return -1; } @@ -315,4 +351,47 @@ public function testSortingWorksAsExpected(Filesystem\Filesystem $fs): void $last = $all[iterator_count($customSortFinder) - 1]; $this->assertEquals('dir_1/dir_1_1/file_5.cpp', $last->getPath()); } + + public function testFinderCanLimitTheResultSet(): void + { + $finder = (new Finder($this->getNestedFileSystemStructure()))->in(['/']); + + $this->assertCount(5, $finder->limit(5)); + $this->assertCount(0, $finder->limit(0)); + + $limited_sorted_files = array_values(iterator_to_array($finder->files()->sortByName()->limit(2))); + $this->assertCount(2, $limited_sorted_files); + $this->assertEquals('dir_1/dir_1_1/file_5.cpp', $limited_sorted_files[0]->getPath()); + $this->assertEquals('dir_1/dir_1_2/file_6.py', $limited_sorted_files[1]->getPath()); + } + + public function testFinderLimitRejectsNegativeValues(): void + { + $fs = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); + $finder = (new Finder($fs))->in(['/']); + $this->expectException(InvalidArgumentException::class); + $finder->limit(-1); + } + + public function testFinderHasAnyDetectsMatchingAndMissingResults(): void + { + $empty_fs = $this->getMockBuilder(Filesystem\Filesystem::class)->getMock(); + $empty_fs->method('listContents')->willReturn([]); + $empty_finder = (new Finder($empty_fs))->in(['/']); + $this->assertFalse($empty_finder->hasAny()); + + $finder = (new Finder($this->getNestedFileSystemStructure()))->in(['/']); + $this->assertTrue($finder->hasAny()); + $this->assertTrue($finder->files()->hasAny()); + $this->assertFalse($finder->files()->depth('> 2')->hasAny()); + } + + public function testFinderHasAnySkipsExpensiveSortingForExistenceChecks(): void + { + $fs = $this->getFlatFileSystemStructure(); + $fs->expects($this->never())->method('getTimestamp'); + + $finder = (new Finder($fs))->in(['/']); + $this->assertTrue($finder->files()->sortByTime()->hasAny()); + } } diff --git a/components/ILIAS/Filesystem/tests/Stream/FileInsideZIPTest.php b/components/ILIAS/Filesystem/tests/Stream/FileInsideZIPTest.php new file mode 100644 index 000000000000..8f580c88e1d8 --- /dev/null +++ b/components/ILIAS/Filesystem/tests/Stream/FileInsideZIPTest.php @@ -0,0 +1,105 @@ + + */ +final class FileInsideZIPTest extends TestCase +{ + private string $zip_file; + + protected function setUp(): void + { + parent::setUp(); + $this->zip_file = tempnam(sys_get_temp_dir(), 'irss_zip_read_test_'); + } + + protected function tearDown(): void + { + parent::tearDown(); + @unlink($this->zip_file); + } + + /** + * @param array $entries + */ + private function buildZip(array $entries): void + { + $zip = new ZipArchive(); + $zip->open($this->zip_file, ZipArchive::OVERWRITE); + foreach ($entries as $name => $content) { + $zip->addFromString($name, $content); + } + $zip->close(); + } + + public function testRelativeEntryIsRead(): void + { + $this->buildZip(['style.css' => 'relative']); + + $stream = Streams::ofFileInsideZIP($this->zip_file, 'style.css'); + + $this->assertSame('relative', (string) $stream); + } + + public function testLegacyEntryIsStillRead(): void + { + $this->buildZip(['/style.css' => 'legacy']); + + $stream = Streams::ofFileInsideZIP($this->zip_file, 'style.css'); + + $this->assertSame('legacy', (string) $stream); + } + + public function testRelativeEntryWinsOverLegacyEntry(): void + { + $this->buildZip(['/style.css' => 'legacy', 'style.css' => 'relative']); + + $stream = Streams::ofFileInsideZIP($this->zip_file, 'style.css'); + + $this->assertSame('relative', (string) $stream); + } + + public function testRelativeEntryWinsAlsoIfTheRequestedPathHasALeadingSlash(): void + { + $this->buildZip(['/style.css' => 'legacy', 'style.css' => 'relative']); + + $stream = Streams::ofFileInsideZIP($this->zip_file, '/style.css'); + + $this->assertSame('relative', (string) $stream); + } + + public function testUnknownEntryThrows(): void + { + $this->buildZip(['style.css' => 'relative']); + + $this->expectException(\InvalidArgumentException::class); + Streams::ofFileInsideZIP($this->zip_file, 'does_not_exist.css'); + } +} diff --git a/components/ILIAS/Filesystem/tests/Util/LegacyZipTest.php b/components/ILIAS/Filesystem/tests/Util/LegacyZipTest.php index fc5fcc3faa49..eb2f60dbe43d 100644 --- a/components/ILIAS/Filesystem/tests/Util/LegacyZipTest.php +++ b/components/ILIAS/Filesystem/tests/Util/LegacyZipTest.php @@ -45,6 +45,8 @@ class LegacyZipTest extends TestCase private string $zip_output_path = ''; + private string $directory_with_control_characters = ''; + protected function setUp(): void { if (file_exists($this->unzips_dir . self::ZIPPED_ZIP)) { @@ -75,6 +77,9 @@ protected function tearDown(): void if (!empty($this->zip_output_path) && file_exists($this->zip_output_path)) { unlink($this->zip_output_path); } + if ($this->directory_with_control_characters !== '' && file_exists($this->directory_with_control_characters)) { + $this->recurseRmdir($this->directory_with_control_characters); + } } public function testZipAndUnzipWithTop(): void @@ -114,6 +119,41 @@ public function testZipAndUnzipWithTop(): void $this->recurseRmdir($extracting_dir); } + /** + * A directory name may legitimately contain control characters, e.g. when it has + * been derived from an exercise assignment title, see + * https://mantis.ilias.de/view.php?id=30709 + */ + public function testZipDirectoryContainingControlCharacters(): void + { + $legacy = new LegacyArchives(); + + $this->directory_with_control_characters = $directory_to_zip = __DIR__ . '/dir_zip/KW 49 _ SW 5 - Halbschnitt _' + . chr(0x0b) . 'Vollschnitt'; + mkdir($directory_to_zip . '/Abgaben', 0777, true); + file_put_contents($directory_to_zip . '/Abgaben/submission.txt', 'submission'); + + $this->zip_output_path = $zip_output_path = $this->zips_dir . self::ZIPPED_ZIP; + + $this->assertTrue($legacy->zip($directory_to_zip, $zip_output_path, true)); + $this->assertFileExists($zip_output_path); + + // the control character is stripped from the names inside the ZIP on purpose, + // see \ILIAS\Filesystem\Util::sanitizeFileName(), so only the tail is compared here + $archive = new \ZipArchive(); + $archive->open($zip_output_path); + $entries = []; + for ($i = 0; $i < $archive->numFiles; $i++) { + $entries[] = $archive->getNameIndex($i); + } + $archive->close(); + + $this->assertNotEmpty( + array_filter($entries, static fn(string $entry): bool => str_ends_with($entry, 'Abgaben/submission.txt')), + 'submission file is missing in the ZIP, found: ' . implode(', ', $entries) + ); + } + private function pathToArray(string $path): array { $ignore = ['.', '..', '.DS_Store']; diff --git a/components/ILIAS/Filesystem/tests/Util/UnzipTest.php b/components/ILIAS/Filesystem/tests/Util/UnzipTest.php index 6467552c04dd..a7052adf862b 100755 --- a/components/ILIAS/Filesystem/tests/Util/UnzipTest.php +++ b/components/ILIAS/Filesystem/tests/Util/UnzipTest.php @@ -24,6 +24,7 @@ use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; use PHPUnit\Framework\Attributes\DataProvider; use ILIAS\Filesystem\Stream\Streams; +use ILIAS\Filesystem\Util\Archive\Archives; use ILIAS\Filesystem\Util\Archive\LegacyArchives; use ILIAS\Filesystem\Util\Archive\Unzip; use ILIAS\Filesystem\Util\Archive\UnzipOptions; @@ -180,6 +181,146 @@ public function testFlatLegacyUnzip(): void $this->assertTrue($this->recurseRmdir($temp_unzip_path)); } + public function testExtractRejectsDecompressionBomb(): void + { + $bomb = sys_get_temp_dir() . '/' . uniqid('bomb', true) . '.zip'; + $zip = new \ZipArchive(); + $zip->open($bomb, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); + $zip->addFromString('bomb.txt', str_repeat("\0", 1024 * 1024)); // 1 MiB -> compresses to a few KB + $zip->close(); + + $out = $this->unzips_dir . uniqid('bomb', true); + $options = (new UnzipOptions()) + ->withZipOutputPath($out) + ->withMaxCompressionRatio(10) + ->withRatioCheckMinUncompressedSize(1024); + $unzip = new Unzip($options, Streams::ofResource(fopen($bomb, 'rb'))); + + $this->assertFalse($unzip->extract()); + $this->assertDirectoryDoesNotExist($out); + + unlink($bomb); + } + + public function testExtractRejectsTooManyEntries(): void + { + $archive = sys_get_temp_dir() . '/' . uniqid('many', true) . '.zip'; + $zip = new \ZipArchive(); + $zip->open($archive, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); + for ($i = 0; $i < 20; $i++) { + $zip->addFromString("f{$i}.txt", 'x'); + } + $zip->close(); + + $out = $this->unzips_dir . uniqid('many', true); + $options = (new UnzipOptions()) + ->withZipOutputPath($out) + ->withMaxAmountOfEntries(5); + $unzip = new Unzip($options, Streams::ofResource(fopen($archive, 'rb'))); + + $this->assertFalse($unzip->extract()); + $this->assertDirectoryDoesNotExist($out); + + unlink($archive); + } + + public function testExtractAllowsLowRatioArchiveDespiteLimits(): void + { + $archive = sys_get_temp_dir() . '/' . uniqid('normal', true) . '.zip'; + $zip = new \ZipArchive(); + $zip->open($archive, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); + $zip->addFromString('a.bin', random_bytes(4096)); // incompressible -> ratio ~1 + $zip->close(); + + $out = $this->unzips_dir . uniqid('normal', true); + $options = (new UnzipOptions()) + ->withZipOutputPath($out) + ->withMaxCompressionRatio(10) + ->withRatioCheckMinUncompressedSize(1024); + $unzip = new Unzip($options, Streams::ofResource(fopen($archive, 'rb'))); + + $this->assertTrue($unzip->extract()); + $this->assertFileExists($out . '/a.bin'); + + unlink($out . '/a.bin'); + rmdir($out); + unlink($archive); + } + + public function testStreamsAreEmptyForRejectedArchive(): void + { + $bomb = sys_get_temp_dir() . '/' . uniqid('bomb', true) . '.zip'; + $zip = new \ZipArchive(); + $zip->open($bomb, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); + $zip->addFromString('bomb.txt', str_repeat("\0", 1024 * 1024)); + $zip->close(); + + $options = (new UnzipOptions()) + ->withMaxCompressionRatio(10) + ->withRatioCheckMinUncompressedSize(1024); + $unzip = new Unzip($options, Streams::ofResource(fopen($bomb, 'rb'))); + + // the whole read API must stay empty, not only extract() + $this->assertFalse($unzip->isWithinLimits()); + $this->assertSame([], iterator_to_array($unzip->getPaths())); + $this->assertSame([], iterator_to_array($unzip->getFiles())); + $this->assertSame([], iterator_to_array($unzip->getFileStreams())); + $this->assertSame([], iterator_to_array($unzip->getStreams())); + $this->assertSame(0, $unzip->getAmountOfFiles()); + + unlink($bomb); + } + + public function testMaxUncompressedSizeIsLimitedByDefault(): void + { + $options = new UnzipOptions(); + $this->assertSame(UnzipOptions::DEFAULT_MAX_UNCOMPRESSED_SIZE, $options->getMaxUncompressedSize()); + $this->assertGreaterThan(UnzipOptions::UNLIMITED, $options->getMaxUncompressedSize()); + } + + public function testExtractRejectsArchiveExceedingMaxUncompressedSize(): void + { + $archive = sys_get_temp_dir() . '/' . uniqid('big', true) . '.zip'; + $zip = new \ZipArchive(); + $zip->open($archive, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); + $zip->addFromString('a.bin', random_bytes(4096)); // incompressible, so only the size limit can bite + $zip->close(); + + $out = $this->unzips_dir . uniqid('big', true); + $options = (new UnzipOptions()) + ->withZipOutputPath($out) + ->withMaxUncompressedSize(1024); + $unzip = new Unzip($options, Streams::ofResource(fopen($archive, 'rb'))); + + $this->assertFalse($unzip->extract()); + $this->assertDirectoryDoesNotExist($out); + + unlink($archive); + } + + public function testArchivesKeepsTheLimitsOfThePassedOptions(): void + { + $archives = new Archives(); + $unzip = $archives->unzip( + Streams::ofResource(fopen($this->zips_dir . '1_folder_1_file_mac.zip', 'rb')), + $archives->unzipOptions() + ->withMaxAmountOfEntries(3) + ->withMaxUncompressedSize(4) + ->withMaxCompressionRatio(5) + ->withRatioCheckMinUncompressedSize(6) + ); + + // the options passed to Archives::unzip() must not be dropped while merging + $options = (new \ReflectionClass($unzip))->getProperty('options'); + $options->setAccessible(true); + $options = $options->getValue($unzip); + + $this->assertSame(3, $options->getMaxAmountOfEntries()); + $this->assertSame(4, $options->getMaxUncompressedSize()); + $this->assertSame(5, $options->getMaxCompressionRatio()); + $this->assertSame(6, $options->getRatioCheckMinUncompressedSize()); + } + private function recurseRmdir(string $path_to_directory): bool { $files = array_diff(scandir($path_to_directory), ['.', '..']); diff --git a/components/ILIAS/Form/classes/class.ilTextInputGUI.php b/components/ILIAS/Form/classes/class.ilTextInputGUI.php index 4f19b4cc9df0..2fe62fd1db55 100755 --- a/components/ILIAS/Form/classes/class.ilTextInputGUI.php +++ b/components/ILIAS/Form/classes/class.ilTextInputGUI.php @@ -341,7 +341,7 @@ public function render(string $a_mode = ""): string } } } else { - $hidden = $this->getHiddenTag($postvar, $this->getValue()); + $hidden = $this->getHiddenTag($postvar, (string) $this->getValue()); } if ($hidden) { $tpl->setVariable("HIDDEN_INPUT", $hidden); diff --git a/components/ILIAS/GlobalScreen/src/Scope/Layout/MetaContent/MetaContent.php b/components/ILIAS/GlobalScreen/src/Scope/Layout/MetaContent/MetaContent.php index 17df216b85b6..24316e8c8a71 100755 --- a/components/ILIAS/GlobalScreen/src/Scope/Layout/MetaContent/MetaContent.php +++ b/components/ILIAS/GlobalScreen/src/Scope/Layout/MetaContent/MetaContent.php @@ -121,12 +121,35 @@ public function reset(): void public function addCss(string $path, string $media = self::MEDIA_SCREEN): void { - $this->css->addItem(new Css($path, $this->resource_version, $media)); + $this->css->addItem(new Css($this->toWebPath($path), $this->resource_version, $media)); } public function addJs(string $path, bool $add_version_number = false, int $batch = 2): void { - $this->js->addItem(new Js($path, $this->resource_version, $add_version_number, $batch)); + $this->js->addItem( + new Js($this->toWebPath($path), $this->resource_version, $add_version_number, $batch) + ); + } + + /** + * Resources are delivered relative to the web root, but components which know their own + * location - plugins in particular, see ilPlugin::getDirectory() - only have an absolute + * one at hand. Such a path would be written into the markup verbatim and could never be + * requested by a browser, so cut the web root off instead. + */ + private function toWebPath(string $path): string + { + if (!defined('ILIAS_ABSOLUTE_PATH')) { + return $path; + } + + $web_root = rtrim(ILIAS_ABSOLUTE_PATH, '/') . '/public/'; + + if (str_starts_with($path, $web_root)) { + return substr($path, strlen($web_root)); + } + + return $path; } public function addInlineCss(string $content, string $media = self::MEDIA_SCREEN): void diff --git a/components/ILIAS/GlobalScreen/tests/Notification/BaseNotificationSetUpTBD.php b/components/ILIAS/GlobalScreen/tests/Notification/BaseNotificationSetUpTBD.php index 7f597cf1797e..03d9ecba7368 100644 --- a/components/ILIAS/GlobalScreen/tests/Notification/BaseNotificationSetUpTBD.php +++ b/components/ILIAS/GlobalScreen/tests/Notification/BaseNotificationSetUpTBD.php @@ -78,8 +78,16 @@ protected function setUp(): void public function getUIFactory(): NoUIFactory { - $factory = new class () extends NoUIFactory { - public function item(): I\Item\Factory + $language_mock = $this->createMock(\ILIAS\Language\Language::class); + $language_mock->method('txt')->willReturnArgument(0); + + $factory = new class ($language_mock) extends NoUIFactory { + public function __construct( + protected \ILIAS\Language\Language $language, + ) { + } + + public function item(): ILIAS\UI\Component\Item\Factory { return new I\Item\Factory(); } @@ -88,7 +96,7 @@ public function symbol(): I\Symbol\Factory { return new I\Symbol\Factory( new I\Symbol\Icon\Factory(), - new I\Symbol\Glyph\Factory(), + new I\Symbol\Glyph\Factory($this->language), new I\Symbol\Avatar\Factory() ); } @@ -102,7 +110,7 @@ public function mainControls(): I\MainControls\Factory new Factory(), new I\Symbol\Factory( new I\Symbol\Icon\Factory(), - new I\Symbol\Glyph\Factory(), + new I\Symbol\Glyph\Factory($this->language), new I\Symbol\Avatar\Factory() ) ) diff --git a/components/ILIAS/GlobalScreen/tests/Scope/Layout/MediaTest.php b/components/ILIAS/GlobalScreen/tests/Scope/Layout/MediaTest.php index 8212d2803b6d..1d76b2f2468a 100755 --- a/components/ILIAS/GlobalScreen/tests/Scope/Layout/MediaTest.php +++ b/components/ILIAS/GlobalScreen/tests/Scope/Layout/MediaTest.php @@ -44,6 +44,8 @@ use ILIAS\GlobalScreen\Scope\Layout\MetaContent\Media\AbstractCollection; use ILIAS\GlobalScreen\Scope\Layout\MetaContent\Media\DeliverPhpFilter; use ILIAS\GlobalScreen\Scope\Layout\MetaContent\Media\VersionParameterFilter; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; require_once('./vendor/composer/vendor/autoload.php'); @@ -135,6 +137,67 @@ public function testAddJsFileWithQuery(): void $this->assertSame(2, $first_item->getBatch()); } + /** + * A plugin only knows its own absolute location, see ilPlugin::getDirectory(). Such a + * path must not end up in the markup verbatim, it has to be cut down to the web root. + * See 0044340. + * + * ILIAS_ABSOLUTE_PATH has to be defined for this, and other tests read that constant, + * hence the isolation. + */ + #[RunInSeparateProcess] + #[PreserveGlobalState(false)] + public function testAbsolutePathBelowTheWebRootBecomesAWebPath(): void + { + $web_path = 'Customizing/global/plugins/Services/Repository/RepositoryObject/Example/js/example.js'; + + $this->meta_content->addJs($this->webRoot() . $web_path); + $collection = $this->meta_content->getJs(); + + $first_item = iterator_to_array($collection->getItems())[$web_path]; + $this->assertInstanceOf(Js::class, $first_item); + $this->assertSame($web_path . '?' . self::VERSION . '=' . $this->version, $first_item->getContent()); + } + + #[RunInSeparateProcess] + #[PreserveGlobalState(false)] + public function testAbsolutePathBelowTheWebRootBecomesAWebPathForCssAsWell(): void + { + $web_path = 'Customizing/global/plugins/Services/Repository/RepositoryObject/Example/css/example.css'; + + $this->meta_content->addCss($this->webRoot() . $web_path); + $collection = $this->meta_content->getCss(); + + $iterator_to_array = iterator_to_array($collection->getItems()); + $first_item = array_shift($iterator_to_array); + $this->assertInstanceOf(Css::class, $first_item); + $this->assertSame($web_path . '?' . self::VERSION . '=' . $this->version, $first_item->getContent()); + } + + public function testPathOutsideOfTheWebRootIsKept(): void + { + $path = '/somewhere/else/example.js'; + + $this->meta_content->addJs($path); + $collection = $this->meta_content->getJs(); + + $first_item = iterator_to_array($collection->getItems())[$path]; + $this->assertSame($path . '?' . self::VERSION . '=' . $this->version, $first_item->getContent()); + } + + /** + * Other tests define ILIAS_ABSOLUTE_PATH as well, so its value depends on the order in + * which they run. Read it instead of assuming one. + */ + private function webRoot(): string + { + if (!defined('ILIAS_ABSOLUTE_PATH')) { + define('ILIAS_ABSOLUTE_PATH', '/var/www/ilias'); + } + + return rtrim(ILIAS_ABSOLUTE_PATH, '/') . '/public/'; + } + public function testDeliverPhpCssIsExcludedFromVersionParameter(): void { $this->meta_content->addVersionParameterFilter(new DeliverPhpFilter()); diff --git a/components/ILIAS/Glossary/Term/class.ilGlossaryTerm.php b/components/ILIAS/Glossary/Term/class.ilGlossaryTerm.php index bd85e6f407da..411e3ab9a0a1 100755 --- a/components/ILIAS/Glossary/Term/class.ilGlossaryTerm.php +++ b/components/ILIAS/Glossary/Term/class.ilGlossaryTerm.php @@ -642,9 +642,12 @@ public static function _copyTerm( int $a_term_id, int $a_glossary_id ): int { - $old_term = new ilGlossaryTerm($a_term_id); - // copy the term + try { + $old_term = new ilGlossaryTerm($a_term_id); + } catch (Exception $e) { + return 0; + } $new_term = new ilGlossaryTerm(); $new_term->setTerm($old_term->getTerm()); $new_term->setLanguage($old_term->getLanguage()); diff --git a/components/ILIAS/Glossary/classes/class.ilObjGlossary.php b/components/ILIAS/Glossary/classes/class.ilObjGlossary.php index 8a1fb18b603c..e836f7c79a41 100755 --- a/components/ILIAS/Glossary/classes/class.ilObjGlossary.php +++ b/components/ILIAS/Glossary/classes/class.ilObjGlossary.php @@ -590,6 +590,9 @@ public function cloneObject(int $target_id, int $copy_id = 0, bool $omit_tree = $term_mappings = array(); foreach (ilGlossaryTerm::getTermList([$this->getRefId()]) as $term) { $new_term_id = ilGlossaryTerm::_copyTerm($term["id"], $new_obj->getId()); + if ($new_term_id === 0) { + continue; + } $term_mappings[$term["id"]] = $new_term_id; // copy tax node assignments diff --git a/components/ILIAS/Group/tests/ilGroupEventHandlerTest.php b/components/ILIAS/Group/tests/ilGroupEventHandlerTest.php index 70da423715ec..83b73b035def 100755 --- a/components/ILIAS/Group/tests/ilGroupEventHandlerTest.php +++ b/components/ILIAS/Group/tests/ilGroupEventHandlerTest.php @@ -60,14 +60,9 @@ protected function initDependencies(): void $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $logger = $this->getMockBuilder(ilLogger::class) - ->disableOriginalConstructor() - ->getMock(); + $logger = $this->createStub(ilLogger::class); - $logger_factory = $this->getMockBuilder(ilLoggerFactory::class) - ->disableOriginalConstructor() - ->onlyMethods(['getComponentLogger']) - ->getMock(); + $logger_factory = $this->createStub(ilLoggerFactory::class); $logger_factory->method('getComponentLogger')->willReturn($logger); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); } diff --git a/components/ILIAS/HTTP/src/Request/RequestFactoryImpl.php b/components/ILIAS/HTTP/src/Request/RequestFactoryImpl.php index 1a1b36ff1f76..f1254047fd53 100755 --- a/components/ILIAS/HTTP/src/Request/RequestFactoryImpl.php +++ b/components/ILIAS/HTTP/src/Request/RequestFactoryImpl.php @@ -62,7 +62,9 @@ public function create(): ServerRequestInterface $server_request->getHeader($this->forwarded_header), true )) { - return $server_request->withUri($server_request->getUri()->withScheme($this->forwarded_proto)); + return $server_request->withUri( + $server_request->getUri()->withScheme(self::DEFAULT_FORWARDED_PROTO) + ); } // alternative if ini settings are used which look like X_FORWARDED_PROTO @@ -74,7 +76,9 @@ public function create(): ServerRequestInterface if (!in_array($this->forwarded_proto, $server_request->getHeader($header_name), true)) { continue; } - return $server_request->withUri($server_request->getUri()->withScheme($this->forwarded_proto)); + return $server_request->withUri( + $server_request->getUri()->withScheme(self::DEFAULT_FORWARDED_PROTO) + ); } } diff --git a/components/ILIAS/HTTP/src/StatusCode.php b/components/ILIAS/HTTP/src/StatusCode.php index cdac27a2a57f..0d46f3a347a5 100755 --- a/components/ILIAS/HTTP/src/StatusCode.php +++ b/components/ILIAS/HTTP/src/StatusCode.php @@ -71,6 +71,7 @@ interface StatusCode public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415; public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; public const HTTP_EXPECTATION_FAILED = 417; + public const HTTP_UNPROCESSABLE_ENTITY = 422; public const HTTP_TOO_MANY_REQUESTS = 429; // [Server Error 5xx] diff --git a/components/ILIAS/HTTP/tests/Request/RequestFactoryImplTest.php b/components/ILIAS/HTTP/tests/Request/RequestFactoryImplTest.php new file mode 100644 index 000000000000..9be4dde9c05c --- /dev/null +++ b/components/ILIAS/HTTP/tests/Request/RequestFactoryImplTest.php @@ -0,0 +1,93 @@ + + */ +final class RequestFactoryImplTest extends TestCase +{ + private array $server_backup; + + protected function setUp(): void + { + parent::setUp(); + $this->server_backup = $_SERVER; + + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['HTTP_HOST'] = 'ilias.example.com'; + $_SERVER['REQUEST_URI'] = '/ilias.php'; + unset($_SERVER['HTTPS']); + } + + protected function tearDown(): void + { + $_SERVER = $this->server_backup; + parent::tearDown(); + } + + public function testSchemeStaysUntouchedWithoutConfiguration(): void + { + $this->assertSame('http', (new RequestFactoryImpl())->create()->getUri()->getScheme()); + } + + public function testSchemeStaysUntouchedIfHeaderDoesNotMatch(): void + { + $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http'; + + $factory = new RequestFactoryImpl('X-Forwarded-Proto', 'https'); + + $this->assertSame('http', $factory->create()->getUri()->getScheme()); + } + + public function testSchemeIsHttpsIfHeaderMatches(): void + { + $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https'; + + $factory = new RequestFactoryImpl('X-Forwarded-Proto', 'https'); + + $this->assertSame('https', $factory->create()->getUri()->getScheme()); + } + + /** + * The configured header value describes when https is in use, it is not the + * protocol itself - see https://mantis.ilias.de/view.php?id=45344 + */ + public function testSchemeIsHttpsForHeaderValuesWhichAreNoProtocol(): void + { + $_SERVER['HTTP_FRONT_END_HTTPS'] = 'on'; + + $factory = new RequestFactoryImpl('FRONT-END-HTTPS', 'on'); + + $this->assertSame('https', $factory->create()->getUri()->getScheme()); + } + + public function testSchemeIsHttpsForHeaderNamesConfiguredWithUnderscores(): void + { + $_SERVER['HTTP_FRONT_END_HTTPS'] = 'on'; + + $factory = new RequestFactoryImpl('FRONT_END_HTTPS', 'on'); + + $this->assertSame('https', $factory->create()->getUri()->getScheme()); + } +} diff --git a/components/ILIAS/ILIASObject/classes/class.ilObjectGUI.php b/components/ILIAS/ILIASObject/classes/class.ilObjectGUI.php index aac6cefae523..c397b8f1f1da 100755 --- a/components/ILIAS/ILIASObject/classes/class.ilObjectGUI.php +++ b/components/ILIAS/ILIASObject/classes/class.ilObjectGUI.php @@ -306,6 +306,7 @@ protected function assignObject(): void public function prepareOutput(bool $show_sub_objects = true): bool { + $this->tpl->loadStandardTemplate(); $base_class = $this->request_wrapper->retrieve("baseClass", $this->refinery->kindlyTo()->string()); if (strtolower($base_class) == "iladministrationgui") { @@ -1065,7 +1066,7 @@ public function saveObject(): void $new_obj->setType($this->requested_new_type); $new_obj->processAutoRating(); $new_obj->setTitle($data['title_and_description']->getTitle()); - $new_obj->setDescription($data['title_and_description']->getDescription()); + $new_obj->setDescription($data['title_and_description']->getLongDescription()); $new_obj->create(); $new_obj->getObjectProperties()->storePropertyTitleAndDescription( @@ -1435,7 +1436,7 @@ protected function importFile(string $file_to_import, string $path_to_uploaded_f $this->tmp_import_dir = $imp->getTemporaryImportDir(); $this->tpl->setOnScreenMessage( 'failure', - $this->lng->txt('obj_import_file_error') . '
' . $e->getMessage() + $this->lng->txt('obj_import_file_error') ); $this->deleteUploadedImportFile($path_to_uploaded_file_in_temp_dir); return; diff --git a/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php b/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php index 3ee6b6716b1b..f42859c75b45 100755 --- a/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php +++ b/components/ILIAS/ILIASObject/classes/class.ilObjectMetaDataGUI.php @@ -321,7 +321,8 @@ protected function isLOMAvailable(): bool 'cmix', 'mep', 'mep:mpg', - 'wiki' + 'wiki', + 'lso' ]) ); } diff --git a/components/ILIAS/ILIASObject/classes/class.ilObjectServiceSettingsGUI.php b/components/ILIAS/ILIASObject/classes/class.ilObjectServiceSettingsGUI.php index c523483f4e47..897981e92bb3 100755 --- a/components/ILIAS/ILIASObject/classes/class.ilObjectServiceSettingsGUI.php +++ b/components/ILIAS/ILIASObject/classes/class.ilObjectServiceSettingsGUI.php @@ -108,7 +108,8 @@ public static function initServiceSettingsForm( $info->setValue("1"); $info->setChecked((bool) ilContainer::_lookupContainerSetting( $obj_id, - self::INFO_TAB_VISIBILITY + self::INFO_TAB_VISIBILITY, + '1' )); //$info->setOptionTitle($lng->txt('obj_tool_setting_info_tab')); $info->setInfo($lng->txt('obj_tool_setting_info_tab_info')); diff --git a/components/ILIAS/ILIASObject/src/Properties/Translations/Language.php b/components/ILIAS/ILIASObject/src/Properties/Translations/Language.php index 7d9fb4263a47..a0e08c4a8456 100755 --- a/components/ILIAS/ILIASObject/src/Properties/Translations/Language.php +++ b/components/ILIAS/ILIASObject/src/Properties/Translations/Language.php @@ -28,6 +28,12 @@ class Language { + public const KEY_LANGUAGE = 'language'; + public const KEY_BASE = 'base'; + public const KEY_DEFAULT = 'default'; + public const KEY_TITLE = 'title'; + public const KEY_DESCRIPTION = 'description'; + public function __construct( private readonly string $language_code, private string $title, @@ -97,22 +103,22 @@ public function toForm( ): array { return [ $field_factory->group([ - 'language' => $field_factory->hidden()->withValue($this->language_code), - 'title' => $field_factory->text($language->txt('title')) + self::KEY_LANGUAGE => $field_factory->hidden()->withValue($this->language_code), + self::KEY_TITLE => $field_factory->text($language->txt('title')) ->withRequired(true) ->withValue($this->title), - 'description' => $field_factory->textarea($language->txt('description')) + self::KEY_DESCRIPTION => $field_factory->textarea($language->txt('description')) ->withValue($this->description), - 'default' => $field_factory->hidden()->withValue($this->isDefault()), - 'base' => $field_factory->hidden()->withValue($this->isBase()), + self::KEY_DEFAULT => $field_factory->hidden()->withValue($this->isDefault()), + self::KEY_BASE => $field_factory->hidden()->withValue($this->isBase()), ])->withAdditionalTransformation( $refinery->custom()->transformation( static fn(array $vs): self => new self( - $vs['language'], - $vs['title'], - $vs['description'], - $vs['default'] === '1', - $vs['base'] === '1' + $vs[self::KEY_LANGUAGE], + $vs[self::KEY_TITLE], + $vs[self::KEY_DESCRIPTION], + $vs[self::KEY_DEFAULT] === '1', + $vs[self::KEY_BASE] === '1' ) ) ) @@ -126,16 +132,32 @@ public function toRow( return $row_builder->buildDataRow( $this->language_code, [ - 'language' => $this->getTranslatedLanguageName($lng, $this->language_code), - 'base' => $this->isBase(), - 'default' => $this->isDefault(), - 'title' => $this->getTitle(), - 'description' => $this->getDescription() + self::KEY_LANGUAGE => $this->getTranslatedLanguageName($lng, $this->language_code), + self::KEY_BASE => $this->isBase(), + self::KEY_DEFAULT => $this->isDefault(), + self::KEY_TITLE => $this->getTitle(), + self::KEY_DESCRIPTION => $this->getDescription() ] )->withDisabledAction(TranslationsTable::ACTION_DELETE, $this->isBase() || $this->isDefault()) ->withDisabledAction(TranslationsTable::ACTION_MAKE_DEFAULT, $this->isDefault()); } + public function getDisplayValueForKey( + SystemLanguage $lng, + string $key + ): string|bool { + return match($key) { + self::KEY_LANGUAGE => $this->getTranslatedLanguageName( + $lng, + $this->language_code + ), + self::KEY_BASE => $this->base, + self::KEY_DEFAULT => $this->default, + self::KEY_TITLE => $this->title, + self::KEY_DESCRIPTION => $this->description + }; + } + private function getTranslatedLanguageName( SystemLanguage $lng, string $language_code diff --git a/components/ILIAS/ILIASObject/src/Properties/Translations/Translations.php b/components/ILIAS/ILIASObject/src/Properties/Translations/Translations.php index 4486d11e61bb..87ed33319e1d 100755 --- a/components/ILIAS/ILIASObject/src/Properties/Translations/Translations.php +++ b/components/ILIAS/ILIASObject/src/Properties/Translations/Translations.php @@ -20,11 +20,6 @@ namespace ILIAS\ILIASObject\Properties\Translations; -use ILIAS\ILIASObject\Properties\Property; -use ILIAS\UI\Component\Input\Field\Factory as FieldFactory; -use ILIAS\UI\Component\Input\Container\Form\FormInput; -use ILIAS\Refinery\Factory as Refinery; - /** * Class handles translation mode for an object. * @@ -84,7 +79,9 @@ public function getDefaultLanguage(): string public function withDefaultLanguage(string $default_language): self { $clone = clone $this; - $clone->languages[$clone->default_language] = $clone->languages[$clone->default_language]->withDefault(false); + if (isset($clone->languages[$clone->default_language])) { + $clone->languages[$clone->default_language] = $clone->languages[$clone->default_language]->withDefault(false); + } $clone->languages[$default_language] = $clone->languages[$default_language]->withDefault(true); $clone->default_language = $default_language; return $clone; diff --git a/components/ILIAS/ILIASObject/src/Properties/Translations/TranslationsTable.php b/components/ILIAS/ILIASObject/src/Properties/Translations/TranslationsTable.php index fb9a6a8f4cad..e0506504ad1b 100644 --- a/components/ILIAS/ILIASObject/src/Properties/Translations/TranslationsTable.php +++ b/components/ILIAS/ILIASObject/src/Properties/Translations/TranslationsTable.php @@ -132,7 +132,10 @@ public function getRows( mixed $filter_data, mixed $additional_parameters ): \Generator { - foreach ($this->translations->getLanguages() as $langauge) { + foreach ($this->orderLanguages( + $this->translations->getLanguages(), + $order + ) as $langauge) { yield $langauge->toRow($row_builder, $this->lng); } } @@ -150,10 +153,10 @@ private function getColumns(): array { $cf = $this->ui_factory->table()->column(); $columns = [ - 'language' => $cf->text($this->lng->txt('language')), + Language::KEY_LANGUAGE => $cf->text($this->lng->txt('language')), ]; if ($this->translations->getContentTranslationActivated()) { - $columns['base'] = $cf->boolean( + $columns[Language::KEY_BASE] = $cf->boolean( $this->lng->txt('obj_base_lang'), $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_checked.svg', '', 'small'), $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_unchecked.svg', '', 'small') @@ -161,13 +164,13 @@ private function getColumns(): array } return $columns + [ - 'default' => $cf->boolean( + Language::KEY_DEFAULT => $cf->boolean( $this->lng->txt('default'), $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_checked.svg', '', 'small'), $this->ui_factory->symbol()->icon()->custom('assets/images/standard/icon_unchecked.svg', '', 'small') ), - 'title' => $cf->text($this->lng->txt('title')), - 'description' => $cf->text($this->lng->txt('description')), + Language::KEY_TITLE => $cf->text($this->lng->txt('title')), + Language::KEY_DESCRIPTION => $cf->text($this->lng->txt('description')), ]; } @@ -379,4 +382,26 @@ private function sendAsync(UIComponent $response): void $this->http->sendResponse(); $this->http->close(); } + + private function orderLanguages( + array $languages, + Order $order + ): array { + return $order->join( + $languages, + function (array $langs, string $field, string $direction): array { + usort( + $langs, + fn(Language $a, Language $b) => $a->getDisplayValueForKey($this->lng, $field) + <=> $b->getDisplayValueForKey($this->lng, $field) + ); + + if ($direction === 'DESC') { + return array_reverse($langs); + } + + return $langs; + } + ); + } } diff --git a/components/ILIAS/ILIASObject/src/Properties/Translations/class.TranslationGUI.php b/components/ILIAS/ILIASObject/src/Properties/Translations/class.TranslationGUI.php index b9eb39c4a766..f8b4c2915ec6 100755 --- a/components/ILIAS/ILIASObject/src/Properties/Translations/class.TranslationGUI.php +++ b/components/ILIAS/ILIASObject/src/Properties/Translations/class.TranslationGUI.php @@ -169,6 +169,7 @@ public function activateContentTranslation(): void ->getData(); if ($data === null) { + $this->listTranslations(); return; } @@ -185,7 +186,7 @@ public function activateContentTranslation(): void $this->object->getObjectProperties()->storePropertyTranslations( $this->translations ); - $this->listTranslations(); + $this->ctrl->redirectByClass(self::class); } public function deactivateContentTranslation(): void @@ -196,7 +197,7 @@ public function deactivateContentTranslation(): void ); $this->tpl->setOnScreenMessage('success', $this->lng->txt('obj_cont_transl_deactivated'), true); - $this->listTranslations(); + $this->ctrl->redirectByClass(self::class); } private function addAddLanguagesToolbarActionAndRetrieveModal( diff --git a/components/ILIAS/Imprint/PRIVACY.md b/components/ILIAS/Imprint/PRIVACY.md new file mode 100644 index 000000000000..e591e32f55f6 --- /dev/null +++ b/components/ILIAS/Imprint/PRIVACY.md @@ -0,0 +1,43 @@ +# Imprint Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information by submitting a [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories) or, if you prefer, via the [ILIAS bug tracker](https://mantis.ilias.de). When using the bug tracker, please select the corresponding component in the **Category** field.** + +## General Information + +The Imprint component provides a single, installation-wide legal notice page (also referred to as "Legal Notice" or "Impressum"). It is accessible through the ILIAS footer without authentication, meaning any visitor -- whether logged in or not -- can view the imprint content when it is activated. + +The imprint page uses the ILIAS page editor (COPage) for content management. There is exactly one imprint page per ILIAS installation (page ID 1, parent type `impr`). Since the imprint is a page object, all personal data associated with its creation and editing is managed by the COPage component, not by the Imprint component itself. + +## Integrated Components + +- The Imprint component employs the following components, please consult the respective PRIVACY.md files: + - [COPage](../COPage/PRIVACY.md) -- the page editor manages all content storage, including page history, author tracking (creator user ID, last change user ID), and page versioning for the imprint page. + - [AccessControl](../AccessControl/PRIVACY.md) -- manages permissions for editing the imprint page via the RBAC system (`ilPermissionGUI`). + - ILIASObject -- provides the base object framework (`ilObject2`, `ilObject2GUI`) for the legal notice administration object. + +## Data being stored + +The Imprint component does not store personal data in its own database tables. All data storage is delegated to the COPage component, which stores the following for the imprint page in the `page_object` table: + +- **User ID of the page creator**: stored as `create_user` when the imprint page is first created. +- **User ID of the last editor**: stored as `last_change_user` each time the imprint page is saved. +- **Page history entries**: each edit creates a history record including the **user ID** of the editor and a **timestamp**, stored in the `page_history` table. + +For details on how this data is handled, see the [COPage PRIVACY.md](../COPage/PRIVACY.md). + +## Data being presented + +- **Any visitor** (including unauthenticated users) can view the imprint page content when it is activated. The content itself is static text entered by persons with editing permissions and does not display system-managed personal data of other users. +- **Persons with the "Write" permission** on the Legal Notice administration object can edit the imprint page. Through the page editor, they have access to the **page history**, which includes **timestamps** and the **user IDs** of persons who made previous edits (as documented by COPage). +- If the imprint page is **not activated**, a preview is shown only to persons with the "Write" permission, along with a notice that the imprint is inactive. + +## Data being deleted + +- The Imprint component does not provide its own deletion mechanism for personal data. The imprint is a system object that exists exactly once per installation and is not intended to be deleted. +- **Page history** entries for the imprint page are managed by the COPage component. For details on how page history and author information are handled upon user account deletion, see the [COPage PRIVACY.md](../COPage/PRIVACY.md). +- **When a user account is deleted**, the COPage component retains the page content but no longer displays the account name, first name, or last name of the deleted user in page history or authorship information. + +## Data being exported + +- The Imprint component does not provide any export functionality for the imprint page. +- No personal data is exported through this component. diff --git a/components/ILIAS/Init/classes/class.ilErrorHandling.php b/components/ILIAS/Init/classes/class.ilErrorHandling.php index 7676978ba4c1..33807ca5b0bd 100755 --- a/components/ILIAS/Init/classes/class.ilErrorHandling.php +++ b/components/ILIAS/Init/classes/class.ilErrorHandling.php @@ -18,6 +18,9 @@ declare(strict_types=1); +use ILIAS\Init\ErrorHandling\Infrastructure\Whoops as ErrorHandlers; +use ILIAS\Init\ErrorHandling\Infrastructure\Logging as ErrorLogging; +use ILIAS\Init\ErrorHandling; use Whoops\Run; use Whoops\RunInterface; use Whoops\Handler\PrettyPageHandler; @@ -34,7 +37,7 @@ * @todo when an error occured and clicking the back button to return to previous page the referer-var in session is deleted -> server error * @todo This class is a candidate for a singleton. initHandlers could only be called once per process anyways, as it checks for static $handlers_registered. */ -class ilErrorHandling +class ilErrorHandling implements ErrorHandling\Application\ContextErrorHandlerProvider { /** @var list */ private const array SENSTIVE_PARAMETER_NAMES = [ @@ -55,6 +58,8 @@ class ilErrorHandling protected ?RunInterface $whoops; protected string $message; + protected ErrorHandling\Incident\ErrorIncidentRegistry $error_incident_registry; + protected ErrorHandling\Application\DevmodeState $devmode_state; /** Error level 1: exit application immedietly */ public int $FATAL = 1; /** Error level 2: show warning page */ @@ -67,6 +72,8 @@ public function __construct() $this->FATAL = 1; $this->WARNING = 2; $this->MESSAGE = 3; + $this->error_incident_registry = new ErrorHandling\Incident\InMemoryErrorIncidentRegistry(); + $this->devmode_state = new ErrorHandling\Infrastructure\Environment\RuntimeDevmodeState(); $this->initWhoopsHandlers(); @@ -89,10 +96,26 @@ protected function initWhoopsHandlers(): void $runtime = $this->getRuntime(); $this->whoops = $this->getWhoops(); - $this->whoops->pushHandler(new ilDelegatingHandler($this, self::SENSTIVE_PARAMETER_NAMES)); + $this->whoops->pushHandler( + new ErrorHandlers\DelegatingHandler($this, self::SENSTIVE_PARAMETER_NAMES) + ); if ($runtime->shouldLogErrors()) { $this->whoops->pushHandler($this->loggingHandler()); } + $this->whoops->pushHandler( + new ErrorHandlers\RecordErrorIncidentHandler( + new ErrorHandling\Application\ProductionOnlyErrorIncidentReporting( + new ErrorHandling\Application\ReportErrorIncident( + new ErrorLogging\LoggingErrorLogDirectory(), + new ErrorLogging\LoggingErrorFileStorageAdapter(), + new ErrorHandling\Incident\SessionPrefixedErrorIncidentFactory(), + $this->error_incident_registry, + self::SENSTIVE_PARAMETER_NAMES + ), + $this->devmode_state + ) + ) + ); $this->whoops->register(); self::$whoops_handlers_registered = true; @@ -106,7 +129,10 @@ public function getHandler(): HandlerInterface { if (ilContext::getType() === ilContext::CONTEXT_SOAP && strcasecmp($_SERVER['REQUEST_METHOD'] ?? '', 'post') === 0) { - return new ilSoapExceptionHandler(); + return new ErrorHandlers\SoapExceptionHandler( + $this->error_incident_registry, + $this->devmode_state + ); } // TODO: There might be more specific execution contexts (WebDAV, REST, etc.) that need specific error handling. @@ -222,7 +248,7 @@ protected function getWhoops(): RunInterface protected function isDevmodeActive(): bool { - return defined('DEVMODE') && (int) DEVMODE === 1; + return $this->devmode_state->isActive(); } protected function defaultHandler(): HandlerInterface @@ -230,40 +256,18 @@ protected function defaultHandler(): HandlerInterface return new CallbackHandler(function ($exception, Inspector $inspector, Run $run) { global $DIC; - $logger = ilLoggingErrorSettings::getInstance(); - $message = 'Sorry, an error occured.'; if ($DIC->isDependencyAvailable('language')) { $DIC->language()->loadLanguageModule('logging'); $message = $DIC->language()->txt('error_sry_error'); } - if (!empty($logger->folder())) { - $session_id = substr(session_id(), 0, 5); - $r = new \Random\Randomizer(); - $err_num = $r->getInt(1, 9999); - $file_name = $session_id . '_' . $err_num; - - $lwriter = new ilLoggingErrorFileStorage($inspector, $logger->folder(), $file_name); - $lwriter = $lwriter->withExclusionList(self::SENSTIVE_PARAMETER_NAMES); - $lwriter->write(); - - if ($DIC->isDependencyAvailable('language')) { - $message = sprintf($DIC->language()->txt('log_error_message'), $file_name); - if ($logger->mail()) { - $message .= ' ' . sprintf( - $DIC->language()->txt('log_error_message_send_mail'), - $logger->mail(), - $file_name, - $logger->mail() - ); - } - } else { - $message = 'Sorry, an error occured. A logfile has been created which can be identified via the code "' . $file_name . '"'; - if ($logger->mail()) { - $message .= ' ' . 'Please send a mail to ' . $logger->mail() . ''; - } - } + $incident = $this->error_incident_registry->current(); + if ($incident !== null) { + $language = $DIC->isDependencyAvailable('language') ? $DIC->language() : null; + $message = new ErrorHandling\Notification\ErrorIncidentUserMessage( + ilLoggingErrorSettings::getInstance() + )->format($incident, $language); } if ($DIC->isDependencyAvailable('ui') && isset($DIC['tpl']) && $DIC->isDependencyAvailable('ctrl')) { @@ -283,10 +287,12 @@ protected function devmodeHandler(): HandlerInterface switch (ERROR_HANDLER) { case 'TESTING': - return (new ilTestingHandler())->withExclusionList(self::SENSTIVE_PARAMETER_NAMES); + return new ErrorHandlers\TestingHandler() + ->withExclusionList(self::SENSTIVE_PARAMETER_NAMES); case 'PLAIN_TEXT': - return (new ilPlainTextHandler())->withExclusionList(self::SENSTIVE_PARAMETER_NAMES); + return new ErrorHandlers\PlainTextHandler() + ->withExclusionList(self::SENSTIVE_PARAMETER_NAMES); case 'PRETTY_PAGE': // fallthrough diff --git a/components/ILIAS/setup_/classes/class.ilIniFilesPopulatedObjective.php b/components/ILIAS/Init/classes/class.ilIniFilesPopulatedObjective.php similarity index 94% rename from components/ILIAS/setup_/classes/class.ilIniFilesPopulatedObjective.php rename to components/ILIAS/Init/classes/class.ilIniFilesPopulatedObjective.php index 75d3cc184ca7..877696fb0668 100755 --- a/components/ILIAS/setup_/classes/class.ilIniFilesPopulatedObjective.php +++ b/components/ILIAS/Init/classes/class.ilIniFilesPopulatedObjective.php @@ -65,7 +65,7 @@ public function achieve(Setup\Environment $environment): Setup\Environment $path = $this->getILIASIniPath(); if (!file_exists($path)) { $ini = new ilIniFile($path); - $ini->GROUPS = parse_ini_file(__DIR__ . "/../ilias.master.ini.php", true); + $ini->GROUPS = parse_ini_file(dirname(__DIR__) . "/resources/ilias.master.ini.php", true); $ini->write(); $environment = $environment ->withResource(Setup\Environment::RESOURCE_ILIAS_INI, $ini); @@ -74,7 +74,7 @@ public function achieve(Setup\Environment $environment): Setup\Environment $path = $this->getClientIniPath($client_id); if (!file_exists($path)) { $client_ini = new ilIniFile($path); - $client_ini->GROUPS = parse_ini_file(__DIR__ . "/../client.master.ini.php", true); + $client_ini->GROUPS = parse_ini_file(dirname(__DIR__) . "/resources/client.master.ini.php", true); $client_ini->write(); $environment = $environment ->withResource(Setup\Environment::RESOURCE_CLIENT_INI, $client_ini); diff --git a/components/ILIAS/Init/classes/class.ilInitialisation.php b/components/ILIAS/Init/classes/class.ilInitialisation.php index 33810d466bb9..14302b56b811 100755 --- a/components/ILIAS/Init/classes/class.ilInitialisation.php +++ b/components/ILIAS/Init/classes/class.ilInitialisation.php @@ -36,6 +36,7 @@ use ILIAS\ILIASObject\Properties\AdditionalProperties\Icon\Factory as CustomIconFactory; use ILIAS\User\PublicInterface as UserPublicInterface; use ILIAS\Mail\Service\MailService; +use ILIAS\Init\AllModernComponents; // needed for slow queries, etc. if (!isset($GLOBALS['ilGlobalStartTime']) || !$GLOBALS['ilGlobalStartTime']) { @@ -1146,7 +1147,9 @@ public static function reInitUser(): void } /** - * ilias initialisation + * @deprecated since ILIAS 12; please use the {@see AllModernComponents} entry point instead. + * See `components/ILIAS/Component/docs/component-bootstrap-migration.md` for a + * more detailed description. */ public static function initILIAS(): void { diff --git a/components/ILIAS/Init/classes/class.ilPasswordAssistanceGUI.php b/components/ILIAS/Init/classes/class.ilPasswordAssistanceGUI.php index fef3663cbd05..93a10cca560e 100755 --- a/components/ILIAS/Init/classes/class.ilPasswordAssistanceGUI.php +++ b/components/ILIAS/Init/classes/class.ilPasswordAssistanceGUI.php @@ -45,6 +45,7 @@ class ilPasswordAssistanceGUI implements ilCtrlSecurityInterface private ilObjUser $actor; private ILIAS\Data\Clock\ClockInterface $clock; private ILIAS\Init\PasswordAssitance\PasswordAssistanceRepository $pwa_repository; + private readonly \ILIAS\Mail\Service\MailSignatureService $signature_service; public function __construct() { @@ -68,6 +69,7 @@ public function __construct() $this->clock ); $this->help->setScreenIdComponent('init'); + $this->signature_service = $DIC->mail()->signature(); } private function retrieveRequestedKey(): string @@ -419,9 +421,7 @@ private function sendPasswordAssistanceMail(ilObjUser $userObj): void $mm->From($sender); $mm->To($userObj->getEmail()); $mm->Body( - str_replace( - ["\\n", "\\t"], - ["\n", "\t"], + $this->buildSystemMailBody( sprintf( $this->lng->txt('pwassist_mail_body'), $pwassist_url, @@ -816,9 +816,7 @@ private function sendUsernameAssistanceMail(string $email, array $logins): void $mm->From($sender); $mm->To($email); $mm->Body( - str_replace( - ["\\n", "\\t"], - ["\n", "\t"], + $this->buildSystemMailBody( sprintf( $this->lng->txt('pwassist_username_mail_body'), implode(",\n", $logins), @@ -854,4 +852,21 @@ private function fillPermanentLink(string $context): void { $this->tpl->setPermanentLink('assistant', null, $context); } + + /** + * Appends the installation signature using line breaks that match the resolved mail body format. + * This should be not needed once "Mail" does not accept primitive strings anymore but supports + * real "Text" handling {@see docs/development/text-representation.md} + */ + private function buildSystemMailBody(string $content): string + { + $body = str_replace(["\\n", "\\t"], ["\n", "\t"], $content); + $signature = $this->signature_service->installation(); + + if (strip_tags($body) !== $body) { + $signature = nl2br($signature); + } + + return $body . $signature; + } } diff --git a/components/ILIAS/setup_/client.master.ini.php b/components/ILIAS/Init/resources/client.master.ini.php similarity index 100% rename from components/ILIAS/setup_/client.master.ini.php rename to components/ILIAS/Init/resources/client.master.ini.php diff --git a/components/ILIAS/setup_/ilias.master.ini.php b/components/ILIAS/Init/resources/ilias.master.ini.php similarity index 100% rename from components/ILIAS/setup_/ilias.master.ini.php rename to components/ILIAS/Init/resources/ilias.master.ini.php diff --git a/components/ILIAS/Init/src/ErrorHandling/Application/ContextErrorHandlerProvider.php b/components/ILIAS/Init/src/ErrorHandling/Application/ContextErrorHandlerProvider.php new file mode 100644 index 000000000000..4a9c36464949 --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Application/ContextErrorHandlerProvider.php @@ -0,0 +1,31 @@ + $sensitive_parameter_names + */ + public function write( + Inspector $inspector, + string $directory, + string $file_name, + array $sensitive_parameter_names + ): void; +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Application/ProductionOnlyErrorIncidentReporting.php b/components/ILIAS/Init/src/ErrorHandling/Application/ProductionOnlyErrorIncidentReporting.php new file mode 100644 index 000000000000..20776fb33210 --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Application/ProductionOnlyErrorIncidentReporting.php @@ -0,0 +1,46 @@ +devmode_state->isActive()) { + return null; + } + + return $this->reporting->report($inspector); + } +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Application/ReportErrorIncident.php b/components/ILIAS/Init/src/ErrorHandling/Application/ReportErrorIncident.php new file mode 100644 index 000000000000..270af6daa88e --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Application/ReportErrorIncident.php @@ -0,0 +1,61 @@ + */ + private readonly array $sensitive_parameter_names + ) { + } + + public function report(Inspector $inspector): ?ErrorIncident + { + $directory = $this->log_directory->path(); + if ($directory === '') { + return null; + } + + $incident = $this->incident_factory->create(session_id()); + $this->log_file_storage->write( + $inspector, + $directory, + $incident->identifier()->value(), + $this->sensitive_parameter_names + ); + $this->incident_registry->record($incident); + + return $incident; + } +} diff --git a/components/ILIAS/setup_/setup_.php b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncident.php similarity index 56% rename from components/ILIAS/setup_/setup_.php rename to components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncident.php index 5d4d38b51a31..0088adc823c3 100644 --- a/components/ILIAS/setup_/setup_.php +++ b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncident.php @@ -18,20 +18,21 @@ declare(strict_types=1); -namespace ILIAS; +namespace ILIAS\Init\ErrorHandling\Incident; -class setup_ implements Component\Component +/** + * A reported error incident. The identifier is shared between the dedicated log + * file name and the user-facing error message. + */ +final readonly class ErrorIncident { - public function init( - array | \ArrayAccess &$define, - array | \ArrayAccess &$implement, - array | \ArrayAccess &$use, - array | \ArrayAccess &$contribute, - array | \ArrayAccess &$seek, - array | \ArrayAccess &$provide, - array | \ArrayAccess &$pull, - array | \ArrayAccess &$internal, - ): void { - // ... + public function __construct( + private ErrorIncidentId $id + ) { + } + + public function identifier(): ErrorIncidentId + { + return $this->id; } } diff --git a/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentFactory.php b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentFactory.php new file mode 100644 index 000000000000..66e0220aac6d --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentFactory.php @@ -0,0 +1,29 @@ +value; + } +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentRegistry.php b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentRegistry.php new file mode 100644 index 000000000000..41fb19438355 --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Incident/ErrorIncidentRegistry.php @@ -0,0 +1,33 @@ +current = $incident; + } + + public function current(): ?ErrorIncident + { + return $this->current; + } + + public function clear(): void + { + $this->current = null; + } +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Incident/SessionPrefixedErrorIncidentFactory.php b/components/ILIAS/Init/src/ErrorHandling/Incident/SessionPrefixedErrorIncidentFactory.php new file mode 100644 index 000000000000..e1d15d77cf3f --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Incident/SessionPrefixedErrorIncidentFactory.php @@ -0,0 +1,40 @@ +randomizer->getInt(1, 9999); + + return new ErrorIncident(new ErrorIncidentId($session_prefix . '_' . $error_number)); + } +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Environment/RuntimeDevmodeState.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Environment/RuntimeDevmodeState.php new file mode 100644 index 000000000000..b6860fb8fd4a --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Environment/RuntimeDevmodeState.php @@ -0,0 +1,37 @@ +withExclusionList($sensitive_parameter_names); + $writer->write(); + } +} diff --git a/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Logging/LoggingErrorLogDirectory.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Logging/LoggingErrorLogDirectory.php new file mode 100644 index 000000000000..30fab2c48bdf --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Logging/LoggingErrorLogDirectory.php @@ -0,0 +1,31 @@ +folder(); + } +} diff --git a/components/ILIAS/Init/classes/ErrorHandling/class.ilDelegatingHandler.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/DelegatingHandler.php similarity index 89% rename from components/ILIAS/Init/classes/ErrorHandling/class.ilDelegatingHandler.php rename to components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/DelegatingHandler.php index 221a908a9030..44884b1cc182 100755 --- a/components/ILIAS/Init/classes/ErrorHandling/class.ilDelegatingHandler.php +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/DelegatingHandler.php @@ -18,6 +18,9 @@ declare(strict_types=1); +namespace ILIAS\Init\ErrorHandling\Infrastructure\Whoops; + +use ILIAS\Init\ErrorHandling\Application\ContextErrorHandlerProvider; use Whoops\Handler\Handler; use Whoops\Handler\HandlerInterface; @@ -30,9 +33,8 @@ * workaround. * This class is not ment to be extended, as the definition of error handlers should be handled in one place * in ilErrorHandling, so this class acts rather dump and asks ilErrorHandling for a handler. - * @author Richard Klees */ -final class ilDelegatingHandler extends Handler +final class DelegatingHandler extends Handler { private ?HandlerInterface $current_handler = null; @@ -40,7 +42,7 @@ final class ilDelegatingHandler extends Handler * @param list $sensitive_data */ public function __construct( - private readonly ilErrorHandling $error_handling, + private readonly ContextErrorHandlerProvider $error_handling, private readonly array $sensitive_data = [] ) { } @@ -48,15 +50,15 @@ public function __construct( private function hideSensitiveData(array $key_value_pairs): array { foreach ($key_value_pairs as $key => &$value) { - if (is_array($value)) { + if (\is_array($value)) { $value = $this->hideSensitiveData($value); } - if (is_string($value) && in_array($key, $this->sensitive_data, true)) { + if (\is_string($value) && \in_array($key, $this->sensitive_data, true)) { $value = 'REMOVED FOR SECURITY'; } - if ($key === 'PHPSESSID' && is_string($value)) { + if ($key === 'PHPSESSID' && \is_string($value)) { $value = substr($value, 0, 5) . ' (SHORTENED FOR SECURITY)'; } @@ -85,7 +87,7 @@ private function hideSensitiveData(array $key_value_pairs): array */ public function handle(): ?int { - if (defined('IL_INITIAL_WD')) { + if (\defined('IL_INITIAL_WD')) { chdir(IL_INITIAL_WD); } @@ -103,6 +105,7 @@ public function handle(): ?int $this->current_handler->setRun($this->getRun()); $this->current_handler->setException($this->getException()); $this->current_handler->setInspector($this->getInspector()); + return $this->current_handler->handle(); } diff --git a/components/ILIAS/Init/classes/ErrorHandling/class.ilPlainTextHandler.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/PlainTextHandler.php similarity index 87% rename from components/ILIAS/Init/classes/ErrorHandling/class.ilPlainTextHandler.php rename to components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/PlainTextHandler.php index ef66bf13c729..bfc6e0f1997c 100755 --- a/components/ILIAS/Init/classes/ErrorHandling/class.ilPlainTextHandler.php +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/PlainTextHandler.php @@ -18,16 +18,19 @@ declare(strict_types=1); +namespace ILIAS\Init\ErrorHandling\Infrastructure\Whoops; + +use Throwable; use Whoops\Exception\Formatter; +use Whoops\Handler\PlainTextHandler as WhoopsPlainTextHandler; /** * A Whoops error handler that prints the same content as the PrettyPageHandler but as plain text. * This is used for better coexistence with xdebug, see #16627. - * @author Richard Klees */ -class ilPlainTextHandler extends \Whoops\Handler\PlainTextHandler +class PlainTextHandler extends WhoopsPlainTextHandler { - protected const KEY_SPACE = 25; + protected const int KEY_SPACE = 25; /** @var list */ private array $exclusion_list = []; @@ -39,6 +42,7 @@ public function withExclusionList(array $exclusion_list): self { $clone = clone $this; $clone->exclusion_list = $exclusion_list; + return $clone; } @@ -54,18 +58,15 @@ public function generateResponse(): string protected function getSimpleExceptionOutput(Throwable $exception): string { - return sprintf( + return \sprintf( '%s: %s in file %s on line %d', - get_class($exception), + $exception::class, $exception->getMessage(), $exception->getFile(), $exception->getLine() ); } - /** - * Get a short info about the exception. - */ protected function getPlainTextExceptionOutput(bool $with_previous = true): string { $message = Formatter::formatExceptionPlain($this->getInspector()); @@ -82,20 +83,15 @@ protected function getPlainTextExceptionOutput(bool $with_previous = true): stri return $message; } - /** - * Get the header for the page. - */ protected function tablesContent(): string { $ret = ''; foreach ($this->tables() as $title => $content) { $ret .= "\n\n-- $title --\n\n"; - if (count($content) > 0) { + if ($content !== []) { foreach ($content as $key => $value) { $key = str_pad((string) $key, self::KEY_SPACE); - // indent multiline values, first print_r, split in lines, - // indent all but first line, then implode again. $first = true; $indentation = str_pad('', self::KEY_SPACE); $value = implode( @@ -106,6 +102,7 @@ static function ($line) use (&$first, $indentation): string { $first = false; return $line; } + return $indentation . $line; }, explode("\n", print_r($value, true)) @@ -122,9 +119,6 @@ static function ($line) use (&$first, $indentation): string { return $this->stripNullBytes($ret); } - /** - * Get the tables that should be rendered. - */ protected function tables(): array { $post = $_POST; @@ -170,8 +164,7 @@ private function hideSensitiveData(array $super_global): array */ private function shortenPHPSessionId(array $server): array { - $cookie_content = $server['HTTP_COOKIE']; - $cookie_content = explode(';', $cookie_content); + $cookie_content = explode(';', $server['HTTP_COOKIE']); foreach ($cookie_content as $key => $content) { $content_array = explode('=', $content); diff --git a/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/RecordErrorIncidentHandler.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/RecordErrorIncidentHandler.php new file mode 100644 index 000000000000..93db5c4d366f --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/RecordErrorIncidentHandler.php @@ -0,0 +1,42 @@ +error_incident_reporting->report($this->getInspector()); + + return null; + } +} diff --git a/components/ILIAS/Init/classes/ErrorHandling/class.ilSoapExceptionHandler.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/SoapExceptionHandler.php similarity index 55% rename from components/ILIAS/Init/classes/ErrorHandling/class.ilSoapExceptionHandler.php rename to components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/SoapExceptionHandler.php index 6efb7c69662e..f4ccf3e838c5 100644 --- a/components/ILIAS/Init/classes/ErrorHandling/class.ilSoapExceptionHandler.php +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/SoapExceptionHandler.php @@ -18,20 +18,43 @@ declare(strict_types=1); -class ilSoapExceptionHandler extends \Whoops\Handler\Handler +namespace ILIAS\Init\ErrorHandling\Infrastructure\Whoops; + +use ILIAS\Init\ErrorHandling\Application\DevmodeState; +use ILIAS\Init\ErrorHandling\Incident\ErrorIncidentRegistry; +use Throwable; +use Whoops\Exception\Formatter; +use Whoops\Handler\Handler; + +/** + * Whoops handler that renders SOAP fault responses for SOAP POST requests. + */ +final class SoapExceptionHandler extends Handler { + public function __construct( + private readonly ErrorIncidentRegistry $incident_registry, + private readonly DevmodeState $devmode_state + ) { + } + private function buildFaultString(): string { - if (!defined('DEVMODE') || DEVMODE !== 1) { - return htmlspecialchars($this->getInspector()->getException()->getMessage()); + $incident = $this->incident_registry->current(); + + if ($this->devmode_state->isActive()) { + $fault_string = Formatter::formatExceptionPlain($this->getInspector()); + $exception = $this->getInspector()->getException(); + $previous = $exception->getPrevious(); + while ($previous) { + $fault_string .= "\n\nCaused by\n" . $this->getSimpleExceptionOutput($previous); + $previous = $previous->getPrevious(); + } + } else { + $fault_string = $this->getInspector()->getException()->getMessage(); } - $fault_string = \Whoops\Exception\Formatter::formatExceptionPlain($this->getInspector()); - $exception = $this->getInspector()->getException(); - $previous = $exception->getPrevious(); - while ($previous) { - $fault_string .= "\n\nCaused by\n" . $this->getSimpleExceptionOutput($previous); - $previous = $previous->getPrevious(); + if ($incident !== null) { + $fault_string .= "\n\n (incident code: " . $incident->identifier()->value() . ')'; } return htmlspecialchars($fault_string); @@ -39,9 +62,9 @@ private function buildFaultString(): string private function getSimpleExceptionOutput(Throwable $exception): string { - return sprintf( + return \sprintf( '%s: %s in file %s on line %d', - get_class($exception), + $exception::class, $exception->getMessage(), $exception->getFile(), $exception->getLine() @@ -52,7 +75,7 @@ public function handle(): ?int { echo $this->toXml(); - return \Whoops\Handler\Handler::QUIT; + return Handler::QUIT; } private function toXml(): string diff --git a/components/ILIAS/Init/classes/ErrorHandling/class.ilTestingHandler.php b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/TestingHandler.php similarity index 89% rename from components/ILIAS/Init/classes/ErrorHandling/class.ilTestingHandler.php rename to components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/TestingHandler.php index 9fed81e5416a..89f5bc4d47f1 100755 --- a/components/ILIAS/Init/classes/ErrorHandling/class.ilTestingHandler.php +++ b/components/ILIAS/Init/src/ErrorHandling/Infrastructure/Whoops/TestingHandler.php @@ -18,13 +18,14 @@ declare(strict_types=1); +namespace ILIAS\Init\ErrorHandling\Infrastructure\Whoops; + /** * A Whoops error handler for testing. * This yields the same output as the plain text handler, but prints a nice message to the tester on top of * the page. - * @author Richard Klees */ -class ilTestingHandler extends ilPlainTextHandler +final class TestingHandler extends PlainTextHandler { public function generateResponse(): string { diff --git a/components/ILIAS/Init/src/ErrorHandling/Notification/ErrorIncidentUserMessage.php b/components/ILIAS/Init/src/ErrorHandling/Notification/ErrorIncidentUserMessage.php new file mode 100644 index 000000000000..a2355c1011bf --- /dev/null +++ b/components/ILIAS/Init/src/ErrorHandling/Notification/ErrorIncidentUserMessage.php @@ -0,0 +1,67 @@ +identifier()->value(); + + if ($language !== null) { + $language->loadLanguageModule('logging'); + $message = \sprintf($language->txt('log_error_message'), $identifier); + + $mail = $this->error_settings->mail(); + if ($mail !== '') { + $message .= ' ' . \sprintf( + $language->txt('log_error_message_send_mail'), + $mail, + $identifier, + $mail + ); + } + + return $message; + } + + $message = 'Sorry, an error occured. A logfile has been created which can be identified via the code "' + . $identifier . '"'; + + $mail = $this->error_settings->mail(); + if ($mail !== '') { + $message .= ' ' . 'Please send a mail to ' . $mail . ''; + } + + return $message; + } +} diff --git a/components/ILIAS/Init/classes/ErrorHandling/README.md b/components/ILIAS/Init/src/ErrorHandling/README.md similarity index 54% rename from components/ILIAS/Init/classes/ErrorHandling/README.md rename to components/ILIAS/Init/src/ErrorHandling/README.md index cef25f90620d..e4d4d7b0eca7 100644 --- a/components/ILIAS/Init/classes/ErrorHandling/README.md +++ b/components/ILIAS/Init/src/ErrorHandling/README.md @@ -1,8 +1,33 @@ -# Error Responders +# Error Handling -This package provides responders for rendering HTTP error pages in ILIAS. +This package covers HTTP error responses and exception logging for ILIAS. -## When to use which responder +## Error incidents and log files + +If a dedicated error log folder is configured, uncaught exceptions are written +to a file in that folder. The user-facing error message references the same +identifier as the file name (for example `abcde_1234`), so reports can be matched +to log files on disk. + +The identifier is represented as an `ErrorIncident` and kept for the current +request in an `ErrorIncidentRegistry`. That way the handler writing the log file +and the handler building the response message share one value. + +`ReportErrorIncident` performs the actual reporting. It is invoked from +`RecordErrorIncidentHandler`, which is registered in the Whoops chain before the +response handlers run. Implementation code is under `Init/src/ErrorHandling/` +(`Incident`, `Application`, `Notification`, `Infrastructure`). + +## Whoops handler chain + +`ilErrorHandling` registers handlers in reverse order (the last pushed handler +runs first): + +1. `RecordErrorIncidentHandler` — writes the dedicated log file when configured +2. `loggingHandler()` — application log and `error_log()` where enabled +3. `DelegatingHandler` — selects the response handler (production, SOAP, devmode, …) + +## When to use which HTTP responder - **ErrorPageResponder** (`Http\ErrorPageResponder`): Use when the DI container and all ILIAS services (UI, language, HTTP, etc.) are available. Renders a full ILIAS page with a UI-Framework MessageBox and optional back button. Use for expected errors (e.g. routing failures, access denied) that should be shown as a proper HTML page. diff --git a/components/ILIAS/Init/src/ErrorHandling/ROADMAP.md b/components/ILIAS/Init/src/ErrorHandling/ROADMAP.md index 3770ffb90e59..47178e21b1e3 100644 --- a/components/ILIAS/Init/src/ErrorHandling/ROADMAP.md +++ b/components/ILIAS/Init/src/ErrorHandling/ROADMAP.md @@ -49,24 +49,17 @@ In almost all cases this redirect is unnecessary: ### Unified log file reporting for all handlers -**Current behaviour** - -Only the **default handler** (production) writes exceptions to a dedicated log -file (via `ilLoggingErrorFileStorage`) when configured. Other handlers (e.g., -SOAP, testing, devmode handlers) do not write to that log file. +**Done** (ILIAS 12). -**Goal** +Previously only the production default handler wrote exceptions to the dedicated +log file via `ilLoggingErrorFileStorage`. SOAP, testing, and devmode handlers did +not. -- Make the ability to report an exception to the dedicated log file available to - **all** Whoops handlers (default, SOAP, testing, devmode, etc.), not only the - default handler. -- Ensure a consistent reporting path: whenever an exception is handled and - logging is enabled, it can be written to the configured log file regardless - of which handler rendered the response. - -**Outcome** +Log file writing now happens in `RecordErrorIncidentHandler`, which runs for every +handled exception before the response handler is chosen. It calls +`ReportErrorIncident` and stores the incident in `ErrorIncidentRegistry`. The +production handler reads that value when it builds the message for the user, so +the code in the UI matches the log file name. -- Administrators and developers get a single, consistent log of reported exceptions - across all entry points and handler types. -- Easier auditing and debugging when errors occur in SOAP, tests, or other - contexts that today do not use the dedicated log file. +Details are documented in `README.md` and implemented under +`Init/src/ErrorHandling/`. diff --git a/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentIdTest.php b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentIdTest.php new file mode 100644 index 000000000000..0096d2990622 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentIdTest.php @@ -0,0 +1,40 @@ +value()); + } + + public function testRejectsEmptyValue(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Error incident identifier must not be empty.'); + + new ErrorIncidentId(''); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentTest.php b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentTest.php new file mode 100644 index 000000000000..78b56e5c1249 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentTest.php @@ -0,0 +1,35 @@ +identifier()); + self::assertSame('abc_1234', $incident->identifier()->value()); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentUserMessageTest.php b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentUserMessageTest.php new file mode 100644 index 000000000000..134c7df9a2be --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/ErrorIncidentUserMessageTest.php @@ -0,0 +1,59 @@ +createMock(ilLoggingErrorSettings::class); + $settings->method('mail')->willReturn('admin@example.org'); + + $message_formatter = new ErrorIncidentUserMessage($settings); + $message = $message_formatter->format(new ErrorIncident(new ErrorIncidentId('abc_12')), null); + + self::assertStringContainsString('abc_12', $message); + self::assertStringContainsString('admin@example.org', $message); + } + + public function testFormatsLocalizedMessageWithLanguage(): void + { + $settings = $this->createMock(ilLoggingErrorSettings::class); + $settings->method('mail')->willReturn(''); + + $language = $this->createMock(ilLanguage::class); + $language->expects($this->once())->method('loadLanguageModule')->with('logging'); + $language->method('txt')->willReturnCallback( + static fn(string $key): string => match ($key) { + 'log_error_message' => 'Logged error %s', + default => $key, + } + ); + + $message_formatter = new ErrorIncidentUserMessage($settings); + $message = $message_formatter->format(new ErrorIncident(new ErrorIncidentId('abc_12')), $language); + + self::assertSame('Logged error abc_12', $message); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/InMemoryErrorIncidentRegistryTest.php b/components/ILIAS/Init/tests/ErrorHandling/InMemoryErrorIncidentRegistryTest.php new file mode 100644 index 000000000000..48c9b9370169 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/InMemoryErrorIncidentRegistryTest.php @@ -0,0 +1,54 @@ +current()); + } + + public function testRecordsAndReturnsCurrentIncident(): void + { + $registry = new InMemoryErrorIncidentRegistry(); + $incident = new ErrorIncident(new ErrorIncidentId('abc_99')); + + $registry->record($incident); + + self::assertSame($incident, $registry->current()); + } + + public function testClearRemovesCurrentIncident(): void + { + $registry = new InMemoryErrorIncidentRegistry(); + $registry->record(new ErrorIncident(new ErrorIncidentId('abc_99'))); + + $registry->clear(); + + self::assertNull($registry->current()); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/LoggingErrorFileStorageAdapterTest.php b/components/ILIAS/Init/tests/ErrorHandling/LoggingErrorFileStorageAdapterTest.php new file mode 100644 index 000000000000..09332741b8c1 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/LoggingErrorFileStorageAdapterTest.php @@ -0,0 +1,62 @@ +skipIfVfsStreamNotAvailable(); + + vfsStream::setup(); + vfsStream::create([ + 'errors' => [], + ]); + + $log_directory = vfsStream::url('root/errors'); + $log_file = vfsStream::url('root/errors/abcde_42.log'); + $inspector = new Inspector(new RuntimeException('adapter test')); + + $adapter = new LoggingErrorFileStorageAdapter(); + $adapter->write( + $inspector, + $log_directory, + 'abcde_42', + ['password'] + ); + + self::assertFileExists($log_file); + self::assertStringContainsString('adapter test', (string) file_get_contents($log_file)); + } + + private function skipIfVfsStreamNotAvailable(): void + { + if (!class_exists(vfsStreamWrapper::class)) { + self::markTestSkipped( + 'vfsStream (https://github.com/bovigo/vfsStream) is required for virtual filesystem tests.' + ); + } + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/ProductionOnlyErrorIncidentReportingTest.php b/components/ILIAS/Init/tests/ErrorHandling/ProductionOnlyErrorIncidentReportingTest.php new file mode 100644 index 000000000000..afe48058eef2 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/ProductionOnlyErrorIncidentReportingTest.php @@ -0,0 +1,92 @@ +createMock(ErrorIncidentReporting::class); + $inner->expects($this->once()) + ->method('report') + ->with($inspector) + ->willReturn($incident); + + $reporting = new ProductionOnlyErrorIncidentReporting($inner, $this->devmodeState(false)); + + $result = $reporting->report($inspector); + + self::assertSame($incident, $result); + } + + public function testSkipsReportingWhenDevmodeIsActive(): void + { + $inner = $this->createMock(ErrorIncidentReporting::class); + $inner->expects($this->never())->method('report'); + + $reporting = new ProductionOnlyErrorIncidentReporting($inner, $this->devmodeState(true)); + + $result = $reporting->report(new Inspector(new RuntimeException('test'))); + + self::assertNull($result); + } + + public function testEvaluatesDevmodeLazilyOnEveryReport(): void + { + $inspector = new Inspector(new RuntimeException('test')); + $incident = new ErrorIncident(new ErrorIncidentId('abc_12')); + + $inner = $this->createStub(ErrorIncidentReporting::class); + $inner->method('report')->willReturn($incident); + + $devmode = $this->devmodeState(true); + $reporting = new ProductionOnlyErrorIncidentReporting($inner, $devmode); + + self::assertNull($reporting->report($inspector)); + + $devmode->is_active = false; + + self::assertSame($incident, $reporting->report($inspector)); + } + + private function devmodeState(bool $is_active): DevmodeState + { + return new class ($is_active) implements DevmodeState { + public function __construct(public bool $is_active) + { + } + + public function isActive(): bool + { + return $this->is_active; + } + }; + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/RecordErrorIncidentHandlerTest.php b/components/ILIAS/Init/tests/ErrorHandling/RecordErrorIncidentHandlerTest.php new file mode 100644 index 000000000000..0b3ca8aefbfe --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/RecordErrorIncidentHandlerTest.php @@ -0,0 +1,39 @@ +createMock(ErrorIncidentReporting::class); + $inspector = new Inspector(new RuntimeException('test')); + $reporting->expects($this->once())->method('report')->with($inspector)->willReturn(null); + + $handler = new RecordErrorIncidentHandler($reporting); + $handler->setInspector($inspector); + + self::assertNull($handler->handle()); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/ReportErrorIncidentTest.php b/components/ILIAS/Init/tests/ErrorHandling/ReportErrorIncidentTest.php new file mode 100644 index 000000000000..d9fe44baa31b --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/ReportErrorIncidentTest.php @@ -0,0 +1,116 @@ +createMock(ErrorLogFileStorage::class); + $storage->expects($this->never())->method('write'); + + $registry = new InMemoryErrorIncidentRegistry(); + $report = new ReportErrorIncident( + new readonly class () implements ErrorLogDirectory { + public function path(): string + { + return ''; + } + }, + $storage, + new SessionPrefixedErrorIncidentFactory(), + $registry, + ['password'] + ); + + $result = $report->report(new Inspector(new RuntimeException('test'))); + + self::assertNull($result); + self::assertNull($registry->current()); + } + + public function testWritesLogFileAndRecordsIncident(): void + { + $this->skipIfVfsStreamNotAvailable(); + + vfsStream::setup(); + vfsStream::create([ + 'errors' => [], + ]); + + $log_directory = vfsStream::url('root/errors'); + $log_file = vfsStream::url('root/errors/abcde_42.log'); + $inspector = new Inspector(new RuntimeException('test')); + $incident = new ErrorIncident(new ErrorIncidentId('abcde_42')); + + $incident_factory = $this->createMock(ErrorIncidentFactory::class); + $incident_factory->expects($this->once()) + ->method('create') + ->willReturn($incident); + + $registry = new InMemoryErrorIncidentRegistry(); + $report = new ReportErrorIncident( + new readonly class ($log_directory) implements ErrorLogDirectory { + public function __construct( + private string $path + ) { + } + + public function path(): string + { + return $this->path; + } + }, + new LoggingErrorFileStorageAdapter(), + $incident_factory, + $registry, + ['password'] + ); + + $result = $report->report($inspector); + + self::assertSame($incident, $result); + self::assertSame($incident, $registry->current()); + self::assertFileExists($log_file); + self::assertStringContainsString('test', (string) file_get_contents($log_file)); + } + + private function skipIfVfsStreamNotAvailable(): void + { + if (!class_exists(vfsStreamWrapper::class)) { + self::markTestSkipped( + 'vfsStream (https://github.com/bovigo/vfsStream) is required for virtual filesystem tests.' + ); + } + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/SessionPrefixedErrorIncidentFactoryTest.php b/components/ILIAS/Init/tests/ErrorHandling/SessionPrefixedErrorIncidentFactoryTest.php new file mode 100644 index 000000000000..dce430a0a33f --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/SessionPrefixedErrorIncidentFactoryTest.php @@ -0,0 +1,45 @@ +create('abcdef0123456789'); + + self::assertSame('abcde_9997', $incident->identifier()->value()); + } + + public function testCreatesIdentifierWhenSessionIdIsEmpty(): void + { + $engine = new \Random\Engine\Mt19937(99); + $factory = new SessionPrefixedErrorIncidentFactory(new \Random\Randomizer($engine)); + + $incident = $factory->create(''); + + self::assertSame('_3172', $incident->identifier()->value()); + } +} diff --git a/components/ILIAS/Init/tests/ErrorHandling/SoapExceptionHandlerTest.php b/components/ILIAS/Init/tests/ErrorHandling/SoapExceptionHandlerTest.php new file mode 100644 index 000000000000..69b344d819b9 --- /dev/null +++ b/components/ILIAS/Init/tests/ErrorHandling/SoapExceptionHandlerTest.php @@ -0,0 +1,88 @@ +record(new ErrorIncident(new ErrorIncidentId('abc_12'))); + + $handler = new SoapExceptionHandler($registry, $this->devmodeState(false)); + $handler->setInspector(new Inspector(new RuntimeException('internal soap failure'))); + + ob_start(); + $handler->handle(); + $output = (string) ob_get_clean(); + + self::assertStringContainsString('internal soap failure', $output); + self::assertStringContainsString('abc_12', $output); + } + + public function testFallsBackToExceptionMessageWithoutIncident(): void + { + $handler = new SoapExceptionHandler(new InMemoryErrorIncidentRegistry(), $this->devmodeState(false)); + $handler->setInspector(new Inspector(new RuntimeException('internal soap failure'))); + + ob_start(); + $handler->handle(); + $output = (string) ob_get_clean(); + + self::assertStringContainsString('internal soap failure', $output); + } + + public function testAppendsIncidentReferenceInDevmodeFaultString(): void + { + $registry = new InMemoryErrorIncidentRegistry(); + $registry->record(new ErrorIncident(new ErrorIncidentId('abc_12'))); + + $handler = new SoapExceptionHandler($registry, $this->devmodeState(true)); + $handler->setInspector(new Inspector(new RuntimeException('internal soap failure'))); + + ob_start(); + $handler->handle(); + $output = (string) ob_get_clean(); + + self::assertStringContainsString('internal soap failure', $output); + self::assertStringContainsString('abc_12', $output); + } + + private function devmodeState(bool $is_active): DevmodeState + { + return new class ($is_active) implements DevmodeState { + public function __construct(private bool $is_active) + { + } + + public function isActive(): bool + { + return $this->is_active; + } + }; + } +} diff --git a/components/ILIAS/ItemGroup/classes/Setup/class.Agent.php b/components/ILIAS/ItemGroup/classes/Setup/class.Agent.php index 40a3967dc68d..2c3737c26f70 100755 --- a/components/ILIAS/ItemGroup/classes/Setup/class.Agent.php +++ b/components/ILIAS/ItemGroup/classes/Setup/class.Agent.php @@ -29,4 +29,11 @@ public function getUpdateObjective(?Setup\Config $config = null): Setup\Objectiv { return new \ilDatabaseUpdateStepsExecutedObjective(new ilItemGroupDBUpdateSteps()); } + + public function getMigrations(): array + { + return [ + new ilItemGroupDisplayMigration() + ]; + } } diff --git a/components/ILIAS/ItemGroup/classes/Setup/class.ilItemGroupDisplayMigration.php b/components/ILIAS/ItemGroup/classes/Setup/class.ilItemGroupDisplayMigration.php new file mode 100644 index 000000000000..f22fabe7cf1d --- /dev/null +++ b/components/ILIAS/ItemGroup/classes/Setup/class.ilItemGroupDisplayMigration.php @@ -0,0 +1,123 @@ +db = $environment->getResource(Environment::RESOURCE_DATABASE); + } + + public function step(Environment $environment): void + { + $result = $this->db->queryF( + 'SELECT id, hide_title, behaviour FROM itgr_data WHERE hide_title <> %s AND behaviour <> %s LIMIT 1', + [ilDBConstants::T_INTEGER, ilDBConstants::T_INTEGER], + [self::MIGRATED_MARKER, self::MIGRATED_MARKER] + ); + + $row = $this->db->fetchAssoc($result); + if ($row === null) { + return; + } + + [$display, $toggleable_initially] = $this->mapLegacyValues((int) $row['hide_title'], (int) $row['behaviour']); + + $this->db->update( + 'itgr_data', + [ + 'display' => [ilDBConstants::T_TEXT, $display], + 'toggleable_initially' => [ilDBConstants::T_TEXT, $toggleable_initially], + 'hide_title' => [ilDBConstants::T_INTEGER, self::MIGRATED_MARKER], + 'behaviour' => [ilDBConstants::T_INTEGER, self::MIGRATED_MARKER], + ], + [ + 'id' => [ilDBConstants::T_INTEGER, (int) $row['id']], + ] + ); + } + + public function getRemainingAmountOfSteps(): int + { + $result = $this->db->queryF( + 'SELECT COUNT(id) AS cnt FROM itgr_data WHERE hide_title <> %s AND behaviour <> %s', + [ilDBConstants::T_INTEGER, ilDBConstants::T_INTEGER], + [self::MIGRATED_MARKER, self::MIGRATED_MARKER] + ); + + return (int) ($this->db->fetchObject($result)?->cnt ?? 0); + } + + /** + * @return array{0: string, 1: string} + */ + private function mapLegacyValues(int $hide_title, int $behaviour): array + { + return match (true) { + $hide_title === 1 => [ + ilItemGroupAR::DISPLAY_WITHOUT_TITLE, + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE_INITIALLY_OPEN, + ], + $behaviour === ilItemGroupBehaviour::EXPANDABLE_CLOSED => [ + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE, + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE_INITIALLY_CLOSED, + ], + $behaviour === ilItemGroupBehaviour::EXPANDABLE_OPEN => [ + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE, + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE_INITIALLY_OPEN, + ], + default => [ + ilItemGroupAR::DISPLAY_WITH_TITLE, + ilItemGroupAR::DISPLAY_WITH_TITLE_AND_TOGGLEABLE_INITIALLY_OPEN, + ] + }; + } +} diff --git a/components/ILIAS/ItemGroup/classes/class.ilItemGroupItems.php b/components/ILIAS/ItemGroup/classes/class.ilItemGroupItems.php index 2387257c60b1..704c693f7461 100755 --- a/components/ILIAS/ItemGroup/classes/class.ilItemGroupItems.php +++ b/components/ILIAS/ItemGroup/classes/class.ilItemGroupItems.php @@ -249,7 +249,7 @@ public static function getItemGroupsAssociatedWithItem(int $ref_id, int $filter_ 'SELECT ref_id, title FROM item_group_item ' . 'LEFT JOIN object_data ON item_group_item.item_group_id = object_data.obj_id ' . 'LEFT JOIN object_reference ON object_data.obj_id = object_reference.obj_id ' - . 'WHERE %s ' + . 'WHERE item_ref_id = %s ' . 'AND item_group_id != %s ' . 'AND object_data.type = \'itgr\'', [ilDBConstants::T_INTEGER, ilDBConstants::T_INTEGER], diff --git a/components/ILIAS/KioskMode_/classes/class.ilKioskModeService.php b/components/ILIAS/KioskMode/classes/class.ilKioskModeService.php similarity index 100% rename from components/ILIAS/KioskMode_/classes/class.ilKioskModeService.php rename to components/ILIAS/KioskMode/classes/class.ilKioskModeService.php diff --git a/components/ILIAS/KioskMode_/classes/class.ilKioskModeView.php b/components/ILIAS/KioskMode/classes/class.ilKioskModeView.php similarity index 100% rename from components/ILIAS/KioskMode_/classes/class.ilKioskModeView.php rename to components/ILIAS/KioskMode/classes/class.ilKioskModeView.php diff --git a/components/ILIAS/KioskMode_/tests/class.ilDummyKioskModeView.php b/components/ILIAS/KioskMode/tests/class.ilDummyKioskModeView.php similarity index 100% rename from components/ILIAS/KioskMode_/tests/class.ilDummyKioskModeView.php rename to components/ILIAS/KioskMode/tests/class.ilDummyKioskModeView.php diff --git a/components/ILIAS/KioskMode_/tests/ilKioskModeServiceTest.php b/components/ILIAS/KioskMode/tests/ilKioskModeServiceTest.php similarity index 100% rename from components/ILIAS/KioskMode_/tests/ilKioskModeServiceTest.php rename to components/ILIAS/KioskMode/tests/ilKioskModeServiceTest.php diff --git a/components/ILIAS/LDAP/classes/class.ilLDAPAttributeToUser.php b/components/ILIAS/LDAP/classes/class.ilLDAPAttributeToUser.php index 91439d4fb6bb..b1ec8e7a4072 100755 --- a/components/ILIAS/LDAP/classes/class.ilLDAPAttributeToUser.php +++ b/components/ILIAS/LDAP/classes/class.ilLDAPAttributeToUser.php @@ -28,7 +28,7 @@ */ class ilLDAPAttributeToUser { - public const MODE_INITIALIZE_ROLES = 1; + public const int MODE_INITIALIZE_ROLES = 1; private array $modes = []; private ilLDAPServer $server_settings; @@ -38,8 +38,9 @@ class ilLDAPAttributeToUser private string $new_user_auth_mode = 'ldap'; private ilLogger $logger; private ilXmlWriter $writer; + private readonly ilLanguage $lng; /** - * @var array|null + * @var array|null */ private ?array $user_defined_fields = null; @@ -53,6 +54,7 @@ public function __construct(ilLDAPServer $a_server) $this->logger = $DIC->logger()->auth(); $this->profile = $DIC['user']->getProfile(); + $this->lng = $DIC['lng']; $this->server_settings = $a_server; @@ -228,7 +230,7 @@ private function usersToXML(): void $rules = $this->mapping->getRules(true); } - $this->writer->xmlElement('Active', [], "true"); + $this->writer->xmlElement('Active', [], 'true'); $this->writer->xmlElement('TimeLimitOwner', [], 7); $this->writer->xmlElement('TimeLimitUnlimited', [], 1); $this->writer->xmlElement('TimeLimitFrom', [], time()); @@ -340,7 +342,7 @@ private function usersToXML(): void default: // Handle user defined fields - if (strpos($field, 'udf_') !== 0) { + if (!str_starts_with($field, 'udf_')) { continue 2; } $id_data = explode('_', $field); @@ -350,7 +352,7 @@ private function usersToXML(): void $this->initUserDefinedFields(); if (!isset($this->user_defined_fields[$id_data[1]])) { $this->logger->warning(sprintf( - "Invalid/Orphaned UD field mapping detected: %s", + 'Invalid/Orphaned UD field mapping detected: %s', $field )); break; @@ -360,7 +362,7 @@ private function usersToXML(): void 'UserDefinedField', [ 'Id' => $this->user_defined_fields[$id_data[1]]->getIdentifier(), - 'Name' => $this->user_defined_fields[$id_data[1]]->getLabel() + 'Name' => $this->user_defined_fields[$id_data[1]]->getLabel($this->lng) ], $value ); @@ -399,7 +401,7 @@ private function doMapping(array $user, array $rule): string { $mapping = strtolower(trim($rule['value'])); - if (strpos($mapping, ',') === false) { + if (!str_contains($mapping, ',')) { return $this->convertInput($user[$mapping] ?? ''); } // Is multiple mapping diff --git a/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php b/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php index 0df6facc2439..ccd3462fff4d 100755 --- a/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php +++ b/components/ILIAS/LDAP/classes/class.ilLDAPCronSynchronization.php @@ -165,10 +165,10 @@ private function deactivateUsers(ilLDAPServer $server, array $a_ldap_users): voi public function addToExternalSettingsForm(int $a_form_id, array &$a_fields, bool $a_is_active): void { if ($a_form_id === ilAdministrationSettingsFormHandler::FORM_LDAP) { - $a_fields["ldap_user_sync_cron"] = [$a_is_active ? - $this->lng->txt("enabled") : - $this->lng->txt("disabled"), - ilAdministrationSettingsFormHandler::VALUE_BOOL]; + $a_fields["ldap_user_sync_cron"] = [ + $a_is_active, + ilAdministrationSettingsFormHandler::VALUE_BOOL + ]; } } } diff --git a/components/ILIAS/LTIProvider/classes/InternalProvider/class.ilLTIProviderObjectSettingGUI.php b/components/ILIAS/LTIProvider/classes/InternalProvider/class.ilLTIProviderObjectSettingGUI.php index 206a516df1f3..1907d099d1e0 100644 --- a/components/ILIAS/LTIProvider/classes/InternalProvider/class.ilLTIProviderObjectSettingGUI.php +++ b/components/ILIAS/LTIProvider/classes/InternalProvider/class.ilLTIProviderObjectSettingGUI.php @@ -131,6 +131,11 @@ public function offerLTIRolesForSelection(bool $a_stat): void */ public function executeCommand(): void { + if (!$this->hasSettingsAccess()) { + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('permission_denied'), true); + $this->ctrl->redirectByClass(ilRepositoryGUI::class); + } + $cmd = $this->ctrl->getCmd('settings'); $next_class = $this->ctrl->getNextClass($this); diff --git a/components/ILIAS/LearningModule/Editing/SubObjectRetrieval.php b/components/ILIAS/LearningModule/Editing/SubObjectRetrieval.php index 0689727c6f11..9ef99b8aaee8 100644 --- a/components/ILIAS/LearningModule/Editing/SubObjectRetrieval.php +++ b/components/ILIAS/LearningModule/Editing/SubObjectRetrieval.php @@ -27,7 +27,6 @@ class SubObjectRetrieval implements RetrievalInterface { protected \ilLanguage $lng; - protected \ILIAS\UI\Factory $f; protected ?array $childs = null; public function __construct( @@ -37,7 +36,6 @@ public function __construct( protected $transl = "" ) { global $DIC; - $this->f = $DIC->ui()->factory(); $this->lng = $DIC->language(); } diff --git a/components/ILIAS/LearningModule/Presentation/class.ilLMTOCExplorerGUI.php b/components/ILIAS/LearningModule/Presentation/class.ilLMTOCExplorerGUI.php index be7d81494781..bb532a804db2 100755 --- a/components/ILIAS/LearningModule/Presentation/class.ilLMTOCExplorerGUI.php +++ b/components/ILIAS/LearningModule/Presentation/class.ilLMTOCExplorerGUI.php @@ -75,7 +75,7 @@ public function __construct( $this->export_all_languages = $export_all_languages; $this->activation_repo = new ilPageActivationDBRepository(); - + $this->setPreloadChilds(false); $this->initTreeData(); } diff --git a/components/ILIAS/LearningModule/classes/class.ilLMObject.php b/components/ILIAS/LearningModule/classes/class.ilLMObject.php index 0ee5f0abad44..7aa9c4088373 100755 --- a/components/ILIAS/LearningModule/classes/class.ilLMObject.php +++ b/components/ILIAS/LearningModule/classes/class.ilLMObject.php @@ -767,6 +767,11 @@ public static function pasteTree( if ($item_lm_id != $a_target_lm->getId() && !$a_as_copy) { // @todo: check whether st is NOT in tree + // update lm object + $item->setLMId($a_target_lm->getId()); + $item->setContentObject($a_target_lm); + $item->update(); + // "move" metadata to new lm $lom_services->derive() ->fromObject($item_lm_id, $item->getId(), $item->getType()) diff --git a/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php b/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php new file mode 100644 index 000000000000..569ba1be25d2 --- /dev/null +++ b/components/ILIAS/LearningSequence/Setup/class.InitLOMForLearningSequenceMigration.php @@ -0,0 +1,36 @@ +lng->txt($data['progress']); + if (array_key_exists('progress', $data)) { + $data['progress'] = $this->lng->txt($data['progress']); + } } return $data; diff --git a/components/ILIAS/LearningSequence/classes/Members/class.ilLearningSequenceParticipantsTableGUI.php b/components/ILIAS/LearningSequence/classes/Members/class.ilLearningSequenceParticipantsTableGUI.php index 7fba050c9b8e..6fc0d426848b 100755 --- a/components/ILIAS/LearningSequence/classes/Members/class.ilLearningSequenceParticipantsTableGUI.php +++ b/components/ILIAS/LearningSequence/classes/Members/class.ilLearningSequenceParticipantsTableGUI.php @@ -367,7 +367,9 @@ public function parse(): void // Custom user data fields if ($udf_ids !== []) { $user_data = array_reduce( - $this->profile->getDataForMultiple($filtered_user_ids), + iterator_to_array( + $this->profile->getDataForMultiple($filtered_user_ids) + ), function (array $c, ProfileData $v) use ($udf_ids): array { if (!$this->checkAcceptance($v->getId())) { return $c; diff --git a/components/ILIAS/LearningSequence/classes/Player/class.ilLSLaunchlinksBuilder.php b/components/ILIAS/LearningSequence/classes/Player/class.ilLSLaunchlinksBuilder.php index 80b65fd879f4..6f694940cf15 100755 --- a/components/ILIAS/LearningSequence/classes/Player/class.ilLSLaunchlinksBuilder.php +++ b/components/ILIAS/LearningSequence/classes/Player/class.ilLSLaunchlinksBuilder.php @@ -25,9 +25,6 @@ */ class ilLSLaunchlinksBuilder { - public const PERM_PARTICIPATE = 'participate'; - public const PERM_UNPARTICIPATE = 'unparticipate'; - public const CMD_STANDARD = ilObjLearningSequenceLearnerGUI::CMD_STANDARD; public const CMD_EXTRO = ilObjLearningSequenceLearnerGUI::CMD_EXTRO; public const CMD_START = ilObjLearningSequenceLearnerGUI::CMD_START; @@ -49,7 +46,7 @@ public function __construct( protected function mayJoin(): bool { - return $this->access->checkAccess(self::PERM_PARTICIPATE, '', $this->lso_ref_id); + return $this->access->checkAccess('read', '', $this->lso_ref_id); } public function currentUserMayUnparticipate(): bool @@ -59,7 +56,7 @@ public function currentUserMayUnparticipate(): bool protected function mayUnparticipate(): bool { - return $this->access->checkAccess(self::PERM_UNPARTICIPATE, '', $this->lso_ref_id); + return $this->isMember() && $this->access->checkAccess('read', '', $this->lso_ref_id); } protected function isMember(): bool diff --git a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php index f7f1dc021e0e..ed0d87390ec7 100755 --- a/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php +++ b/components/ILIAS/LearningSequence/classes/Settings/class.ilObjLearningSequenceSettingsGUI.php @@ -19,6 +19,8 @@ declare(strict_types=1); use ILIAS\HTTP\Wrapper\ArrayBasedRequestWrapper; +use ILIAS\ILIASObject\Properties\CoreProperties\TitleAndDescription; +use ILIAS\ILIASObject\Properties\ObjectReferenceProperties\AvailabilityPeriod\AvailabilityPeriod; class ilObjLearningSequenceSettingsGUI { @@ -99,7 +101,7 @@ protected function buildForm( protected function buildFormElements( ilObjLearningSequence $lso, ILIAS\UI\Component\Input\Factory $if - ) { + ): array { $txt = fn($id) => $this->lng->txt($id); $shift_trafo = $this->refinery->custom()->transformation( static fn(array $v) => current($v) @@ -125,13 +127,13 @@ protected function buildFormElements( $formElements['online'] = $if->field()->section( [ - $props->getPropertyIsOnline() + 'online' => $props->getPropertyIsOnline() ->toForm( $this->lng, $if->field(), $this->refinery ), - $ref_props->getPropertyAvailabilityPeriod() + 'availability_period' => $ref_props->getPropertyAvailabilityPeriod() ->toForm( $this->lng, $if->field(), @@ -154,9 +156,38 @@ protected function buildFormElements( $this->refinery->always(false) ]) ); + // Metadata + $custom_md = $if->field()->checkbox($this->lng->txt('obj_tool_setting_custom_metadata')) + ->withValue((bool) ilContainer::_lookupContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + '0' + )) + ->withAdditionalTransformation( + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->bool(), + $this->refinery->always(false) + ]) + ); + //Taxonomies + $taxonomies = $if->field()->checkbox($this->lng->txt('obj_tool_setting_taxonomies')) + ->withValue((bool) ilContainer::_lookupContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + '0' + )) + ->withAdditionalTransformation( + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->bool(), + $this->refinery->always(false) + ]) + ); + $section_additional = $if->field()->section( [ - self::PROP_GALLERY => $gallery + self::PROP_GALLERY => $gallery, + ilObjectServiceSettingsGUI::CUSTOM_METADATA => $custom_md, + ilObjectServiceSettingsGUI::TAXONOMIES => $taxonomies ], $txt('obj_features') ); @@ -211,14 +242,42 @@ protected function update(): ?string $lso = $this->obj; $obj_props = $lso->getObjectProperties(); + $ref_props = $lso->getObjectReferenceProperties(); + + $title_and_description = $data['object'] ?? null; + if ($title_and_description instanceof TitleAndDescription) { + $obj_props->storePropertyTitleAndDescription($title_and_description); + } + + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + ($data['additional'][ilObjectServiceSettingsGUI::CUSTOM_METADATA] ?? false) ? '1' : '0' + ); + ilContainer::_writeContainerSetting( + $lso->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + ($data['additional'][ilObjectServiceSettingsGUI::TAXONOMIES] ?? false) ? '1' : '0' + ); + + $obj_props->storePropertyIsOnline( + $data['online']['online'] ?? $obj_props->getPropertyIsOnline()->withOffline() + ); - $obj_props->storePropertyTitleAndDescription($data['object']); - list($online, $availability) = $data['online']; - $obj_props->storePropertyIsOnline($online); - $lso->storeAvailabilityPeriod($availability); + $availability_period = $data['online']['availability_period'] ?? null; + if ($availability_period instanceof AvailabilityPeriod) { + $lso->storeAvailabilityPeriod( + $availability_period->withObjectReferenceId($lso->getRefId()) + ); + } elseif ($ref_props !== null) { + // keep current value (no-op), but ensure it stays bound to current ref id + $lso->storeAvailabilityPeriod( + $ref_props->getPropertyAvailabilityPeriod()->withObjectReferenceId($lso->getRefId()) + ); + } $settings = $lso->getLSSettings() - ->withMembersGallery($data['additional'][self::PROP_GALLERY]); + ->withMembersGallery($data['additional'][self::PROP_GALLERY] ?? false); $lso->updateSettings($settings); $obj_props->storePropertyTitleAndIconVisibility($data['common']['icon']); diff --git a/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceSetupAgent.php b/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceSetupAgent.php index cdff906c33ce..dc84be7b3625 100755 --- a/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceSetupAgent.php +++ b/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceSetupAgent.php @@ -20,6 +20,7 @@ use ILIAS\Setup; use ILIAS\Refinery; +use ILIAS\LearningSequence\Setup\InitLOMForLearningSequenceMigration; class ilLearningSequenceSetupAgent implements Setup\Agent { @@ -69,6 +70,9 @@ public function getUpdateObjective(?Setup\Config $config = null): Setup\Objectiv new ilDatabaseUpdateStepsExecutedObjective( new LSODropActivationDBUpdateSteps() ), + new ilDatabaseUpdateStepsExecutedObjective( + new ilLearningSequenceStreamlinePermissionsDBUpdateSteps() + ), ); } @@ -89,7 +93,8 @@ public function getStatusObjective(Setup\Metrics\Storage $storage): Setup\Object 'Component LearningSequence', true, new ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new ilLearningSequenceRectifyPostConditionsTableDBUpdateSteps()), - new ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new ilLearningSequenceRegisterNotificationType()) + new ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new ilLearningSequenceRegisterNotificationType()), + new ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new ilLearningSequenceStreamlinePermissionsDBUpdateSteps()) ); } @@ -98,6 +103,8 @@ public function getStatusObjective(Setup\Metrics\Storage $storage): Setup\Object */ public function getMigrations(): array { - return []; + return [ + new InitLOMForLearningSequenceMigration(), + ]; } } diff --git a/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceStreamlinePermissionsDBUpdateSteps.php b/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceStreamlinePermissionsDBUpdateSteps.php new file mode 100644 index 000000000000..d35f72ef0034 --- /dev/null +++ b/components/ILIAS/LearningSequence/classes/Setup/class.ilLearningSequenceStreamlinePermissionsDBUpdateSteps.php @@ -0,0 +1,134 @@ +db = $db; + } + + public function step_1(): void + { + $read_ops_id = $this->getOperationId('read'); + $participate_ops_id = $this->getOperationId('participate'); + $unparticipate_ops_id = $this->getOperationId('unparticipate'); + + if ($read_ops_id === null) { + throw new \RuntimeException('Cannot migrate learning sequence permissions: RBAC operation "read" not found.'); + } + + $old_ops_ids = array_values( + array_filter([ + $participate_ops_id, + $unparticipate_ops_id + ]) + ); + if ($old_ops_ids === []) { + return; + } + + $res = $this->db->query( + "SELECT pa.rol_id, pa.ref_id, pa.ops_id " . + "FROM rbac_pa pa " . + "JOIN object_reference ref ON ref.ref_id = pa.ref_id " . + "JOIN object_data obj ON obj.obj_id = ref.obj_id " . + "WHERE obj.type = '" . self::TYPE_TITLE . "'" + ); + + while ($row = $this->db->fetchAssoc($res)) { + $serialized = $row['ops_id'] ?? null; + if (!is_string($serialized) || $serialized === '') { + continue; + } + + $ops = @unserialize($serialized, ['allowed_classes' => false]); + if (!is_array($ops)) { + continue; + } + + $ops = array_map('intval', $ops); + $has_old = false; + foreach ($old_ops_ids as $old_ops_id) { + if (in_array((int) $old_ops_id, $ops, true)) { + $has_old = true; + break; + } + } + if (!$has_old) { + continue; + } + + $ops[] = $read_ops_id; + $ops = array_values(array_unique(array_diff($ops, array_map('intval', $old_ops_ids)))); + sort($ops); + + $this->db->manipulateF( + 'UPDATE rbac_pa SET ops_id = %s WHERE rol_id = %s AND ref_id = %s', + [\ilDBConstants::T_TEXT, \ilDBConstants::T_INTEGER, \ilDBConstants::T_INTEGER], + [serialize($ops), (int) $row['rol_id'], (int) $row['ref_id']] + ); + } + } + + public function step_2(): void + { + $participate_ops_id = $this->getOperationId('participate'); + $unparticipate_ops_id = $this->getOperationId('unparticipate'); + + if ($participate_ops_id === null && $unparticipate_ops_id === null) { + return; + } + + $ops_ids = array_values(array_filter([(int) $participate_ops_id, (int) $unparticipate_ops_id])); + if ($ops_ids === []) { + return; + } + + $in = implode(',', array_map('intval', $ops_ids)); + $sql = + "DELETE FROM rbac_ta " . + "WHERE typ_id IN (" . + "SELECT obj_id FROM object_data " . + "WHERE type = 'typ' AND title = '" . self::TYPE_TITLE . "'" . + ") " . + "AND ops_id IN (" . $in . ")"; + + $this->db->manipulate($sql); + } + + private function getOperationId(string $operation): ?int + { + $res = $this->db->queryF( + 'SELECT ops_id FROM rbac_operations WHERE operation = %s', + [\ilDBConstants::T_TEXT], + [$operation] + ); + $row = $this->db->fetchAssoc($res); + if (!is_array($row) || !isset($row['ops_id'])) { + return null; + } + return (int) $row['ops_id']; + } +} diff --git a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php index c9122c7e633d..6383a7b78352 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php +++ b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceExporter.php @@ -91,12 +91,55 @@ public function getXmlExportTailDependencies(string $a_entity, string $a_target_ { $res = []; if ($a_entity == "lso") { + // advanced metadata + $advmd_ids = []; + foreach ($a_ids as $id) { + $rec_ids = $this->getActiveAdvMDRecords((int) $id); + foreach ($rec_ids as $rec_id) { + $advmd_ids[] = $id . ":" . $rec_id; + } + } + if ($advmd_ids !== []) { + $res[] = [ + "component" => "components/ILIAS/AdvancedMetaData", + "entity" => "advmd", + "ids" => $advmd_ids + ]; + } + // service settings $res[] = [ "component" => "components/ILIAS/ILIASObject", "entity" => "common", "ids" => $a_ids ]; + + // metadata + $md_ids = []; + foreach ($a_ids as $id) { + $md_ids[] = $id . ":0:lso"; + } + $res[] = [ + "component" => "components/ILIAS/MetaData", + "entity" => "md", + "ids" => $md_ids + ]; + + // taxonomies + $tax_ids = []; + foreach ($a_ids as $id) { + $t_ids = ilObjTaxonomy::getUsageOfObject((int) $id); + foreach ($t_ids as $t_id) { + $tax_ids[$t_id] = $t_id; + } + } + if ($tax_ids !== []) { + $res[] = [ + "component" => "components/ILIAS/Taxonomy", + "entity" => "tax", + "ids" => $tax_ids + ]; + } } // container pages @@ -120,4 +163,28 @@ public function getXmlExportTailDependencies(string $a_entity, string $a_target_ return $res; } + + protected function getActiveAdvMDRecords(int $a_id): array + { + $active = []; + + foreach (ilAdvancedMDRecord::_getActivatedRecordsByObjectType('lso') as $record_obj) { + foreach ($record_obj->getAssignedObjectTypes() as $obj_info) { + if ($obj_info['obj_type'] === 'lso' && (int) $obj_info['optional'] === 0) { + $active[] = $record_obj->getRecordId(); + } + + // local activation + if ( + $obj_info['obj_type'] === 'lso' && + (int) $obj_info['optional'] === 1 && + $a_id === $record_obj->getParentObject() + ) { + $active[] = $record_obj->getRecordId(); + } + } + } + + return $active; + } } diff --git a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php index fdadca6e450c..28f7a11d4364 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php +++ b/components/ILIAS/LearningSequence/classes/class.ilLearningSequenceImporter.php @@ -59,6 +59,26 @@ public function importXmlRepresentation(string $a_entity, string $a_id, string $ LSOPageType::EXTRO->value . ':' . $a_id, LSOPageType::EXTRO->value . ':' . (string) $this->obj->getId() ); + + $a_mapping->addMapping( + 'components/ILIAS/MetaData', + 'md', + $a_id . ':0:lso', + (string) $this->obj->getId() . ':0:lso' + ); + + $a_mapping->addMapping( + "components/ILIAS/Taxonomy", + "tax_item", + "lso:obj:" . $a_id, + (string) $this->obj->getId() + ); + $a_mapping->addMapping( + "components/ILIAS/Taxonomy", + "tax_item_obj_id", + "lso:obj:" . $a_id, + (string) $this->obj->getId() + ); } public function finalProcessing(ilImportMapping $a_mapping): void @@ -77,6 +97,20 @@ public function finalProcessing(ilImportMapping $a_mapping): void $new_obj_id = $this->obj->getId(); ilPageObject::_writeParentId($pg_type, (int) $new_pg_id, (int) $new_obj_id); } + + // taxonomy usages + $maps = $a_mapping->getMappingsOfEntity("components/ILIAS/LearningSequence", "lso"); + foreach ($maps as $old => $new) { + if ($old !== "new_id" && (int) $old > 0) { + $new_tax_ids = $a_mapping->getMapping("components/ILIAS/Taxonomy", "tax_usage_of_obj", (string) $old); + if ($new_tax_ids !== "") { + $tax_ids = explode(":", (string) $new_tax_ids); + foreach ($tax_ids as $tid) { + ilObjTaxonomy::saveUsage((int) $tid, (int) $new); + } + } + } + } } public function afterContainerImportProcessing(ilImportMapping $mapping): void diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php index 9f22bfc7dc38..4064699026e9 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequence.php @@ -97,7 +97,8 @@ public function create(): int if (!$id) { return 0; } - $this->ref_props = $this->repo_ref_props->getFor(null); + + $this->createMetaData(); $this->raiseEvent(self::E_CREATE); return $this->getId(); @@ -108,6 +109,8 @@ public function update(): bool if (!parent::update()) { return false; } + + $this->updateMetaData(); $this->raiseEvent(self::E_UPDATE); return true; @@ -115,6 +118,8 @@ public function update(): bool public function delete(): bool { + $this->deleteMetaData(); + if (!parent::delete()) { return false; } @@ -123,6 +128,8 @@ public function delete(): bool $this->getSettingsDB()->delete($this->getId()); $this->getStateDB()->deleteFor($this->getRefId()); + ilObjTaxonomy::deleteUsagesOfObject($this->getId()); + $this->raiseEvent(self::E_DELETE); return true; diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceAccess.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceAccess.php index a7597c60a976..3250db2a68fa 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceAccess.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceAccess.php @@ -48,11 +48,6 @@ public static function _getCommands(): array 'cmd' => ilObjLearningSequenceGUI::CMD_SETTINGS, 'permission' => 'write', 'lang_var' => 'settings' - ], - [ - 'cmd' => ilObjLearningSequenceGUI::CMD_UNPARTICIPATE, - 'permission' => 'unparticipate', - 'lang_var' => 'unparticipate' ] ); } diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php index 28902c7fbe32..b86b658e4847 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceGUI.php @@ -51,9 +51,11 @@ * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjSurveyGUI * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjFileUploadHandlerGUI * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjLearningSequenceEditIntroGUI, ilObjLearningSequenceEditExtroGUI + * @ilCtrl_Calls ilObjLearningSequenceGUI: ilObjectMetaDataGUI, ilTaxonomySettingsGUI, ilObjTaxonomyGUI */ -class ilObjLearningSequenceGUI extends ilContainerGUI implements ilCtrlBaseClassInterface +class ilObjLearningSequenceGUI extends ilContainerGUI implements ilCtrlBaseClassInterface, \ILIAS\Taxonomy\Settings\ModifierGUIInterface { + protected \ILIAS\Taxonomy\Service $taxonomy; public const CMD_VIEW = "view"; public const CMD_LEARNER_VIEW = "learnerView"; public const CMD_CONTENT = "manageContent"; @@ -228,6 +230,7 @@ public function __construct() $this->post_wrapper = $DIC->http()->wrapper()->post(); $this->refinery = $DIC->refinery(); $this->content_style = $DIC->contentStyle(); + $this->taxonomy = $DIC->taxonomy(); $this->help->setScreenIdComponent($this->type); $this->lng->loadLanguageModule($this->type); @@ -292,6 +295,7 @@ public function executeCommand(): void } $this->tabs->activateTab(self::TAB_SETTINGS); + $this->setEditTabs(); $this->ctrl->forwardCommand($this->getGUISettings()); break; case "ilobjlearningsequencecontentgui": @@ -350,6 +354,23 @@ public function executeCommand(): void $gui = $this->object->getLocalDI()["gui.learner.lp"]; $this->ctrl->forwardCommand($gui); break; + case "ilobjectmetadatagui": + $this->tabs->activateTab("meta_data"); + $mdgui = new ilObjectMetaDataGUI($this->object); + $this->ctrl->forwardCommand($mdgui); + break; + case "iltaxonomysettingsgui": + case "ilobjtaxonomygui": + $this->tabs->activateTab(self::TAB_SETTINGS); + $this->setEditTabs("taxonomy"); + $tax_gui = $this->taxonomy->gui()->getSettingsGUI( + $this->object->getId(), + $this->lng->txt("cntr_tax_settings_info"), + true, + $this + ); + $this->ctrl->forwardCommand($tax_gui); + break; case "ilobjlearningsequenceeditintrogui": $which_page = LSOPageType::INTRO; $which_tab = self::TAB_EDIT_INTRO; @@ -519,7 +540,9 @@ public function addToNavigationHistory(): void protected function getGUIInfo(): ilInfoScreenGUI { - return new ilInfoScreenGUI($this); + $info = new ilInfoScreenGUI($this); + $info->addMetaDataSections($this->object->getId(), 0, 'lso'); + return $info; } protected function getGUIPermissions(): ilPermissionGUI @@ -659,13 +682,29 @@ protected function afterSave(ilObject $new_object): void public function unparticipate(): void { - if ($this->checkAccess('unparticipate')) { + if ($this->checkAccess('read')) { $usr_id = $this->user->getId(); - $this->getObject()->getLSRoles()->leave($usr_id); + if ($this->getObject()->getLSRoles()->isMember($usr_id)) { + $this->getObject()->getLSRoles()->leave($usr_id); + } } $this->ctrl->redirectByClass('ilObjLearningSequenceLearnerGUI', self::CMD_LEARNER_VIEW); } + protected function getSubServices(): array + { + $subs = [ + ilObjectServiceSettingsGUI::CUSTOM_METADATA, + ilObjectServiceSettingsGUI::TAXONOMIES, + ilObjectServiceSettingsGUI::CALENDAR_CONFIGURATION, + ilObjectServiceSettingsGUI::TAG_CLOUD, + ilObjectServiceSettingsGUI::BADGES, + ilObjectServiceSettingsGUI::SKILLS + ]; + + return $subs; + } + /** * Initializes the header action for the object list GUI with optional subtype and sub-ID. * Disables multi-download functionality for the object list GUI if initialized. @@ -684,6 +723,26 @@ protected function initHeaderAction(?string $sub_type = null, ?int $sub_id = nul } + protected function setEditTabs(string $active_tab = "settings_misc"): void + { + $this->tabs->addSubTab( + "settings_misc", + $this->lng->txt("general"), + $this->ctrl->getLinkTargetByClass("ilobjlearningsequencesettingsgui", "settings") + ); + + if (ilContainer::_lookupContainerSetting( + $this->object->getId(), + ilObjectServiceSettingsGUI::TAXONOMIES, + '0' + )) { + $this->taxonomy->gui()->addSettingsSubTab($this->object->getId()); + } + + $this->tabs->activateTab(self::TAB_SETTINGS); + $this->tabs->activateSubTab($active_tab); + } + protected function getTabs(): void { if ($this->checkAccess("read")) { @@ -709,6 +768,17 @@ protected function getTabs(): void $this->lng->txt(self::TAB_SETTINGS), $this->getLinkTarget(self::CMD_SETTINGS) ); + + // metadata + $mdgui = new ilObjectMetaDataGUI($this->object); + $mdtab = $mdgui->getTab(); + if ($mdtab) { + $this->tabs->addTab( + "meta_data", + $this->lng->txt("meta_data"), + $mdtab + ); + } } if ($this->checkAccess("read")) { @@ -791,6 +861,16 @@ protected function addSubTabsForContent(string $active): void $this->tabs->activateSubTab($active); } + public function getProperties(int $tax_id): array + { + return []; + } + + public function getActions(int $tax_id): array + { + return []; + } + protected function checkAccess(string $which): bool { return $this->access->checkAccess($which, "", $this->ref_id); @@ -891,12 +971,19 @@ public function addCustomData(array $a_data): array { $udfs = $this->profile->getAllUserDefinedFields(); return array_reduce( - $this->profile->getDataForMultiple(array_keys($a_data)), + iterator_to_array( + $this->profile->getDataForMultiple( + array_keys($a_data) + ) + ), function (array $c, ProfileData $v) use ($a_data, $udfs): array { $c[$v->getId()] = $a_data[$v->getId()]; foreach ($udfs as $field) { $field_id = $field->getIdentifier(); - $c[$v->getId()]['udf_' . $field_id] = (string) $v->getAdditionalFieldByIdentifier($field_id); + $c[$v->getId()]['udf_' . $field_id] = implode( + ', ', + $v->getAdditionalFieldByIdentifier($field_id) ?? [] + ); } return $c; }, diff --git a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php index 345ff97a2806..c47ed4bbfd8c 100755 --- a/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php +++ b/components/ILIAS/LearningSequence/classes/class.ilObjLearningSequenceListGUI.php @@ -18,8 +18,6 @@ declare(strict_types=1); -declare(strict_types=1); - class ilObjLearningSequenceListGUI extends ilObjectListGUI { public function __construct() diff --git a/components/ILIAS/LearningSequence/module.xml b/components/ILIAS/LearningSequence/module.xml index 51840c7d7923..7af63f1e5882 100755 --- a/components/ILIAS/LearningSequence/module.xml +++ b/components/ILIAS/LearningSequence/module.xml @@ -25,6 +25,7 @@ repository="1" group="lso" offline_handling="1" + amet="1" > rolf htlm diff --git a/components/ILIAS/LearningSequence/tests/IliasMocks.php b/components/ILIAS/LearningSequence/tests/IliasMocks.php index 3e4ae624ccce..51d7f0f619d4 100755 --- a/components/ILIAS/LearningSequence/tests/IliasMocks.php +++ b/components/ILIAS/LearningSequence/tests/IliasMocks.php @@ -55,10 +55,12 @@ protected function mockUIFactory(): UIFactory }); $ui_factory->method('link') ->willReturn(new CImpl\Link\Factory()); + $language_mock = $this->createMock(\ILIAS\Language\Language::class); + $language_mock->method('txt')->willReturnArgument(0); $ui_factory->method('symbol') ->willReturn(new CImpl\Symbol\Factory( new CImpl\Symbol\Icon\Factory(), - new CImpl\Symbol\Glyph\Factory(), + new CImpl\Symbol\Glyph\Factory($language_mock), new CImpl\Symbol\Avatar\Factory() )); diff --git a/components/ILIAS/Locator/PRIVACY.md b/components/ILIAS/Locator/PRIVACY.md new file mode 100644 index 000000000000..ec7aa2775299 --- /dev/null +++ b/components/ILIAS/Locator/PRIVACY.md @@ -0,0 +1,37 @@ +# Locator Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information by submitting a [Pull Request](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/docs/development/contributing.md#pull-request-to-the-repositories) or, if you prefer, via the [ILIAS bug tracker](https://mantis.ilias.de). When using the bug tracker, please select the corresponding component in the **Category** field.** + + +## General Information + +The Locator component provides the breadcrumb navigation bar displayed at the top of ILIAS pages. It renders the hierarchical path from the repository root to the current object (e.g., Repository > Category > Course > Folder), allowing users to navigate back to parent containers. The Locator does not store, modify, or delete any data itself. It reads object titles and hierarchy information from the repository tree at render time and discards this information after the page is generated. + +The breadcrumb path may be shortened within courses depending on the global setting "rep_breadcr_crs" and per-course container settings. This affects only which repository nodes are displayed in the breadcrumb, not any personal data. + +## Integrated Components + +- The Locator component employs the following components, please consult the respective PRIVACY.md files: + - [AccessControl](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/AccessControl/PRIVACY.md) — the Locator checks the "visible" permission on each repository node before including it in the breadcrumb path. + - [Container](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Container/PRIVACY.md) — the Locator reads per-course container settings to determine whether the breadcrumb path should be shortened to the course level. + - ILIASObject — the Locator uses `ilObject` to look up object IDs, types, and icons for breadcrumb items. + - Tree — the Locator uses `ilTree` to retrieve the hierarchical path from the repository root to the current node. + - [Course](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Course/PRIVACY.md) — the Locator references `ilObjCourseGUI` constants to interpret course-level breadcrumb settings. + +## Data being stored + +The Locator component does not store any personal data. It operates as a read-only navigational component that assembles breadcrumb entries from the repository tree at render time. No database writes, user preferences, or persistent state are created by this component. + +## Data being presented + +The Locator component does not present any personal data. It displays only **object titles** (e.g., course names, category names, folder names) and **object type icons** as breadcrumb links. No user names, user IDs, or other personal information are rendered by this component. + +Each breadcrumb item is only shown if the current user has the "visible" permission on the corresponding repository node. Items for which the user lacks this permission are silently omitted from the breadcrumb path. + +## Data being deleted + +The Locator component does not store any data and therefore has no data to delete. Since the breadcrumb is generated dynamically on each page load, no deletion scenarios apply. + +## Data being exported + +The Locator component does not provide any export functionality. No personal data is exported by this component. diff --git a/components/ILIAS/Logging/Logging.php b/components/ILIAS/Logging/Logging.php index ea5202974232..4fbc0bad6559 100644 --- a/components/ILIAS/Logging/Logging.php +++ b/components/ILIAS/Logging/Logging.php @@ -32,9 +32,52 @@ public function init( array | \ArrayAccess &$pull, array | \ArrayAccess &$internal, ): void { - $contribute[\ILIAS\Setup\Agent::class] = static fn() => - new \ilLoggingSetupAgent( - $pull[\ILIAS\Refinery\Factory::class] + /*$define[] = Logging\Logger\LoggerFactoryInterface::class; + $define[] = Logging\Logger\DefaultConfigLoggerFactoryInterface::class; + $define[] = Logging\Config\ConfigInterface::class; + + $internal[Logging\Config\Basic\ConfigInterface::class] = static fn() => + new Logging\Config\Basic\Config( + new Logging\Config\Basic\IniReader( + $use[\ilIniFile::class] // TODO change to whatever this is now called + ) + ); + $internal[Logging\Config\ByComponent\ConfigInterface::class] = static fn() => + new Logging\Config\ByComponent\Config( + new Logging\Config\ByComponent\DBRepository( + $use[\ilDBInterface::class] // TODO change to whatever this is now called + ), + $internal[Logging\Config\Basic\ConfigInterface::class] + ); + $internal[Logging\Logger\LevelFetcher\LevelFetcherFactory::class] = static fn() => + new Logging\Logger\LevelFetcher\LevelFetcherFactory(); + $internal[Logging\Logger\LazyInternalFactoryInterface::class] = static fn() => + new Logging\Logger\LazyInternalFactory( + new Logging\Logger\Monolog\Factory(), + $internal[Logging\Config\Basic\ConfigInterface::class] + ); + + $implement[Logging\Logger\LoggerFactoryInterface::class] = static fn() => + new Logging\Logger\LoggerFactory( + $internal[Logging\Logger\LazyInternalFactoryInterface::class], + $internal[Logging\Config\ByComponent\ConfigInterface::class], + $internal[Logging\Logger\LevelFetcher\LevelFetcherFactory::class] + ); + $implement[Logging\Logger\DefaultConfigLoggerFactoryInterface::class] = static fn() => + new Logging\Logger\DefaultConfigLoggerFactory( + $internal[Logging\Logger\LazyInternalFactoryInterface::class], + $internal[Logging\Config\Basic\ConfigInterface::class], + $internal[Logging\Logger\LevelFetcher\LevelFetcherFactory::class] + ); + $implement[Logging\Config\ConfigInterface::class] = static fn() => + new Logging\Config\Config( + $internal[Logging\Config\Basic\ConfigInterface::class], + $internal[Logging\Config\ByComponent\ConfigInterface::class] + );*/ + + $contribute[Setup\Agent::class] = static fn() => + new Logging\Setup\Agent( + $pull[Refinery\Factory::class] ); } } diff --git a/components/ILIAS/Logging/README.md b/components/ILIAS/Logging/README.md index 93f84584dc19..fa30a4723558 100755 --- a/components/ILIAS/Logging/README.md +++ b/components/ILIAS/Logging/README.md @@ -1,60 +1,58 @@ -# Logging Service +# Logging -Starting with release 5.1 a new logging service based on [Monolog](https://github.com/Seldaek/monolog) is available. +The Logging components providers loggers to other components in ILIAS. Those Loggers use [Monolog](https://github.com/Seldaek/monolog), +and are [PSR-3](https://www.php-fig.org/psr/psr-3/) compliant. -The service provides support for different log levels per component. +## Configuration -## Activate Logging for Components +The basic configuration of Logging is done in the `ilias.ini.php` (or alternatively using the Setup). All relevant fields +are in the section `log`. `path` and `file` determine the location of the log directory and the name of the log file, +and `default_level` defines the default log level. -To use different log levels for your component, you have to enable "logging" in your module.xml or service.xml. +Every component and plugin of an ILIAS installation also has its own log level, configurable in the Logging administration. +If no log level is set explicitly for a component, the default log level is used. -```php - - -... - - - -``` - -Call `composer du` to trigger the reading of the XML files. - -Different log levels for components can be defined in "ILIAS -> Administration -> Logging -> Components". -If no component specific log level is given, the the global log level is used. +Your `ilias.ini.php` may also contain an additional field `level` under `log`. That field doesn't do anything, and +can be removed. ## Definition of Log Levels -ILIAS (monolog) support the following log levels defines in [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424): +ILIAS (via Monolog) supports the following log levels defined in [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424): -- DEBUG: Detailed debug information -- INFO: Interesting event. E.g user logs in -- NOTICE: Normal but significant events -- WARNING: Exceptional occurences that are no errors. E.g calls of deprecated methods -- ERROR: Runtime errors that do not require immediate action -- CRITICAL: Critical conditions - e.g. a module service is unasable due to missing librarys. -- ALERT: Immediate action is required. E.g. no database connection +- DEBUG: Detailed debug information. +- INFO: Interesting event, e.g. a user logs in. +- NOTICE: Normal but significant events. +- WARNING: Exceptional occurences that are no errors, e.g. calls of deprecated methods. +- ERROR: Runtime errors that do not require immediate action. +- CRITICAL: Critical conditions, e.g. a service is unusable due to missing libraries. +- ALERT: Immediate action is required, e.g. no database connection. - EMERGENCY: The system is unusable. ## Using the Logging Service -An instance of the logging service is available via `$DIC->logger()`. You should reveice the logger for your component by calling a method with your component id on this object. +work in progress -```php +Loggers are available via their ID through the [`LoggerFactory`](src/Logger/LoggerFactoryInterface.php). To get the +logger for your component or plugin, with its own log level, use its respective ID. The factory also gives out loggers +for any other ID, the default log level is then used. -// Get component logger -$grp_logger = $DIC->logger->grp(); - -// write a message with info log level -$grp_logger->info('info message'); +```php +$logger = $factory->getLazy('crs'); +$logger->info('Lorem ipsum'); ``` -## Using Placeholders +Logging also offers a [`DefaultConfigLoggerFactory`](src/Logger/DefaultConfigLoggerFactoryInterface.php), which does not +depend on the Database component. You should only use it if you need to log anything before the database is initialized. +As a tradeoff, its loggers will always use the default log level, no matter the ID. -The ilLogger exposes the placeholder feature given by the monolog bundle, which implements a PSR-3 compliant logger interface. +Note that both factories share the same cache, so it's not possible to get two different loggers with the same ID. If +your component needs to use both a database-unaware logger and a logger with the correct log level, use a different ID +for the former (e.g. `crs_default`). -Placeholders should be used to allow escaping of user input just as `$database->quote(...)` is used to escape user input in SQL queries. +### Using Placeholders -### Example usage +The Logger exposes the placeholder feature of Monolog. Placeholders should be used to allow escaping of user input just +as `$database->quote(...)` is used to escape user input in SQL queries. ```php $logger->debug('Lorem ipsum {foo} dolor {bar}.', [ diff --git a/components/ILIAS/Logging/ROADMAP.md b/components/ILIAS/Logging/ROADMAP.md index 416c2baa6312..c259d6039e94 100755 --- a/components/ILIAS/Logging/ROADMAP.md +++ b/components/ILIAS/Logging/ROADMAP.md @@ -2,11 +2,20 @@ ## Short Term -... +### Move UI to KS, activities + +The Logging administration should be moved to KS, and the GUI classes +refactored. This can be done with the help of activities. ## Mid Term -... +### Allow Components register and configure loggers + +Instead of giving every component and plugin a logger by default, there +should be a mechanism for components to configure their loggers (e.g. +should the log level be changeable in the GUI, for loggers that can't +depend on the database). They should also be able to register additional +loggers. ## Long Term diff --git a/components/ILIAS/Logging/classes/NullLogger.php b/components/ILIAS/Logging/classes/NullLogger.php index 532f8715bf18..3fb5f2012d50 100755 --- a/components/ILIAS/Logging/classes/NullLogger.php +++ b/components/ILIAS/Logging/classes/NullLogger.php @@ -22,9 +22,12 @@ use ilLogger; use ilLogLevel; -use Monolog\Logger; +use ILIAS\Logging\Logger\LoggerInterface; use Exception; +/** + * @deprecated If a null version of the new logger would be handy, let the Logging authorities know. + */ class NullLogger extends ilLogger { public function __construct() @@ -77,7 +80,7 @@ public function emergency(string $message, array $context = []): void } /** @noinspection \PhpInconsistentReturnPointsInspection */ - public function getLogger(): Logger + protected function getLogger(): LoggerInterface { throw new Exception('Can not return monolog logger from a null logger.'); } diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingDefinitionProcessor.php b/components/ILIAS/Logging/classes/Setup/class.ilLoggingDefinitionProcessor.php deleted file mode 100755 index f2c46a9f3f9c..000000000000 --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingDefinitionProcessor.php +++ /dev/null @@ -1,70 +0,0 @@ -db = $db; - } - - public function purge(): void - { - } - - public function beginComponent(string $component, string $type): void - { - $this->component_id = ''; - } - - public function endComponent(string $component, string $type): void - { - $this->component_id = ''; - } - - public function beginTag(string $name, array $attributes): void - { - if ($name === "module" || $name === "service") { - $this->component_id = $attributes["id"] ?? ''; - return; - } - - if ($name !== "logging") { - return; - } - - if ($this->component_id === '') { - throw new \RuntimeException( - "Found $name-tag outside of module or service in {$this->component_id}." - ); - } - ilLogComponentLevels::updateFromXML($this->component_id); - } - - public function endTag(string $name): void - { - if ($name === "module" || $name === "service") { - $this->component_id = ''; - } - } -} diff --git a/components/ILIAS/Logging/classes/class.ilComponentLogger.php b/components/ILIAS/Logging/classes/class.ilComponentLogger.php index 75af11e69bbf..5a250bf95b67 100755 --- a/components/ILIAS/Logging/classes/class.ilComponentLogger.php +++ b/components/ILIAS/Logging/classes/class.ilComponentLogger.php @@ -19,6 +19,10 @@ declare(strict_types=1); /** * Component logger with individual log levels by component id + * + * @deprecated Please use {@see \ILIAS\Logging\Logger\LoggerInterface} via + * {@see \ILIAS\Logging\Logger\LoggerFactoryInterface} instead. + * * @author Stefan Meyer */ class ilComponentLogger extends ilLogger diff --git a/components/ILIAS/Logging/classes/class.ilLogComponentLevel.php b/components/ILIAS/Logging/classes/class.ilLogComponentLevel.php deleted file mode 100755 index 3943cdbc6de7..000000000000 --- a/components/ILIAS/Logging/classes/class.ilLogComponentLevel.php +++ /dev/null @@ -1,81 +0,0 @@ - - * @version $Id$ - * - */ -class ilLogComponentLevel -{ - private string $compontent_id = ''; - private ?int $component_level = null; - - protected ilDBInterface $db; - - public function __construct(string $a_component_id, ?int $a_level = null) - { - global $DIC; - - $this->db = $DIC->database(); - $this->compontent_id = $a_component_id; - if ($a_level === null) { - $this->read(); - } else { - $this->setLevel($a_level); - } - } - - public function getComponentId(): string - { - return $this->compontent_id; - } - - public function setLevel(?int $a_level): void - { - $this->component_level = $a_level; - } - - public function getLevel(): ?int - { - return $this->component_level; - } - - public function update(): void - { - $this->db->replace( - 'log_components', - array('component_id' => array('text',$this->getComponentId())), - array('log_level' => array('integer',$this->getLevel())) - ); - } - - public function read(): void - { - $query = 'SELECT * FROM log_components ' . - 'WHERE component_id = ' . $this->db->quote($this->getComponentId(), 'text'); - - $res = $this->db->query($query); - while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) { - $this->component_level = (int) $row->log_level; - } - } -} diff --git a/components/ILIAS/Logging/classes/class.ilLogComponentLevels.php b/components/ILIAS/Logging/classes/class.ilLogComponentLevels.php deleted file mode 100755 index 12764f4866af..000000000000 --- a/components/ILIAS/Logging/classes/class.ilLogComponentLevels.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @version $Id$ - * - */ -class ilLogComponentLevels -{ - protected static ?ilLogComponentLevels $instance = null; - /** - * @var ilLogComponentLevel[] - */ - protected array $components = array(); - - protected ilDBInterface $db; - - /** - * constructor - */ - protected function __construct() - { - global $DIC; - $this->db = $DIC->database(); - $this->read(); - } - - public static function getInstance(): ilLogComponentLevels - { - if (!self::$instance) { - self::$instance = new self(); - } - return self::$instance; - } - - /** - * @param string $a_component_id - */ - public static function updateFromXML($a_component_id): bool - { - global $DIC; - - $ilDB = $DIC->database(); - if (!$a_component_id) { - return false; - } - - $query = 'SELECT * FROM log_components ' . - 'WHERE component_id = ' . $ilDB->quote($a_component_id, 'text'); - $res = $ilDB->query($query); - if (!$res->numRows()) { - $query = 'INSERT INTO log_components (component_id) ' . - 'VALUES (' . - $ilDB->quote($a_component_id, 'text') . - ')'; - $ilDB->manipulate($query); - } - return true; - } - - /** - * Get component levels - * @return ilLogComponentLevel[] - */ - public function getLogComponents(): array - { - return $this->components; - } - - public function read(): void - { - $query = 'SELECT * FROM log_components '; - $res = $this->db->query($query); - - $this->components = array(); - while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) { - $this->components[] = new ilLogComponentLevel((string) $row->component_id, (int) $row->log_level); - } - } -} diff --git a/components/ILIAS/Logging/classes/class.ilLogComponentTableGUI.php b/components/ILIAS/Logging/classes/class.ilLogComponentTableGUI.php index 335f3a31a5ef..ecdd5cc81d1e 100755 --- a/components/ILIAS/Logging/classes/class.ilLogComponentTableGUI.php +++ b/components/ILIAS/Logging/classes/class.ilLogComponentTableGUI.php @@ -17,32 +17,28 @@ *********************************************************************/ declare(strict_types=1); + +use ILIAS\Logging\Config\Basic\ConfigInterface as BasicConfig; +use ILIAS\Logging\Config\ByComponent\RepositoryInterface as ComponentConfigRepo; +use ILIAS\Logging\ILIASLogLevel; + /** * Component logger with individual log levels by component id */ class ilLogComponentTableGUI extends ilTable2GUI { - protected ilComponentRepository $component_repo; - protected ?ilLoggingDBSettings $settings = null; - protected bool $editable = true; - - public function __construct(object $a_parent_obj, string $a_parent_cmd = "") - { - global $DIC; - $this->component_repo = $DIC["component.repository"]; - + public function __construct( + protected bool $editable, + protected ilComponentRepository $component_repo, + protected BasicConfig $basic_log_config, + protected ComponentConfigRepo $component_config_repo, + object $a_parent_obj, + string $a_parent_cmd = "" + ) { $this->setId('il_log_component'); parent::__construct($a_parent_obj, $a_parent_cmd); } - /** - * Set ediatable (write permission granted) - */ - public function setEditable(bool $a_status): void - { - $this->editable = $a_status; - } - /** * Check if ediatable (write permission granted) */ @@ -57,7 +53,6 @@ public function isEditable(): bool public function init(): void { $this->setFormAction($this->ctrl->getFormAction($this->getParentObject())); - $this->settings = ilLoggingDBSettings::getInstance(); $this->setRowTemplate('tpl.log_component_row.html', 'components/ILIAS/Logging'); $this->addColumn($this->lng->txt('log_component_col_component'), 'component_sortable'); @@ -74,63 +69,76 @@ public function init(): void $this->setLimit(500); } - /** - * Get settings - */ - public function getSettings(): ilLoggingDBSettings - { - return $this->settings; - } - /** * Parse table */ public function parse(): void { - $components = ilLogComponentLevels::getInstance()->getLogComponents(); - $rows = array(); - foreach ($components as $component) { - $row['id'] = $component->getComponentId(); - if ($component->getComponentId() == 'log_root') { - $row['component'] = 'Root'; - $row['component_sortable'] = '_' . $row['component']; - } else { - if ($this->component_repo->hasComponentId( - $component->getComponentId() - )) { - $row['component'] = $this->component_repo->getComponentById( - $component->getComponentId() - )->getName(); - } else { - $row['component'] = "Unknown (" . $component->getComponentId() . ")"; - } - $row['component_sortable'] = $row['component']; - } - $row['level'] = (int) $component->getLevel(); + $levels_by_component = $this->component_config_repo->getAllLevelsForComponents(); + + $rows = []; + foreach ($this->component_repo->getComponents() as $id => $component) { + $row = []; + $row['id'] = $id; + $row['component'] = $row['component_sortable'] = $component->getName(); + $row['level'] = $levels_by_component[$id]?->value ?? 0; + unset($levels_by_component[$id]); + $rows[] = $row; + } + foreach ($this->component_repo->getPlugins() as $id => $plugin) { + $row = []; + $row['id'] = $id; + $row['component'] = $row['component_sortable'] = $plugin->getName(); + $row['level'] = $levels_by_component[$id]?->value ?? 0; + unset($levels_by_component[$id]); + $rows[] = $row; + } + foreach ($levels_by_component as $id => $level) { + $row = []; + $row['id'] = $id; + $row['component'] = $row['component_sortable'] = sprintf( + $this->lng->txt('log_component_unknown'), + $id + ); + $row['level'] = $level->value; + unset($levels_by_component[$id]); $rows[] = $row; } $this->setMaxCount(count($rows)); $this->setData($rows); } - /** - * @inheritDoc - */ protected function fillRow(array $a_set): void { $this->tpl->setVariable('CNAME', $a_set['component']); - if ($a_set['id'] == 'log_root') { - $this->tpl->setVariable('TXT_DESC', $this->lng->txt('log_component_root_desc')); - } - $default_option_value = ilLoggingDBSettings::getInstance()->getLevel(); - $array_options = ilLogLevel::getLevelOptions(); - $default_option = array( 0 => $this->lng->txt('default') . " (" . $array_options[$default_option_value] . ")"); - $array_options = $default_option + $array_options; + $default_label = sprintf( + $this->lng->txt('log_level_default'), + $this->presentableLogLevel($this->basic_log_config->defaultLevel()) + ); + $options = [0 => $default_label]; + foreach (ILIASLogLevel::cases() as $level) { + $options[$level->value] = $this->presentableLogLevel($level); + } $levels = new ilSelectInputGUI('', 'level[' . $a_set['id'] . ']'); - $levels->setOptions($array_options); + $levels->setOptions($options); $levels->setValue($a_set['level']); $this->tpl->setVariable('C_SELECT_LEVEL', $levels->render()); } + + protected function presentableLogLevel(ILIASLogLevel $level): string + { + return match ($level) { + ILIASLogLevel::DEBUG => $this->lng->txt('log_level_debug'), + ILIASLogLevel::INFO => $this->lng->txt('log_level_info'), + ILIASLogLevel::NOTICE => $this->lng->txt('log_level_notice'), + ILIASLogLevel::WARNING => $this->lng->txt('log_level_warning'), + ILIASLogLevel::ERROR => $this->lng->txt('log_level_error'), + ILIASLogLevel::CRITICAL => $this->lng->txt('log_level_critical'), + ILIASLogLevel::ALERT => $this->lng->txt('log_level_alert'), + ILIASLogLevel::EMERGENCY => $this->lng->txt('log_level_emergency'), + ILIASLogLevel::OFF => $this->lng->txt('log_level_off') + }; + } } diff --git a/components/ILIAS/Logging/classes/class.ilLogger.php b/components/ILIAS/Logging/classes/class.ilLogger.php index 94c684c4b42f..62d1002dd378 100755 --- a/components/ILIAS/Logging/classes/class.ilLogger.php +++ b/components/ILIAS/Logging/classes/class.ilLogger.php @@ -18,16 +18,20 @@ declare(strict_types=1); -use Monolog\Logger; +use ILIAS\Logging\Logger\LoggerInterface; use Monolog\Processor\MemoryPeakUsageProcessor; /** * Component logger with individual log levels by component id + * + * @deprecated Please use {@see \ILIAS\Logging\Logger\LoggerInterface} via + * {@see \ILIAS\Logging\Logger\LoggerFactoryInterface} instead. + * * @author Stefan Meyer */ abstract class ilLogger { - public function __construct(private readonly Logger $logger) + public function __construct(private readonly LoggerInterface $logger) { } @@ -36,7 +40,7 @@ public function __construct(private readonly Logger $logger) */ public function isHandling(int $level): bool { - return $this->getLogger()->isHandling($level); + return $this->getLogger()->isHandlingLogLevel($level); } public function log(string $message, int $level = ilLogLevel::INFO, array $context = []): void @@ -91,7 +95,7 @@ public function emergency(string $message, array $context = []): void $this->getLogger()->emergency($message, $context); } - public function getLogger(): Logger + protected function getLogger(): LoggerInterface { return $this->logger; } @@ -128,22 +132,6 @@ public function logStack(?int $level = null, string $message = '', array $contex $level = ilLogLevel::INFO; } - - try { - throw new Exception($message); - } catch (Exception $ex) { - $this->getLogger()->log($level, $message . "\n" . $ex->getTraceAsString(), $context); - } - } - - /** - * Write memory peak usage - * Automatically called at end of script - */ - public function writeMemoryPeakUsage(int $level): void - { - $this->getLogger()->pushProcessor(new MemoryPeakUsageProcessor()); - $this->getLogger()->log($level, 'Memory usage: '); - $this->getLogger()->popProcessor(); + $this->getLogger()->logStack($level, $message, $context); } } diff --git a/components/ILIAS/Logging/classes/class.ilLoggingDBSettings.php b/components/ILIAS/Logging/classes/class.ilLoggingDBSettings.php index fc25a9694818..8c3ea9e0c9fc 100755 --- a/components/ILIAS/Logging/classes/class.ilLoggingDBSettings.php +++ b/components/ILIAS/Logging/classes/class.ilLoggingDBSettings.php @@ -17,39 +17,31 @@ *********************************************************************/ declare(strict_types=1); + +use ILIAS\Logging\Config\Basic\ConfigInterface as BasicConfig; +use ILIAS\Logging\Config\ByComponent\ConfigInterface as ComponentConfig; +use ILIAS\Logging\Logger\LegacyInitiator; + /** -* @defgroup ServicesLogging Services/Logging -* -* @author Stefan Meyer -* @ingroup ServicesLogging -*/ + * @deprecated Please use {@see \ILIAS\Logging\Config\ConfigInterface} instead. + * + * @defgroup ServicesLogging Services/Logging + * + * @author Stefan Meyer + * @ingroup ServicesLogging + */ class ilLoggingDBSettings implements ilLoggingSettings { protected static ?ilLoggingDBSettings $instance = null; - private bool $enabled = false; - private ilSetting $storage; - - private int $level; - private bool $cache = false; - private int $cache_level; - private bool $memory_usage = false; - private bool $browser = false; - /** - * @var string[] - */ - private array $browser_users = array(); - - + protected BasicConfig $basic_config; + protected ComponentConfig $component_config; private function __construct() { - $this->enabled = (bool) ILIAS_LOG_ENABLED; - $this->level = ilLogLevel::INFO; - $this->cache_level = ilLogLevel::DEBUG; - - $this->storage = new ilSetting('logging'); - $this->read(); + $initiator = LegacyInitiator::getInstance(); + $this->basic_config = $initiator->basicConfig(); + $this->component_config = $initiator->componentConfig(); } public static function getInstance(): self @@ -66,143 +58,24 @@ public static function getInstance(): self */ public function getLevelByComponent(string $a_component_id): int { - $levels = ilLogComponentLevels::getInstance()->getLogComponents(); - foreach ($levels as $level) { - if ($level->getComponentId() == $a_component_id) { - if ($level->getLevel()) { - return $level->getLevel(); - } - } - } - return $this->getLevel(); - } - - /** - * @return ilSetting - */ - protected function getStorage(): ilSetting - { - return $this->storage; + return $this->component_config->level($a_component_id)->value; } /** * Check if logging is enabled - * @return bool */ public function isEnabled(): bool { - return $this->enabled; + return $this->basic_config->isLoggingEnabled(); } public function getLogDir(): string { - return ILIAS_LOG_DIR; - } - - public function getLogFile(): string - { - return ILIAS_LOG_FILE; + return $this->basic_config->pathToLogDirectory(); } public function getLevel(): int { - return $this->level; - } - - public function setLevel(int $a_level): void - { - $this->level = $a_level; - } - - public function setCacheLevel(int $a_level): void - { - $this->cache_level = $a_level; - } - - public function getCacheLevel(): int - { - return $this->cache_level; - } - - public function enableCaching(bool $a_status): void - { - $this->cache = $a_status; - } - - public function isCacheEnabled(): bool - { - return $this->cache; - } - - public function enableMemoryUsage(bool $a_stat): void - { - $this->memory_usage = $a_stat; - } - - public function isMemoryUsageEnabled(): bool - { - return $this->memory_usage; - } - - public function isBrowserLogEnabled(): bool - { - return $this->browser; - } - - - public function isBrowserLogEnabledForUser(string $a_login): bool - { - if (!$this->isBrowserLogEnabled()) { - return false; - } - if (in_array($a_login, $this->getBrowserLogUsers())) { - return true; - } - return false; - } - - public function enableBrowserLog(bool $a_stat): void - { - $this->browser = $a_stat; - } - - public function getBrowserLogUsers(): array - { - return $this->browser_users; - } - - public function setBrowserUsers(array $users): void - { - $this->browser_users = $users; - } - - - /** - * Update setting - */ - public function update(): void - { - $this->getStorage()->set('level', (string) $this->getLevel()); - $this->getStorage()->set('cache', (string) $this->isCacheEnabled()); - $this->getStorage()->set('cache_level', (string) $this->getCacheLevel()); - $this->getStorage()->set('memory_usage', (string) $this->isMemoryUsageEnabled()); - $this->getStorage()->set('browser', (string) $this->isBrowserLogEnabled()); - $this->getStorage()->set('browser_users', serialize($this->getBrowserLogUsers())); - } - - - /** - * Read settings - * - * @access private - */ - private function read(): void - { - $this->setLevel((int) $this->getStorage()->get('level', (string) $this->level)); - $this->enableCaching((bool) $this->getStorage()->get('cache', (string) $this->cache)); - $this->setCacheLevel((int) $this->getStorage()->get('cache_level', (string) $this->cache_level)); - $this->enableMemoryUsage((bool) $this->getStorage()->get('memory_usage', (string) $this->memory_usage)); - $this->enableBrowserLog((bool) $this->getStorage()->get('browser', (string) $this->browser)); - $this->setBrowserUsers((array) unserialize($this->getStorage()->get('browser_users', serialize($this->browser_users)))); + return $this->basic_config->defaultLevel()->value; } } diff --git a/components/ILIAS/Logging/classes/class.ilLoggingSetupSettings.php b/components/ILIAS/Logging/classes/class.ilLoggingSetupSettings.php deleted file mode 100755 index 11288c80e180..000000000000 --- a/components/ILIAS/Logging/classes/class.ilLoggingSetupSettings.php +++ /dev/null @@ -1,109 +0,0 @@ - -* @ingroup ServicesLogging -*/ -class ilLoggingSetupSettings implements ilLoggingSettings -{ - private bool $enabled = false; - private string $log_dir = ''; - private string $log_file = ''; - - - public function init(): void - { - $ilIliasIniFile = new ilIniFile("./ilias.ini.php"); - $ilIliasIniFile->read(); - - $enabled = $ilIliasIniFile->readVariable('log', 'enabled'); - $this->enabled = $enabled == '1'; - $this->log_dir = (string) $ilIliasIniFile->readVariable('log', 'path'); - $this->log_file = (string) $ilIliasIniFile->readVariable('log', 'file'); - } - - /** - * Logging enabled - * @return bool - */ - public function isEnabled(): bool - { - return $this->enabled; - } - - public function getLogDir(): string - { - return $this->log_dir; - } - - public function getLogFile(): string - { - return $this->log_file; - } - - /** - * Get log Level - * @return int - */ - public function getLevel(): int - { - return ilLogLevel::INFO; - } - - public function getLevelByComponent(string $a_component_id): int - { - return $this->getLevel(); - } - - /** - * Get log Level - * @return int - */ - public function getCacheLevel(): int - { - return ilLogLevel::INFO; - } - - public function isCacheEnabled(): bool - { - return false; - } - - public function isMemoryUsageEnabled(): bool - { - return false; - } - - public function isBrowserLogEnabled(): bool - { - return false; - } - - public function isBrowserLogEnabledForUser(string $a_login): bool - { - return false; - } - - public function getBrowserLogUsers(): array - { - return array(); - } -} diff --git a/components/ILIAS/Logging/classes/class.ilObjLoggingSettingsGUI.php b/components/ILIAS/Logging/classes/class.ilObjLoggingSettingsGUI.php index fc91f1e100ff..00b286407990 100755 --- a/components/ILIAS/Logging/classes/class.ilObjLoggingSettingsGUI.php +++ b/components/ILIAS/Logging/classes/class.ilObjLoggingSettingsGUI.php @@ -17,9 +17,15 @@ *********************************************************************/ declare(strict_types=1); + use ILIAS\DI\Container; use ILIAS\Refinery\Factory as Refinery; use ILIAS\HTTP\Services as Services; +use ILIAS\Logging\Config\Basic\ConfigInterface as BasicConfig; +use ILIAS\Logging\Config\ByComponent\ConfigInterface as ByComponentConfig; +use ILIAS\Logging\Config\ByComponent\RepositoryInterface as ComponentConfigRepo; +use ILIAS\Logging\ILIASLogLevel; +use ILIAS\Logging\Logger\LegacyInitiator; /** * @@ -31,21 +37,16 @@ */ class ilObjLoggingSettingsGUI extends ilObjectGUI { - protected const SECTION_SETTINGS = 'settings'; - protected const SUB_SECTION_MAIN = 'log_general_settings'; - protected const SUB_SECTION_COMPONENTS = 'log_components'; - protected const SUB_SECTION_ERROR = 'log_error_settings'; + protected const string SECTION_SETTINGS = 'settings'; + protected const string SUB_SECTION_COMPONENTS = 'log_components'; + protected const string SUB_SECTION_ERROR = 'log_error_settings'; - protected ilLoggingDBSettings $log_settings; - protected ilLogger $log; protected ilLoggingErrorSettings $error_settings; protected Refinery $refinery; + protected ilComponentRepository $component_repo; + protected BasicConfig $basic_log_config; + protected ComponentConfigRepo $component_config_repo; - /** - * - * @param mixed $a_data - * @param boolean $a_prepare_output - */ public function __construct($a_data, int $a_id, bool $a_call_by_reference, bool $a_prepare_output = true) { global $DIC; @@ -54,19 +55,17 @@ public function __construct($a_data, int $a_id, bool $a_call_by_reference, bool parent::__construct($a_data, $a_id, $a_call_by_reference, $a_prepare_output); $this->lng = $DIC->language(); + $this->component_repo = $DIC["component.repository"]; - $this->initSettings(); $this->initErrorSettings(); $this->lng->loadLanguageModule('logging'); $this->lng->loadLanguageModule('log'); - $this->log = ilLoggerFactory::getLogger('log'); $this->refinery = $DIC->refinery(); - } - public function getLogger(): ilLogger - { - return $this->log; + $initiator = LegacyInitiator::getInstance(); + $this->basic_log_config = $initiator->basicConfig(); + $this->component_config_repo = $initiator->componentConfigRepository(); } public function executeCommand(): void @@ -74,6 +73,7 @@ public function executeCommand(): void $next_class = $this->ctrl->getNextClass($this); $cmd = $this->ctrl->getCmd(); $this->prepareOutput(); + $this->checkPermission('read'); switch ($next_class) { case 'ilpermissiongui': @@ -84,7 +84,7 @@ public function executeCommand(): void default: if ($cmd == "" || $cmd == "view") { - $cmd = "settings"; + $cmd = "errorSettings"; } $this->$cmd(); @@ -111,11 +111,6 @@ public function getAdminTabs(): void public function setSubTabs(string $a_section): void { - $this->tabs_gui->addSubTab( - static::SUB_SECTION_MAIN, - $this->lng->txt(static::SUB_SECTION_MAIN), - $this->ctrl->getLinkTarget($this, 'settings') - ); $this->tabs_gui->addSubTab( static::SUB_SECTION_ERROR, $this->lng->txt(static::SUB_SECTION_ERROR), @@ -129,108 +124,6 @@ public function setSubTabs(string $a_section): void $this->tabs_gui->activateSubTab($a_section); } - protected function initSettings() - { - $this->log_settings = ilLoggingDBSettings::getInstance(); - } - - public function getSettings(): ilLoggingDBSettings - { - return $this->log_settings; - } - - public function settings(?ilPropertyFormGUI $form = null) - { - if (!$this->rbac_system->checkAccess("read", $this->object->getRefId())) { - $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE); - } - - $this->tabs_gui->setTabActive(static::SECTION_SETTINGS); - $this->setSubTabs(static::SUB_SECTION_MAIN); - - if (!$form instanceof ilPropertyFormGUI) { - $form = $this->initFormSettings(); - } - $this->tpl->setContent($form->getHTML()); - $this->getLogger()->debug('Currrent level is ' . $this->getSettings()->getLevel()); - return true; - } - - public function updateSettings(): void - { - if (!$this->rbac_system->checkAccess('write', $this->object->getRefId())) { - $this->ilias->raiseError($this->lng->txt("permission_denied"), $this->ilias->error_obj->MESSAGE); - } - $form = $this->initFormSettings(); - if ($form->checkInput()) { - $this->getSettings()->setLevel((int) $form->getInput('level')); - $this->getSettings()->enableCaching((bool) $form->getInput('cache')); - $this->getSettings()->setCacheLevel((int) $form->getInput('cache_level')); - $this->getSettings()->enableMemoryUsage((bool) $form->getInput('memory')); - $this->getSettings()->enableBrowserLog((bool) $form->getInput('browser')); - $this->getSettings()->setBrowserUsers($form->getInput('browser_users')); - - $this->getLogger()->info(print_r($form->getInput('browser_users'), true)); - - $this->getSettings()->update(); - - $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true); - $this->ctrl->redirect($this, 'settings'); - return; - } - - $this->tpl->setOnScreenMessage('failure', $this->lng->txt('err_check_input')); - $form->setValuesByPost(); - $this->settings($form); - } - - protected function initFormSettings(): ilPropertyFormGUI - { - $form = new ilPropertyFormGUI(); - $form->setTitle($this->lng->txt('logs_settings')); - $form->setFormAction($this->ctrl->getFormAction($this)); - - if ($this->access->checkAccess('write', '', $this->object->getRefId())) { - $form->addCommandButton('updateSettings', $this->lng->txt('save')); - } - - $level = new ilSelectInputGUI($this->lng->txt('log_log_level'), 'level'); - $level->setOptions(ilLogLevel::getLevelOptions()); - $level->setValue($this->getSettings()->getLevel()); - $form->addItem($level); - - $cache = new ilCheckboxInputGUI($this->lng->txt('log_cache_'), 'cache'); - $cache->setInfo($this->lng->txt('log_cache_info')); - $cache->setValue('1'); - $cache->setChecked($this->getSettings()->isCacheEnabled()); - $form->addItem($cache); - - $cache_level = new ilSelectInputGUI($this->lng->txt('log_cache_level'), 'cache_level'); - $cache_level->setOptions(ilLogLevel::getLevelOptions()); - $cache_level->setValue($this->getSettings()->getCacheLevel()); - $cache->addSubItem($cache_level); - - $memory = new ilCheckboxInputGUI($this->lng->txt('log_memory'), 'memory'); - $memory->setValue('1'); - $memory->setChecked($this->getSettings()->isMemoryUsageEnabled()); - $form->addItem($memory); - - // Browser handler - $browser = new ilCheckboxInputGUI($this->lng->txt('log_browser'), 'browser'); - $browser->setValue('1'); - $browser->setChecked($this->getSettings()->isBrowserLogEnabled()); - $form->addItem($browser); - - // users - $users = new ilTextInputGUI($this->lng->txt('log_browser_users'), 'browser_users'); - $users->setValue(current($this->getSettings()->getBrowserLogUsers())); - $users->setMulti(true); - $users->setMultiValues($this->getSettings()->getBrowserLogUsers()); - $this->getLogger()->debug(print_r($this->getSettings()->getBrowserLogUsers(), true)); - $browser->addSubItem($users); - return $form; - } - /** * Show components @@ -240,8 +133,14 @@ protected function components(): void $this->tabs_gui->activateTab(static::SECTION_SETTINGS); $this->setSubTabs(static::SUB_SECTION_COMPONENTS); - $table = new ilLogComponentTableGUI($this, 'components'); - $table->setEditable($this->checkPermissionBool('write')); + $table = new ilLogComponentTableGUI( + $this->checkPermissionBool('write'), + $this->component_repo, + $this->basic_log_config, + $this->component_config_repo, + $this, + 'components' + ); $table->init(); $table->parse(); $this->tpl->setContent($table->getHTML()); @@ -277,8 +176,14 @@ static function ($k, $v): array { ); } foreach ($levels as $component_id => $value) { - $level = new ilLogComponentLevel($component_id, $value); - $level->update(); + if ($value === 0) { + $this->component_config_repo->resetLevelForComponent($component_id); + } + $level = ILIASLogLevel::tryFrom($value); + if ($level === null) { + continue; + } + $this->component_config_repo->updateLevelForComponent($component_id, $level); } $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true); $this->ctrl->redirect($this, 'components'); @@ -287,10 +192,7 @@ static function ($k, $v): array { protected function resetComponentLevels(): void { $this->checkPermission('write'); - foreach (ilLogComponentLevels::getInstance()->getLogComponents() as $component) { - $component->setLevel(null); - $component->update(); - } + $this->component_config_repo->resetLevelsForAllComponents(); $this->tpl->setOnScreenMessage('success', $this->lng->txt('settings_saved'), true); $this->ctrl->redirect($this, 'components'); } diff --git a/components/ILIAS/Logging/classes/error/class.ilLoggingErrorFileStorage.php b/components/ILIAS/Logging/classes/error/class.ilLoggingErrorFileStorage.php index 04077df92b4b..0b1a853c352c 100755 --- a/components/ILIAS/Logging/classes/error/class.ilLoggingErrorFileStorage.php +++ b/components/ILIAS/Logging/classes/error/class.ilLoggingErrorFileStorage.php @@ -140,9 +140,9 @@ protected function tables(): array $post = $_POST; $server = $_SERVER; - $post = $this->hideSensitiveData($post); - $server = $this->hideSensitiveData($server); - $server = $this->shortenPHPSessionId($server); + $post = $this->hideSensitiveData((array) $post); + $server = $this->hideSensitiveData((array) $server); + $server = $this->shortenPHPSessionId((array) $server); return [ 'GET Data' => $_GET, diff --git a/components/ILIAS/Logging/classes/extensions/class.ilTraceProcessor.php b/components/ILIAS/Logging/classes/extensions/class.ilTraceProcessor.php deleted file mode 100755 index 1bfc71c6db84..000000000000 --- a/components/ILIAS/Logging/classes/extensions/class.ilTraceProcessor.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @version $Id$ - * - */ -class ilTraceProcessor -{ - private int $level = 0; - - public function __construct(int $a_level) - { - $this->level = $a_level; - } - - /** - * @todo fix shifting calls - */ - public function __invoke(LogRecord $record): LogRecord - { - if ($record['level'] < $this->level) { - return $record; - } - - $trace = debug_backtrace(); - - // shift current method - array_shift($trace); - - // shift internal monolog calls - array_shift($trace); - array_shift($trace); - array_shift($trace); - array_shift($trace); - - if (is_array($trace) && count($trace)) { - $trace_info = - ($trace[0]['class'] ?? '') . '::' . - ($trace[0]['function'] ?? '') . ':' . - ($trace[0]['line'] ?? ''); - $record['extra'] = array_merge( - $record['extra'], - array('trace' => $trace_info) - ); - } - return $record; - } -} diff --git a/components/ILIAS/Logging/classes/public/class.ilLogLevel.php b/components/ILIAS/Logging/classes/public/class.ilLogLevel.php index 1678c78701eb..308468a3b339 100755 --- a/components/ILIAS/Logging/classes/public/class.ilLogLevel.php +++ b/components/ILIAS/Logging/classes/public/class.ilLogLevel.php @@ -26,6 +26,7 @@ * * @author Stefan Meyer * + * @deprecated Please use {@see \ILIAS\Logging\ILIASLogLevel} instead. */ class ilLogLevel { diff --git a/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php b/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php index e865f2b34aca..849b836548af 100755 --- a/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php +++ b/components/ILIAS/Logging/classes/public/class.ilLoggerFactory.php @@ -18,49 +18,29 @@ declare(strict_types=1); -use Monolog\Logger; -use Monolog\Handler\StreamHandler; -use Monolog\Handler\BrowserConsoleHandler; -use Monolog\Formatter\LineFormatter; -use Monolog\Handler\FingersCrossedHandler; -use Monolog\Handler\NullHandler; -use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; -use ILIAS\DI\Container; -use Monolog\Processor\PsrLogMessageProcessor; +use ILIAS\Logging\Logger\LegacyInitiator; /** * Logging factory * + * @deprecated Please use {@see \ILIAS\Logging\Logger\LoggerInterface} via + * {@see \ILIAS\Logging\Logger\LoggerFactoryInterface} instead. + * * @author Stefan Meyer * */ class ilLoggerFactory { - protected const DEFAULT_FORMAT = "[%extra.suid%] [%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; - - protected const ROOT_LOGGER = 'root'; - protected const COMPONENT_ROOT = 'log_root'; - protected const SETUP_LOGGER = 'setup'; - private static ?ilLoggerFactory $instance = null; - private ilLoggingSettings $settings; - protected Container $dic; - - private bool $enabled = false; //ToDo PHP8 Review: This is a private var never read only written and should probably be removed. - /** * @var array */ - private array $loggers = array(); - - protected function __construct(ilLoggingSettings $settings) - { - global $DIC; + private array $loggers = []; - $this->dic = $DIC; - $this->settings = $settings; - $this->enabled = $this->getSettings()->isEnabled(); + protected function __construct( + protected ilLoggingSettings $settings + ) { } public static function getInstance(): ilLoggerFactory @@ -72,16 +52,6 @@ public static function getInstance(): ilLoggerFactory return static::$instance; } - public static function newInstance(ilLoggingSettings $settings): ilLoggerFactory - { - return static::$instance = new self($settings); - } - - public function isLoggingEnabled(): bool - { - return $this->enabled; - } - /** * Get component logger @@ -98,7 +68,7 @@ public static function getLogger(string $a_component_id): ilLogger public static function getRootLogger(): ilLogger { $factory = self::getInstance(); - return $factory->getComponentLogger(self::ROOT_LOGGER); + return $factory->getComponentLogger('root'); } @@ -107,51 +77,6 @@ public static function getRootLogger(): ilLogger */ public function initUser(string $a_login): void { - if (!$this->getSettings()->isBrowserLogEnabledForUser($a_login)) { - return; - } - - foreach ($this->loggers as $a_component_id => $logger) { - if ($this->isConsoleAvailable()) { - $browser_handler = new BrowserConsoleHandler(); - $browser_handler->setLevel($this->getSettings()->getLevelByComponent($a_component_id)); - $browser_handler->setFormatter(new ilLineFormatter(static::DEFAULT_FORMAT, 'Y-m-d H:i:s.u', true, true)); - $logger->getLogger()->pushHandler($browser_handler); - } - } - } - - /** - * Check if console handler is available - */ - protected function isConsoleAvailable(): bool - { - if (ilContext::getType() !== ilContext::CONTEXT_WEB) { - return false; - } - - if (($this->dic->isDependencyAvailable('ctrl') && $this->dic->ctrl()->isAsynch()) || - ( - $this->dic->isDependencyAvailable('http') && - strtolower( - $this->dic->http()->request()->getServerParams()['HTTP_X_REQUESTED_WITH'] ?? '' - ) === 'xmlhttprequest' - ) - ) { - return false; - } - - if ($this->dic->isDependencyAvailable('http') && - str_contains($this->dic->http()->request()->getServerParams()['HTTP_ACCEPT'] ?? '', 'text/html')) { - return true; - } - - if ($this->dic->isDependencyAvailable('http') && - str_contains($this->dic->http()->request()->getServerParams()['HTTP_ACCEPT'] ?? '', 'application/json')) { - return false; - } - - return true; } public function getSettings(): ilLoggingSettings @@ -159,102 +84,21 @@ public function getSettings(): ilLoggingSettings return $this->settings; } - /** - * @return ilComponentLogger[] - */ - protected function getLoggers(): array - { - return $this->loggers; - } - public function getComponentLogger(string $a_component_id): ilLogger { if (isset($this->loggers[$a_component_id])) { return $this->loggers[$a_component_id]; } - $loggerNamePrefix = ''; - if (defined('CLIENT_ID')) { - $loggerNamePrefix = CLIENT_ID . '_'; - } - - switch ($a_component_id) { - case 'root': - $logger = new Logger($loggerNamePrefix . 'root'); - break; - - default: - $logger = new Logger($loggerNamePrefix . $a_component_id); - break; - } - - if (!$this->isLoggingEnabled()) { - $null_handler = new NullHandler(); - $logger->pushHandler($null_handler); - - return $this->loggers[$a_component_id] = new ilComponentLogger($logger); - } - + $initiator = LegacyInitiator::getInstance(); - // standard stream handler - $stream_handler = new StreamHandler( - $this->getSettings()->getLogDir() . '/' . $this->getSettings()->getLogFile(), - Logger::DEBUG, // default minimum level, will be overwritten by component log level - true - ); - - if ($a_component_id == self::ROOT_LOGGER) { - $stream_handler->setLevel($this->getSettings()->getLevelByComponent(self::COMPONENT_ROOT)); - } else { - $stream_handler->setLevel($this->getSettings()->getLevelByComponent($a_component_id)); - } - - // format lines - $line_formatter = new ilLineFormatter(static::DEFAULT_FORMAT, 'Y-m-d H:i:s.u', true, true); - $stream_handler->setFormatter($line_formatter); - - if ($this->getSettings()->isCacheEnabled()) { - // add new finger crossed handler - $finger_crossed_handler = new FingersCrossedHandler( - $stream_handler, - new ErrorLevelActivationStrategy($this->getSettings()->getCacheLevel()), - 1000 + if ($a_component_id === 'root') { + return $this->loggers['root'] = new ilComponentLogger( + $initiator->defaultConfigLoggerFactory()->getLazy('legacy_root') ); - $logger->pushHandler($finger_crossed_handler); - } else { - $logger->pushHandler($stream_handler); - } - - if ( - $this->dic->offsetExists('ilUser') && - $this->dic->user() instanceof ilObjUser - ) { - if ($this->getSettings()->isBrowserLogEnabledForUser($this->dic->user()->getLogin())) { - if ($this->isConsoleAvailable()) { - $browser_handler = new BrowserConsoleHandler(); - $browser_handler->setLevel($this->getSettings()->getLevel()); - $browser_handler->setFormatter($line_formatter); - $logger->pushHandler($browser_handler); - } - } } - - - // suid log - $logger->pushProcessor(function ($record) { - $record['extra']['suid'] = substr(session_id(), 0, 5); - return $record; - }); - - // append trace - $logger->pushProcessor(new ilTraceProcessor(ilLogLevel::DEBUG)); - - // Interpolate context variables. - $logger->pushProcessor(new PsrLogMessageProcessor()); - - // register new logger - $this->loggers[$a_component_id] = new ilComponentLogger($logger); - - return $this->loggers[$a_component_id]; + return $this->loggers[$a_component_id] = new ilComponentLogger( + $initiator->loggerFactory()->getLazy($a_component_id) + ); } } diff --git a/components/ILIAS/Logging/exceptions/class.ilLogException.php b/components/ILIAS/Logging/exceptions/class.ilLogException.php index c032ac963262..5dce492d0adf 100755 --- a/components/ILIAS/Logging/exceptions/class.ilLogException.php +++ b/components/ILIAS/Logging/exceptions/class.ilLogException.php @@ -21,6 +21,8 @@ /** * ILIAS Log exception class * + * @deprecated + * * @author Alex Killing * @version $Id:$ * @ingroup ServicesLogging diff --git a/components/ILIAS/Logging/interfaces/interface.ilLoggingSettings.php b/components/ILIAS/Logging/interfaces/interface.ilLoggingSettings.php index bc7c51932f4a..856268fb3543 100755 --- a/components/ILIAS/Logging/interfaces/interface.ilLoggingSettings.php +++ b/components/ILIAS/Logging/interfaces/interface.ilLoggingSettings.php @@ -17,34 +17,21 @@ *********************************************************************/ /** -* -* @author Stefan Meyer -* @version $Id$ -* -* -* @ingroup ServicesLogging -*/ + * @deprecated Please use {@see \ILIAS\Logging\Config\ConfigInterface} instead. + * + * @author Stefan Meyer + * @version $Id$ + * + * + * @ingroup ServicesLogging + */ interface ilLoggingSettings { public function isEnabled(): bool; public function getLogDir(): string; - public function getLogFile(): string; - public function getLevel(): int; public function getLevelByComponent(string $a_component_id): int; - - public function getCacheLevel(): int; - - public function isCacheEnabled(): bool; - - public function isMemoryUsageEnabled(): bool; - - public function isBrowserLogEnabled(): bool; - - public function isBrowserLogEnabledForUser(string $a_login): bool; - - public function getBrowserLogUsers(): array; } diff --git a/components/ILIAS/Logging/src/Config/Basic/Config.php b/components/ILIAS/Logging/src/Config/Basic/Config.php new file mode 100755 index 000000000000..7ddd4d7f6fd8 --- /dev/null +++ b/components/ILIAS/Logging/src/Config/Basic/Config.php @@ -0,0 +1,64 @@ +is_enabled ??= (bool) $this->reader->isLoggingEnabled(); + } + + public function pathToLogFile(): string + { + return $this->log_file ??= + rtrim($this->reader->logPath(), '/') . '/' . ltrim($this->reader->logFile(), '/'); + } + + public function pathToLogDirectory(): string + { + return $this->log_directory ??= $this->reader->logPath(); + } + + public function defaultLevel(): ILIASLogLevel + { + return $this->default_level ??= $this->logLevelFromString($this->reader->defaultLevel()); + } + + protected function logLevelFromString(string $raw_level): ILIASLogLevel + { + return ILIASLogLevel::tryFromString(strtoupper($raw_level)) ?? + ILIASLogLevel::tryFrom((int) $raw_level) ?? + ILIASLogLevel::INFO; + } +} diff --git a/components/ILIAS/Logging/Testrail/throwException.php b/components/ILIAS/Logging/src/Config/Basic/ConfigInterface.php similarity index 61% rename from components/ILIAS/Logging/Testrail/throwException.php rename to components/ILIAS/Logging/src/Config/Basic/ConfigInterface.php index 1fb407e9a5d0..24873aea2d3f 100755 --- a/components/ILIAS/Logging/Testrail/throwException.php +++ b/components/ILIAS/Logging/src/Config/Basic/ConfigInterface.php @@ -16,16 +16,19 @@ * *********************************************************************/ -chdir("./../../../"); -$ini = new ilIniFile("ilias.ini.php"); -$ini->read(); +declare(strict_types=1); -$http = $ini->readVariable("server", "http_path"); -$http = preg_replace("/^(https:\/\/)|(http:\/\/)+/", "", $http); +namespace ILIAS\Logging\Config\Basic; -$_SERVER['HTTP_HOST'] = $http; -$_SERVER['REQUEST_URI'] = ""; +use ILIAS\Logging\ILIASLogLevel; -ilInitialisation::initILIAS(); +interface ConfigInterface +{ + public function isLoggingEnabled(): bool; -throw new Exception("This is your error message"); + public function pathToLogFile(): string; + + public function pathToLogDirectory(): string; + + public function defaultLevel(): ILIASLogLevel; +} diff --git a/components/ILIAS/Logging/src/Config/Basic/IniReader.php b/components/ILIAS/Logging/src/Config/Basic/IniReader.php new file mode 100755 index 000000000000..6221c175c13d --- /dev/null +++ b/components/ILIAS/Logging/src/Config/Basic/IniReader.php @@ -0,0 +1,51 @@ +ilias_ini_file->readVariable('log', 'enabled'); + } + + public function logFile(): string + { + return $this->ilias_ini_file->readVariable('log', 'file'); + } + + public function logPath(): string + { + return $this->ilias_ini_file->readVariable('log', 'path'); + } + + public function defaultLevel(): string + { + return $this->ilias_ini_file->readVariable('log', 'default_level'); + } +} diff --git a/components/ILIAS/Logging/Testrail/raiseError.php b/components/ILIAS/Logging/src/Config/Basic/IniReaderInterface.php similarity index 58% rename from components/ILIAS/Logging/Testrail/raiseError.php rename to components/ILIAS/Logging/src/Config/Basic/IniReaderInterface.php index 375ef8508ade..27904aba94bd 100755 --- a/components/ILIAS/Logging/Testrail/raiseError.php +++ b/components/ILIAS/Logging/src/Config/Basic/IniReaderInterface.php @@ -16,20 +16,17 @@ * *********************************************************************/ -chdir("./../../../"); -$ini = new ilIniFile("ilias.ini.php"); -$ini->read(); +declare(strict_types=1); -$http = $ini->readVariable("server", "http_path"); -$http = preg_replace("/^(https:\/\/)|(http:\/\/)+/", "", $http); +namespace ILIAS\Logging\Config\Basic; -$_SERVER['HTTP_HOST'] = $http; -$_SERVER['REQUEST_URI'] = ""; +interface IniReaderInterface +{ + public function isLoggingEnabled(): string; -ilInitialisation::initILIAS(); + public function logFile(): string; -global $DIC; + public function logPath(): string; -$ilErr = $DIC['ilErr']; - -$ilErr->raiseError("This is your error message", $ilErr->FATAL); + public function defaultLevel(): string; +} diff --git a/components/ILIAS/Logging/src/Config/ByComponent/Config.php b/components/ILIAS/Logging/src/Config/ByComponent/Config.php new file mode 100755 index 000000000000..821d439305ef --- /dev/null +++ b/components/ILIAS/Logging/src/Config/ByComponent/Config.php @@ -0,0 +1,51 @@ + + */ + protected array $levels_by_component_id; + + public function __construct( + protected RepositoryInterface $repo, + protected BasicConfigInterface $basic_config + ) { + } + + public function level(string $component_id): ILIASLogLevel + { + return $this->getLevels()[$component_id] ?? $this->basic_config->defaultLevel(); + } + + /** + * @return array + */ + protected function getLevels(): array + { + return $this->levels_by_component_id ??= $this->repo->getAllLevelsForComponents(); + } +} diff --git a/components/ILIAS/Logging/src/Config/ByComponent/ConfigInterface.php b/components/ILIAS/Logging/src/Config/ByComponent/ConfigInterface.php new file mode 100755 index 000000000000..f0387e2cd7ca --- /dev/null +++ b/components/ILIAS/Logging/src/Config/ByComponent/ConfigInterface.php @@ -0,0 +1,28 @@ +db->queryF( + 'SELECT * FROM log_components WHERE component_id = %s', + [ilDBConstants::T_TEXT], + [$component_id] + ); + if (!$res->numRows()) { + $this->db->insert( + 'log_components', + ['component_id' => [ilDBConstants::T_TEXT, $component_id]] + ); + } + } + + /** + * @return array + */ + public function getAllLevelsForComponents(): array + { + $levels_by_components = []; + $res = $this->db->query('SELECT * FROM log_components'); + while (($row = $res->fetchAssoc())) { + $levels_by_components[(string) $row['component_id']] = isset($row['log_level']) ? + ILIASLogLevel::tryFrom((int) $row['log_level']) : null; + } + return $levels_by_components; + } + + public function getLevelForComponent(string $component_id): ?ILIASLogLevel + { + $res = $this->db->queryF( + 'SELECT * FROM log_components WHERE component_id = %s', + [ilDBConstants::T_TEXT], + [$component_id] + ); + if (($row = $res->fetchAssoc()) && isset($row['log_level'])) { + return ILIASLogLevel::tryFrom((int) $row['log_level']); + } + return null; + } + + public function updateLevelForComponent(string $component_id, ILIASLogLevel $level): void + { + $this->db->replace( + 'log_components', + ['component_id' => [ilDBConstants::T_TEXT, $component_id]], + ['log_level' => [ilDBConstants::T_INTEGER, $level->value]] + ); + } + + public function resetLevelForComponent(string $component_id): void + { + $this->db->manipulateF( + 'DELETE FROM log_components WHERE component_id = %s', + [ilDBConstants::T_TEXT], + [$component_id] + ); + } + + public function resetLevelsForAllComponents(): void + { + $this->db->manipulate('DELETE FROM log_components'); + } +} diff --git a/components/ILIAS/Logging/src/Config/ByComponent/RepositoryInterface.php b/components/ILIAS/Logging/src/Config/ByComponent/RepositoryInterface.php new file mode 100755 index 000000000000..61ff5f2f8e9f --- /dev/null +++ b/components/ILIAS/Logging/src/Config/ByComponent/RepositoryInterface.php @@ -0,0 +1,41 @@ + + */ + public function getAllLevelsForComponents(): array; + + public function getLevelForComponent(string $component_id): ?ILIASLogLevel; + + public function updateLevelForComponent(string $component_id, ILIASLogLevel $level): void; + + public function resetLevelForComponent(string $component_id): void; + + public function resetLevelsForAllComponents(): void; +} diff --git a/components/ILIAS/Logging/src/Config/Config.php b/components/ILIAS/Logging/src/Config/Config.php new file mode 100755 index 000000000000..7c3faf839a22 --- /dev/null +++ b/components/ILIAS/Logging/src/Config/Config.php @@ -0,0 +1,43 @@ +basic; + } + + public function byComponent(): ByComponentConfigInterface + { + return $this->by_component; + } +} diff --git a/components/ILIAS/Logging/src/Config/ConfigInterface.php b/components/ILIAS/Logging/src/Config/ConfigInterface.php new file mode 100755 index 000000000000..a44fb8d20b0b --- /dev/null +++ b/components/ILIAS/Logging/src/Config/ConfigInterface.php @@ -0,0 +1,31 @@ + self::DEBUG, + 'INFO' => self::INFO, + 'NOTICE' => self::NOTICE, + 'WARNING' => self::WARNING, + 'ERROR' => self::ERROR, + 'CRITICAL' => self::CRITICAL, + 'ALERT' => self::ALERT, + 'EMERGENCY' => self::EMERGENCY, + 'OFF' => self::OFF, + ]; + + case DEBUG = 100; + case INFO = 200; + case NOTICE = 250; + case WARNING = 300; + case ERROR = 400; + case CRITICAL = 500; + case ALERT = 550; + case EMERGENCY = 600; + + case OFF = 1000; + + public static function tryFromString(string $value): ?self + { + return self::STRING_MAP[$value] ?? null; + } + + public function toString(): string + { + return array_search($this, self::STRING_MAP, true); + } +} diff --git a/components/ILIAS/Logging/src/LegacyInitiator.php b/components/ILIAS/Logging/src/LegacyInitiator.php new file mode 100755 index 000000000000..936b47911c35 --- /dev/null +++ b/components/ILIAS/Logging/src/LegacyInitiator.php @@ -0,0 +1,152 @@ +dic = $DIC; + } + + public static function getInstance(): self + { + return self::$instance ??= new self(); + } + + public function basicConfig(): BasicConfigInterface + { + if (isset($this->basic_config)) { + return $this->basic_config; + } + /** + * This exists purely to appease unit tests in other components, + * which somehow depend on the dependencies of ilLoggerFactory. + */ + if ($this->dic->offsetExists('ilIliasIniFile')) { + $basic_config = new BasicConfig(new IniReader($this->dic->iliasIni())); + } else { + $basic_config = new class () implements BasicConfigInterface { + public function isLoggingEnabled(): bool + { + return (bool) ILIAS_LOG_ENABLED; + } + + public function pathToLogFile(): string + { + return rtrim(ILIAS_LOG_DIR, '/') . '/' . + ltrim(ILIAS_LOG_FILE, '/'); + } + + public function pathToLogDirectory(): string + { + return ILIAS_LOG_DIR; + } + + public function defaultLevel(): ILIASLogLevel + { + return ILIASLogLevel::INFO; + } + }; + } + + return $this->basic_config = $basic_config; + } + + public function componentConfigRepository(): ComponentConfigRepoInterface + { + return $this->component_config_repo ??= new ComponentConfigRepo( + $this->dic->database() + ); + } + + public function componentConfig(): ComponentConfigInterface + { + return $this->component_config ??= new ComponentConfig( + $this->componentConfigRepository(), + $this->basicConfig() + ); + } + + protected function lazyInternalFactory(): LazyInternalFactoryInterface + { + return $this->lazy_internal_factory ??= new LazyInternalFactory( + new MonologFactory(), + $this->basicConfig() + ); + } + + protected function levelFetcherFactory(): LevelFetcherFactoryInterface + { + return $this->level_fetcher_factory ??= new LevelFetcherFactory(); + } + + public function loggerFactory(): LoggerFactoryInterface + { + return $this->logger_factory ??= new LoggerFactory( + $this->lazyInternalFactory(), + $this->componentConfig(), + $this->levelFetcherFactory() + ); + } + + public function defaultConfigLoggerFactory(): DefaultConfigLoggerFactoryInterface + { + return $this->default_config_logger_factory ??= new DefaultConfigLoggerFactory( + $this->lazyInternalFactory(), + $this->basicConfig(), + $this->levelFetcherFactory() + ); + } +} diff --git a/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactory.php b/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactory.php new file mode 100755 index 000000000000..f1e60c859e9d --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactory.php @@ -0,0 +1,43 @@ +internal_factory->getLazyGhost( + $component_id, + $this->level_fetcher_factory->defaultLevelFetcher($this->basic_config) + ); + } +} diff --git a/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactoryInterface.php b/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactoryInterface.php new file mode 100755 index 000000000000..156ac46579d6 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/DefaultConfigLoggerFactoryInterface.php @@ -0,0 +1,33 @@ + + */ + protected array $loggers = []; + + public function __construct( + protected MonologFactoryInterface $monolog_factory, + protected BasicConfigInterface $basic_config + ) { + } + + public function getLazyGhost( + string $component_id, + LevelFetcherInterface $level_fetcher + ): LoggerInterface { + if (isset($this->loggers[$component_id])) { + return $this->loggers[$component_id]; + } + + /** @var Logger $lazy_logger */ + $lazy_logger = new ReflectionClass(Logger::class)->newLazyGhost( + function (Logger $logger) use ($component_id, $level_fetcher): void { + $monolog_logger = $this->buildMonologLogger($component_id, $level_fetcher); + $logger->__construct($monolog_logger); + } + ); + return $this->loggers[$component_id] = $lazy_logger; + } + + protected function buildMonologLogger( + string $component_id, + LevelFetcherInterface $level_fetcher + ): MonologLogger { + if (!$this->basic_config->isLoggingEnabled()) { + return $this->monolog_factory->nullLogger($component_id); + } + return $this->monolog_factory->logger( + $component_id, + $level_fetcher->fetchLevel(), + $this->basic_config->pathToLogFile() + ); + } +} diff --git a/components/ILIAS/Logging/src/Logger/LazyInternalFactoryInterface.php b/components/ILIAS/Logging/src/Logger/LazyInternalFactoryInterface.php new file mode 100755 index 000000000000..b678c887f9c8 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/LazyInternalFactoryInterface.php @@ -0,0 +1,32 @@ +config_by_component->level($this->component_id); + } +} diff --git a/components/ILIAS/Logging/src/Logger/LevelFetcher/DefaultLevelFetcher.php b/components/ILIAS/Logging/src/Logger/LevelFetcher/DefaultLevelFetcher.php new file mode 100755 index 000000000000..20d0b5445b44 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/LevelFetcher/DefaultLevelFetcher.php @@ -0,0 +1,37 @@ +basic_config->defaultLevel(); + } +} diff --git a/components/ILIAS/Logging/src/Logger/LevelFetcher/LevelFetcherFactory.php b/components/ILIAS/Logging/src/Logger/LevelFetcher/LevelFetcherFactory.php new file mode 100755 index 000000000000..b2596eedcf01 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/LevelFetcher/LevelFetcherFactory.php @@ -0,0 +1,40 @@ +logger->isHandling($level); + } + + public function dump(mixed $value, mixed $level = ILIASLogLevel::INFO): void + { + $this->log($level, '{dump}', ['dump' => print_r($value, true)]); + } + + public function logStack(mixed $level = ILIASLogLevel::INFO, string|Stringable $message = '', array $context = []): void + { + try { + throw new Exception($message); + } catch (Exception $ex) { + $this->log($level, $message . "\n" . $ex->getTraceAsString(), $context); + } + } + + public function log(mixed $level, Stringable|string $message, array $context = []): void + { + if ($level instanceof ILIASLogLevel) { + $level = $level->value; + } + $this->logger->log($level, $message, $context); + } +} diff --git a/components/ILIAS/Logging/src/Logger/LoggerFactory.php b/components/ILIAS/Logging/src/Logger/LoggerFactory.php new file mode 100755 index 000000000000..5a8d801011ea --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/LoggerFactory.php @@ -0,0 +1,43 @@ +internal_factory->getLazyGhost( + $component_id, + $this->level_fetcher_factory->componentLevelFetcher($this->config_by_component, $component_id) + ); + } +} diff --git a/components/ILIAS/Logging/src/Logger/LoggerFactoryInterface.php b/components/ILIAS/Logging/src/Logger/LoggerFactoryInterface.php new file mode 100755 index 000000000000..7506ea9f22c6 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/LoggerFactoryInterface.php @@ -0,0 +1,26 @@ +buildStandardHandler($level, $file_path); + $logger->pushHandler($handler); + + $logger->pushProcessor(function ($record) { + $record['extra']['suid'] = substr(session_id(), 0, 5); + return $record; + }); // suid log + $logger->pushProcessor(new ILIASTraceProcessor(ILIASLogLevel::DEBUG)); // append trace + $logger->pushProcessor(new PsrLogMessageProcessor()); // Interpolate context variables. + + return $logger; + } + + protected function buildStandardHandler(ILIASLogLevel $level, string $file_path): Handler + { + $stream_handler = new StreamHandler( + $file_path, + $level->value, + true + ); + + $line_formatter = new ILIASLineFormatter(); + $stream_handler->setFormatter($line_formatter); + + return $stream_handler; + } + + public function nullLogger(string $name): MonologLogger + { + $logger = new MonologLogger($name); + $logger->pushHandler(new NullHandler()); + return $logger; + } +} diff --git a/components/ILIAS/Logging/src/Logger/Monolog/FactoryInterface.php b/components/ILIAS/Logging/src/Logger/Monolog/FactoryInterface.php new file mode 100755 index 000000000000..77ed9fb91aa7 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/Monolog/FactoryInterface.php @@ -0,0 +1,31 @@ + - * @ingroup ServicesLogging - */ -class ilLineFormatter extends LineFormatter +class ILIASLineFormatter extends LineFormatter { - /** - * @inheritDoc - */ + protected const string DEFAULT_FORMAT = "[%extra.suid%] [%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + protected const string DEFAULT_DATE_FORMAT = 'Y-m-d H:i:s.u'; + + public function __construct() + { + parent::__construct( + self::DEFAULT_FORMAT, + self::DEFAULT_DATE_FORMAT, + true, + true, + false + ); + } + public function format(LogRecord $record): string { if (isset($record["extra"]["trace"])) { diff --git a/components/ILIAS/Logging/src/Logger/Monolog/ILIASTraceProcessor.php b/components/ILIAS/Logging/src/Logger/Monolog/ILIASTraceProcessor.php new file mode 100644 index 000000000000..a5140b17c250 --- /dev/null +++ b/components/ILIAS/Logging/src/Logger/Monolog/ILIASTraceProcessor.php @@ -0,0 +1,81 @@ +level->value) { + return $record; + } + + $trace = debug_backtrace(); + + // shift current method and first internal monolog call + array_shift($trace); + array_shift($trace); + + $previous_line = $trace[0]['line'] ?? ''; + while (($class = $trace[0]['class'] ?? '') !== '') { + foreach (self::SKIP_CLASS_NAMES_START_WITH as $start) { + if (str_starts_with($class, $start)) { + /* + * To find the line where the logger is called, we need to stay one frame "behind", + * otherwise we'll get the line where the function that calls the logger is + * called from. + */ + $previous_line = $trace[0]['line'] ?? ''; + array_shift($trace); + continue 2; + } + } + break; + } + + if (is_array($trace) && count($trace)) { + $trace_info = + ($trace[0]['class'] ?? '') . '::' . + ($trace[0]['function'] ?? '') . ':' . + $previous_line; + $record['extra'] = array_merge( + $record['extra'], + array('trace' => $trace_info) + ); + } + return $record; + } +} diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupAgent.php b/components/ILIAS/Logging/src/Setup/Agent.php similarity index 56% rename from components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupAgent.php rename to components/ILIAS/Logging/src/Setup/Agent.php index 417c53eed974..7d4d90d65459 100755 --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupAgent.php +++ b/components/ILIAS/Logging/src/Setup/Agent.php @@ -18,17 +18,23 @@ declare(strict_types=1); -use ILIAS\Setup; -use ILIAS\Setup\Config; +namespace ILIAS\Logging\Setup; + +use ILIAS\Setup\Agent as AgentInterface; +use ILIAS\Setup\Agent\HasNoNamedObjective; +use ILIAS\Setup\Objective\NullObjective; +use ILIAS\Setup\ObjectiveCollection; +use ILIAS\Setup\Config as ConfigInterface; use ILIAS\Setup\Objective; use ILIAS\Setup\Metrics\Storage; use ILIAS\Refinery\Factory; use ILIAS\Refinery\Transformation; -use ILIAS\UI; +use ilDatabaseUpdateStepsExecutedObjective; +use ILIAS\Logging\Setup\Steps\DBUpdateSteps12; -class ilLoggingSetupAgent implements Setup\Agent +class Agent implements AgentInterface { - use Setup\Agent\HasNoNamedObjective; + use HasNoNamedObjective; protected Factory $refinery; @@ -37,79 +43,59 @@ public function __construct(Factory $refinery) $this->refinery = $refinery; } - /** - * @inheritdoc - */ public function hasConfig(): bool { return true; } - /** - * @inheritdoc - */ public function getArrayToConfigTransformation(): Transformation { return $this->refinery->custom()->transformation(function ($data) { - return new \ilLoggingSetupConfig( + return new Config( $data["enable"] ?? false, $data["path_to_logfile"] ?? null, - $data["errorlog_dir"] ?? null + $data["default_level"] ?? null, + $data["errorlog_dir"] ?? null, ); }); } - /** - * @inheritdoc - */ - public function getInstallObjective(?Config $config = null): Objective + public function getInstallObjective(?ConfigInterface $config = null): Objective { - return new ilLoggingConfigStoredObjective($config); + return new ConfigStoredObjective($config); } - /** - * @inheritdoc - */ - public function getUpdateObjective(?Config $config = null): Objective + public function getUpdateObjective(?ConfigInterface $config = null): Objective { - $objective = new Setup\Objective\NullObjective(); + $objective = new NullObjective(); if ($config !== null) { - $objective = new ilLoggingConfigStoredObjective($config); + $objective = new ConfigStoredObjective($config); } - return new ILIAS\Setup\ObjectiveCollection( - 'Update of Services/Logging', + return new ObjectiveCollection( + 'Update of ILIAS\Logging', false, $objective, + new DefaultLevelMigratedObjective(), new ilDatabaseUpdateStepsExecutedObjective( - new ilLoggingUpdateSteps8() + new DBUpdateSteps12() ) ); } - /** - * @inheritdoc - */ public function getBuildObjective(): Objective { - return new Setup\Objective\NullObjective(); + return new NullObjective(); } - /** - * @inheritdoc - */ public function getStatusObjective(Storage $storage): Objective { - return new Setup\ObjectiveCollection( - 'Component Logging', + return new ObjectiveCollection( + 'Component ILIAS\Logging', true, - new ilLoggingMetricsCollectedObjective($storage), - new ilDatabaseUpdateStepsMetricsCollectedObjective($storage, new ilLoggingUpdateSteps8()) + new MetricsCollectedObjective($storage) ); } - /** - * @inheritDoc - */ public function getMigrations(): array { return []; diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupConfig.php b/components/ILIAS/Logging/src/Setup/Config.php similarity index 70% rename from components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupConfig.php rename to components/ILIAS/Logging/src/Setup/Config.php index 147e54b93ba9..44e9a6f5f9e6 100755 --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingSetupConfig.php +++ b/components/ILIAS/Logging/src/Setup/Config.php @@ -18,28 +18,39 @@ declare(strict_types=1); -use ILIAS\Setup\Config; +namespace ILIAS\Logging\Setup; -class ilLoggingSetupConfig implements Config +use ILIAS\Setup\Config as ConfigInterface; +use InvalidArgumentException; +use ILIAS\Logging\ILIASLogLevel; + +class Config implements ConfigInterface { protected bool $enabled; - protected ?string $path_to_logfile; - protected ?string $path_to_errorlogfiles; + protected ?ILIASLogLevel $level; protected ?string $errorlog_dir; public function __construct( bool $enabled, ?string $path_to_logfile, + ?string $level, ?string $errorlog_dir ) { if ($enabled && !$path_to_logfile) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( "Expected a path to the logfile, if logging is enabled." ); } + $level = $level === null ? null : ILIASLogLevel::tryFromString($level); + if ($enabled && !$level) { + throw new InvalidArgumentException( + "Expected a valid default log level, if logging is enabled." + ); + } $this->enabled = $enabled; $this->path_to_logfile = $this->normalizePath($path_to_logfile); + $this->level = $level; $this->errorlog_dir = $this->normalizePath($errorlog_dir); } @@ -62,6 +73,11 @@ public function getPathToLogfile(): ?string return $this->path_to_logfile; } + public function getDefaultLevel(): ?ILIASLogLevel + { + return $this->level; + } + public function getErrorlogDir(): ?string { return $this->errorlog_dir; diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingConfigStoredObjective.php b/components/ILIAS/Logging/src/Setup/ConfigStoredObjective.php similarity index 82% rename from components/ILIAS/Logging/classes/Setup/class.ilLoggingConfigStoredObjective.php rename to components/ILIAS/Logging/src/Setup/ConfigStoredObjective.php index f6149424abb3..7b3470f018b9 100755 --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingConfigStoredObjective.php +++ b/components/ILIAS/Logging/src/Setup/ConfigStoredObjective.php @@ -18,12 +18,16 @@ declare(strict_types=1); +namespace ILIAS\Logging\Setup; + use ILIAS\Setup\Objective; use ILIAS\Setup\Environment; use ILIAS\Setup\Config; use ILIAS\Setup\UnachievableException; +use ilIniFilesLoadedObjective; +use ilIniFile; -class ilLoggingConfigStoredObjective implements Objective +class ConfigStoredObjective implements Objective { protected Config $config; @@ -39,7 +43,7 @@ public function getHash(): string public function getLabel(): string { - return "Fill ini with settings for Services/Logging"; + return "Fill ini with settings for ILIAS\Logging"; } public function isNotable(): bool @@ -56,6 +60,7 @@ public function getPreconditions(Environment $environment): array public function achieve(Environment $environment): Environment { + /** @var ilIniFile $ini */ $ini = $environment->getResource(Environment::RESOURCE_ILIAS_INI); $logPath = ''; @@ -68,11 +73,8 @@ public function achieve(Environment $environment): Environment $ini->setVariable("log", "enabled", $this->config->isEnabled() ? "1" : "0"); $ini->setVariable("log", "path", $logPath); $ini->setVariable("log", "file", $logFile); - $ini->setVariable( - "log", - "error_path", - $this->config->getErrorlogDir() ?? '' - ); + $ini->setVariable("log", "default_level", $this->config->getDefaultLevel()?->toString() ?? ""); + $ini->setVariable("log", "error_path", $this->config->getErrorlogDir() ?? ''); if (!$ini->write()) { throw new UnachievableException("Could not write ilias.ini.php"); @@ -81,13 +83,12 @@ public function achieve(Environment $environment): Environment return $environment; } - /** - * @inheritDoc - */ public function isApplicable(Environment $environment): bool { + /** @var ilIniFile $ini */ $ini = $environment->getResource(Environment::RESOURCE_ILIAS_INI); $enabled = $this->config->isEnabled() ? "1" : "0"; + $level = $this->config->getDefaultLevel()?->toString() ?? ""; $logPath = ''; $logFile = ''; @@ -99,6 +100,7 @@ public function isApplicable(Environment $environment): bool return $ini->readVariable("log", "path") !== $logPath || $ini->readVariable("log", "file") !== $logFile || + $ini->readVariable("log", "default_level") !== $level || $ini->readVariable("log", "error_path") !== $this->config->getErrorlogDir() || $ini->readVariable("log", "enabled") !== $enabled ; diff --git a/components/ILIAS/Logging/src/Setup/DefaultLevelMigratedObjective.php b/components/ILIAS/Logging/src/Setup/DefaultLevelMigratedObjective.php new file mode 100755 index 000000000000..162ce2738053 --- /dev/null +++ b/components/ILIAS/Logging/src/Setup/DefaultLevelMigratedObjective.php @@ -0,0 +1,92 @@ +getResource(Environment::RESOURCE_ILIAS_INI); + /** @var ilSettingsFactory $settings_factory */ + $settings_factory = $environment->getResource(Environment::RESOURCE_SETTINGS_FACTORY); + $settings = $settings_factory->settingsFor("logging"); + + if (!$ini->groupExists("log")) { + return $environment; + } + + // Default is INFO, if settings were never saved + $level = ILIASLogLevel::tryFrom((int) $settings->get("level", "")) ?? ILIASLogLevel::INFO; + $ini->setVariable("log", "default_level", $level->toString()); + + $settings->delete("level"); + /* + * It would be better to also delete the long defunct "level" field in the + * ilias.ini.php, but deleting fields is not supported by ilIniFile. + */ + + if (!$ini->write()) { + throw new UnachievableException("Could not write ilias.ini.php"); + } + + return $environment; + } + + public function isApplicable(Environment $environment): bool + { + $ini = $environment->getResource(Environment::RESOURCE_ILIAS_INI); + return !$ini->variableExists("log", "default_level"); + } +} diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingMetricsCollectedObjective.php b/components/ILIAS/Logging/src/Setup/MetricsCollectedObjective.php similarity index 82% rename from components/ILIAS/Logging/classes/Setup/class.ilLoggingMetricsCollectedObjective.php rename to components/ILIAS/Logging/src/Setup/MetricsCollectedObjective.php index bee5934ff019..504767c40b89 100755 --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingMetricsCollectedObjective.php +++ b/components/ILIAS/Logging/src/Setup/MetricsCollectedObjective.php @@ -18,11 +18,15 @@ declare(strict_types=1); +namespace ILIAS\Logging\Setup; + use ILIAS\Setup\Metrics\CollectedObjective; use ILIAS\Setup\Environment; use ILIAS\Setup\Metrics\Storage; +use ilIniFilesLoadedObjective; +use ilIniFile; -class ilLoggingMetricsCollectedObjective extends CollectedObjective +class MetricsCollectedObjective extends CollectedObjective { protected function getTentativePreconditions(Environment $environment): array { @@ -33,6 +37,7 @@ protected function getTentativePreconditions(Environment $environment): array protected function collectFrom(Environment $environment, Storage $storage): void { + /** @var ilIniFile $ini */ $ini = $environment->getResource(Environment::RESOURCE_ILIAS_INI); if (!$ini) { return; @@ -48,6 +53,11 @@ protected function collectFrom(Environment $environment, Storage $storage): void $ini->readVariable("log", "path") . "/" . $ini->readVariable("log", "file"), "The path to the logfile." ); + $storage->storeConfigText( + "default_level", + $ini->readVariable("log", "default_level"), + "The default log level." + ); $storage->storeConfigText( "errorlog_dir", $ini->readVariable("log", "error_path"), diff --git a/components/ILIAS/Logging/src/Setup/Steps/DBUpdateSteps12.php b/components/ILIAS/Logging/src/Setup/Steps/DBUpdateSteps12.php new file mode 100644 index 000000000000..9848feec8969 --- /dev/null +++ b/components/ILIAS/Logging/src/Setup/Steps/DBUpdateSteps12.php @@ -0,0 +1,58 @@ +db = $db; + } + + /** + * Remove default entries, all components/plugins now get a log level. + */ + public function step_1(): void + { + if ($this->db->tableExists('log_components')) { + $this->db->manipulate( + "DELETE FROM log_components WHERE log_level = 0 OR log_level IS NULL" + ); + } + } + + /** + * Remove the root logger log level. + */ + public function step_2(): void + { + if ($this->db->tableExists('log_components')) { + $this->db->manipulate( + "DELETE FROM log_components WHERE component_id = 'log_root'" + ); + } + } +} diff --git a/components/ILIAS/Logging/tests/Config/Basic/ConfigTest.php b/components/ILIAS/Logging/tests/Config/Basic/ConfigTest.php new file mode 100755 index 000000000000..4cc80fc0d0be --- /dev/null +++ b/components/ILIAS/Logging/tests/Config/Basic/ConfigTest.php @@ -0,0 +1,180 @@ +createMock(IniReaderInterface::class); + $reader + ->expects($this->never()) + ->method($this->anything()); + + $config = new Config($reader); + } + + #[TestWith(['0', false])] + #[TestWith(['', false])] + #[TestWith(['1', true])] + public function testIsLoggingEnabled(string $input, bool $expected_result): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('isLoggingEnabled') + ->willReturn($input); + + $config = new Config($reader); + $actual_result = $config->isLoggingEnabled(); + + $this->assertSame($expected_result, $actual_result); + } + + public function testIsLoggingEnabledIsCached(): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('isLoggingEnabled') + ->willReturn('1'); + + $config = new Config($reader); + $first_result = $config->isLoggingEnabled(); + $second_result = $config->isLoggingEnabled(); + + $this->assertSame($first_result, $second_result, 'Result should be cached and stable.'); + } + + #[TestWith(['/path/to/log', 'file.log', '/path/to/log/file.log'], 'no trailing slashes')] + #[TestWith(['/path/to/log/', 'file.log', '/path/to/log/file.log'], 'slash after path')] + #[TestWith(['/path/to/log', '/file.log', '/path/to/log/file.log'], 'slash before file')] + public function testPathToLogFile( + string $expected_path, + string $expected_file, + string $expected_result + ): void { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('logFile') + ->willReturn($expected_file); + $reader + ->expects($this->once()) + ->method('logPath') + ->willReturn($expected_path); + + $config = new Config($reader); + $actual_result = $config->pathToLogFile(); + + $this->assertSame($expected_result, $actual_result); + } + + public function testPathToLogFileIsCached(): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('logFile') + ->willReturn('file.log'); + $reader + ->expects($this->once()) + ->method('logPath') + ->willReturn('/path/to/log'); + + $config = new Config($reader); + $first_result = $config->pathToLogFile(); + $second_result = $config->pathToLogFile(); + + $this->assertSame($first_result, $second_result, 'Result should be cached and stable.'); + } + + public function testPathToLogDirectory(): void + { + $expected_path = '/path/to/log/'; + + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('logPath') + ->willReturn($expected_path); + + $config = new Config($reader); + $actual_path = $config->pathToLogDirectory(); + + $this->assertSame($expected_path, $actual_path); + } + + public function testPathToLogDirectoryIsCached(): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('logPath') + ->willReturn('/path/to/log/'); + + $config = new Config($reader); + $first_result = $config->pathToLogFile(); + $second_result = $config->pathToLogFile(); + + $this->assertSame($first_result, $second_result, 'Result should be cached and stable.'); + } + + #[TestWith(['250', ILIASLogLevel::NOTICE], 'from integer')] + #[TestWith(['ALERT', ILIASLogLevel::ALERT], 'from upper case string')] + #[TestWith(['warning', ILIASLogLevel::WARNING], 'from lower case string')] + #[TestWith(['Emergency', ILIASLogLevel::EMERGENCY], 'from capitalized string')] + #[TestWith(['', ILIASLogLevel::INFO], 'empty, so use fallback')] + #[TestWith(['MUJjOI', ILIASLogLevel::INFO], 'something else, so use fallback')] + public function testDefaultLevel(string $input, ILIASLogLevel $expected_level): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('defaultLevel') + ->willReturn($input); + + $config = new Config($reader); + $actual_level = $config->defaultLevel(); + + $this->assertSame($expected_level, $actual_level); + } + + public function testDefaultLevelIsCached(): void + { + $reader = $this->createMock(IniReaderInterface::class); + $reader + ->expects($this->once()) + ->method('defaultLevel') + ->willReturn('WARNING'); + + $config = new Config($reader); + $first_result = $config->defaultLevel(); + $second_result = $config->defaultLevel(); + + $this->assertSame($first_result, $second_result, 'Result should be cached and stable.'); + } +} diff --git a/components/ILIAS/Logging/tests/Config/ByComponent/ConfigTest.php b/components/ILIAS/Logging/tests/Config/ByComponent/ConfigTest.php new file mode 100755 index 000000000000..4c9a999cc443 --- /dev/null +++ b/components/ILIAS/Logging/tests/Config/ByComponent/ConfigTest.php @@ -0,0 +1,129 @@ +createMock(RepositoryInterface::class); + $basic_config = $this->createMock(BasicConfigInterface::class); + + $repo + ->expects($this->never()) + ->method($this->anything()); + $basic_config + ->expects($this->never()) + ->method($this->anything()); + + $config = new Config($repo, $basic_config); + } + + public function testLevel(): void + { + $expected_component = 'comp_id'; + $expected_level = ILIASLogLevel::WARNING; + + $repo = $this->createMock(RepositoryInterface::class); + $basic_config = $this->createStub(BasicConfigInterface::class); + + $repo + ->expects($this->once()) + ->method('getAllLevelsForComponents') + ->willReturn([ + 'other_component' => ILIASLogLevel::CRITICAL, + 'comp_id' => $expected_level + ]); + + $config = new Config($repo, $basic_config); + $actual_level = $config->level($expected_component); + + $this->assertSame($expected_level, $actual_level); + } + + public function testLevelWithDefaultBecauseNoValue(): void + { + $expected_component = 'comp_id'; + $expected_level = ILIASLogLevel::EMERGENCY; + + $repo = $this->createMock(RepositoryInterface::class); + $basic_config = $this->createMock(BasicConfigInterface::class); + + $repo + ->expects($this->once()) + ->method('getAllLevelsForComponents') + ->willReturn(array_merge(['other_component' => ILIASLogLevel::CRITICAL])); + $basic_config + ->expects($this->atLeastOnce()) + ->method('defaultLevel') + ->willReturn($expected_level); + + $config = new Config($repo, $basic_config); + $actual_level = $config->level($expected_component); + + $this->assertSame( + $expected_level, + $expected_level, + 'When there is nothing set explicitly, level should fall back to the default.' + ); + } + + public function testLevelOnlyReadOutOnce(): void + { + $repo = $this->createMock(RepositoryInterface::class); + $basic_config = $this->createStub(BasicConfigInterface::class); + + $expected_component_1 = 'comp_1'; + $expected_component_2 = 'comp_2'; + $expected_level_1 = ILIASLogLevel::ALERT; + $expected_level_2 = ILIASLogLevel::CRITICAL; + + $repo + ->expects($this->once()) + ->method('getAllLevelsForComponents') + ->willReturn([ + $expected_component_1 => $expected_level_1, + $expected_component_2 => $expected_level_2 + ]); + + $config = new Config($repo, $basic_config); + $level_1 = $config->level('comp_1'); + $level_2 = $config->level('comp_2'); + $level_1_again = $config->level('comp_1'); + + + $this->assertSame( + $level_1, + $level_1_again, + 'Repeated reads on the same component should give the same level.' + ); + $this->assertNotSame( + $level_1, + $level_2, + 'Repeated reads on the different component should give the same level.' + ); + } +} diff --git a/components/ILIAS/Logging/tests/Logger/DefaultConfigLoggerFactoryTest.php b/components/ILIAS/Logging/tests/Logger/DefaultConfigLoggerFactoryTest.php new file mode 100755 index 000000000000..58053cea5349 --- /dev/null +++ b/components/ILIAS/Logging/tests/Logger/DefaultConfigLoggerFactoryTest.php @@ -0,0 +1,64 @@ +createStub(LoggerInterface::class); + $expected_level_fectcher = $this->createStub(LevelFetcherInterface::class); + + $internal_factory = $this->createMock(LazyInternalFactoryInterface::class); + $internal_factory + ->expects($this->atLeastOnce()) + ->method('getLazyGhost') + ->with($expected_component_id, $expected_level_fectcher) + ->willReturn($expected_logger); + + $basic_config = $this->createMock(BasicConfigInterface::class); + $basic_config + ->expects($this->never()) + ->method($this->anything()); + + $level_fetcher_factory = $this->createMock(LevelFetcherFactoryInterface::class); + $level_fetcher_factory + ->expects($this->atLeastOnce()) + ->method('defaultLevelFetcher') + ->with($basic_config) + ->willReturn($expected_level_fectcher); + + $factory = new DefaultConfigLoggerFactory($internal_factory, $basic_config, $level_fetcher_factory); + $actual_logger = $factory->getLazy($expected_component_id); + + $this->assertSame( + $expected_logger, + $actual_logger, + 'This should return the logger from LazyInternalFactory' + ); + } +} diff --git a/components/ILIAS/Logging/tests/Logger/LazyInternalFactoryTest.php b/components/ILIAS/Logging/tests/Logger/LazyInternalFactoryTest.php new file mode 100755 index 000000000000..28190c9b510f --- /dev/null +++ b/components/ILIAS/Logging/tests/Logger/LazyInternalFactoryTest.php @@ -0,0 +1,156 @@ +createMock(BasicConfigInterface::class); + $monolog_factory = $this->createMock(MonologFactoryInterface::class); + $level_fetcher = $this->createMock(LevelFetcherInterface::class); + + $monolog_factory + ->expects($this->never()) + ->method($this->anything()); + $basic_config + ->expects($this->never()) + ->method($this->anything()); + $level_fetcher + ->expects($this->never()) + ->method($this->anything()); + + $lazy_factory = new LazyInternalFactory($monolog_factory, $basic_config); + $logger = $lazy_factory->getLazyGhost('name', $level_fetcher); + } + + public function testGetLazyGhostIsInitializedAfterCallWithCorrectParameters(): void + { + $expected_name = 'name'; + $expected_log_level = ILIASLogLevel::EMERGENCY; + $expected_path = '/path/to/logfile'; + + $basic_config = $this->createMock(BasicConfigInterface::class); + $monolog_factory = $this->createMock(MonologFactoryInterface::class); + $level_fetcher = $this->createMock(LevelFetcherInterface::class); + + $basic_config + ->expects($this->atLeastOnce()) + ->method('isLoggingEnabled') + ->willReturn(true); + $basic_config + ->expects($this->atLeastOnce()) + ->method('pathToLogFile') + ->willReturn($expected_path); + $monolog_factory + ->expects($this->atLeastOnce()) + ->method('logger') + ->with($expected_name, $expected_log_level, $expected_path) + ->willReturn($this->createStub(MonologLogger::class)); + $level_fetcher + ->expects($this->atLeastOnce()) + ->method('fetchLevel') + ->willReturn($expected_log_level); + + $lazy_factory = new LazyInternalFactory($monolog_factory, $basic_config); + $logger = $lazy_factory->getLazyGhost($expected_name, $level_fetcher); + // actually initialize the logger + $logger->info('test'); + } + + public function testGetLazyGhostIsCached(): void + { + $basic_config = $this->createMock(BasicConfigInterface::class); + $monolog_factory = $this->createMock(MonologFactoryInterface::class); + $level_fetcher_1 = $this->createMock(LevelFetcherInterface::class); + $level_fetcher_2 = $this->createMock(LevelFetcherInterface::class); + $level_fetcher_3 = $this->createMock(LevelFetcherInterface::class); + + $monolog_factory + ->expects($this->exactly(2)) + ->method('logger') + ->willReturn($this->createStub(MonologLogger::class)); + $basic_config + ->expects($this->atLeastOnce()) + ->method('isLoggingEnabled') + ->willReturn(true); + $level_fetcher_1 + ->expects($this->atLeastOnce()) + ->method('fetchLevel') + ->willReturn(ILIASLogLevel::INFO); + $level_fetcher_2 + ->expects($this->atLeastOnce()) + ->method('fetchLevel') + ->willReturn(ILIASLogLevel::INFO); + $level_fetcher_3 + ->expects($this->never()) + ->method($this->anything()); + + $lazy_factory = new LazyInternalFactory($monolog_factory, $basic_config); + $logger_1 = $lazy_factory->getLazyGhost('name', $level_fetcher_1); + $logger_2 = $lazy_factory->getLazyGhost('another name', $level_fetcher_2); + $logger_3 = $lazy_factory->getLazyGhost('name', $level_fetcher_3); + + // actually initialize the loggers + $logger_1->info('test'); + $logger_2->info('test'); + $logger_3->info('test'); + + $this->assertSame($logger_1, $logger_3, 'There should only be one logger per component ID.'); + $this->assertNotSame($logger_1, $logger_2, 'Loggers with different component ID should be different.'); + } + + public function testGetLazyGhostWhenLoggingIsDisabled(): void + { + $expected_name = 'name'; + + $basic_config = $this->createStub(BasicConfigInterface::class); + $monolog_factory = $this->createMock(MonologFactoryInterface::class); + $level_fetcher = $this->createMock(LevelFetcherInterface::class); + + $basic_config + ->method('isLoggingEnabled') + ->willReturn(false); + $monolog_factory + ->expects($this->atLeastOnce()) + ->method('nullLogger') + ->with($expected_name) + ->willReturn($this->createStub(MonologLogger::class)); + $monolog_factory + ->expects($this->never()) + ->method('logger'); + $level_fetcher + ->expects($this->never()) + ->method($this->anything()); + + $lazy_factory = new LazyInternalFactory($monolog_factory, $basic_config); + $logger = $lazy_factory->getLazyGhost($expected_name, $level_fetcher); + // actually initialize the logger + $logger->info('test'); + } +} diff --git a/components/ILIAS/Logging/tests/Logger/LevelFetcher/LevelFetcherFactoryTest.php b/components/ILIAS/Logging/tests/Logger/LevelFetcher/LevelFetcherFactoryTest.php new file mode 100755 index 000000000000..1118c214c6a6 --- /dev/null +++ b/components/ILIAS/Logging/tests/Logger/LevelFetcher/LevelFetcherFactoryTest.php @@ -0,0 +1,87 @@ +createMock(BasicConfigInterface::class); + $basic_config + ->expects($this->atLeastOnce()) + ->method('defaultLevel') + ->willReturn($expected_level); + + $factory = new LevelFetcherFactory(); + $fetcher = $factory->defaultLevelFetcher($basic_config); + $actual_level = $fetcher->fetchLevel(); + + $this->assertSame($expected_level, $actual_level); + } + + public function testDefaultLevelFetcherIsLazy(): void + { + $basic_config = $this->createMock(BasicConfigInterface::class); + $basic_config + ->expects($this->never()) + ->method($this->anything()); + + $factory = new LevelFetcherFactory(); + $fetcher = $factory->defaultLevelFetcher($basic_config); + } + + public function testComponentLevelFetcher(): void + { + $expected_level = ILIASLogLevel::ALERT; + $expected_component = 'comp_id'; + + $by_component_config = $this->createMock(ByComponentConfigInterface::class); + $by_component_config + ->expects($this->atLeastOnce()) + ->method('level') + ->with($expected_component) + ->willReturn($expected_level); + + $factory = new LevelFetcherFactory(); + $fetcher = $factory->componentLevelFetcher($by_component_config, $expected_component); + $actual_level = $fetcher->fetchLevel(); + + $this->assertSame($expected_level, $actual_level); + } + + public function testComponentLevelFetcherIsLazy(): void + { + $by_component_config = $this->createMock(ByComponentConfigInterface::class); + $by_component_config + ->expects($this->never()) + ->method($this->anything()); + + $factory = new LevelFetcherFactory(); + $fetcher = $factory->componentLevelFetcher($by_component_config, 'comp_id'); + } +} diff --git a/components/ILIAS/Logging/tests/Logger/LoggerFactoryTest.php b/components/ILIAS/Logging/tests/Logger/LoggerFactoryTest.php new file mode 100755 index 000000000000..a4429b3aa70a --- /dev/null +++ b/components/ILIAS/Logging/tests/Logger/LoggerFactoryTest.php @@ -0,0 +1,64 @@ +createStub(LoggerInterface::class); + $expected_component = 'comp_id'; + $expected_level_fectcher = $this->createStub(LevelFetcherInterface::class); + + $internal_factory = $this->createMock(LazyInternalFactoryInterface::class); + $internal_factory + ->expects($this->atLeastOnce()) + ->method('getLazyGhost') + ->with($expected_component, $expected_level_fectcher) + ->willReturn($expected_logger); + + $config_by_component = $this->createMock(ConfigByComponentInterface::class); + $config_by_component + ->expects($this->never()) + ->method($this->anything()); + + $level_fetcher_factory = $this->createMock(LevelFetcherFactoryInterface::class); + $level_fetcher_factory + ->expects($this->atLeastOnce()) + ->method('componentLevelFetcher') + ->with($config_by_component, $expected_component) + ->willReturn($expected_level_fectcher); + + $factory = new LoggerFactory($internal_factory, $config_by_component, $level_fetcher_factory); + $actual_logger = $factory->getLazy($expected_component); + + $this->assertSame( + $expected_logger, + $actual_logger, + 'This should return the logger from LazyInternalFactory' + ); + } +} diff --git a/components/ILIAS/Logging/tests/ilLogComponentLevelTest.php b/components/ILIAS/Logging/tests/ilLogComponentLevelTest.php deleted file mode 100755 index 5d61818f82fa..000000000000 --- a/components/ILIAS/Logging/tests/ilLogComponentLevelTest.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @ingroup ServicesCopyWizard - */ -class ilLogComponentLevelTest extends TestCase -{ - protected Container $dic; - - protected function setUp(): void - { - $this->initDependencies(); - parent::setUp(); - } - - public function testLevel(): void - { - $component_level = new ilLogComponentLevel( - 'log', - ilLogLevel::CRITICAL - ); - $this->assertEquals('log', $component_level->getComponentId()); - $this->assertEquals(ilLogLevel::CRITICAL, $component_level->getLevel()); - } - - - protected function setGlobalVariable(string $name, $value): void - { - global $DIC; - - $GLOBALS[$name] = $value; - unset($DIC[$name]); - $DIC[$name] = static function (\ILIAS\DI\Container $c) use ($value) { - return $value; - }; - } - - protected function initDependencies(): void - { - $this->dic = new Container(); - $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); - } -} diff --git a/components/ILIAS/Mail/classes/Service/MailService.php b/components/ILIAS/Mail/classes/Service/MailService.php index 44e029ffa7d7..0fb87a845c05 100755 --- a/components/ILIAS/Mail/classes/Service/MailService.php +++ b/components/ILIAS/Mail/classes/Service/MailService.php @@ -28,7 +28,6 @@ use ilMailTemplateServiceInterface; use ILIAS\Data\Factory as DataFactory; use ilMailTemplatePlaceholderResolver; -use ilMailTemplatePlaceholderToEmptyResolver; use ILIAS\Mail\Autoresponder\AutoresponderService; use ILIAS\Mail\Autoresponder\AutoresponderServiceImpl; use ILIAS\Mail\Autoresponder\AutoresponderDatabaseRepository; @@ -104,10 +103,6 @@ public static function init(Container $container): void ); }; - $container[ilMailTemplatePlaceholderToEmptyResolver::class] = static function (Container $c): ilMailTemplatePlaceholderToEmptyResolver { - return new ilMailTemplatePlaceholderToEmptyResolver(); - }; - $container['mail.template_engine.factory'] = static function (Container $c): MustacheTemplateEngineFactory { return new MustacheTemplateEngineFactory(); }; @@ -142,10 +137,6 @@ public function placeholderResolver(): ilMailTemplatePlaceholderResolver return $this->dic[ilMailTemplatePlaceholderResolver::class]; } - public function placeholderToEmptyResolver(): ilMailTemplatePlaceholderToEmptyResolver - { - return $this->dic[ilMailTemplatePlaceholderToEmptyResolver::class]; - } public function templateEngineFactory(): TemplateEngineFactoryInterface { diff --git a/components/ILIAS/Mail/classes/class.ilMail.php b/components/ILIAS/Mail/classes/class.ilMail.php index a3c04849cf89..c0ac9028415f 100755 --- a/components/ILIAS/Mail/classes/class.ilMail.php +++ b/components/ILIAS/Mail/classes/class.ilMail.php @@ -74,7 +74,6 @@ public function __construct( private ?int $mail_obj_ref_id = null, private ?ilObjUser $actor = null, private ?ilMailTemplatePlaceholderResolver $placeholder_resolver = null, - private ?ilMailTemplatePlaceholderToEmptyResolver $placeholder_to_empty_resolver = null, ?Conductor $legal_documents = null, ?MailSignatureService $signature_service = null, ) { @@ -102,7 +101,6 @@ public function __construct( $this->table_mail_saved = 'mail_saved'; $this->setSaveInSentbox(false); $this->placeholder_resolver = $placeholder_resolver ?? $DIC->mail()->placeholderResolver(); - $this->placeholder_to_empty_resolver = $placeholder_to_empty_resolver ?? $DIC->mail()->placeholderToEmptyResolver(); $this->legal_documents = $legal_documents ?? $DIC['legalDocuments']; $this->signature_service = $signature_service ?? $DIC->mail()->signature(); $this->refinery = $DIC->refinery(); @@ -616,7 +614,7 @@ private function sendInternalMail( private function replacePlaceholders( string $message, - int $usr_id = 0 + ?int $usr_id = null ): string { try { if ($this->context_id) { @@ -625,7 +623,7 @@ private function replacePlaceholders( $context = new ilMailTemplateGenericContext(); } - $user = $usr_id > 0 ? $this->getUserInstanceById($usr_id) : null; + $user = ($usr_id !== null && $usr_id > 0) ? $this->getUserInstanceById($usr_id) : null; $message = $this->placeholder_resolver->resolve( $context, $message, @@ -644,10 +642,6 @@ private function replacePlaceholders( return $message; } - private function replacePlaceholdersEmpty(string $message): string - { - return $this->placeholder_to_empty_resolver->resolve($message); - } private function distributeMail(MailDeliveryData $mail_data): bool { @@ -709,7 +703,7 @@ private function sendMailWithReplacedEmptyPlaceholder( $this->sendChanneledMails( $mail_data, $recipients, - $this->replacePlaceholdersEmpty($mail_data->getMessage()), + $this->replacePlaceholders($mail_data->getMessage()), ); } @@ -1193,7 +1187,7 @@ public function sendMail( $external_eail_recipients_bcc, $mail_data->getSubject(), $mail_data->isUsePlaceholder() ? - $this->replacePlaceholders($mail_data->getMessage(), 0) : + $this->replacePlaceholders($mail_data->getMessage()) : $mail_data->getMessage(), $mail_data->getAttachments() ); diff --git a/components/ILIAS/Mail/classes/class.ilMailTemplateContext.php b/components/ILIAS/Mail/classes/class.ilMailTemplateContext.php index 12b002411c44..1001ab0af517 100755 --- a/components/ILIAS/Mail/classes/class.ilMailTemplateContext.php +++ b/components/ILIAS/Mail/classes/class.ilMailTemplateContext.php @@ -18,8 +18,8 @@ declare(strict_types=1); -use OrgUnit\PublicApi\OrgUnitUserService; use OrgUnit\User\ilOrgUnitUser; +use OrgUnit\PublicApi\OrgUnitUserService; abstract class ilMailTemplateContext { @@ -53,7 +53,16 @@ abstract public function getTitle(): string; abstract public function getDescription(): string; /** - * @return array{mail_salutation: array{placeholder: string, label: string, supportsNestedPlaceholders?: true}, first_name: array{placeholder: string, label: string}, last_name: array{placeholder: string, label: string}, login: array{placeholder: string, label: string}, title: array{placeholder: string, label: string, supportsCondition: true}, firstname_lastname_superior: array{placeholder: string, label: string}, ilias_url: array{placeholder: string, label: string}, installation_name: array{placeholder: string, label: string}} + * @return array{ + * mail_salutation: array{placeholder: string, label: string, requiresRecipient: true, supportsNestedPlaceholders: true}, + * first_name: array{placeholder: string, label: string, requiresRecipient: true}, + * last_name: array{placeholder: string, label: string, requiresRecipient: true}, + * login: array{placeholder: string, label: string, requiresRecipient: true}, + * title: array{placeholder: string, label: string, requiresRecipient: true}, + * firstname_lastname_superior: array{placeholder: string, label: string, requiresRecipient: true}, + * ilias_url: array{placeholder: string, label: string}, + * installation_name: array{placeholder: string, label: string} + * } */ private function getGenericPlaceholders(): array { @@ -61,36 +70,43 @@ private function getGenericPlaceholders(): array 'mail_salutation' => [ 'placeholder' => 'MAIL_SALUTATION', 'label' => $this->getLanguage()->txt('mail_nacc_salutation'), + 'requiresRecipient' => true, 'supportsNestedPlaceholders' => true, ], 'first_name' => [ 'placeholder' => 'FIRST_NAME', 'label' => $this->getLanguage()->txt('firstname'), + 'requiresRecipient' => true, ], 'last_name' => [ 'placeholder' => 'LAST_NAME', 'label' => $this->getLanguage()->txt('lastname'), + 'requiresRecipient' => true, ], 'login' => [ 'placeholder' => 'LOGIN', 'label' => $this->getLanguage()->txt('mail_nacc_login'), + 'requiresRecipient' => true, ], 'title' => [ 'placeholder' => 'TITLE', 'label' => $this->getLanguage()->txt('mail_nacc_title'), - 'supportsCondition' => true, + 'requiresRecipient' => true, ], 'firstname_lastname_superior' => [ 'placeholder' => 'FIRSTNAME_LASTNAME_SUPERIOR', 'label' => $this->getLanguage()->txt('mail_firstname_last_name_superior'), + 'requiresRecipient' => true, ], 'ilias_url' => [ 'placeholder' => 'ILIAS_URL', 'label' => $this->getLanguage()->txt('mail_nacc_ilias_url'), + 'requiresRecipient' => false, ], 'installation_name' => [ 'placeholder' => 'INSTALLATION_NAME', 'label' => $this->getLanguage()->txt('mail_nacc_installation_name'), + 'requiresRecipient' => false, ], ]; } @@ -111,7 +127,12 @@ public function getNestedPlaceholders(): array } /** - * @return array + * @return array */ final public function getPlaceholders(): array { @@ -122,10 +143,62 @@ final public function getPlaceholders(): array } /** - * @return array + * @return array */ abstract public function getSpecificPlaceholders(): array; + public function requiresRecipientByPlaceholderName(string $placeholder_name): bool + { + $found = $this->findPlaceholderByMustacheName($placeholder_name); + if ($found === null) { + return false; + } + + return $this->placeholderDefinitionRequiresRecipient($found['definition']); + } + + /** + * @return array{key: string, definition: array{ + * placeholder: string, + * label: string, + * requiresRecipient?: bool, + * supportsNestedPlaceholders?: bool + * }}|null + */ + private function findPlaceholderByMustacheName(string $placeholder_name): ?array + { + foreach ($this->getPlaceholders() as $key => $placeholder_definition) { + if (strtoupper($placeholder_definition['placeholder']) !== strtoupper($placeholder_name)) { + continue; + } + + return [ + 'key' => (string) $key, + 'definition' => $placeholder_definition, + ]; + } + + return null; + } + + /** + * @param array{ + * placeholder: string, + * label: string, + * requiresRecipient?: bool, + * supportsNestedPlaceholders?: bool + * } $placeholder_definition + */ + private function placeholderDefinitionRequiresRecipient(array $placeholder_definition): bool + { + return $placeholder_definition['requiresRecipient'] ?? false; + } + /** * @param array $context_parameters */ diff --git a/components/ILIAS/Mail/classes/class.ilObjMailGUI.php b/components/ILIAS/Mail/classes/class.ilObjMailGUI.php index 20093d1c0aea..ae711061898a 100755 --- a/components/ILIAS/Mail/classes/class.ilObjMailGUI.php +++ b/components/ILIAS/Mail/classes/class.ilObjMailGUI.php @@ -448,6 +448,7 @@ protected function getExternalSettingsForm(): ilPropertyFormGUI ); $password->setRetype(false); $password->setSkipSyntaxCheck(true); + $password->setUseStripSlashes(false); $password->setDisabled(!$this->isEditingAllowed()); $password->setDisableHtmlAutoComplete(true); $smtp->addSubItem($password); diff --git a/components/ILIAS/Mail/src/TemplateEngine/MailTemplateContextAdapter.php b/components/ILIAS/Mail/src/TemplateEngine/MailTemplateContextAdapter.php index b5b32983c0a7..b280c370e77b 100644 --- a/components/ILIAS/Mail/src/TemplateEngine/MailTemplateContextAdapter.php +++ b/components/ILIAS/Mail/src/TemplateEngine/MailTemplateContextAdapter.php @@ -79,6 +79,14 @@ public function __get(string $name): string } } + if ($this->recipient === null) { + foreach ($this->contexts as $context) { + if ($context->requiresRecipientByPlaceholderName($name)) { + return $name; + } + } + } + return ''; } } diff --git a/components/ILIAS/Mail/tests/ilMailTemplatePlaceholderToEmptyResolverTest.php b/components/ILIAS/Mail/tests/ilMailTemplatePlaceholderToEmptyResolverTest.php new file mode 100644 index 000000000000..a8151ef787ca --- /dev/null +++ b/components/ILIAS/Mail/tests/ilMailTemplatePlaceholderToEmptyResolverTest.php @@ -0,0 +1,102 @@ +setValue(null, null); + + parent::tearDown(); + } + + public function testNullRecipientResolvesContextPlaceholdersAndKeepsRecipientDependentNames(): void + { + $lng = $this->createMock(ilLanguage::class); + $this->setGlobalVariable('lng', $lng); + $env_helper = $this->createMock(ilMailEnvironmentHelper::class); + $env_helper->method('getClientId')->willReturn('phpunit_client'); + $env_helper->method('getHttpPath')->willReturn('https://ilias.example/'); + + $lng_helper = $this->createMock(ilMailLanguageHelper::class); + $lng_helper->method('getCurrentLanguage')->willReturn($lng); + + $context = new class ( + new OrgUnitUserService(), + $env_helper, + new ilMailUserHelper(), + $lng_helper + ) extends ilMailTemplateContext { + public function getId(): string + { + return 'phpunit_context'; + } + + public function getTitle(): string + { + return 'phpunit'; + } + + public function getDescription(): string + { + return 'phpunit'; + } + + public function getSpecificPlaceholders(): array + { + return [ + 'course_title' => [ + 'placeholder' => 'COURSE_TITLE', + 'label' => 'Course Title', + ], + ]; + } + + public function resolveSpecificPlaceholder( + string $placeholder_id, + array $context_parameters, + ?ilObjUser $recipient = null + ): string { + if ('course_title' === $placeholder_id) { + return 'My Course'; + } + + return ''; + } + }; + + $resolver = new ilMailTemplatePlaceholderResolver(new MustacheTemplateEngine(new \Mustache\Engine())); + $message = 'Hello {{FIRST_NAME}} {{LAST_NAME}}, welcome to {{COURSE_TITLE}} at {{ILIAS_URL}}{{INSTALLATION_NAME}}'; + + $resolved = $resolver->resolve($context, $message, null, ['ref_id' => 123]); + + $this->assertStringContainsString('FIRST_NAME', $resolved); + $this->assertStringContainsString('LAST_NAME', $resolved); + $this->assertStringNotContainsString('{{FIRST_NAME}}', $resolved); + $this->assertStringNotContainsString('{{LAST_NAME}}', $resolved); + $this->assertStringContainsString('My Course', $resolved); + $this->assertStringContainsString('https://ilias.example/', $resolved); + $this->assertStringContainsString('phpunit_client', $resolved); + } +} diff --git a/components/ILIAS/Mail/tests/ilMailTest.php b/components/ILIAS/Mail/tests/ilMailTest.php index af1b17589623..80507a8b0ce1 100755 --- a/components/ILIAS/Mail/tests/ilMailTest.php +++ b/components/ILIAS/Mail/tests/ilMailTest.php @@ -691,7 +691,6 @@ private function create(int $ref_id = 234, int $usr_id = 123): ilMail $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock(), $this->getMockBuilder(ilMailTemplatePlaceholderResolver::class)->disableOriginalConstructor()->getMock(), null, - null, $this->getMockBuilder(MailSignatureService::class)->disableOriginalConstructor()->getMock(), ); diff --git a/components/ILIAS/Maps/templates/default/tpl.google_map.js b/components/ILIAS/Maps/templates/default/tpl.google_map.js index 29fff34fa9c6..c3d40ee9870a 100755 --- a/components/ILIAS/Maps/templates/default/tpl.google_map.js +++ b/components/ILIAS/Maps/templates/default/tpl.google_map.js @@ -13,27 +13,35 @@ * https://github.com/ILIAS-eLearning */ -ilMapData = Array(); -ilMap = Array(); -ilMapOptions = []; -ilCM = Array(); -ilMapUserMarker = Array(); +window.ilMapData = window.ilMapData || []; +window.ilMap = window.ilMap || []; +window.ilMapOptions = window.ilMapOptions || []; +window.ilCM = window.ilCM || []; +window.ilMapUserMarker = window.ilMapUserMarker || []; ilMapData["{MAP_ID}"] = new Array({LAT},{LONG},{ZOOM},{TYPE_CONTROL},{NAV_CONTROL},{UPDATE_LISTENER},{LARGE_CONTROL},{CENTRAL_MARKER}); ilMapUserMarker["{MAP_ID}"] = Array(); ilMapUserMarker["{UMAP_ID}"][{CNT}] = new Array({ULAT},{ULONG}, "
{USER_INFO}<\/span><\/div>"); -if (google.maps) +var ilMarkerImage = null; +if (typeof google !== "undefined" && google.maps) { - var ilMarkerImage = new google.maps.MarkerImage( - "./assets/images/standard/icon_mapm.svg", - new google.maps.Size(12, 20), - new google.maps.Point(0,0), - new google.maps.Point(6, 20)); + // Google Maps still supports legacy `google.maps.Marker`, but `google.maps.MarkerImage` + // is an older wrapper API for marker icons. Using the icon as a plain object with + // `url`, `scaledSize`, `origin`, and `anchor` passes the same marker configuration in + // the format the current marker API expects. This keeps the existing legacy marker + // behavior and custom SVG icon, while avoiding the deprecated `MarkerImage` wrapper + // that no longer rendered reliably here. + ilMarkerImage = { + url: "./assets/images/standard/icon_mapm.svg", + scaledSize: new google.maps.Size(12, 20), + origin: new google.maps.Point(0, 0), + anchor: new google.maps.Point(6, 20) + }; } -if (google.maps) +if (typeof google !== "undefined" && google.maps) { ilInitMaps(); } @@ -52,7 +60,7 @@ function ilInitMaps() for (var i=0;i { e.preventDefault(); e.stopPropagation(); diff --git a/components/ILIAS/Membership/classes/class.ilMembershipNotifications.php b/components/ILIAS/Membership/classes/class.ilMembershipNotifications.php index c77bde4656da..100be39ee1b5 100755 --- a/components/ILIAS/Membership/classes/class.ilMembershipNotifications.php +++ b/components/ILIAS/Membership/classes/class.ilMembershipNotifications.php @@ -448,9 +448,6 @@ public static function addToSettingsForm( ); $option->addSubItem($changeable); } - } elseif ($noti->isValidMode(self::MODE_ALL)) { - $option = new ilRadioOption($lng->txt("mem_force_notification_mode_all"), (string) self::MODE_ALL); - $force_noti->addOption($option); } // set current mode diff --git a/components/ILIAS/Membership/tests/ilWaitingListTest.php b/components/ILIAS/Membership/tests/ilWaitingListTest.php index c3d686dffd68..22f90feb4e13 100755 --- a/components/ILIAS/Membership/tests/ilWaitingListTest.php +++ b/components/ILIAS/Membership/tests/ilWaitingListTest.php @@ -52,8 +52,8 @@ protected function initDependencies(): void $this->dic = new Container(); $GLOBALS['DIC'] = $this->dic; - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); - $this->setGlobalVariable('ilAppEventHandler', $this->createMock(ilAppEventHandler::class)); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); + $this->setGlobalVariable('ilAppEventHandler', $this->createStub(ilAppEventHandler::class)); } protected function setGlobalVariable(string $name, $value): void diff --git a/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandler.php b/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandler.php index cd5ccae84ead..461515282559 100644 --- a/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandler.php +++ b/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandler.php @@ -26,20 +26,37 @@ use ILIAS\MetaData\Paths\PathInterface; use ILIAS\MetaData\Paths\FactoryInterface as PathFactory; use ILIAS\MetaData\Paths\Filters\FilterType; +use ILIAS\MetaData\Paths\Navigator\NavigatorFactoryInterface as NavigatorFactory; +// TODO rename to something more appropriate class IdentifierHandler implements IdentifierHandlerInterface { - protected ManipulatorInterface $manipulator; - protected PathFactory $path_factory; + protected const PLACEHOLDER_TITLE = 'PLACEHOLDER'; public function __construct( - ManipulatorInterface $manipulator, - PathFactory $path_factory + protected ManipulatorInterface $manipulator, + protected PathFactory $path_factory, + protected NavigatorFactory $navigator_factory ) { $this->manipulator = $manipulator; $this->path_factory = $path_factory; } + public function preparePlaceholderTitleIfEmpty( + SetInterface $set + ): SetInterface { + $path_to_title = $this->getPathToTitle(); + $navigator = $this->navigator_factory->navigator($path_to_title, $set->getRoot()); + if ($navigator->lastElementAtFinalStep() !== null) { + return $set; + } + return $this->manipulator->prepareCreateOrUpdate( + $set, + $path_to_title, + self::PLACEHOLDER_TITLE + ); + } + public function prepareUpdateOfIdentifier( SetInterface $set, RessourceIDInterface $ressource_id @@ -71,6 +88,16 @@ protected function generateIdentifierCatalog(): string return 'ILIAS'; } + protected function getPathToTitle(): PathInterface + { + return $this->path_factory + ->custom() + ->withNextStep('general') + ->withNextStep('title') + ->withNextStep('string') + ->get(); + } + protected function getPathToFirstIdentifierEntry(): PathInterface { return $this->path_factory diff --git a/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandlerInterface.php b/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandlerInterface.php index 4d8bbc7e96e9..eb5a3443a106 100644 --- a/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandlerInterface.php +++ b/components/ILIAS/MetaData/classes/Repository/IdentifierHandler/IdentifierHandlerInterface.php @@ -29,4 +29,8 @@ public function prepareUpdateOfIdentifier( SetInterface $set, RessourceIDInterface $ressource_id ): SetInterface; + + public function preparePlaceholderTitleIfEmpty( + SetInterface $set + ): SetInterface; } diff --git a/components/ILIAS/MetaData/classes/Repository/LOMDatabaseRepository.php b/components/ILIAS/MetaData/classes/Repository/LOMDatabaseRepository.php index b87e01ddf535..27ceb26f696f 100755 --- a/components/ILIAS/MetaData/classes/Repository/LOMDatabaseRepository.php +++ b/components/ILIAS/MetaData/classes/Repository/LOMDatabaseRepository.php @@ -116,6 +116,7 @@ public function transferMD( $this->processor->cleanMarkers($from_set); } $from_set = $this->identifier_handler->prepareUpdateOfIdentifier($from_set, $to_ressource_id); + $from_set = $this->identifier_handler->preparePlaceholderTitleIfEmpty($from_set); $this->manipulator->deleteAllMD($to_ressource_id); $this->manipulator->transferMD($from_set, $to_ressource_id); } diff --git a/components/ILIAS/MetaData/classes/Repository/Services/Services.php b/components/ILIAS/MetaData/classes/Repository/Services/Services.php index aa930f8b2690..ad2b9c721392 100755 --- a/components/ILIAS/MetaData/classes/Repository/Services/Services.php +++ b/components/ILIAS/MetaData/classes/Repository/Services/Services.php @@ -159,7 +159,8 @@ public function repository(): RepositoryInterface ), new IdentifierHandler( $this->manipulator_services->manipulator(), - $this->path_services->pathFactory() + $this->path_services->pathFactory(), + $this->path_services->navigatorFactory() ) ); } diff --git a/components/ILIAS/MetaData/tests/Copyright/CopyrightDataTest.php b/components/ILIAS/MetaData/tests/Copyright/CopyrightDataTest.php index 5d5c9e409598..1c71e54a313d 100755 --- a/components/ILIAS/MetaData/tests/Copyright/CopyrightDataTest.php +++ b/components/ILIAS/MetaData/tests/Copyright/CopyrightDataTest.php @@ -28,7 +28,7 @@ class CopyrightDataTest extends TestCase { protected function getMockURI(): URI { - return $this->createMock(URI::class); + return $this->createStub(URI::class); } protected function getData(?URI $image_link, string $image_file): CopyrightData diff --git a/components/ILIAS/MetaData/tests/Copyright/DatabaseRepositoryTest.php b/components/ILIAS/MetaData/tests/Copyright/DatabaseRepositoryTest.php index 3291ec775c4d..41fafb0c3f79 100755 --- a/components/ILIAS/MetaData/tests/Copyright/DatabaseRepositoryTest.php +++ b/components/ILIAS/MetaData/tests/Copyright/DatabaseRepositoryTest.php @@ -127,7 +127,7 @@ public function insert(string $table, array $values): void protected function getMockURI(): URI|MockObject { - return $this->createMock(URI::class); + return $this->createStub(URI::class); } protected function getRepo(WrapperInterface $wrapper): DatabaseRepository diff --git a/components/ILIAS/MetaData/tests/Copyright/RendererTest.php b/components/ILIAS/MetaData/tests/Copyright/RendererTest.php index 485d33d0871b..058cf4adefe3 100755 --- a/components/ILIAS/MetaData/tests/Copyright/RendererTest.php +++ b/components/ILIAS/MetaData/tests/Copyright/RendererTest.php @@ -124,31 +124,22 @@ public function exposeLegacyData(): array protected function getMockIcon(): MockObject|Icon { - return $this->getMockBuilder(IIcon::class) - ->disableOriginalConstructor() - ->getMock(); + return $this->createStub(IIcon::class); } protected function getMockLink(): MockObject|Link { - return $this->getMockBuilder(ILink::class) - ->disableOriginalConstructor() - ->onlyMethods(['withAdditionalRelationshipToReferencedResource']) - ->getMock(); + return $this->createStub(ILink::class); } protected function getMockLegacy(): MockObject|Content { - return $this->getMockBuilder(ILegacy::class) - ->disableOriginalConstructor() - ->getMock(); + return $this->createStub(ILegacy::class); } protected function getMockURI(string $link): URI { - $uri = $this->getMockBuilder(URI::class) - ->disableOriginalConstructor() - ->getMock(); + $uri = $this->createStub(URI::class); $uri->method('__toString')->willReturn($link); return $uri; } diff --git a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/HandlerTest.php b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/HandlerTest.php index 7f86881e57ca..24d5eb3933e1 100644 --- a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/HandlerTest.php +++ b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/HandlerTest.php @@ -37,7 +37,7 @@ class HandlerTest extends TestCase { protected function getURI(string $string): URI { - $url = $this->createMock(URI::class); + $url = $this->createStub(URI::class); $url->method('__toString')->willReturn($string); return $url; } diff --git a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/ParserTest.php b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/ParserTest.php index dcf0faf65b3d..010943242417 100644 --- a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/ParserTest.php +++ b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/ParserTest.php @@ -29,7 +29,7 @@ class ParserTest extends TestCase { protected function getURI(string $string): URI { - $url = $this->createMock(URI::class); + $url = $this->createStub(URI::class); $url->method('__toString')->willReturn($string); return $url; } diff --git a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/RequestTest.php b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/RequestTest.php index dd582c41d112..6442a7c61138 100644 --- a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/RequestTest.php +++ b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Requests/RequestTest.php @@ -29,7 +29,7 @@ class RequestTest extends TestCase { protected function getURI(): URI { - return $this->createMock(URI::class); + return $this->createStub(URI::class); } protected function getEmptyRequest(): Request diff --git a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/RequestProcessorTestCase.php b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/RequestProcessorTestCase.php index c269ebb49e3d..61110f3bc6e4 100644 --- a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/RequestProcessorTestCase.php +++ b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/RequestProcessorTestCase.php @@ -46,7 +46,7 @@ protected function getDate(string $string): \DateTimeImmutable protected function getURI(string $string): URI { - $url = $this->createMock(URI::class); + $url = $this->createStub(URI::class); $url->method('__toString')->willReturn($string); return $url; } diff --git a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/WriterTest.php b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/WriterTest.php index 48c637d306ce..a829375a2947 100644 --- a/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/WriterTest.php +++ b/components/ILIAS/MetaData/tests/OERExposer/OAIPMH/Responses/WriterTest.php @@ -32,7 +32,7 @@ class WriterTest extends TestCase { protected function getURI(string $string): URI { - $url = $this->createMock(URI::class); + $url = $this->createStub(URI::class); $url->method('__toString')->willReturn($string); return $url; } diff --git a/components/ILIAS/MetaData/tests/OERHarvester/CronJob/AutomaticPublisherTest.php b/components/ILIAS/MetaData/tests/OERHarvester/CronJob/AutomaticPublisherTest.php index 01cbd4813035..8eae5661a969 100644 --- a/components/ILIAS/MetaData/tests/OERHarvester/CronJob/AutomaticPublisherTest.php +++ b/components/ILIAS/MetaData/tests/OERHarvester/CronJob/AutomaticPublisherTest.php @@ -400,7 +400,7 @@ public function writeSimpleDCMetaData(int $obj_id, int $ref_id, string $type): \ protected function getNullLogger(): \ilLogger { - return $this->createMock(\ilLogger::class); + return $this->createStub(\ilLogger::class); } protected function getCronResultWrapper(): WrapperInterface diff --git a/components/ILIAS/MetaData/tests/OERHarvester/Publisher/PublisherTest.php b/components/ILIAS/MetaData/tests/OERHarvester/Publisher/PublisherTest.php index 67073dfbeb58..ffce7ba46f6a 100644 --- a/components/ILIAS/MetaData/tests/OERHarvester/Publisher/PublisherTest.php +++ b/components/ILIAS/MetaData/tests/OERHarvester/Publisher/PublisherTest.php @@ -255,7 +255,7 @@ public function writeSimpleDCMetaData(int $obj_id, int $ref_id, string $type): \ protected function getNullAccess(): \ilAccess { - return $this->createMock(\ilAccess::class); + return $this->createStub(\ilAccess::class); } public function testBlock(): void diff --git a/components/ILIAS/MetaData/tests/Presentation/DataTest.php b/components/ILIAS/MetaData/tests/Presentation/DataTest.php index 2519c9208146..7ebf6bb52fc3 100755 --- a/components/ILIAS/MetaData/tests/Presentation/DataTest.php +++ b/components/ILIAS/MetaData/tests/Presentation/DataTest.php @@ -69,7 +69,7 @@ public function vocabularySlot(): SlotIdentifier protected function getData(): Data { - $format = $this->createMock(DateFormat::class); + $format = $this->createStub(DateFormat::class); $format->method('applyTo')->willReturnCallback(function (\DateTimeImmutable $arg) { return $arg->format('d:m:Y'); }); diff --git a/components/ILIAS/MetaData/tests/Presentation/UtilitiesTest.php b/components/ILIAS/MetaData/tests/Presentation/UtilitiesTest.php index 692f40f83491..8c2a9c9d50c6 100755 --- a/components/ILIAS/MetaData/tests/Presentation/UtilitiesTest.php +++ b/components/ILIAS/MetaData/tests/Presentation/UtilitiesTest.php @@ -43,13 +43,13 @@ protected function setUp(): void return key_exists($arg, $map); }); - $this->format = $this->createMock(DateFormat::class); - $user = $this->createMock(\ilObjUser::class); + $this->format = $this->createStub(DateFormat::class); + $user = $this->createStub(\ilObjUser::class); $user->method('getDateFormat')->willReturn($this->format); - $refinery = $this->createMock(Refinery::class); - $encoding_group = $this->createMock(EncodeGroup::class); - $transformation = $this->createMock(Transformation::class); + $refinery = $this->createStub(Refinery::class); + $encoding_group = $this->createStub(EncodeGroup::class); + $transformation = $this->createStub(Transformation::class); $transformation->method('transform')->willReturnCallback(function ($arg) { return '~encoded:' . $arg . '~'; }); diff --git a/components/ILIAS/MetaData/tests/Repository/IdentifierHandler/IdentifierHandlerTest.php b/components/ILIAS/MetaData/tests/Repository/IdentifierHandler/IdentifierHandlerTest.php index 0d5d481b4bf9..d4d9cb37da52 100644 --- a/components/ILIAS/MetaData/tests/Repository/IdentifierHandler/IdentifierHandlerTest.php +++ b/components/ILIAS/MetaData/tests/Repository/IdentifierHandler/IdentifierHandlerTest.php @@ -32,6 +32,11 @@ use ILIAS\MetaData\Paths\NullBuilder as NullPathBuilder; use ILIAS\MetaData\Paths\Filters\FilterType; use ILIAS\MetaData\Paths\NullPath; +use ILIAS\MetaData\Paths\Navigator\NullNavigatorFactory; +use ILIAS\MetaData\Paths\Navigator\NavigatorInterface; +use ILIAS\MetaData\Elements\ElementInterface; +use ILIAS\MetaData\Paths\Navigator\NullNavigator; +use ILIAS\MetaData\Elements\NullElement; class IdentifierHandlerTest extends TestCase { @@ -69,7 +74,7 @@ public function type(): string }; } - protected function getIdentifierHandler(): IdentifierHandler + protected function getIdentifierHandler(bool $title_exists = false): IdentifierHandler { $manipulator = new class () extends NullManipulator { public function prepareCreateOrUpdate( @@ -149,7 +154,33 @@ public function custom(): PathBuilder } }; - return new class ($manipulator, $path_factory) extends IdentifierHandler { + $navigator_factory = new class ($title_exists) extends NullNavigatorFactory { + public function __construct( + protected bool $title_exists + ) { + } + + public function navigator(PathInterface $path, ElementInterface $start_element): NavigatorInterface + { + return new class ($path, $this->title_exists) extends NullNavigator { + public function __construct( + protected PathInterface $path, + protected bool $title_exists + ) { + } + + public function lastElementAtFinalStep(): ?ElementInterface + { + if ($this->title_exists && $this->path->toString() === '~start~%general%title%string') { + return new NullElement(); + } + return null; + } + }; + } + }; + + return new class ($manipulator, $path_factory, $navigator_factory) extends IdentifierHandler { protected function getInstallID(): string { return 'MockInstID'; @@ -200,4 +231,30 @@ public function testPrepareUpdateOfIdentifierForSubIDZero(): void $this->assertContains($expected_entry_changes, $prepared_changes); $this->assertContains($expected_catalog_changes, $prepared_changes); } + + public function testPreparePlaceholderTitleIfEmptyWhenNotEmpty(): void + { + $set = $this->getSet(); + $identifier_handler = $this->getIdentifierHandler(true); + + $prepared_set = $identifier_handler->preparePlaceholderTitleIfEmpty($set); + + $prepared_changes = $prepared_set->prepared_changes; + $this->assertEmpty($prepared_changes); + } + + public function testPreparePlaceholderTitleIfEmptyWhenEmpty(): void + { + $set = $this->getSet(); + $identifier_handler = $this->getIdentifierHandler(false); + + $prepared_set = $identifier_handler->preparePlaceholderTitleIfEmpty($set); + + $expected_change = [ + 'path' => '~start~%general%title%string', + 'values' => ['PLACEHOLDER'] + ]; + $prepared_changes = $prepared_set->prepared_changes; + $this->assertSame([$expected_change], $prepared_changes); + } } diff --git a/components/ILIAS/MetaData/tests/Services/CopyrightHelper/CopyrightTest.php b/components/ILIAS/MetaData/tests/Services/CopyrightHelper/CopyrightTest.php index d912de2dc928..8693a2d41dfb 100644 --- a/components/ILIAS/MetaData/tests/Services/CopyrightHelper/CopyrightTest.php +++ b/components/ILIAS/MetaData/tests/Services/CopyrightHelper/CopyrightTest.php @@ -42,16 +42,12 @@ class CopyrightTest extends TestCase { protected function getIcon(): Icon { - return $this->getMockBuilder(IIcon::class) - ->disableOriginalConstructor() - ->getMock(); + return $this->createStub(IIcon::class); } protected function getLink(): Link { - return $this->getMockBuilder(ILink::class) - ->disableOriginalConstructor() - ->getMock(); + return $this->createStub(ILink::class); } protected function getRenderer( diff --git a/components/ILIAS/MetaData/tests/XML/Copyright/CopyrightHandlerTest.php b/components/ILIAS/MetaData/tests/XML/Copyright/CopyrightHandlerTest.php index 1e92e59a645c..a5a60d42f90e 100644 --- a/components/ILIAS/MetaData/tests/XML/Copyright/CopyrightHandlerTest.php +++ b/components/ILIAS/MetaData/tests/XML/Copyright/CopyrightHandlerTest.php @@ -39,7 +39,7 @@ class CopyrightHandlerTest extends TestCase { protected function getURI(string $link): URI { - $url = $this->createMock(URI::class); + $url = $this->createStub(URI::class); $url->method('__toString')->willReturn($link); return $url; } diff --git a/components/ILIAS/MyStaff/PRIVACY.md b/components/ILIAS/MyStaff/PRIVACY.md new file mode 100644 index 000000000000..053d5c43e5ba --- /dev/null +++ b/components/ILIAS/MyStaff/PRIVACY.md @@ -0,0 +1,191 @@ +# Staff Privacy + +**Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing +or incorrect information via [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories).** + +## Integrated Components + +The **Staff** component aggregates data from various ILIAS components. Please consult the respective privacy documentation: + +- [OrgUnit](../OrgUnit/PRIVACY.md) provides information about accounts' assignment to **organisational units**, + what accounts they have authority over, and which data this authority grants access to via + the **position access** mechanism. +- [Skill](../Skill/PRIVACY.md) provides information about **achieved skill levels**, and a pre-built UI + showing that information for a given account. +- **User** handles **account identification**, provides **personal profile data** and whether a profile + is **published**, and provides a list of 'User Actions'. +- **Tree** is used together with **ILIASObject** to check the hierarchy of **organisational units**. +- **ILIASObject** is also used to retrieve **titles** of courses. +- [AccessControl](../AccessControl/PRIVACY.md) is used to check permissions to decide whether objects can be linked to. +- **Tracking** provides information about the **learning progress status** of accounts in courses. +- [Course](../Course/PRIVACY.md) together with **Membership** provides information about **enrolment status + in courses** of accounts. +- [Certificate](../Certificate/PRIVACY.md) provides information about **awarded certificates**, + and a pre-built UI showing that information for a given account. + +## General Information + +What data is shown in **Staff** depends heavily on the position access configuration +of **OrgUnit**. + +The component provides a number of reporting views to give accounts +an overview over the status of everyone they have authority over +(as defined via organisational units). This can include personal profile +data, enrolment and learning progress status in courses, +achieved skill levels, and awarded certificates. + +Note that a view by [EmployeeTalk](../EmployeeTalk/PRIVACY.md) is offered in the same main +menu entry, see that component for the related privacy information. + +## Data being stored + +The component does not store any data itself, it only aggregates +data stored elsewhere. + +## Data being presented + +The component offers different views that show different data +of all accounts that the current account has authority over via the +organisational units. + +Additionally, views that report individually on single accounts +under the authority of the current account are also available, +see [below](#account-specific-views). + +All views are only available if 'Enable Main Menu Entry' is +enabled in the **OrgUnit** settings, and if the current account +has authority over at least one account. + +### Staff List + +The Staff List presents the following **personal profile** data of +all relevant accounts: + +- **Profile Picture** +- **Login** +- All other **personal profile fields** of type 'Default' + and set to 'Searchable' in the **User** profile administration. + +Further, a selection of 'User Actions' is available, +which exposes the accounts' **user ID**. + +### Course Memberships + +'Course Memberships' is only available if the current account has the +'Manage Members' permission in courses over at least one account under +their authority, as granted by position access in the **OrgUnit** +administration. This permission can be set as a default per position, +but can also be overwritten locally in individual courses. + +The view shows a table of those **course enrolments** of accounts where +the current account has the 'Manage Members' permission over that +account in that course. Included is the following data: + +- **Title** of the course. +- **Login** of the account. +- **First Name**, **Last Name**, **E-Mail**, and **Organisational Units** + of the account, only if the corresponding **personal profile field** is + set to 'Searchable' via the **User** component. +- **Member Status** of the account in the course: 'Registered', 'Waiting List', + 'Requested' +- **Learning Progress** status of the account in the course. Only shown if + learning progress is active on the installation, and the + current account has the 'View learning progress of other users' + position permission over the account in the course. + +### Certificates + +'Certificates' is only available if certificates are activated +on the installation. Also, the current account must have the +'View certificates of other users' permission in courses, exercises, +or tests over at least one account under their authority, as granted +by position access in the **OrgUnit** administration. This permission +can be set as a default per position, but can also be overwritten locally in +individual courses, exercises, and tests. + +The view presents data related to certificates achieved by accounts in +courses, exercises, or tests. For a certificate to appear, +the current account must have the 'View certificates of other users' +permission over that account in that object. + +A table of all such **certificates** of those accounts is shown, +with the following data: + +- **Title** of the object in which the certificate was awarded. +- **Issued On:** Date on which the certificate was awarded. +- **Login** of the account to which the certificate was awarded. +- **First Name**, **Last Name**, **E-Mail**, and **Organisational Units** + of the account, only if the corresponding **personal profile field** is + set to 'Searchable' via the **User** component. + +### Competences + +'Competences' is only available if competence management is +activated on the installation. Also, the current account must have the +'View competences of other users' permission in courses, groups, surveys, +or tests over at least one account under their authority, as granted +by position access in the **OrgUnit** administration. This permission +can be set as a default per position, but can also be overwritten locally in +individual courses, groups, surveys, and tests. + +It presents data related to competences achieved by accounts +in courses, groups, surveys, or tests. For a competence to appear, +the current account must have the 'View competences of other users' +permission over that account in that object. + +A table of all such **certificates** of those accounts is shown, +with the following data: + +- **Competence:** Title of the competence. +- **Competence Level:** Title of the achieved level in the competence. +- **Login** of the account. +- **First Name**, **Last Name**, **E-Mail**, and **Organisational Units** + of the account, only if the corresponding **personal profile field** is + set to 'Searchable' via the **User** component. + +### Account-Specific Views + +All account-specific views always show the **profile picture** and the **login** +of the selected account. They also show their **first name** and +**last name**, if the account's profile is published. + +The following account-specific views are offered: + +- **Course Memberships:** Same as the [Course Memberships](#course-memberships) overview, + but without the fields **Login**, **First Name**, **Last Name**, + **E-Mail**, and **Organisational Units**. Available under the same conditions. +- **Certificates:** All certificates of the account, regardless of position + access, as presented to the user by the **Certificate** component + via 'Achievements > Certificates'. Available under the same conditions as the + [Certificates](#certificates) overview. +- **Competences:** All competences of the account, regardless of position + access, as presented to the user by the **Skill** component + via 'Achievements > Competences > Selected Competences'. + Available under the same conditions as the [Competences](#competences) overview. +- **Profile:** The profile of the account supplied by the **User** component. Only + available if the account's profile is published. + +Note that a view by [EmployeeTalk](../EmployeeTalk/PRIVACY.md) is also +offered here, see that component for the related privacy information. + +## Data being deleted + +The component does not store any data itself. Its behaviour when +deleting e.g. accounts or courses depends on the behaviour of the +related integrated component. + +## Data being exported + +Many of the tables offered in the component can be exported +in Excel or CSV format. The data being exported matches the +data shown in the UI, see [above](#data-being-presented). + +The following views contain exportable tables: + +- Staff List +- Course Membership (both the overview, and the account-specific view) +- Certificates (overview only) +- Competences (overview only) + +Additionally, in the 'Certificates' views (account-specific and +overview) the certificates awarded to accounts can be downloaded. diff --git a/components/ILIAS/News/classes/class.ilNewsForContextBlockGUI.php b/components/ILIAS/News/classes/class.ilNewsForContextBlockGUI.php index 2d698667fb70..da2d994301f9 100755 --- a/components/ILIAS/News/classes/class.ilNewsForContextBlockGUI.php +++ b/components/ILIAS/News/classes/class.ilNewsForContextBlockGUI.php @@ -70,6 +70,7 @@ public function __construct() $this->help = $DIC["ilHelp"]; $this->settings = $DIC->settings(); $this->tabs = $DIC->tabs(); + $this->logger = $DIC->logger()->news(); $locator = $DIC->news()->internal(); $this->std_request = $locator->gui()->standardRequest(); diff --git a/components/ILIAS/News/src/Data/NewsCollection.php b/components/ILIAS/News/src/Data/NewsCollection.php index 4630ce467cee..5e078ee1c63e 100644 --- a/components/ILIAS/News/src/Data/NewsCollection.php +++ b/components/ILIAS/News/src/Data/NewsCollection.php @@ -442,7 +442,7 @@ public function orderByDate(): static uasort( $ordered->news_items, - fn(NewsItem $a, NewsItem $b): int => $a->getCreationDate() <=> $b->getCreationDate() + fn(NewsItem $a, NewsItem $b): int => $b->getCreationDate() <=> $a->getCreationDate() ); return $ordered; diff --git a/components/ILIAS/Notes/Note/class.ilNoteGUI.php b/components/ILIAS/Notes/Note/class.ilNoteGUI.php index 11dbb52618a6..ec823422d266 100755 --- a/components/ILIAS/Notes/Note/class.ilNoteGUI.php +++ b/components/ILIAS/Notes/Note/class.ilNoteGUI.php @@ -1051,7 +1051,12 @@ public function updateNote(): void public function editNoteForm( bool $a_init_form = true ): string { - $this->edit_note_form = true; + $this->edit_note_form = false; + if ($this->notes_access->canEdit( + $this->manager->getById($this->requested_note_id) + )) { + $this->edit_note_form = true; + } return $this->getListHTML($a_init_form); } diff --git a/components/ILIAS/OpenIdConnect/classes/class.ilOpenIdConnectUserSync.php b/components/ILIAS/OpenIdConnect/classes/class.ilOpenIdConnectUserSync.php index 83a995d66ebf..4917129a549f 100755 --- a/components/ILIAS/OpenIdConnect/classes/class.ilOpenIdConnectUserSync.php +++ b/components/ILIAS/OpenIdConnect/classes/class.ilOpenIdConnectUserSync.php @@ -18,13 +18,12 @@ declare(strict_types=1); -use ILIAS\User\Profile\Profile; use ILIAS\Language\Language; class ilOpenIdConnectUserSync { - public const AUTH_MODE = 'oidc'; - private const UDF_STRING = 'udf_'; + public const string AUTH_MODE = 'oidc'; + private const string UDF_STRING = 'udf_'; private readonly ilLogger $logger; private readonly Language $lng; @@ -33,7 +32,7 @@ class ilOpenIdConnectUserSync private string $int_account = ''; private int $usr_id = 0; /** - * @var array|null + * @var array */ private array $user_defined_fields; @@ -255,7 +254,7 @@ private function transformToXml(): void continue 2; } - $field = $this->user_defined_fields[$id_data[1]] ?? null; + $definition = $this->user_defined_fields[$id_data[1]] ?? null; if ($definition === null) { $this->logger->warning( sprintf( @@ -269,8 +268,8 @@ private function transformToXml(): void $this->writer->xmlElement( 'UserDefinedField', [ - 'Id' => $field->getIdentifier(), - 'Name' => $field->getLabel($this->lng) + 'Id' => $definition->getIdentifier(), + 'Name' => $definition->getLabel($this->lng) ], $value ); diff --git a/components/ILIAS/OrgUnit/OrgUnit.php b/components/ILIAS/OrgUnit/OrgUnit.php index b65df02e25d1..81da6b2e9520 100644 --- a/components/ILIAS/OrgUnit/OrgUnit.php +++ b/components/ILIAS/OrgUnit/OrgUnit.php @@ -38,5 +38,7 @@ public function init( ); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "authority.js"); + $contribute[Component\Resource\PublicAsset::class] = fn() => + new Component\Resource\ComponentJS($this, "position_multi_line_input.js"); } } diff --git a/components/ILIAS/OrgUnit/classes/Positions/Authorities/class.ilOrgUnitGenericMultiInputGUI.php b/components/ILIAS/OrgUnit/classes/Positions/Authorities/class.ilOrgUnitGenericMultiInputGUI.php index 5b69a40715b5..89d2f6964c84 100755 --- a/components/ILIAS/OrgUnit/classes/Positions/Authorities/class.ilOrgUnitGenericMultiInputGUI.php +++ b/components/ILIAS/OrgUnit/classes/Positions/Authorities/class.ilOrgUnitGenericMultiInputGUI.php @@ -325,7 +325,7 @@ public function render(int|string $iterator_id = 0, bool $clean_render = false): public function initCSSandJS(): void { - $this->global_tpl->addJavascript('assets/js/generic_multi_line_input.js'); + $this->global_tpl->addJavascript('assets/js/position_multi_line_input.js'); } /** @@ -364,19 +364,9 @@ public function insert(\ilTemplate $a_tpl): void } if ($this->getMulti()) { $output = "
{$output}
"; - $config = json_encode($this->input_options); - $options = json_encode([ - 'limit' => 999999, - 'sortable' => false, - 'locale' => $this->lng->getLangKey() - ]); global $tpl; - $tpl->addOnLoadCode( - " - il.DataCollection.genericMultiLineInit('{$this->getFieldId()}',$config,$options); - document.body.querySelector('#{$this->getFieldId()}').removeAttribute('style'); - " - ); + $fieldId = $this->getFieldId(); + $tpl->addOnLoadCode("il.OrgUnit.positionMultiLineInit('{$fieldId}');"); } $a_tpl->setCurrentBlock("prop_generic"); diff --git a/components/ILIAS/OrgUnit/resources/position_multi_line_input.js b/components/ILIAS/OrgUnit/resources/position_multi_line_input.js new file mode 100644 index 000000000000..9770cfdc07d4 --- /dev/null +++ b/components/ILIAS/OrgUnit/resources/position_multi_line_input.js @@ -0,0 +1,197 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + ******************************************************************** */ + +/* global jQuery */ +window.il = window.il || {}; +window.il.OrgUnit = window.il.OrgUnit || {}; + +(function (jq) { + /** + * Multi-line form rows for OrgUnit position authorities. + * The row with #multi_line_add_button is a prototype: no remove action, only add. + */ + window.il.OrgUnit = (() => { + const EMPTY_ID = 'empty'; + const MIN_LAST_CELL_WIDTH = 150; + const WIDTH_OFFSET = 100; + + jq.fn.extend({ + positionMultiLineInit() { + const element = this; + let counter = 0; + const cloneTemplate = jq(this).find('.multi_input_line').first(); + + const isStandaloneAddLine = (line) => jq(line).find('#multi_line_add_button').length > 0; + + /** + * Authority rows only (not the standalone “add first row” prototype). + * Do not use :visible — on first paint the wrapper may still be display:none + * until the next onLoad statement runs, which would hide every nested row from :visible. + */ + const getAuthorityLines = () => jq(element) + .find('.multi_input_line') + .filter((__, el) => !isStandaloneAddLine(el)); + + const setPrototypeRemoveVisibility = (standaloneAddButton) => { + if (standaloneAddButton.length === 0) { + return; + } + const prototypeRow = standaloneAddButton.closest('.multi_input_line'); + prototypeRow.find('.remove_button').hide(); + }; + + const updatePrototypeVisibility = () => { + const standaloneAddButton = jq(element).find('#multi_line_add_button'); + if (standaloneAddButton.length > 0) { + const standaloneLine = standaloneAddButton.closest('.multi_input_line'); + if (getAuthorityLines().length === 0) { + standaloneLine.show(); + standaloneAddButton.show(); + } else { + standaloneAddButton.hide(); + standaloneLine.hide(); + } + setPrototypeRemoveVisibility(standaloneAddButton); + } + }; + + const calcWidth = (row) => { + if (row.find('.ml-input').length === 0) { + return; + } + const iconsWidth = row.find('.multi_icons_wrapper').last().width() || 0; + let sumWidths = iconsWidth; + row.find('.ml-input').each((_, inputCell) => { + sumWidths += jq(inputCell).width() || 0; + }); + const lastInputWidth = row.find('.ml-input').last().width() || 0; + const usedWidth = sumWidths - lastInputWidth; + const remainingWidth = (row.width() || 0) - usedWidth - WIDTH_OFFSET; + const lastCell = row.find('.ml-input').last(); + if (remainingWidth > MIN_LAST_CELL_WIDTH) { + lastCell.width(remainingWidth); + } else { + lastCell.css('width', ''); + } + }; + + jq(this).find('.multi_input_line').each((_, el) => { + calcWidth(jq(el)); + }); + + const setupCloneLine = (template) => { + template.hide(); + template.removeClass('multi_input_line'); + const fieldId = element.attr('id') || ''; + const nameSelector = `textarea[name^='${fieldId}'], input[name^='${fieldId}'], select[name^='${fieldId}']`; + template.find(nameSelector).each((_, inputEl) => { + const input = jq(inputEl); + const name = input.attr('name'); + const regex = new RegExp(`^${fieldId}\\[[0-9]+\\](.*)$`); + const matches = regex.exec(name); + if (!matches) { + return; + } + input.attr('name', `${EMPTY_ID}[${counter}]${matches[1]}`); + }); + }; + + setupCloneLine(cloneTemplate); + + const setupLine = (line, isInit = false) => { + const $line = line; + + jq(line).find('.add_button').on('click', () => { + const newLine = cloneTemplate.clone(); + newLine.show(); + newLine.addClass('multi_input_line'); + setupLine(newLine); + jq(element).append(newLine); + calcWidth(newLine); + jq(element).trigger('change'); + jq(document).trigger('multi_line_add_button', [$line, newLine]); + jq(element).find("textarea, input[type='text']").last().focus(); + updatePrototypeVisibility(); + return false; + }); + + jq(line).find('.remove_button').on('click', () => { + if (isStandaloneAddLine(line)) { + return false; + } + $line.remove(); + updatePrototypeVisibility(); + jq(element).trigger('change'); + jq(document).trigger('multi_line_remove_button', $line); + return false; + }); + + if (!isInit) { + const fieldId = element.attr('id') || ''; + const cloneSelector = ( + `textarea[name^='${EMPTY_ID}'], input[name^='${EMPTY_ID}'], ` + + `select[name^='${EMPTY_ID}']` + ); + $line.find(cloneSelector).each((_, inputEl) => { + const input = jq(inputEl); + const rawName = input.attr('name'); + input.val(''); + const regex = new RegExp(`^${EMPTY_ID}\\[[0-9]+\\](.*)$`); + const matches = regex.exec(rawName); + if (!matches) { + return; + } + const suffix = matches[1]; + let idx = counter; + let candidate = `${fieldId}[${idx}]${suffix}`; + const isNameTaken = (n) => jq('input, select, textarea') + .filter((__, el) => el.getAttribute('name') === n).length > 0; + while (isNameTaken(candidate)) { + idx += 1; + candidate = `${fieldId}[${idx}]${suffix}`; + } + input.attr('name', candidate); + }); + } + counter += 1; + }; + + jq(this).find('.multi_input_line').each((_, el) => { + setupLine(jq(el), true); + }); + updatePrototypeVisibility(); + jq(element).trigger('change'); + + return element; + }, + }); + + const positionMultiLineInit = (id) => { + const root = document.getElementById(id); + if (!root) { + return; + } + jq(root).positionMultiLineInit(); + // PHP outputs the wrapper hidden (display:none) until init runs; avoids a flash + // of the clone row before setupCloneLine hides it. + root.removeAttribute('style'); + }; + + return { + positionMultiLineInit, + }; + })(); +}(jQuery)); diff --git a/components/ILIAS/OrgUnit/templates/default/tpl.prop_generic_multi_line.html b/components/ILIAS/OrgUnit/templates/default/tpl.prop_generic_multi_line.html index cbf6fb83f7c5..88a7ccd5890a 100755 --- a/components/ILIAS/OrgUnit/templates/default/tpl.prop_generic_multi_line.html +++ b/components/ILIAS/OrgUnit/templates/default/tpl.prop_generic_multi_line.html @@ -25,9 +25,5 @@ {IMAGE_PLUS} {IMAGE_MINUS} - - {IMAGE_UP} - {IMAGE_DOWN} -
diff --git a/components/ILIAS/Poll/tests/PollBlockTest.php b/components/ILIAS/Poll/tests/PollBlockTest.php index fb84e11c3f60..63bdafdbf229 100755 --- a/components/ILIAS/Poll/tests/PollBlockTest.php +++ b/components/ILIAS/Poll/tests/PollBlockTest.php @@ -48,8 +48,8 @@ protected function setUp(): void $dic = new ILIAS\DI\Container(); $GLOBALS['DIC'] = $dic; - $db = $this->createMock(ilDBInterface::class); - $lng = $this->createMock(ilLanguage::class); + $db = $this->createStub(ilDBInterface::class); + $lng = $this->createStub(ilLanguage::class); $this->setGlobalVariable( "ilDB", diff --git a/components/ILIAS/Portfolio/classes/class.ilObjPortfolioBaseGUI.php b/components/ILIAS/Portfolio/classes/class.ilObjPortfolioBaseGUI.php index 05fe7fbcf62e..92a626532d2b 100755 --- a/components/ILIAS/Portfolio/classes/class.ilObjPortfolioBaseGUI.php +++ b/components/ILIAS/Portfolio/classes/class.ilObjPortfolioBaseGUI.php @@ -71,6 +71,7 @@ public function __construct( $this->lng->loadLanguageModule("prtf"); $this->lng->loadLanguageModule("user"); $this->lng->loadLanguageModule("obj"); + $this->lng->loadLanguageModule("prtt"); $this->requested_ppage = $this->port_request->getPortfolioPageId(); $this->requested_user_page = $this->port_request->getUserPage(); diff --git a/components/ILIAS/PrivacySecurity/tests/ilPrivacySettingsTest.php b/components/ILIAS/PrivacySecurity/tests/ilPrivacySettingsTest.php index ede535384ef8..cfdefd6ceff4 100755 --- a/components/ILIAS/PrivacySecurity/tests/ilPrivacySettingsTest.php +++ b/components/ILIAS/PrivacySecurity/tests/ilPrivacySettingsTest.php @@ -74,10 +74,10 @@ protected function initDependencies(): void define('SYSTEM_FOLDER_ID', 9); } - $this->setGlobalVariable('ilDB', $this->createMock(ilDBInterface::class)); - $this->setGlobalVariable('ilSetting', $this->getMockBuilder(ilSetting::class)->disableOriginalConstructor()->getMock()); - $this->setGlobalVariable('ilUser', $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock()); - $this->setGlobalVariable('ilAccess', $this->getMockBuilder(ilAccess::class)->disableOriginalConstructor()->getMock()); - $this->setGlobalVariable('rbacsystem', $this->getMockBuilder(ilRbacSystem::class)->disableOriginalConstructor()->getMock()); + $this->setGlobalVariable('ilDB', $this->createStub(ilDBInterface::class)); + $this->setGlobalVariable('ilSetting', $this->createStub(ilSetting::class)); + $this->setGlobalVariable('ilUser', $this->createStub(ilObjUser::class)); + $this->setGlobalVariable('ilAccess', $this->createStub(ilAccess::class)); + $this->setGlobalVariable('rbacsystem', $this->createStub(ilRbacSystem::class)); } } diff --git a/components/ILIAS/Questions/Legacy/Administration/ViewConfiguration.php b/components/ILIAS/Questions/Legacy/Administration/ViewConfiguration.php new file mode 100755 index 000000000000..13992e69967f --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Administration/ViewConfiguration.php @@ -0,0 +1,217 @@ +url_builder, + $this->configuration_token + ] = $url_builder->acquireParameter( + self::PARAMETER_NAMESPACE, + self::CONFIGURATION_TOKEN_STRING + ); + + $this->current_configuration = $query_wrapper->retrieve( + $this->configuration_token->getName(), + $this->refinery->custom()->transformation( + function (mixed $values): array { + $current_configuration = [ + DefaultView::getIdentifier() + ]; + if (!is_array($values)) { + return $current_configuration; + } + + $available_capabilities = [ + AsyncView::getIdentifier(), + DefaultView::getIdentifier(), + TextFeedback::getIdentifier(), + SuggestedLearningContent::getIdentifier(), + MarkingAllowingPartialPoints::getIdentifier() + ]; + + return array_reduce( + $values, + function (array $c, string $v) use ($available_capabilities): array { + if ($v === AsyncView::getIdentifier() + || $v === DefaultView::getIdentifier()) { + $c = array_filter( + $c, + fn(string $v): bool => $v !== DefaultView::getIdentifier() + && $v !== AsyncView::getIdentifier() + ); + } + + if (in_array($v, $available_capabilities) + && !in_array($v, $c)) { + $c[] = $v; + } + + return $c; + }, + $current_configuration + ); + } + ) + ); + } + + public function isAsync(): bool + { + return in_array( + AsyncView::getIdentifier(), + $this->current_configuration + ); + } + + public function getCurrentConfiguration(): array + { + return $this->current_configuration; + } + + public function getURLBuilderWithPreservedConfigurationParameter( + ?URLBuilder $url_builder = null + ): URLBuilder { + if ($url_builder !== null) { + [ + $url_builder, + $configuration_token + ] = $url_builder->acquireParameter( + self::PARAMETER_NAMESPACE, + self::CONFIGURATION_TOKEN_STRING + ); + } else { + $url_builder = $this->url_builder; + $configuration_token = $this->configuration_token; + } + + return $url_builder->withParameter( + $configuration_token, + $this->current_configuration + ); + } + + public function initializeToolbar(): void + { + $configuration_without_view = array_filter( + $this->current_configuration, + fn(string $v): bool => $v !== DefaultView::getIdentifier() && $v !== AsyncView::getIdentifier() + ); + $this->toolbar->addComponent( + $this->ui_factory->viewControl()->mode( + [ + $this->lng->txt('default_view') => $this->url_builder->withParameter( + $this->configuration_token, + [...$configuration_without_view, DefaultView::getIdentifier()] + )->buildURI()->__toString(), + $this->lng->txt('async_view') => $this->url_builder->withParameter( + $this->configuration_token, + [...$configuration_without_view, AsyncView::getIdentifier()] + )->buildURI()->__toString() + ], + $this->lng->txt('select_view') + )->withActive( + in_array(DefaultView::getIdentifier(), $this->current_configuration) + ? $this->lng->txt('default_view') + : $this->lng->txt('async_view') + ), + ); + + $this->toolbar->addComponent( + $this->buildToolbarButton( + MarkingAllowingPartialPoints::getIdentifier() + ) + ); + + $this->toolbar->addComponent( + $this->buildToolbarButton( + TextFeedback::getIdentifier() + ) + ); + + $this->toolbar->addComponent( + $this->buildToolbarButton( + SuggestedLearningContent::getIdentifier() + ) + ); + } + + private function buildToolbarButton( + string $identifier + ): StandardButton { + $capability_activated = in_array($identifier, $this->current_configuration); + $filtered_configuration = array_filter( + $this->current_configuration, + fn(string $v): bool => $v !== $identifier + ); + + return $this->ui_factory->button()->standard( + $this->buildButtonLabel($identifier, $capability_activated), + $this->url_builder->withParameter( + $this->configuration_token, + $capability_activated + ? $filtered_configuration + : [...$filtered_configuration, $identifier] + )->buildURI()->__toString() + ); + } + + private function buildButtonLabel( + string $identifier, + bool $enabled + ): string { + $identifier_lng_string = strtolower($identifier); + + return $enabled + ? $this->lng->txt("disable_{$identifier_lng_string}") + : $this->lng->txt("enable_{$identifier_lng_string}"); + } +} diff --git a/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionPreviewGUI.php b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionPreviewGUI.php new file mode 100755 index 000000000000..dd1aa73fe2b9 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionPreviewGUI.php @@ -0,0 +1,526 @@ +ctrl = $DIC['ilCtrl']; + $this->lng = $DIC['lng']; + $this->tpl = $DIC['tpl']; + $this->current_user = $DIC['user']->getLoggedInUser(); + $this->tabs_gui = $DIC['ilTabs']; + $this->toolbar = $DIC['ilToolbar']; + $this->http = $DIC['http']; + $this->ui_factory = $DIC['ui.factory']; + $this->ui_renderer = $DIC['ui.renderer']; + $this->ui_service = $DIC->uiService(); + $this->refinery = $DIC['refinery']; + $this->data_factory = new DataFactory(); + $this->uuid_factory = new UuidFactory(); + + $this->temp_attempt_repository = new AttemptRepository( + $DIC['ilDB'], + $this->uuid_factory + ); + + [ + $url_builder, + $this->action_token, + $this->row_id_token + ] = $this->getUrlBuilder()->acquireParameters( + self::PARAMETER_NAMENSPACE, + self::ACTION_TOKEN_STRING, + self::ROW_ID_TOKEN_STRING + ); + + $this->view_configuration = new ViewConfiguration( + $this->lng, + $this->refinery, + $this->ui_factory, + $this->http->wrapper()->query(), + $url_builder, + $DIC['ilToolbar'] + ); + + $this->url_builder = $this->view_configuration + ->getURLBuilderWithPreservedConfigurationParameter(); + + /** + * sk, 2026.05.06: This is done this way as this is a completely + * temporary class. It should be made as simple as possible to get rid + * of it. + */ + $local_dic = LocalDIC::dic(); + $this->repository = $local_dic[Repository::class]; + $this->answer_form_factory = $local_dic[AnswerFormFactory::class]; + $this->participant_view = $local_dic[PublicInterface::class] + ->getParticipantView( + $this->view_configuration->getCurrentConfiguration(), + $this->object_id + ); + } + + public function executeCommand(): void + { + $cmd = $this->ctrl->getCmd(); + + $table_action = $this->http->wrapper()->query()->retrieve( + $this->action_token->getName(), + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->string(), + $this->refinery->always(null) + ]) + ); + + if ($table_action !== null) { + $cmd = $table_action; + } + + if ($cmd === null || $cmd === '') { + $cmd = self::CMD_DEFAULT; + } + $cmd .= 'Cmd'; + $this->$cmd(); + } + + private function showCmd(): void + { + $this->view_configuration->initializeToolbar(); + + $filter = $this->buildFilter( + $this->ctrl->getLinkTargetByClass( + $this->getClassPath() + ) + ); + + $this->tpl->setContent( + $this->ui_renderer->render([ + $filter, + $this->ui_factory->table()->data( + $this, + $this->lng->txt('questions'), + [ + OverviewTableColumns::Title->value + => $this->ui_factory->table()->column()->link( + $this->lng->txt('title') + ), + OverviewTableColumns::AnswerFormTypes->value + => $this->ui_factory->table()->column()->text( + $this->lng->txt('contained_answer_form_types') + )->withIsOptional(true, true) + ->withIsSortable(false), + ], + )->withRange(new Range(0, 20)) + ->withFilter( + $this->ui_service->filter()->getData($filter) + )->withRequest($this->http->request()) + ]) + ); + } + + private function showQuestionCmd(): void + { + $is_async = $this->view_configuration->isAsync(); + $question_id = $this->retrieveQuestionIdFromQuery(); + $attempt = $this->temp_attempt_repository->get( + $this->current_user->getId() + ); + + if ($question_id === null) { + $this->tpl->setOnScreenMessage( + GlobalTemplate::MESSAGE_TYPE_FAILURE, + $this->lng->txt('invalid') + ); + $this->showCmd(); + } + + $this->tabs_gui->clearTargets(); + $this->tabs_gui->setBackTarget( + $this->lng->txt('back'), + $this->view_configuration->getURLBuilderWithPreservedConfigurationParameter( + $this->getUrlBuilder() + )->buildURI()->__toString() + ); + + $this->toolbar->addComponent( + $this->ui_factory->button()->standard( + $this->lng->txt('delete_responses'), + $this->view_configuration->getURLBuilderWithPreservedConfigurationParameter( + $this->getUrlBuilderWithPreservedQuestionParameter( + $question_id, + self::CMD_DELETE_RESPONSES + ) + )->buildURI()->__toString() + ) + ); + + $view = $this->participant_view->getQuestionView( + $question_id, + $attempt?->getAttemptId(), + true, + false, + $is_async ? true : false, + $is_async ? true : false + ); + + if ($attempt === null) { + $this->temp_attempt_repository->storeNew( + $this->current_user->getId(), + $view->getAttemptId() + ); + } + + $content = [ + $this->ui_factory->panel()->standard( + $this->lng->txt('question'), + $is_async + ? $view->getUI() + : $this->ui_factory->legacy()->content( + $this->buildQuestionForm($view, $question_id) + ) + ) + ]; + + if (!$is_async && $attempt?->isQuestionSolved($question_id) ?? false) { + $content[] = $this->ui_factory->panel()->standard( + $this->lng->txt('feedback'), + $this->participant_view->getQuestionView( + $question_id, + $attempt->getAttemptId(), + false, + true, + true, + true + )->getUI() + ); + } + + $this->tpl->setContent( + $this->ui_renderer->render( + $content + ) + ); + } + + private function respondCmd(): void + { + $question_id = $this->retrieveQuestionIdFromQuery(); + $attempt = $this->temp_attempt_repository->get( + $this->current_user->getId() + ); + + if ($question_id === null || $attempt === null) { + $this->tpl->setOnScreenMessage( + GlobalTemplate::MESSAGE_TYPE_FAILURE, + $this->lng->txt('invalid') + ); + $this->showCmd(); + } + + $this->participant_view->persistResponse( + $question_id, + $attempt->getAttemptId() + ); + + $this->temp_attempt_repository->storeSolved( + $attempt->withAdditionalSolvedQuestion($question_id) + ); + + $this->ctrl->redirectToURL( + $this->view_configuration->getURLBuilderWithPreservedConfigurationParameter( + $this->getUrlBuilderWithPreservedQuestionParameter( + $question_id, + self::CMD_SHOW_QUESTION + ) + )->buildURI()->__toString() + ); + } + + private function deleteResponsesCmd(): void + { + $question_id = $this->retrieveQuestionIdFromQuery(); + $attempt = $this->temp_attempt_repository->get( + $this->current_user->getId() + ); + + if ($question_id === null || $attempt === null) { + $this->tpl->setOnScreenMessage( + GlobalTemplate::MESSAGE_TYPE_FAILURE, + $this->lng->txt('invalid') + ); + $this->showCmd(); + } + + $this->participant_view->deleteResponsesFor( + $attempt->getAttemptId(), + $question_id + ); + + $this->temp_attempt_repository->storeSolved( + $attempt->withQuestionRemovedFromSolved($question_id) + ); + + $this->ctrl->redirectToURL( + $this->view_configuration->getURLBuilderWithPreservedConfigurationParameter( + $this->getUrlBuilderWithPreservedQuestionParameter( + $question_id, + self::CMD_SHOW_QUESTION + ) + )->buildURI()->__toString() + ); + } + + #[\Override] + public function getRows( + DataRowBuilder $row_builder, + array $visible_column_ids, + Range $range, + Order $order, + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): \Generator { + foreach ($this->repository->getQuestionDataOnlyForAllQuestions( + $range, + $order, + $filter_data + ) as $question) { + yield $row_builder->buildDataRow( + $question->getid()->toString(), + [ + OverviewTableColumns::Title->value => $this->ui_factory->link()->standard( + $question->getTitle(), + $this->view_configuration + ->getURLBuilderWithPreservedConfigurationParameter() + ->withParameter($this->action_token, self::CMD_SHOW_QUESTION) + ->withParameter($this->row_id_token, $question->getid()->toString()) + ->buildURI() + ->__toString() + ), + OverviewTableColumns::AnswerFormTypes->value => implode( + '
', + $question->getListOfContainedAnswerFormTypeLabels($this->lng) + ) + ] + ); + } + } + + #[\Override] + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return $this->repository->getQuestionsCount($filter_data); + } + + private function buildFilter( + string $action + ): Filter { + $filter_inputs = OverviewTableColumns::getFilterInputs( + $this->lng, + $this->ui_factory->input()->field(), + $this->answer_form_factory->getAnswerFormTypesArrayForSelect( + $this->lng + ) + ); + + $active = array_fill(0, count($filter_inputs), true); + + $filter = $this->ui_service->filter()->standard( + 'question_table_filter_id', + $action, + $filter_inputs, + $active, + true, + true + ); + + $request = $this->http->request(); + return $request->getMethod() === 'POST' + ? $filter->withRequest($request) + : $filter; + } + + private function retrieveQuestionIdFromQuery(): ?Uuid + { + return $this->http->wrapper()->query()->retrieve( + $this->row_id_token->getName(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + function (string $v): Uuid { + try { + return $this->uuid_factory->fromString($v); + } catch (Throwable $e) { + throw new ConstraintViolationException( + sprintf('The value could not be transformed into a Uuid'), + 'not_valid' + ); + } + } + ), + $this->refinery->always(null) + ]) + ); + } + + private function getUrlBuilder( + ?string $cmd = null + ): URLBuilder { + return new URLBuilder( + $this->data_factory->uri( + ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTargetByClass( + $this->getClassPath(), + $cmd + ) + ) + ); + } + + private function getUrlBuilderWithPreservedQuestionParameter( + Uuid $question_id, + string $cmd + ): URLBuilder { + [$url_builder, $row_id_parameter] = $this->getUrlBuilder($cmd) + ->acquireParameter( + self::PARAMETER_NAMENSPACE, + self::ROW_ID_TOKEN_STRING + ); + + return $url_builder->withParameter( + $row_id_parameter, + $question_id->toString() + ); + } + + private function buildQuestionForm( + QuestionParticipantView $view, + Uuid $question_id + ): string { + $tpl = new \ilTemplate( + 'tpl.qsts_preview_presentation_interactive.html', + true, + true, + 'components/ILIAS/Questions' + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_FORM_ACTION, + $this->view_configuration->getURLBuilderWithPreservedConfigurationParameter( + $this->getUrlBuilderWithPreservedQuestionParameter( + $question_id, + self::CMD_RESPOND + ) + )->buildURI() + ->__toString() + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_QUESTION_OUTPUT, + $this->ui_renderer->render($view->getUI()) + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_SUBMIT_BUTTON_LABEL, + $this->lng->txt('send') + ); + + return $tpl->get(); + } + + private function getClassPath(): array + { + return [ilObjQuestionsGUI::class, ilObjQuestionPreviewGUI::class]; + } +} diff --git a/components/ILIAS/Mail/classes/class.ilMailTemplatePlaceholderToEmptyResolver.php b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestions.php similarity index 71% rename from components/ILIAS/Mail/classes/class.ilMailTemplatePlaceholderToEmptyResolver.php rename to components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestions.php index fccd7e723113..b2cb613898d0 100755 --- a/components/ILIAS/Mail/classes/class.ilMailTemplatePlaceholderToEmptyResolver.php +++ b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestions.php @@ -18,15 +18,13 @@ declare(strict_types=1); -class ilMailTemplatePlaceholderToEmptyResolver +class ilObjQuestions extends ilObject { - public function resolve( - string $message, - ): string { - return preg_replace( - "/({{)(\w+)(}})/", - '$2', - $message - ); + public function __construct( + int $id = 0, + bool $referenced = true + ) { + $this->type = 'qsts'; + parent::__construct($id, $referenced); } } diff --git a/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsAccess.php b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsAccess.php new file mode 100755 index 000000000000..4ea07f76b5d0 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsAccess.php @@ -0,0 +1,27 @@ + + * @ingroup components\ILIASTest + */ +class ilObjQuestionsAccess extends ilObjectAccess +{ +} diff --git a/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsGUI.php b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsGUI.php new file mode 100755 index 000000000000..65ffe901b138 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Administration/class.ilObjQuestionsGUI.php @@ -0,0 +1,234 @@ +help = $DIC['ilHelp']; + $this->data_factory = new DataFactory(); + + $this->type = 'qsts'; + + parent::__construct($a_data, $a_id, $a_call_by_reference, false); + + $local_dic = LocalDIC::dic(); + $this->edit_view = $local_dic[PublicInterface::class] + ->getEditView( + [ + DefaultView::getIdentifier(), + TextFeedback::getIdentifier(), + SuggestedLearningContent::getIdentifier(), + MarkingAllowingPartialPoints::getIdentifier() + ], + $this->object->getId() + ); + $this->configuration_repository = $local_dic[ConfigurationRepository::class]; + + $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); + + if (!$this->access->checkAccess('read', '', $this->object->getRefId())) { + $this->ilias->raiseError($this->lng->txt("msg_no_perm_read_assf"), $this->ilias->error_obj->WARNING); + } + } + + public function executeCommand(): void + { + $next_class = $this->ctrl->getNextClass($this); + $cmd = $this->ctrl->getCmd(); + $this->prepareOutput(); + + switch ($next_class) { + case strtolower(ilPermissionGUI::class): + $this->tabs_gui->activateTab(self::TAB_IDENTIFIER_PERMISSIONS); + $this->ctrl->forwardCommand(new \ilPermissionGUI($this)); + break; + + case strtolower(QstsQuestionPageGUI::class): + $this->edit_view->forwardPageCmds( + $this->buildEditQuestionsBaseUri(), + $this->ref_id + ); + break; + + case strtolower(ConfigurationGUI::class): + $this->tabs_gui->activateTab(self::TAB_IDENTIFIER_SETTINGS); + $this->ctrl->forwardCommand( + new ConfigurationGUI( + $this->ctrl, + $this->http, + $this->lng, + $this->refinery, + $this->tpl, + $this->ui_factory, + $this->ui_renderer, + $this->configuration_repository + ) + ); + break; + + case strtolower(GlobalConfigurationGUI::class): + $this->tabs_gui->activateTab(self::TAB_IDENTIFIER_UNITS); + $this->ctrl->forwardCommand( + new GlobalConfigurationGUI( + $this->units_repository, + $this->lng, + $this->ctrl, + $this->rbac_system, + $this->tpl, + $this->toolbar, + $this->tabs_gui, + $this->help + ) + ); + break; + + case strtolower(ilObjQuestionPreviewGUI::class): + $this->addSubTabs(); + $this->tabs_gui->activateTab(self::TAB_IDENTIFIER_QUESTIONS); + $this->tabs_gui->activateSubTab(self::SUB_TAB_IDENTIFIER_PREVIEW_QUESTIONS); + $this->ctrl->forwardCommand( + new ilObjQuestionPreviewGUI( + $this->object->getId() + ) + ); + + break; + default: + $this->addSubTabs(); + if ($cmd === null || $cmd === '' || $cmd === 'view') { + $cmd = 'editQuestions'; + } + $cmd .= 'Cmd'; + $this->$cmd(); + break; + } + } + + private function editQuestionsCmd(): void + { + $this->tabs_gui->activateTab(self::TAB_IDENTIFIER_QUESTIONS); + $this->tabs_gui->activateSubTab(self::SUB_TAB_IDENTIFIER_EDIT_QUESTIONS); + + $this->tpl->setContent( + $this->ui_renderer->render( + $this->edit_view->getUI( + $this->buildEditQuestionsBaseUri(), + $this->object->getRefId() + ) + ) + ); + } + + public function getAdminTabs(): void + { + $this->addTabs(); + } + + protected function addTabs(): void + { + if ($this->rbac_system->checkAccess('read', $this->object->getRefId())) { + $this->tabs_gui->addTab( + self::TAB_IDENTIFIER_QUESTIONS, + $this->lng->txt(self::TAB_IDENTIFIER_QUESTIONS), + $this->ctrl->getLinkTargetByClass(self::class, 'editQuestions') + ); + + $this->tabs_gui->addTab( + self::TAB_IDENTIFIER_SETTINGS, + $this->lng->txt(self::TAB_IDENTIFIER_SETTINGS), + $this->ctrl->getLinkTargetByClass(ConfigurationGUI::class, ''), + ); + } + + if ($this->rbac_system->checkAccess('edit_permission', $this->object->getRefId())) { + $this->tabs_gui->addTab( + self::TAB_IDENTIFIER_PERMISSIONS, + $this->lng->txt(self::TAB_IDENTIFIER_PERMISSIONS), + $this->ctrl->getLinkTargetByClass([self::class, ilPermissionGUI::class], 'perm'), + ); + } + } + + private function addSubTabs(): void + { + if (!$this->rbac_system->checkAccess('read', $this->object->getRefId())) { + return; + } + + $this->tabs_gui->addSubTab( + self::SUB_TAB_IDENTIFIER_EDIT_QUESTIONS, + $this->lng->txt('edit'), + $this->ctrl->getLinkTargetByClass(self::class, 'editQuestions') + ); + + $this->tabs_gui->addSubTab( + self::SUB_TAB_IDENTIFIER_PREVIEW_QUESTIONS, + $this->lng->txt('preview'), + $this->ctrl->getLinkTargetByClass([self::class, ilObjQuestionPreviewGUI::class]) + ); + } + + private function buildEditQuestionsBaseUri(): URI + { + return $this->data_factory->uri( + ILIAS_HTTP_PATH . '/' . $this->ctrl->getFormActionByClass(self::class, 'editQuestions') + ); + } +} diff --git a/components/ILIAS/Questions/Legacy/LocalDIC.php b/components/ILIAS/Questions/Legacy/LocalDIC.php new file mode 100755 index 000000000000..52836d70a14d --- /dev/null +++ b/components/ILIAS/Questions/Legacy/LocalDIC.php @@ -0,0 +1,294 @@ + new DataFactory(); + $dic[UuidFactory::class] = static fn($c): UuidFactory => new UuidFactory(); + $dic[MustacheEngine::class] = static fn($c): MustacheEngine + => new MustacheEngine(['escape' => static fn($v) => $v]); + $dic[\ilFileServicesFilenameSanitizer::class] = static fn($c): \ilFileServicesFilenameSanitizer + => new \ilFileServicesFilenameSanitizer( + $DIC->fileServiceSettings() + ); + + $dic[PublicInterface::class] = static fn($c): PublicInterface + => new DefaultPublicInterface( + $DIC['lng'], + $DIC['user']->getLoggedInUser(), + $DIC['refinery'], + $DIC['ui.factory'], + $DIC['ui.renderer'], + $DIC['global_screen'], + $DIC['tpl'], + $DIC->contentStyle(), + $DIC['ilCtrl'], + $DIC['http'], + $DIC['ilTabs'], + $DIC->uiService(), + $c[UuidFactory::class], + $c[ConfigurationRepository::class], + $c[AnswerFormFactory::class], + $c[QuestionsRepository::class], + $c[AttemptRepository::class], + $c[LayoutFactory::class], + $c[Capabilities\Factory::class] + ); + + $dic[ConfigurationRepository::class] = static fn($c): ConfigurationRepository + => new ConfigurationRepository( + $DIC['ilSetting'], + $DIC['user']->getSettings()->getSettingByDefinitionClass( + CreateMode::class + ), + new \ilSetting('questions') + ); + $dic[PersistenceFactory::class] = static fn($c): PersistenceFactory + => new PersistenceFactory(); + $dic[QuestionTableDefinitions::class] = static fn($c): QuestionTableDefinitions + => new QuestionTableDefinitions( + $c[PersistenceFactory::class] + ); + $dic[AnswerFormGenericTableDefinitions::class] = static fn($c): AnswerFormGenericTableDefinitions + => new AnswerFormGenericTableDefinitions( + $c[PersistenceFactory::class] + ); + $dic[DatabaseStatementBuilder::class] = static fn($c): DatabaseStatementBuilder + => new DatabaseStatementBuilder( + $c[PersistenceFactory::class], + $c[QuestionTableDefinitions::class], + $c[AnswerFormGenericTableDefinitions::class] + ); + $dic[AttemptTableDefinitions::class] = static fn($c): AttemptTableDefinitions + => new AttemptTableDefinitions( + $c[PersistenceFactory::class] + ); + $dic[AttemptRepository::class] = static fn($c): AttemptRepository + => new AttemptRepository( + $DIC['ilDB'], + $DIC['refinery'], + $c[UuidFactory::class], + $c[PersistenceFactory::class], + $c[AttemptTableDefinitions::class] + ); + $dic[Capabilities\Factory::class] = static fn($c): Capabilities\Factory + => new Capabilities\Factory([ + new Capabilities\TextFeedback\Capability( + $c[DataFactory::class]->text(), + new Capabilities\TextFeedback\Repository( + $DIC['ilDB'], + $DIC['refinery'], + $c[UuidFactory::class], + $c[DataFactory::class]->text(), + $c[PersistenceFactory::class], + new Capabilities\TextFeedback\TableDefinitions( + $c[PersistenceFactory::class] + ) + ) + ), + new Capabilities\SuggestedLearningContent\Capability( + $DIC['ilCtrl'], + $DIC['rbacsystem'], + $DIC['tree'], + $DIC['static_url'], + $DIC['user']->getLoggedInUser(), + new Capabilities\SuggestedLearningContent\Repository( + $DIC['ilDB'], + $DIC['refinery'], + $DIC['resource_storage'], + $c[PersistenceFactory::class], + new Capabilities\SuggestedLearningContent\TableDefinitions( + $c[PersistenceFactory::class] + ) + ) + ), + new Capabilities\MarkingAllowingPartialPoints\Capability(), + new Capabilities\DefaultView\Capability(), + new Capabilities\AsyncView\Capability() + ]); + $dic[AnswerFormFactory::class] = static fn($c): AnswerFormFactory + => new AnswerFormFactory( + $c[UuidFactory::class], + [ + $c[Cloze\Definition::class] + ] + ); + $dic[QuestionsRepository::class] = static fn($c): QuestionsRepository + => new QuestionsRepository( + $DIC['ilDB'], + $DIC['refinery'], + $c[UuidFactory::class], + $c[DatabaseStatementBuilder::class], + $c[PersistenceFactory::class], + $c[QuestionTableDefinitions::class], + $c[AnswerFormGenericTableDefinitions::class], + $c[AnswerFormFactory::class] + ); + $dic[LayoutFactory::class] = static fn($c): LayoutFactory => + new LayoutFactory( + $DIC['ui.factory'], + $DIC['http'], + $DIC['lng'], + $DIC['resource_storage'], + $DIC['filesystem']->temp(), + $DIC['upload'], + $c[\ilFileServicesFilenameSanitizer::class] + ); + $dic[Cloze\Properties\ClozeText\Factory::class] = static fn($c): Cloze\Properties\ClozeText\Factory + => new Cloze\Properties\ClozeText\Factory( + $DIC['refinery'], + $c[MustacheEngine::class], + $c[DataFactory::class]->text() + ); + $dic[Cloze\Properties\Gaps\AnswerOptions\Factory::class] = static fn($c): Cloze\Properties\Gaps\AnswerOptions\Factory + => new Cloze\Properties\Gaps\AnswerOptions\Factory( + $c[UuidFactory::class], + $DIC['refinery'] + ); + $dic[Cloze\Properties\Gaps\Factory::class] = static fn($c): Cloze\Properties\Gaps\Factory + => new Cloze\Properties\Gaps\Factory( + $DIC['refinery'], + $c[UuidFactory::class], + $c[Cloze\Properties\Gaps\AnswerOptions\Factory::class], + [ + new Cloze\Properties\Gaps\Text( + $DIC['lng'], + $DIC['refinery'] + ), + new Cloze\Properties\Gaps\Numeric( + $DIC['lng'], + $DIC['refinery'] + ), + new Cloze\Properties\Gaps\Select( + $DIC['lng'], + $DIC['refinery'] + ), + new Cloze\Properties\Gaps\LongMenu( + $DIC['lng'], + $DIC['refinery'], + $DIC['tpl'] + ) + ] + ); + $dic[Cloze\TableDefinitions::class] = static fn($c): Cloze\TableDefinitions + => new Cloze\TableDefinitions( + $c[PersistenceFactory::class], + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ); + $dic[Cloze\Properties\Factory::class] = static fn($c): Cloze\Properties\Factory + => new Cloze\Properties\Factory( + $c[PersistenceFactory::class], + $c[Cloze\Properties\ClozeText\Factory::class], + $c[Cloze\Properties\Gaps\Factory::class], + $c[Cloze\Properties\Combinations\Factory::class] + ); + $dic[Cloze\Response\Factory::class] = static fn($c): Cloze\Response\Factory + => new Cloze\Response\Factory( + $c[UuidFactory::class], + $c[PersistenceFactory::class] + ); + $dic[Cloze\Properties\Gaps\Edit::class] = static fn($c): Cloze\Properties\Gaps\Edit + => new Cloze\Properties\Gaps\Edit( + $DIC['upload'], + $c[Cloze\Properties\Factory::class], + $c[Cloze\Properties\Gaps\Factory::class] + ); + $dic[Cloze\Views\Edit::class] = static fn($c): Cloze\Views\Edit + => new Cloze\Views\Edit( + $c[Cloze\Properties\Factory::class], + $c[Cloze\Properties\ClozeText\Factory::class], + $c[Cloze\Properties\Gaps\Edit::class] + ); + $dic[Cloze\Definition::class] = static fn($c): Cloze\Definition => new Cloze\Definition( + $c[Cloze\TableDefinitions::class], + [ + new Cloze\Capabilities\TextFeedback( + $c[UuidFactory::class], + $c[DataFactory::class]->text() + ), + new Cloze\Capabilities\MarkingAllowingPartialPoints( + $c[Cloze\Properties\Factory::class], + $c[Cloze\Response\Factory::class] + ), + new Cloze\Capabilities\DefaultView( + $c[MustacheEngine::class], + $c[Cloze\Response\Factory::class] + ), + new Cloze\Capabilities\AsyncView( + $DIC['ui.renderer'], + $c[MustacheEngine::class], + $c[Cloze\Response\Factory::class] + ) + ], + $c[Cloze\Properties\Factory::class], + $c[Cloze\Response\Factory::class], + $c[Cloze\Views\Edit::class] + ); + $dic[Cloze\Properties\Combinations\Factory::class] = static fn($c): Cloze\Properties\Combinations\Factory + => new Cloze\Properties\Combinations\Factory( + $c[UuidFactory::class], + $c[PersistenceFactory::class], + $c[Cloze\TableDefinitions::class] + ); + + return $dic; + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPage.php b/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPage.php new file mode 100644 index 000000000000..c8abce9710bb --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPage.php @@ -0,0 +1,191 @@ +uuid_factory = new UuidFactory(); + } + + #[\Override] + public function getParentType(): string + { + return 'qsts'; + } + + public function getEditView(): Edit + { + return $this->edit_view; + } + + public function setEditView( + Edit $edit_view + ): void { + $this->edit_view = $edit_view; + } + + public function getQuestion(): Question + { + return $this->question; + } + + public function setQuestion( + Question $question + ): void { + $this->question = $question; + } + + public function getParticipantView(): Viewable + { + return $this->participant_view; + } + + public function setParticipantView( + Viewable $participant_view + ): void { + $this->participant_view = $participant_view; + } + + public function getAttemptData(): ?Attempt + { + return $this->attempt_data; + } + + public function setAttemptData( + ?Attempt $attempt_data + ): void { + $this->attempt_data = $attempt_data; + } + + public function getRequiredCapabilities(): ?RequiredCapabilities + { + return $this->required_capabilites; + } + + public function setRequiredCapabilities( + RequiredCapabilities $required_capabilities + ): void { + $this->required_capabilites = $required_capabilities; + } + + public function getViewConfiguration(): ?ViewConfiguration + { + return $this->view_configuration; + } + + public function setViewConfiguration( + ViewConfiguration $view_configuration + ): void { + $this->view_configuration = $view_configuration; + } + + #[\Override] + public function pasteContents( + string $page_content_id, + bool $a_self_ass = false + ): array|bool { + $answer_form_element = $this->page_manager + ->content($this->getDomDoc()) + ->getContentDomNode(...explode(':', $page_content_id)) + ?->getElementsByTagName(ilPCAnswerForm::ANSWER_FORM_ELEMENT_TAG); + + if ($answer_form_element?->length > 0) { + foreach ($answer_form_element->getIterator() as $node) { + self::$answer_form_mapping[$node->getAttribute(ilPCAnswerForm::ANSWER_FORM_ID_ATTRIBUTE)] + = $this->uuid_factory->uuid4AsString(); + } + } + + return parent::pasteContents($page_content_id, $a_self_ass); + } + + #[\Override] + public function cutContents( + array $page_content_ids + ): array|bool { + return parent::cutContents( + array_filter( + $page_content_ids, + fn(string $v): bool => $this->page_manager + ->content($this->getDomDoc()) + ->getContentDomNode(...explode(':', $v)) + ?->getElementsByTagName('AnswerForm') + ?->length < 1 + ) + ); + } + + /** + * 2026-06-30, sk:This is awfull, but as there are statics used in the copy + * process this is the only way I found to do this. If somebody has a better + * idea... + * + * @return array|null + */ + public static function getAnswerFormMapping(): array + { + return self::$answer_form_mapping; + } + + public static function setAnswerFormMapping( + array $answer_form_mapping + ): void { + self::$answer_form_mapping = $answer_form_mapping; + } + + public function addQuestionText( + string $text + ): void { + $this->buildDom(); + + $lng = $this->user->getLanguage(); + if ($lng === '') { + $lng = 'de'; + } + + $page_element = new \ilPCParagraph($this); + $page_element->create($this, 'pg'); + $page_element->setLanguage($lng); + $page_element->setText($text); + + $this->update(); + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPageConfig.php b/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPageConfig.php new file mode 100644 index 000000000000..5a671e51ae45 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/QstsQuestionPageConfig.php @@ -0,0 +1,31 @@ +setEnablePCType('Tabs', true); + $this->setEnablePCType('AnswerForm', true); + $this->setEnablePCType('LegacyAnswerFormText', true); + $this->setEnableInternalLinks(false); + $this->setEnablePageToc(true); + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/class.QstsQuestionPageGUI.php b/components/ILIAS/Questions/Legacy/PageEditor/class.QstsQuestionPageGUI.php new file mode 100644 index 000000000000..31746c812b8a --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/class.QstsQuestionPageGUI.php @@ -0,0 +1,92 @@ +getPageId()); + + $this->setEnabledPageFocus(false); + + $this->obj->setQuestion($question); + $this->obj->setParentId($obj_id); + $this->obj->setRequiredCapabilities($required_capabilities); + $this->obj->setViewConfiguration($view_configuration); + } + + #[\Override] + public function finishEditing(): void + { + $this->ctrl->redirectToURL($this->return_uri->__toString()); + } + + public function withEditView( + Edit $edit_view + ): self { + $clone = clone $this; + $clone->obj->setEditView($edit_view); + return $clone; + } + + public function withParticipantView( + Viewable $participant_view + ): self { + $clone = clone $this; + $clone->obj->setParticipantView($participant_view); + return $clone; + } + + public function withAttemptData( + ?Attempt $attempt + ): self { + $clone = clone $this; + $clone->obj->setAttemptData($attempt); + return $clone; + } + + public function withReturnUri( + URI $return_uri + ): self { + $clone = clone $this; + $clone->return_uri = $return_uri; + return $clone; + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerForm.php b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerForm.php new file mode 100644 index 000000000000..70ed2a3181b1 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerForm.php @@ -0,0 +1,233 @@ +setType('answf'); + } + + #[\Override] + public static function getLangVars(): array + { + return ['ed_insert_pcqst', 'empty_question', 'pc_qst']; + } + + #[\Override] + public function modifyPageContentPostXsl( + string $output, + string $mode, + bool $abstract_only = false + ): string { + if ($this->pg_obj::class !== QstsQuestionPage::class) { + return $output; + } + + global $DIC; + $global_tpl = $DIC['tpl']; + $lng = $DIC['lng']; + $ui_factory = $DIC['ui.factory']; + $ui_renderer = $DIC['ui.renderer']; + $refinery = $DIC['refinery']; + + return mb_ereg_replace_callback( + self::ANSWER_FORM_PLACEHOLDER, + fn(array $matches): string => $this->renderAnswerForm( + $global_tpl, + $lng, + $ui_factory, + $ui_renderer, + $refinery, + $this->pg_obj->getQuestion()->getAnswerFormPropertiesByIdString($matches[1]), + $this->pg_obj->getAttemptData() + ), + $output + ); + } + + #[\Override] + public static function afterPageUpdate( + ilPageObject $page, + DOMDocument $domdoc, + string $xml, + bool $creation + ): void { + if ($page::class !== QstsQuestionPage::class || $creation) { + return; + } + + global $DIC; + $dom_util = $DIC->copage()->internal()->domain()->domUtil(); + /** @var Repository $question_repository */ + $question_repository = LocalDIC::dic()[Repository::class]; + + $uuid_factory = new UuidFactory(); + + /** @var \ILIAS\Questions\Question\Question $question */ + $question = $page->getQuestion(); + + $answer_form_mapping = \QstsQuestionPage::getAnswerFormMapping(); + \QstsQuestionPage::setAnswerFormMapping([]); + + $answer_forms = []; + foreach ($dom_util->path($domdoc, '//AnswerForm') as $node) { + $answer_form_id = $node->getAttribute(self::ANSWER_FORM_ID_ATTRIBUTE); + $answer_form = $question->getAnswerFormPropertiesByIdString($answer_form_id); + + if ($answer_form === null && in_array($answer_form_id, $answer_form_mapping)) { + $old_answer_form_id = array_search($answer_form_id, $answer_form_mapping); + $old_answer_form = $question->getAnswerFormPropertiesByIdString( + $old_answer_form_id + ); + + if ($old_answer_form === null) { + $old_answer_form_uuid = $uuid_factory->fromString($answer_form_id); + $old_answer_form = $question_repository->getQuestionForAnswerFormId( + $old_answer_form_uuid + )->getAnswerFormPropertiesByIdString( + $old_answer_form_uuid + ); + } + + $question = $question->withAnswerFormProperties( + $old_answer_form->clone( + $uuid_factory, + [ + 'new_question_id' => $question->getId(), + 'answer_form_id' => $uuid_factory->fromString( + $answer_form_id + ) + ] + ) + ); + } + + $answer_forms[] = $answer_form_id; + } + + $page->setQuestion($question->withoutDeletedAnswerForms($answer_forms)); + + $question_repository->update( + [$page->getQuestion()] + ); + } + + #[\Override] + public static function handleCopiedContent( + DOMDocument $domdoc, + bool $self_ass = true, + bool $clone_mobs = false, + int $new_parent_id = 0, + int $obj_copy_id = 0 + ): void { + global $DIC; + $dom_util = $DIC->copage()->internal()->domain()->domUtil(); + + $answer_form_mapping = \QstsQuestionPage::getAnswerFormMapping(); + if ($answer_form_mapping === []) { + return; + } + + foreach ($dom_util->path($domdoc, '//AnswerForm') as $node) { + $old_answer_form_id = $node->getAttribute(self::ANSWER_FORM_ID_ATTRIBUTE); + if (isset($answer_form_mapping[$old_answer_form_id])) { + $node->setAttribute( + self::ANSWER_FORM_ID_ATTRIBUTE, + $answer_form_mapping[$old_answer_form_id] + ); + } + } + } + + public function create( + Uuid $answer_form_id + ): void { + $this->createInitialChildNode( + $this->hier_id, + '', + self::ANSWER_FORM_ELEMENT_TAG, + [self::ANSWER_FORM_ID_ATTRIBUTE => $answer_form_id->toString()] + ); + } + + public function getAnswerFormIdStringFromAttribute(): string + { + return $this->getChildNode()->attributes + ->getNamedItem(self::ANSWER_FORM_ID_ATTRIBUTE)->nodeValue; + } + + private function renderAnswerForm( + GlobalTemplate $global_tpl, + Language $lng, + UIFactory $ui_factory, + UIRenderer $ui_renderer, + Refinery $refinery, + ?AnswerFormProperties $answer_form_properties, + ?Attempt $attempt_data + ): string { + if ($answer_form_properties === null) { + return $lng->txt('broken_answer_form'); + } + + /** @var RequiredCapabilities $required_capabilities */ + $required_capabilities = $this->pg_obj->getRequiredCapabilities(); + + $answer_form_response = $attempt_data?->getResponseForQuestion( + $answer_form_properties->getQuestionId() + )?->getAnswerFormResponse( + $answer_form_properties->getAnswerFormId() + ); + + return $ui_renderer->render( + $required_capabilities + ->getParticipantViewProvider() + ->getParticipantView($answer_form_properties) + ->show( + $global_tpl, + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $this->pg_obj->getViewConfiguration(), + $answer_form_properties, + $attempt_data, + $answer_form_response + ) + ); + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerFormGUI.php b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerFormGUI.php new file mode 100644 index 000000000000..4edb44721193 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCAnswerFormGUI.php @@ -0,0 +1,95 @@ +tabs = $DIC['ilTabs']; + $this->ui_renderer = $DIC['ui.renderer']; + $this->data_factory = new DataFactory(); + + $this->edit_view = $pg_obj->getEditView(); + + parent::__construct($pg_obj, $content_obj, $hier_id, $pc_id); + } + + public function executeCommand() + { + $cmd = $this->ctrl->getCmd() . 'Cmd'; + $this->$cmd(); + } + + public function insertCmd(): void + { + $content_obj = new ilPCAnswerForm($this->pg_obj); + $content_obj->setHierId($this->hier_id); + $this->tpl->setContent( + $this->ui_renderer->render( + $this->edit_view->getCreateAnswerForm( + $this->data_factory->uri( + ILIAS_HTTP_PATH . '/' . $this->ctrl->getFormActionByClass(self::class, 'insert') + ), + $this->pg_obj->getQuestion(), + $content_obj + ) + ) + ); + } + + public function editCmd(): void + { + /** @var \ILIAS\Questions\Question\Question $question */ + $question = $this->pg_obj->getQuestion(); + $answer_form_properties = $question->getAnswerFormPropertiesByIdString( + $this->getContentObject()->getAnswerFormIdStringFromAttribute() + ); + + $this->tpl->setContent( + $this->ui_renderer->render( + $this->edit_view->getEditAnswerForm( + $this->data_factory->uri( + ILIAS_HTTP_PATH . '/' . $this->ctrl->getFormActionByClass(self::class, 'edit') + ), + $question, + $answer_form_properties, + $answer_form_properties->getDefinition() + ) + ) + ); + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormText.php b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormText.php new file mode 100644 index 000000000000..a5fdabc3cbfb --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormText.php @@ -0,0 +1,61 @@ +setType('laft'); + } + + #[\Override] + public function modifyPageContentPostXsl( + string $output, + string $mode, + bool $abstract_only = false + ): string { + if ($this->pg_obj::class !== QstsQuestionPage::class) { + return $output; + } + + return mb_ereg_replace_callback( + self::TEXT_PLACEHOLDER, + static fn(array $matches): string => \ilRTE::_replaceMediaObjectImageSrc( + base64_decode($matches[1]) + ), + $output + ); + } + + public function create( + string $legacy_answer_form_text + ): void { + $this->createInitialChildNode( + $this->hier_id, + '', + self::ELEMENT_TAG, + [self::TEXT_ATTRIBUTE => $legacy_answer_form_text] + ); + } +} diff --git a/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormTextGUI.php b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormTextGUI.php new file mode 100644 index 000000000000..ba24c634cdc7 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/PageEditor/class.ilPCLegacyAnswerFormTextGUI.php @@ -0,0 +1,33 @@ +tpl->setOnScreenMessage(MessageBox::FAILURE, $this->lng->txt('legacy_text_cannot_be_edited'), true); + $this->ctrl->redirectByClass(\QstsQuestionPageGUI::class, 'edit'); + } +} diff --git a/components/ILIAS/Questions/Legacy/Temp/Attempt.php b/components/ILIAS/Questions/Legacy/Temp/Attempt.php new file mode 100644 index 000000000000..0c705fd68274 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Temp/Attempt.php @@ -0,0 +1,74 @@ +attempt_id; + } + + public function isQuestionSolved( + Uuid $question_id + ): bool { + return in_array($question_id->toString(), $this->solved_questions); + } + + public function getSolvedQuestionsForStorage(): string + { + return implode(',', $this->solved_questions); + } + + public function withAdditionalSolvedQuestion( + Uuid $question_id + ): self { + if ($this->isQuestionSolved($question_id)) { + return $this; + } + + $clone = clone $this; + $clone->solved_questions[] = $question_id->toString(); + return $clone; + } + + public function withQuestionRemovedFromSolved( + Uuid $question_id + ): self { + if (!$this->isQuestionSolved($question_id)) { + return $this; + } + + $clone = clone $this; + unset( + $clone->solved_questions[array_search($question_id->toString(), $clone->solved_questions)] + ); + return $clone; + } +} diff --git a/components/ILIAS/Questions/Legacy/Temp/AttemptRepository.php b/components/ILIAS/Questions/Legacy/Temp/AttemptRepository.php new file mode 100644 index 000000000000..31a59b4fe920 --- /dev/null +++ b/components/ILIAS/Questions/Legacy/Temp/AttemptRepository.php @@ -0,0 +1,86 @@ +db->fetchObject( + $this->db->queryF( + 'SELECT attempt_id, solved_questions from ' . self::TABLE_NAME . ' WHERE user_id = %s', + [FieldDefinition::T_INTEGER], + [$user_id] + ) + ); + + if ($value === null) { + return null; + } + + return new Attempt( + $this->uuid_factory->fromString($value->attempt_id), + $value->solved_questions === '' + ? [] + : explode(',', $value->solved_questions) + ); + } + + public function storeNew( + int $user_id, + Uuid $attempt_id + ): void { + $this->db->insert( + self::TABLE_NAME, + [ + 'user_id' => [FieldDefinition::T_INTEGER, $user_id], + 'attempt_id' => [FieldDefinition::T_TEXT, $attempt_id->toString()] + ] + ); + } + + public function storeSolved( + Attempt $attempt + ): void { + $this->db->update( + self::TABLE_NAME, + [ + 'solved_questions' => [FieldDefinition::T_TEXT, $attempt->getSolvedQuestionsForStorage()] + ], + [ + 'attempt_id' => [FieldDefinition::T_TEXT, $attempt->getAttemptId()->toString()] + ] + ); + } +} diff --git a/components/ILIAS/Questions/Questions.php b/components/ILIAS/Questions/Questions.php new file mode 100644 index 000000000000..01c8fae14235 --- /dev/null +++ b/components/ILIAS/Questions/Questions.php @@ -0,0 +1,133 @@ + new PersistenceFactory(); + $internal[\EvalMath::class] = static fn() => new \EvalMath(); + + $contribute[AgentInterface::class] = static fn() => + new Agent( + $internal[PersistenceFactory::class], + new TableNameBuilder( + QuestionRepository::COMPONENT_NAMESPACE, + null + ), + $seek[AnswerFormMigration::class], + $seek[CapabilityMigration::class] + ); + $contribute[AnswerFormMigration::class] = static fn() + => new MigrationCloze( + new ClozeTableDefinitions( + $internal[PersistenceFactory::class], + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ), + $internal[\EvalMath::class] + ); + $contribute[AnswerFormMigration::class] = static fn() + => new MigrationLongMenu( + new ClozeTableDefinitions( + $internal[PersistenceFactory::class], + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ) + ); + $contribute[AnswerFormMigration::class] = static fn() + => new MigrationNumeric( + new ClozeTableDefinitions( + $internal[PersistenceFactory::class], + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ), + $internal[\EvalMath::class] + ); + $contribute[AnswerFormMigration::class] = static fn() + => new MigrationTextSubset( + new ClozeTableDefinitions( + $internal[PersistenceFactory::class], + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ) + ); + + $contribute[CapabilityMigration::class] = static fn() + => new TextFeedbackMigration( + new TextFeedbackTableDefinitions( + $internal[PersistenceFactory::class] + ) + ); + $contribute[CapabilityMigration::class] = static fn() + => new SuggestedLearningContentMigration( + new SuggestedLearningContentTableDefinitions( + $internal[PersistenceFactory::class] + ) + ); + + $contribute[Component\Resource\PublicAsset::class] = fn() + => new Component\Resource\ComponentJS( + $this, + 'js/dist/questions.js' + ); + $contribute[User\Settings\UserSettings::class] = fn() + => new Questions\UserSettings\Settings(); + } +} diff --git a/components/ILIAS/Questions/README.md b/components/ILIAS/Questions/README.md new file mode 100644 index 000000000000..6b2a3b9fda2b --- /dev/null +++ b/components/ILIAS/Questions/README.md @@ -0,0 +1 @@ +# Questions diff --git a/components/ILIAS/Questions/maintenance.json b/components/ILIAS/Questions/maintenance.json new file mode 100644 index 000000000000..462ad3856cc3 --- /dev/null +++ b/components/ILIAS/Questions/maintenance.json @@ -0,0 +1,14 @@ +{ + "maintenance_model": "Classic", + "first_maintainer": "dstrassner(48931)", + "second_maintainer": "mbecker(27266)", + "implicit_maintainers": [], + "coordinator": [ + "" + ], + "tester": "SIG EA", + "testcase_writer": "Fabian(27631)", + "path": "Modules/Test", + "belong_to_component": "Test & Assessment", + "used_in_components": [] +} \ No newline at end of file diff --git a/components/ILIAS/Questions/resources/js/dist/questions.js b/components/ILIAS/Questions/resources/js/dist/questions.js new file mode 100644 index 000000000000..ca6fc283a510 --- /dev/null +++ b/components/ILIAS/Questions/resources/js/dist/questions.js @@ -0,0 +1,15 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + */ +!function(e){"use strict";function t(e,t,i){return"Enter"===i.key&&"LI"===i.target.nodeName?(i.stopImmediatePropagation(),i.preventDefault(),void n(i)):"ArrowDown"===i.key?(i.stopImmediatePropagation(),i.preventDefault(),"UL"===i.target.nextElementSibling?.nodeName&&i.target.nextElementSibling.firstElementChild.focus(),void("LI"===i.target.nodeName&&null!==i.target.nextElementSibling&&i.target.nextElementSibling.focus())):"ArrowUp"===i.key&&"LI"===i.target.nodeName?(i.stopImmediatePropagation(),i.preventDefault(),void(null===i.target.previousElementSibling?i.target.parentElement.previousElementSibling.focus():i.target.previousElementSibling.focus())):void function(e,t,i){"UL"===i.target.nextElementSibling?.nodeName&&i.target.nextElementSibling.remove();if("Tab"===i.key||i.target.value.lengthe.toLowerCase().includes(i.target.value.toLowerCase()));if(0===o.length)return;const r=document.createElement("ul");o.forEach(e=>{const t=document.createElement("li");t.tabIndex=0,t.textContent=e,r.appendChild(t)}),r.addEventListener("click",n),r.addEventListener("keyup",n),i.target.parentNode.appendChild(r)}(e,t,i)}function n(e){"keydown"===e.type&&"Enter"!==e.key||(e.target.parentNode.previousElementSibling.value=e.target.textContent,e.target.parentNode.previousElementSibling.focus(),e.target.parentNode.remove())}const i="gap_type",o="lower_limit",r="upper_limit",s="response";function a(e,t){const n=parseFloat(t);return Number.isNaN(e[r])||Number.isNaN(parseFloat(e[r]))?["o"]:n<=e[r]?["o","b"]:void 0===e[r]&&n===e[o]||n>=e[o]?["i"]:["o","a"]}function c(e,t){return"numeric"===e[i]&&"i"===a(e[s],t)[0]||"numeric"!==e[i]&&t===e[s].given_response}function l(e,t){return""===t?["no_response"]:"numeric"===e[i]?a(e,t):c(e,t)?["best_response"]:["other_response"]}var u={isBestResponse(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;const n=Object.keys(t);for(let i=0;ie[t],e.target.ownerDocument.defaultView);return o[n].apply(o,i)}function g(e){const t=atob(e),n=new Uint8Array(t.length);for(let e=0;ee.length>t.length?e.length:t.length)),e.addEventListener("keyup",e=>t(n,i,e)))},e.questions.cloze.specificTextFeedback=e.questions.specificTextFeedback||{},e.questions.cloze.specificTextFeedback=u,e.questions.textFeedback=e.questions.textFeedback||{},e.questions.textFeedback.retrieve=function(e,t,n,i,o){const{panelTitle:r}=n;delete n.panelTitle;const{specificFeedbackEndPoint:s}=n;delete n.specificFeedbackEndpoint;const a=p(e,s,"isBestResponse",[i,o])?"best":"other";let c="";return Object.hasOwn(n,a)&&(c=n[a]),t.replace("-panel-title-to-replace-",r).replace("-panel-content-to-replace-",c+p(e,s,"retrieveSpecificFeedback",[n,i,o]))},e.questions.suggestedLearningContent=e.questions.suggestedLearningContent||{},e.questions.suggestedLearningContent.retrieve=function(e,t,n){return n},e.questions.asyncView=e.questions.asyncView||{},e.questions.asyncView.showFeedback=function(e,t,n,i,o,...r){const s=g(t),a=JSON.parse(g(i));let c="";void 0!==o&&(c+=g(o));const l=e.target.previousElementSibling.querySelectorAll("input, select, textarea"),u=Array.from(l).reduce((e,t)=>(e[t.name]=t.value,u),{}),p=JSON.parse(g(n));r.forEach((t,n)=>{c+=t(e,s,p[n],a,u)}),e.target.nextElementSibling.innerHTML=c}}(il); diff --git a/components/ILIAS/Questions/resources/js/src/AsyncView/showFeedback.js b/components/ILIAS/Questions/resources/js/src/AsyncView/showFeedback.js new file mode 100644 index 000000000000..475345790574 --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/AsyncView/showFeedback.js @@ -0,0 +1,77 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +/** + * @param {String} base64 + * @returns {string} + */ +function base64toUtf8(base64) { + const binaryString = atob(base64); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i += 1) { + bytes[i] = binaryString.charCodeAt(i); + } + const decoder = new TextDecoder(); + return decoder.decode(bytes); +} + +/** + * @param {Event} event + * @param {string} panel Standard panel scafold rendered in php. + * @param {Object} feedbackDataArray Object containing all possible feedbacks + * @param {Object} bestResponse + * @param {Object} response + * @param {...string} Endpoints the retrieve feedbacks of different feedback providers + */ +export default function showFeedback( + event, + panel, + feedbackDataArray, + bestResponse, + bestResponseOutput, + ...feedbackCallbacks +) { + const decodedPanel = base64toUtf8(panel); + const decodedBestResponse = JSON.parse( + base64toUtf8( + bestResponse, + ), + ); + + let feedback = ''; + + if (typeof bestResponseOutput !== 'undefined') { + feedback += base64toUtf8(bestResponseOutput); + } + const inputs = event.target.previousElementSibling.querySelectorAll('input, select, textarea'); + const response = Array.from(inputs).reduce( + (resp, input) => { + resp[input.name] = input.value; + return response; + }, + {}, + ); + + const decodedFeedbackData = JSON.parse(base64toUtf8(feedbackDataArray)); + + feedbackCallbacks.forEach( + (v, i) => { + feedback += v(event, decodedPanel, decodedFeedbackData[i], decodedBestResponse, response); + }, + ); + + event.target.nextElementSibling.innerHTML = feedback; +} diff --git a/components/ILIAS/Questions/resources/js/src/Cloze/feedback.js b/components/ILIAS/Questions/resources/js/src/Cloze/feedback.js new file mode 100644 index 000000000000..47def6716b46 --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/Cloze/feedback.js @@ -0,0 +1,140 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +const keyGapType = 'gap_type'; +const keyLowerLimit = 'lower_limit'; +const keyUpperLimit = 'upper_limit'; +const keyResponseObject = 'response'; +const keyGivenResponse = 'given_response'; +const keyNoResponse = 'no_response'; +const keyBestResponse = 'best_response'; +const keyOtherResponse = 'other_response'; +const keyInRange = 'i'; +const keyOutOfRange = 'o'; +const keyBelowRange = 'b'; +const keyAboveRange = 'a'; + +/** + * @param {Object} bestResponse + * @param {string} response + * @return {Array} All feedback keys triggered by given response. + */ +function getKeysForNumericValue(bestResponse, response) { + const responseAsFloat = parseFloat(response); + + if (Number.isNaN(bestResponse[keyUpperLimit]) + || Number.isNaN(parseFloat(bestResponse[keyUpperLimit]))) { + return [keyOutOfRange]; + } + + if (responseAsFloat <= bestResponse[keyUpperLimit]) { + return [keyOutOfRange, keyBelowRange]; + } + + if ((typeof bestResponse[keyUpperLimit] === 'undefined' + && responseAsFloat === bestResponse[keyLowerLimit]) + || responseAsFloat >= bestResponse[keyLowerLimit]) { + return [keyInRange]; + } + + return [keyOutOfRange, keyAboveRange]; +} + +/** + * @param {Object} bestResponse + * @param {string} response + * @return {bool} + */ +function isResponseForInputBest(bestResponse, response) { + if ((bestResponse[keyGapType] === 'numeric' + && getKeysForNumericValue(bestResponse[keyResponseObject], response)[0] === keyInRange) + || (bestResponse[keyGapType] !== 'numeric' + && response === bestResponse[keyResponseObject][keyGivenResponse])) { + return true; + } + + return false; +} + +/** + * @param {Object} bestResponse + * @param {string} response + * @return {Array} All feedback keys triggered by given response. + */ +function getKeysForOtherAnswerValue(bestResponse, response) { + if (response === '') { + return [keyNoResponse]; + } + + if (bestResponse[keyGapType] === 'numeric') { + return getKeysForNumericValue(bestResponse, response); + } + + return isResponseForInputBest(bestResponse, response) + ? [keyBestResponse] + : [keyOtherResponse]; +} + +export default { + /** + * @param {Object} bestResponse + * @param {Object} response + */ + isBestResponse(bestResponse, response) { + if (Object.keys(bestResponse).length !== Object.keys(response).length) { + return false; + } + + const keys = Object.keys(response); + for (let i = 0; i < keys.length; i += 1) { + if (!isResponseForInputBest(bestResponse[keys[i]], response[keys[i]])) { + return false; + } + } + return true; + }, + /** + * @param {Object} data + * @param {Object} bestResponse + * @param {Object} response + */ + retrieveSpecificFeedback(data, bestResponse, response) { + let feedbacks = ''; + + const responseKeys = Object.keys(response); + for (let i = 0; i < responseKeys.length; i += 1) { + const property = responseKeys[i]; + if (Object.hasOwn(data, property)) { + if (Object.hasOwn(data[property], response[property])) { + feedbacks += data[property][response[property]]; + } + + const keys = getKeysForOtherAnswerValue( + bestResponse[property], + response[property], + ); + + for (let j = 0; j < keys.length; j += 1) { + if (Object.hasOwn(data[property], keys[i])) { + feedbacks += data[property][keys[j]]; + } + } + } + } + + return feedbacks; + }, +}; diff --git a/components/ILIAS/Questions/resources/js/src/Cloze/longmenuAutocomplete.js b/components/ILIAS/Questions/resources/js/src/Cloze/longmenuAutocomplete.js new file mode 100644 index 000000000000..71b2a0846c4f --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/Cloze/longmenuAutocomplete.js @@ -0,0 +1,127 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +/** + * @param {number} autocompleteLength + * @param {array} answerOptions + * @param {Event} e + */ +function keyHandler(autocompleteLength, answerOptions, e) { + if (e.key === 'Enter' && e.target.nodeName === 'LI') { + e.stopImmediatePropagation(); + e.preventDefault(); + onSelectHandler(e); + return; + } + + if (e.key === 'ArrowDown') { + e.stopImmediatePropagation(); + e.preventDefault(); + if (e.target.nextElementSibling?.nodeName === 'UL') { + e.target.nextElementSibling.firstElementChild.focus(); + } + + if (e.target.nodeName === 'LI' && e.target.nextElementSibling !== null) { + e.target.nextElementSibling.focus(); + } + return; + } + + if (e.key === 'ArrowUp' && e.target.nodeName === 'LI') { + e.stopImmediatePropagation(); + e.preventDefault(); + if (e.target.previousElementSibling === null) { + e.target.parentElement.previousElementSibling.focus(); + } else { + e.target.previousElementSibling.focus(); + } + return; + } + + onChangeHandler(autocompleteLength, answerOptions, e); +} + +/** + * @param {number} autocompleteLength + * @param {array} answerOptions + * @param {Event} e + */ +function onChangeHandler(autocompleteLength, answerOptions, e) { + if (e.target.nextElementSibling?.nodeName === 'UL') { + e.target.nextElementSibling.remove(); + } + + if (e.key === 'Tab' || e.target.value.length < autocompleteLength) { + return; + } + + const matchingAnswers = answerOptions.filter( + (answer) => answer.toLowerCase().includes(e.target.value.toLowerCase()), + ); + + if (matchingAnswers.length === 0) { + return; + } + + const list = document.createElement('ul'); + matchingAnswers.forEach((answer) => { + const listElement = document.createElement('li'); + listElement.tabIndex = 0; + listElement.textContent = answer; + list.appendChild(listElement); + }); + list.addEventListener('click', onSelectHandler); + list.addEventListener('keyup', onSelectHandler); + e.target.parentNode.appendChild(list); +} + +function onSelectHandler(e) { + if (e.type === 'keydown' && e.key !== 'Enter') { + return; + } + e.target.parentNode.previousElementSibling.value = e.target.textContent; + e.target.parentNode.previousElementSibling.focus(); + e.target.parentNode.remove(); +} + +/** + * @param {HTMLElement} input + * @param {number} autocompleteLength + * @param {array} answerOptions + */ +export default function longmenuAutocomplete( + input, + autocompleteLength, + answerOptions, +) { + if (input.nodeName === 'INPUT') { + input.setAttribute( + 'size', + answerOptions.reduce( + (a, b) => { + if (a.length > b.length) { + return a.length; + } + return b.length; + }, + ), + ); + input.addEventListener( + 'keyup', + (e) => keyHandler(autocompleteLength, answerOptions, e), + ); + } +} diff --git a/components/ILIAS/Questions/resources/js/src/SuggestedLearningContent/retrieve.js b/components/ILIAS/Questions/resources/js/src/SuggestedLearningContent/retrieve.js new file mode 100644 index 000000000000..60318c3fe529 --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/SuggestedLearningContent/retrieve.js @@ -0,0 +1,25 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +/** + * @param {Event} event + * @param {string} panel Standard panel scafold rendered in php. + * @param {Object} data Object containing all possible feedbacks + * @returns {string} + */ +export default function retrieve(event, panel, data) { + return data; +} diff --git a/components/ILIAS/Questions/resources/js/src/TextFeedback/retrieve.js b/components/ILIAS/Questions/resources/js/src/TextFeedback/retrieve.js new file mode 100644 index 000000000000..e5c90af3105c --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/TextFeedback/retrieve.js @@ -0,0 +1,81 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +const placeholderPanelTitle = '-panel-title-to-replace-'; +const placeholderPanelContent = '-panel-content-to-replace-'; + +const keyBestResponse = 'best'; +const keyOtherResponse = 'other'; + +/** + * This function is used to call a namespaced function that has been handed in + * the form of two Strings. This is needed to be able to initialize most of the + * js in a file, but still define proper endpoints in php without some funky + * template parsing of js files. + * + * @param {Event} event + * @param {string} namespace + * @param {string} func + * @param {Array} args + * @returns {string} + */ +function executeSpecificEndPointFunction(event, namespace, func, args) { + const context = namespace.split('.').reduce( + (c, v) => c[v], + event.target.ownerDocument.defaultView, + ); + return context[func].apply(context, args); +} + +/** + * @param {Event} event + * @param {string} panel Standard panel scafold rendered in php. + * @param {Object} data Object containing all possible feedbacks + * @param {Object} bestResponse + * @param {Object} response + * @returns {string} + */ +export default function retrieve(event, panel, data, bestResponse, response) { + const { panelTitle } = data; + delete data.panelTitle; + const { specificFeedbackEndPoint } = data; + delete data.specificFeedbackEndpoint; + + const key = executeSpecificEndPointFunction( + event, + specificFeedbackEndPoint, + 'isBestResponse', + [bestResponse, response], + ) ? keyBestResponse : keyOtherResponse; + + let genericFeedback = ''; + if (Object.hasOwn(data, key)) { + genericFeedback = data[key]; + } + + return panel.replace( + placeholderPanelTitle, + panelTitle, + ).replace( + placeholderPanelContent, + genericFeedback + executeSpecificEndPointFunction( + event, + specificFeedbackEndPoint, + 'retrieveSpecificFeedback', + [data, bestResponse, response], + ), + ); +} diff --git a/components/ILIAS/Questions/resources/js/src/questions.js b/components/ILIAS/Questions/resources/js/src/questions.js new file mode 100644 index 000000000000..43194811908d --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/questions.js @@ -0,0 +1,34 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + */ + +import il from 'ilias'; +import longmenuAutocomplete from './Cloze/longmenuAutocomplete.js'; +import clozeSpecificTextFeedback from './Cloze/feedback.js'; +import textFeedbackRetrieve from './TextFeedback/retrieve.js'; +import suggestedLearningContentRetrieve from './SuggestedLearningContent/retrieve.js'; +import asyncViewShowFeedback from './AsyncView/showFeedback.js'; + +il.questions = il.questions || {}; +il.questions.cloze = il.questions.cloze || {}; +il.questions.cloze.initLongmenuGap = longmenuAutocomplete; +il.questions.cloze.specificTextFeedback = il.questions.specificTextFeedback || {}; +il.questions.cloze.specificTextFeedback = clozeSpecificTextFeedback; +il.questions.textFeedback = il.questions.textFeedback || {}; +il.questions.textFeedback.retrieve = textFeedbackRetrieve; +il.questions.suggestedLearningContent = il.questions.suggestedLearningContent || {}; +il.questions.suggestedLearningContent.retrieve = suggestedLearningContentRetrieve; +il.questions.asyncView = il.questions.asyncView || {}; +il.questions.asyncView.showFeedback = asyncViewShowFeedback; diff --git a/components/ILIAS/Questions/resources/js/src/rollup.config.js b/components/ILIAS/Questions/resources/js/src/rollup.config.js new file mode 100644 index 000000000000..8ffc0a1b98f6 --- /dev/null +++ b/components/ILIAS/Questions/resources/js/src/rollup.config.js @@ -0,0 +1,27 @@ +import terser from '@rollup/plugin-terser'; +import copyright from '../../../../../../scripts/Copyright-Checker/copyright.js'; +import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright.js'; + +export default { + external: [ + 'document', + 'ilias', + ], + input: './questions.js', + output: { + file: '../dist/questions.js', + format: 'iife', + banner: copyright, + globals: { + document: 'document', + ilias: 'il', + }, + plugins: [ + terser({ + format: { + comments: preserveCopyright, + }, + }), + ], + }, +}; diff --git a/components/ILIAS/Questions/service.xml b/components/ILIAS/Questions/service.xml new file mode 100644 index 000000000000..2f7a463b3da2 --- /dev/null +++ b/components/ILIAS/Questions/service.xml @@ -0,0 +1,21 @@ + + + + + adm + + + + + + + + + + + + + + + diff --git a/components/ILIAS/Questions/src/Administration/ConfigurationRepository.php b/components/ILIAS/Questions/src/Administration/ConfigurationRepository.php new file mode 100755 index 000000000000..fa9e33a3ee4e --- /dev/null +++ b/components/ILIAS/Questions/src/Administration/ConfigurationRepository.php @@ -0,0 +1,85 @@ +user_setting_create_mode->isChangeableByUser(); + } + + public function getGlobalCreateMode(): CreateModes + { + return CreateModes::tryFrom( + $this->questions_settings->get( + self::SETTINGS_KEY_CREATE_MODE, + '' + ) + ) ?? CreateModes::getDefaultMode(); + } + + public function isCreateModeSimple( + DefaultEnvironment $environment + ): bool { + return $this->isCreateModeChangeableByUser() && $environment->isCreateModeSimple() + || $this->getGlobalCreateMode() === CreateModes::Simple; + } + + public function persistCreateMode( + CreateModes $create_mode + ): void { + $this->questions_settings->set( + self::SETTINGS_KEY_CREATE_MODE, + $create_mode->value + ); + } + + public function getInputForCreateMode( + FieldFactory $field_factory, + Language $lng, + Refinery $refinery + ): Input { + return $this->user_setting_create_mode->getInput( + $field_factory, + $lng, + $refinery, + $this->common_settings + ); + } +} diff --git a/components/ILIAS/Questions/src/Administration/class.ConfigurationGUI.php b/components/ILIAS/Questions/src/Administration/class.ConfigurationGUI.php new file mode 100755 index 000000000000..74ff8631a861 --- /dev/null +++ b/components/ILIAS/Questions/src/Administration/class.ConfigurationGUI.php @@ -0,0 +1,115 @@ +ctrl->getCmd(self::CMD_DEFAULT) . 'Cmd'; + $this->$cmd(); + } + + private function viewCmd( + ?StandardForm $form = null + ): void { + $this->tpl->setContent( + $this->ui_renderer->render( + $form ?? $this->buildSettingsForm() + ) + ); + } + + private function saveCmd(): void + { + $form = $this->buildSettingsForm()->withRequest($this->http->request()); + $data = $form->getData(); + if ($data === null) { + $this->viewCmd($form); + } + + $this->repository->persistCreateMode( + $data['default_user_settings']['create_mode'] + ); + + $this->ctrl->redirectByClass( + [ + \ilAdministrationGUI::class, + \ilObjQuestionsGUI::class, + self::class + ] + ); + } + + private function buildSettingsForm(): StandardForm + { + return $this->ui_factory->input()->container()->form()->standard( + $this->ctrl->getLinkTargetByClass( + [ + \ilAdministrationGUI::class, + \ilObjQuestionsGUI::class, + self::class + ], + self::CMD_SAVE + ), + [ + 'default_user_settings' => $this->ui_factory->input()->field()->section( + [ + 'create_mode' => $this->repository->getInputForCreateMode( + $this->ui_factory->input()->field(), + $this->lng, + $this->refinery + )->withAdditionalTransformation( + $this->refinery->custom()->transformation( + static fn(string $v): CreateModes => CreateModes::tryFrom($v) + ?? CreateModes::getDefaultMode() + ) + ) + ], + $this->lng->txt('default_user_settings') + ) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/AsyncView.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/AsyncView.php new file mode 100644 index 000000000000..4269aba6cb26 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/AsyncView.php @@ -0,0 +1,256 @@ +setVariable( + self::TEMPLATE_VARIABLE_ANSWER_FORM, + $this->getAnswerFormPresentation( + $lng, + $ui_factory, + $view_configuration, + $answer_form_properties, + $attempt_data, + $response_data + ) + ); + + if (!$view_configuration->isInteractive()) { + return $ui_factory->legacy()->content($tpl->get()); + } + + $global_tpl->addJavaScript(self::JAVASCRIPT_BASE_FILE); + + foreach ($this->getJavascriptFiles() as $file) { + $global_tpl->addJavaScript($file); + } + + $feedback_array = $this->buildFeedbackArray( + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $view_configuration, + $answer_form_properties, + $attempt_data + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_CHECK_BUTTON, + $this->ui_renderer->render( + $ui_factory->button()->standard( + $lng->txt('check'), + '' + )->withAdditionalOnLoadCode( + fn(string $id) => "document.querySelector(`#{$id}`).addEventListener(" + . '"click", (e) => il.questions.asyncView.showFeedback(e, "' + . base64_encode( + $this->buildFeedbackPanelWithPlaceholders($ui_factory) + ) . '", "' . base64_encode(json_encode($feedback_array['feedback_data'])) . '", "' + . ($feedback_array[self::KEY_BEST_RESPONSE] === null + ? '' + : base64_encode(json_encode($feedback_array[self::KEY_BEST_RESPONSE]))) . '", ' + . (array_key_exists(self::KEY_BEST_RESPONSE_OUTPUT, $feedback_array) + ? '"' . base64_encode($feedback_array[self::KEY_BEST_RESPONSE_OUTPUT]) . '"' + : 'undefined') + . ', ' + . implode(', ', $feedback_array['feedback_callbacks']) + . '));' + ) + ) + ); + + return $ui_factory->legacy()->content($tpl->get()); + } + + private function buildFeedbackArray( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + ViewConfiguration $view_configuration, + AnswerFormProperties $answer_form_properties, + ?AdditionalAttemptData $attempt_data, + ): array { + $best_response = $required_capabilities + ->getMarking($answer_form_properties) + ->getBestResponse($answer_form_properties); + $feedbacks = [ + self::KEY_BEST_RESPONSE => $best_response->toClientSideRepresentation() + ]; + + if ($view_configuration->showBestResponse()) { + $feedbacks[self::KEY_BEST_RESPONSE_OUTPUT] = $this->ui_renderer->render( + $ui_factory->panel()->standard( + $lng->txt('best_response'), + $ui_factory->legacy()->content( + $this->getAnswerFormPresentation( + $lng, + $ui_factory, + $view_configuration->withShowBestResponse(true), + $answer_form_properties, + $attempt_data, + $best_response + ) + ) + ) + ); + } + + if (!$view_configuration->showFeedback()) { + return $feedbacks; + } + + return $this->addFeedbacksFromProvidersToFeedbacks( + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $answer_form_properties, + $feedbacks + ); + } + + private function addFeedbacksFromProvidersToFeedbacks( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + AnswerFormProperties $answer_form_properties, + array $feedbacks + ): array { + $feedbacks['feedback_callbacks'] = []; + $feedbacks['feedback_data'] = []; + + return array_reduce( + $required_capabilities->getRequiredFeedbackProviders(), + function ( + array $c, + FeedbackProvider $v + ) use ( + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $answer_form_properties + ): array { + $feedback = $v->getFeedback($answer_form_properties); + $feedback_data = $feedback->getAllFeedbacksForClientSideCode( + $lng, + $refinery, + $ui_factory, + $this->ui_renderer, + $required_capabilities, + $answer_form_properties + ); + + if ($feedback_data !== []) { + $c['feedback_callbacks'][] = $feedback->getFeedbackClientSideEndPoint(); + $c['feedback_data'][] = $feedback_data; + } + + return $c; + }, + $feedbacks + ); + } + + private function buildFeedbackPanelWithPlaceholders( + UIFactory $ui_factory + ): string { + return $this->ui_renderer->render( + $ui_factory->panel()->standard( + self::PLACEHOLDER_PANEL_TITLE, + $ui_factory->legacy()->content( + self::PLACEHOLDER_PANEL_CONTENT + ) + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/Capability.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/Capability.php new file mode 100644 index 000000000000..d4ee1aacf344 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/AsyncView/Capability.php @@ -0,0 +1,76 @@ +getDefinition() + ->hasCapability( + self::getIdentifier() + ); + } + + #[\Override] + public function getParticipantView( + Properties $answer_form_properties + ): Participant { + return $answer_form_properties + ->getDefinition() + ->getCapability(self::getIdentifier()); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormDelete( + Properties $answer_form_properties + ): void { + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Capability.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Capability.php new file mode 100644 index 000000000000..00c6a767a56b --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Capability.php @@ -0,0 +1,47 @@ +getDefinition() + ->hasCapability( + self::getIdentifier() + ); + } + + #[\Override] + public function getParticipantView( + Properties $answer_form_properties + ): Participant { + return $answer_form_properties + ->getDefinition() + ->getCapability(self::getIdentifier()); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormDelete( + Properties $answer_form_properties + ): void { + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/DefaultView/DefaultView.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/DefaultView/DefaultView.php new file mode 100644 index 000000000000..46f5feccb28b --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/DefaultView/DefaultView.php @@ -0,0 +1,201 @@ +buildMainContent( + $global_tpl, + $lng, + $ui_factory, + $required_capabilities, + $view_configuration, + $properties, + $attempt_data, + $response_data + ); + + if (!$view_configuration->showFeedback()) { + return $main_content; + } + + return $this->addFeedbackSubPanelsToContent( + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $properties, + $response_data, + [ + $ui_factory->panel()->standard( + $this->buildMainContentLabel( + $lng, + $view_configuration->showBestResponse() + ), + $main_content + ) + ] + ); + } + + private function buildMainContent( + GlobalTemplate $global_tpl, + Language $lng, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + ViewConfiguration $view_configuration, + ?AnswerFormProperties $answer_form_properties, + ?AdditionalAttemptData $additional_attempt_data, + ?AnswerFormResponse $answer_form_response + ): array|Component { + if ($view_configuration->showBestResponse()) { + $best_response = $required_capabilities->getMarking( + $answer_form_properties + )?->getBestResponse( + $answer_form_properties + ); + + return $this->getAnswerFormPresentation( + $lng, + $ui_factory, + $view_configuration->withShowBestResponse(true), + $answer_form_properties, + $additional_attempt_data, + $best_response + ); + } + + $global_tpl->addJavaScript(self::JAVASCRIPT_BASE_FILE); + + foreach ($this->getJavascriptFiles() as $file) { + $global_tpl->addJavaScript($file); + } + + return $this->getAnswerFormPresentation( + $lng, + $ui_factory, + $view_configuration, + $answer_form_properties, + $additional_attempt_data, + $answer_form_response + ); + } + + private function addFeedbackSubPanelsToContent( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + AnswerFormProperties $answer_form_properties, + AnswerFormResponse $answer_form_response, + array $content + ): array { + return array_reduce( + $required_capabilities->getRequiredFeedbackProviders(), + function ( + array $c, + FeedbackProvider $v + ) use ( + $lng, + $refinery, + $ui_factory, + $answer_form_properties, + $answer_form_response, + $required_capabilities + ): array { + $output = $v->getFeedback( + $answer_form_properties + )->getParticipantOutput( + $lng, + $refinery, + $ui_factory, + $answer_form_properties, + $answer_form_response, + $required_capabilities + ); + + if ($output === null) { + return $c; + } + + $c[] = $output->getUI(); + return $c; + }, + $content + ); + } + + private function buildMainContentLabel( + Language $lng, + bool $show_best_response + ): string { + if ($show_best_response) { + return $lng->txt('best_response'); + } + + return $lng->txt('question'); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/ActionWithTab.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/ActionWithTab.php new file mode 100644 index 000000000000..ed30d1b0ee66 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/ActionWithTab.php @@ -0,0 +1,78 @@ +do->__invoke($environment); + } + + public function getIdentifier(): string + { + return self::PREFIX . '_' . md5($this->capability::class); + } + + public function addTab( + Environment $environment, + \ilTabsGUI $tabs_gui + ): void { + $action = $this->getIdentifier(); + $tabs_gui->addTab( + $action, + $environment->getLanguage()->txt($this->lang_var), + $environment->withActionParameter($action) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ); + } + + public function activateTab( + \ilTabsGUI $tabs_gui + ): void { + $tabs_gui->activateTab( + $this->getIdentifier() + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalFormStepAction.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalFormStepAction.php new file mode 100644 index 000000000000..b2f096241e21 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalFormStepAction.php @@ -0,0 +1,233 @@ +getSubAction(); + $environment_with_preserved_parameters = $environment + ->withPreservedTableRowIdsParameter() + ->withPreservedFormStartSubActionParameter(); + return match ($sub_action) { + self::SUB_ACTION_SAVE => $this->forwardToNextForm( + $environment_with_preserved_parameters + ), + self::SUB_ACTION_BACK => $this->backToPreviousForm( + $environment_with_preserved_parameters + ), + default => $this->buildFormWithCarry( + $environment_with_preserved_parameters + ) + }; + } + + public function getIdentifier(): string + { + return self::PREFIX . '_' . md5($this->capability::class); + } + + private function toPrevious( + DefaultEnvironment $envrionment + ): Async|EditForm { + if ($this->previous instanceof AnswerFormEditView) { + return $this->previous + ->backToLastEditCommand($envrionment->withActionParameter('')) + ->withIsFinalStep(false); + } + + return $this->previous->getAnswerFormEditAdditionalStep()->do( + $envrionment + ); + } + + public function withPrevious( + Capability|AnswerFormEditView $previous + ): self { + $clone = clone $this; + $clone->previous = $previous; + return $clone; + } + + private function toNext( + DefaultEnvironment $environment + ): Async|EditForm|Properties { + if ($this->next === null) { + return $environment->getAnswerFormProperties(); + } + + return $this->next->getAnswerFormEditAdditionalStep()->do( + $environment + ); + } + + public function withNext( + ?Capability $next + ): self { + $clone = clone $this; + $clone->next = $next; + return $clone; + } + + public function getAsTableAction( + DefaultEnvironment $environment + ): TableAction { + return $environment->getUIFactory()->table()->action()->standard( + $environment->getLanguage()->txt($this->lang_var), + $environment->withActionParameter( + $this->getIdentifier() + )->getUrlBuilder(), + $environment->getTableRowIdToken() + ); + } + + private function buildFormWithCarry( + DefaultEnvironment $environment + ): EditForm { + $properties = $environment->getAnswerFormProperties(); + + $inputs_builder_for_points = $this->retrieve_inputs_builder->__invoke( + $environment + )->withCarry( + $properties->toCarry() + ); + + $inputs_builder_for_points->persistCarry(); + + return $this->buildForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder_for_points + ); + } + + private function buildForm( + DefaultEnvironment $environment, + InputsBuilderSession $inputs_builder + ): EditForm { + $properties = $environment->getAnswerFormProperties(); + return $environment->getPresentationFactory()->getEditForm( + $inputs_builder, + $environment->withSubActionParameter( + self::SUB_ACTION_SAVE + )->getUrlBuilder(), + $this->previous === null + ? null + : $environment->withSubActionParameter( + self::SUB_ACTION_BACK + )->getUrlBuilder() + )->withIsFinalStep(true) + ->withContentBeforeForm( + $properties->getClozeText()->buildPanelForEditing( + $environment->getUIFactory(), + $environment->getLanguage(), + $properties->getGaps(), + $properties->getLegacyClozeText() + ) + ); + } + + private function forwardToNextForm( + DefaultEnvironment $environment + ): EditForm|Properties { + $processed_form = $this->processForm($environment); + if ($processed_form instanceof EditForm) { + return $processed_form; + } + + return $this->toNext( + $environment->withAnswerFormProperties($processed_form) + ); + } + + private function backToPreviousForm( + DefaultEnvironment $environment + ): EditForm { + $processed_form = $this->processForm($environment); + if ($processed_form instanceof EditForm) { + return $processed_form; + } + + return $this->toPrevious( + $environment->withAnswerFormProperties($processed_form) + ); + } + + private function processForm( + DefaultEnvironment $environment + ): EditForm|Properties { + $inputs_builder = $this->retrieve_inputs_builder->__invoke($environment); + + $properties = $inputs_builder->retrieveCarry( + $this->retrieve_properties_from_carry_transformation->__invoke($environment) + ); + $form = $this->buildForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder + )->withRequest($environment->getHttpServices()->request()); + + $data = $form->getData(); + if ($data === null) { + $inputs_builder->persistCarry(); + return $form; + } + + return $data; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalStepProvider.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalStepProvider.php new file mode 100644 index 000000000000..319fbcc00ddf --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/AdditionalStepProvider.php @@ -0,0 +1,26 @@ + An array of all possible feedbacks + * as FeedbackViews structured in a way that makes it possible to retrieve + * the correct array corresponding to the answer of the user in the callback + * provided in getClientSideFeedbackEndPoint. The component takes care of + * transporting the information to javascript. + */ + public function getAllFeedbacksForClientSideCode( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + UIRenderer $ui_renderer, + RequiredCapabilities $required_capabilities, + Properties $properties + ): array; +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/FeedbackProvider.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/FeedbackProvider.php new file mode 100644 index 000000000000..2d44472aef47 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/FeedbackProvider.php @@ -0,0 +1,30 @@ +feedback; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/Marking.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/Marking.php new file mode 100644 index 000000000000..192187709fed --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/Definitions/Marking.php @@ -0,0 +1,36 @@ + $available_capabilities + */ + private readonly array $available_capabilities; + + /** + * @param list $available_capabilities + */ + public function __construct( + array $available_capabilities + ) { + $this->available_capabilities = array_reduce( + $available_capabilities, + function (array $c, Capability $v): array { + $c[$v->getIdentifier()] = $v; + return $c; + }, + [] + ); + } + + /** + * + * @param list> $capability_identifiers + */ + public function get( + array $capability_identifiers + ): RequiredCapabilities { + $required_capabilities = []; + $participant_view_providers = []; + $marking_providers = []; + $required_feedback_providers = []; + $required_actions_with_tab = []; + $required_form_step_actions = []; + $required_page_migration_providers = []; + + foreach ($capability_identifiers as $capability_identifier) { + if (!isset($this->available_capabilities[$capability_identifier])) { + throw new \InvalidArgumentException( + "The capability {$capability_identifier} does not exist." + ); + } + + $capability = $this->available_capabilities[$capability_identifier]; + $required_capabilities[$capability_identifier] = $capability; + + if ($capability instanceof ParticipantViewProvider) { + $participant_view_providers[] = $capability; + } + + if ($capability instanceof MarkingProvider) { + $marking_providers[] = $capability; + } + + if ($capability instanceof FeedbackProvider) { + $required_feedback_providers[] = $capability; + } + + if ($capability instanceof AdditionalTabProvider) { + $action_with_tab = $capability->getAnswerFormEditAdditionalTab(); + $required_actions_with_tab[$action_with_tab->getIdentifier()] = $action_with_tab; + } + + if ($capability instanceof AdditionalStepProvider) { + $form_step_action = $capability->getAnswerFormEditAdditionalStep(); + $required_form_step_actions[$form_step_action->getIdentifier()] = $form_step_action; + } + + if ($capability instanceof PageMigrationProvider) { + $required_page_migration_providers[] = $capability; + } + } + + if (count($participant_view_providers) !== 1 || count($marking_providers) > 1) { + throw new \InvalidArgumentException( + 'You have to provide exactly one Capability providing a Participant View' + . 'and one Capability providing Marking at most.' + ); + } + + return new RequiredCapabilities( + $required_capabilities, + $participant_view_providers[0], + $required_feedback_providers, + $required_actions_with_tab, + $required_form_step_actions, + $required_page_migration_providers, + $marking_providers[0] ?? null + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/Capability.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/Capability.php new file mode 100644 index 000000000000..1158f2a894e6 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/Capability.php @@ -0,0 +1,102 @@ +getTypeGenericProperties() + ->getDefinition() + ->hasCapability( + self::getIdentifier() + ) + && $answer_form_properties + ->getTypeGenericProperties() + ->getAvailablePoints() !== null; + } + + #[\Override] + public function getAnswerFormEditAdditionalStep(): AdditionalFormStepAction + { + return new AdditionalFormStepAction( + $this, + 'edit_available_points', + fn(Environment $v): InputsBuilderSession + => $v->getAnswerFormProperties() + ->getDefinition() + ->getCapability(self::getIdentifier()) + ->getEditFormInputsBuilder($v), + fn(Environment $v) => $v->getAnswerFormProperties() + ->getDefinition() + ->getCapability(self::getIdentifier()) + ->getCarryPropertiesFromCarryTransformation($v) + ); + } + + #[\Override] + public function getMarking( + Properties $answer_form_properties + ): Marking { + return $answer_form_properties + ->getDefinition() + ->getCapability(self::getIdentifier()); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormDelete( + Properties $answer_form_properties + ): void { + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/MarkingAllowingPartialPoints.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/MarkingAllowingPartialPoints.php new file mode 100644 index 000000000000..2b53542fcaa0 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/MarkingAllowingPartialPoints/MarkingAllowingPartialPoints.php @@ -0,0 +1,44 @@ + $capability_class_names + * @param array $required_feedback_views + * @param array $required_actions_with_tab + * @param array $required_step_actions + * @param array $required_step_actions + */ + public function __construct( + private readonly array $capabilities, + private ParticipantViewProvider $participant_view_provider, + private array $required_feedback_providers, + private array $required_actions_with_tab, + private array $required_form_step_actions, + private array $required_page_migration_providers, + private ?MarkingProvider $marking_provider + ) { + + } + + /** + * @param list $answer_form_properties + */ + public function areAllCapabilitiesSupportedByAnswerForms( + array $answer_form_properties + ): bool { + foreach ($answer_form_properties as $property) { + foreach ($this->capabilities as $capability) { + if (!$capability->isAvailableFor($property)) { + return false; + } + } + } + + return true; + } + + public function getParticipantViewProvider(): ParticipantViewProvider + { + return $this->participant_view_provider; + } + + /** + * @return array + */ + public function getRequiredFeedbackProviders(): array + { + return $this->required_feedback_providers; + } + + /** + * @return array + */ + public function getRequiredFormStepActions(): array + { + return $this->required_form_step_actions; + } + + /** + * @return array + */ + public function getRequiredPageMigrationProviders(): array + { + return $this->required_page_migration_providers; + } + + public function isMarkingRequired(): bool + { + return $this->marking_provider !== null; + } + + public function getMarking( + AnswerFormProperties $answer_form_properties + ): ?Marking { + return $this->marking_provider?->getMarking($answer_form_properties); + } + + public function isCapabilityRequired( + string $identifier + ): bool { + return array_key_exists($identifier, $this->capabilities); + } + + public function onAnswerFormClone( + UuidFactory $uuid_factory, + AnswerFormProperties $old_properties, + AnswerFormProperties $new_properties + ): void { + foreach ($this->capabilities as $capability) { + $capability->onAnswerFormClone( + $uuid_factory, + $old_properties, + $new_properties + ); + } + } + + public function onAnswerFormUpdate( + AnswerFormProperties $properties + ): void { + foreach ($this->capabilities as $capability) { + $capability->onAnswerFormUpdate($properties); + } + } + + public function create( + \ilTabsGUI $tabs_gui, + DefaultEnvironment $environment, + AnswerFormEditView $edit_view, + string $action_from_get + ): Async|Viewable|AnswerFormProperties|null { + $tab_action = $this->required_actions_with_tab[$action_from_get] ?? null; + if ($tab_action !== null) { + $tab_action->activateTab($tabs_gui); + + return $tab_action->do( + $environment->withActionParameter($action_from_get) + ); + } + + $step_action = $this->retrieveNextFormStepFromActionIdentifier( + $edit_view, + $action_from_get + ); + + if ($step_action === null) { + return null; + } + + $environment->setEditAnswerFormBackTarget(); + return $step_action->do( + $environment->withActionParameter($action_from_get) + ); + } + + public function edit( + \ilTabsGUI $tabs_gui, + DefaultEnvironment $environment, + AnswerFormEditView $edit_view, + string $action_from_get + ): Async|Viewable|AnswerFormProperties|null { + $environment->setEditAnswerFormTabs( + $this->required_actions_with_tab + ); + + return $this->create( + $tabs_gui, + $environment, + $edit_view, + $action_from_get + ); + } + + public function additionalAnswerFormStepsRequired(): bool + { + return $this->required_form_step_actions !== []; + } + + public function doFirstFormStepAction( + DefaultEnvironment $environment, + AnswerFormEditView $edit_view + ): EditForm|AnswerFormProperties { + if ($this->required_form_step_actions === []) { + return $environment->getAnswerFormProperties(); + } + + $keys = array_keys($this->required_form_step_actions); + + return $this->required_form_step_actions[$keys[0]] + ->withPrevious( + $edit_view + )->withNext( + isset($keys[1]) + ? $this->required_form_step_actions[$keys[1]] + : null + )->do( + $environment->withActionParameter($keys[0]) + ); + } + + private function retrieveNextFormStepFromActionIdentifier( + AnswerFormEditView $edit_view, + string $action_identifier + ): ?AdditionalFormStepAction { + $action = $this->required_form_step_actions[$action_identifier] ?? null; + if ($action === null) { + return null; + } + + $keys = array_keys($this->required_form_step_actions); + $current_index = array_search($action_identifier, $keys); + + $next_index = $current_index + 1; + if (isset($keys[$next_index])) { + $action = $action->withNext( + $this->required_form_step_actions[$next_index] + ); + } + + return $action->withPrevious( + $current_index > 0 + ? $this->required_form_step_actions[$keys[$current_index - 1]] + : $edit_view + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Capability.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Capability.php new file mode 100644 index 000000000000..3c6fd632099c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Capability.php @@ -0,0 +1,143 @@ +buildDoEditActionClosure() + ); + } + + #[\Override] + public function getFeedback( + Properties $answer_form_properties + ): ?Feedback { + return new Feedback( + $this->ctrl, + $this->static_url, + $this->repository + ); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): void { + $suggested_learning_content = $this->repository->getFor( + $old_answer_form_properties->getAnswerFormId() + ); + $this->repository->store( + $suggested_learning_content->clone( + $uuid_factory, + ['answer_form_id' => $new_answer_form_properties->getAnswerFormId()] + ) + ); + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): void { + } + + #[\Override] + public function onAnswerFormDelete( + Properties $answer_form_properties + ): void { + $this->repository->delete( + $answer_form_properties->getAnswerFormId() + ); + } + + private function buildDoEditActionClosure(): \Closure + { + return function ( + Environment $environment + ): Async|Viewable { + $sub_action = $environment->getSubAction(); + $overview = $this->buildOverview($environment); + if ($sub_action === '') { + return $overview; + } + + return $overview->doAction( + $sub_action + ); + }; + } + + private function buildOverview( + Environment $environment + ): Overview { + return new Overview( + $this->ctrl, + $this->rbac_system, + $this->tree, + $this->current_user, + $this->static_url, + $environment, + $this->repository + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Content.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Content.php new file mode 100644 index 000000000000..805fc7ecf949 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Content.php @@ -0,0 +1,205 @@ +target_ref_id = $decoded_content[self::KEY_TARGET_REF_ID] ?? null; + $this->sub_object_id = $decoded_content[self::KEY_SUB_OBJECT_ID] ?? null; + $this->rid = $this->irss->manage()->find( + $decoded_content[self::KEY_RID] ?? '' + ); + $this->file_title = $decoded_content[self::KEY_FILE_TITLE] ?? ''; + + } + + public function getAnswerFormId(): Uuid + { + return $this->answer_form_id; + } + + public function getType(): Types + { + return $this->type; + } + + public function withType( + Types $type + ): self { + $clone = clone $this; + $clone->type = $type; + return $clone; + } + + public function getTargetRefId(): ?int + { + return $this->target_ref_id; + } + + public function withTargetRefId( + int $target_ref_id + ): self { + $clone = clone $this; + $clone->target_ref_id = $target_ref_id; + return $clone; + } + + public function withSubObjectId( + int $sub_object_id + ): self { + $clone = clone $this; + $clone->sub_object_id = $sub_object_id; + return $clone; + } + + public function withFileInfo( + array $file_info + ): self { + $clone = clone $this; + $clone->rid = $this->irss->manage()->find($file_info[self::KEY_RID][0]); + $clone->file_title = $file_info[self::KEY_FILE_TITLE]; + return $clone; + } + + public function getContentForPresentation( + Language $lng, + \ilCtrl $ctrl, + StaticURLServices $static_url, + UIFactory $ui_factory + ): ?StandardLink { + return $this->type->present( + $lng, + $ctrl, + $static_url, + $this->irss, + $ui_factory, + $this->file_title, + $this->rid, + $this->target_ref_id, + $this->sub_object_id + ); + } + + public function getListing( + \ilCtrl $ctrl, + StaticURLServices $static_url, + Environment $environment + ): array { + $lng = $environment->getLanguage(); + + return [ + $lng->txt('type') => $this->type->getTranslatedOptionName($lng), + $lng->txt('content') => $this + ->getContentForPresentation( + $environment->getLanguage(), + $ctrl, + $static_url, + $environment->getUIFactory() + ) ?? '' + ]; + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_form_id = $environment['answer_form_id']; + return $clone; + } + + public function toStorage( + PersistenceFactory $persistence_factory + ): array { + if ($this->type === null) { + throw new \UnexpectedValueException( + 'You cannot save a Suggested Learnign Content without a Type!' + ); + } + + return [ + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $this->answer_form_id->toString() + ), + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $this->type->value + ), + $persistence_factory->value( + \ilDBConstants::T_TEXT, + json_encode($this->buildContentArray()) + ) + ]; + } + + private function buildContentArray(): array + { + $array = []; + if ($this->target_ref_id !== null) { + $array[self::KEY_TARGET_REF_ID] = $this->target_ref_id; + } + + if ($this->sub_object_id !== null) { + $array[self::KEY_SUB_OBJECT_ID] = $this->sub_object_id; + } + + if ($this->rid !== null) { + $array[self::KEY_RID] = $this->rid->serialize(); + } + + if ($this->file_title !== '') { + $array[self::KEY_FILE_TITLE] = $this->file_title; + } + + return $array; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Feedback.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Feedback.php new file mode 100644 index 000000000000..c25a21052ae3 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Feedback.php @@ -0,0 +1,112 @@ +buildFeedbackView( + $lng, + $properties, + $ui_factory + ); + } + + #[\Override] + public function getFeedbackClientSideEndPoint(): string + { + return 'il.questions.suggestedLearningContent.retrieve'; + } + + #[\Override] + public function getAllFeedbacksForClientSideCode( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + UIRenderer $ui_renderer, + RequiredCapabilities $required_capabilities, + Properties $properties + ): array { + $feedback_view = $this->buildFeedbackView( + $lng, + $properties, + $ui_factory + ); + return $feedback_view === null + ? [] + : [ + $ui_renderer->render( + $feedback_view->getUI() + ) + ]; + } + + private function buildFeedbackView( + Language $lng, + Properties $properties, + UIFactory $ui_factory + ): ?FeedbackView { + $content = $this->repository->getFor( + $properties->getAnswerFormId() + )->getContentForPresentation( + $lng, + $this->ctrl, + $this->static_url, + $ui_factory + ); + if ($content === null) { + return null; + } + + return new FeedbackView( + $ui_factory->panel()->standard( + $lng->txt('suggested_learning_content'), + $content + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Migration.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Migration.php new file mode 100644 index 000000000000..8137cd0f410e --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Migration.php @@ -0,0 +1,269 @@ +old_repository === null) { + $this->old_repository = new SuggestedSolutionsDatabaseRepository( + $migration_insert->getDb() + ); + $this->irss_migration_helper = new \ilResourceStorageMigrationHelper( + new Stakeholder(), + $environment + ); + } + + $old_suggested_learning_content = $this->old_repository->selectFor( + $migration_insert->getOldQuestionId() + )[0] ?? null; + + if ($old_suggested_learning_content === null) { + return $migration_insert; + } + + $insert = $this->buildInsertFromOldSuggestedSolution( + $migration_insert, + $old_suggested_learning_content + ); + + if ($insert === null) { + return $migration_insert; + } + + return $migration_insert->withAdditionalInsert($insert); + } + + private function buildInsertFromOldSuggestedSolution( + MigrationInsert $migration_insert, + SuggestedSolution $old_values + ): ?Insert { + $type = $this->buildNewTypeFromOld($old_values->getType()); + $content = $this->buildContentStringFromOldSuggesteSolution( + $migration_insert->getDb(), + $type, + $old_values + ); + + if ($content === null) { + return null; + } + + $pf = $migration_insert->getPersistenceFactory(); + return $pf->insert( + $this->table_definitions->getColumns( + $migration_insert->getTableNameBuilder(null), + TableTypes::SuggestedLearningContent + ), + [ + $pf->value( + FieldDefinition::T_TEXT, + $migration_insert->getAnswerFormId()->toString() + ), + $pf->value( + FieldDefinition::T_TEXT, + $type->value + ), + $pf->value( + FieldDefinition::T_TEXT, + json_encode($content) + ), + ] + ); + + } + + private function buildNewTypeFromOld( + string $old_type + ): Types { + return match($old_type) { + SuggestedSolution::TYPE_FILE => Types::File, + SuggestedSolution::TYPE_LM => Types::LearningModule, + SuggestedSolution::TYPE_LM_PAGE => Types::LearningModulePage, + SuggestedSolution::TYPE_LM_CHAPTER => Types::LearningModuleChapter, + SuggestedSolution::TYPE_GLOSARY_TERM => Types::GlossaryTerm + }; + } + + private function buildContentStringFromOldSuggesteSolution( + \ilDBInterface $db, + Types $type, + SuggestedSolution $old_values + ): ?array { + $old_parent_and_owner = $this->fetchQuestionParentAndOwnerFromDB( + $db, + $old_values->getQuestionId() + ); + if ($old_values instanceof SuggestedSolutionFile) { + $rid = $this->irss_migration_helper->movePathToStorage( + $this->buildFilePath( + $old_parent_and_owner->obj_fi, + $old_values + ), + $this->determineNewOwner( + $old_parent_and_owner->owner + ) + ); + + if ($rid === null) { + return null; + } + + return [ + Content::KEY_FILE_TITLE => $old_values->getTitle() === $old_values->getFilename() + ? '' + : $old_values->getTitle(), + Content::KEY_RID => $rid->serialize() + ]; + } + + $id = $this->parseInternalLink( + $old_values->getInternalLink() + ); + + if ($id === null) { + return null; + } + + if ($type === Types::LearningModule) { + return [ + Content::KEY_TARGET_REF_ID => $id + ]; + } + + $target_ref_id = $this->fetchTargetRefIdFromDB( + $db, + $type, + $id + ); + + if ($target_ref_id === null) { + return null; + } + + return [ + Content::KEY_TARGET_REF_ID => $target_ref_id, + Content::KEY_SUB_OBJECT_ID => $id + ]; + } + + private function fetchQuestionParentAndOwnerFromDB( + \ilDBInterface $db, + int $old_question_id + ): \stdClass { + return $db->fetchObject( + $db->queryF( + 'SELECT obj_fi, owner FROM qpl_questions WHERE question_id = %s', + [FieldDefinition::T_INTEGER], + [$old_question_id] + ) + ); + } + + private function fetchTargetRefIdFromDB( + \ilDBInterface $db, + Types $type, + int $sub_object_id + ): ?int { + if ($type === Types::LearningModulePage + || $type === Types::LearningModuleChapter) { + return $db->fetchObject( + $db->queryF( + 'SELECT object_reference.ref_id FROM lm_data' . PHP_EOL + . 'INNER JOIN object_reference' . PHP_EOL + . 'ON lm_data.lm_id = object_reference.obj_id' . PHP_EOL + . 'WHERE lm_data.obj_id = %s', + [FieldDefinition::T_INTEGER], + [$sub_object_id] + ) + )?->lm_id; + } + + return $db->fetchObject( + $db->queryF( + 'SELECT object_reference.ref_id FROM glossary_term' . PHP_EOL + . 'INNER JOIN object_reference' . PHP_EOL + . 'ON glossary_term.glo_id = object_reference.obj_id' . PHP_EOL + . 'WHERE glossary_term.id = %s', + [FieldDefinition::T_INTEGER], + [$sub_object_id] + ) + )?->glo_id ?? null; + } + + private function determineNewOwner( + int $owner + ): int { + if ($owner > 0) { + return $owner; + } + + return $this->irss_migration_helper + ->getStakeholder() + ->getOwnerOfNewResources(); + } + + private function buildFilePath( + int $parent_id, + SuggestedSolutionFile $old_values + ): string { + return \ilFileUtils::removeTrailingPathSeparators(CLIENT_WEB_DIR) + . "/assessment/{$parent_id}/{$old_values->getQuestionId()}" + . "/solution/{$old_values->getFilename()}"; + } + + private function parseInternalLink( + string $link + ): ?int { + if (preg_match("/il__\w+_(\d+)/", $link, $matches) !== 1) { + return null; + } + + return (int) $matches[1]; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/NodeRetrieval.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/NodeRetrieval.php new file mode 100644 index 000000000000..2311c9f4eed6 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/NodeRetrieval.php @@ -0,0 +1,277 @@ + + */ + private readonly array $requested_types; + + public function __construct( + private readonly \ilRbacSystem $rbac_system, + private readonly \ilTree $tree, + private readonly Environment $environment, + private readonly string $requested_type + ) { + [$this->url_builder, $this->node_parameter_token] = $environment + ->withSubActionParameter(self::SUB_ACTION_RETRIEVE_NODES) + ->getUrlBuilder() + ->acquireParameter( + self::PARAMETER_NAMESPACE, + self::PARAMETER_ID_STRING_NODE + ); + + $this->requested_types = [ + ...self::CONTAINER_CONTENT_TYPES, + $requested_type + ]; + } + + #[\Override] + public function getNodes( + NodeFactory $node_factory, + IconFactory $icon_factory, + array $sync_node_id_whitelist = [], + ?string $parent_id = null + ): \Generator { + if ($parent_id === null) { + $parent_id = ROOT_FOLDER_ID; + } + + yield from $this->buildFilteredNodes( + $node_factory, + $icon_factory, + $this->tree->getChildsByTypeFilter( + $parent_id, + $this->requested_types + ) + ); + } + + #[\Override] + public function getNodesAsLeaf( + NodeFactory $node_factory, + IconFactory $icon_factory, + array $node_ids, + ): \Generator { + foreach ($node_ids as $node_id) { + $node = $this->tree->getNodeData((int) $node_id); + yield $node_factory->leaf( + explode('.', $node['path'] ?? ''), + $node['title'] ?? $this->environment->getLanguage()->txt('invalid') + ); + } + } + + #[\Override] + public function can( + string $sub_action + ): bool { + return $sub_action === self::SUB_ACTION_RETRIEVE_NODES + && $this->environment->getHttpServices()->wrapper()->query()->has( + $this->node_parameter_token->getName() + ); + } + + #[\Override] + public function do( + string $action + ): Async { + $node_id = $this->retrieveNodeIdFromQuery(); + + $response = ''; + if ($node_id !== null) { + $response = iterator_to_array( + $this->buildFilteredNodes( + $this->environment->getUIFactory()->input()->field()->node(), + $this->environment->getUIFactory()->symbol()->icon(), + $this->tree->getChildsByTypeFilter( + $node_id, + $this->requested_types + ) + ) + ); + } + + return $this->environment->getPresentationFactory()->getAsync($response); + } + + public function buildValidNodeConstraint(): Constraint + { + return $this->environment->getRefinery()->custom()->constraint( + function (array $v): bool { + if (!isset($v[0])) { + return false; + } + $data = $this->tree->getNodeData((int) $v[0]); + return $data['type'] === $this->requested_type; + }, + function (\Closure $txt, array $v): string { + if (!isset($v[0])) { + return $txt('required'); + } + $data = $this->tree->getNodeData((int) $v[0]); + return sprintf( + $txt('invalid_node_selected'), + $txt("obj_{$data['type']}") + ); + } + ); + } + + private function buildFilteredNodes( + NodeFactory $node_factory, + IconFactory $icon_factory, + array $nodes + ): \Generator { + foreach ($nodes as $node) { + $is_visible = $this->rbac_system->checkAccess('visible', $node['ref_id']); + $is_container = in_array($node['type'], self::CONTAINER_CONTENT_TYPES); + if (!$is_container && !$is_visible) { + continue; + } + + if (!$is_container) { + yield $node_factory->leaf( + explode('.', $node['path']), + $node['title'], + $this->getIconForNodeArray( + $icon_factory, + $node + ) + ); + continue; + } + + $is_readable = $this->rbac_system->checkAccess('read', $node['ref_id']); + if ($is_visible && $is_readable && $node['parent'] === ROOT_FOLDER_ID) { + yield $node_factory->branch( + explode('.', $node['path']), + $node['title'], + $this->getIconForNodeArray( + $icon_factory, + $node + ), + ...$this->buildFilteredNodes( + $node_factory, + $icon_factory, + $this->tree->getChildsByTypeFilter( + $node['ref_id'], + $this->requested_types + ) + ) + ); + continue; + } + + if ($is_visible && $is_readable) { + yield $node_factory->async( + $this->getAsyncNodeRenderUrl($node['ref_id']), + explode('.', $node['path']), + $node['title'], + $this->getIconForNodeArray( + $icon_factory, + $node + ) + ); + continue; + } + + if ($is_readable) { + yield from $this->buildFilteredNodes( + $node_factory, + $icon_factory, + $this->tree->getChildsByTypeFilter( + $node['ref_id'], + $this->requested_types + ) + ); + } + } + } + + private function getAsyncNodeRenderUrl( + int $node_id + ): URI { + return $this->url_builder->withParameter( + $this->node_parameter_token, + (string) $node_id + )->buildURI(); + } + + private function retrieveNodeIdFromQuery(): ?int + { + $refinery = $this->environment->getRefinery(); + + return $this->environment + ->getHttpServices() + ->wrapper() + ->query() + ->retrieve( + $this->node_parameter_token->getName(), + $refinery->byTrying([ + $refinery->kindlyTo()->int(), + $refinery->always(null) + ]) + ); + } + + private function getIconForNodeArray( + IconFactory $icon_factory, + array $node + ): StandardIcon { + return $icon_factory->standard( + $node['type'], + $this->environment->getLanguage()->txt( + "obj_{$node['type']}" + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Overview.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Overview.php new file mode 100644 index 000000000000..75206e73a8c0 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Overview.php @@ -0,0 +1,361 @@ +environment->getUIFactory()->listing()->descriptive( + $this->repository->getFor( + $this->environment->getAnswerFormId() + )->getListing( + $this->ctrl, + $this->static_url, + $this->environment + ) + ) + ]; + + if ($this->environment->getEditability() === Editability::Full) { + $prompt = $this->buildPrompt(); + $content[] = $prompt; + $content[] = $this->environment->getUIFactory()->button()->standard( + $this->environment->getLanguage()->txt('edit'), + $prompt->getShowSignal() + ); + } + + return $this->environment->getUIFactory()->panel()->standard( + $this->environment->getLanguage()->txt('suggested_learning_content'), + $content + ); + } + + public function doAction( + string $action + ): Async { + return match($action) { + self::SUB_ACTION_SELECT_TYPE => $this->buildPromptShowAsync( + $this->buildSelectTypeForm() + ), + self::SUB_ACTION_SELECT_CONTENT => $this->processSelectTypeForm(), + self::SUB_ACTION_SAVE_CONTENT => $this->processSelectContentForm(), + self::SUB_ACTION_SAVE_SUB_CONTENT => $this->processSelectSubContentForm(), + default => $this->forwardActionToActors($action) + }; + } + + private function buildPrompt(): Prompt + { + return $this->environment->getUIFactory()->prompt()->standard( + $this->environment->withSubActionParameter( + self::SUB_ACTION_SELECT_TYPE + )->getUrlBuilder()->buildURI() + ); + } + + private function forwardActionToActors( + string $action + ): Async { + $node_retrieval = new NodeRetrieval( + $this->rbac_system, + $this->tree, + $this->environment, + $this->retrieveReferencedObjectTypeFromCarry() + ); + + if ($node_retrieval->can($action)) { + return $node_retrieval->do($action); + } + + $upload_handler = $this->environment->getPresentationFactory()->getUploadHandler( + $this->environment, + new Stakeholder( + $this->current_user->getId() + ) + ); + + if ($upload_handler->can($action)) { + return $upload_handler->do($action); + } + + throw new \InvalidArgumentException( + "No actor found that can '{$action}'" + ); + } + + private function buildSelectTypeForm(): StandardForm + { + $uf = $this->environment->getUIFactory(); + + return $uf->input()->container()->form()->standard( + $this->environment->withSubActionParameter( + self::SUB_ACTION_SELECT_CONTENT + )->getUrlBuilder()->buildURI()->__toString(), + [ + 'type' => $this->buildTypeSelect() + ] + )->withSubmitLabel( + $this->environment->getLanguage()->txt('next') + ); + } + + private function processSelectTypeForm(): Async + { + $form = $this->buildSelectTypeForm()->withRequest( + $this->environment->getHttpServices()->request() + ); + $data = $form->getData(); + if ($data === null) { + return $this->buildPromptShowAsync($form); + ; + } + + if ($data['type'] === Types::None) { + $this->repository->delete( + $this->environment->getAnswerFormId() + ); + return $this->buildRedirectToOverviewAsync(); + } + + $inputs_builder = $this->buildInputsBuilderSelectContentForm() + ->withCarry($data['type']->value); + $inputs_builder->persistCarry(); + + return $this->buildPromptShowAsync( + $this->buildSelectContentForm($inputs_builder) + ); + } + + private function buildSelectContentForm( + InputsBuilderSession $inputs_builder + ): StandardForm { + $uf = $this->environment->getUIFactory(); + + $form = $uf->input()->container()->form()->standard( + $this->environment->withSubActionParameter( + self::SUB_ACTION_SAVE_CONTENT + )->getUrlBuilder()->buildURI()->__toString(), + [ + 'content' => $inputs_builder->getInputs() + ] + ); + + $type = $inputs_builder->retrieveCarry( + $this->environment->getRefinery()->custom()->transformation( + fn(string $v): Types => Types::tryFrom($v) + ) + ); + if ($type->hasSelectContentSubForm()) { + return $form->withSubmitLabel( + $this->environment->getLanguage()->txt('next') + ); + } + return $form; + } + + private function processSelectContentForm(): Async + { + $select_content_inputs_builder = $this->buildInputsBuilderSelectContentForm(); + $form = $this->buildSelectContentForm( + $select_content_inputs_builder + )->withRequest( + $this->environment->getHttpServices()->request() + ); + $data = $form->getData(); + if ($data === null) { + $select_content_inputs_builder->persistCarry(); + return $this->buildPromptShowAsync($form); + } + + if (!$data['content']->getType()->hasSelectContentSubForm()) { + $this->repository->store($data['content']); + return $this->buildRedirectToOverviewAsync(); + } + + $select_sub_content_inputs_builder = $this + ->buildInputsBuilderSelectSubContentForm() + ->withCarry( + json_encode([ + 'type' => $data['content']->getType()->value, + 'target_ref_id' => $data['content']->getTargetRefId() + ]) + ); + $select_sub_content_inputs_builder->persistCarry(); + + return $this->buildPromptShowAsync( + $this->buildSelectSubContentForm($select_sub_content_inputs_builder) + ); + } + + private function buildSelectSubContentForm( + InputsBuilderSession $inputs_builder + ): StandardForm { + $uf = $this->environment->getUIFactory(); + + $form = $uf->input()->container()->form()->standard( + $this->environment->withSubActionParameter( + self::SUB_ACTION_SAVE_SUB_CONTENT + )->getUrlBuilder()->buildURI()->__toString(), + [ + 'content' => $inputs_builder->getInputs() + ] + ); + return $form; + } + + private function processSelectSubContentForm(): Async + { + $inputs_builder = $this->buildInputsBuilderSelectSubContentForm(); + $form = $this->buildSelectSubContentForm( + $inputs_builder + )->withRequest( + $this->environment->getHttpServices()->request() + ); + $data = $form->getData(); + if ($data === null) { + $inputs_builder->persistCarry(); + return $this->buildPromptShowAsync($form); + } + + $this->repository->store($data['content']); + return $this->buildRedirectToOverviewAsync(); + } + + private function buildTypeSelect(): Select + { + return $this->environment->getUIFactory()->input()->field()->select( + $this->environment->getLanguage()->txt('type'), + Types::buildOptionsList( + $this->environment->getLanguage() + ) + )->withAdditionalTransformation( + $this->environment->getRefinery()->custom()->transformation( + fn(string $v): Types => Types::tryFrom($v) ?? Types::None + ) + )->withRequired(true); + } + + private function buildInputsBuilderSelectContentForm(): InputsBuilderSession + { + return $this->environment->getPresentationFactory() + ->getSessionBasedInputsBuilder( + $this->environment->getRefinery()->custom()->transformation( + fn(string $v): Section + => Types::tryFrom($v)->buildContentInput( + $this->repository, + $this->rbac_system, + $this->tree, + $this->environment, + $this->current_user->getId() + ) + ) + ); + } + + private function buildInputsBuilderSelectSubContentForm(): InputsBuilderSession + { + return $this->environment->getPresentationFactory() + ->getSessionBasedInputsBuilder( + $this->environment->getRefinery()->custom()->transformation( + function (string $v): Section { + $v_array = json_decode($v, true); + return Types::tryFrom($v_array['type'])->buildSubContentInput( + $this->repository, + $this->rbac_system, + $this->environment, + $v_array['target_ref_id'] + ); + } + ) + ); + } + + private function buildPromptShowAsync( + StandardForm $form + ): Async { + $lng = $this->environment->getLanguage(); + + return $this->environment->getPresentationFactory()->getAsync( + $this->environment->getUIFactory()->prompt()->state()->show( + $form + )->withTitle( + $lng->txt('edit_suggested_learning_content') + ) + ); + } + + private function buildRedirectToOverviewAsync(): Async + { + return $this->environment->getPresentationFactory()->getAsync( + $this->environment->getUIFactory()->prompt()->state()->redirect( + $this->environment + ->withDefaultSubAction() + ->getUrlBuilder() + ->buildURI() + ) + ); + } + + private function retrieveReferencedObjectTypeFromCarry(): string + { + $inputs_builder = $this->buildInputsBuilderSelectContentForm(); + $inputs_builder->persistCarry(); + + return $inputs_builder->retrieveCarry( + $this->environment->getRefinery()->custom()->transformation( + fn(string $v): string => Types::tryFrom($v) + ->getReferencedObjectType() + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Repository.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Repository.php new file mode 100644 index 000000000000..79571ff0d84c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Repository.php @@ -0,0 +1,169 @@ +table_names_builder = new TableNameBuilder( + QuestionRepository::COMPONENT_NAMESPACE, + null + ); + } + + public function getNew( + Uuid $answer_form_id, + Types $type + ): Content { + return new Content( + $this->irss, + $answer_form_id, + $type, + '' + ); + } + + public function getFor( + Uuid $answer_form_id, + ): Content { + $database_values = $this->buildQuery( + $answer_form_id + )->getRecords()->current(); + + if ($database_values === null) { + return $this->getNew( + $answer_form_id, + Types::None + ); + } + + return $database_values->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ), + $this->refinery->custom()->transformation( + fn(array $vs): Content => new Content( + $this->irss, + $answer_form_id, + Types::tryFrom($vs[0]['type']), + $vs[0]['content'] + ) + ) + ); + } + + public function store( + Content $content + ): void { + (new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ))->withAdditionalStatement( + $this->persistence_factory->replace( + $this->table_definitions->getColumns( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ), + $content->toStorage( + $this->persistence_factory + ) + ) + )->run(); + } + + public function delete( + Uuid $answer_form_id + ): void { + (new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ))->withAdditionalStatement( + $this->persistence_factory->delete( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ), + [ + $this->persistence_factory->where( + $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ) + ] + ) + )->run(); + } + + private function buildQuery( + Uuid $answer_form_id + ): Query { + return $this->table_definitions->completeQuery( + new Query( + $this->db, + $this->refinery, + QuestionRepository::COMPONENT_NAMESPACE, + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ) + ), + $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ) + )->withAdditionalWhere( + $this->persistence_factory->where( + $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::SuggestedLearningContent + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Stakeholder.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Stakeholder.php new file mode 100644 index 000000000000..2c5c79794ba8 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/Stakeholder.php @@ -0,0 +1,39 @@ + + */ +class Stakeholder extends AbstractResourceStakeholder +{ + public function getId(): string + { + return 'questions_suggested_learning_content'; + } + + public function getOwnerOfNewResources(): int + { + return $this->default_owner; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableDefinitions.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableDefinitions.php new file mode 100644 index 000000000000..001213a858bd --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableDefinitions.php @@ -0,0 +1,100 @@ +persistence_factory->table( + $table_names_builder, + $table_type + ); + return array_map( + fn(string $v): Column => $this->persistence_factory->column( + $table, + $v + ), + self::SUGGESTED_LEARNING_CONTENT_TABLE_COLUMNS + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type + ); + + return $this->persistence_factory->column( + $table, + self::SUGGESTED_LEARNING_CONTENT_TABLE_ID_COLUMN + ); + } + + public function completeQuery( + Query $query, + ?Column $base_table_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder(null); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::SuggestedLearningContent + ) + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $base_table_id_column + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableTypes.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableTypes.php new file mode 100644 index 000000000000..dd42118ae452 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/SuggestedLearningContent/TableTypes.php @@ -0,0 +1,28 @@ + $lng->txt('glossary_term'), + default => $lng->txt($this->value) + }; + } + + public static function buildOptionsList( + Language $lng + ): array { + return array_reduce( + self::cases(), + function (array $c, Types $v) use ($lng): array { + if ($v === Types::None) { + return $c; + } + $c[$v->value] = $v->getTranslatedOptionName($lng); + return $c; + }, + [] + ); + } + + public function present( + Language $lng, + \ilCtrl $ctrl, + StaticURLServices $static_url, + IRSS $irss, + UIFactory $ui_factory, + string $file_title, + ?ResourceIdentification $rid, + ?int $target_ref_id, + ?int $sub_object_id + ): ?StandardLink { + return match($this) { + self::File => $ui_factory->link()->standard( + $file_title === '' + ? $irss->manage()->getResource($rid)->getCurrentRevision()->getTitle() + : $file_title, + $irss->consume()->src($rid)->getSrc(true) + ), + self::LearningModule => $this->buildLinkToLearningModule( + $ctrl, + $lng, + $ui_factory->link(), + $target_ref_id + ), + self::LearningModulePage, + self::LearningModuleChapter, + self::GlossaryTerm => $this->buildLinkToSubObject( + $lng, + $ui_factory->link(), + $static_url, + $target_ref_id, + $sub_object_id + ), + self::None => null + }; + } + + public function getReferencedObjectType(): string + { + return match ($this) { + self::LearningModule, + self::LearningModuleChapter, + self::LearningModulePage => 'lm', + self::GlossaryTerm => 'glo', + default => '' + }; + } + + public function hasSelectContentSubForm(): bool + { + return $this !== self::LearningModule && $this !== self::File; + } + + public function buildContentInput( + Repository $repository, + \ilRbacSystem $rbac_system, + \ilTree $tree, + Environment $environment, + int $current_user_id + ): Section { + return match($this) { + self::File => $this->buildUploadFileInput( + $repository, + $environment, + $current_user_id + ), + default => $this->buildSelectObjectInput( + $repository, + $rbac_system, + $tree, + $environment, + $this->getReferencedObjectType() + ) + }; + } + + public function buildSubContentInput( + Repository $repository, + \ilRbacSystem $rbac_system, + Environment $environment, + int $target_ref_id + ): Section { + if (!$this->hasSelectContentSubForm()) { + throw new InvalidArgumentException( + 'This type of SuggestedLearningContent does not provide a SubContentInput.' + ); + } + + $ff = $environment->getUIFactory()->input()->field(); + $lng = $environment->getLanguage(); + + return $ff->section( + [ + 'sub_object' => $ff->select( + $this->getTranslatedOptionName($lng), + $this->buildSubContentOptions( + $rbac_system, + $target_ref_id + ) + )->withRequired(true) + ], + $lng->txt('select_target') + )->withAdditionalTransformation( + $environment->getRefinery()->custom()->transformation( + fn(array $vs): Content => $repository->getNew( + $environment->getAnswerFormId(), + $this + )->withTargetRefId($target_ref_id) + ->withSubObjectId((int) $vs['sub_object']) + ) + ); + } + + private function buildLinkToLearningModule( + \ilCtrl $ctrl, + Language $lng, + LinkFactory $link_factory, + int $target_ref_id + ): StandardLink { + $ctrl->setParameterByClass( + \ilLMPresentationGUI::class, + 'ref_id', + $target_ref_id + ); + + $link = $link_factory->standard( + "{$this->getTranslatedOptionName($lng)}: {$this->lookupObjectTitle($target_ref_id)}", + $ctrl->getLinkTargetByClass( + [ + \ilLMPresentationGUI::class + ], + ) + ); + $ctrl->clearParameterByClass( + \ilLMPresentationGUI::class, + 'ref_id' + ); + return $link; + } + + private function buildLinkToSubObject( + Language $lng, + LinkFactory $link_factory, + StaticURLServices $static_url, + int $target_ref_id, + int $sub_object_id + ): StandardLink { + $sub_object_title = match($this) { + self::GlossaryTerm => ( + new \ilGlossaryTerm($sub_object_id) + )->getTerm(), + default => \ilLMObject::_lookupTitle( + $sub_object_id + ) + }; + + return $link_factory->standard( + "{$this->getTranslatedOptionName($lng)}: {$this->lookupObjectTitle($target_ref_id)} - {$sub_object_title}", + $static_url->builder()->build( + $this->value, + null, + [$sub_object_id] + )->__toString() + ); + } + + private function lookupObjectTitle( + int $target_ref_id + ): string { + return \ilObject::_lookupTitle( + \ilObject::_lookupObjId($target_ref_id) + ); + } + + private function buildUploadFileInput( + Repository $repository, + Environment $environment, + int $current_user_id + ): Section { + $ff = $environment->getUIFactory()->input()->field(); + $lng = $environment->getLanguage(); + + return $ff->section( + [ + Content::KEY_FILE_TITLE => $ff->text( + $lng->txt('title'), + $lng->txt('if_no_title_then_filename') + ), + Content::KEY_RID => $ff->file( + $environment->getPresentationFactory()->getUploadHandler( + $environment, + new Stakeholder($current_user_id) + ), + $lng->txt('file') + )->withRequired(true) + ], + $lng->txt('upload_file') + )->withAdditionalTransformation( + $environment->getRefinery()->custom()->transformation( + fn(array $vs): Content => $repository->getNew( + $environment->getAnswerFormId(), + $this + )->withFileInfo($vs) + ) + ); + } + + private function buildSelectObjectInput( + Repository $repository, + \ilRbacSystem $rbac_system, + \ilTree $tree, + Environment $environment, + string $type + ): Section { + $ff = $environment->getUIFactory()->input()->field(); + $lng = $environment->getLanguage(); + + $node_retrieval = new NodeRetrieval( + $rbac_system, + $tree, + $environment, + $type + ); + + return $ff->section( + [ + 'object' => $ff->treeSelect( + $node_retrieval, + $lng->txt('select') + )->withAdditionalTransformation( + $node_retrieval->buildValidNodeConstraint() + ) + ], + $this->getTranslatedOptionName($lng) + )->withAdditionalTransformation( + $environment->getRefinery()->custom()->transformation( + fn(array $vs): Content => $repository->getNew( + $environment->getAnswerFormId(), + $this + )->withTargetRefId((int) $vs['object'][0]) + ) + ); + } + + private function buildSubContentOptions( + \ilRbacSystem $rbac_system, + int $target_ref_id + ): array { + if (!$rbac_system->checkAccess('read', $target_ref_id)) { + return []; + } + + return match ($this) { + self::GlossaryTerm => array_reduce( + (new \ilObjGlossary($target_ref_id))->getTermList(), + function (array $c, array $v): array { + $c[$v['id']] = $v['term']; + return $c; + }, + [] + ), + self::LearningModulePage, + self::LearningModuleChapter => array_reduce( + \ilLMObject::getObjectList( + \ilObject::_lookupObjectId($target_ref_id), + $this === self::LearningModuleChapter + ? 'st' + : 'pg' + ), + function (array $c, array $v): array { + $c[$v['obj_id']] = $v['title']; + return $c; + }, + [] + ) + }; + + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Capability.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Capability.php new file mode 100644 index 000000000000..ca02e412dae1 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Capability.php @@ -0,0 +1,233 @@ +getTypeGenericProperties() + ->getDefinition() + ->hasCapability( + self::getIdentifier() + ); + } + + #[\Override] + public function getAnswerFormEditAdditionalTab(): ActionWithTab + { + return new ActionWithTab( + $this, + 'feedback', + $this->buildDoEditActionClosure() + ); + } + + #[\Override] + public function getFeedback( + Properties $answer_form_properties + ): ?Feedback { + return $this->retrieveMigratedFeedback( + $answer_form_properties->getAnswerFormId(), + $answer_form_properties + ->getTypeGenericProperties() + ->getDefinition() + ->getCapability( + self::getIdentifier() + ) + ); + } + + #[\Override] + public function runPageMigration(): void + { + $this->repository->migratePageFeedback(); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): void { + $this->repository->store( + $new_answer_form_properties->getAnswerFormId(), + $this->repository->getFor( + $old_answer_form_properties->getAnswerFormId(), + $old_answer_form_properties + ->getTypeGenericProperties() + ->getDefinition() + ->getCapability(self::getIdentifier()) + )->onAnswerFormClone( + $uuid_factory, + $old_answer_form_properties, + $new_answer_form_properties + ) + ); + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): void { + $this->repository->store( + $answer_form_properties->getAnswerFormId(), + $this->repository->getFor( + $answer_form_properties->getAnswerFormId(), + $answer_form_properties + ->getTypeGenericProperties() + ->getDefinition() + ->getCapability(self::getIdentifier()) + )->onAnswerFormUpdate( + $answer_form_properties + ) + ); + } + + public function onAnswerFormDelete( + Properties $answer_form_properties + ): void { + $this->repository->delete( + $answer_form_properties->getAnswerFormId() + ); + } + + private function buildDoEditActionClosure(): \Closure + { + return function ( + Environment $environment + ): Async|Viewable { + $sub_action = $environment->getSubAction(); + return match ($sub_action) { + '' => $this->buildOverview($environment), + self::SUB_ACTION_INSERT_LEGACY_TEXTS => $this->buildOverviewWithLegacyTexts( + $environment + ), + self::SUB_ACTION_SAVE => $this->save($environment), + default => $this->buildOverview($environment)->doAction( + $this->repository, + $sub_action + ) + }; + }; + } + + private function buildOverview( + Environment $environment + ): Overview { + return new Overview( + $environment, + $this->text_factory, + $this->retrieveMigratedFeedback( + $environment->getAnswerFormId(), + $environment + ->getAnswerFormProperties() + ->getTypeGenericProperties() + ->getDefinition() + ->getCapability(self::getIdentifier()) + ), + $environment->withSubActionParameter( + self::SUB_ACTION_SAVE + )->getUrlBuilder(), + $environment->withSubActionParameter( + self::SUB_ACTION_INSERT_LEGACY_TEXTS + )->getUrlBuilder() + ); + } + + private function buildOverviewWithLegacyTexts( + Environment $environment + ): Overview { + return $this->buildOverview($environment) + ->withLegacyTextsAsValues(true); + } + + private function save( + Environment $environment + ): Overview { + $feedback = $this->buildOverview($environment)->processForm(); + if ($feedback instanceof Overview) { + return $feedback; + } + + $this->repository->store( + $environment->getAnswerFormId(), + $feedback + ); + + return $environment->redirectTo( + $environment->withDefaultSubAction()->getUrlBuilder() + ); + } + + private function retrieveMigratedFeedback( + Uuid $answer_form_id, + TextFeedback $feedback + ): TextFeedback { + $feedback_with_data = $this->repository->getFor( + $answer_form_id, + $feedback + ); + + if ($feedback_with_data->requiresPageMigration()) { + $feedback_with_data = $feedback_with_data->withMigratedPageFeedbacks(); + $this->repository->store( + $answer_form_id, + $feedback_with_data + ); + } + + return $feedback_with_data; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Migration.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Migration.php new file mode 100644 index 000000000000..36282fb85ed8 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Migration.php @@ -0,0 +1,393 @@ +buildGenericFeedbackInsert( + $migration_insert->getPersistenceFactory(), + $migration_insert + ); + if ($generic_feedback_insert !== null) { + $migration_insert = $migration_insert + ->withAdditionalInsert( + $generic_feedback_insert + ); + } + + $specific_feedback_insert = $this->buildSpecificFeedbackInsert( + $migration_insert->getPersistenceFactory(), + $answer_form_migration, + $migration_insert + ); + if ($specific_feedback_insert !== null) { + $migration_insert = $migration_insert + ->withAdditionalInsert( + $specific_feedback_insert + ); + } + + return $migration_insert; + } + + private function fetchGenericFeedbackDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->queryF( + 'SELECT * FROM qpl_fb_generic WHERE question_fi = %s ORDER BY question_fi', + [FieldDefinition::T_INTEGER], + [$old_question_id] + ); + + yield from $this->fetchFeedbacksForQuestions($db, $query); + } + + private function fetchSpecificFeedbackDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->queryF( + 'SELECT * FROM qpl_fb_specific WHERE question_fi = %s ORDER BY question_fi', + [FieldDefinition::T_INTEGER], + [$old_question_id] + ); + + yield from $this->fetchFeedbacksForQuestions($db, $query); + } + + private function fetchFeedbacksForQuestions( + \ilDBInterface $db, + \ilDBStatement $query + ): \Generator { + $feedbacks_for_question = null; + while (($row = $db->fetchAssoc($query)) !== null) { + if ($feedbacks_for_question === null) { + $feedbacks_for_question = [$row]; + continue; + } + + if ($feedbacks_for_question[0]['question_fi'] === $row['question_fi']) { + $feedbacks_for_question[] = $row; + continue; + } + + yield $feedbacks_for_question; + $feedbacks_for_question = [$row]; + } + + if ($feedbacks_for_question !== null) { + yield $feedbacks_for_question; + } + } + + private function buildGenericFeedbackInsert( + PersistenceFactory $persistence_factory, + MigrationInsert $migration_insert + ): ?Insert { + $insert = null; + foreach ($this->fetchGenericFeedbackDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $feedback_for_question) { + $insert = $this->addGenericFeedbackToInsert( + $persistence_factory, + $migration_insert, + $insert, + $feedback_for_question + ); + } + + return $insert; + } + + private function addGenericFeedbackToInsert( + PersistenceFactory $persistence_factory, + MigrationInsert $migration_insert, + ?Insert $insert, + array $feedback_for_question + ): Insert { + $values = $this->buildNewGenericFeedbackValuesFromOld( + $persistence_factory, + $migration_insert, + $feedback_for_question + ); + + if ($insert === null) { + return $persistence_factory->insert( + $this->table_definitions->getColumns( + $migration_insert->getTableNameBuilder(null), + TableTypes::FeedbackGeneric + ), + $values + ); + } + + return $insert->withAdditionalValues($values); + } + + private function buildNewGenericFeedbackValuesFromOld( + PersistenceFactory $persistence_factory, + MigrationInsert $migration_insert, + array $feedback_for_question + ): array { + $page_editor_used = $migration_insert->wasIliasPageEditorUsedForAdditionalTexts(); + + $feedback_best_response = ''; + $feedback_other_response = ''; + foreach ($feedback_for_question as $feedback_row) { + $feedback_text = $this->generateTextValueForFeedback( + $migration_insert->getDb(), + $page_editor_used, + $feedback_row['feedback_id'], + $feedback_row['feedback'] + ); + if ($feedback_row['correctness'] === '1') { + $feedback_best_response = $feedback_text; + continue; + } + $feedback_other_response = $feedback_text; + } + + return [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $migration_insert->getAnswerFormId()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + '' + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $feedback_best_response, + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + '' + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $feedback_other_response + ) + ]; + } + + private function buildSpecificFeedbackInsert( + PersistenceFactory $persistence_factory, + AnswerFormMigration $answer_form_migration, + MigrationInsert $migration_insert + ): ?Insert { + $insert = null; + foreach ($this->fetchSpecificFeedbackDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $feedback_for_question) { + $insert = $this->addSpecificFeedbackToInsert( + $persistence_factory, + $answer_form_migration, + $migration_insert, + $insert, + $feedback_for_question + ); + } + + return $insert; + } + + private function addSpecificFeedbackToInsert( + PersistenceFactory $persistence_factory, + AnswerFormMigration $answer_form_migration, + MigrationInsert $migration_insert, + ?Insert $insert, + array $feedback_for_question + ): ?Insert { + $values = $this->buildNewSpecificFeedbackValuesFromOld( + $persistence_factory, + $answer_form_migration, + $migration_insert, + $feedback_for_question + ); + + if ($values === []) { + return $insert; + } + + if ($insert === null) { + $insert = $persistence_factory->insert( + $this->table_definitions->getColumns( + $migration_insert->getTableNameBuilder(null), + TableTypes::FeedbackSpecific + ), + array_shift($values) + ); + } + + return array_reduce( + $values, + fn(Insert $c, array $v): Insert + => $c->withAdditionalValues($v), + $insert + ); + } + + private function buildNewSpecificFeedbackValuesFromOld( + PersistenceFactory $persistence_factory, + AnswerFormMigration $answer_form_migration, + MigrationInsert $migration_insert, + array $feedback_for_question + ): array { + $conditions = array_reduce( + $feedback_for_question, + function ( + array $c, + array $v + ) use ( + $answer_form_migration, + $migration_insert + ): array { + $parent_id = $answer_form_migration->getNewAnswerInputIdForOld( + $v['question'] + ); + + $conditions = $answer_form_migration->getConditionsForFeedbackFromOldValues( + $v['answer'], + $v['question'] + ); + + if ($parent_id === null || $conditions === null) { + return $c; + } + + if (!array_key_exists($parent_id->toString(), $c)) { + $c[$parent_id->toString()] = []; + } + + /* + * sk, 2026-06-09: We got rid of the option to set a value and a + * range on numeric gaps. We now need to make sure that we do not + * have feedback for both. If there is feedback for both only the + * first one is kept. I do not see a better solution. + */ + if ($conditions[0] === Range::InRange->value + && array_filter( + $c[$parent_id->toString()], + fn(array $v): bool => $v['conditions'][0] === Range::InRange->value + ) !== []) { + return $c; + } + + $c[$parent_id->toString()][] = [ + 'conditions' => $conditions, + 'text' => $this->generateTextValueForFeedback( + $migration_insert->getDb(), + $migration_insert->wasIliasPageEditorUsedForAdditionalTexts(), + $v['feedback_id'], + $v['feedback'] + ) + ]; + + return $c; + }, + [] + ); + + $inserts = []; + foreach ($conditions as $parent_id => $definitions) { + foreach ($definitions as $definition) { + foreach ($definition['conditions'] as $condition) { + $inserts[] = [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $migration_insert->getUuid()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $migration_insert->getAnswerFormId()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $parent_id + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $condition + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + '' + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->sanitizeLegacyText( + $migration_insert->getDb(), + $definition['text'], + $migration_insert->wasIliasPageEditorUsedForAdditionalTexts() + ) + ), + ]; + } + } + } + + return $inserts; + } + + private function generateTextValueForFeedback( + \ilDBInterface $db, + bool $page_editor_used, + int $feedback_id, + string $feedback_text + ): string { + if ($page_editor_used) { + return "####{$feedback_id}####"; + } + + return $this->sanitizeLegacyText( + $db, + $feedback_text, + $page_editor_used + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Overview.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Overview.php new file mode 100644 index 000000000000..3d6dd44f9351 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Overview.php @@ -0,0 +1,228 @@ +specific_feedback_table = $feedback->getSpecificFeedbackTable( + $environment + ); + } + + #[\Override] + public function getUI(): array + { + $ui_factory = $this->environment->getUIFactory(); + $lng = $this->environment->getLanguage(); + + $content = []; + + if ($this->feedback->hasLegacyTexts() + && !$this->set_legacy_texts_as_values) { + $content[] = $ui_factory->messageBox()->info( + $lng->txt('insert_legacy_texts_info') + )->withButtons([ + $ui_factory->button()->standard( + $lng->txt('insert_legacy_texts'), + $this->insert_legacy_texts_uri->buildURI()->__toString() + ) + ]); + } + + $form = $this->form ?? $this->buildForm(); + if ($form !== null) { + $content[] = $form; + } + + if ($this->specific_feedback_table !== null) { + $modal = $this->specific_feedback_table->getCreateModal( + $this->environment + ); + $content[] = $ui_factory->button()->standard( + $lng->txt('create_feedback'), + $modal->getShowSignal() + ); + $content[] = $modal; + $content[] = $this->specific_feedback_table->getTable( + $this->environment, + $this->feedback + )->withTitle( + $lng->txt('specific_feedback') + ); + } + + if ($this->modal !== null) { + $content[] = $this->modal; + } + return $content; + } + + public function withLegacyTextsAsValues( + bool $replace_with_legacy_texts + ): self { + $clone = clone $this; + $clone->set_legacy_texts_as_values = $replace_with_legacy_texts; + return $clone; + } + + public function processForm(): TextFeedback|StandardForm + { + $this->form = $this->buildForm()?->withRequest( + $this->environment->getHttpServices()->request() + ); + $data = $this->form?->getData(); + + return $data === null + ? $this + : $data['feedback']; + } + + public function doAction( + Repository $repository, + string $action + ): Async|self { + $result = $this->specific_feedback_table->doAction( + $this->environment, + $this->feedback, + $action + ); + + if ($result instanceof Async) { + return $result; + } + + $clone = clone $this; + if ($result instanceof RoundTripModal) { + $clone->modal = $result->withOnLoad($result->getShowSignal()); + return $clone; + } + + $repository->store($this->environment->getAnswerFormId(), $result); + $clone->feedback = $result; + $clone->specific_feedback_table = $result->getSpecificFeedbackTable( + $this->environment + ); + return $clone; + } + + private function buildForm(): ?StandardForm + { + $if = $this->environment->getUIFactory()->input(); + $lng = $this->environment->getLanguage(); + + $inputs = $this->buildGenericFormInputs(); + + $additional_inputs = $this->feedback->getAdditionalInputs( + $lng, + $this->environment->getUIFactory(), + $this->set_legacy_texts_as_values + ); + + if ($additional_inputs !== null) { + $inputs['specific_feedback'] = $if->field()->section( + $additional_inputs, + $lng->txt('edit_specific_feedback') + ); + } + + if ($inputs === []) { + return null; + } + + return $if->container()->form()->standard( + $this->save_uri->buildURI()->__toString(), + [ + 'feedback' => $if->field()->group( + $inputs + )->withAdditionalTransformation( + $this->environment->getRefinery()->custom()->transformation( + fn(array $vs): TextFeedback => ($vs['specific_feedback'] ?? $this->feedback) + ->withFeedbackBestResponse( + $this->text_factory->markdown($vs['generic_feedback']['max_points']) + )->withFeedbackOtherResponse( + $this->text_factory->markdown($vs['generic_feedback']['not_max_points']) + ) + ) + ) + ] + ); + } + + private function buildGenericFormInputs(): array + { + if (!$this->environment->isMarkingRequired()) { + return []; + } + + $if = $this->environment->getUIFactory()->input(); + $lng = $this->environment->getLanguage(); + + return [ + 'generic_feedback' => $if->field()->section( + [ + 'max_points' => $if->field()->markdown( + new \ilUIMarkdownPreviewGUI(), + Types::BestResponse->getTranslatedOptionName($lng) + )->withValue( + $this->set_legacy_texts_as_values + ? $this->environment->getRefinery()->string()->stripTags()->transform( + $this->feedback->getFeedbackBestResponseLegacy() + ) : $this->feedback->getFeedbackBestResponse() + ?->getRawRepresentation() ?? '' + ), + 'not_max_points' => $if->field()->markdown( + new \ilUIMarkdownPreviewGUI(), + Types::OtherResponse->getTranslatedOptionName($lng) + )->withValue( + $this->set_legacy_texts_as_values + ? $this->environment->getRefinery()->string()->stripTags()->transform( + $this->feedback->getFeedbackOtherResponseLegacy() + ) : $this->feedback->getFeedbackOtherResponse() + ?->getRawRepresentation() ?? '' + ), + ], + $lng->txt('edit_generic_feedback') + ) + ]; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/OverviewTable.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/OverviewTable.php new file mode 100644 index 000000000000..e0fb1a05607a --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/OverviewTable.php @@ -0,0 +1,44 @@ +feedback_table_names_builder = new TableNameBuilder( + QuestionRepository::COMPONENT_NAMESPACE, + null + ); + } + + public function getFor( + Uuid $answer_form_id, + TextFeedback $feedback + ): TextFeedback { + $database_values = $this + ->buildQuery() + ->withAdditionalWhere( + $this->persistence_factory->where( + $this->feedback_table_definitions->getIdColumn( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ) + )->withGroupBy( + $this->feedback_table_definitions->getIdColumn( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ) + )->getRecords()->current(); + + if ($database_values === null) { + return $feedback; + } + + $feedback_with_generic_values = $database_values->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ), + $this->refinery->custom()->transformation( + fn(array $vs): TextFeedback => $feedback->withGenericFeedbackFromDatabase( + $this->text_factory, + $vs + ) + ) + ); + + return $feedback_with_generic_values->withSpecificFeedbackFromDatabase( + $this->uuid_factory, + $this->text_factory, + $database_values->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->feedback_table_names_builder, + TableTypes::FeedbackSpecific + ), + $this->refinery->identity() + ) + ); + } + + public function store( + Uuid $answer_form_id, + TextFeedback $feedback + ): void { + $feedback->toStorage( + $this->persistence_factory, + $this->feedback_table_definitions, + $this->feedback_table_names_builder, + $answer_form_id, + new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ) + )->run(); + } + + public function delete( + Uuid $answer_form_id + ): void { + (new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ))->withAdditionalStatement( + $this->persistence_factory->delete( + $this->persistence_factory->table( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ), + [ + $this->persistence_factory->where( + $this->feedback_table_definitions->getForeignKeyColumn( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ) + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ] + ) + )->withAdditionalStatement( + $this->persistence_factory->delete( + $this->persistence_factory->table( + $this->feedback_table_names_builder, + TableTypes::FeedbackSpecific + ), + [ + $this->persistence_factory->where( + $this->feedback_table_definitions->getForeignKeyColumn( + $this->feedback_table_names_builder, + TableTypes::FeedbackSpecific + ) + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ] + ) + )->run(); + } + + private function buildQuery(): Query + { + return $this->feedback_table_definitions->completeQuery( + new Query( + $this->db, + $this->refinery, + QuestionRepository::COMPONENT_NAMESPACE, + $this->persistence_factory->table( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ) + ), + $this->feedback_table_definitions->getIdColumn( + $this->feedback_table_names_builder, + TableTypes::FeedbackGeneric + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/SpecificTextFeedback.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/SpecificTextFeedback.php new file mode 100644 index 000000000000..dc3b12acb48f --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/SpecificTextFeedback.php @@ -0,0 +1,150 @@ +id; + } + + public function getParentId(): Uuid + { + return $this->parent_id; + } + + public function getCondition(): string + { + return $this->condition; + } + + public function withCondition( + string $condition + ): self { + $clone = clone $this; + $clone->condition = $condition; + return $clone; + } + + public function getFeedbackText(): Markdown + { + return $this->feedback_text; + } + + public function withFeedbackText( + Markdown $text + ): self { + $clone = clone $this; + $clone->feedback_text = $text; + return $clone; + } + + public function getFeedbackTextForPresentation( + Refinery $refinery + ): string { + if ($this->feedback_text !== null) { + return $refinery->string()->markdown()->toHTML()->transform( + $this->feedback_text->getRawRepresentation() + ); + } + + return $this->feedback_legacy; + } + + public function toStorage( + PersistenceFactory $persistence_factory + ): array { + if ($this->feedback_text === null) { + throw new \UnexpectedValueException( + 'You cannot save a SpecificTextFeedback without a feedback text!' + ); + } + + return [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->parent_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->condition + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_text->getRawRepresentation() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_legacy + ) + ]; + } + + public function requiresPageMigration(): bool + { + return preg_match('/####\d+####/', $this->feedback_legacy) === 1; + } + + public function withMigratedPageFeedbacks(): self + { + $clone = clone $this; + $feedback = trim($clone->feedback_legacy, '#'); + if (!is_numeric($feedback)) { + return $clone; + } + + $feedback_page = (new \ilAssSpecFeedbackPageGUI( + (int) $feedback + ))->presentation(); + + $clone->feedback_legacy = ''; + if (strip_tags($feedback_page) !== '') { + $clone->feedback_legacy = $feedback_page; + } + + return $clone; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableDefinitions.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableDefinitions.php new file mode 100644 index 000000000000..10453c206f7c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableDefinitions.php @@ -0,0 +1,162 @@ +persistence_factory->table( + $table_names_builder, + $table_type + ); + + return array_map( + fn(string $v): Column => $this->persistence_factory->column( + $table, + $v + ), + match($table_type) { + TableTypes::FeedbackGeneric => self::FEEDBACK_GENERIC_TABLE_COLUMNS, + TableTypes::FeedbackSpecific => self::FEEDBACK_SPECIFIC_TABLE_COLUMNS + } + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type + ); + + return match($table_type) { + TableTypes::FeedbackGeneric => $this->persistence_factory->column( + $table, + self::FEEDBACK_GENERIC_TABLE_ID_COLUMN + ), + TableTypes::FeedbackSpecific => $this->persistence_factory->column( + $table, + self::FEEDBACK_SPECIFIC_TABLE_ID_COLUMN + ) + }; + } + + public function getForeignKeyColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type + ); + + return match($table_type) { + TableTypes::FeedbackGeneric => $this->persistence_factory->column( + $table, + self::FEEDBACK_GENERIC_TABLE_FOREIGN_KEY_COLUMN + ), + TableTypes::FeedbackSpecific => $this->persistence_factory->column( + $table, + self::FEEDBACK_SPECIFIC_TABLE_FOREIGN_KEY_COLUMN + ) + }; + } + + public function completeQuery( + Query $query, + ?Column $base_table_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder(null); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::FeedbackGeneric + ) + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::FeedbackSpecific + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $base_table_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + TableTypes::FeedbackSpecific + ), + JoinType::Left + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $base_table_id_column + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableTypes.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableTypes.php new file mode 100644 index 000000000000..2d9b54ebf5da --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/TableTypes.php @@ -0,0 +1,29 @@ + + */ + private array $specific_feedbacks = []; + + abstract public function getAdditionalInputs( + Language $lng, + UIFactory $ui_factory, + bool $set_legacy_texts_as_values + ): ?array; + + abstract public function getSpecificFeedbackTable( + Environment $environment + ): ?OverviewTable; + + abstract public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): static; + + abstract public function onAnswerFormUpdate( + Properties $answer_form_properties + ): static; + + abstract protected function specificFeedbackInputsHaveLegacyTexts(): bool; + + /** + * @return list + */ + abstract protected function getSpecificFeedbackParticipantOutput( + UIFactory $ui_factory, + Refinery $refinery, + Properties $properties, + ?Response $response + ): array; + + /** + * The endpoint must point to a javascript namespace containing the functions + * `retrieveSpecificFeedback(data, bestResponse, response)` where `data` is + * the array produced by `getSpecificFeedbackForClientSideCode()`, `bestResponse` + * it the array produced by `Reponse::toClientSideRepresentation()` and `response` + * is an object containing all the inputs and their values as set in the + * interface. + */ + abstract protected function getSpecificFeedbackClientSideEndPoint(): string; + + abstract protected function getSpecificFeedbackForClientSideCode( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + Properties $properties + ): array; + + #[\Override] + final public static function getCapabilityIdentifier(): string + { + return Capability::getIdentifier(); + } + + public function withGenericFeedbackFromDatabase( + TextFactory $text_factory, + ?array $database_data + ): static { + if ($database_data === null) { + return $this; + } + $clone = clone $this; + if ($database_data[0]['feedback_best_response'] !== '') { + $clone->feedback_best_response = $text_factory->markdown( + $database_data[0]['feedback_best_response'] + ); + } + $clone->feedback_best_response_legacy = $database_data[0]['feedback_best_response_legacy']; + + if ($database_data[0]['feedback_other_response'] !== '') { + $clone->feedback_other_response = $text_factory->markdown( + $database_data[0]['feedback_other_response'] + ); + } + $clone->feedback_other_response_legacy = $database_data[0]['feedback_other_response_legacy']; + return $clone; + } + + public function withSpecificFeedbackFromDatabase( + UuidFactory $uuid_factory, + TextFactory $text_factory, + ?array $database_data + ): static { + if ($database_data === null + || $database_data === []) { + return $this; + } + + $clone = clone $this; + foreach ($database_data as $feedback_data) { + $feedback = new SpecificTextFeedback( + $uuid_factory->fromString($feedback_data['id']), + $uuid_factory->fromString($feedback_data['answer_form_id']), + $uuid_factory->fromString($feedback_data['parent_id']), + $feedback_data['condition'], + $text_factory->markdown($feedback_data['feedback']), + $feedback_data['feedback_legacy'] + ); + + $clone->specific_feedbacks[$feedback_data['id']] = $feedback; + } + + return $clone; + } + + public function getFeedbackBestResponse(): ?Markdown + { + return $this->feedback_best_response; + } + + public function withFeedbackBestResponse( + Markdown $feedback_best_response + ): static { + $clone = clone $this; + $clone->feedback_best_response = $feedback_best_response; + return $clone; + } + + public function getFeedbackBestResponseLegacy(): string + { + return $this->feedback_best_response_legacy; + } + + public function getFeedbackOtherResponse(): ?Markdown + { + return $this->feedback_other_response; + } + + public function withFeedbackOtherResponse( + Markdown $feedback_other_response + ): static { + $clone = clone $this; + $clone->feedback_other_response = $feedback_other_response; + return $clone; + } + + public function getFeedbackOtherResponseLegacy(): string + { + return $this->feedback_other_response_legacy; + } + + public function hasLegacyTexts(): bool + { + return $this->feedback_best_response_legacy !== '' + || $this->feedback_other_response_legacy !== '' + || $this->specificFeedbackInputsHaveLegacyTexts(); + } + + public function getSpecificFeedbackForId( + Uuid $id + ): ?SpecificTextFeedback { + return $this->specific_feedbacks[$id->toString()] ?? null; + } + + public function getSpecificFeedbackForConditionOrNew( + UuidFactory $uuid_factory, + Uuid $answer_form_id, + Uuid $parent_id, + string $condition + ): SpecificTextFeedback { + $feedback = array_filter( + $this->specific_feedbacks, + fn(SpecificTextFeedback $v): bool => $v->getParentId()->toString() === $parent_id->toString() + && $v->getCondition() === $condition + ); + + return $feedback !== [] + ? current($feedback) + : new SpecificTextFeedback( + $uuid_factory->uuid4(), + $answer_form_id, + $parent_id, + $condition + ); + } + + /** + * @var array + */ + public function getSpecificFeedbacks(): array + { + return $this->specific_feedbacks; + } + + public function withSpecificFeedback( + SpecificTextFeedback $specific_feedback + ): static { + $clone = clone $this; + $clone->specific_feedbacks[$specific_feedback->getId()->toString()] = $specific_feedback; + return $clone; + } + + public function withoutSpecificFeedback( + SpecificTextFeedback $specific_feedback + ): static { + $clone = clone $this; + unset($clone->specific_feedbacks[$specific_feedback->getId()->toString()]); + return $clone; + } + + #[\Override] + public function getParticipantOutput( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + Properties $properties, + ?Response $response, + RequiredCapabilities $required_capabilities + ): ?FeedbackView { + if ($response === null) { + return []; + } + + $generic_feedback = []; + if ($required_capabilities->isMarkingRequired()) { + $generic_feedback[] = $response->isBest() + ? $this->getRenderedFeedbackBestResponse( + $lng, + $refinery, + $ui_factory + ) : $this->getRenderedFeedbackOtherResponse( + $lng, + $refinery, + $ui_factory + ); + } + + $feedback = [ + ...$generic_feedback, + ...$this->getSpecificFeedbackParticipantOutput( + $ui_factory, + $refinery, + $properties, + $response + ) + ]; + + if ($feedback === []) { + return null; + } + + return new FeedbackView( + $ui_factory->panel()->standard( + $lng->txt('feedback'), + $feedback + ) + ); + } + + #[\Override] + public function getFeedbackClientSideEndPoint(): string + { + return 'il.questions.textFeedback.retrieve'; + } + + #[\Override] + public function getAllFeedbacksForClientSideCode( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + UIRenderer $ui_renderer, + RequiredCapabilities $required_capabilities, + Properties $properties + ): array { + $feedbacks = []; + if ($required_capabilities->isMarkingRequired()) { + $feedbacks[self::KEY_BEST_RESPONSE] = $ui_renderer->render( + $this->getRenderedFeedbackBestResponse( + $lng, + $refinery, + $ui_factory + ) + ); + + $feedbacks[self::KEY_OTHER_RESPONSE] = $ui_renderer->render( + $this->getRenderedFeedbackOtherResponse( + $lng, + $refinery, + $ui_factory + ) + ); + } + + return [ + self::KEY_PANEL_TITEL => $lng->txt('feedback'), + self::KEY_SPECIFIC_FEEDBACK_END_POINT => $this->getSpecificFeedbackClientSideEndPoint(), + ...$feedbacks, + ...$this->getSpecificFeedbackForClientSideCode( + $lng, + $refinery, + $ui_factory, + $properties + ) + ]; + } + + public function requiresPageMigration(): bool + { + if (preg_match('/####\d+####/', $this->feedback_best_response_legacy) === 1 + || preg_match('/####\d+####/', $this->feedback_other_response_legacy) === 1) { + return true; + } + + foreach ($this->specific_feedbacks as $feedback) { + if ($feedback->requiresPageMigration()) { + return true; + } + } + + return false; + } + + public function withMigratedPageFeedbacks(): self + { + $clone = clone $this; + $feedback_best = trim($clone->feedback_best_response_legacy, '#'); + if (is_numeric($feedback_best)) { + $clone->feedback_best_response_legacy = $this->migrateGenericFeedbackPage( + (int) $feedback_best + ); + } + + $feedback_other = trim($clone->feedback_other_response_legacy, '#'); + if (is_numeric($feedback_other)) { + $clone->feedback_other_response_legacy = $this->migrateGenericFeedbackPage( + (int) $feedback_other + ); + } + + $clone->specific_feedbacks = array_map( + fn(SpecificTextFeedback $v): SpecificTextFeedback + => $v->withMigratedPageFeedbacks(), + $clone->specific_feedbacks + ); + + return $clone; + } + + public function toStorage( + PersistenceFactory $persistence_factory, + TableDefinitions $feedback_table_definitions, + TableNameBuilder $feedback_table_names_builder, + Uuid $answer_form_id, + Manipulate $manipulate + ): Manipulate { + $manipulate_with_feedback = $manipulate + ->withAdditionalStatement( + $this->buildReplaceForGenericFeedback( + $persistence_factory, + $feedback_table_definitions, + $feedback_table_names_builder, + $answer_form_id + ) + )->withAdditionalStatement( + $this->buildDeleteForSpecificFeedback( + $persistence_factory, + $feedback_table_definitions, + $feedback_table_names_builder, + $answer_form_id + ) + ); + + $specific_feedback_replace = $this->buildReplaceForSpecificFeedback( + $persistence_factory, + $feedback_table_definitions, + $feedback_table_names_builder + ); + + if ($specific_feedback_replace === null) { + return $manipulate_with_feedback; + } + + return $manipulate_with_feedback->withAdditionalStatement( + $specific_feedback_replace + ); + } + + private function buildReplaceForGenericFeedback( + PersistenceFactory $persistence_factory, + TableDefinitions $feedback_table_definitions, + TableNameBuilder $feedback_table_names_builder, + Uuid $answer_form_id + ): Replace { + return $persistence_factory->replace( + $feedback_table_definitions->getColumns( + $feedback_table_names_builder, + TableTypes::FeedbackGeneric + ), + [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_best_response?->getRawRepresentation() ?? '' + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_best_response_legacy + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_other_response?->getRawRepresentation() ?? '' + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->feedback_other_response_legacy + ) + ] + ); + } + + private function buildDeleteForSpecificFeedback( + PersistenceFactory $persistence_factory, + TableDefinitions $feedback_table_definitions, + TableNameBuilder $feedback_table_names_builder, + Uuid $answer_form_id + ): Delete { + return $persistence_factory->delete( + $persistence_factory->table( + $feedback_table_names_builder, + TableTypes::FeedbackSpecific + ), + [ + $persistence_factory->where( + $feedback_table_definitions->getForeignKeyColumn( + $feedback_table_names_builder, + TableTypes::FeedbackSpecific + ), + new Value( + FieldDefinition::T_TEXT, + $answer_form_id->toString() + ) + ) + ] + ); + } + + private function buildReplaceForSpecificFeedback( + PersistenceFactory $persistence_factory, + TableDefinitions $feedback_table_definitions, + TableNameBuilder $feedback_table_names_builder + ): ?Replace { + return array_reduce( + $this->specific_feedbacks, + fn(?Replace $c, SpecificTextFeedback $v) => $c === null + ? $persistence_factory->replace( + $feedback_table_definitions->getColumns( + $feedback_table_names_builder, + TableTypes::FeedbackSpecific + ), + $v->toStorage($persistence_factory) + ) : $c->withAdditionalValues( + $v->toStorage($persistence_factory) + ) + ); + } + + private function getRenderedFeedbackBestResponse( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory + ): Component { + if ($this->feedback_best_response === null) { + return $ui_factory->messageBox()->success( + $this->feedback_best_response_legacy === '' + ? $lng->txt('best_response_given') + : $this->feedback_best_response_legacy + ); + } + + $rendered_markdown = $refinery->string()->markdown()->toHTML() + ->transform($this->feedback_best_response->getRawRepresentation()); + + return $ui_factory->messageBox()->success( + $rendered_markdown === '' + ? $lng->txt('best_response_given') + : $rendered_markdown + ); + } + + private function getRenderedFeedbackOtherResponse( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory + ): Component { + if ($this->feedback_other_response === null) { + return $ui_factory->messageBox()->info( + $this->feedback_other_response_legacy === '' + ? $lng->txt('other_response_given') + : $this->feedback_other_response_legacy + ); + } + + $rendered_markdown = $refinery->string()->markdown()->toHTML() + ->transform($this->feedback_other_response->getRawRepresentation()); + + return $ui_factory->messageBox()->info( + $rendered_markdown === '' + ? $lng->txt('other_response_given') + : $rendered_markdown + ); + } + + private function migrateGenericFeedbackPage( + int $page_id + ): string { + $feedback_page = (new \ilAssGenFeedbackPageGUI( + $page_id + ))->presentation(); + + if (strip_tags($feedback_page) === '') { + return ''; + } + + return $feedback_page; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Types.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Types.php new file mode 100644 index 000000000000..c50fcd2e072b --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TextFeedback/Types.php @@ -0,0 +1,36 @@ +txt($this->value); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Capabilities/TypeSpecification.php b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TypeSpecification.php new file mode 100644 index 000000000000..f6da8d139020 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Capabilities/TypeSpecification.php @@ -0,0 +1,26 @@ + $available_answer_form_types + */ + private readonly array $available_answer_form_types; + + /** + * @param array<\ILIAS\Questions\AnswerForm\Definition> $available_answer_form_types + */ + public function __construct( + private readonly UuidFactory $uuid_factory, + array $available_answer_form_types + ) { + $this->available_answer_form_types = array_reduce( + $available_answer_form_types, + function (array $c, Definition $v) { + $c[$this->getHashedClass($v::class)] = $v; + return $c; + }, + [] + ); + } + + /** + * + * @return array + */ + public function getAvailableDefinitions(): array + { + return array_values($this->available_answer_form_types); + } + + public function getDefinitionForClass( + string $class + ): Definition { + $definition = $this->available_answer_form_types[$this->getHashedClass($class)] ?? null; + if ($definition === null) { + throw new InvalidArgumentException('This type of answer form does not exist.'); + } + return $definition; + } + + /** + * @return array + */ + public function getAnswerFormTypesArrayForSelect( + Language $lng + ): array { + return array_reduce( + $this->available_answer_form_types, + function (array $c, Definition $v) use ($lng): array { + $c[$this->getHashedClass($v::class)] = $v->getLabel($lng); + return $c; + }, + [] + ); + } + + public function getHashedClass(string $class): string + { + return md5($class); + } + + public function getTypeDefinitionFromSelectValue( + string $value + ): Definition { + $type_definition = $this->available_answer_form_types[$value] ?? null; + if ($type_definition === null) { + throw new InvalidArgumentException('This type of answer form does not exist.'); + } + return $type_definition; + } + + public function getDefaultTypeGenericProperties( + Uuid $question_id, + Definition $type_definition, + ?Uuid $answer_form_id = null + ): TypeGenericProperties { + return new TypeGenericProperties( + $answer_form_id ?? $this->uuid_factory->uuid4(), + $question_id, + $type_definition + ); + } + + public function buildTypeGenericPropertiesFromDatabase( + array $db_values + ): TypeGenericProperties { + return new TypeGenericProperties( + $this->uuid_factory->fromString($db_values['id']), + $this->uuid_factory->fromString($db_values['question_id']), + $this->getDefinitionForClass($db_values['type']), + $db_values['available_points'], + $db_values['image_size'], + $db_values['shuffle_answer_options'] === 1, + $db_values['additional_text'], + $db_values['additional_text_legacy'] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Migration/Migration.php b/components/ILIAS/Questions/src/AnswerForm/Migration/Migration.php new file mode 100644 index 000000000000..b85b7bd314ec --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Migration/Migration.php @@ -0,0 +1,49 @@ +db; + } + + public function getIO(): IOWrapper + { + return $this->io; + } + + public function getUuid(): Uuid + { + return $this->uuid_factory->uuid4(); + } + + public function getPersistenceFactory(): PersistenceFactory + { + return $this->persistence_factory; + } + + public function getTableNameBuilder( + ?TableSubNameSpace $table_sub_name_space + ): TableNameBuilder { + return new TableNameBuilder( + $this->component_name_space, + $table_sub_name_space + ); + } + + public function getOldQuestionId(): int + { + return $this->old_question_id; + } + + public function getAnswerFormId(): Uuid + { + return $this->answer_form_id; + } + + public function wasIliasPageEditorUsedForAdditionalTexts(): bool + { + return $this->ilias_page_editor_used_for_additional_texts; + } + + public function withAvailablePoints( + float $available_points + ): self { + $clone = clone $this; + $clone->available_points = $available_points; + return $clone; + } + + public function withImageSize( + int $image_size + ): self { + $clone = clone $this; + $clone->image_size = $image_size; + return $clone; + } + + public function withShuffleAnswerOptions( + bool $shuffle_answer_options + ): self { + $clone = clone $this; + $clone->shuffle_answer_options = $shuffle_answer_options; + return $clone; + } + + public function withAdditionalText( + string $additional_text + ): self { + $clone = clone $this; + $clone->additional_text = $additional_text; + return $clone; + } + + public function withAdditionalTextLegacy( + string $additional_text_legacy + ): self { + $clone = clone $this; + $clone->additional_text_legacy = $additional_text_legacy; + return $clone; + } + + public function withAdditionalInsert( + Insert $insert + ): self { + $clone = clone $this; + $clone->inserts[] = $insert; + return $clone; + } + + public function run(): void + { + $this->inserts[] = $this->buildCoreAnswerFormInsertStatement(); + $atom_query = $this->db->buildAtomQuery(); + + $manipulates = []; + $locked_tables = []; + foreach ($this->inserts as $statement) { + $table_to_lock = $statement->getTableToLock(); + if (!in_array($table_to_lock, $locked_tables)) { + $atom_query->addTableLock($table_to_lock); + $locked_tables[] = $table_to_lock; + } + $manipulates[] = $statement->toManipulateString($this->db); + } + $atom_query->addQueryCallable( + function (\ilDBInterface $db) use ($manipulates): void { + foreach ($manipulates as $manipulate) { + $db->manipulate($manipulate); + } + } + ); + $atom_query->run(); + } + + private function buildCoreAnswerFormInsertStatement(): Insert + { + return $this->persistence_factory->insert( + $this->answer_form_generic_table_definitions->getColumns( + $this->getTableNameBuilder(null), + AnswerFormGenericTableTypes::AnswerForms + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $this->definition_class + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $this->new_question_id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->available_points + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->image_size + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->shuffle_answer_options === null + ? null + : ($this->shuffle_answer_options ? 1 : 0) + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $this->additional_text + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $this->additional_text_legacy + ) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Migration/MigrationPurifier.php b/components/ILIAS/Questions/src/AnswerForm/Migration/MigrationPurifier.php new file mode 100755 index 000000000000..caca7c763c08 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Migration/MigrationPurifier.php @@ -0,0 +1,117 @@ +set('HTML.DefinitionID', 'migration'); + $config->set('HTML.DefinitionRev', 2); + $config->set('Cache.SerializerPath', sys_get_temp_dir()); + $config->set('HTML.Doctype', 'XHTML 1.0 Strict'); + $config->set('HTML.AllowedElements', $this->getAllowedElements()); + $config->set('HTML.ForbiddenAttributes', 'div@style'); + $config->autoFinalize = false; + $config->set( + 'URI.AllowedSchemes', + [ + ...$config->get('URI.AllowedSchemes'), + 'data' => true + ] + ); + $config->autoFinalize = true; + if (($def = $config->maybeGetRawHTMLDefinition()) !== null) { + $def->addAttribute('img', 'data-id', 'Number'); + $def->addAttribute('a', 'target', 'Enum#_blank,_self,_target,_top'); + } + + return $config; + } + + private function getAllowedElements(): array + { + return $this->removeUnsupportedElements( + $this->makeElementListTinyMceCompliant( + $this->getElementsUsedForAdvancedEditing() + ) + ); + } + + private function getElementsUsedForAdvancedEditing(): array + { + $tags = $this->db->fetchObject( + $this->db->query( + 'SELECT value FROM settings' . PHP_EOL + . 'WHERE module = "advanced_editing"' . PHP_EOL + . 'AND keyword = "advanced_editing_used_html_tags_assessment"' + ) + )?->value ?? ''; + + if ($tags === '') { + return self::DEFAULT_TAGS; + } + + return unserialize($tags, ['allowed_classes' => false]); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Migration/SanitizeLegacyText.php b/components/ILIAS/Questions/src/AnswerForm/Migration/SanitizeLegacyText.php new file mode 100644 index 000000000000..ea64832261d8 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Migration/SanitizeLegacyText.php @@ -0,0 +1,60 @@ +purifiery === null) { + $this->purifiery = new MigrationPurifier($db); + $this->rte_used = $this->fetchIsRteUsedFromDb($db); + } + $cleaned_text = $this->purifiery->purify($text); + + if ($ilias_page_editor_text || !$this->rte_used) { + $cleaned_text = nl2br($cleaned_text); + } + + return \ilLegacyFormElementsUtil::prepareTextareaOutput( + $cleaned_text, + true + ); + } + + private function fetchIsRteUsedFromDb( + \ilDBInterface $db + ): bool { + return $db->fetchObject( + $db->query( + 'SELECT value FROM settings' . PHP_EOL + . 'WHERE module = "advanced_editing"' . PHP_EOL + . 'AND keyword = "advanced_editing_javascript_editor"' + ) + )?->value === 'tinymce'; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableDefinitions.php b/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableDefinitions.php new file mode 100644 index 000000000000..94e0fa025042 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableDefinitions.php @@ -0,0 +1,128 @@ + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + $v + ), + array_values( + array_filter( + self::ANSWER_FORM_TABLE_COLUMNS, + fn(string $v) => !in_array($v, $columns_to_skip) + ) + ) + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypes $table_type + ): Column { + return $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + self::ANSWER_FORM_TABLE_ID_COLUMN + ); + } + + public function getForeignKeyColumn( + TableNameBuilder $table_names_builder, + TableTypes $table_type + ): Column { + return $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + self::ANSWER_FORM_TABLE_FOREIGN_KEY_COLUMN + ); + } + + public function completeQuestionQuery( + Query $query, + ?Column $base_table_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder(null); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormGenericTableTypes::AnswerForms + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $base_table_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormGenericTableTypes::AnswerForms + ), + JoinType::Left + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableTypes.php b/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableTypes.php new file mode 100644 index 000000000000..0e713c3128af --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Persistence/AnswerFormGenericTableTypes.php @@ -0,0 +1,28 @@ +answer_form_id; + } + + public function getQuestionId(): Uuid + { + return $this->question_id; + } + + public function getDefinition(): ?Definition + { + return $this->definition; + } + + public function getAvailablePoints(): ?float + { + return $this->available_points; + } + + public function getImageSize(): ?int + { + return $this->image_size; + } + + public function getShuffleAnswerOptions(): ?bool + { + return $this->shuffle_answer_options; + } + + public function getAdditionalText(): string + { + return $this->additional_text; + } + + public function getAdditionalTextLegacy(): string + { + return $this->additional_text_legacy; + } + + public function toStorage( + PersistenceFactory $persistence_factory, + AnswerFormGenericTableDefinitions $answer_form_generic_definitions, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + if ($this->definition === null) { + throw new \UnexpectedValueException( + 'You cannot save a Answer Form without a Type!' + ); + } + + $table_names_builder = $manipulate->getTableNameBuilder(null); + + return $manipulate->withAdditionalStatement( + $manipulation_type === ManipulationType::Create + ? $this->buildInsertStatement( + $persistence_factory, + $answer_form_generic_definitions, + $table_names_builder + ) : $this->buildUpdateStatement( + $persistence_factory, + $answer_form_generic_definitions, + $table_names_builder + ) + ); + } + + public function toDelete( + PersistenceFactory $persistence_factory, + AnswerFormGenericTableDefinitions $answer_form_generic_table_definitions, + Manipulate $manipulate + ): Manipulate { + $table_names_builder = $manipulate->getTableNameBuilder( + $answer_form_generic_table_definitions->getTableSubNameSpace() + ); + $table_type = AnswerFormGenericTableTypes::AnswerForms; + + return $manipulate->withAdditionalStatement( + $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $persistence_factory->where( + $answer_form_generic_table_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ) + ) + ] + ) + ); + } + + private function buildInsertStatement( + PersistenceFactory $persistence_factory, + AnswerFormGenericTableDefinitions $answer_form_generic_table_definitions, + TableNameBuilder $table_names_builder + ): Insert { + return $persistence_factory->insert( + $answer_form_generic_table_definitions->getColumns( + $table_names_builder, + AnswerFormGenericTableTypes::AnswerForms + ), + [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->definition::class + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->question_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->available_points + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->image_size + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->getShuffleAnswerOptionsForStorage() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->additional_text + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->additional_text_legacy + ) + ] + ); + } + + private function buildUpdateStatement( + PersistenceFactory $persistence_factory, + AnswerFormGenericTableDefinitions $answer_form_generic_table_definitions, + TableNameBuilder $table_names_builder + ): Update { + $table_type = AnswerFormGenericTableTypes::AnswerForms; + + return $persistence_factory->update( + $answer_form_generic_table_definitions->getColumns( + $table_names_builder, + $table_type, + [ + 'id', + 'type', + 'question_id', + 'additional_text_legacy' + ] + ), + [ + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->available_points + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->image_size + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->getShuffleAnswerOptionsForStorage() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->additional_text + ) + + ], + [ + $persistence_factory->where( + $answer_form_generic_table_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ) + ) + ] + ); + } + + private function getShuffleAnswerOptionsForStorage(): ?int + { + if ($this->shuffle_answer_options === null) { + return null; + } + + return $this->shuffle_answer_options ? 1 : 0; + } +} diff --git a/components/ILIAS/Questions/src/AnswerForm/Views/Edit.php b/components/ILIAS/Questions/src/AnswerForm/Views/Edit.php new file mode 100644 index 000000000000..b54a01818687 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerForm/Views/Edit.php @@ -0,0 +1,48 @@ +|Component + */ + public function show( + GlobalTemplate $global_template, + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + ViewConfiguration $view_configuration, + Properties $properties, + ?AdditionalAttemptData $attempt_data, + ?Response $response_data + ): array|Component; + + public function retrieveResponse( + Uuid $response_id, + Properties $properties, + RequestWrapper $post_wrapper + ): Response; +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/AsyncView.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/AsyncView.php new file mode 100644 index 000000000000..c40fde5b4da4 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/AsyncView.php @@ -0,0 +1,84 @@ +mustache_engine->render( + $properties->getClozeTextForPresentation(), + $properties->getGaps()->getPlaceholderArray( + $lng, + $view_configuration, + $additional_attempt_data, + $response_data + ) + ); + } + + #[\Override] + public function retrieveResponse( + Uuid $response_id, + Properties $properties, + RequestWrapper $post_wrapper + ): Response { + return $this->response_factory->fromPost( + $response_id, + $properties, + $post_wrapper + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/DefaultView.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/DefaultView.php new file mode 100644 index 000000000000..f046c904b5c3 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/DefaultView.php @@ -0,0 +1,84 @@ +legacy()->content( + $this->mustache_engine->render( + $properties->getClozeTextForPresentation(), + $properties->getGaps()->getPlaceholderArray( + $lng, + $view_configuration, + $additional_attempt_data, + $response_data + ) + ) + ); + } + + #[\Override] + public function retrieveResponse( + Uuid $response_id, + Properties $properties, + RequestWrapper $post_wrapper + ): Response { + return $this->response_factory->fromPost( + $response_id, + $properties, + $post_wrapper + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/MarkingAllowingPartialPoints.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/MarkingAllowingPartialPoints.php new file mode 100644 index 000000000000..d8e2453ad523 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/MarkingAllowingPartialPoints.php @@ -0,0 +1,93 @@ +calculateAwardedPoints($properties); + } + + #[\Override] + public function getBestResponse( + Properties $properties + ): Response { + return $this->response_factory->getBestResponse($properties); + } + + #[\Override] + public function getEditFormInputsBuilder( + Environment $environment, + ): InputsBuilderSession { + return $environment->getPresentationFactory()->getSessionBasedInputsBuilder( + $environment->getRefinery()->custom()->transformation( + function (?string $carry) use ($environment): Section { + $properties_from_carry = $this->properties_factory + ->fromCarry( + $environment->getAnswerFormProperties(), + $carry + ); + return $properties_from_carry->getGaps() + ->buildPointInputs( + $environment->getLanguage(), + $environment->getUIFactory(), + $properties_from_carry, + $environment->isInCreationContext(), + $environment->getTableRowIds() + ); + } + ) + ); + } + + #[\Override] + public function getCarryPropertiesFromCarryTransformation( + Environment $environment + ): CustomTransformation { + return $environment->getRefinery()->custom()->transformation( + fn(?string $carry): Properties => $this->properties_factory + ->fromCarry( + $environment->getAnswerFormProperties(), + $carry + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedback.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedback.php new file mode 100644 index 000000000000..d87840761547 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedback.php @@ -0,0 +1,303 @@ +uuid_factory, + $this->text_factory, + new TextFeedbackOverviewDataRetrieval( + $environment->getLanguage(), + $environment->getRefinery(), + $this->uuid_factory, + $environment->getAnswerFormProperties(), + $this + ) + ); + } + + #[\Override] + public function onAnswerFormClone( + UuidFactory $uuid_factory, + Properties $old_answer_form_properties, + Properties $new_answer_form_properties + ): static { + /** @var Gaps $old_gaps */ + $old_gaps = $old_answer_form_properties->getGaps(); + /** @var Gaps $new_gaps */ + $new_gaps = $new_answer_form_properties->getGaps(); + + return array_reduce( + $this->getSpecificFeedbacks(), + function ( + TextFeedback $c, + SpecificTextFeedback $v + ) use ($uuid_factory, $old_gaps, $new_gaps): self { + $old_gap = $old_gaps->getGapById($v->getParentId()); + try { + $answer_option_position = $old_gap + ->getAnswerOptions() + ->getAnswerOptionById( + $uuid_factory->fromString($v->getCondition()) + )->getPosition(); + $new_answer_option_id = $new_gaps + ->getGapByPosition($old_gap->getPosition()) + ->getAnswerOptions() + ->getAnswerOptionForPositionOrNew($answer_option_position) + ->getAnswerOptionId(); + + return $c->withoutSpecificFeedback($v) + ->withSpecificFeedback( + $v->withCondition( + $new_answer_option_id->toString() + ) + ); + } catch (InvalidUuidStringException $e) { + return $c; + } + }, + clone $this + ); + } + + #[\Override] + public function onAnswerFormUpdate( + Properties $answer_form_properties + ): static { + /** @var Gaps $gaps */ + $gaps = $answer_form_properties->getGaps(); + + return array_reduce( + $this->getSpecificFeedbacks(), + function ( + TextFeedback $c, + SpecificTextFeedback $v + ) use ($gaps): self { + $gap = $gaps->getGapById($v->getParentId()); + if ($gap === null + || !$gap->getType()->isValidFeedbackCondition( + $this->uuid_factory, + $gap, + $v->getCondition() + ) + ) { + return $c->withoutSpecificFeedback($v); + } + + return $c; + }, + clone $this + ); + } + + #[\Override] + public function specificFeedbackInputsHaveLegacyTexts(): bool + { + return false; + } + + #[\Override] + protected function getSpecificFeedbackParticipantOutput( + UIFactory $ui_factory, + Refinery $refinery, + Properties $properties, + ?Response $response + ): array { + $specific_feedbacks = $this->getSpecificFeedbacks(); + if ($response === null || $specific_feedbacks === []) { + return []; + } + + /** @var Gaps $gaps */ + $gaps = $properties->getGaps(); + + return array_reduce( + $this->orderFeedbacksByAnswerInputId($specific_feedbacks), + function ( + array $c, + array $v + ) use ( + $ui_factory, + $refinery, + $gaps, + $response + ): array { + $gap_id = $v[0]->getParentId(); + + /** @var ?AnswerInputResponse $answer_for_gap */ + $answer_for_gap = $response?->getResponseForInput($gap_id); + + if ($answer_for_gap === null) { + return $this->addFeedbackForNoSelectionToParticipantOutput( + $ui_factory, + $refinery, + $v, + $c + ); + } + + $gap = $gaps->getGapById($gap_id); + $output = $gap->getType()->getSpecificFeedbackParticipantOutput( + $ui_factory, + $gap, + $v, + $answer_for_gap + ); + + if ($output !== null) { + $c[] = $output; + } + + return $c; + }, + [] + ); + } + + #[\Override] + protected function getSpecificFeedbackClientSideEndPoint(): string + { + return 'il.questions.cloze.specificTextFeedback'; + } + + #[\Override] + protected function getSpecificFeedbackForClientSideCode( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + Properties $properties + ): array { + $specific_feedbacks = $this->getSpecificFeedbacks(); + if ($specific_feedbacks === []) { + return []; + } + + return array_map( + fn(array $v): array => array_reduce( + $v, + function (array $c, SpecificTextFeedback $v) use ($refinery): array { + $c[$v->getCondition()] = $v->getFeedbackTextForPresentation( + $refinery + ); + return $c; + }, + [] + ), + $this->orderFeedbacksByAnswerInputId($specific_feedbacks) + ); + } + + public function buildSpecificFeedbackOverviewTableArray(): array + { + return array_reduce( + $this->getSpecificFeedbacks(), + function (array $c, SpecificTextFeedback $v): array { + $gap_id = $v->getParentId()->toString(); + $key = md5($v->getFeedbackText()->getRawRepresentation()); + if (!array_key_exists($gap_id, $c)) { + $c[$gap_id] = []; + } + if (!array_key_exists($key, $c[$gap_id])) { + $c[$gap_id][$key] = []; + } + + $c[$gap_id][$key][] = $v; + return $c; + }, + [] + ); + } + + private function orderFeedbacksByAnswerInputId( + array $specific_feedbacks + ): array { + return array_reduce( + $specific_feedbacks, + function (array $c, SpecificTextFeedback $v): array { + $parent_id = $v->getParentId()->toString(); + if (!array_key_exists($parent_id, $c)) { + $c[$parent_id] = []; + } + + $c[$parent_id][] = $v; + return $c; + }, + [] + ); + } + + private function addFeedbackForNoSelectionToParticipantOutput( + UIFactory $ui_factory, + Refinery $refinery, + array $specific_feedbacks, + array $participant_output + ): array { + $feedback_nothing_selected = array_filter( + $specific_feedbacks, + fn(SpecificTextFeedback $v): bool => TextFeedbackTypes::tryFrom($v->getCondition()) === TextFeedbackTypes::NoResponse + ); + + if ($feedback_nothing_selected !== []) { + $participant_output[] = $ui_factory->legacy()->content( + $feedback_nothing_selected[0]->getFeedbackTextForPresentation( + $refinery + ) + ); + } + + return $participant_output; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewDataRetrieval.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewDataRetrieval.php new file mode 100644 index 000000000000..af35a05e3964 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewDataRetrieval.php @@ -0,0 +1,135 @@ + + * } + */ + private readonly array $feedback; + + public function __construct( + private readonly Language $lng, + private readonly Refinery $refinery, + private readonly UuidFactory $uuid_factory, + private readonly Properties $answer_form_properties, + TextFeedback $feedback + ) { + $this->feedback = $feedback->buildSpecificFeedbackOverviewTableArray(); + } + + #[\Override] + public function getRows( + DataRowBuilder $row_builder, + array $visible_column_ids, + Range $range, + Order $order, + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): \Generator { + foreach ($this->feedback as $gap_feedbacks) { + yield from $this->buildColumnValues( + $row_builder, + $gap_feedbacks + ); + } + } + + #[\Override] + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return count($this->feedback); + } + + public function getSpecificFeedbacksForRowId( + string $table_row_id + ): array { + $ids = explode('_', $table_row_id); + $feedbacks_for_gap = array_reduce( + $this->feedback[array_shift($ids)], + fn(array $c, array $v): array => [...$c, ...$v], + [] + ); + return array_filter( + $feedbacks_for_gap, + fn(SpecificTextFeedback $v): bool => in_array($v->getId(), $ids) + ); + } + + private function buildColumnValues( + DataRowBuilder $row_builder, + array $gap_feedbacks + ): \Generator { + foreach ($gap_feedbacks as $feedbacks) { + yield $this->buildTableRow( + $row_builder, + $feedbacks + ); + } + } + + private function buildTableRow( + DataRowBuilder $row_builder, + array $feedbacks + ): DataRow { + $gap_id = $feedbacks[0]->getParentId(); + $gap = $this->answer_form_properties->getGaps()->getGapById($gap_id); + + $keys = [$gap_id->toString()]; + $answer_options = []; + foreach ($feedbacks as $feedback) { + $keys[] = $feedback->getId()->toString(); + $answer_options[] = $gap->getType()->getLabelForValue( + $this->uuid_factory, + $gap, + $feedback->getCondition() + ); + } + + return $row_builder->buildDataRow( + implode('_', $keys), + [ + 'gap' => $gap->buildShortenedGapRepresentation(), + 'answer_options' => implode('
', $answer_options), + 'feedback' => $feedbacks[0] + ->getFeedbackTextForPresentation($this->refinery) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewTable.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewTable.php new file mode 100644 index 000000000000..da5478a2b0da --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Capabilities/TextFeedbackOverviewTable.php @@ -0,0 +1,499 @@ +getUIFactory(); + $lng = $environment->getLanguage(); + + return $ui_factory->modal()->roundtrip( + $lng->txt('create_feedback'), + null, + [ + 'gap' => $environment->getAnswerFormProperties()->getGaps() + ->buildGapsSelect( + $lng->txt('select_gap'), + $ui_factory->input()->field() + )->withAdditionalTransformation( + $environment->getRefinery()->custom()->transformation( + fn(string $v): Uuid => $this->uuid_factory->fromString($v) + ) + )->withRequired(true) + ], + $environment->withSubActionParameter( + self::SUB_ACTION_ENTER_FEEDBACK + )->getUrlBuilder()->buildURI()->__toString() + )->withSubmitLabel($lng->txt('next')); + } + + #[\Override] + public function getTable( + Environment $environment, + TextFeedback $feedback + ): DataTable { + return $environment->getUIFactory()->table()->data( + $this->data_retrieval, + '', + $this->getColumns( + $environment->getUIFactory()->table()->column(), + $environment->getLanguage() + ) + )->withActions( + $this->getActions( + $environment + ) + )->withRequest($environment->getHttpServices()->request()); + } + + #[\Override] + public function doAction( + Environment $environment, + TextFeedback $feedback, + string $action + ): Async|RoundTripModal|TextFeedback { + return match($action) { + self::SUB_ACTION_ENTER_FEEDBACK => $this->processSelectGapModal( + $environment, + $feedback + ), + self::SUB_ACTION_EDIT_FEEDBACK => $this->editFeedback( + $environment->withPreservedTableRowIdsParameter(), + $feedback + ), + self::SUB_ACTION_SAVE_FEEDBACK => $this->processEnterFeedbackModal( + $environment, + $feedback + ), + self::SUB_ACTION_CONFIRM_DELETE_FEEDBACK => $this->confirmDeleteFeedback( + $environment + ), + self::SUB_ACTION_DELETE_FEEDBACK => $this->deleteFeedback( + $environment, + $feedback + ) + }; + } + + private function processSelectGapModal( + Environment $environment, + TextFeedback $feedback + ): RoundTripModal { + $create_modal = $this->getCreateModal($environment) + ->withRequest($environment->getHttpServices()->request()); + $data = $create_modal->getData(); + if ($data === null) { + return $create_modal; + } + + $inputs_builder = $this->buildEnterFeedbackInputBuilder( + $environment, + $feedback, + $data['gap'] + ); + + $enter_feedback_modal = $this->buildEnterFeedbackModal( + $environment, + $inputs_builder + ); + + $inputs_builder + ->withCarry( + $data['gap']->toString() + )->persistCarry(); + + return $enter_feedback_modal; + } + + private function buildEnterFeedbackModal( + Environment $environment, + InputsBuilderSession $inputs_builder + ): RoundTripModal { + return $environment->getUIFactory()->modal()->roundtrip( + $environment->getLanguage()->txt('edit_feedback'), + null, + [ + 'feedback' => $inputs_builder->getInputs() + ], + $environment->withSubActionParameter( + self::SUB_ACTION_SAVE_FEEDBACK + )->getUrlBuilder()->buildURI()->__toString() + ); + } + + private function processEnterFeedbackModal( + Environment $environment, + TextFeedback $feedback + ): RoundTripModal|TextFeedback { + $specific_feedbacks = $this->getSpecifcFeedbacksFromQuery( + $environment + ); + + $gap_id = null; + if (isset($specific_feedbacks[0])) { + $gap_id = $specific_feedbacks[0]->getParentId(); + $environment = $environment->withPreservedTableRowIdsParameter(); + } + + $inputs_builder = $this->buildEnterFeedbackInputBuilder( + $environment, + $feedback, + $gap_id, + array_map( + fn(SpecificTextFeedback $v): string => $v->getCondition(), + $specific_feedbacks + ) + ); + + $modal = $this->buildEnterFeedbackModal( + $environment, + $inputs_builder + )->withRequest($environment->getHttpServices()->request()); + + $data = $modal->getData(); + if ($data === null) { + $inputs_builder->persistCarry(); + return $modal; + } + + return $data['feedback']; + } + + private function editFeedback( + Environment $environment, + TextFeedback $feedback + ): Async|TextFeedback { + $specific_feedbacks = $this->getSpecifcFeedbacksFromQuery( + $environment + ); + + return $environment->getPresentationFactory()->getAsync( + $this->buildEnterFeedbackModal( + $environment, + $this->buildEnterFeedbackInputBuilder( + $environment, + $feedback, + $specific_feedbacks[0]->getParentId(), + array_map( + fn(SpecificTextFeedback $v): string => $v->getCondition(), + $specific_feedbacks + ), + $specific_feedbacks[0]->getFeedbackText()->getRawRepresentation() + ) + ) + ); + } + + private function confirmDeleteFeedback( + Environment $environment + ): Async { + $pf = $environment->getPresentationFactory(); + $uf = $environment->getUIFactory(); + $lng = $environment->getLanguage(); + $selected_feedbacks = $this->data_retrieval->getSpecificFeedbacksForRowId( + $environment->getTableRowIds()[0] + ); + + if ($selected_feedbacks === []) { + return $pf->getAsync( + $uf->messageBox()->failure( + $lng->txt('ui_field_option_filter_no_selection') + ) + ); + } + + return $pf->getAsync( + $uf->modal()->interruptive( + $lng->txt('confirm'), + $lng->txt('confirm_delete_feedback'), + $environment + ->withSubActionParameter(self::SUB_ACTION_DELETE_FEEDBACK) + ->getUrlBuilder() + ->buildURI() + ->__toString() + )->withAffectedItems([ + $uf->modal()->interruptiveItem()->standard( + $environment->getTableRowIds()[0], + $selected_feedbacks[0]->getFeedbackText() + ?->getRawRepresentation() ?? '' + ) + ]) + ); + } + + private function deleteFeedback( + Environment $environment, + TextFeedback $feedback + ): RoundTripModal|TextFeedback { + $uf = $environment->getUIFactory(); + $lng = $environment->getLanguage(); + $selected_feedbacks = $environment->getHttpServices()->wrapper()->post() + ->retrieve( + 'interruptive_items', + $environment->getRefinery()->custom()->transformation( + fn(array $vs): array => $this->data_retrieval + ->getSpecificFeedbacksForRowId($vs[0]) + ) + ); + + if ($selected_feedbacks === []) { + return $uf->modal()->roundtrip( + $lng->txt('error'), + $uf->messageBox()->failure( + $lng->txt('ui_field_option_filter_no_selection') + ) + ); + } + + return array_reduce( + $selected_feedbacks, + fn(TextFeedback $c, SpecificTextFeedback $v): TextFeedback => $c->withoutSpecificFeedback($v), + $feedback + ); + } + + private function buildEnterFeedbackInputBuilder( + Environment $environment, + TextFeedback $feedback, + ?Uuid $selected_gap = null, + array $selected_conditions = [], + string $feedback_text = '' + ): InputsBuilderSession { + return $environment->getPresentationFactory()->getSessionBasedInputsBuilder( + $environment->getRefinery()->custom()->transformation( + function ( + ?string $v + ) use ( + $environment, + $feedback, + $selected_gap, + $selected_conditions, + $feedback_text + ): Section { + $gap_id = $selected_gap + ?? $this->uuid_factory->fromString($v); + + return $this->buildSpecificFeedbackSection( + $environment->getUIFactory(), + $environment->getRefinery(), + $environment->getLanguage(), + $environment->getAnswerFormProperties() + ->getGaps() + ->getGapById($gap_id), + $environment->isMarkingRequired(), + $feedback->getSpecificFeedbacks(), + $selected_conditions, + $feedback_text + )->withAdditionalTransformation( + $this->buildSpecificFeedbackTransformation( + $environment->getRefinery(), + $feedback, + $environment->getAnswerFormId(), + $gap_id, + $selected_conditions + ) + ); + } + ) + ); + } + + private function buildSpecificFeedbackSection( + UIFactory $ui_factory, + Refinery $refinery, + Language $lng, + Gap $gap, + bool $is_marking_required, + array $existing_specific_feedbacks, + array $selected_conditions, + string $feedback_text + ): Section { + $answer_options = $gap->getType()->getFeedbackSelectValues( + $gap, + $is_marking_required + ); + + foreach ($existing_specific_feedbacks as $feedback) { + if (!in_array($feedback->getCondition(), $selected_conditions)) { + unset($answer_options[$feedback->getCondition()]); + } + } + + return $ui_factory->input()->field()->section( + [ + 'answer_options' => $ui_factory->input()->field()->multiSelect( + $lng->txt('answer_options'), + $answer_options + )->withHasOptionFilter(true) + ->withRequired(true) + ->withValue($selected_conditions), + 'feedback' => $ui_factory->input()->field()->markdown( + new \ilUIMarkdownPreviewGUI(), + $lng->txt('feedback') + )->withAdditionalTransformation( + $refinery->custom()->transformation( + fn(string $v): Markdown => $this->text_factory->markdown($v) + ) + )->withRequired(true) + ->withValue($feedback_text) + ], + $lng->txt('feedback') + ); + } + + private function buildSpecificFeedbackTransformation( + Refinery $refinery, + TextFeedback $feedback, + Uuid $answer_form_id, + Uuid $gap_id, + array $selected_conditions + ): CustomTransformation { + return $refinery->custom()->transformation( + function ( + array $vs + ) use ( + $feedback, + $answer_form_id, + $gap_id, + $selected_conditions + ): TextFeedback { + $feedback_with_removed_specific_feedbacks = array_reduce( + array_diff($selected_conditions, $vs['answer_options']), + fn(TextFeedback $c, string $v): TextFeedback => $c->withoutSpecificFeedback( + $c->getSpecificFeedbackForConditionOrNew( + $this->uuid_factory, + $answer_form_id, + $gap_id, + $v + ) + ), + $feedback + ); + + return array_reduce( + $vs['answer_options'], + fn(TextFeedback $c, string $v): TextFeedback => $c->withSpecificFeedback( + $c->getSpecificFeedbackForConditionOrNew( + $this->uuid_factory, + $answer_form_id, + $gap_id, + $v + )->withFeedbackText($vs['feedback']) + ), + $feedback_with_removed_specific_feedbacks + ); + } + ); + } + + private function getSpecifcFeedbacksFromQuery( + Environment $environment + ): array { + $selected_table_row_ids = $environment->getTableRowIds(); + + if ($selected_table_row_ids === []) { + return []; + } + + return $this->data_retrieval->getSpecificFeedbacksForRowId( + $selected_table_row_ids[0] + ); + } + + private function getColumns( + ColumnFactory $column_factory, + Language $lng + ): array { + return [ + 'gap' => $column_factory->text( + $lng->txt('gap') + )->withIsSortable(false), + 'answer_options' => $column_factory->text( + $lng->txt('answer_options') + )->withIsSortable(false), + 'feedback' => $column_factory->text( + $lng->txt('feedback') + )->withIsSortable(false) + ]; + } + + private function getActions( + Environment $environment + ): array { + $af = $environment->getUIFactory()->table()->action(); + $lng = $environment->getLanguage(); + + return [ + 'edit' => $af->single( + $lng->txt('edit'), + $environment->withSubActionParameter( + self::SUB_ACTION_EDIT_FEEDBACK + )->getUrlBuilder(), + $environment->getTableRowIdToken() + )->withAsync(true), + 'delete' => $af->single( + $lng->txt('delete'), + $environment->withSubActionParameter( + self::SUB_ACTION_CONFIRM_DELETE_FEEDBACK + )->getUrlBuilder(), + $environment->getTableRowIdToken() + )->withAsync(true), + ]; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Definition.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Definition.php new file mode 100644 index 000000000000..c9460bd3b1dd --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Definition.php @@ -0,0 +1,142 @@ + $available_capabilities + */ + private readonly array $available_capabilities; + + /** + * @param list $available_capabilities + */ + public function __construct( + private readonly TableDefinitions $table_definitions, + array $available_capabilities, + private readonly PropertiesFactory $properties_factory, + private readonly ResponseFactory $response_factory, + private readonly Edit $edit_view + ) { + $this->available_capabilities = array_reduce( + $available_capabilities, + function (array $c, TypeSpecification $v): array { + $c[$v::getCapabilityIdentifier()] = $v; + return $c; + }, + [] + ); + } + + #[\Override] + public function getLabel( + Language $lng + ): string { + return $lng->txt('cloze'); + } + + #[\Override] + public function buildProperties( + TypeGenericProperties $type_generic_data, + ?Query $query + ): Properties { + return $this->properties_factory->fromData( + $type_generic_data, + $query + ); + } + + #[\Override] + public function buildResponse( + Uuid $response_id, + AnswerFormProperties $answer_form_properties, + ?Query $query + ): Response { + return $this->response_factory->fromQuery( + $response_id, + $answer_form_properties, + $query + ); + } + + #[\Override] + public function buildResponseFromPreviewData( + Uuid $response_id, + AnswerFormProperties $answer_form_properties, + array $preview_data + ): Response { + return $this->response_factory->fromPreviewData( + $response_id, + $answer_form_properties, + $preview_data + ); + } + + #[\Override] + public function getTableDefinitions(): TableDefinitions + { + return $this->table_definitions; + } + + #[\Override] + public function hasCapability( + string $capability_identifier + ): bool { + return array_key_exists($capability_identifier, $this->available_capabilities); + } + + #[\Override] + public function getCapability( + string $capability_identifier + ): ?TypeSpecification { + return $this->available_capabilities[$capability_identifier] ?? null; + } + + #[\Override] + public function getEditView(): Edit + { + return $this->edit_view; + } + + #[\Override] + public function initializeAttemptData( + Attempt $attempt, + AnswerFormProperties $answer_form_properties + ): Attempt { + return $answer_form_properties->getGaps()->initializeAttemptData($attempt); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Layout/OverviewTable.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Layout/OverviewTable.php new file mode 100644 index 000000000000..731f85f2b8ea --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Layout/OverviewTable.php @@ -0,0 +1,137 @@ +environment->getUIFactory()->table()->data( + $this, + $this->environment->getLanguage()->txt('gaps'), + $this->getColums() + )->withActions($this->getActions()) + ->withRequest( + $this->environment->getHttpServices()->request() + ); + } + + #[\Override] + public function getRows( + DataRowBuilder $row_builder, + array $visible_column_ids, + Range $range, + Order $order, + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): \Generator { + yield from $this->environment->getAnswerFormProperties()->getGaps() + ->toTableRows( + $row_builder, + $this->environment->getLanguage(), + $this->environment->isMarkingRequired() + ); + } + + #[\Override] + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return $this->environment->getAnswerFormProperties() + ->getGaps()->getNumberOfGaps(); + } + + private function getColums(): array + { + $f = $this->environment->getUIFactory()->table()->column(); + + $columns = [ + 'gap' => $f->text( + $this->environment->getLanguage()->txt('title') + )->withIsSortable(false), + 'type' => $f->text( + $this->environment->getLanguage()->txt('gap_type') + )->withIsSortable(false) + ]; + + if ($this->environment->isMarkingRequired()) { + $columns = [ + ...$columns, + 'answers_options_awarding_points' => $f->text( + $this->environment->getLanguage()->txt('answer_options_awarding_points') + )->withIsSortable(false), + 'available_points' => $f->number( + $this->environment->getLanguage()->txt('available_points') + )->withDecimals(4) + ->withIsSortable(false) + ]; + } + + return $columns; + } + + private function getActions(): array + { + $taf = $this->environment->getUIFactory()->table()->action(); + return array_reduce( + $this->environment->getAnswerFormTableActionsForRequiredCapabilities(), + function (array $c, TableAction $v): array { + $c[] = $v; + return $c; + }, + [ + 'edit_gaps' => $taf->standard( + $this->environment->getLanguage()->txt('edit_gaps'), + $this->environment + ->withSubActionParameter(EditGaps::SUB_ACTION_JUMP_TO_SET_GAP_TYPES) + ->withFormStartSubActionParameter(EditGaps::SUB_ACTION_JUMP_TO_SET_GAP_TYPES) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + ), + 'edit_answer_options' => $taf->standard( + $this->environment->getLanguage()->txt('edit_answer_options'), + $this->environment + ->withSubActionParameter(EditGaps::SUB_ACTION_JUMP_TO_SET_ANSWER_OPTIONS) + ->withFormStartSubActionParameter(EditGaps::SUB_ACTION_JUMP_TO_SET_ANSWER_OPTIONS) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + ) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/BasicMigrationFunctions.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/BasicMigrationFunctions.php new file mode 100644 index 000000000000..274a57f2dff5 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/BasicMigrationFunctions.php @@ -0,0 +1,281 @@ +answer_inputs_mapping === null) { + return null; + } + + return $this->answer_inputs_mapping[$id] ?? null; + } + + private function buildGapInsertStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + ?Insert $gaps_insert, + Uuid $answer_input_id, + Uuid $answer_form_id, + int $position, + string $gap_type, + ?int $max_chars, + ?float $step_size, + ?TextMatchingOptions $matching_options, + ?int $min_autocomplete, + ?int $shuffle + ): Insert { + $this->answer_inputs_mapping[$position] = $answer_input_id; + + if ($gaps_insert === null) { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerInputs + ), + $this->buildGapValuesForInsert( + $persistence_factory, + $answer_input_id, + $answer_form_id, + $position, + $gap_type, + $max_chars, + $step_size, + $matching_options, + $min_autocomplete, + $shuffle + ) + ); + } + + return $gaps_insert->withAdditionalValues( + $this->buildGapValuesForInsert( + $persistence_factory, + $answer_input_id, + $answer_form_id, + $position, + $gap_type, + $max_chars, + $step_size, + $matching_options, + $min_autocomplete, + $shuffle + ) + ); + } + + private function buildGapValuesForInsert( + PersistenceFactory $persistence_factory, + Uuid $answer_input_id, + Uuid $answer_form_id, + int $position, + string $gap_type, + ?int $max_chars, + ?float $step_size, + ?TextMatchingOptions $matching_options, + ?int $min_autocomplete, + ?int $shuffle + ): array { + return [ + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_input_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_form_id->toString()), + $persistence_factory->value(FieldDefinition::T_INTEGER, $position), + $persistence_factory->value(FieldDefinition::T_TEXT, $gap_type), + $persistence_factory->value(FieldDefinition::T_INTEGER, $max_chars), + $persistence_factory->value(FieldDefinition::T_FLOAT, $step_size), + $persistence_factory->value(FieldDefinition::T_INTEGER, $matching_options?->value), + $persistence_factory->value(FieldDefinition::T_INTEGER, $min_autocomplete), + $persistence_factory->value(FieldDefinition::T_INTEGER, $shuffle) + ]; + } + + private function buildAnswerOptionInsertStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + ?Insert $options_insert, + Uuid $answer_option_id, + Uuid $answer_input_id, + int $position, + string $text_value, + float $points, + ?float $lower_limit, + ?float $upper_limit + ): Insert { + if ($options_insert === null) { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerOptions + ), + $this->buildOptionValuesForInsert( + $persistence_factory, + $answer_option_id, + $answer_input_id, + $position, + $text_value, + $points, + $lower_limit, + $upper_limit + ) + ); + } + + return $options_insert->withAdditionalValues( + $this->buildOptionValuesForInsert( + $persistence_factory, + $answer_option_id, + $answer_input_id, + $position, + $text_value, + $points, + $lower_limit, + $upper_limit + ) + ); + } + + private function buildOptionValuesForInsert( + PersistenceFactory $persistence_factory, + Uuid $answer_option_id, + Uuid $answer_input_id, + int $position, + string $text_value, + float $points, + ?float $lower_limit, + ?float $upper_limit + ): array { + return [ + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_option_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_input_id->toString()), + $persistence_factory->value(FieldDefinition::T_INTEGER, $position), + $persistence_factory->value(FieldDefinition::T_TEXT, $text_value), + $persistence_factory->value(FieldDefinition::T_FLOAT, $points), + $persistence_factory->value(FieldDefinition::T_FLOAT, $lower_limit), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $lower_limit !== $upper_limit + ? $upper_limit + : null + ) + ]; + } + + private function buildAnswerFormInsertStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + Uuid $answer_form_id, + ScoringIdentical $scoring_identical, + int $combinations_enabled + ): Insert { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ), + [ + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_form_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $scoring_identical->value), + $persistence_factory->value(FieldDefinition::T_INTEGER, $combinations_enabled) + ] + ); + } + + private function buildScoringIdenticalFromOld( + int $scoring_identical + ): ScoringIdentical { + if ($scoring_identical === '1') { + return ScoringIdentical::ScoreAll; + } + + return ScoringIdentical::OnlyScoreDistinct; + } + + private function buildNewTextRatingFromOld( + string $old_text_rating + ): TextMatchingOptions { + return match($old_text_rating) { + \assClozeGap::TEXTGAP_RATING_CASEINSENSITIVE => TextMatchingOptions::CaseInsensitive, + \assClozeGap::TEXTGAP_RATING_CASESENSITIVE => TextMatchingOptions::CaseSensitive, + \assClozeGap::TEXTGAP_RATING_LEVENSHTEIN1 => TextMatchingOptions::Levenstein1, + \assClozeGap::TEXTGAP_RATING_LEVENSHTEIN2 => TextMatchingOptions::Levenstein2, + \assClozeGap::TEXTGAP_RATING_LEVENSHTEIN3 => TextMatchingOptions::Levenstein3, + \assClozeGap::TEXTGAP_RATING_LEVENSHTEIN4 => TextMatchingOptions::Levenstein4, + \assClozeGap::TEXTGAP_RATING_LEVENSHTEIN5 => TextMatchingOptions::Levenstein5 + }; + } + + private function replaceGapsAndSantizeLegacyClozeText( + \ilDBInterface $db, + string $gap_replace_regex, + string $text, + array $gaps_mapping, + bool $ilias_page_editor_text + ): string { + ksort($gaps_mapping); + + return mb_ereg_replace_callback( + $gap_replace_regex, + function (array $matches) use (&$gaps_mapping): string { + return '{{' . Gap::GAP_PLACEHOLDER_NAME . '_' . array_shift($gaps_mapping) . '}}'; + }, + $this->sanitizeLegacyText( + $db, + $text, + $ilias_page_editor_text + ) + ); + } + + private function limitToFloat( + \EvalMath $math, + string $limit + ): float { + return (float) $math->e($limit); + } + + private function getHtmlQuestionContentPurifier(): \ilHtmlPurifierInterface + { + return \ilHtmlPurifierFactory::getInstanceByType('qpl_usersolution'); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationCloze.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationCloze.php new file mode 100644 index 000000000000..7ab1ed084c22 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationCloze.php @@ -0,0 +1,402 @@ +fetchDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $db_row) { + $answer_form_id = $migration_insert->getAnswerFormId(); + if (!isset($answer_input_mapping[$db_row->gap_id])) { + $answer_input_mapping[$db_row->gap_id] = $migration_insert->getUuid(); + $answer_options_mapping[$db_row->gap_id] = []; + $this->answer_options_mapping_for_feedback[$db_row->gap_id] = [ + 'is_numeric' => $db_row->cloze_type == \assClozeGap::TYPE_NUMERIC, + 'is_feedback_per_gap' => $db_row->feedback_mode === \ilAssClozeTestFeedback::FB_MODE_GAP_QUESTION, + 'answer_options' => [] + ]; + $gaps_insert = $this->buildGapInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $gaps_insert, + $answer_input_mapping[$db_row->gap_id], + $answer_form_id, + $db_row->gap_id, + $this->buildNewGapTypeIdentifierFromOld((int) $db_row->cloze_type), + null, + null, + $this->buildNewTextRatingFromOld($db_row->textgap_rating), + null, + $db_row->shuffle === '1' ? 1 : 0 + ); + } + + $answer_option_id = $migration_insert->getUuid(); + $answer_options_mapping[$db_row->gap_id][$db_row->answertext] = [ + 'is_numeric' => $db_row->cloze_type == \assClozeGap::TYPE_NUMERIC, + 'answer_option_id' => $answer_option_id + ]; + $this->answer_options_mapping_for_feedback[$db_row->gap_id]['answer_options'][$db_row->aorder] = $answer_option_id; + + if (!isset($available_points[$answer_option_id->toString()]) + || $available_points[$answer_option_id->toString()] < $db_row->points) { + $available_points[$answer_option_id->toString()] = $db_row->points; + } + + $answer_options_insert = $this->buildAnswerOptionInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_options_insert, + $answer_option_id, + $answer_input_mapping[$db_row->gap_id], + $db_row->aorder, + $db_row->answertext, + $db_row->points, + $this->limitToFloat($this->math, $db_row->lowerlimit), + $this->limitToFloat($this->math, $db_row->upperlimit) + ); + } + + if (!isset($db_row)) { + return null; + } + + if ($db_row->combinations_enabled) { + $migration_insert = $this->addCombinationInsertStatements( + $migration_insert->getPersistenceFactory(), + $migration_insert, + $answer_input_mapping, + $answer_options_mapping + ); + } + + return $migration_insert + ->withAdditionalInsert( + $this->buildAnswerFormInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_form_id, + $this->buildScoringIdenticalFromOld((int) $db_row->identical_scoring), + $db_row->combinations_enabled + ) + )->withAdditionalInsert( + $gaps_insert + )->withAdditionalInsert( + $answer_options_insert + )->withAdditionalTextLegacy( + $this->replaceGapsAndSantizeLegacyClozeText( + $migration_insert->getDb(), + '\[gap\].+?\[\/gap\]', + $db_row->cloze_text, + $answer_input_mapping, + $migration_insert->wasIliasPageEditorUsedForAdditionalTexts() + ) + )->withAvailablePoints( + array_reduce( + $available_points, + fn(float $c, float $v): float => $c + $v, + 0.0 + ) + ); + } + + #[\Override] + public function getConditionsForFeedbackFromOldValues( + int $answer, + int $question + ): ?array { + $gap = $this->answer_options_mapping_for_feedback[$question]; + + if ($gap['is_feedback_per_gap'] && $answer !== -10 + || !$gap['is_feedback_per_gap'] && $answer === -10) { + return null; + } + + if ($answer === -10) { + return array_map( + fn(Uuid $v): string => $v->toString(), + $gap['answer_options'] + ); + } + + if ($answer === -1) { + return [Types::NoResponse->value]; + } + + if ($answer === -2) { + return [Types::OtherResponse->value]; + } + + if ($gap['is_numeric']) { + return [$this->buildRangeValue(true, $answer)->value]; + } + + $answer_option_id = array_filter( + $gap['answer_options'], + fn(string $v): bool => $v == $answer, + ARRAY_FILTER_USE_KEY + ); + + if ($answer_option_id !== []) { + return [array_shift($answer_option_id)->toString()]; + } + + return null; + } + + private function fetchDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->query( + 'SELECT *, EXISTS (' . PHP_EOL + . 'SELECT gap_fi FROM qpl_a_cloze_combi_res' . PHP_EOL + . 'WHERE question_fi = a.question_fi' . PHP_EOL + . ') combinations_enabled' . PHP_EOL + . 'FROM qpl_qst_cloze q' . PHP_EOL + . 'JOIN qpl_a_cloze a ON q.question_fi = a.question_fi' . PHP_EOL + . "WHERE q.question_fi = {$db->quote($old_question_id)}" . PHP_EOL + . 'ORDER BY a.gap_id, a.aorder' + ); + + while (($row = $db->fetchObject($query)) !== null) { + yield $row; + } + } + + private function fetchCombinationsDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->query( + 'SELECT combination_id, gap_fi, answer, points, row_id FROM qpl_a_cloze_combi_res' . PHP_EOL + . "WHERE question_fi = {$db->quote($old_question_id)}" . PHP_EOL + . 'ORDER BY combination_id, row_id' + ); + + while (($row = $db->fetchObject($query)) !== null) { + yield $row; + } + } + + private function addCombinationInsertStatements( + PersistenceFactory $persistence_factory, + MigrationInsert $migration_insert, + array $answer_input_mapping, + array $answer_options_mapping + ): MigrationInsert { + $combination_mapping = []; + $combinations_insert = null; + $combinations_to_answer_options_insert = null; + foreach ($this->fetchCombinationsDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $db_row) { + if ($db_row->answer !== 'out_of_bound' + && !isset($answer_options_mapping[$db_row->gap_fi][$db_row->answer])) { + continue; + } + + $answer_option = $db_row->answer === 'out_of_bound' + ? reset($answer_options_mapping[$db_row->gap_fi]) + : $answer_options_mapping[$db_row->gap_fi][$db_row->answer]; + + if (!isset($combination_mapping[$db_row->combination_id . $db_row->row_id])) { + $combination_mapping[$db_row->combination_id . $db_row->row_id] = $migration_insert->getUuid(); + $combinations_insert = $this->buildCombinationsInsert( + $persistence_factory, + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $combinations_insert, + $combination_mapping[$db_row->combination_id . $db_row->row_id], + $migration_insert->getAnswerFormId(), + $db_row->points + ); + } + + $combinations_to_answer_options_insert = $this->buildCombinationsToAnswerOptionsInsert( + $persistence_factory, + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $combinations_to_answer_options_insert, + $combination_mapping[$db_row->combination_id . $db_row->row_id], + $answer_input_mapping[$db_row->gap_fi], + $answer_option['answer_option_id'], + $this->buildRangeValue($answer_option['is_numeric'], $db_row->answer) + ); + } + + return $migration_insert->withAdditionalInsert($combinations_insert) + ->withAdditionalInsert($combinations_to_answer_options_insert); + } + + private function buildCombinationsInsert( + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + ?Insert $combinations_insert, + Uuid $combination_id, + Uuid $answer_form_id, + float $points + ): Insert { + $values = [ + $persistence_factory->value(FieldDefinition::T_TEXT, $combination_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_form_id->toString()), + $persistence_factory->value(FieldDefinition::T_FLOAT, $points), + ]; + + if ($combinations_insert === null) { + return $persistence_factory->insert( + $this->table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationsTableIdentifier() + ), + $values + ); + } + + return $combinations_insert->withAdditionalValues($values); + } + + private function buildCombinationsToAnswerOptionsInsert( + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + ?Insert $combinations_to_answer_options_insert, + Uuid $combination_id, + Uuid $gap_id, + Uuid $answer_option_id, + ?Range $in_range + ): Insert { + $values = [ + $persistence_factory->value(FieldDefinition::T_TEXT, $combination_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $gap_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_option_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $in_range?->value) + ]; + + if ($combinations_to_answer_options_insert === null) { + return $persistence_factory->insert( + $this->table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ), + $values + ); + } + + return $combinations_to_answer_options_insert->withAdditionalValues($values); + } + + private function buildNewGapTypeIdentifierFromOld( + int $old_gap_type + ): string { + return match($old_gap_type) { + \assClozeGap::TYPE_TEXT => 'text', + \assClozeGap::TYPE_SELECT => 'select', + \assClozeGap::TYPE_NUMERIC => 'numeric' + }; + } + + private function buildRangeValue( + bool $is_numeric, + string|int $value + ): ?Range { + if ($is_numeric === false) { + return null; + } + + if ($value === 'out_of_bounds') { + return Range::OutOfRange; + } + + if ($value === \ilAssClozeTestFeedback::FB_NUMERIC_GAP_TOO_LOW_INDEX) { + return Range::BelowRange; + } + + if ($value === \ilAssClozeTestFeedback::FB_NUMERIC_GAP_TOO_HIGH_INDEX) { + return Range::AboveRange; + } + + return Range::InRange; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationLongMenu.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationLongMenu.php new file mode 100644 index 000000000000..8fe8575e950e --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationLongMenu.php @@ -0,0 +1,228 @@ +getAnswerFormId(); + + $answer_input_mapping = []; + $gaps_insert = null; + $answer_options_to_insert = []; + $available_points = []; + + foreach ($this->fetchDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $db_row) { + if (!isset($answer_input_mapping[$db_row->gap_number])) { + $answer_input_id = $migration_insert->getUuid(); + $answer_input_mapping[$db_row->gap_number] = $answer_input_id; + + $gaps_insert = $this->buildGapInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $gaps_insert, + $answer_input_id, + $answer_form_id, + $db_row->gap_number, + $this->buildNewGapTypeIdentifierFromOld($db_row->type), + null, + null, + null, + $db_row->min_auto_complete, + $db_row->shuffle_answers === '1' ? 1 : 0 + ); + + $answers_from_file = $this->loadAnswersFromFile( + $environment->getResource(Environment::RESOURCE_ILIAS_INI), + $environment->getResource(Environment::RESOURCE_CLIENT_ID), + $migration_insert->getOldQuestionId(), + $db_row->gap_number + ); + + $answer_options_to_insert[$answer_input_id->toString()] = array_map( + fn(int $v) => [ + 'answer_option_id' => $migration_insert->getUuid(), + 'answer_input_id' => $answer_input_id, + 'position' => $v, + 'text' => trim($answers_from_file[$v]), + 'points' => 0.0 + ], + array_keys($answers_from_file) + ); + } + + $answer_input_id_string = $answer_input_mapping[$db_row->gap_number]->toString(); + $position = array_find_key( + $answer_options_to_insert[$answer_input_id_string], + fn(array $v, int $k): bool => trim($v['text']) === trim($db_row->answer_text) + ); + + if ($position !== null) { + $answer_options_to_insert[$answer_input_id_string][$position]['points'] = $db_row->points; + $available_points[$answer_input_id_string] = $db_row->points; + } + } + + if (!isset($db_row)) { + return null; + } + + $answer_options_insert = null; + foreach (array_reduce( + $answer_options_to_insert, + fn(array $c, array $v): array => [...$c, ...$v], + [] + ) as $answer) { + $answer_options_insert = $this->buildAnswerOptionInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_options_insert, + $answer['answer_option_id'], + $answer['answer_input_id'], + $answer['position'], + $answer['text'], + $answer['points'], + null, + null + ); + } + + return $migration_insert + ->withAdditionalInsert( + $this->buildAnswerFormInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_form_id, + $this->buildScoringIdenticalFromOld($db_row->identical_scoring), + 0 + ) + )->withAdditionalTextLegacy( + $this->replaceGapsAndSantizeLegacyClozeText( + $migration_insert->getDb(), + '\[Longmenu \d+\]', + $db_row->long_menu_text, + $answer_input_mapping, + $migration_insert->wasIliasPageEditorUsedForAdditionalTexts() + ) + )->withAdditionalInsert($gaps_insert) + ->withAdditionalInsert($answer_options_insert) + ->withAvailablePoints( + array_reduce( + $available_points, + fn(float $c, float $v): float => $c + $v, + 0.0 + ) + ); + } + + #[\Override] + public function getConditionsForFeedbackFromOldValues( + int $answer, + int $question + ): null { + return null; + } + + private function fetchDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->query( + 'SELECT * FROM qpl_qst_lome q' . PHP_EOL + . 'JOIN qpl_a_lome a ON q.question_fi = a.question_fi' . PHP_EOL + . "WHERE q.question_fi = {$db->quote($old_question_id)}" . PHP_EOL + . 'ORDER BY a.gap_number, a.position' + ); + + while (($row = $db->fetchObject($query)) !== null) { + yield $row; + } + } + + private function loadAnswersFromFile( + \ilIniFile $ini, + string $client_id, + int $old_question_id, + int $gap_id + ): array { + $file = "{$ini->readVariable('clients', 'datadir')}/{$client_id}/assessment/longMenuQuestion/{$old_question_id}/{$gap_id}.txt"; + + if (!file_exists($file)) { + return []; + } + + return explode( + "\n", + file_get_contents($file) + ); + } + + private function buildNewGapTypeIdentifierFromOld( + int $old_gap_type + ): string { + return match($old_gap_type) { + \assLongMenu::ANSWER_TYPE_TEXT_VAL => 'long_menu', + \assLongMenu::ANSWER_TYPE_SELECT_VAL => 'select' + }; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationNumeric.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationNumeric.php new file mode 100644 index 000000000000..6649cc95aff8 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationNumeric.php @@ -0,0 +1,142 @@ +math->suppress_errors = true; + } + + #[\Override] + public function getOldQuestionTypeIdentifier(): string + { + return 'assNumeric'; + } + + #[\Override] + public function getDefinitionClass(): string + { + return Definition::class; + } + + #[\Override] + public function completeMigrationInsert( + Environment $environment, + MigrationInsert $migration_insert + ): ?MigrationInsert { + $db_row = $this->fetchDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + )?->current(); + + if ($db_row === null) { + return null; + } + + $answer_form_id = $migration_insert->getAnswerFormId(); + $gap_id = $migration_insert->getUuid(); + return $migration_insert->withAdditionalInsert( + $this->buildGapInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + null, + $gap_id, + $answer_form_id, + 0, + 'numeric', + null, + 0.0001, + null, + null, + null + ) + )->withAdditionalInsert( + $this->buildAnswerOptionInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + null, + $migration_insert->getUuid(), + $gap_id, + 0, + '', + $db_row->points, + $this->limitToFloat($this->math, $db_row->lowerlimit), + $this->limitToFloat($this->math, $db_row->upperlimit) + ) + )->withAdditionalInsert( + $this->buildAnswerFormInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_form_id, + ScoringIdentical::ScoreAll, + 0 + ) + )->withAdditionalText( + '{{' . Gap::GAP_PLACEHOLDER_NAME . '_' . $gap_id->toString() . '}}' + )->withAvailablePoints($db_row->points); + } + + #[\Override] + public function getConditionsForFeedbackFromOldValues( + int $answer, + int $question + ): null { + return null; + } + + private function fetchDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->query( + 'SELECT points, lowerlimit, upperlimit FROM qpl_num_range' . PHP_EOL + . "WHERE question_fi = {$db->quote($old_question_id)}" + ); + + while (($row = $db->fetchObject($query)) !== null) { + yield $row; + } + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationTextSubset.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationTextSubset.php new file mode 100644 index 000000000000..27e0a58182b9 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Migration/MigrationTextSubset.php @@ -0,0 +1,185 @@ +getAnswerFormId(); + $answer_options_insert = null; + $gaps = []; + $available_points = []; + + foreach ($this->fetchDBValues( + $migration_insert->getDb(), + $migration_insert->getOldQuestionId() + ) as $db_row) { + if ($gaps === []) { + $gaps_insert = null; + for ($i = 0; $i < $db_row->correctanswers; $i++) { + $gap_id = $migration_insert->getUuid(); + $gaps[] = $gap_id; + + $gaps_insert = $this->buildGapInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $gaps_insert, + $gap_id, + $answer_form_id, + $i, + 'text', + null, + null, + $this->buildNewTextRatingFromOld($db_row->textgap_rating), + null, + 0 + ); + } + + $migration_insert = $migration_insert->withAdditionalInsert($gaps_insert); + } + + $available_points[] = $db_row->points; + + foreach ($gaps as $gap_id) { + $answer_options_insert = $this->buildAnswerOptionInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_options_insert, + $migration_insert->getUuid(), + $gap_id, + $db_row->aorder, + $db_row->answertext, + $db_row->points, + null, + null + ); + } + } + + if (!isset($db_row)) { + return null; + } + + rsort($available_points); + + return $migration_insert + ->withAdditionalInsert( + $this->buildAnswerFormInsertStatement( + $this->table_definitions, + $migration_insert->getPersistenceFactory(), + $migration_insert->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $answer_form_id, + ScoringIdentical::OnlyScoreDistinct, + 0 + ) + )->withAdditionalInsert( + $answer_options_insert + )->withAdditionalText( + $this->buildAdditionalTextFromGapsArray($gaps) + )->withAvailablePoints( + array_sum( + array_slice( + $available_points, + 0, + count($gaps) + ) + ) + ); + } + + #[\Override] + public function getConditionsForFeedbackFromOldValues( + int $answer, + int $question + ): null { + return null; + } + + private function fetchDBValues( + \ilDBInterface $db, + int $old_question_id + ): \Generator { + $query = $db->query( + 'SELECT * FROM qpl_qst_textsubset q' . PHP_EOL + . 'JOIN qpl_a_textsubset a ON q.question_fi = a.question_fi' . PHP_EOL + . "WHERE q.question_fi = {$db->quote($old_question_id)}" . PHP_EOL + ); + + while (($row = $db->fetchObject($query)) !== null) { + yield $row; + } + } + + private function buildAdditionalTextFromGapsArray( + array $gaps + ): string { + $text_array = []; + foreach ($gaps as $index => $gap) { + $position = $index + 1; + $text_array[] = "{$position}. {{GAP_{$gap->toString()}}}"; + } + + return implode( + "\n\n", + $text_array + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Factory.php new file mode 100644 index 000000000000..b24c6ab3de23 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Factory.php @@ -0,0 +1,46 @@ +refinery, + $this->mustache_engine, + $this->text_factory, + $this->text_factory->markdown($text) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Text.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Text.php new file mode 100644 index 000000000000..2bab1bf870a2 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/ClozeText/Text.php @@ -0,0 +1,202 @@ +markdown( + new \ilUIMarkdownPreviewGUI(), + $lng->txt('cloze_text') + )->withMustacheVariables([ + Gap::GAP_PLACEHOLDER_NAME => $lng->txt('insert_gap') + ])->withAdditionalTransformation( + $this->refinery->custom()->transformation( + fn(string $v): self => $cloze_text_factory->buildFromTextString($v) + ) + )->withAdditionalTransformation( + $this->refinery->custom()->constraint( + fn(self $v): bool => !$is_required && $v->getRawRepresentation() === '' + || $v->hasAtLeastOneGap(), + $lng->txt('no_gaps') + ) + )->withRequired($is_required) + ->withValue($this->cloze_text->getRawRepresentation()); + } + + public function getRawRepresentation(): string + { + return $this->cloze_text->getRawRepresentation(); + } + + public function getRenderedMarkdownForParticipantPresentation(): string + { + return $this->refinery->string()->markdown()->toHTML()->transform( + $this->cloze_text->getRawRepresentation() + ); + } + + public function buildPanelForEditing( + UIFactory $ui_factory, + Language $lng, + Gaps $gaps, + string $legacy_cloze_text + ): StandardPanel { + return $ui_factory->panel()->standard( + $lng->txt('cloze_text'), + $ui_factory->legacy()->latexContent( + $this->getRenderedMarkdownForEditingPresentation( + $gaps, + $legacy_cloze_text + ) + ) + ); + } + + public function getRenderedMarkdownForEditingPresentation( + Gaps $gaps, + string $legacy_cloze_text + ): string { + $text = $this->cloze_text->getRawRepresentation() === '' + ? $legacy_cloze_text + : $this->refinery->string()->markdown()->toHTML()->transform( + $this->cloze_text->getRawRepresentation() + ); + + return $this->mustache_engine->render( + $text, + $gaps->getPlaceholderArrayForEditFormPanel() + ); + } + + public function updateGapsFromMarkdown( + Uuid $answer_form_id, + Gaps $pre_existing_gaps + ): Gaps { + if ($this->cloze_text->getRawRepresentation() === '') { + return $pre_existing_gaps->withResetGaps(); + } + + $position = 0; + return array_reduce( + $this->mustache_engine->getTokenizer()->scan($this->cloze_text->getRawRepresentation()), + function (Gaps $c, array $v) use ($answer_form_id, $pre_existing_gaps, &$position): Gaps { + if ($v['type'] !== '_v' + || !str_starts_with($v['name'], Gap::GAP_PLACEHOLDER_NAME)) { + return $c; + } + + if ($v['name'] === Gap::GAP_PLACEHOLDER_NAME) { + return $c->withNewGap($answer_form_id, $position++); + } + + $gap = $pre_existing_gaps->getGapByTagName($v['name']); + if ($gap !== null) { + return $c->withGap( + $gap->withPosition( + $position++ + ) + ); + } + + return $c->withAdditionalGapFromTagName( + $answer_form_id, + $v['name'], + $position++ + ); + }, + $pre_existing_gaps->withResetGaps() + ); + } + + public function withUpdateMarkdownAfterCloning( + \Closure $replace_gaps + ): self { + $clone = clone $this; + $clone->cloze_text = $this->text_factory->markdown( + $replace_gaps($clone->cloze_text->getRawRepresentation()) + ); + return $clone; + } + + public function withIdsOfNewGapsInClozeText( + array $new_gaps + ): self { + if ($new_gaps === []) { + return $this; + } + + $clone = clone $this; + $clone->cloze_text = $this->text_factory->markdown( + mb_ereg_replace_callback( + '{{' . Gap::GAP_PLACEHOLDER_NAME . '}}', + function (array $matches) use (&$new_gaps): string { + return array_shift($new_gaps)->getGapPlaceholder(); + }, + $this->cloze_text->getRawRepresentation() + ) + ); + return $clone; + } + + private function hasAtLeastOneGap(): bool + { + if ($this->cloze_text->getRawRepresentation() === '') { + return false; + } + + foreach ($this->mustache_engine->getTokenizer() + ->scan($this->cloze_text->getRawRepresentation()) as $token) { + if ($token['type'] === '_v' + && str_starts_with($token['name'], Gap::GAP_PLACEHOLDER_NAME)) { + return true; + } + } + + return false; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combination.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combination.php new file mode 100644 index 000000000000..9c0d9656bfb9 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combination.php @@ -0,0 +1,353 @@ + $matching_values + */ + public function __construct( + private Uuid $id, + private readonly ?float $available_points, + private array $matching_values = [] + ) { + uasort( + $this->matching_values, + fn(MatchingValue $a, MatchingValue $b): int => $a->getGap()->getPosition() <=> $b->getGap()->getPosition() + ); + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getAvailablePoints(): ?float + { + return $this->available_points; + } + + public function getValuePresentation( + Language $lng + ): string { + return implode( + '
', + array_map( + fn(MatchingValue $v): string => $v->buildPresentationString($lng), + $this->matching_values + ) + ); + } + + public function containsAnswerOptionsExactly( + array $vs + ): bool { + return array_diff( + $vs, + array_map( + fn(MatchingValue $v): string => $v->getAnswerOption()->getAnswerOptionId()->toString(), + $this->matching_values + ) + ) === []; + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $environment['combination_id'] = $uuid_factory->uuid4(); + $clone = clone $this; + $clone->id = $environment['combination_id']; + $clone->matching_values = array_map( + fn(MatchingValue $v): MatchingValue => $v->clone( + $uuid_factory, + $environment + ), + $clone->matching_values + ); + return $clone; + } + + public function toStorage( + Uuid $answer_form_id, + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + Manipulate $manipulate + ): Manipulate { + if ($this->matching_values === []) { + throw new \UnexpectedValueException( + 'A Combination without MatchingValues cannot be stored.' + ); + } + + return array_reduce( + $this->matching_values, + fn(Manipulate $c, MatchingValue $v): Manipulate => $c->withAdditionalStatement( + $v->toStorage( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ), + $manipulate->withAdditionalStatement( + $this->buildReplace( + $table_definitions, + $persistence_factory, + $table_names_builder, + $answer_form_id + ) + ) + ); + } + + public function toDelete( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + Manipulate $manipulate + ): Manipulate { + return $manipulate->withAdditionalStatement( + $this->buildDelete( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + )->withAdditionalStatement( + $this->buildDeleteForLinkedValues( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ); + } + + private function buildReplace( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder, + Uuid $answer_form_id + ): Replace { + return $persistence_factory->replace( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + $table_definitions->getCombinationsTableIdentifier() + ), + [ + $persistence_factory->value(FieldDefinition::T_TEXT, $this->id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $answer_form_id->toString()), + $persistence_factory->value(FieldDefinition::T_FLOAT, $this->available_points) + ] + ); + } + + private function buildDelete( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_definition = AnswerFormSpecificTableTypes::Additional; + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_definition, + $table_definitions->getCombinationsTableIdentifier() + ), + [ + $persistence_factory->where( + $table_definitions->getIdColumn( + $table_names_builder, + $table_definition, + $table_definitions->getCombinationsTableIdentifier() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->id->toString() + ) + ) + ] + ); + } + + private function buildDeleteForLinkedValues( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_definition = AnswerFormSpecificTableTypes::Additional; + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_definition, + $table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ), + [ + $persistence_factory->where( + $table_definitions->getIdColumn( + $table_names_builder, + $table_definition, + $table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->id->toString() + ) + ) + ] + ); + } + + public function toTableRow( + Language $lng, + DataRowBuilder $data_row_builder + ): DataRow { + return $data_row_builder->buildDataRow( + $this->id->toString(), + [ + 'gaps' => $this->buildGapsString(), + 'values' => $this->getValuePresentation($lng), + 'available_points' => $this->getAvailablePoints() + ] + ); + } + + public function buildGapsString(): string + { + return implode( + '
', + array_map( + fn(MatchingValue $v): string => $v->getGap()->buildShortenedGapRepresentation(), + $this->matching_values + ) + ); + } + + public function buildPointsInputs( + FieldFactory $field_factory, + Refinery $refinery, + Language $lng, + Factory $combinations_factory, + Properties $properties + ): Section { + return $field_factory->section( + [ + 'values' => $this->buildValuesInputs( + $field_factory, + $properties + ), + 'points' => $field_factory->numeric( + $lng->txt('points') + )->withStepSize(0.01) + ->withRequired(true) + ->withValue($this->getAvailablePoints()) + ], + $lng->txt('values') + )->withAdditionalTransformation( + $refinery->custom()->constraint( + fn(array $vs): bool => !$properties->getCombinations() + ->hasMatchingCombinationForAnswerOptionIds($vs['values']), + $lng->txt('gap_combination_already_exists') + ) + )->withAdditionalTransformation( + $refinery->custom()->transformation( + fn(array $v): Properties => $properties->withCombinations( + $properties->getCombinations()->withAdditionalCombination( + $combinations_factory->buildCombination( + $this->id, + $v['points'], + $combinations_factory->buildMatchingValuesFromForm( + $properties, + $this->id, + $v['values'] + ) + ) + ) + ) + ) + ); + } + + public function buildCarryString(): string + { + return json_encode([ + $this->id->toString() => array_map( + fn(MatchingValue $v) => $v->getGap()->getAnswerInputId()->toString(), + $this->matching_values + ) + ]); + } + + private function buildValuesInputs( + FieldFactory $field_factory, + Properties $properties + ): Group { + return $field_factory->group( + array_reduce( + $this->matching_values, + function ( + array $c, + MatchingValue $v + ) use ( + $field_factory, + $properties + ): array { + $gap_id = $v->getGap()->getAnswerInputId(); + $gap = $properties->getGaps()->getGapById($gap_id); + $c[$gap_id->toString()] = $field_factory->select( + $gap->buildShortenedGapName(), + $gap->getType()->getCombinationsSelectValues($gap) + )->withRequired(true) + ->withValue( + $v->getInRange()?->value ?? $v->getAnswerOption() + ?->getAnswerOptionId()->toString() + ); + return $c; + }, + [] + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combinations.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combinations.php new file mode 100644 index 000000000000..9eee90c60fbb --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Combinations.php @@ -0,0 +1,187 @@ +combinations = array_reduce( + $combinations, + function (array $c, Combination $v): array { + $c[$v->getId()->toString()] = $v; + return $c; + }, + [] + ); + } + + public function areCombinationsEnabled(): bool + { + return $this->enabled; + } + + public function withCombinationsEnabled( + bool $combinations_enabled + ): self { + $clone = clone $this; + $clone->enabled = $combinations_enabled; + return $clone; + } + + public function getCombinationById( + string $id + ): ?Combination { + return $this->combinations[$id] ?? null; + } + + public function withAdditionalCombination( + Combination $combination + ): self { + $clone = clone $this; + $clone->combinations[$combination->getId()->toString()] = $combination; + return $clone; + } + + public function withoutCombination( + string $id + ): self { + $clone = clone $this; + $clone->deleted_combinations[] = $clone->combinations[$id]; + unset($clone->combinations[$id]); + return $clone; + } + + public function hasMatchingCombinationForAnswerOptionIds( + array $vs + ): bool { + foreach ($this->combinations as $combination) { + if ($combination->containsAnswerOptionsExactly($vs)) { + return true; + } + } + return false; + } + + public function getEditView(): Edit + { + return new Edit( + $this->combinations_factory + ); + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_form_id = $environment['answer_form_id']; + $clone->combinations = array_map( + fn(Combination $v): Combination => $v->clone( + $uuid_factory, + $environment + ), + $this->combinations + ); + return + $clone; + } + + public function toStorage( + Manipulate $manipulate, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Manipulate { + return array_reduce( + $this->combinations, + fn(Manipulate $c, Combination $v): Manipulate => $v->toStorage( + $this->answer_form_id, + $this->persistence_factory, + $table_definitions, + $table_names_builder, + $c + ), + array_reduce( + $this->deleted_combinations, + fn(Manipulate $c, Combination $v): Manipulate => $v->toDelete( + $this->persistence_factory, + $table_definitions, + $table_names_builder, + $manipulate + ), + $manipulate + ) + ); + } + + public function toDelete( + Manipulate $manipulate, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Manipulate { + return array_reduce( + $this->combinations, + fn(Manipulate $c, Combination $v): Manipulate => $c->withAdditionalStatement( + $v->toDelete( + $this->persistence_factory, + $table_definitions, + $table_names_builder, + $manipulate + ) + ), + $manipulate + ); + } + + public function toTableRows( + Language $lng, + DataRowBuilder $row_builder, + ): \Generator { + foreach ($this->combinations as $combination) { + yield $combination->toTableRow($lng, $row_builder); + } + } + + public function getNumberOfCombinations(): int + { + return count($this->combinations); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Edit.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Edit.php new file mode 100644 index 000000000000..fb7117472686 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Edit.php @@ -0,0 +1,83 @@ +addEditAnswerFormSubTab( + self::SUB_ACTION_EDIT_COMBINATIONS_OVERVIEW, + self::LANG_VAR_EDIT_COMBINATIONS + ); + } + + public function show( + Environment $environment + ): Async|Viewable|Properties|null { + if (!$environment->isMarkingRequired()) { + return null; + } + + $environment->addEditAnswerFormSubTab( + self::SUB_ACTION_EDIT_COMBINATIONS_OVERVIEW, + self::LANG_VAR_EDIT_COMBINATIONS + ); + + $environment->activateEditAnswerFormSubTab( + self::SUB_ACTION_EDIT_COMBINATIONS_OVERVIEW + ); + + $combinations_overview = $this->buildOverview($environment); + + $sub_action = $environment->getSubAction(); + if ($sub_action === self::SUB_ACTION_EDIT_COMBINATIONS_OVERVIEW + || $sub_action === '') { + return $combinations_overview; + } + + return $combinations_overview->doAction(); + } + + private function buildOverview( + Environment $environment + ): Overview { + return new Overview( + $environment, + $this->combinations_factory + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Factory.php new file mode 100644 index 000000000000..d6f13e896c44 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Factory.php @@ -0,0 +1,307 @@ +persistence_factory, + $type_generic_properties->getAnswerFormId(), + $combinations_enabled, + !$combinations_enabled || $gaps === null || $query === null + ? [] + : $this->retrieveCombinationsFromQuery( + $type_generic_properties + ->getDefinition() + ->getTableDefinitions() + ->getTableSubNameSpace(), + $this->retrieveMatchingValuesFromQuery( + $gaps, + $query + ), + $query + ) + ); + } + + /** + * @param array $gap_ids + */ + public function buildNewCombination( + Gaps $gaps, + array $gap_ids, + ): Combination { + $combination_id = $this->uuid_factory->uuid4(); + return $this->buildCombination( + $combination_id, + null, + array_map( + fn(string $v): MatchingValue => new MatchingValue( + $combination_id, + $gaps->getGapById( + $this->uuid_factory->fromString($v) + ) + ), + $gap_ids + ) + ); + } + + /** + * @param array<\ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Combinations\MatchingValue> $matching_values + */ + public function buildCombination( + Uuid $combination_id, + ?float $points, + array $matching_values + ): Combination { + return new Combination( + $combination_id, + $points, + $matching_values + ); + } + + /** + * @param array $values_array + */ + public function buildMatchingValuesFromForm( + Properties $properties, + Uuid $combination_id, + array $values_array + ): array { + return array_reduce( + array_keys($values_array), + function (array $c, string $v) use ( + $properties, + $values_array, + $combination_id + ): array { + $gap = $properties->getGaps()->getGapById( + $this->uuid_factory->fromString($v) + ); + + $range = Range::tryFrom($values_array[$v]); + $answer_option = $this->retrieveAnswerOptionForFormValues( + $gap, + $values_array[$v], + $range + ); + + if ($answer_option === null) { + return $c; + } + + $c[] = new MatchingValue( + $combination_id, + $gap, + $answer_option, + $range + ); + return $c; + }, + [] + ); + } + + public function buildCombinationFromCarryValue( + string $carry, + Properties $properties + ): Combination { + $values_array = json_decode($carry, true); + $combination_id = $this->uuid_factory->fromString( + array_key_first($values_array) + ); + + return new Combination( + $combination_id, + null, + array_map( + fn(string $v): MatchingValue => new MatchingValue( + $combination_id, + $properties->getGaps()->getGapById( + $this->uuid_factory->fromString($v) + ) + ), + $values_array[$combination_id->toString()] + ) + ); + } + + private function retrieveCombinationsFromQuery( + TableSubNameSpace $table_sub_name_space, + array $matching_values, + Query $query + ): array { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $query->getTableNameBuilder( + $table_sub_name_space + ), + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationsTableIdentifier() + ), + $query->getRefinery()->custom()->transformation( + fn(array $vs): array => $this->buildCombinationsFromQuery( + array_filter( + $vs, + fn(array $v): bool => $v['answer_form_id'] !== null + ), + $matching_values + ) + ) + ); + } + + private function buildCombinationsFromQuery( + array $values, + array $matching_values + ): array { + if ($values === []) { + return []; + } + + return array_reduce( + $values, + function (array $c, array $v) use ($matching_values): array { + if (array_key_exists($v['id'], $c)) { + return $c; + } + + $c[$v['id']] = new Combination( + $this->uuid_factory->fromString($v['id']), + $v['points'], + isset($matching_values[$v['id']]) + ? array_values($matching_values[$v['id']]) + : null + ); + + return $c; + }, + [] + ); + } + + private function retrieveMatchingValuesFromQuery( + Gaps $gaps, + Query $query + ): array { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $query->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace(), + ), + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ), + $query->getRefinery()->custom()->transformation( + function (array $vs) use ($gaps): array { + return $this->buildMatchingValuesArray( + $gaps, + $vs + ); + } + ) + ); + } + + private function retrieveAnswerOptionForFormValues( + Gap $gap, + string $value, + ?Range $range + ): AnswerOption { + if ($range === null) { + return $gap->getAnswerOptions() + ->getAnswerOptionById( + $this->uuid_factory->fromString($value) + ); + } + + $answer_options_awarding_points = $gap + ->getAnswerOptions() + ->getAnswerOptionsAwardingPoints(); + + return array_shift($answer_options_awarding_points); + } + + private function buildMatchingValuesArray( + Gaps $gaps, + array $values + ): array { + return array_reduce( + $values, + function (array $c, array $v) use ($gaps): array { + if (isset($c[$v['combination_id']][$v['gap_id']])) { + return $c; + } + + if (!array_key_exists($v['combination_id'], $c)) { + $c[$v['combination_id']] = []; + } + + $gap = $gaps->getGapById( + $this->uuid_factory->fromString($v['gap_id']) + ); + + $c[$v['combination_id']][$v['gap_id']] = new MatchingValue( + $this->uuid_factory->fromString($v['combination_id']), + $gap, + $gap->getAnswerOptions() + ->getAnswerOptionById( + $this->uuid_factory->fromString($v['answer_option_id']) + ), + Range::tryFrom($v['in_range'] ?? '') + ); + + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/MatchingValue.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/MatchingValue.php new file mode 100644 index 000000000000..519c536430a2 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/MatchingValue.php @@ -0,0 +1,134 @@ +gap; + } + + public function getAnswerOption(): ?AnswerOption + { + return $this->answer_option; + } + + public function getInRange(): ?Range + { + return $this->in_range; + } + + public function buildPresentationString( + Language $lng + ): string { + if ($this->answer_option === null) { + return ''; + } + + if ($this->in_range !== null) { + return $this->in_range->getLabel($lng); + } + + $value = $this->answer_option->getTextValue(); + if (strlen($value) < 11) { + return $value; + } + + return mb_substr($value, 0, 10) . '...'; + } + + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->combination_id = $environment['combination_id']; + $clone->gap = $environment['gaps']->getGapByPosition( + $this->gap->getPosition() + ); + return $clone; + } + + public function toStorage( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Replace { + if ($this->answer_option === null) { + throw new \UnexpectedValueException( + 'A MatchingValue without AnswerOption cannot be stored.' + ); + } + + $table_type = AnswerFormSpecificTableTypes::Additional; + return $persistence_factory->replace( + $table_definitions->getColumns( + $table_names_builder, + $table_type, + $table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ), + [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->combination_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->gap->getAnswerInputId()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_option?->getAnswerOptionId()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->in_range?->value + ) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Overview.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Overview.php new file mode 100644 index 000000000000..11b269ce6bce --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Combinations/Overview.php @@ -0,0 +1,347 @@ +buildSetCombinationGapsModal(); + $content = [ + $this->environment->getUIFactory()->button()->standard( + $this->environment->getLanguage()->txt('add_gap_combination'), + $modal->getShowSignal() + ), + $modal, + $this->buildTable() + ]; + if ($this->modal !== null) { + $content[] = $this->modal; + } + return $content; + } + + #[\Override] + public function getRows( + DataRowBuilder $row_builder, + array $visible_column_ids, + Range $range, + Order $order, + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): \Generator { + yield from $this->environment->getAnswerFormProperties() + ->getCombinations()->toTableRows( + $this->environment->getLanguage(), + $row_builder + ); + } + + #[\Override] + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return $this->environment->getAnswerFormProperties() + ->getCombinations()->getNumberOfCombinations(); + } + + public function doAction(): Async|self|Properties + { + return match ($this->environment->getSubAction()) { + self::SUB_ACTION_SET_COMBINATION_VALUES => $this->processSetCombinationGapsModal(), + self::SUB_ACTION_DELETE_COMBINATION => $this->deleteCombination(), + self::SUB_ACTION_SAVE => $this->processSetCombinationValues(), + default => $this->buildAction() + }; + } + + private function buildTable(): DataTable + { + return $this->environment->getUIFactory()->table()->data( + $this, + $this->environment->getLanguage()->txt('gap_combinations'), + $this->getColumns() + )->withActions($this->getActions()) + ->withRequest($this->environment->getHttpServices()->request()); + } + + private function getColumns(): array + { + $cf = $this->environment->getUIFactory()->table()->column(); + return [ + 'gaps' => $cf->text($this->environment->getLanguage()->txt('gaps')), + 'values' => $cf->text($this->environment->getLanguage()->txt('values')), + 'available_points' => $cf->number($this->environment->getLanguage()->txt('points'))->withDecimals(2) + ]; + } + + private function getActions(): array + { + $af = $this->environment->getUIFactory()->table()->action(); + return [ + $af->single( + $this->environment->getLanguage()->txt('edit'), + $this->environment + ->withSubActionParameter(self::SUB_ACTION_JUMP_TO_SET_COMBINATION_VALUES) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + )->withAsync(true), + $af->single( + $this->environment->getLanguage()->txt('delete'), + $this->environment + ->withSubActionParameter(self::SUB_ACTION_CONFIRM_DELETE_COMBINATION) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + )->withAsync(true) + ]; + } + + private function buildAction(): Async + { + $affected_item = $this->environment->getAnswerFormProperties() + ->getCombinations()->getCombinationById( + $this->environment->getTableRowIds()[0] + ); + + if ($affected_item === null) { + return $this->buildNoItemsSelectedAsync(); + } + + return $this->environment->getPresentationFactory()->getAsync( + match ($this->environment->getSubAction()) { + self::SUB_ACTION_JUMP_TO_SET_COMBINATION_VALUES => + $this->buildSetCombinationValuesModal( + $this->buildInputsBuilder($affected_item) + ), + self::SUB_ACTION_CONFIRM_DELETE_COMBINATION => + $this->confirmDeleteCombination($affected_item) + } + ); + } + + private function buildNoItemsSelectedAsync(): Async + { + return new Async( + $this->environment->getHttpServices(), + $this->environment->getUIFactory()->messageBox() + ->failure('no_combination_selected') + ); + } + + private function buildSetCombinationGapsModal(): RoundTripModal + { + $properties = $this->environment->getAnswerFormProperties(); + $gaps = $properties->getGaps(); + return $this->environment->getUIFactory()->modal()->roundtrip( + $this->environment->getLanguage()->txt('add_gap_combination'), + $properties->getClozeText()->buildPanelForEditing( + $this->environment->getUIFactory(), + $this->environment->getLanguage(), + $gaps, + $properties->getLegacyClozeText() + ), + [ + 'combination' => $gaps->buildGapsMultiSelect( + $this->environment->getLanguage()->txt('select_gaps_for_combination'), + $this->environment->getUIFactory()->input()->field() + )->withRequired(true) + ->withAdditionalTransformation( + $this->environment->getRefinery()->custom()->constraint( + fn(array $v): bool => count($v) > 1, + $this->environment->getLanguage()->txt('combination_needs_more_than_one') + ) + )->withAdditionalTransformation( + $this->environment->getRefinery()->custom()->transformation( + fn(array $v): Combination => $this->combinations_factory + ->buildNewCombination($gaps, $v) + ) + ) + ], + $this->environment + ->withSubActionParameter(self::SUB_ACTION_SET_COMBINATION_VALUES) + ->getUrlBuilder() + ->buildURI() + ->__toString() + )->withSubmitLabel($this->environment->getLanguage()->txt('next')); + } + + private function processSetCombinationGapsModal(): self + { + $clone = clone $this; + + $set_gaps_modal = $clone->buildSetCombinationGapsModal() + ->withRequest($clone->environment->getHttpServices()->request()); + $data = $set_gaps_modal->getData(); + + if ($data === null) { + $clone->modal = $set_gaps_modal->withOnLoad($set_gaps_modal->getShowSignal()); + return $clone; + } + + $set_values_modal = $clone->buildSetCombinationValuesModal( + $this->buildInputsBuilder($data['combination']) + ); + $clone->modal = $set_values_modal->withOnLoad($set_values_modal->getShowSignal()); + return $clone; + } + + private function buildSetCombinationValuesModal( + InputsBuilder $inputs_builder + ): RoundTripModal { + $properties = $this->environment->getAnswerFormProperties(); + $gaps = $properties->getGaps(); + + return $this->environment->getUIFactory()->modal()->roundtrip( + $this->environment->getLanguage()->txt('edit'), + $properties->getClozeText()->buildPanelForEditing( + $this->environment->getUIFactory(), + $this->environment->getLanguage(), + $gaps, + $properties->getLegacyClozeText() + ), + [ + 'values_awarding_points' => $inputs_builder->getInputs() + ], + $this->environment->withSubActionParameter(self::SUB_ACTION_SAVE) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ); + } + + private function processSetCombinationValues(): self|Properties + { + $inputs_builder = $this->buildInputsBuilder(null); + $set_values_modal = $this->buildSetCombinationValuesModal($inputs_builder) + ->withRequest($this->environment->getHttpServices()->request()); + $data = $set_values_modal->getData(); + if ($data === null) { + $this->modal = $set_values_modal->withOnLoad($set_values_modal->getShowSignal()); + $inputs_builder->persistCarry(); + return $this; + } + + return $data['values_awarding_points']; + } + + private function confirmDeleteCombination( + Combination $affected_item + ): InterruptiveModal { + return $this->environment->getUIFactory()->modal()->interruptive( + $this->environment->getLanguage()->txt('confirm'), + $this->environment->getLanguage()->txt('delete_combination'), + $this->environment->withSubActionParameter( + self::SUB_ACTION_DELETE_COMBINATION + )->getUrlBuilder() + ->withParameter( + $this->environment->getTableRowIdToken(), + [$affected_item->getId()->toString()] + )->buildURI()->__toString() + ); + } + + private function deleteCombination(): Properties + { + $combination_identifier = $this->environment->getTableRowIds(); + if ($combination_identifier === []) { + return $this->environment->getAnswerFormProperties(); + } + + /** @var \ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Properties $answer_form_properties */ + $answer_form_properties = $this->environment->getAnswerFormProperties(); + + return $answer_form_properties->withCombinations( + $answer_form_properties->getCombinations()->withoutCombination( + $combination_identifier[0] + ) + ); + } + + private function buildInputsBuilder( + ?Combination $combination, + ): InputsBuilderSession { + $builder = $this->environment->getPresentationFactory()->getSessionBasedInputsBuilder( + $this->environment->getRefinery()->custom()->transformation( + function (?string $v) use ($combination): ?Section { + $properties = $this->environment->getAnswerFormProperties(); + if ($combination === null) { + $combination = $this->combinations_factory + ->buildCombinationFromCarryValue( + $v, + $properties + ); + } + + return $combination?->buildPointsInputs( + $this->environment->getUIFactory()->input()->field(), + $this->environment->getRefinery(), + $this->environment->getLanguage(), + $this->combinations_factory, + $properties + ); + } + ) + ); + + if ($combination === null) { + return $builder; + } + + $builder_with_string = $builder->withCarry($combination->buildCarryString()); + $builder_with_string->persistCarry(); + return $builder_with_string; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Definitions/ScoringIdentical.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Definitions/ScoringIdentical.php new file mode 100644 index 000000000000..5a1903432530 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Definitions/ScoringIdentical.php @@ -0,0 +1,68 @@ +txt($this->value); + } + + public static function buildInput( + Language $lng, + FieldFactory $ff, + Refinery $refinery, + self $default_value + ): Select { + return $ff->select( + $lng->txt('scoring_of_identical_responses'), + self::buildOptionsList($lng) + )->withRequired(true) + ->withAdditionalTransformation( + $refinery->custom()->transformation( + fn(string $v): self => self::tryFrom($v) ?? $default_value + ) + ); + } + + private static function buildOptionsList( + Language $lng + ): array { + return array_reduce( + self::cases(), + function (array $c, self $v) use ($lng): array { + $c[$v->value] = $lng->txt($v->value); + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Factory.php new file mode 100644 index 000000000000..0d22027a12f0 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Factory.php @@ -0,0 +1,185 @@ +getAnswerFormId(), + $type_generic_properties->getQuestionId(), + $type_generic_properties->getDefinition(), + $type_generic_properties->getAvailablePoints(), + $this->cloze_text_factory->buildFromTextString( + $type_generic_properties->getAdditionalText() + ), + $type_generic_properties->getAdditionalTextLegacy(), + ScoringIdentical::ScoreAll, + $this->gaps_factory->getEmptyGapsObject( + $type_generic_properties->getAnswerFormId() + ), + $this->combinations_factory->getCombinations( + $type_generic_properties, + false + ) + ); + } + + [ + 'scoring_identical_responses' => $scoring_identical_responses, + 'combinations_enabled' => $combinations_enabled + ] = $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $query->getTableNameBuilder( + $type_generic_properties + ->getDefinition() + ->getTableDefinitions() + ->getTableSubNameSpace() + ), + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ), + $query->getRefinery()->custom()->transformation( + function (array $vs) use ($type_generic_properties): array { + $values = $this->retrieveFirstMatchingRowFromDBRecords( + $type_generic_properties->getAnswerFormId()->toString(), + $vs + ); + return [ + 'scoring_identical_responses' => ScoringIdentical::tryFrom($values['scoring_identical_responses']), + 'combinations_enabled' => $values['combinations_enabled'] === 1 + ]; + } + ) + ); + + $gaps = $this->gaps_factory->fromDatabase( + $this->persistence_factory, + $type_generic_properties + ->getDefinition() + ->getTableDefinitions() + ->getTableSubNameSpace(), + $type_generic_properties->getAnswerFormId(), + $query + ); + + return new Properties( + $type_generic_properties->getAnswerFormId(), + $type_generic_properties->getQuestionId(), + $type_generic_properties->getDefinition(), + $type_generic_properties->getAvailablePoints(), + $this->cloze_text_factory->buildFromTextString( + $type_generic_properties->getAdditionalText() + ), + $type_generic_properties->getAdditionalTextLegacy(), + $scoring_identical_responses, + $gaps, + $this->combinations_factory->getCombinations( + $type_generic_properties, + $combinations_enabled, + $gaps, + $query + ) + ); + } + + public function fromBasicEditingForm( + Properties $properties, + ClozeText $cloze_text, + ScoringIdentical $scoring_of_identical_responses, + bool $combinations_enabled + ): Properties { + $updated_properties = $properties + ->withScoringOfIdenticalResponses($scoring_of_identical_responses) + ->withCombinations( + $properties->getCombinations()->withCombinationsEnabled( + $combinations_enabled + ) + ); + + if ($updated_properties->getLegacyClozeText() !== '' + && $cloze_text->getRawRepresentation() === '') { + return $updated_properties; + } + + $updated_gaps = $cloze_text->updateGapsFromMarkdown( + $properties->getAnswerFormId(), + $properties->getGaps() + ); + + return $updated_properties + ->withClozeText( + $cloze_text->withIdsOfNewGapsInClozeText( + $updated_gaps->getIncompleteGaps() + ) + )->withGaps($updated_gaps); + } + + public function fromCarry( + Properties $properties, + ?string $carry + ): Properties { + if ($carry === null + || !is_array( + ($carry_array = json_decode($carry, true)) + )) { + return $properties; + } + + return $properties->withValuesFromCarry( + $this->cloze_text_factory, + $carry_array + ); + } + + private function retrieveFirstMatchingRowFromDBRecords( + string $answer_form_id, + array $vs + ): ?array { + foreach ($vs as $row) { + if ($row['answer_form_id'] === $answer_form_id) { + return $row; + } + } + return null; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOption.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOption.php new file mode 100644 index 000000000000..85de10e513cd --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOption.php @@ -0,0 +1,204 @@ +answer_option_id; + } + + public function getPosition(): ?int + { + return $this->position; + } + + public function withPosition( + int $position + ): self { + $clone = clone $this; + $clone->position = $position; + return $clone; + } + + public function getTextValue(): string + { + return $this->text_value; + } + + public function withTextValue( + string $text_value + ): self { + $clone = clone $this; + $clone->text_value = $text_value; + return $clone; + } + + public function getLowerLimit(): ?float + { + return $this->lower_limit; + } + + public function withLowerLimit( + float $lower_limit + ): self { + $clone = clone $this; + $clone->lower_limit = $lower_limit; + return $clone; + } + + public function getUpperLimit(): ?float + { + return $this->upper_limit; + } + + public function withUpperLimit( + ?float $upper_limit + ): self { + $clone = clone $this; + $clone->upper_limit = $upper_limit; + return $clone; + } + + public function getAvailablePoints(): ?float + { + return $this->available_points; + } + + public function withAvailablePoints( + ?float $available_points + ): self { + $clone = clone $this; + $clone->available_points = $available_points; + return $clone; + } + + public function toCarry(): array + { + $values = [ + self::FORM_KEY_ID => $this->getAnswerOptionId()->toString(), + self::FORM_KEY_POSITION => (string) $this->getPosition(), + self::FORM_KEY_TEXT_VALUE => $this->getTextValue() + ]; + + if ($this->getLowerLimit() !== null) { + $values[self::FORM_KEY_LOWER_LIMIT] = (string) $this->getLowerLimit(); + } + + if ($this->getUpperLimit() !== null) { + $values[self::FORM_KEY_UPPER_LIMIT] = (string) $this->getUpperLimit(); + } + + if ($this->getAvailablePoints() !== null) { + $values[self::FORM_KEY_AVAILABLE_POINTS] = (string) $this->getAvailablePoints(); + } + + return $values; + } + + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_input_id = $environment['answer_input_id']; + $clone->answer_option_id = $uuid_factory->uuid4(); + return $clone; + } + + public function buildReplace( + PersistenceFactory $persistence_factory, + ?Replace $replace, + array $columns + ): Replace { + if ($replace === null) { + return $persistence_factory->replace( + $columns, + $this->buildValuesForGapReplace($persistence_factory) + ); + } + + return $replace->withAdditionalValues( + $this->buildValuesForGapReplace($persistence_factory) + ); + } + + private function buildValuesForGapReplace( + PersistenceFactory $persistence_factory + ): array { + return [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_option_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_input_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->position + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->text_value + ), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->available_points + ), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->lower_limit + ), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->upper_limit + ) + ]; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOptions.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOptions.php new file mode 100644 index 000000000000..ea7be6a34b1e --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/AnswerOptions.php @@ -0,0 +1,390 @@ +answer_options_awarding_points = $this->buildAnswerOptionsAwardingPointsFromAnswerOptions($answer_options); + } + + public function getMaxAvailablePoints(): float + { + return array_reduce( + $this->answer_options_awarding_points, + function (?float $c, AnswerOption $v): ?float { + if ($v->getAvailablePoints() === null) { + return $c; + } + + if ($c === null) { + return $v->getAvailablePoints(); + } + + return max($c, $v->getAvailablePoints()); + } + ); + } + + public function isIncomplete(): bool + { + return $this->is_incomplete + || $this->answer_options === [] + || $this->answer_options_awarding_points === []; + } + + public function withIsIncomplete( + bool $is_incomplete + ): self { + $clone = clone $this; + $clone->is_incomplete = $is_incomplete; + return $clone; + } + + public function getAnswerOptionById( + Uuid $answer_option_id + ): ?AnswerOption { + $answer_option_id_string = $answer_option_id->toString(); + return array_find( + $this->answer_options, + function (AnswerOption $v) use ($answer_option_id_string): bool { + $id_string = $v->getAnswerOptionId()->toString(); + return $id_string === $answer_option_id_string; + } + ); + } + + public function getAnswerOptionByTextValue( + string $text_value + ): ?AnswerOption { + return array_find( + $this->answer_options, + fn(AnswerOption $v): bool => $v->getTextValue() === $text_value + ); + } + + public function getAnswerOptionForPositionOrNew( + int $position + ): AnswerOption { + return $this->answer_options[$position] + ?? $this->factory->getDefaultAnswerOptionForPosition( + $this->answer_input_id, + $position + ); + } + + public function getBestAnswerOption(): ?AnswerOption + { + return array_reduce( + $this->answer_options_awarding_points, + fn(?AnswerOption $c, AnswerOption $v): ?AnswerOption + => $v->getAvailablePoints() > $c?->getAvailablePoints() + ? $v + : $c + ); + } + + public function getTagsArrayFromAnswerOptions(): array + { + return array_reduce( + $this->answer_options, + function (array $c, AnswerOption $v): array { + if ($v->getTextValue() === '') { + return $c; + } + $c[] = $v->getTextValue(); + return $c; + }, + [] + ); + } + + public function getAnswerOptionsAwardingPoints(): array + { + return $this->answer_options_awarding_points; + } + + public function withAnswerOptionsAwardingPoints( + array $options + ): self { + $clone = clone $this; + $clone->answer_options_awarding_points = array_reduce( + $options, + function (array $c, string $v): array { + $answer_option = $this->retrieveAnswerOptionByTextValue($v); + if ($answer_option !== null) { + $c[] = $answer_option; + } + return $c; + }, + [] + ); + return $clone; + } + + public function withAnswerOptions( + array $answer_options + ): self { + $clone = clone $this; + $clone->answer_options = $answer_options; + return $clone; + } + + public function withAnswerOptionsFromTags( + array $tags + ): self { + $clone = clone $this; + $position = 0; + $clone->answer_options = array_map( + function (string $v) use (&$position): AnswerOption { + return $this->buildAnswerOptionFromTag( + $position++, + $v + ); + }, + $tags + ); + return $clone; + } + + public function withAnswerOptionsWithAddedPointsFromForm( + Refinery $refinery, + array $values_from_form + ): self { + $clone = clone $this; + $clone->answer_options = array_map( + function (AnswerOption $v) use ($refinery, $values_from_form): AnswerOption { + $answer_option_id = $v->getAnswerOptionId()->toString(); + if (array_key_exists($answer_option_id, $values_from_form)) { + return $v->withAvailablePoints( + $refinery->byTrying([ + $refinery->kindlyTo()->float(), + $refinery->always(null) + ])->transform($values_from_form[$answer_option_id]) + ); + } + + return $v; + }, + $clone->answer_options + ); + $clone->answer_options_awarding_points = $clone + ->buildAnswerOptionsAwardingPointsFromAnswerOptions($clone->answer_options); + return $clone; + } + + public function buildArrayForSelectInput( + Transformation $shuffle_transformation + ): array { + return array_reduce( + $shuffle_transformation->transform($this->answer_options), + function (array $c, AnswerOption $v): array { + $c[$v->getAnswerOptionId()->toString()] = $v->getTextValue(); + return $c; + }, + [] + ); + } + + public function toCarry(): array + { + return [ + self::KEY_IS_INCOMPLETE => $this->is_incomplete ? 1 : 0, + self::KEY_ANSWER_OPIONS => array_map( + fn(AnswerOption $v): array => $v->toCarry(), + $this->answer_options + ), + self::KEY_ANSWER_OPTIONS_AWARDING_POINTS => array_map( + fn(AnswerOption $v): string => $v->getAnswerOptionId()->toString(), + $this->answer_options_awarding_points + ) + ]; + } + + public function withValuesFromCarry( + array $carry + ): self { + $clone = clone $this; + $clone->is_incomplete = $carry[self::KEY_IS_INCOMPLETE] === 1; + $clone->answer_options = array_map( + fn(array $vs): AnswerOption => $this->factory->buildAnswerOption( + $vs[AnswerOption::FORM_KEY_ID], + $this->answer_input_id, + (int) $vs[AnswerOption::FORM_KEY_POSITION], + $vs[AnswerOption::FORM_KEY_TEXT_VALUE], + $vs[AnswerOption::FORM_KEY_LOWER_LIMIT] ?? null, + $vs[AnswerOption::FORM_KEY_UPPER_LIMIT] ?? null, + $vs[AnswerOption::FORM_KEY_AVAILABLE_POINTS] ?? null + ), + $carry[self::KEY_ANSWER_OPIONS] ?? [] + ); + + $clone->answer_options_awarding_points = array_filter( + $clone->answer_options, + fn(AnswerOption $v): bool => in_array( + $v->getAnswerOptionId()->toString(), + $carry[self::KEY_ANSWER_OPTIONS_AWARDING_POINTS] ?? [] + ) + ); + return $clone; + } + + public function getEditPointsInputs( + FieldFactory $ff, + \Closure $build_label, + ?array $answer_options_awarding_points = null + ): array { + return array_reduce( + $answer_options_awarding_points ?? $this->answer_options, + function (array $c, AnswerOption $v) use ($ff, $build_label): array { + $c[$v->getAnswerOptionId()->toString()] = $ff->numeric($build_label($v)) + ->withStepSize(0.01) + ->withValue($v->getAvailablePoints()); + return $c; + }, + [] + ); + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_input_id = $environment['answer_input_id']; + $clone->answer_options = array_map( + fn(AnswerOption $v): AnswerOption => $v->clone( + $uuid_factory, + $environment + ), + $this->answer_options + ); + return $clone; + } + + public function buildReplace( + ?Replace $replace, + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Replace { + return array_reduce( + $this->answer_options, + fn(?Replace $c, AnswerOption $v): Replace => $v->buildReplace( + $persistence_factory, + $c, + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerOptions + ) + ), + $replace + ); + } + + public function buildDelete( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_type = AnswerFormSpecificTableTypes::AnswerOptions; + + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $persistence_factory->where( + $table_definitions->getForeignKeyColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_input_id->toString() + ) + ) + ] + ); + } + + private function buildAnswerOptionsAwardingPointsFromAnswerOptions( + array $answer_options + ): array { + return array_filter( + $answer_options, + fn(AnswerOption $v): bool => $v->getAvailablePoints() > 0.0 + ); + } + + private function buildAnswerOptionFromTag( + int $position, + string $text_value + ): AnswerOption { + $answer_option = $this->retrieveAnswerOptionByTextValue($text_value) + ?? $this->factory->getDefaultAnswerOptionForPosition( + $this->answer_input_id, + $position + ); + + return $answer_option + ->withPosition($position) + ->withTextValue($text_value); + } + + private function retrieveAnswerOptionByTextValue( + string $value + ): ?AnswerOption { + $filtered_array = array_filter( + $this->answer_options, + fn(AnswerOption $v): bool => $v->getTextValue() === $value + ); + return array_shift($filtered_array) ?? null; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Factory.php new file mode 100644 index 000000000000..c87b3a82beac --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Factory.php @@ -0,0 +1,147 @@ +uuid_factory->uuid4(), + $answer_input_id, + $position + ); + } + + public function buildAnswerOption( + string $answer_option_id, + Uuid $answer_input_id, + int $position, + string $text_value, + ?string $lower_limit, + ?string $upper_limit, + ?string $points + ): AnswerOption { + return new AnswerOption( + $this->uuid_factory->fromString($answer_option_id), + $answer_input_id, + $position, + $text_value, + $this->convertToFloatOrNull($lower_limit), + $this->convertToFloatOrNull($upper_limit), + $this->convertToFloatOrNull($points) + ); + } + + public function fromDatabase( + PersistenceFactory $persistence_factory, + TableSubNameSpace $table_name_specifier, + Query $query + ): array { + return $query->retrieveCurrentRecord( + $persistence_factory->table( + $query->getTableNameBuilder( + $table_name_specifier + ), + AnswerFormSpecificTableTypes::AnswerOptions + ), + $query->getRefinery()->custom()->transformation( + function (array $vs): array { + if ($vs === []) { + return []; + } + + $previous_answer_input_id = null; + $return_array = []; + $answer_options = []; + foreach ($vs as $v) { + if (array_key_exists($v['id'], $answer_options)) { + continue; + } + + if ($previous_answer_input_id !== null + && $v['answer_input_id'] !== $previous_answer_input_id) { + $return_array[$previous_answer_input_id] = new AnswerOptions( + $this, + $this->uuid_factory->fromString($previous_answer_input_id), + $answer_options + ); + $answer_options = []; + } + $previous_answer_input_id = $v['answer_input_id']; + $answer_options[$v['id']] = new AnswerOption( + $this->uuid_factory->fromString($v['id']), + $this->uuid_factory->fromString($v['answer_input_id']), + $v['position'], + $v['text_value'], + $v['lower_limit'], + $v['upper_limit'], + $v['points'] + ); + } + + $return_array[$v['answer_input_id']] = new AnswerOptions( + $this, + $this->uuid_factory->fromString($v['answer_input_id']), + $answer_options + ); + + return $return_array; + } + ) + ); + } + + private function convertToFloatOrNull( + ?string $value + ): ?float { + return $this->refinery->byTrying([ + $this->refinery->kindlyTo()->float(), + $this->refinery->always(null) + ])->transform($value); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Upload.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Upload.php new file mode 100755 index 000000000000..4f36758c8459 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/AnswerOptions/Upload.php @@ -0,0 +1,211 @@ +environment + ->withSubActionParameter(self::SUB_ACTION_UPLOAD) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getFileRemovalURL(): string + { + return $this->environment + ->withSubActionParameter(self::SUB_ACTION_REMOVE) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getExistingFileInfoURL(): string + { + return $this->environment + ->withSubActionParameter(self::SUB_ACTION_INFO) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getInfoForExistingFiles( + array $file_ids + ): array { + return array_map( + fn($file_id): FileInfoResult => $this->getInfoResult($file_id), + $file_ids + ); + } + + #[\Override] + public function getInfoResult( + string $identifier + ): ?FileInfoResult { + return new BasicFileInfoResult( + $this->getFileIdentifierParameterName(), + $identifier, + 'unknown', + 0, + 'unknown' + ); + } + + #[\Override] + public function supportsChunkedUploads(): bool + { + return false; + } + + #[\Override] + public function can( + string $sub_action + ): bool { + $has_file_identifier = $this->hasFileIdentifier(); + + return $sub_action === self::SUB_ACTION_UPLOAD + || $sub_action === self::SUB_ACTION_REMOVE && $has_file_identifier + || $sub_action === self::SUB_ACTION_INFO && $has_file_identifier; + } + + #[\Override] + public function do( + string $action + ): Async { + $response = match($action) { + self::SUB_ACTION_UPLOAD => $this->upload(), + self::SUB_ACTION_REMOVE => $this->remove(), + self::SUB_ACTION_INFO => $this->info(), + default => '' + }; + + return $this->environment->getPresentationFactory()->getAsync($response); + } + + private function upload(): string + { + $this->upload->process(); + + $result_array = $this->upload->getResults(); + $result = end($result_array); + + if (!($result instanceof UploadResult) || !$result->isOK()) { + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_FAILED, + '', + $result->getStatus()->getMessage() + ); + } + + $content = base64_encode(file_get_contents($result->getPath())); + unlink($result->getPath()); + + return json_encode( + new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_OK, + $content, + 'file upload OK' + ) + ); + } + + private function remove(): string + { + return json_encode( + new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_OK, + $this->retrieveFileIdentifier(), + 'We just don\'t do anything here.' + ) + ); + } + + private function info(): string + { + return json_encode( + $this->getInfoResult( + $this->retrieveFileIdentifier() + ) + ); + } + + private function hasFileIdentifier(): bool + { + return $this->environment + ->getHttpServices() + ->wrapper() + ->query() + ->has($this->getFileIdentifierParameterName()); + } + + private function retrieveFileIdentifier(): string + { + if (!$this->hasFileIdentifier()) { + return ''; + } + + return $this->environment + ->getHttpServices() + ->wrapper() + ->query() + ->retrieve( + $this->getFileIdentifierParameterName(), + $this->environment->getRefinery()->kindlyTo()->string() + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Edit.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Edit.php new file mode 100644 index 000000000000..8899f8e442d9 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Edit.php @@ -0,0 +1,389 @@ +file_upload, + $environment + ); + if ($upload_handler->can($sub_action)) { + return $upload_handler->do($sub_action); + } + + return match ($sub_action) { + self::SUB_ACTION_SET_GAP_TYPES, + self::SUB_ACTION_JUMP_TO_SET_GAP_TYPES + => $this->buildGapTypesFormWithCarry( + $environment, + $environment->getAnswerFormProperties(), + $sub_action + ), + self::SUB_ACTION_BACK_TO_EDIT_BASIC_PROPERTIES + => $this->backToEditBasicProperties( + $environment, + $sub_action + ), + self::SUB_ACTION_BACK_TO_SET_GAP_TYPES + => $this->backToGapTypesForm( + $environment, + $sub_action + ), + self::SUB_ACTION_SET_ANSWER_OPTIONS + => $this->forwardToAnswerOptionsForm( + $environment, + $sub_action + ), + self::SUB_ACTION_BACK_TO_SET_ANSWER_OPTIONS, + self::SUB_ACTION_JUMP_TO_SET_ANSWER_OPTIONS + => $this->buildAnswerOptionsFormWithCarry( + $environment, + $environment->getAnswerFormProperties(), + $sub_action + ), + self::SUB_ACTION_PROCESS_SET_ANSWER_OPTIONS + => $this->processAnswerOptionsForm( + $environment, + $sub_action + ) + }; + } + + private function backToEditBasicProperties( + Environment $environment, + string $sub_action + ): EditForm|string { + $processed_form = $this->processGapTypesForm( + $environment, + $sub_action + ); + if ($processed_form instanceof EditForm) { + return $processed_form; + } + + return $processed_form->toCarry(); + } + + private function backToGapTypesForm( + Environment $environment, + string $sub_action + ): EditForm { + $processed_form = $this->processAnswerOptionsForm( + $environment, + $sub_action + ); + if ($processed_form instanceof EditForm) { + return $processed_form; + } + + return $this->buildGapTypesFormWithCarry( + $environment, + $processed_form, + $sub_action + ); + } + + private function buildGapTypesFormWithCarry( + Environment $environment, + Properties $properties, + string $sub_action + ): EditForm { + $inputs_builder = $this->buildInputsBuilderForTypesForm( + $environment + )->withCarry( + $properties->toCarry() + ); + + $inputs_builder->persistCarry(); + + return $this->buildGapTypesForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder, + $sub_action + ); + } + + private function buildGapTypesForm( + Environment $environment, + InputsBuilderSession $inputs_builder, + string $sub_action + ): EditForm { + /** @var \ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Properties $properties */ + $properties = $environment->getAnswerFormProperties(); + + $inputs_builder->persistCarry(); + + return $environment->getPresentationFactory()->getEditForm( + $inputs_builder, + $this->buildPostTarget( + $environment, + self::SUB_ACTION_SET_ANSWER_OPTIONS + ), + $sub_action === self::SUB_ACTION_JUMP_TO_SET_GAP_TYPES + || $environment->getFormStartSubAction() === self::SUB_ACTION_JUMP_TO_SET_GAP_TYPES + ? null + : $this->buildPostTarget( + $environment, + self::SUB_ACTION_BACK_TO_EDIT_BASIC_PROPERTIES + ) + )->withContentBeforeForm( + $properties->getClozeText()->buildPanelForEditing( + $environment->getUIFactory(), + $environment->getLanguage(), + $properties->getGaps(), + $properties->getLegacyClozeText() + ) + ); + } + + private function processGapTypesForm( + Environment $environment, + string $sub_action + ): EditForm|Properties { + $inputs_builder_for_types = $this->buildInputsBuilderForTypesForm( + $environment + ); + + $properties = $inputs_builder_for_types->retrieveCarry( + $this->buildRetrievePropertiesTransformation($environment) + ); + + $form = $this->buildGapTypesForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder_for_types, + $sub_action + )->withRequest($environment->getHttpServices()->request()); + + $data = $form->getData(); + if ($data === null) { + $inputs_builder_for_types->persistCarry(); + return $form; + } + + return $data; + } + + private function buildInputsBuilderForTypesForm( + Environment $environment + ): InputsBuilderSession { + return $environment->getPresentationFactory()->getSessionBasedInputsBuilder( + $environment->getRefinery()->custom()->transformation( + function (?string $carry) use ($environment): Section { + $properties_from_carry = $this->properties_factory + ->fromCarry( + $environment->getAnswerFormProperties(), + $carry + ); + return $properties_from_carry->getGaps()->buildGapsTypeInputs( + $environment->getLanguage(), + $environment->getUIFactory()->input()->field(), + $this->gap_factory->getAvailableGapTypesOptionsArray( + $environment->getLanguage() + ), + $properties_from_carry, + $environment->isInCreationContext(), + $environment->getTableRowIds() + ); + } + ) + ); + } + + private function forwardToAnswerOptionsForm( + Environment $environment, + string $sub_action + ): EditForm { + $processed_form = $this->processGapTypesForm( + $environment, + $sub_action + ); + if ($processed_form instanceof EditForm) { + return $processed_form; + } + + return $this->buildAnswerOptionsFormWithCarry( + $environment, + $processed_form, + $sub_action + ); + } + + private function buildAnswerOptionsFormWithCarry( + Environment $environment, + Properties $properties, + string $sub_action + ): EditForm { + $inputs_builder = $this->buildInputsBuilderForAnswerOptionsForm( + $environment, + $properties, + )->withCarry( + $properties->toCarry() + ); + + $inputs_builder->persistCarry(); + + return $this->buildAnswerOptionsForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder, + $sub_action + ); + } + + private function buildAnswerOptionsForm( + Environment $environment, + InputsBuilderSession $inputs_builder, + string $sub_action + ): EditForm { + $properties = $environment->getAnswerFormProperties(); + return $environment->getPresentationFactory()->getEditForm( + $inputs_builder, + $this->buildPostTarget( + $environment, + self::SUB_ACTION_PROCESS_SET_ANSWER_OPTIONS + ), + $sub_action === self::SUB_ACTION_JUMP_TO_SET_ANSWER_OPTIONS + || $environment->getFormStartSubAction() === self::SUB_ACTION_JUMP_TO_SET_ANSWER_OPTIONS + ? null + : $this->buildPostTarget( + $environment, + self::SUB_ACTION_BACK_TO_SET_GAP_TYPES + ) + )->withIsFinalStep(true) + ->withContentBeforeForm( + $properties->getClozeText()->buildPanelForEditing( + $environment->getUIFactory(), + $environment->getLanguage(), + $properties->getGaps(), + $properties->getLegacyClozeText() + ) + ); + } + + private function processAnswerOptionsForm( + Environment $environment, + string $sub_action + ): EditForm|Properties { + $inputs_builder_for_options = $this->buildInputsBuilderForAnswerOptionsForm( + $environment, + $environment->getAnswerFormProperties() + ); + + $properties = $inputs_builder_for_options->retrieveCarry( + $this->buildRetrievePropertiesTransformation($environment) + ); + + $form = $this->buildAnswerOptionsForm( + $environment->withAnswerFormProperties($properties), + $inputs_builder_for_options, + $sub_action + )->withRequest($environment->getHttpServices()->request()); + + $data = $form->getData(); + if ($data === null) { + $inputs_builder_for_options->persistCarry(); + return $form; + } + + return $data; + } + + private function buildInputsBuilderForAnswerOptionsForm( + Environment $environment, + Properties $properties + ): InputsBuilderSession { + return $environment->getPresentationFactory()->getSessionBasedInputsBuilder( + $environment->getRefinery()->custom()->transformation( + function (?string $carry) use ( + $environment, + $properties + ): Section { + $properties_from_carry = $this->properties_factory + ->fromCarry( + $properties, + $carry + ); + return $properties_from_carry->getGaps() + ->buildAnswerOptionsInputs( + $this->file_upload, + $environment, + $properties_from_carry + ); + } + ) + ); + } + + private function buildPostTarget( + Environment $environment, + string $next_step + ): URLBuilder { + return $environment + ->withSubActionParameter($next_step) + ->getUrlBuilder(); + } + + private function buildRetrievePropertiesTransformation( + Environment $environment + ): CustomTransformation { + return $environment->getRefinery()->custom()->transformation( + fn(?string $carry): Properties => $this->properties_factory + ->fromCarry( + $environment->getAnswerFormProperties(), + $carry + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Factory.php new file mode 100644 index 000000000000..d0147e99db3d --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Factory.php @@ -0,0 +1,162 @@ +available_gap_types[$type->getIdentifier()] = $type; + } + } + + public function getAvailableGapTypes(): array + { + return $this->available_gap_types; + } + + public function getAvailableGapTypesOptionsArray( + Language $lng + ): array { + return array_map( + fn(Type $v) => $lng->txt("{$v->getIdentifier()}_gap"), + $this->available_gap_types + ); + } + + public function getNewGap( + Uuid $answer_form_id, + int $position, + string $id = '' + ): Gap { + $answer_input_id = $id !== '' + ? $this->uuid_factory->fromString($id) + : $this->uuid_factory->uuid4(); + + return new Gap( + $answer_input_id, + $answer_form_id, + $position, + $this->answer_options_factory->getDefaultAnswerOptions($answer_input_id) + ); + } + + public function getEmptyGapsObject( + Uuid $answer_form_id, + ): Gaps { + return new Gaps( + $this->refinery, + $this, + $answer_form_id, + [] + ); + } + + public function getGapTypeByIdentifier( + string $identifier + ): Type { + if (!array_key_exists($identifier, $this->available_gap_types)) { + throw new \InvalidArgumentException('Gap type does not exist.'); + } + return $this->available_gap_types[$identifier]; + } + + public function fromDatabase( + PersistenceFactory $persistence_factory, + TableSubNameSpace $table_name_specifier, + Uuid $answer_form_id, + Query $query + ): Gaps { + $answer_options = $this->answer_options_factory->fromDatabase( + $persistence_factory, + $table_name_specifier, + $query + ); + + return $query->retrieveCurrentRecord( + $persistence_factory->table( + $query->getTableNameBuilder( + $table_name_specifier + ), + AnswerFormSpecificTableTypes::AnswerInputs + ), + $query->getRefinery()->custom()->transformation( + function (array $vs) use ($answer_form_id, $answer_options): Gaps { + $previous_answer_input_id = null; + $gaps = []; + foreach ($vs as $v) { + if ($v['answer_form_id'] !== $answer_form_id->toString() + || $previous_answer_input_id === $v['id']) { + continue; + } + $previous_answer_input_id = $v['id']; + $gaps[] = $this->buildGapFromDBValues($v, $answer_options); + } + return new Gaps( + $this->refinery, + $this, + $answer_form_id, + $gaps + ); + } + ) + ); + } + + private function buildGapFromDBValues( + array $values, + array $answer_options + ): Gap { + $answer_input_uuid = $this->uuid_factory->fromString($values['id']); + return new Gap( + $answer_input_uuid, + $this->uuid_factory->fromString($values['answer_form_id']), + $values['position'], + $answer_options[$values['id']], + $this->getGapTypeByIdentifier($values['gap_type']), + $values['max_chars'], + $values['step_size'], + $values['text_matching_method'] === null + ? null + : TextMatchingOptions::tryFrom($values['text_matching_method']), + $values['min_autocomplete'], + $values['shuffle_answer_options'] === 1 + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gap.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gap.php new file mode 100644 index 000000000000..03d118e59daf --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gap.php @@ -0,0 +1,451 @@ + $answer_options + */ + public function __construct( + private Uuid $answer_input_id, + private Uuid $answer_form_id, + private int $position, + private AnswerOptions $answer_options, + private ?Type $type = null, + private ?int $max_chars = null, + private ?float $step_size = null, + private ?TextMatchingOptions $text_matching_method = null, + private ?int $min_autocomplete = null, + private ?bool $shuffle_answer_options = null + ) { + } + + public function getAnswerInputId(): Uuid + { + return $this->answer_input_id; + } + + public function getPosition(): int + { + return $this->position; + } + + public function withPosition( + int $position + ): self { + $clone = clone $this; + $clone->position = $position; + return $clone; + } + + public function isUndefined(): bool + { + return $this->type === null; + } + + public function getType(): ?Type + { + return $this->type; + } + + public function withType( + Type $type + ): self { + $clone = clone $this; + $clone->type = $type; + return $clone; + } + + public function getMaxChars(): ?int + { + return $this->max_chars; + } + + public function withMaxChars( + ?int $max_chars + ): self { + $clone = clone $this; + $clone->max_chars = $max_chars; + return $clone; + } + + public function getStepSize(): ?float + { + return $this->step_size; + } + + public function withStepSize( + float $step_size + ): self { + $clone = clone $this; + $clone->step_size = $step_size; + return $clone; + } + + public function getTextMatchingMethod(): ?TextMatchingOptions + { + return $this->text_matching_method; + } + + public function withTextMatchingMethod( + TextMatchingOptions $matching_method + ): self { + $clone = clone $this; + $clone->text_matching_method = $matching_method; + return $clone; + } + + public function getMinAutocomplete(): ?int + { + return $this->min_autocomplete; + } + + public function withMinAutocomplete( + int $min_autocomplete + ): self { + $clone = clone $this; + $clone->min_autocomplete = $min_autocomplete; + return $clone; + } + + public function getShuffleAnswerOptions(): ?bool + { + return $this->shuffle_answer_options; + } + + public function withShuffleAnswerOptions( + bool $shuffle_answer_options + ): self { + $clone = clone $this; + $clone->shuffle_answer_options = $shuffle_answer_options; + return $clone; + } + + public function getAnswerOptions(): AnswerOptions + { + return $this->answer_options; + } + + public function withAnswerOptions( + AnswerOptions $answer_options + ): self { + $clone = clone $this; + $clone->answer_options = $answer_options; + return $clone; + } + + public function toCarry(): array + { + $inputs = [ + self::KEY_TYPE => $this->type?->getIdentifier() ?? '', + self::KEY_POSITION => $this->position, + self::KEY_ANSWER_OPTIONS => $this->answer_options->toCarry() + ]; + + if ($this->max_chars !== null) { + $inputs[self::KEY_MAX_CHARS] = (string) $this->getMaxChars(); + } + + if ($this->step_size !== null) { + $inputs[self::KEY_STEP_SIZE] = (string) $this->getStepSize(); + } + + if ($this->text_matching_method !== null) { + $inputs[self::KEY_TEXT_MATCHING_METHOD] = $this->getTextMatchingMethod()->value; + } + + if ($this->min_autocomplete !== null) { + $inputs[self::KEY_MIN_AUTOCOMPLETE] = (string) $this->getMinAutocomplete(); + } + + if ($this->shuffle_answer_options !== null) { + $inputs[self::KEY_SHUFFLE_ANSWER_OPTIONS] = $this->getShuffleAnswerOptions() ? '1' : '0'; + } + + return $inputs; + } + + public function withValuesFromCarry( + Refinery $refinery, + Factory $gaps_factory, + array $carry + ): self { + if ($carry === null) { + return $this; + } + + $clone = clone $this; + $clone->type = $carry[self::KEY_TYPE] === '' + ? $this->type + : $gaps_factory->getGapTypeByIdentifier($carry[self::KEY_TYPE]); + $clone->position = $carry[self::KEY_POSITION]; + + $clone->max_chars = $refinery->byTrying([ + $refinery->kindlyTo()->int(), + $refinery->always($this->getMaxChars()) + ])->transform($carry[self::KEY_MAX_CHARS] ?? null); + + $clone->step_size = $refinery->byTrying([ + $refinery->kindlyTo()->float(), + $refinery->always($this->getStepSize()) + ])->transform($carry[self::KEY_STEP_SIZE] ?? null); + + $clone->text_matching_method = is_string($carry[self::KEY_TEXT_MATCHING_METHOD] ?? null) + ? TextMatchingOptions::tryFrom($carry[self::KEY_TEXT_MATCHING_METHOD]) + : $this->getTextMatchingMethod(); + + $clone->min_autocomplete = $refinery->byTrying([ + $refinery->kindlyTo()->int(), + $refinery->always($this->getMinAutocomplete()) + ])->transform($carry[self::KEY_MIN_AUTOCOMPLETE] ?? null); + + $clone->shuffle_answer_options = $refinery->byTrying([ + $refinery->kindlyTo()->bool(), + $refinery->always($this->getShuffleAnswerOptions()) + ])->transform($carry[self::KEY_SHUFFLE_ANSWER_OPTIONS] ?? null); + + $clone->answer_options = $this->answer_options + ->withValuesFromCarry($carry[self::KEY_ANSWER_OPTIONS]); + + return $clone; + } + + public function buildReplace( + ?Replace $replace, + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Replace { + if ($this->type === null) { + throw new \UnexpectedValueException( + 'A Gap without Type cannot be stored.' + ); + } + + $table_type = AnswerFormSpecificTableTypes::AnswerInputs; + + if ($replace === null) { + return $persistence_factory->replace( + $table_definitions->getColumns( + $table_names_builder, + $table_type + ), + $this->buildValuesForGapReplace($persistence_factory) + ); + } + + return $replace->withAdditionalValues( + $this->buildValuesForGapReplace($persistence_factory) + ); + } + + public function getGapPlaceholder(): string + { + return "{{{$this->buildGapPlaceholderNameWithId()}}}"; + } + + public function buildShortenedGapName(): string + { + return self::GAP_PLACEHOLDER_NAME . '_' . $this->getShortenedAnswerInputId(); + } + + public function buildShortenedGapRepresentation(): string + { + return "[{$this->buildShortenedGapName()}]"; + } + + public function buildGapPlaceholderNameWithId(): string + { + return self::GAP_PLACEHOLDER_NAME . '_' . $this->getAnswerInputId()->toString(); + } + + public function buildParticipantViewLegacyInput( + Language $lng, + Refinery $refinery, + ?AdditionalAttemptData $attempt_data, + ?Response $response_data + ): string { + return $this->type->getParticipantViewLegacyInput( + $this, + $attempt_data, + $response_data + ); + } + + public function getEditAnswerOptionsSection( + FileUpload $file_upload, + Environment $environment + ): Section { + $section = $environment->getUIFactory()->input()->field()->section( + $this->type->getEditAnswerOptionsInputs( + $file_upload, + $environment, + $this + ), + "{$this->buildShortenedGapName()} ({$environment->getLanguage()->txt("{$this->type->getIdentifier()}_gap")})" + ); + + $edit_section_constraint = $this->type->getEditAnswerOptionsSectionConstraint(); + if ($edit_section_constraint !== null) { + $section = $section->withAdditionalTransformation($edit_section_constraint); + } + + + return $section->withAdditionalTransformation( + $this->type->getBuildGapTransformation( + $this + ) + ); + } + + public function getEditPointsSection( + Language $lng, + UIFactory $ui_factory, + bool $input_required + ): Section { + $section = $ui_factory->input()->field()->section( + $this->type->getEditPointsInputs( + $ui_factory, + $this->getAnswerOptions(), + $input_required + ), + "{$this->buildShortenedGapName()} ({$lng->txt("{$this->type->getIdentifier()}_gap")})" + ); + + $edit_section_constraint = $this->type->getEditPointsSectionConstraint( + $input_required + ); + if ($edit_section_constraint !== null) { + $section = $section->withAdditionalTransformation($edit_section_constraint); + } + + + return $section->withAdditionalTransformation( + $this->type->getAddPointsTransformation($this) + ); + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $environment['answer_input_id'] = $uuid_factory->uuid4(); + $clone = clone $this; + $clone->answer_input_id = $environment['answer_input_id']; + $clone->answer_form_id = $environment['answer_form_id']; + $clone->answer_options = $clone->answer_options->clone( + $uuid_factory, + $environment + ); + return $clone; + } + + public function toTableRow( + DataRowBuilder $row_builder, + Language $lng + ): DataRow { + $total_points = 0; + $answer_options_list = ''; + foreach ($this->answer_options->getAnswerOptionsAwardingPoints() as $option) { + $total_points += $option->getAvailablePoints(); + + $gap_text = $option->getTextValue(); + if ($gap_text === '') { + $gap_text = $option->getLowerlimit(); + } + + $answer_options_list .= "{$gap_text} ({$option->getAvailablePoints()})
"; + } + + return $row_builder->buildDataRow( + $this->answer_input_id->toString(), + [ + 'gap' => $this->buildShortenedGapName(), + 'type' => $lng->txt("{$this->type->getIdentifier()}_gap"), + 'answers_options_awarding_points' => $answer_options_list, + 'available_points' => $total_points + ] + ); + } + + private function buildValuesForGapReplace( + PersistenceFactory $persistence_factory + ): array { + return [ + $persistence_factory->value(FieldDefinition::T_TEXT, $this->answer_input_id->toString()), + $persistence_factory->value(FieldDefinition::T_TEXT, $this->answer_form_id->toString()), + $persistence_factory->value(FieldDefinition::T_INTEGER, $this->position), + $persistence_factory->value(FieldDefinition::T_TEXT, $this->type->getIdentifier()), + $persistence_factory->value(FieldDefinition::T_INTEGER, $this->max_chars), + $persistence_factory->value(FieldDefinition::T_FLOAT, $this->step_size), + $persistence_factory->value(FieldDefinition::T_INTEGER, $this->text_matching_method?->value), + $persistence_factory->value(FieldDefinition::T_INTEGER, $this->min_autocomplete), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->shuffle_answer_options === null + ? null + : ($this->shuffle_answer_options ? 1 : 0) + ) + + ]; + } + + private function getShortenedAnswerInputId(): string + { + return mb_substr($this->answer_input_id->toString(), 0, 4); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gaps.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gaps.php new file mode 100644 index 000000000000..9c0d53ca2c12 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Gaps.php @@ -0,0 +1,789 @@ + + */ + private array $gaps; + + public function __construct( + private readonly Refinery $refinery, + private readonly Factory $factory, + private Uuid $answer_form_id, + array $gaps + ) { + uasort( + $gaps, + fn(Gap $a, Gap $b): int => $a->getPosition() <=> $b->getPosition() + ); + + $this->gaps = array_reduce( + $gaps, + function (array $c, Gap $v): array { + $c[$v->getAnswerInputId()->toString()] = $v; + return $c; + }, + [] + ); + } + + public function getTotalAvailablePoints(): ?float + { + return array_reduce( + $this->gaps, + function (?float $c, Gap $v): ?float { + $points_from_options = $v->getAnswerOptions()->getMaxAvailablePoints(); + + if ($points_from_options === null) { + return $c; + } + + if ($c === null) { + return $points_from_options; + } + + return $c + $points_from_options; + } + ); + } + + public function getGapById( + Uuid $gap_id + ): ?Gap { + return $this->gaps[$gap_id->toString()] ?? null; + } + + public function getGapByTagName( + string $tag_name + ): ?Gap { + return $this->gaps[$this->extractIdFromTagName($tag_name)] ?? null; + } + + public function getGapByPosition( + int $position + ): ?Gap { + foreach ($this->gaps as $gap) { + if ($gap->getPosition() === $position) { + return $gap; + } + } + return null; + } + + public function getNumberOfGaps( + ): int { + return count($this->gaps); + } + + public function hasAtLeastOneGap(): bool + { + return $this->gaps !== []; + } + + public function withGap( + Gap $gap + ): self { + $clone = clone $this; + $clone->gaps[$gap->getAnswerInputId()->toString()] = $gap; + return $clone; + } + + public function withNewGap( + Uuid $answer_form_id, + int $position + ): self { + $new_gap = $this->factory->getNewGap($answer_form_id, $position); + $clone = clone $this; + $clone->gaps[$new_gap->getAnswerInputId()->toString()] = $new_gap; + + return $clone; + } + + public function withAdditionalGapFromTagName( + Uuid $answer_form_id, + string $tag_name, + int $position + ): self { + $answer_input_id = $this->extractIdFromTagName($tag_name); + $clone = clone $this; + $clone->gaps[$answer_input_id] = $this->factory->getNewGap( + $answer_form_id, + $position, + $answer_input_id + ); + return $clone; + } + + public function withResetGaps(): self + { + if ($this->gaps === []) { + return $this; + } + + $clone = clone $this; + $clone->gaps = []; + return $clone; + } + + public function getIncompleteGaps(): array + { + return array_filter( + $this->gaps, + fn(Gap $v): bool => $v->getAnswerOptions()->isIncomplete() + ); + } + + public function withMarkedIncompleteGaps(): self + { + $clone = clone $this; + $clone->gaps = array_map( + fn(Gap $v): Gap => $v->getAnswerOptions()->isIncomplete() + ? $v->withAnswerOptions( + $v->getAnswerOptions()->withIsIncomplete(true) + ) : $v, + $clone->gaps + ); + return $clone; + } + + public function getRemovedGaps( + self $old_gaps + ): array { + return array_diff_key($old_gaps->gaps, $this->gaps); + } + + public function getAddedGaps( + self $old_gaps + ): array { + return array_diff_key($this->gaps, $old_gaps->gaps); + } + + public function getPlaceholderArray( + Language $lng, + ViewConfiguration $view_configuration, + ?AdditionalAttemptData $additional_attempt_data, + ?Response $response_data + ): array { + return array_reduce( + $this->gaps, + function ( + array $c, + Gap $v + ) use ( + $lng, + $view_configuration, + $additional_attempt_data, + $response_data + ): array { + $c[$v->buildGapPlaceholderNameWithId($v)] = $view_configuration->isInteractive() + ? $v->buildParticipantViewLegacyInput( + $lng, + $this->refinery, + $additional_attempt_data, + $response_data + ) : $this->buildStaticGapReplacement( + $lng, + $view_configuration->showBestResponse(), + $response_data, + $v + ); + return $c; + }, + [] + ); + } + + public function getPlaceholderArrayForEditFormPanel(): array + { + return array_reduce( + $this->gaps, + function (array $c, Gap $v): array { + $c[$v->buildGapPlaceholderNameWithId($v)] = $v->buildShortenedGapRepresentation(); + return $c; + }, + [] + ); + } + + public function buildGapsTypeInputs( + Language $lng, + FieldFactory $ff, + array $available_gap_types, + Properties $properties, + bool $is_in_creation_context, + array $selected_gaps + ): Section { + return $ff->section( + array_reduce( + $this->retrieveGapsForInputs( + $is_in_creation_context, + $selected_gaps + ), + function (array $c, Gap $v) use ($ff, $available_gap_types): array { + $c[$v->getAnswerInputId()->toString()] = $ff->select( + $v->buildShortenedGapName(), + $available_gap_types + )->withRequired(true) + ->withValue($v->getType()?->getIdentifier()); + return $c; + }, + [] + ), + $lng->txt('set_gap_types') + )->withAdditionalTransformation( + $this->refinery->custom()->transformation( + fn(array $vs): Properties => $properties->withGaps( + array_reduce( + array_keys($vs), + fn(self $c, string $v): self => $c->withGap( + $c->gaps[$v]->withType( + $this->factory->getGapTypeByIdentifier($vs[$v]) + ) + ), + $this + ) + ) + ) + ); + } + + public function buildAnswerOptionsInputs( + FileUpload $file_upload, + Environment $environment, + Properties $properties, + ): Section { + return $environment->getUIFactory()->input()->field()->section( + array_reduce( + $this->retrieveGapsForInputs( + $environment->isInCreationContext(), + $environment->getTableRowIds() + ), + function (array $c, Gap $v) use ($file_upload, $environment): array { + $c[$v->getAnswerInputId()->toString()] = $v->getEditAnswerOptionsSection( + $file_upload, + $environment + ); + return $c; + }, + [] + ), + $environment->getLanguage()->txt('edit_answer_options') + )->withAdditionalTransformation( + $this->refinery->custom()->transformation( + fn(array $vs): Properties => $properties->withGaps( + array_reduce( + array_keys($vs), + fn(self $c, string $v): self => $c->withGap($vs[$v]), + $this + ) + ) + ) + ); + } + + public function buildPointInputs( + Language $lng, + UIFactory $ui_factory, + Properties $properties, + bool $is_in_creation_context, + array $selected_gaps + ): Section { + return $ui_factory->input()->field()->section( + array_reduce( + $this->retrieveGapsForInputs( + $is_in_creation_context, + $selected_gaps + ), + function ( + array $c, + Gap $v + ) use ( + $lng, + $ui_factory, + $properties + ): array { + $c[$v->getAnswerInputId()->toString()] = $v->getEditPointsSection( + $lng, + $ui_factory, + !$properties->getCombinations()->areCombinationsEnabled() + || $this->getNumberOfGaps() < 2 + ); + return $c; + }, + [] + ), + $lng->txt('edit_points') + )->withAdditionalTransformation( + $this->refinery->custom()->transformation( + fn(array $vs): Properties => $properties->withGaps( + array_reduce( + array_keys($vs), + fn(self $c, string $v): self => $c->withGap($vs[$v]), + $this + ) + ) + ) + ); + } + + public function buildGapsSelect( + string $label, + FieldFactory $ff + ): Select { + return $ff->select( + $label, + $this->buildOptionsArray() + ); + } + + public function buildGapsMultiSelect( + string $label, + FieldFactory $ff + ): MultiSelect { + return $ff->multiSelect( + $label, + $this->buildOptionsArray() + ); + } + + public function toCarry(): array + { + return array_reduce( + $this->gaps, + function (array $c, Gap $v): array { + $c[$v->getAnswerInputId()->toString()] = $v->toCarry(); + return $c; + }, + [] + ); + } + + public function withValuesFromCarry( + array $carry + ): self { + $clone = clone $this; + foreach ($carry as $answer_input_id => $gap_definition) { + if (!isset($clone->gaps[$answer_input_id])) { + $clone->gaps[$answer_input_id] = $this->factory->getNewGap( + $this->answer_form_id, + 0, + $answer_input_id + ); + } + + $clone->gaps[$answer_input_id] = $clone->gaps[$answer_input_id] + ->withValuesFromCarry( + $this->refinery, + $this->factory, + $gap_definition + ); + } + + return $clone; + } + + /** + * + * @return list + */ + public function getBestResponses(): array + { + return array_filter( + array_map( + fn(Gap $v): AnswerInputResponse => $v->getType()->getBestResponse( + $v + ), + $this->gaps + ) + ); + } + + public function initializeAttemptData( + Attempt $attempt + ): Attempt { + return array_reduce( + $this->gaps, + fn(Attempt $c, Gap $v): Attempt => $v->getShuffleAnswerOptions() + ? $c->withAdditionalData( + $v->getAnswerInputId(), + $this->refinery->kindlyTo()->string()->transform( + (new RandomSeed())->createSeed() + ) + ) : $c, + $attempt + ); + } + + /** + * + * @return list + */ + public function retrieveResponsesFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory + ): array { + return array_map( + fn(Gap $v): AnswerInputResponse => $v->getType() + ->retrieveResponseFromPost( + $post_wrapper, + $uuid_factory, + $v + ), + $this->gaps + ); + } + + /** + * + * @return list + */ + public function retrieveResponsesFromPreviewData( + UuidFactory $uuid_factory, + array $preview_data + ): array { + return array_reduce( + $this->gaps, + function ( + array $c, + Gap $v + ) use ( + $uuid_factory, + $preview_data + ): array { + $response_object = $v->getType()->retrieveResponseFromPreviewData( + $uuid_factory, + $v, + $preview_data[$v->getAnswerInputId()->toString()] ?? [] + ); + + if ($response_object !== null) { + $c[$v->getAnswerInputId()->toString()] = $response_object; + } + + return $c; + }, + [] + ); + } + + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_form_id = $environment['answer_form_id']; + $clone->gaps = array_map( + fn(Gap $v): Gap => $v->clone($uuid_factory, $environment), + $this->gaps + ); + return $clone; + } + + public function toTableRows( + DataRowBuilder $row_builder, + Language $lng + ): \Generator { + foreach ($this->orderGapsByPosition($this->gaps) as $gap) { + yield $gap->toTableRow( + $row_builder, + $lng + ); + } + } + + public function toStorage( + Manipulate $manipulate, + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Manipulate { + [ + 'gaps' => $replace_for_gaps, + 'answer_options' => $replace_for_answer_options + ] = array_reduce( + $this->gaps, + fn(array $c, Gap $v): array => [ + 'gaps' => $v->buildReplace( + $c['gaps'], + $table_definitions, + $persistence_factory, + $table_names_builder + ), + 'answer_options' => $v->getAnswerOptions()->buildReplace( + $c['answer_options'], + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ], + [ + 'gaps' => null, + 'answer_options' => null + ] + ); + + return $manipulate->withAdditionalStatement( + $this->buildDeleteForRemovedGaps( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + )->withAdditionalStatement($replace_for_gaps) + ->withAdditionalStatement($replace_for_answer_options); + } + + public function toDelete( + Manipulate $manipulate, + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Manipulate { + return array_reduce( + $this->gaps, + fn(Manipulate $c, Gap $v): Manipulate => $c->withAdditionalStatement( + $v->getAnswerOptions()->buildDelete( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ), + $manipulate->withAdditionalStatement( + $this->buildDeleteForDeletionOfAnswerForm( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ) + ); + } + + private function buildDeleteForRemovedGaps( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_type = AnswerFormSpecificTableTypes::AnswerInputs; + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $persistence_factory->where( + $table_definitions->getForeignKeyColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ) + ), + $persistence_factory->where( + $table_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + array_map( + fn(Gap $v): string => $v->getAnswerInputId()->toString(), + $this->gaps + ) + ), + Operator::In, + Junctor::Conjunction, + true + ) + ] + ); + } + + private function buildDeleteForDeletionOfAnswerForm( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_type = AnswerFormSpecificTableTypes::AnswerInputs; + + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $persistence_factory->where( + $table_definitions->getForeignKeyColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ), + ) + ] + ); + } + + private function orderGapsByPosition( + array $gaps + ): array { + usort( + $gaps, + fn(Gap $a, Gap $b) => $a->getPosition() <=> $b->getPosition() + ); + + return $gaps; + } + + private function extractIdFromTagName( + string $tag_name + ): string { + return mb_substr($tag_name, mb_strlen(Gap::GAP_PLACEHOLDER_NAME) + 1); + } + + private function buildOptionsArray(): array + { + return array_reduce( + $this->gaps, + function (array $c, Gap $v): array { + $c[$v->getAnswerInputId()->toString()] = $v->buildShortenedGapName(); + return $c; + }, + [] + ); + } + + private function buildStaticGapReplacement( + Language $lng, + bool $show_best_response, + ?Response $response_data, + Gap $gap + ): string { + $static_gap_template = new \ilTemplate( + 'tpl.cloze_gap_static.html', + true, + true, + 'components/ILIAS/Questions' + ); + $static_gap_template->setVariable( + 'SOLUTION_VALUE', + $this->retrieveStaticGapReplacementValue( + $lng, + $show_best_response, + $response_data, + $gap + ) + ); + return $static_gap_template->get(); + } + + private function retrieveStaticGapReplacementValue( + Language $lng, + bool $show_best_response, + ?Response $response_data, + Gap $gap + ): string { + $empty_gap_text = $lng->txt( + $show_best_response + ? 'no_best_response_available' + : 'no_response_given' + ); + + if ($response_data === null) { + return $empty_gap_text; + } + + $response = $response_data->getResponseForInput( + $gap->getAnswerInputId() + ); + + if ($response === null) { + return $empty_gap_text; + } + + if ($response instanceof Uuid) { + return $gap->getAnswerOptions()->getAnswerOptionById($response)->getTextValue(); + } + + return $response; + } + + private function retrieveGapsForInputs( + bool $is_in_creation_context, + array $selected_gaps + ): array { + if ($is_in_creation_context) { + return $this->gaps; + } + + if ($selected_gaps === []) { + return $this->getIncompleteGaps(); + } + + return $this->filterGapsBySelected($selected_gaps); + } + + private function filterGapsBySelected( + array $selected_gaps + ): array { + return array_filter( + $this->gaps, + fn(string $k): bool => in_array($k, $selected_gaps), + ARRAY_FILTER_USE_KEY + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/LongMenu.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/LongMenu.php new file mode 100644 index 000000000000..a961df8d954c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/LongMenu.php @@ -0,0 +1,292 @@ +getAnswerInputId()->toString(); + + $gaptemplate = new \ilTemplate( + 'tpl.cloze_gap_longmenu.html', + true, + true, + 'components/ILIAS/Questions' + ); + + $gaptemplate->setVariable( + 'GAP_NAME', + $gap_name + ); + + $response = $response_data?->getResponseForInput($gap->getAnswerInputId()); + if ($response !== null) { + $gaptemplate->setVariable( + 'VALUE', + htmlentities( + $response instanceof Uuid + ? $gap->getAnswerOptions() + ->getAnswerOptionById($response) + ->getTextValue() + : $response + ) + ); + } + + $this->global_tpl->addOnLoadCode('il.questions.cloze.initLongmenuGap(' + . "document.querySelector('input[name=\"{$gap_name}\"]'), " + . "{$gap->getMinAutocomplete()}, " + . json_encode( + array_values( + $gap->getAnswerOptions()->buildArrayForSelectInput( + $this->refinery->random()->dontShuffle() + ) + ) + ) . ')'); + return $gaptemplate->get(); + } + + #[\Override] + public function getEditAnswerOptionsInputs( + FileUpload $file_upload, + Environment $environment, + Gap $gap + ): array { + $ff = $environment->getUIFactory()->input()->field(); + $inputs = [ + 'answer_options' => $ff->tag( + $environment->getLanguage()->txt('answer_options'), + [] + )->withValue($gap->getAnswerOptions()->getTagsArrayFromAnswerOptions()), + 'upload_answer_options' => $ff->file( + new Upload( + $file_upload, + $environment + ), + $environment->getLanguage()->txt('upload_answer_options'), + $environment->getLanguage()->txt('upload_answer_options_info') + )->withAcceptedMimeTypes(self::ACCEPTED_MIME_TYPES), + 'min_autocomplete' => $ff->numeric( + $environment->getLanguage()->txt('min_auto_complete') + )->withRequired(true) + ->withValue($gap->getMinAutocomplete() ?? self::DEFAULT_MIN_AUTOCOMPLETE) + ]; + + if ($environment->isMarkingRequired()) { + $inputs['options_awarding_points'] = $ff->tag( + $environment->getLanguage()->txt('answer_options_awarding_points'), + $gap->getAnswerOptions()->getTagsArrayFromAnswerOptions() + )->withRequired(true) + ->withValue( + array_values( + array_map( + fn(AnswerOption $v): string => $v->getTextValue(), + $gap->getAnswerOptions()->getAnswerOptionsAwardingPoints() + ) + ) + ); + } + + return $inputs; + } + + #[\Override] + public function getEditAnswerOptionsSectionConstraint(): ?Constraint + { + return $this->refinery->custom()->constraint( + function (array $vs): bool { + $values = [ + ...$vs['answer_options'], + ...$this->retrieveAnswerOptionsArrayFromUpload( + $vs['upload_answer_options'] + ) + ]; + + return $values !== [] && array_filter( + $vs['options_awarding_points'], + fn(string $v): bool => !in_array($v, $values) + ) === []; + }, + $this->lng->txt('error') + ); + } + #[\Override] + public function getEditPointsInputs( + UIFactory $ui_factory, + AnswerOptions $answer_options, + bool $input_required + ): array { + return $answer_options->getEditPointsInputs( + $ui_factory->input()->field(), + fn(AnswerOption $v): string => $v->getTextValue(), + $answer_options->getAnswerOptionsAwardingPoints() + ); + } + + #[\Override] + public function getEditPointsSectionConstraint( + bool $input_required + ): ?Constraint { + if (!$input_required) { + return null; + } + + return $this->refinery->custom()->constraint( + function (array $vs): bool { + foreach ($vs as $v) { + if ($v > 0.0) { + return true; + } + } + return false; + }, + $this->lng->txt('at_least_one_gap_positiv_points') + ); + } + + #[\Override] + public function getBuildGapTransformation( + Gap $gap + ): Transformation { + return $this->refinery->custom()->transformation( + fn(array $vs): Gap => $gap + ->withMinAutocomplete($vs['min_autocomplete']) + ->withAnswerOptions( + $gap->getAnswerOptions()->withAnswerOptionsFromTags( + [ + ...$vs['answer_options'], + ...$this->retrieveAnswerOptionsArrayFromUpload( + $vs['upload_answer_options'] + ) + ] + )->withAnswerOptionsAwardingPoints($vs['options_awarding_points']) + ) + ); + } + + #[\Override] + public function retrieveResponseFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory, + Gap $gap + ): AnswerInputResponse { + $response_value = $this->retrieveResponseValueFromPost( + $post_wrapper, + $uuid_factory, + $gap + ); + + $response_is_uuid = $response_value instanceof Uuid; + + return new AnswerInputResponse( + $gap, + $response_is_uuid + ? $response_value + : null, + $response_is_uuid + ? '' + : $response_value + ); + } + + private function retrieveAnswerOptionsArrayFromUpload( + ?array $upload_value + ): array { + if ($upload_value === null + || ($decoded_value = base64_decode($upload_value[0] ?? '')) === '') { + return []; + } + + return array_filter( + mb_split('\R', $decoded_value) + ); + } + + private function retrieveResponseValueFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory, + Gap $gap + ): Uuid|string { + return $post_wrapper->retrieve( + $gap->getAnswerInputId()->toString(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + function (?string $v) use ($gap): Uuid|string { + if ($v === null) { + return ''; + } + + $answer_option = $gap->getAnswerOptions() + ->getAnswerOptionByTextValue($v); + + if ($answer_option === null) { + return $v; + } + + return $answer_option?->getAnswerOptionId(); + } + ), + $this->refinery->always('') + ]) + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Numeric.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Numeric.php new file mode 100644 index 000000000000..3b3a068c5a5c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Numeric.php @@ -0,0 +1,388 @@ +setVariable( + 'GAP_NAME', + $gap->getAnswerInputId()->toString() + ); + + $response = $response_data?->getResponseForInput($gap->getAnswerInputId()); + if ($response !== null) { + $gaptemplate->setVariable( + 'VALUE_GAP', + ' value="' . \ilLegacyFormElementsUtil::prepareFormOutput( + $response + ) . '"' + ); + } + + return $gaptemplate->get(); + } + + #[\Override] + public function getEditAnswerOptionsInputs( + FileUpload $file_upload, + Environment $environment, + Gap $gap + ): array { + $answer_option = $gap->getAnswerOptions()->getAnswerOptionForPositionOrNew(0); + + $ff = $environment->getUIFactory()->input()->field(); + return [ + self::KEY_LOWER_LIMIT => $ff->numeric($environment->getLanguage()->txt('range_lower_limit')) + ->withStepSize($gap->getStepSize() ?? self::DEFAULT_SUB_ACTION_SIZE) + ->withRequired(true) + ->withValue($answer_option->getLowerLimit()), + self::KEY_UPPER_LIMIT => $ff->numeric($environment->getLanguage()->txt('range_upper_limit')) + ->withStepSize($gap->getStepSize() ?? self::DEFAULT_SUB_ACTION_SIZE) + ->withValue($answer_option->getUpperLimit()), + self::KEY_STEP_SIZE => $ff->numeric($environment->getLanguage()->txt('step_size')) + ->withStepSize(0.000001) + ->withRequired(true) + ->withValue($gap->getStepSize() ?? self::DEFAULT_SUB_ACTION_SIZE) + ]; + } + + #[\Override] + public function getEditAnswerOptionsSectionConstraint(): ?Constraint + { + return $this->refinery->custom()->constraint( + fn(array $vs): bool => $vs[self::KEY_UPPER_LIMIT] === null + || $vs[self::KEY_UPPER_LIMIT] >= $vs[self::KEY_LOWER_LIMIT] + && $vs[self::KEY_UPPER_LIMIT] >= $vs[self::KEY_LOWER_LIMIT], + $this->lng->txt('upper_limit_bigger_than_lower') + ); + } + + #[\Override] + public function getEditPointsInputs( + UIFactory $ui_factory, + AnswerOptions $answer_options, + bool $input_required + ): array { + $inputs = $answer_options->getEditPointsInputs( + $ui_factory->input()->field(), + function (AnswerOption $v): string { + if ($v->getUpperLimit() === null) { + return sprintf( + $this->lng->txt('equal'), + $v->getLowerLimit() + ); + } + + return sprintf( + $this->lng->txt('between'), + $v->getLowerLimit(), + $v->getUpperLimit() + ); + } + ); + return array_map( + fn(NumericInput $v): NumericInput => $v->withRequired($input_required), + $inputs + ); + } + + #[\Override] + public function getEditPointsSectionConstraint( + bool $input_required + ): ?Constraint { + return null; + } + + #[\Override] + public function getBuildGapTransformation( + Gap $gap + ): Transformation { + return $this->refinery->custom()->transformation( + fn(array $vs): Gap => $gap->withAnswerOptions( + $gap->getAnswerOptions()->withAnswerOptions([ + $gap->getAnswerOptions()->getAnswerOptionForPositionOrNew(0) + ->withLowerLimit($vs['lower_limit']) + ->withUpperLimit($vs['upper_limit']) + ]) + )->withStepSize($vs['step_size']) + ); + } + + #[\Override] + public function getCombinationsSelectValues( + Gap $gap + ): array { + return [ + Range::InRange->value => Range::InRange->getLabel($this->lng), + Range::OutOfRange->value => Range::OutOfRange->getLabel($this->lng) + ]; + } + + #[\Override] + public function getFeedbackSelectValues( + Gap $gap, + bool $is_marking_required + ): array { + return $this->getCombinationsSelectValues($gap); + } + + #[\Override] + public function isValidFeedbackCondition( + UuidFactory $uuid_factory, + Gap $gap, + string $condition + ): bool { + return Range::tryFrom($condition) !== null; + } + + #[\Override] + public function getLabelForValue( + UuidFactory $uuid_factory, + Gap $gap, + string $value + ): string { + return Range::tryFrom($value)?->getLabel($this->lng) ?? ''; + } + + #[\Override] + public function retrieveResponseFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory, + Gap $gap + ): AnswerInputResponse { + return new AnswerInputResponse( + $gap, + null, + $post_wrapper->retrieve( + $gap->getAnswerInputId()->toString(), + $this->refinery->byTrying([ + $this->refinery->in()->series([ + $this->refinery->kindlyTo()->float(), + $this->refinery->kindlyTo()->string() + ]), + $this->refinery->always('') + ]) + ) + ); + } + + #[\Override] + public function isBestResponse( + Gap $gap, + AnswerInputResponse $response + ): bool { + if ($response->getResponse() === null) { + return false; + } + + /** @var ?AnswerOption $answer_option */ + $answer_options_awarding_points = $gap->getAnswerOptions() + ->getAnswerOptionsAwardingPoints(); + + $answer_option = $answer_options_awarding_points === null + ? null + : array_shift($answer_options_awarding_points); + + if ($answer_option === null) { + return false; + } + + return $this->getRangeValueFromResponseValue( + $answer_option, + $response->getResponse() + ) === Range::InRange; + } + + #[\Override] + public function calculateAwardedPointsForResponse( + Gap $gap, + Uuid|string|null $response + ): float { + if ($response === null) { + return 0.0; + } + + $answer_option = $this->getAnswerOptionAwardingPoints($gap); + + if ($answer_option === null) { + return 0.0; + } + + if ($this->getRangeValueFromResponseValue( + $answer_option, + $response + ) === Range::InRange) { + return $answer_option->getAvailablePoints(); + } + + return 0.0; + } + + #[\Override] + public function buildClientSideRepresentationOfResponse( + Gap $gap, + AnswerInputResponse $response + ): array { + $answer_option = $this->getAnswerOptionAwardingPoints($gap); + + return [ + self::KEY_RESPONSE => $response->getResponse(), + self::KEY_LOWER_LIMIT => $answer_option->getLowerLimit(), + self::KEY_UPPER_LIMIT => $answer_option->getUpperLimit() + ]; + } + + #[\Override] + public function getSpecificFeedbackParticipantOutput( + UIFactory $ui_factory, + Gap $gap, + array $specific_feedbacks, + Uuid|string $answer_input_response + ): ?Component { + $specific_feedbacks_by_condition = array_reduce( + $specific_feedbacks, + function (array $c, SpecificTextFeedback $v): array { + if (!array_key_exists($v->getCondition(), $c)) { + $c[$v->getCondition()] = []; + } + + $c[$v->getCondition()] = $v->getFeedbackTextForPresentation($this->refinery); + + return $c; + }, + [] + ); + + $range_value = $this->getRangeValueFromResponseValue( + $this->getAnswerOptionAwardingPoints($gap), + $answer_input_response + ); + + if (isset($specific_feedbacks_by_condition[$range_value->value])) { + return $ui_factory->legacy()->content( + $specific_feedbacks_by_condition[$range_value->value] + ); + } + + if (($range_value === Range::BelowRange + || $range_value === Range::BelowRange) + && isset($specific_feedbacks_by_condition[Range::OutOfRange->value])) { + return $ui_factory->legacy()->content( + $specific_feedbacks_by_condition[Range::OutOfRange->value] + ); + } + + return null; + } + + #[\Override] + protected function retrieveResponseTextFromAnswerOption( + AnswerOption $answer_option + ): string { + $trafo = $this->refinery->kindlyTo()->string(); + $lower_limit_string = $trafo->transform( + $answer_option->getLowerLimit() + ); + $upper_limit = $answer_option->getUpperLimit(); + return $upper_limit === null + ? $lower_limit_string + : "{$lower_limit_string} - {$trafo->transform($upper_limit)}"; + } + + private function getAnswerOptionAwardingPoints( + Gap $gap + ): AnswerOption { + /** @var ?AnswerOption $answer_option */ + $answer_options_awarding_points = $gap->getAnswerOptions() + ->getAnswerOptionsAwardingPoints(); + + return $answer_options_awarding_points === null + ? null + : array_shift($answer_options_awarding_points); + } + + private function getRangeValueFromResponseValue( + AnswerOption $answer_option, + string $response + ): Range { + $response_as_float = $this->refinery->kindlyTo()->float()->transform( + $response + ); + + $upper_limit = $answer_option->getUpperLimit(); + $lower_limit = $answer_option->getLowerLimit(); + + if ($response < $lower_limit) { + return Range::BelowRange; + } + + if ($upper_limit === null + && $response_as_float === $lower_limit + || $response_as_float <= $upper_limit) { + return Range::InRange; + } + + return Range::AboveRange; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Select.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Select.php new file mode 100644 index 000000000000..022598bd795c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Select.php @@ -0,0 +1,253 @@ +getResponseForInput( + $gap->getAnswerInputId() + )?->toString(); + + foreach ($gap->getAnswerOptions()->buildArrayForSelectInput( + $this->buildShuffler( + $gap, + $additional_attempt_data + ) + ) as $answer_option_id => $answer_option) { + $gaptemplate->setCurrentBlock('select_gap_option'); + $gaptemplate->setVariable( + 'SELECT_GAP_VALUE', + $answer_option_id + ); + $gaptemplate->setVariable( + 'SELECT_GAP_TEXT', + \ilLegacyFormElementsUtil::prepareFormOutput($answer_option) + ); + + if ($answer_option_id === $selected_answer_option) { + $gaptemplate->setVariable( + 'SELECT_GAP_SELECTED', + ' selected="selected"' + ); + } + + $gaptemplate->parseCurrentBlock(); + } + + $gaptemplate->setVariable( + 'PLEASE_SELECT', + $this->lng->txt('please_select') + ); + + $gaptemplate->setVariable( + 'GAP_NAME', + $gap->getAnswerInputId()->toString() + ); + + return $gaptemplate->get(); + } + + #[\Override] + public function getEditAnswerOptionsInputs( + FileUpload $file_upload, + Environment $environment, + Gap $gap + ): array { + $ff = $environment->getUIFactory()->input()->field(); + return [ + 'answer_options' => $ff->tag( + $environment->getLanguage()->txt('answer_options'), + [] + )->withRequired(true) + ->withValue($gap->getAnswerOptions()->getTagsArrayFromAnswerOptions()), + 'shuffle_answer_options' => $ff->checkbox( + $environment->getLanguage()->txt('shuffle_answers') + )->withValue($gap?->getShuffleAnswerOptions() ?? self::DEFAULT_SHUFFLE_ANSWER_OPTIONS) + ]; + } + + #[\Override] + public function getEditAnswerOptionsSectionConstraint(): ?Constraint + { + return null; + } + + #[\Override] + public function getEditPointsInputs( + UIFactory $ui_factory, + AnswerOptions $answer_options, + bool $input_required + ): array { + return $answer_options->getEditPointsInputs( + $ui_factory->input()->field(), + fn(AnswerOption $v): string => $v->getTextValue() + ); + } + + #[\Override] + public function getEditPointsSectionConstraint( + bool $input_required + ): ?Constraint { + if (!$input_required) { + return null; + } + + return $this->refinery->custom()->constraint( + function (array $vs): bool { + foreach ($vs as $v) { + if ($v > 0.0) { + return true; + } + } + return false; + }, + $this->lng->txt('at_least_one_gap_positiv_points') + ); + } + + #[\Override] + public function getBuildGapTransformation( + Gap $gap + ): Transformation { + return $this->refinery->custom()->transformation( + fn(array $vs): Gap => $gap->withAnswerOptions( + $gap->getAnswerOptions()->withAnswerOptionsFromTags( + $vs['answer_options'] + ) + )->withShuffleAnswerOptions($vs['shuffle_answer_options']) + ); + } + + #[\Override] + public function retrieveResponseFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory, + Gap $gap + ): AnswerInputResponse { + return new AnswerInputResponse( + $gap, + $post_wrapper->retrieve( + $gap->getAnswerInputId()->toString(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + function (?string $v) use ($uuid_factory, $gap): ?Uuid { + if ($v === null) { + return null; + } + + try { + $answer_option_id = $uuid_factory->fromString($v); + } catch (\Exception $e) { + return null; + } + + if ($gap->getAnswerOptions()->getAnswerOptionById( + $answer_option_id + ) === null) { + return null; + } + + return $answer_option_id; + } + ), + $this->refinery->always(null) + ]) + ), + '' + ); + } + + private function buildShuffler( + Gap $gap, + ?AdditionalAttemptData $additional_attempt_data + ): Transformation { + if (!$gap->getShuffleAnswerOptions()) { + return $this->refinery->random()->dontShuffle(); + } + + return $this->refinery->random()->shuffleArray( + $this->buildSeed( + $gap, + $additional_attempt_data + ) + ); + } + + private function buildSeed( + Gap $gap, + ?AdditionalAttemptData $additional_attempt_data + ): GivenSeed { + if ($additional_attempt_data === null) { + return new RandomSeed(); + } + + $given_seed = $additional_attempt_data->getAdditionalDataFor( + $gap->getAnswerInputId() + ); + + if (is_numeric($given_seed)) { + return new GivenSeed( + $this->refinery->kindlyTo()->int()->transform( + $given_seed + ) + ); + } + + return new RandomSeed(); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Text.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Text.php new file mode 100644 index 000000000000..ae073f876488 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Text.php @@ -0,0 +1,281 @@ +getMaxChars(); + if ($gap_size > 0) { + $gaptemplate->setCurrentBlock('size_and_maxlength'); + $gaptemplate->setVariable('TEXT_GAP_SIZE', $gap_size); + $gaptemplate->parseCurrentBlock(); + } + $gaptemplate->setVariable( + 'GAP_NAME', + $gap->getAnswerInputId()->toString() + ); + + $response = $response_data?->getResponseForInput($gap->getAnswerInputId()); + if ($response !== null) { + $gaptemplate->setVariable( + 'VALUE_GAP', + ' value="' . \ilLegacyFormElementsUtil::prepareFormOutput( + $response + ) . '"' + ); + } + + return $gaptemplate->get(); + } + + #[\Override] + public function getEditAnswerOptionsInputs( + FileUpload $file_upload, + Environment $environment, + Gap $gap + ): array { + $ff = $environment->getUIFactory()->input()->field(); + return [ + 'answer_options' => $ff->tag( + $environment->getLanguage()->txt('answer_options'), + [] + )->withRequired(true) + ->withValue($gap->getAnswerOptions()->getTagsArrayFromAnswerOptions()), + 'matching_method' => $ff->select( + $environment->getLanguage()->txt('text_matching_method'), + TextMatchingOptions::buildOptionsList($environment->getLanguage()) + )->withRequired(true) + ->withValue($gap->getTextMatchingMethod()?->value ?? self::DEFAULT_TECT_MATCHING_METHOD->value), + 'max_chars' => $ff->numeric( + $environment->getLanguage()->txt('max_characters'), + )->withValue($gap->getMaxChars()) + ]; + } + + #[\Override] + public function getEditAnswerOptionsSectionConstraint(): ?Constraint + { + return $this->refinery->custom()->constraint( + fn(array $vs): bool => array_filter( + $vs['answer_options'], + fn(string $v): bool => in_array($v, $vs['answer_options']) + ) !== [], + $this->lng->txt('answer_options_must_be_unique') + ); + } + + #[\Override] + public function getEditPointsInputs( + UIFactory $ui_factory, + AnswerOptions $answer_options, + bool $input_required + ): array { + return $answer_options->getEditPointsInputs( + $ui_factory->input()->field(), + fn(AnswerOption $v): string => $v->getTextValue() + ); + } + + #[\Override] + public function getEditPointsSectionConstraint( + bool $input_required + ): ?Constraint { + if (!$input_required) { + return null; + } + + return $this->refinery->custom()->constraint( + function (array $vs): bool { + foreach ($vs as $v) { + if ($v > 0.0) { + return true; + } + } + return false; + }, + $this->lng->txt('at_least_one_gap_positiv_points') + ); + } + + #[\Override] + public function getBuildGapTransformation( + Gap $gap + ): Transformation { + return $this->refinery->custom()->transformation( + fn(array $vs): Gap => $gap->withMaxChars($vs['max_chars']) + ->withTextMatchingMethod( + TextMatchingOptions::tryFrom($vs['matching_method']) + ?? self::DEFAULT_TECT_MATCHING_METHOD + )->withAnswerOptions( + $gap->getAnswerOptions()->withAnswerOptionsFromTags( + $vs['answer_options'] + ) + ) + ); + } + + #[\Override] + public function retrieveResponseFromPost( + RequestWrapper $post_wrapper, + UuidFactory $uuid_factory, + Gap $gap + ): AnswerInputResponse { + return new AnswerInputResponse( + $gap, + null, + $post_wrapper->retrieve( + $gap->getAnswerInputId()->toString(), + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->string(), + $this->refinery->always('') + ]) + ) + ); + } + + #[\Override] + public function isBestResponse( + Gap $gap, + AnswerInputResponse $response + ): bool { + return $this->getBestResponse( + $gap + )?->getResponse() === $response->getResponse(); + } + + #[\Override] + public function calculateAwardedPointsForResponse( + Gap $gap, + Uuid|string|null $response + ): float { + + $answer_option = array_filter( + $gap->getAnswerOptions()->getAnswerOptionsAwardingPoints(), + fn(AnswerOption $v): bool => $response === $v->getTextValue() + ); + + if ($answer_option === []) { + return 0.0; + } + + return array_shift($answer_option)->getAvailablePoints(); + } + + #[\Override] + public function buildClientSideRepresentationOfResponse( + Gap $gap, + AnswerInputResponse $response + ): array { + return [ + self::KEY_RESPONSE => $response->getResponse() + ]; + } + + #[\Override] + public function getSpecificFeedbackParticipantOutput( + UIFactory $ui_factory, + Gap $gap, + array $specific_feedbacks, + Uuid|string $answer_input_response + ): ?Component { + $specific_feedbacks_by_condition = array_reduce( + $specific_feedbacks, + function (array $c, SpecificTextFeedback $v): array { + $c[$v->getCondition()] = $v->getFeedbackText(); + return $c; + }, + [] + ); + + if ($answer_input_response instanceof Uuid) { + return $this->getSpecificFeedbackParticipantOutputForAnswerOption( + $ui_factory, + $specific_feedbacks_by_condition[$answer_input_response->toString()] ?? null + ); + } + + if ($this->getBestResponse($gap) === null) { + return null; + } + + if ($this->getBestResponse($gap)->getResponse() === $answer_input_response) { + return isset($specific_feedbacks_by_condition[TextFeedbackTypes::BestResponse->value]) + ? $ui_factory->legacy()->content( + $this->refinery->string()->markdown()->toHTML()->transform( + $specific_feedbacks_by_condition[TextFeedbackTypes::BestResponse->value]->getRawRepresentation() + ) + ) : null; + } + + return isset($specific_feedbacks_by_condition[TextFeedbackTypes::OtherResponse->value]) + ? $ui_factory->legacy()->content( + $this->refinery->string()->markdown()->toHTML()->transform( + $specific_feedbacks_by_condition[TextFeedbackTypes::OtherResponse->value]->getRawRepresentation() + ) + ) : null; + } + + #[\Override] + protected function retrieveResponseTextFromAnswerOption( + AnswerOption $answer_option + ): string { + return $answer_option->getTextValue(); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Type.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Type.php new file mode 100644 index 000000000000..a9d8f67c99b2 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Gaps/Type.php @@ -0,0 +1,310 @@ +getAnswerOptions()->buildArrayForSelectInput( + $this->refinery->random()->dontShuffle() + ); + } + + public function getFeedbackSelectValues( + Gap $gap, + bool $is_marking_required + ): array { + $basic_select_values = $this->getCombinationsSelectValues( + $gap + ); + if (!$is_marking_required) { + return $basic_select_values; + } + return [ + ...[ + TextFeedbackTypes::BestResponse->value => TextFeedbackTypes::BestResponse + ->getTranslatedOptionName($this->lng), + TextFeedbackTypes::OtherResponse->value => TextFeedbackTypes::OtherResponse + ->getTranslatedOptionName($this->lng), + TextFeedbackTypes::NoResponse->value => TextFeedbackTypes::NoResponse + ->getTranslatedOptionName($this->lng) + ], + ...$basic_select_values + ]; + } + + public function isValidFeedbackCondition( + UuidFactory $uuid_factory, + Gap $gap, + string $condition + ): bool { + if (TextFeedbackTypes::tryFrom($condition) !== null + || Range::tryFrom($condition) !== null) { + return true; + } + + try { + return $gap->getAnswerOptions()->getAnswerOptionById( + $uuid_factory->fromString($condition) + ) !== null; + } catch (InvalidUuidStringException $e) { + return false; + } + } + + public function getLabelForValue( + UuidFactory $uuid_factory, + Gap $gap, + string $value + ): string { + $from_feedback = TextFeedbackTypes::tryFrom($value); + if ($from_feedback !== null) { + return $from_feedback->getTranslatedOptionName($this->lng); + } + + return $gap->getAnswerOptions()->getAnswerOptionById( + $uuid_factory->fromString($value) + )->getTextValue(); + } + + public function getAddPointsTransformation( + Gap $gap + ): Transformation { + return $this->refinery->custom()->transformation( + fn(array $vs): Gap => $gap->withAnswerOptions( + $gap->getAnswerOptions() + ->withAnswerOptionsWithAddedPointsFromForm($this->refinery, $vs) + ) + ); + } + + public function getBestResponse( + Gap $gap + ): ?AnswerInputResponse { + $best_answer_option = $gap->getAnswerOptions()->getBestAnswerOption(); + if ($best_answer_option === null) { + return null; + } + + $text = $this->retrieveResponseTextFromAnswerOption( + $best_answer_option + ); + if ($text !== '') { + $best_answer_option = null; + } + + return new AnswerInputResponse( + $gap, + $best_answer_option?->getAnswerOptionId(), + $text + ); + } + + public function isBestResponse( + Gap $gap, + AnswerInputResponse $response + ): bool { + $response_value = $response->getResponse(); + + if (!($response_value instanceof Uuid)) { + return false; + } + + return $this->getBestResponse( + $gap + )->getResponse()?->compareTo( + $response_value + ) === 0; + } + + public function calculateAwardedPointsForResponse( + Gap $gap, + Uuid|string|null $response + ): float { + if (!($response instanceof Uuid)) { + return 0.0; + } + + $answer_option = $gap->getAnswerOptions()->getAnswerOptionById($response); + + if ($answer_option === null) { + return 0.0; + } + + return $answer_option->getAvailablePoints() ?? 0.0; + } + + public function buildClientSideRepresentationOfResponse( + Gap $gap, + AnswerInputResponse $response + ): array { + return [ + self::KEY_RESPONSE => $response->getResponse()->toString() + ]; + } + + public function getSpecificFeedbackParticipantOutput( + UIFactory $ui_factory, + Gap $gap, + array $specific_feedbacks, + Uuid|string $answer_input_response + ): ?Component { + $specific_feedbacks_by_condition = array_reduce( + $specific_feedbacks, + function (array $c, SpecificTextFeedback $v): array { + if (!array_key_exists($v->getCondition(), $c)) { + $c[$v->getCondition()] = []; + } + + $c[$v->getCondition()] = $v->getFeedbackTextForPresentation($this->refinery); + + return $c; + }, + [] + ); + + if ($answer_input_response instanceof Uuid) { + return $this->getSpecificFeedbackParticipantOutputForAnswerOption( + $ui_factory, + $specific_feedbacks_by_condition[$answer_input_response->toString()] ?? null + ); + } + + if ($this->getBestResponse($gap) === null) { + return null; + } + + if ($this->getBestResponse($gap)->getResponse() === $answer_input_response) { + return isset($specific_feedbacks_by_condition[TextFeedbackTypes::BestResponse->value]) + ? $ui_factory->legacy()->content( + $specific_feedbacks_by_condition[TextFeedbackTypes::BestResponse->value] + ) : null; + } + + return isset($specific_feedbacks_by_condition[TextFeedbackTypes::OtherResponse->value]) + ? $ui_factory->legacy()->content( + $specific_feedbacks_by_condition[TextFeedbackTypes::OtherResponse] + ) : null; + } + + public function retrieveResponseFromPreviewData( + UuidFactory $uuid_factory, + Gap $gap, + array $preview_data + ): ?AnswerInputResponse { + if ($preview_data === []) { + return null; + } + + return new AnswerInputResponse( + $gap, + isset($preview_data[AnswerInputResponse::KEY_SELECTED_ANSWER_OPTION]) + ? $uuid_factory->fromString($preview_data[AnswerInputResponse::KEY_SELECTED_ANSWER_OPTION]) + : null, + $preview_data[AnswerInputResponse::KEY_TEXT] ?? '' + ); + } + + protected function retrieveResponseTextFromAnswerOption( + AnswerOption $answer_option + ): string { + return ''; + } + + private function getSpecificFeedbackParticipantOutputForAnswerOption( + UIFactory $ui_factory, + ?string $specific_feedback + ): ?Component { + if ($specific_feedback === null) { + return null; + } + + return $ui_factory->legacy()->content($specific_feedback); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Properties.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Properties.php new file mode 100644 index 000000000000..3813ed31d417 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Properties/Properties.php @@ -0,0 +1,524 @@ + $gaps + */ + public function __construct( + private Uuid $answer_form_id, + private Uuid $question_id, + private readonly Definition $definition, + private readonly ?float $available_points, + private Text $cloze_text, + private string $legacy_cloze_text, + private ScoringIdentical $scoring_identical, + private Gaps $gaps, + private Combinations $combinations + ) { + } + + #[\Override] + public function getAnswerFormId(): Uuid + { + return $this->answer_form_id; + } + + #[\Override] + public function getQuestionId(): Uuid + { + return $this->question_id; + } + + #[\Override] + public function getDefinition(): ?Definition + { + return $this->definition; + } + + #[\Override] + public function getTypeGenericProperties(): TypeGenericProperties + { + return new TypeGenericProperties( + $this->answer_form_id, + $this->question_id, + $this->definition, + $this->buildAvailablePointsForGenericProperties(), + null, + null, + $this->cloze_text->getRawRepresentation(), + $this->legacy_cloze_text + ); + } + + public function getClozeText(): Text + { + return $this->cloze_text; + } + + public function withClozeText( + Text $cloze_text + ): self { + $clone = clone $this; + $clone->cloze_text = $cloze_text; + return $clone; + } + + public function getLegacyClozeText(): string + { + return $this->legacy_cloze_text; + } + + public function getClozeTextForPresentation(): string + { + return $this->cloze_text->getRawRepresentation() === '' + ? \ilRTE::_replaceMediaObjectImageSrc($this->legacy_cloze_text, 0) + : $this->cloze_text->getRenderedMarkdownForParticipantPresentation(); + } + + public function getScoringOfIdenticalResponses(): ScoringIdentical + { + return $this->scoring_identical; + } + + public function withScoringOfIdenticalResponses( + ScoringIdentical $scoring_identical + ): self { + $clone = clone $this; + $clone->scoring_identical = $scoring_identical; + return $clone; + } + + public function getCombinations(): Combinations + { + return $this->combinations; + } + + public function withCombinations( + Combinations $combinations + ): self { + $clone = clone $this; + $clone->combinations = $combinations; + $clone->updated_combinations = true; + return $clone; + } + + public function getGaps(): Gaps + { + return $this->gaps; + } + + public function withGaps( + Gaps $gaps + ): self { + $clone = clone $this; + $clone->gaps = $gaps; + $clone->updated_gaps = true; + return $clone; + } + + #[\Override] + public function getBasicPropertiesForListing( + Environment $environment + ): array { + $lng = $environment->getLanguage(); + + $listing = [ + $lng->txt('cloze_text') => $this->cloze_text + ->getRenderedMarkdownForEditingPresentation( + $this->gaps, + $this->getLegacyClozeText() + ) + ]; + + if ($environment->isMarkingRequired()) { + $listing[$lng->txt('scoring_of_identical_responses')] = $this + ->scoring_identical + ->getTranslatedOptionName($lng); + } + + return [ + ...$listing, + $lng->txt('gap_combinations') => $this->combinations->areCombinationsEnabled() + ? $lng->txt('enabled') + : $lng->txt('disabled') + ]; + } + + #[\Override] + public function completeEditOverview( + Environment $environment, + EditOverview $edit_overview + ): EditOverview { + return $edit_overview->withTable( + new OverviewTable( + $environment + )->getTable() + ); + } + + public function buildBasicEditingInputs( + Environment $environment, + Factory $properties_factory, + ClozeTextFactory $cloze_text_factory, + bool $add_legacy_cloze_text_to_input + ): Section { + $lng = $environment->getLanguage(); + $ff = $environment->getUIFactory()->input()->field(); + $refinery = $environment->getRefinery(); + + $cloze_text_input = $this->cloze_text->getInput( + $lng, + $ff, + $cloze_text_factory, + $this->legacy_cloze_text === '' + || $this->legacy_cloze_text !== '' + && $this->cloze_text->getRawRepresentation() !== '' + ); + + if ($add_legacy_cloze_text_to_input) { + $cloze_text_input = $cloze_text_input->withValue( + strip_tags($this->legacy_cloze_text) + ); + } + + $inputs = [ + self::KEY_CLOZE_TEXT => $cloze_text_input, + self::KEY_SCORING_IDENTICAL => ScoringIdentical::buildInput( + $lng, + $ff, + $refinery, + $this->scoring_identical + )->withValue($this->getScoringOfIdenticalResponses()->value) + ]; + + if ($environment->isMarkingRequired()) { + $inputs[self::KEY_ENABLE_COMBINATIONS] = $ff->checkbox( + $lng->txt('cloze_enable_gap_combinations') + )->withValue($this->combinations->areCombinationsEnabled()); + } + + return $ff->section( + $inputs, + $lng->txt('edit_basic_answer_form_properties') + )->withAdditionalTransformation( + $refinery->custom()->transformation( + fn(array $vs): self => $properties_factory->fromBasicEditingForm( + $this, + $vs[self::KEY_CLOZE_TEXT], + $vs[self::KEY_SCORING_IDENTICAL], + $vs[self::KEY_ENABLE_COMBINATIONS] ?? false + ) + ) + ); + } + + public function toCarry(): string + { + return json_encode([ + self::KEY_CLOZE_TEXT => $this->cloze_text->getRawRepresentation(), + self::KEY_GAPS => $this->gaps->toCarry(), + self::KEY_SCORING_IDENTICAL => $this->scoring_identical->value, + self::KEY_ENABLE_COMBINATIONS => $this->combinations + ->areCombinationsEnabled() ? 1 : 0 + ]); + } + + public function withValuesFromCarry( + ClozeTextFactory $cloze_text_factory, + array $carry + ): self { + $clone = clone $this; + + $clone->cloze_text = $cloze_text_factory->buildFromTextString( + $carry[self::KEY_CLOZE_TEXT] + ); + $clone->gaps = $this->getGaps()->withValuesFromCarry( + $carry[self::KEY_GAPS] + ); + $clone->scoring_identical = ScoringIdentical::tryFrom( + $carry[self::KEY_SCORING_IDENTICAL] + ); + $clone->combinations = $this->combinations->withCombinationsEnabled( + $carry[self::KEY_ENABLE_COMBINATIONS] === 1 + ); + return $clone; + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->answer_form_id = $environment['answer_form_id']; + $clone->question_id = $environment['new_question_id']; + $environment['gaps'] = $clone->gaps->clone($uuid_factory, $environment); + + $update_text_closure = $this->buildReplaceClonedGapsInTextsClosure( + $environment['gaps'] + ); + $clone->cloze_text = $clone->cloze_text->withUpdateMarkdownAfterCloning( + $update_text_closure + ); + $clone->legacy_cloze_text = $update_text_closure($this->legacy_cloze_text); + + $clone->gaps = $environment['gaps']; + $clone->combinations->clone($uuid_factory, $environment); + return $clone; + } + + #[\Override] + public function toStorage( + PersistenceFactory $persistence_factory, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + $table_definitions = $this->definition->getTableDefinitions(); + + $table_names_builder = $manipulate->getTableNameBuilder( + $table_definitions->getTableSubNameSpace() + ); + + $answer_form_statement = $manipulation_type === ManipulationType::Create + ? $this->buildInsertAnswerFormStatement( + $table_definitions, + $persistence_factory, + $table_names_builder + ) : $this->buildUpdateAnswerFormStatement( + $table_definitions, + $persistence_factory, + $table_names_builder + ); + + return $this->gaps->toStorage( + $this->addReplaceCombinationsStatements( + $manipulate, + $table_definitions, + $table_names_builder + )->withAdditionalStatement( + $answer_form_statement + ), + $persistence_factory, + $table_definitions, + $table_names_builder + ); + } + + #[\Override] + public function toDelete( + PersistenceFactory $persistence_factory, + Manipulate $manipulate + ): Manipulate { + $table_definitions = $this->definition->getTableDefinitions(); + $table_names_builder = $manipulate->getTableNameBuilder( + $table_definitions->getTableSubNameSpace() + ); + + return $this->gaps->toDelete( + $manipulate->withAdditionalStatement( + $this->buildDeleteAnswerFormStatement( + $table_definitions, + $persistence_factory, + $table_names_builder + ) + ), + $persistence_factory, + $table_definitions, + $table_names_builder + ); + } + + private function buildInsertAnswerFormStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Insert { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ), + [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->scoring_identical->value + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->combinations->areCombinationsEnabled() ? 1 : 0 + ) + ] + ); + } + + private function buildUpdateAnswerFormStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Update { + $table_type = AnswerFormSpecificTableTypes::TypeSpecificAnswerForms; + return $persistence_factory->update( + $table_definitions->getColumns( + $table_names_builder, + $table_type, + '', + ['answer_form_id'] + ), + [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->scoring_identical->value + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->combinations->areCombinationsEnabled() ? 1 : 0 + ) + ], + [ + $persistence_factory->where( + $table_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ) + ) + ] + ); + } + + private function addReplaceCombinationsStatements( + Manipulate $manipulate, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Manipulate { + if (!$this->combinations->areCombinationsEnabled() + || !$this->updated_combinations) { + return $manipulate; + } + + return $this->combinations->toStorage( + $manipulate, + $table_definitions, + $table_names_builder + ); + } + + private function buildDeleteAnswerFormStatement( + TableDefinitions $table_definitions, + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): Delete { + $table_type = AnswerFormSpecificTableTypes::TypeSpecificAnswerForms; + + return $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $persistence_factory->where( + $table_definitions->getForeignKeyColumn( + $table_names_builder, + $table_type + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->answer_form_id->toString() + ) + ) + ] + ); + } + + private function buildAvailablePointsForGenericProperties(): ?float + { + if (!$this->updated_gaps && !$this->updated_combinations) { + return $this->available_points; + } + + if (!$this->combinations->areCombinationsEnabled()) { + return $this->gaps->getTotalAvailablePoints(); + } + + return 1.1; + } + + private function buildReplaceClonedGapsInTextsClosure( + Gaps $new_gaps + ): \Closure { + return function ($text) use ($new_gaps): string { + $position = 0; + return mb_ereg_replace_callback( + '{{' . Gap::GAP_PLACEHOLDER_NAME + . '_[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}}}', + function ($matches) use ($new_gaps, &$position): string { + return '{{' . Gap::GAP_PLACEHOLDER_NAME + . "_{$new_gaps->getGapByPosition($position++)->getAnswerInputId()->toString()}}}"; + }, + $text + ); + }; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerForm.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerForm.php new file mode 100644 index 000000000000..c7b90e807d3c --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerForm.php @@ -0,0 +1,193 @@ + $answer_input_responses + */ + private readonly array $answer_input_responses; + + /** + * @param array $answer_input_responses + */ + public function __construct( + private readonly TableDefinitions $table_definitions, + private readonly Uuid $response_id, + private readonly Uuid $answer_form_id, + array $answer_input_responses + ) { + $this->answer_input_responses = array_reduce( + $answer_input_responses, + function (array $c, AnswerInput $v): array { + $c[$v->getAnswerInputId()->toString()] = $v; + return $c; + }, + [] + ); + } + + #[\Override] + public function getAnswerFormId(): Uuid + { + return $this->answer_form_id; + } + + #[\Override] + public function isBest(): bool + { + foreach ($this->answer_input_responses as $response) { + if (!$response->isBest()) { + return false; + } + } + + + return true; + } + + #[\Override] + public function toPreviewStorage(): array + { + return array_map( + fn(AnswerInput $v): array => $v->toPreviewStorage(), + $this->answer_input_responses + ); + } + + #[\Override] + public function toStorage( + PersistenceFactory $persistence_factory, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + return $manipulate->withAdditionalStatement( + array_reduce( + $this->answer_input_responses, + fn(?Insert $c, AnswerInput $v): Insert => $v->toStorage( + $this->table_definitions, + $manipulate->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + $persistence_factory, + $c, + $this->response_id + ) + ) + ); + } + + #[\Override] + public function toDelete( + PersistenceFactory $persistence_factory, + Manipulate $manipulate + ): Manipulate { + return $manipulate->withAdditionalStatement( + $persistence_factory->delete( + $persistence_factory->table( + $manipulate->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + AnswerFormSpecificTableTypes::Responses + ), + [ + $persistence_factory->where( + $this->table_definitions->getIdColumn( + $manipulate->getTableNameBuilder( + $this->table_definitions->getTableSubNameSpace() + ), + AnswerFormSpecificTableTypes::Responses + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->response_id->toString() + ) + ) + ] + ) + ); + } + + #[\Override] + public function toClientSideRepresentation(): array + { + return array_reduce( + $this->answer_input_responses, + function (array $c, AnswerInput $v): array { + $c[$v->getAnswerInputId()->toString()] = $v->toClientSideRepresentation(); + return $c; + }, + [] + ); + } + + public function getResponseForInput( + Uuid $answer_input_id + ): Uuid|string|null { + if (isset($this->answer_input_responses[$answer_input_id->toString()])) { + return $this->answer_input_responses[$answer_input_id->toString()]->getResponse(); + } + + return null; + } + + public function calculateAwardedPoints( + Properties $answer_form_properties + ): float { + return array_reduce( + $this->answer_input_responses, + function (?float $c, AnswerInput $v) use ($answer_form_properties): ?float { + $gap = $answer_form_properties + ->getGaps() + ->getGapById( + $v->getAnswerInputId() + ); + + if ($gap === null) { + return 0.0; + } + + $awarded_points = $gap->getType()->calculateAwardedPointsForResponse( + $gap, + $v->getResponse() + ); + + if ($c === null) { + return $awarded_points; + } + + return $c + $awarded_points; + } + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerInput.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerInput.php new file mode 100644 index 000000000000..8d0b0471fcb8 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/AnswerInput.php @@ -0,0 +1,135 @@ +gap->getAnswerInputId(); + } + + public function getResponse(): Uuid|string|null + { + if ($this->selected_answer_option !== null) { + return $this->selected_answer_option; + } + + if ($this->text !== '') { + return $this->text; + } + + return null; + } + + public function isBest(): bool + { + return $this->gap->getType()->isBestResponse($this->gap, $this); + } + + public function toClientSideRepresentation(): array + { + return [ + self::KEY_GAP_TYPE => $this->gap->getType()->getIdentifier(), + self::KEY_RESPONSE => $this->gap->getType()->buildClientSideRepresentationOfResponse( + $this->gap, + $this + ) + ]; + } + + public function toPreviewStorage(): array + { + return [ + self::KEY_SELECTED_ANSWER_OPTION => $this->selected_answer_option?->toString(), + self::KEY_TEXT => $this->text + ]; + } + + public function toStorage( + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + PersistenceFactory $persistence_factory, + ?Insert $insert, + Uuid $id + ): Insert { + if ($insert === null) { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Responses + ), + $this->buildValuesArrayForStorage($persistence_factory, $id) + ); + } + + return $insert->withAdditionalValues( + $this->buildValuesArrayForStorage($persistence_factory, $id) + ); + } + + private function buildValuesArrayForStorage( + PersistenceFactory $persistence_factory, + Uuid $id + ): array { + return [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->gap->getAnswerInputId()->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->selected_answer_option?->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->text + ) + ]; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/Factory.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/Factory.php new file mode 100644 index 000000000000..c5d46e33f2b5 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Response/Factory.php @@ -0,0 +1,158 @@ +getDefinition() + ->getTableDefinitions(); + + if ($query === null) { + return new AnswerForm( + $table_definitions, + $response_id, + $answer_form_properties->getAnswerFormId() + ); + } + + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $query->getTableNameBuilder( + $table_definitions->getTableSubNameSpace() + ), + AnswerFormSpecificTableTypes::Responses + ), + $query->getRefinery()->custom()->transformation( + fn (array $vs): AnswerForm => new AnswerForm( + $table_definitions, + $response_id, + $answer_form_properties->getAnswerFormId(), + $this->retrieveAnswerInputResponsesFromValues( + $answer_form_properties, + $vs + ) + ) + ) + ); + } + + public function fromPost( + Uuid $response_id, + Properties $answer_form_properties, + RequestWrapper $post_wrapper + ): AnswerForm { + return new AnswerForm( + $answer_form_properties + ->getDefinition() + ->getTableDefinitions(), + $response_id, + $answer_form_properties->getAnswerFormId(), + $answer_form_properties->getGaps()->retrieveResponsesFromPost( + $post_wrapper, + $this->uuid_factory + ), + ); + } + + public function fromPreviewData( + Uuid $response_id, + Properties $answer_form_properties, + array $preview_data + ): AnswerForm { + return new AnswerForm( + $answer_form_properties + ->getDefinition() + ->getTableDefinitions(), + $response_id, + $answer_form_properties->getAnswerFormId(), + $answer_form_properties->getGaps()->retrieveResponsesFromPreviewData( + $this->uuid_factory, + $preview_data + ), + ); + } + + public function getBestResponse( + Properties $answer_form_properties, + ): AnswerForm { + return new AnswerForm( + $answer_form_properties + ->getDefinition() + ->getTableDefinitions(), + $this->uuid_factory->uuid4(), + $answer_form_properties->getAnswerFormId(), + $answer_form_properties->getGaps()->getBestResponses(), + ); + } + + private function retrieveAnswerInputResponsesFromValues( + Properties $answer_form_properties, + array $values + ): array { + return array_reduce( + $values, + function (array $c, array $vs) use ($answer_form_properties): array { + $answer_input_id = $this->uuid_factory + ->fromString($vs['answer_input_id']); + + $gap = $answer_form_properties->getGaps()->getGapById( + $answer_input_id + ); + + if ($gap === null) { + return $c; + } + + $c[] = new AnswerInput( + $gap, + $vs['selected_answer_option'] === null + ? null + : $this->uuid_factory + ->fromString($vs['selected_answer_option']), + $vs['text'] + ); + + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/TableDefinitions.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/TableDefinitions.php new file mode 100644 index 000000000000..298f5cdcdd21 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/TableDefinitions.php @@ -0,0 +1,382 @@ +table_name_specifiers; + } + + public function getColumns( + TableNameBuilder $table_names_builder, + TableTypes $table_type, + string $sub_table_identifier = '', + array $columns_to_skip = [] + ): array { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type, + $sub_table_identifier + ); + $column_identifiers = match($table_type) { + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms => self::ANSWER_FORM_TABLE_COLUMNS, + AnswerFormSpecificTableTypes::AnswerInputs => self::ANSWER_INPUTS_TABLE_COLUMNS, + AnswerFormSpecificTableTypes::AnswerOptions => self::ANSWER_OPTIONS_TABLE_COLUMNS, + AnswerFormSpecificTableTypes::Responses => self::RESPONSE_TABLE_COLUMNS, + AnswerFormSpecificTableTypes::Additional => match($sub_table_identifier) { + self::COMBINATION_TABLE_IDENTIFIER => self::COMBINATION_TABLE_COLUMNS, + self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_IDENTIFIER => self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_COLUMNS + } + }; + + return array_map( + fn(string $v): Column => $this->persistence_factory->column( + $table, + $v + ), + array_values( + array_filter( + $column_identifiers, + fn(string $v) => !in_array($v, $columns_to_skip) + ) + ) + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypes $table_type, + string $sub_table_identifier = '' + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type, + $sub_table_identifier + ); + + if ($table_type === AnswerFormSpecificTableTypes::TypeSpecificAnswerForms) { + return $this->persistence_factory->column( + $table, + self::ANSWER_FORM_TABLE_ID_COLUMN + ); + } + + if ($table_type === AnswerFormSpecificTableTypes::Responses) { + return $this->persistence_factory->column( + $table, + self::RESPONSE_TABLE_ID_COLUMN + ); + } + + if ($sub_table_identifier === self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_IDENTIFIER) { + return $this->persistence_factory->column( + $table, + self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_ID_COLUMN + ); + } + + return $this->persistence_factory->column( + $table, + self::ID_COLUMN + ); + } + + public function getForeignKeyColumn( + TableNameBuilder $table_names_builder, + TableTypes $table_type, + string $sub_table_identifier = '' + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type, + $sub_table_identifier + ); + + return match($table_type) { + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms => $this->persistence_factory->column( + $table, + self::ANSWER_FORM_TABLE_FOREIGN_KEY_COLUMN + ), + AnswerFormSpecificTableTypes::AnswerInputs => $this->persistence_factory->column( + $table, + self::ANSWER_INPUTS_TABLE_FOREIGN_KEY_COLUMN + ), + AnswerFormSpecificTableTypes::AnswerOptions => $this->persistence_factory->column( + $table, + self::ANSWER_OPTIONS_TABLE_FOREIGN_KEY_COLUMN + ), + AnswerFormSpecificTableTypes::Responses => $this->persistence_factory->column( + $table, + self::RESPONSE_TABLE_FOREIGN_KEY_COLUMN + ), + AnswerFormSpecificTableTypes::Additional => $this->persistence_factory->column( + $table, + $sub_table_identifier === self::COMBINATION_TABLE_IDENTIFIER + ? self::COMBINATION_TABLE_FOREIGN_KEY_COLUMN + : self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_FOREIGN_KEY_COLUMN + ) + }; + } + + #[\Override] + public function completeQuestionQuery( + Query $query, + ?Column $answer_form_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder( + $this->getTableSubNameSpace() + ); + + $combinations_id_column = $this->getIdColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + self::COMBINATION_TABLE_IDENTIFIER + ); + + return $query->withAdditionalJoin( + $this->persistence_factory->join( + $answer_form_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ), + JoinType::Left + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $answer_form_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerInputs + ), + JoinType::Left + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerInputs + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $this->getIdColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerInputs + ), + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerOptions + ), + JoinType::Left + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $this->getIdColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerInputs + ) + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerOptions + ) + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + AnswerFormSpecificTableTypes::AnswerOptions + ), + self::ANSWER_OPTIONS_TABLE_ADDITIONAL_ORDER_COLUMN + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $answer_form_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + self::COMBINATION_TABLE_IDENTIFIER + ), + JoinType::Left + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + self::COMBINATION_TABLE_IDENTIFIER + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $combinations_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_IDENTIFIER + ), + JoinType::Left + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Additional, + self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_IDENTIFIER + ) + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $combinations_id_column + ) + ); + } + + #[\Override] + public function completeResponseQuery( + Query $query, + ?Column $base_table_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder( + $this->getTableSubNameSpace() + ); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + AnswerFormSpecificTableTypes::Responses + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $base_table_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + AnswerFormSpecificTableTypes::Responses + ), + JoinType::Left + ) + ); + } + + public function getCombinationsTableIdentifier(): string + { + return self::COMBINATION_TABLE_IDENTIFIER; + } + + public function getCombinationToAnswerOptionsTableIdentifier(): string + { + return self::COMBINATION_TO_ANSWER_OPTIONS_TABLE_IDENTIFIER; + } +} diff --git a/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Views/Edit.php b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Views/Edit.php new file mode 100644 index 000000000000..582affb3d234 --- /dev/null +++ b/components/ILIAS/Questions/src/AnswerFormTypes/Cloze/Views/Edit.php @@ -0,0 +1,339 @@ +getSubAction(); + + return match($sub_action) { + '' => $this->startEditing($environment), + self::SUB_ACTION_PROCESS_BASIC_PROPERTIES => $this->processBasicEditingForm( + $environment + ), + default => $this->forwardCmdToEditGaps( + $environment + ) + }; + } + + #[\Override] + public function edit( + Environment $environment + ): EditOverview|EditForm|Async|ForImmediateStorage|Properties { + $sub_action = $environment->getSubAction(); + + $combinations = $environment->getAnswerFormProperties()->getCombinations(); + if ($environment->isMarkingRequired() + && $combinations->areCombinationsEnabled()) { + $combinations->getEditView()->addCombinationsSubTab($environment); + } + + if ($sub_action === '') { + return $environment->getAnswerFormProperties()->completeEditOverview( + $environment, + $environment->getPresentationFactory()->getEditOverview( + $environment, + $environment->withSubActionParameter(self::SUB_ACTION_EDIT_BASIC_PROPERTIES) + ->withFormStartSubActionParameter(self::SUB_ACTION_EDIT_BASIC_PROPERTIES) + ->getUrlBuilder() + ) + ); + } + + $environment->setEditAnswerFormBackTarget(); + + return match ($sub_action) { + self::SUB_ACTION_EDIT_BASIC_PROPERTIES => $this->startEditing($environment), + self::SUB_ACTION_ADD_LEGACY_TEXT_BASIC_PROPERTIES => + $this->addLegacyTextToBasicProperties($environment), + self::SUB_ACTION_CONFIRMED_GAP_REMOVAL, + self::SUB_ACTION_PROCESS_BASIC_PROPERTIES => $this->processBasicEditingForm( + $environment->withPreservedTableRowIdsParameter() + ), + default => $this->forwardCmdToEditGaps( + $environment + ->withPreservedTableRowIdsParameter() + ->withPreservedFormStartSubActionParameter() + ) + }; + } + + #[\Override] + public function other( + Environment $environment + ): Async|Viewable|Properties { + $from_other = $environment + ->getAnswerFormProperties() + ->getCombinations()->getEditView()->show($environment); + + if ($from_other === null) { + return $this->edit( + $environment->withDefaultSubAction() + ); + } + + return $from_other; + } + + #[\Override] + public function backToLastEditCommand( + Environment $environment + ): EditForm { + return $this->edit_gaps->do( + $environment, + EditGaps::SUB_ACTION_BACK_TO_SET_ANSWER_OPTIONS + ); + } + + private function startEditing( + Environment $environment + ): EditForm { + $input_builder = $this->buildInputsBuilderForBasicInputs( + $environment, + false + ); + $input_builder->resetCarry(); + + return $this->buildBasicEditingForm( + $environment, + $input_builder, + false + ); + } + + private function forwardCmdToEditGaps( + Environment $environment + ): EditForm|Async|Properties { + $processed_form = $this->edit_gaps->do( + $environment, + $environment->getSubAction() + ); + if (is_string($processed_form)) { + $inputs_builder = $this->buildInputsBuilderForBasicInputs( + $environment, + false, + $processed_form + ); + + $inputs_builder->persistCarry(); + + return $this->buildBasicEditingForm( + $environment, + $inputs_builder, + false + ); + } + + return $processed_form; + } + + private function buildBasicEditingForm( + Environment $environment, + InputsBuilderSession $inputs_builder, + bool $add_legacy_cloze_text_to_input + ): EditForm { + $editing_form = $this->buildEditFormForBasicInputs( + $environment, + $inputs_builder + ); + + /** @var \ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Properties $properties */ + $properties = $environment->getAnswerFormProperties(); + if (!$add_legacy_cloze_text_to_input + && $properties->getLegacyClozeText() !== '' + && $properties->getClozeText()->getRawRepresentation() === '') { + return $editing_form->withInsertLegacyTextsButton( + $environment->withSubActionParameter( + self::SUB_ACTION_ADD_LEGACY_TEXT_BASIC_PROPERTIES + )->getUrlBuilder() + ); + } + + return $editing_form; + } + + private function addLegacyTextToBasicProperties( + Environment $environment + ): EditForm { + $inputs_builder = $this->buildInputsBuilderForBasicInputs( + $environment, + true + ); + + $inputs_builder->persistCarry(); + + return $this->buildBasicEditingForm( + $environment, + $inputs_builder, + true + ); + } + + private function processBasicEditingForm( + Environment $environment + ): EditForm|Async|ForImmediateStorage|Properties { + $inputs_builder = $this->buildInputsBuilderForBasicInputs( + $environment, + false, + ); + + $form = $this->buildBasicEditingForm( + $environment, + $inputs_builder, + false + )->withRequest($environment->getHttpServices()->request()); + + /** @var \ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Properties $data */ + $data = $form->getData(); + if ($data === null) { + $inputs_builder->persistCarry(); + return $form; + } + + $new_gaps = $data->getGaps(); + $old_gaps = $environment->getAnswerFormProperties()->getGaps(); + + if ($environment->getSubAction() !== self::SUB_ACTION_CONFIRMED_GAP_REMOVAL) { + $removed_gaps = $new_gaps->getRemovedGaps($old_gaps); + if ($removed_gaps !== []) { + return $form->withConfirmation( + $this->buildRemovedGapsConfirmation( + $environment, + $removed_gaps + ) + ); + } + } + + if ($new_gaps->getAddedGaps($old_gaps) === []) { + return new ForImmediateStorage($data); + } + + return $this->edit_gaps->do( + $environment->withAnswerFormProperties( + $data->withGaps( + $data->getGaps()->withMarkedIncompleteGaps() + ) + )->withPreservedFormStartSubActionParameter() + ); + } + + private function buildEditFormForBasicInputs( + Environment $environment, + InputsBuilderSession $inputs_builder + ): EditForm { + return $environment->getPresentationFactory()->getEditForm( + $inputs_builder, + $environment + ->withSubActionParameter(self::SUB_ACTION_PROCESS_BASIC_PROPERTIES) + ->withPreservedFormStartSubActionParameter() + ->getUrlBuilder(), + null + ); + } + + private function buildInputsBuilderForBasicInputs( + Environment $environment, + bool $add_legacy_cloze_text_to_input, + ?string $carry = null + ): InputsBuilderSession { + $inputs_builder = $environment->getPresentationFactory() + ->getSessionBasedInputsBuilder( + $environment->getRefinery()->custom()->transformation( + fn(?string $carry): Section => $this->properties_factory + ->fromCarry( + $environment->getAnswerFormProperties(), + $carry + )->buildBasicEditingInputs( + $environment, + $this->properties_factory, + $this->cloze_text_factory, + $add_legacy_cloze_text_to_input + ) + ) + ); + + if ($carry === null) { + return $inputs_builder; + } + + return $inputs_builder->withCarry($carry); + } + + /** + * @param array<\ILIAS\Questions\AnswerFormTypes\Cloze\Properties\Gaps\Gap> $removed_gaps + */ + private function buildRemovedGapsConfirmation( + Environment $environment, + array $removed_gaps + ): InterruptiveModal { + return $environment->getUIFactory()->modal()->interruptive( + $environment->getLanguage()->txt('confirm'), + $environment->getLanguage()->txt('confirm_remove_gaps'), + $environment->withSubActionParameter( + self::SUB_ACTION_CONFIRMED_GAP_REMOVAL + )->getUrlBuilder()->buildURI()->__toString() + )->withAffectedItems( + array_map( + fn(Gap $v): InterruptiveItem => $environment->getUIFactory() + ->modal()->interruptiveItem()->standard( + $v->getAnswerInputId()->toString(), + $v->buildShortenedGapName() + ), + $removed_gaps + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/Attempt/AdditionalAttemptData.php b/components/ILIAS/Questions/src/Attempt/AdditionalAttemptData.php new file mode 100644 index 000000000000..ff7fbbea58a9 --- /dev/null +++ b/components/ILIAS/Questions/src/Attempt/AdditionalAttemptData.php @@ -0,0 +1,30 @@ + + */ + private array $responses = []; + + public function __construct( + private readonly Uuid $identifier, + private readonly int $shuffle_questions_seed, + private array $additional_data = [] + ) { + } + + public function getId(): Uuid + { + return $this->identifier; + } + + public function getShuffleQuestionsSeed(): GivenSeed + { + return new GivenSeed($this->shuffle_questions_seed); + } + + public function getAdditionalDataFor( + Uuid $parent_id + ): ?string { + if (!isset($this->additional_data[$parent_id->toString()])) { + return null; + } + return $this->additional_data[$parent_id->toString()]; + } + + public function withAdditionalData( + Uuid $parent_id, + string $data + ): self { + if (isset($this->additional_data[$parent_id->toString()])) { + throw new InvalidArgumentException( + 'This is a storage for data that stays constant accross the test run.' + . 'Data cannot be changed one it is set.' + ); + } + + $clone = clone $this; + $clone->additional_data[$parent_id->toString()] = $data; + return $clone; + } + + public function getResponseForQuestion( + Uuid $question_id + ): ?Response { + return $this->responses[$question_id->toString()] ?? null; + } + + public function withResponse( + Response $response + ): self { + $clone = clone $this; + $clone->responses[$response->getQuestionId()->toString()] = $response; + return $clone; + } + + public function basicDataToStorage( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): Insert { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + TableTypes::AttemptData + ), + [ + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $this->identifier->toString() + ), + $persistence_factory->value( + \ilDBConstants::T_INTEGER, + $this->shuffle_questions_seed + ) + ] + ); + } + + public function additionalDataToStorage( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder + ): ?Insert { + return array_reduce( + array_keys($this->additional_data), + fn(?Insert $c, string $v): Insert + => $this->buildAdditionalDataInsert( + $persistence_factory, + $table_definitions, + $table_names_builder, + $c, + $v + ) + ); + } + + public function toPreviewStorage(): string + { + return json_encode( + [ + self::KEY_ADDITONAL_DATA => $this->additional_data, + self::KEY_RESPONSES => array_map( + fn(Response $v): array => $v->toPreviewStorage(), + $this->responses + ) + ] + ); + } + + private function buildAdditionalDataInsert( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + ?Insert $insert, + string $parent_id + ): Insert { + if ($insert === null) { + return $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + TableTypes::AdditionalAttemptData + ), + $this->buildAdditionalDataValuesArray( + $persistence_factory, + $parent_id + ) + ); + } + + return $insert->withAdditionalValues( + $this->buildAdditionalDataValuesArray( + $persistence_factory, + $parent_id + ) + ); + } + + private function buildAdditionalDataValuesArray( + PersistenceFactory $persistence_factory, + string $parent_id + ): array { + return [ + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $this->identifier->toString() + ), + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $parent_id + ), + $persistence_factory->value( + \ilDBConstants::T_TEXT, + $this->additional_data[$parent_id] + ) + ]; + } +} diff --git a/components/ILIAS/Questions/src/Attempt/Repository.php b/components/ILIAS/Questions/src/Attempt/Repository.php new file mode 100644 index 000000000000..52333a04ec99 --- /dev/null +++ b/components/ILIAS/Questions/src/Attempt/Repository.php @@ -0,0 +1,432 @@ +table_names_builder = new TableNameBuilder( + QuestionRepository::COMPONENT_NAMESPACE, + null + ); + } + + /** + * @param array $questions + * @throws InvalidArgumentException + */ + public function getAttemptFor( + ?Uuid $attempt_id, + array $questions + ): Attempt { + if ($attempt_id === null) { + $attempt = $this->getNewAttempt($questions); + $this->storeAttempt($attempt); + return $attempt; + } + + $base_table_id_column = $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::Responses + ); + + $database_values = array_reduce( + $questions, + fn(Query $c, Question $v): Query => $v->completeResponseQuery( + $c, + $base_table_id_column + ), + $this->buildQuery($attempt_id) + )->getRecords() + ->current(); + + if ($database_values === null) { + throw new \InvalidArgumentException('No Attempt With Given Identifier'); + } + + return array_reduce( + $questions, + fn(Attempt $c, Question $v): Attempt => $c->withResponse( + $this->retrieveCurrentResponseFromQuery( + $v, + $c->getId(), + $database_values + ) + ), + $this->retrieveAttemptFromQuery( + $attempt_id, + $database_values, + $this->retriveAdditionalDataFromQuery( + $database_values + ) + ) + ); + } + + public function getNewResponseFor( + Uuid $question_id, + Uuid $attempt_id + ): Response { + return new Response( + $this->uuid_factory->uuid4(), + $question_id, + $attempt_id, + new \DateTimeImmutable('@' . time()) + ); + } + + public function storeResponse( + Response $response + ): void { + $response->toStorage( + $this->persistence_factory, + $this->table_definitions, + $this->table_names_builder, + ManipulationType::Create, + new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ) + )->run(); + } + + public function deleteResponsesFor( + Uuid $attempt_id, + Question $question + ): void { + $manipulate = new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ); + foreach ($this->getAllResponsesFor($attempt_id, $question) as $response) { + $manipulate = $response->toDelete( + $this->persistence_factory, + $this->table_definitions, + $this->table_names_builder, + $manipulate + ); + } + + $manipulate->run(); + } + + public function getAttemptFromPreviewData( + Question $question, + string $preview_data + ): ?Attempt { + $data_array = json_decode($preview_data, true); + + if (!is_array($data_array) || $data_array === []) { + return $this->getNewAttempt([$question]); + } + + $response_id = $this->uuid_factory->uuid4(); + + return array_reduce( + $data_array[Attempt::KEY_RESPONSES] ?? [], + fn(Attempt $c, array $v): Attempt => $c->withResponse( + new Response( + $response_id, + $question->getId(), + $this->uuid_factory->uuid4(), + new \DateTimeImmutable( + 'now', + new \DateTimeZone('UTC') + ), + $v[Response::KEY_POINTS] ?? 0.0, + $question->retrieveAnswerFormResponsesFromPreviewData( + $response_id, + $v[Response::KEY_RESPONSES] ?? [] + ) + ) + ), + new Attempt( + $this->uuid_factory->uuid4(), + 0, + $data_array[Attempt::KEY_ADDITONAL_DATA] ?? [] + ) + ); + } + + private function storeAttempt( + Attempt $attempt + ): void { + $manipulate = (new Manipulate( + $this->db, + QuestionRepository::COMPONENT_NAMESPACE + ))->withAdditionalStatement( + $attempt->basicDataToStorage( + $this->persistence_factory, + $this->table_definitions, + $this->table_names_builder + ) + ); + + $additional_data_statement = $attempt->additionalDataToStorage( + $this->persistence_factory, + $this->table_definitions, + $this->table_names_builder + ); + + if ($additional_data_statement !== null) { + $manipulate = $manipulate->withAdditionalStatement( + $additional_data_statement + ); + } + + $manipulate->run(); + } + + /** + * @param array $questions + */ + private function getNewAttempt( + array $questions + ): Attempt { + $attempt = new Attempt( + $this->uuid_factory->uuid4(), + (new RandomSeed())->createSeed() + ); + + return array_reduce( + $questions, + fn(Attempt $c, Question $v) => $v->initializeAttemptData($c), + $attempt + ); + } + + private function getAllResponsesFor( + Uuid $attempt_id, + Question $question + ): \Generator { + $base_table_id_column = $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::Responses + ); + + $database_values = $question->completeResponseQuery( + $this->buildQuery($attempt_id), + $base_table_id_column + )->getRecords() + ->current(); + + if ($database_values === null) { + throw new \InvalidArgumentException('No Attempt With Given Identifier'); + } + + return $this->retrieveAllResponsesFromQuery( + $question, + $attempt_id, + $database_values + ); + } + + private function buildQuery( + Uuid $attempt_id + ): Query { + $attempt_data_id_column = $this->table_definitions->getIdColumn( + $this->table_names_builder, + TableTypes::AttemptData + ); + return $this->table_definitions->completeAttemptQuery( + new Query( + $this->db, + $this->refinery, + QuestionRepository::COMPONENT_NAMESPACE, + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::AttemptData + ) + ), + $attempt_data_id_column + )->withAdditionalWhere( + $this->persistence_factory->where( + $attempt_data_id_column, + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $attempt_id->toString() + ) + ) + )->withGroupBy( + $attempt_data_id_column + ); + } + + private function retriveAdditionalDataFromQuery( + Query $query + ): array { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::AdditionalAttemptData + ), + $this->refinery->custom()->transformation( + function (array $vs): array { + return array_reduce( + $vs, + function (array $c, array $v): array { + $c[$v['parent_id']] = $v['data']; + return $c; + }, + [] + ); + } + ) + ); + } + + private function retrieveAttemptFromQuery( + Uuid $attempt_id, + Query $query, + array $additional_seeds + ): Attempt { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::AttemptData + ), + $this->refinery->custom()->transformation( + fn(array $vs): Attempt => new Attempt( + $attempt_id, + $vs[0]['shuffler_seed'], + $additional_seeds + ) + ) + ); + } + + private function retrieveCurrentResponseFromQuery( + Question $question, + Uuid $attempt_id, + Query $query + ): Response { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::Responses + ), + $this->refinery->custom()->transformation( + function ( + array $vs + ) use ( + $question, + $attempt_id, + $query + ): Response { + $question_id_string = $question->getId()->toString(); + + $last_record = array_reduce( + $vs, + fn(array $c, array $v): array + => $v['question_id'] === $question_id_string ? $v : $c, + [] + ); + + if ($last_record === []) { + return $this->getNewResponseFor( + $question->getId(), + $attempt_id + ); + } + + $response_id = $this->uuid_factory + ->fromString($last_record['id']); + + return new Response( + $response_id, + $question->getId(), + $attempt_id, + new \DateTimeImmutable("@{$last_record['create_timestamp']}"), + $last_record['awarded_points'], + $question->retrieveAnswerFormResponsesFromQuery( + $response_id, + $query + ) + ); + } + ) + ); + } + + private function retrieveAllResponsesFromQuery( + Question $question, + Uuid $attempt_id, + Query $query + ): \Generator { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->table_names_builder, + TableTypes::Responses + ), + $this->refinery->custom()->transformation( + function ( + array $vs + ) use ( + $question, + $attempt_id, + $query + ): \Generator { + if ($vs === []) { + return; + } + + foreach ($vs as $v) { + $response_id = $this->uuid_factory + ->fromString($v['id']); + + yield new Response( + $response_id, + $question->getId(), + $attempt_id, + new \DateTimeImmutable("@{$v['create_timestamp']}"), + $v['awarded_points'], + $question->retrieveAnswerFormResponsesFromQuery( + $response_id, + $query + ) + ); + } + } + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/Attempt/Response.php b/components/ILIAS/Questions/src/Attempt/Response.php new file mode 100644 index 000000000000..2eb7acd5f895 --- /dev/null +++ b/components/ILIAS/Questions/src/Attempt/Response.php @@ -0,0 +1,204 @@ + $answer_form_responses + */ + private array $answer_form_responses; + + /** + * @param array $answer_form_responses + */ + public function __construct( + private readonly Uuid $id, + private readonly Uuid $question_id, + private readonly Uuid $attempt_id, + private readonly \DateTimeImmutable $create_date, + private ?float $awarded_points = null, + array $answer_form_responses = [] + ) { + $this->answer_form_responses = array_reduce( + $answer_form_responses, + function (array $c, AnswerFormResponse $v): array { + $c[$v->getAnswerFormId()->toString()] = $v; + return $c; + }, + [] + ); + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getQuestionId(): Uuid + { + return $this->question_id; + } + + public function getAwardedPoints(): ?float + { + return $this->awarded_points; + } + + public function withAwardedPoints( + float $awarded_points + ): self { + $clone = clone $this; + $clone->awarded_points = $awarded_points; + return $clone; + } + + public function getCreateDate(): \DateTimeImmutable + { + return $this->create_date; + } + + public function getAnswerFormResponse( + Uuid $answer_form_id + ): ?AnswerFormResponse { + return $this->answer_form_responses[$answer_form_id->toString()] ?? null; + } + + public function withAnswerFormResponse( + AnswerFormResponse $response + ): self { + $clone = clone $this; + $clone->answer_form_responses[$response->getAnswerFormId()->toString()] = $response; + return $clone; + } + + public function toPreviewStorage(): array + { + return [ + self::KEY_POINTS => $this->awarded_points, + self::KEY_RESPONSES => array_map( + fn(AnswerFormResponse $v): array => $v->toPreviewStorage(), + $this->answer_form_responses + ) + ]; + } + + public function toStorage( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + return array_reduce( + $this->answer_form_responses, + fn(Manipulate $c, AnswerFormResponse $v): Manipulate + => $v->toStorage( + $persistence_factory, + $manipulation_type, + $c + ), + $manipulate->withAdditionalStatement( + $persistence_factory->insert( + $table_definitions->getColumns( + $table_names_builder, + TableTypes::Responses + ), + $this->buildValuesArrayForStorage($persistence_factory) + ) + ) + ); + } + + public function toDelete( + PersistenceFactory $persistence_factory, + TableDefinitions $table_definitions, + TableNameBuilder $table_names_builder, + Manipulate $manipulate + ): Manipulate { + return array_reduce( + $this->answer_form_responses, + fn(Manipulate $c, AnswerFormResponse $v): Manipulate + => $v->toDelete( + $persistence_factory, + $c + ), + $manipulate->withAdditionalStatement( + $persistence_factory->delete( + $persistence_factory->table( + $table_names_builder, + TableTypes::Responses + ), + [ + $persistence_factory->where( + $table_definitions->getIdColumn( + $table_names_builder, + TableTypes::Responses + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->id->toString() + ) + ) + ] + ) + ) + ); + } + + private function buildValuesArrayForStorage( + PersistenceFactory $persistence_factory + ): array { + return [ + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->attempt_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_TEXT, + $this->question_id->toString() + ), + $persistence_factory->value( + FieldDefinition::T_FLOAT, + $this->awarded_points + ), + $persistence_factory->value( + FieldDefinition::T_INTEGER, + $this->create_date->getTimestamp() + ) + ]; + } +} diff --git a/components/ILIAS/Questions/src/Attempt/TableDefinitions.php b/components/ILIAS/Questions/src/Attempt/TableDefinitions.php new file mode 100644 index 000000000000..f60fa886fa7e --- /dev/null +++ b/components/ILIAS/Questions/src/Attempt/TableDefinitions.php @@ -0,0 +1,203 @@ +persistence_factory->table( + $table_names_builder, + $table_type + ); + + return array_map( + fn(string $v): Column => $this->persistence_factory->column( + $table, + $v + ), + match($table_type) { + TableTypes::AttemptData => self::ATTEMPT_DATA_TABLE_COLUMNS, + TableTypes::AdditionalAttemptData => self::ADDITIONAL_ATTEMPT_DATA_TABLE_COLUMNS, + TableTypes::Responses => self::RESPONSES_TABLE_COLUMNS + } + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): ?Column { + return match($table_type) { + TableTypes::AttemptData, + TableTypes::Responses => $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + self::ID_COLUMN + ), + default => null + }; + } + + public function getForeignKeyColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): ?Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type + ); + + return match($table_type) { + TableTypes::AdditionalAttemptData => $this->persistence_factory->column( + $table, + self::ADDITIONAL_ATTEMPT_DATA_TABLE_FOREIGN_KEY_COLUMN + ), + TableTypes::Responses => $this->persistence_factory->column( + $table, + self::RESPONSES_TABLE_PRIMARY_FOREIGN_KEY_COLUMN + ), + default => null + }; + } + + public function completeAttemptQuery( + Query $query, + ?Column $base_table_id_column + ): Query { + $table_names_builder = $query->getTableNameBuilder(null); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::AttemptData + ) + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::AdditionalAttemptData + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $base_table_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + TableTypes::AdditionalAttemptData + ), + JoinType::Left + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::Responses + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $base_table_id_column, + $this->getForeignKeyColumn( + $table_names_builder, + TableTypes::Responses + ), + JoinType::Left + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $base_table_id_column + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + TableTypes::Responses + ), + self::RESPONSES_TABLE_SECONDARY_FOREIGN_KEY_COLUMN + ) + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + TableTypes::Responses + ), + self::RESPONSES_TABLE_ADDITIONAL_ORDERING_COLUMN + ), + OrderDirection::Asc + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/Attempt/TableTypes.php b/components/ILIAS/Questions/src/Attempt/TableTypes.php new file mode 100644 index 000000000000..968ad7c793ef --- /dev/null +++ b/components/ILIAS/Questions/src/Attempt/TableTypes.php @@ -0,0 +1,30 @@ +lng, + $this->refinery, + $this->ui_factory, + $this->http, + $this->questions_repository, + $this->attempt_repository, + $this->capabilities_factory, + $required_capabilities_class_names, + $owner_obj_id + ); + } + + #[\Override] + public function getEditView( + array $required_capabilities_class_names, + int $owner_obj_id + ): Edit { + return new Edit( + $this->lng, + $this->current_user, + $this->refinery, + $this->ui_factory, + $this->ui_renderer, + $this->global_screen, + $this->global_tpl, + $this->content_style, + $this->ctrl, + $this->http, + $this->tabs_gui, + $this->ui_services, + $this->uuid_factory, + $this->configuration_repository, + $this->answer_form_factory, + $this->questions_repository, + $this->attempt_repository, + $this->layout_factory, + $this->capabilities_factory, + $required_capabilities_class_names, + $owner_obj_id + ); + } +} diff --git a/components/ILIAS/Questions/src/Definitions/Clonable.php b/components/ILIAS/Questions/src/Definitions/Clonable.php new file mode 100644 index 000000000000..1fde6df69cdd --- /dev/null +++ b/components/ILIAS/Questions/src/Definitions/Clonable.php @@ -0,0 +1,31 @@ + $lng->txt('in_range'), + self::OutOfRange => $lng->txt('out_of_range'), + self::BelowRange => $lng->txt('below_range'), + self::AboveRange => $lng->txt('above_range') + }; + } +} diff --git a/components/ILIAS/Questions/src/Definitions/TextMatchingOptions.php b/components/ILIAS/Questions/src/Definitions/TextMatchingOptions.php new file mode 100644 index 000000000000..c4c76919e765 --- /dev/null +++ b/components/ILIAS/Questions/src/Definitions/TextMatchingOptions.php @@ -0,0 +1,56 @@ + $lng->txt("cloze_textgap_{$this->value}"), + default => sprintf($lng->txt('cloze_textgap_levenshtein_of'), $this->value) + }; + } + + public static function buildOptionsList( + Language $lng + ): array { + return array_reduce( + self::cases(), + function (array $c, self $v) use ($lng): array { + $c[$v->value] = $v->getLabel($lng); + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Column.php b/components/ILIAS/Questions/src/Persistence/Column.php new file mode 100644 index 000000000000..63a1aa110f31 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Column.php @@ -0,0 +1,50 @@ +table->getName(); + } + + public function getColumnAlias(): string + { + return "{$this->table->getName()}_{$this->identifier}"; + } + + public function getColumnString(): string + { + return "{$this->table->getName()}.{$this->identifier}"; + } + + public function getAliasedColumnString(): string + { + return "{$this->table->getName()}.{$this->identifier} {$this->getColumnAlias()}"; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Delete.php b/components/ILIAS/Questions/src/Persistence/Delete.php new file mode 100644 index 000000000000..5bf813a4ccae --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Delete.php @@ -0,0 +1,73 @@ + $where + */ + public function __construct( + private readonly Table $table, + private readonly array $where + ) { + } + + public function getTableToLock(): string + { + return $this->table->getName(); + } + + public function toManipulateString( + \ilDBInterface $db + ): string { + return "DELETE FROM {$this->table->getName()}" . PHP_EOL + . $this->buildWhereString($db); + } + + private function buildWhereString( + \ilDBInterface $db + ): string { + $values = []; + return sprintf( + array_reduce( + $this->where, + function (?string $c, Where $v) use ($db, &$values): string { + $quoted_value = $v->getRight()->getQuotedValue($db); + if (is_array($quoted_value)) { + $values = [ + ...$values, + ...array_values($quoted_value) + ]; + } else { + $values[] = $quoted_value; + } + + if ($c === null) { + return "WHERE {$v->toSql()}" . PHP_EOL; + } + + return "{$c}{$v->getLogicalOperator()->value} {$v->toSql()}" . PHP_EOL; + } + ) ?? '', + ...$values + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Factory.php b/components/ILIAS/Questions/src/Persistence/Factory.php new file mode 100644 index 000000000000..f2cf8d805a4b --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Factory.php @@ -0,0 +1,125 @@ + $columns + * @param array<\ILIAS\Questions\Persistence\Value> $values + */ + public function insert( + array $columns, + array $values + ): Insert { + return new Insert($columns, $values); + } + + /** + * @param array<\ILIAS\Questions\Persistence\Column> $columns + * @param array<\ILIAS\Questions\Persistence\Value> $values + */ + public function replace( + array $columns, + array $values + ): Replace { + return new Replace($columns, $values); + } + + /** + * @param array<\ILIAS\Questions\Persistence\Column> $columns + * @param array<\ILIAS\Questions\Persistence\Value> $values + * @param array<\ILIAS\Questions\Persistence\Where> $where + */ + public function update( + array $columns, + array $values, + array $where + ): Update { + return new Update($columns, $values, $where); + } + + /** + * @param array<\ILIAS\Questions\Persistence\Where> $where + */ + public function delete( + Table $table, + array $where + ): Delete { + return new Delete($table, $where); + } + + public function table( + TableNameBuilder $table_names_builder, + TableTypes $table, + string $sub_table_identifier = '' + ): Table { + return new Table($table_names_builder, $table, $sub_table_identifier); + } + + public function column( + Table $table, + string $identifier + ): Column { + return new Column($table, $identifier); + } + + /** + * @param array<\ILIAS\Questions\Persistence\Column> $columns + */ + public function select( + array $columns + ): Select { + return new Select($columns); + } + + public function join( + Column $left, + Column $right, + JoinType $type = JoinType::Inner + ): Join { + return new Join($left, $right, $type); + } + + public function where( + Column $left, + Value $right, + Operator $comparison = Operator::Equal, + Junctor $junctor = Junctor::Conjunction, + bool $negate = false + ): Where { + return new Where($left, $right, $comparison, $junctor, $negate); + } + + public function order( + Column $column, + OrderDirection $direction = OrderDirection::Asc + ): Order { + return new Order($column, $direction); + } + + public function value( + string $type, + null|string|int|float|array $value + ): Value { + return new Value($type, $value); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Insert.php b/components/ILIAS/Questions/src/Persistence/Insert.php new file mode 100644 index 000000000000..bccf22ee793d --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Insert.php @@ -0,0 +1,114 @@ + $columns + * @param array<\ILIAS\Questions\Persistence\Value> $values + */ + public function __construct( + protected readonly array $columns, + array $values + ) { + if ($columns === [] || count($columns) !== count($values)) { + throw new \InvalidArgumentException( + "There MUST be at least one Column and the same amount of Values as there are Columns." + ); + } + + $table_name = $columns[0]->getTableName(); + foreach ($columns as $column) { + if ($column->getTableName() !== $table_name) { + throw new \InvalidArgumentException( + "All Columns MUST belong to the same Table." + ); + } + } + + $this->value_sets[] = $values; + } + + /** + * @param array<\ILIAS\Questions\Persistence\Value> $values + */ + public function withAdditionalValues( + array $values + ): self { + if (count($values) !== count($this->columns)) { + throw new \InvalidArgumentException( + "There MUST be the same amount of Values as there are Columns." + ); + } + + $clone = clone $this; + $clone->value_sets[] = $values; + return $clone; + } + + public function getTableToLock(): string + { + return $this->columns[0]->getTableName(); + } + + public function toManipulateString( + \ilDBInterface $db + ): string { + return "INSERT INTO {$this->columns[0]->getTableName()}" . PHP_EOL + . $this->buildColumnsString() . PHP_EOL + . $this->buildValuesString($db); + } + + protected function buildColumnsString(): string + { + return '(' + . implode( + ', ', + array_map( + fn(Column $v): string => $v->getColumnString(), + $this->columns + ) + ) . ')'; + } + + protected function buildValuesString( + \ilDBInterface $db + ): string { + $return = []; + foreach ($this->value_sets as $values) { + $return[] = '(' . implode( + ', ', + array_map( + fn(Value $v): string => $v->getQuotedValue($db), + $values + ) + ) . ')'; + } + + return 'VALUES ' . implode( + ',' . PHP_EOL, + $return + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Join.php b/components/ILIAS/Questions/src/Persistence/Join.php new file mode 100644 index 000000000000..63e13042ff96 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Join.php @@ -0,0 +1,37 @@ +type->value} JOIN {$this->new->getTableName()} " + . "ON {$this->existing->getColumnString()} = {$this->new->getColumnString()}"; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/JoinType.php b/components/ILIAS/Questions/src/Persistence/JoinType.php new file mode 100644 index 000000000000..3a7d11732407 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/JoinType.php @@ -0,0 +1,27 @@ +component_name_space, + $table_sub_name_space + ); + } + + public function withAdditionalStatement( + Insert|Update|Replace|Delete $statement + ): self { + $clone = clone $this; + $clone->statements[] = $statement; + return $clone; + } + + public function run(): void + { + if ($this->statements === []) { + return; + } + + $atom_query = $this->db->buildAtomQuery(); + + $manipulates = []; + $locked_tables = []; + foreach ($this->statements as $statement) { + $table_to_lock = $statement->getTableToLock(); + if (!in_array($table_to_lock, $locked_tables)) { + $atom_query->addTableLock($table_to_lock); + $locked_tables[] = $table_to_lock; + } + $manipulates[] = $statement->toManipulateString($this->db); + } + $atom_query->addQueryCallable( + function (\ilDBInterface $db) use ($manipulates): void { + foreach ($manipulates as $manipulate) { + $db->manipulate($manipulate); + } + } + ); + $atom_query->run(); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/ManipulationType.php b/components/ILIAS/Questions/src/Persistence/ManipulationType.php new file mode 100644 index 000000000000..8bca6030c258 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/ManipulationType.php @@ -0,0 +1,29 @@ +'; + case Greater = '>'; + case Less = '<'; + case GreaterOrEqual = '>='; + case LessOrEqual = '<='; + case In = 'IN'; + case Like = 'LIKE'; + case Between = 'BETWEEN'; + + public function toSql( + Column $left, + int $nr_of_values + ): string { + $placeholders = '%s'; + for ($i = 1; $i < $nr_of_values; $i++) { + $placeholders .= ', %s'; + } + + return match($this) { + self::In => "{$left->getColumnString()} {$this->value} ({$placeholders})", + self::Between => "{$left->getColumnString()} {$this->value} %s AND %s", + default => "{$left->getColumnString()} {$this->value} %s" + }; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Order.php b/components/ILIAS/Questions/src/Persistence/Order.php new file mode 100644 index 000000000000..b7d73975448e --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Order.php @@ -0,0 +1,35 @@ +column->getColumnString()} {$this->direction->value}"; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/OrderDirection.php b/components/ILIAS/Questions/src/Persistence/OrderDirection.php new file mode 100644 index 000000000000..072b3a6acd97 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/OrderDirection.php @@ -0,0 +1,27 @@ +component_name_space, + $table_sub_name_space + ); + } + + public function getRefinery(): Refinery + { + return $this->refinery; + } + + public function withAdditionalSelect( + Select $select + ): self { + $clone = clone $this; + $clone->select[] = $select; + return $clone; + } + + public function withAdditionalJoin( + Join $join + ): self { + $clone = clone $this; + $clone->joins[] = $join; + return $clone; + } + + public function withAdditionalWhere( + Where $where + ): self { + $clone = clone $this; + $clone->where[] = $where; + return $clone; + } + + public function withAdditionalOrder( + Order $order + ): self { + $clone = clone $this; + $clone->order[] = $order; + return $clone; + } + + public function withRange( + Range $range + ): self { + $clone = clone $this; + $clone->range = $range; + return $clone; + } + + public function withGroupBy( + Column $group_by + ): self { + $clone = clone $this; + $clone->group_by = $group_by; + return $clone; + } + + public function getRecords(): \Generator + { + $result = $this->toSql(); + + $this->current_record = [$this->db->fetchAssoc($result)]; + if ($this->current_record[0] === null) { + return null; + } + + if ($this->group_by === null) { + yield $this; + yield from $this->getRecordsUngrouped($result); + return; + } + + yield from $this->getRecordsGrouped( + $result, + $this->group_by->getColumnAlias() + ); + } + + public function retrieveCurrentRecord( + Table $table, + Transformation $transformation + ): mixed { + $table_name = $table->getName(); + $filtered_record = []; + foreach ($this->current_record as $data_set) { + $filtered_dataset = $this->filterDataSetByTable($table_name, $data_set); + if (array_filter($filtered_dataset) !== []) { + $filtered_record[] = $filtered_dataset; + } + } + + return $transformation->transform($filtered_record); + } + + private function toSql(): \ilDBStatement + { + return $this->db->queryF( + 'SELECT ' . implode( + ', ', + array_reduce( + $this->select, + static fn(array $c, Select $v): array => [...$c, ...$v->toColumnsArray()], + [] + ) + ) . " FROM {$this->base_table->getName()}" + . array_reduce( + $this->joins, + static fn(string $c, Join $v): string => $c . PHP_EOL . $v->toSql(), + '' + ) . PHP_EOL + . $this->buildWhereString() + . 'ORDER BY ' . implode( + ', ', + array_reduce( + $this->order, + static function (array $c, Order $v): array { + $c[] = $v->toSql(); + return $c; + }, + [] + ) + ) . PHP_EOL + . ($this->range !== null ? "LIMIT {$this->range->getStart()}, {$this->range->getLength()}" : ''), + $this->binding_types, + $this->binding_values + ); + } + + private function buildWhereString(): string + { + return array_reduce( + $this->where, + function (?string $c, Where $v): string { + $this->addValueToBinding($v->getRight()); + if ($c === null) { + return "WHERE {$v->toSql()}" . PHP_EOL; + } + + return "{$c}{$v->getLogicalOperator()->value} {$v->toSql()}" . PHP_EOL; + } + ) ?? ''; + } + + private function addValueToBinding( + Value $value + ): void { + if (!is_array($value->getValue())) { + $this->binding_types[] = $value->getType(); + $this->binding_values[] = $value->getValue(); + return; + } + + foreach ($value->getValue() as $v) { + $this->binding_types[] = $value->getType(); + $this->binding_values[] = $v; + } + } + + private function getRecordsGrouped( + \ilDBStatement $result, + string $group_by + ): \Generator { + while (($db_record = $this->db->fetchAssoc($result)) !== null) { + if ($db_record[$group_by] === $this->current_record[0][$group_by]) { + $this->current_record[] = $db_record; + continue; + } + yield $this; + $this->current_record = [$db_record]; + } + yield $this; + } + + private function getRecordsUngrouped( + \ilDBStatement $result + ): \Generator { + while (($db_record = $this->db->fetchAssoc($result)) !== null) { + $this->current_record[0] = $db_record; + yield $this; + } + } + + private function filterDataSetByTable( + string $table_name, + array $data_set + ): array { + return array_reduce( + array_keys($data_set), + function (array $c, string $v) use ($table_name, $data_set): array { + if (str_starts_with($v, $table_name)) { + $c[mb_substr($v, mb_strlen($table_name) + 1)] = $data_set[$v]; + } + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Replace.php b/components/ILIAS/Questions/src/Persistence/Replace.php new file mode 100644 index 000000000000..9b34db9f6d8c --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Replace.php @@ -0,0 +1,33 @@ +columns[0]->getTableName()}" . PHP_EOL + . $this->buildColumnsString() . PHP_EOL + . $this->buildValuesString($db); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Select.php b/components/ILIAS/Questions/src/Persistence/Select.php new file mode 100644 index 000000000000..ef4c4ad50258 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Select.php @@ -0,0 +1,40 @@ + $columns + */ +class Select +{ + public function __construct( + private readonly array $columns + ) { + } + + public function toColumnsArray(): array + { + return array_map( + fn(Column $v): string => $v->getAliasedColumnString(), + $this->columns + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Storable.php b/components/ILIAS/Questions/src/Persistence/Storable.php new file mode 100644 index 000000000000..261687414e9d --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Storable.php @@ -0,0 +1,35 @@ +table_names_builder->getTableNameFor( + $this->table, + $this->sub_table_identifier + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/TableNameBuilder.php b/components/ILIAS/Questions/src/Persistence/TableNameBuilder.php new file mode 100644 index 000000000000..e5cd818baa10 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/TableNameBuilder.php @@ -0,0 +1,63 @@ +value === '' && $specifier === '') { + throw \InvalidArgumentException( + 'Identifier cannot be empty if Type->value is empty.' + ); + } + + $base_name = "{$this->component_name_space}"; + if ($table->value !== '') { + $base_name .= "_{$table->value}"; + } + + $additions = ''; + + if ($this->table_sub_name_space !== null) { + $additions = $this->table_sub_name_space->get(); + } + + if ($specifier !== '') { + $additions .= "_{$specifier}"; + } + + if ($additions === '') { + return $base_name; + } + + return "{$base_name}_{$additions}"; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/TableSubNameSpace.php b/components/ILIAS/Questions/src/Persistence/TableSubNameSpace.php new file mode 100644 index 000000000000..fee67a8902f3 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/TableSubNameSpace.php @@ -0,0 +1,51 @@ + 6 + || mb_strlen($sub_name_space) > 8) { + throw new \InvalidArgumentException( + '$vendor cannot be empty or longer than 6, ' + . '$sub_name_space cannot be empty or longer than 8 characters.' + ); + } + } + + public function get(): string + { + if ($this->vendor === 'ILIAS') { + return $this->sub_name_space; + } + return "{$this->vendor}_{$this->sub_name_space}"; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/TableTypes.php b/components/ILIAS/Questions/src/Persistence/TableTypes.php new file mode 100644 index 000000000000..09a938572931 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/TableTypes.php @@ -0,0 +1,25 @@ + $columns + * @param array<\ILIAS\Questions\Persistence\Value> $values + * @param array<\ILIAS\Questions\Persistence\Where> $where + */ + public function __construct( + private readonly array $columns, + private readonly array $values, + private readonly array $where + ) { + if ($columns === [] || count($columns) !== count($values)) { + throw new \InvalidArgumentException( + "There MUST be at least one Column and the same amount of Values as there are Columns." + ); + } + + $table_name = $columns[0]->getTableName(); + foreach ($columns as $column) { + if ($column->getTableName() !== $table_name) { + throw new \InvalidArgumentException( + "All Columns MUST belong to the same Table." + ); + } + } + } + + public function getTableToLock(): string + { + return $this->columns[0]->getTableName(); + } + + public function toManipulateString( + \ilDBInterface $db + ): string { + return "UPDATE {$this->columns[0]->getTableName()}" . PHP_EOL + . $this->buildSetterString($db) . PHP_EOL + . $this->buildWhereString($db); + } + + private function buildSetterString( + \ilDBInterface $db + ): string { + return trim( + array_reduce( + array_keys($this->columns), + fn(string $c, int $v): string => $c + . "{$this->columns[$v]->getColumnString()} = {$this->values[$v]->getQuotedValue($db)},", + 'SET ' + ), + ',' + ); + } + + private function buildWhereString( + \ilDBInterface $db + ): string { + $values = []; + return sprintf( + array_reduce( + $this->where, + function (?string $c, Where $v) use ($db, &$values): string { + $quoted_value = $v->getRight()->getQuotedValue($db); + if (is_array($quoted_value)) { + $values = [ + ...$values, + ...array_values($quoted_value) + ]; + } else { + $values[] = $quoted_value; + } + + if ($c === null) { + return "WHERE {$v->toSql()}" . PHP_EOL; + } + + return "{$c}{$v->getLogicalOperator()->value} {$v->toSql()}" . PHP_EOL; + } + ) ?? '', + ...$values + ); + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Value.php b/components/ILIAS/Questions/src/Persistence/Value.php new file mode 100644 index 000000000000..3ed7a8107435 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Value.php @@ -0,0 +1,68 @@ +type; + } + + public function getValue(): string|int|array + { + return $this->value; + } + + public function getQuotedValue( + \ilDBInterface $db + ): array|string { + if (!is_array($this->value)) { + return $db->quote( + $this->value, + $this->type + ); + } + + return array_map( + fn(mixed $v): string => $db->quote($v, $this->type), + $this->value + ); + } + + public function getNumberOfElements(): int + { + if (is_array($this->value)) { + return count($this->value); + } + + return 1; + } +} diff --git a/components/ILIAS/Questions/src/Persistence/Where.php b/components/ILIAS/Questions/src/Persistence/Where.php new file mode 100644 index 000000000000..c0714bb73224 --- /dev/null +++ b/components/ILIAS/Questions/src/Persistence/Where.php @@ -0,0 +1,52 @@ +negate ? 'NOT ' : '') + . $this->comparison->toSql( + $this->left, + $this->right->getNumberOfElements() + ); + } + + public function getRight(): Value + { + return $this->right; + } + + public function getLogicalOperator(): Junctor + { + return $this->junctor; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Definitions/Actor.php b/components/ILIAS/Questions/src/Presentation/Definitions/Actor.php new file mode 100644 index 000000000000..b77e2ee1b97e --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Definitions/Actor.php @@ -0,0 +1,34 @@ +acquireURLBuilderAndParameters($base_uri); + } + + #[\Override] + public function getHttpServices(): HTTPServices + { + return $this->http; + } + + #[\Override] + public function getLanguage(): Language + { + return $this->lng; + } + + #[\Override] + public function getRefinery(): Refinery + { + return $this->refinery; + } + + #[\Override] + public function getUIFactory(): UIFactory + { + return $this->presentation_factory->getUIFactory(); + } + + #[\Override] + public function setEditAnswerFormBackTarget(): void + { + $this->tabs_gui->clearTargets(); + $this->tabs_gui->setBackTarget( + $this->lng->txt('cancel'), + $this->buildEditAnswerFormBackUrl()->buildURI()->__toString() + ); + } + + #[\Override] + public function addEditAnswerFormSubTab( + string $sub_action, + string $language_variable + ): void { + $this->tabs_gui->addSubTab( + $sub_action, + $this->lng->txt($language_variable), + $this->withSubActionParameter($sub_action) + ->withActionParameter(Edit::ACTION_OTHER_ANSWER_FORM) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ); + } + + #[\Override] + public function activateEditAnswerFormSubTab( + string $sub_action + ): void { + $this->tabs_gui->activateSubTab($sub_action); + } + + #[\Override] + public function getPresentationFactory(): Factory + { + return $this->presentation_factory; + } + + #[\Override] + public function getUrlBuilder(): URLBuilder + { + return $this->url_builder; + } + + #[\Override] + public function withSubActionParameter( + string $sub_action + ): self { + $clone = clone $this; + if ($clone->sub_action_token === null) { + [ + $clone->url_builder, + $clone->sub_action_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_SUB_ACTION + ); + } + $clone->url_builder = $clone->url_builder + ->withParameter($clone->sub_action_token, $sub_action); + return $clone; + } + + #[\Override] + public function withDefaultSubAction(): self + { + $clone = clone $this; + $clone->default_sub_action = true; + return $clone; + } + + #[\Override] + public function getSubAction(): string + { + if ($this->default_sub_action) { + return ''; + } + + $sub_action_token = $this->sub_action_token; + if ($sub_action_token === null) { + [,$sub_action_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_SUB_ACTION + ); + } + + return $this->retrieveStringValueForToken( + $sub_action_token, + self::TOKEN_STRING_SUB_ACTION + ); + } + + #[\Override] + public function getEditability(): Editability + { + return $this->editability; + } + + #[\Override] + public function isMarkingRequired(): bool + { + return $this->required_capabilities->isMarkingRequired(); + } + + #[\Override] + public function getAnswerFormTableActionsForRequiredCapabilities(): array + { + return array_map( + fn(AdditionalFormStepAction $v): TableAction => $v->getAsTableAction( + $this->withActionParameter($v->getIdentifier()) + ), + $this->required_capabilities->getRequiredFormStepActions() + ); + } + + #[\Override] + public function isInCreationContext(): bool + { + return $this->is_in_creation_context; + } + + #[\Override] + public function getAnswerFormId(): ?Uuid + { + if ($this->answer_form_properties !== null) { + return $this->answer_form_properties->getAnswerFormId(); + } + + $answer_form_id_token = $this->answer_form_id_token; + if ($answer_form_id_token === null) { + [,$answer_form_id_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_ANSWER_FORM_ID + ); + } + return $this->http->wrapper()->query()->retrieve( + $answer_form_id_token->getName(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + $this->buildRetrieveUuidClosure() + ), + $this->refinery->always(null) + ]) + ); + } + + #[\Override] + public function getAnswerFormProperties(): ?Properties + { + return $this->answer_form_properties; + } + + #[\Override] + public function withAnswerFormProperties( + Properties $properties + ): self { + $clone = clone $this; + $clone->answer_form_properties = $properties; + return $clone; + } + + #[\Override] + public function getTableRowIdToken(): URLBuilderToken + { + return $this->table_row_token; + } + + /** + * @return list + */ + #[\Override] + public function getTableRowIds(): array + { + if ($this->table_row_ids === null) { + $this->table_row_ids = $this->http->wrapper()->query()->retrieve( + $this->table_row_token->getName(), + $this->refinery->byTrying([ + $this->refinery->kindlyTo()->listOf( + $this->refinery->custom()->transformation( + fn($v): string => $v !== '' + ? $this->refinery->kindlyTo()->string()->transform($v) + : throw new \UnexpectedValueException() + ) + ), + $this->refinery->always([]) + ]) + ); + } + + return $this->table_row_ids; + } + + #[\Override] + public function withPreservedTableRowIdsParameter(): self + { + $clone = clone $this; + $clone->table_row_ids = $clone->getTableRowIds(); + $clone->url_builder = $this->url_builder + ->withParameter($this->table_row_token, $clone->table_row_ids); + return $clone; + } + + #[\Override] + public function redirectTo(URLBuilder $target): void + { + $this->ctrl->redirectToURL( + $target->buildURI()->__toString() + ); + } + + public function withIsInCreationContext( + bool $is_in_creation_context + ): self { + $clone = clone $this; + $clone->is_in_creation_context = $is_in_creation_context; + return $clone; + } + + public function getParentObjId(): int + { + return $this->parent_obj_id; + } + + public function getAction(): string + { + $action_token = $this->action_token; + if ($action_token === null) { + [,$action_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_ACTION + ); + } + return $this->retrieveStringValueForToken($action_token); + } + + public function withActionParameter( + string $action + ): self { + $clone = clone $this; + if ($clone->action_token === null) { + [ + $clone->url_builder, + $clone->action_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_ACTION + ); + } + $clone->url_builder = $clone->url_builder + ->withParameter($clone->action_token, $action); + return $clone; + } + + public function withQuestionIdParameter( + Uuid $question_id + ): self { + $clone = clone $this; + $clone->url_builder = $this->url_builder + ->withParameter($this->question_id_token, $question_id->toString()); + return $clone; + } + + public function withAnswerFormTypeHashParameter( + string $type_hash + ): self { + $clone = clone $this; + if ($clone->type_hash_token === null) { + [ + $clone->url_builder, + $clone->type_hash_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_TYPE_HASH + ); + } + + $clone->url_builder = $clone->url_builder + ->withParameter($clone->type_hash_token, $type_hash); + return $clone; + } + + public function withAnswerFormIdParameter( + Uuid $answer_form_id + ): self { + $clone = clone $this; + if ($clone->answer_form_id_token === null) { + [ + $clone->url_builder, + $clone->answer_form_id_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_ANSWER_FORM_ID + ); + } + $clone->url_builder = $clone->url_builder->withParameter( + $clone->answer_form_id_token, + $answer_form_id->toString() + ); + return $clone; + } + + public function withCreateModeParameter(): self + { + $clone = clone $this; + if ($clone->create_mode_token === null) { + [ + $clone->url_builder, + $clone->create_mode_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_CREATE_MODE + ); + } + + $clone->url_builder = $clone->url_builder + ->withParameter($clone->create_mode_token, '1'); + return $clone; + } + + #[\Override] + public function withFormStartSubActionParameter( + string $sub_action + ): self { + $clone = clone $this; + if ($clone->form_start_sub_action_token === null) { + [ + $clone->url_builder, + $clone->form_start_sub_action_token + ] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_FORM_START_SUB_ACTION + ); + } + + $clone->url_builder = $clone->url_builder + ->withParameter( + $clone->form_start_sub_action_token, + $sub_action + ); + return $clone; + } + + #[\Override] + public function withPreservedFormStartSubActionParameter(): self + { + return $this->withFormStartSubActionParameter( + $this->getFormStartSubAction() + ); + } + + public function getQuestionId(): ?Uuid + { + return $this->http->wrapper()->query()->retrieve( + $this->question_id_token->getName(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + $this->buildRetrieveUuidClosure() + ), + $this->refinery->always(null) + ]) + ); + } + + /** + * This function will either return the QuestionIds from the $_GET parameter + * for row ids OR from an InterruptiveItems $_POST value. + * @return array<\ILIAS\Data\UUID\Uuid>|string|null + */ + public function getQuestionIds(): array|string|null + { + return $this->http->wrapper()->query()->retrieve( + $this->table_row_token->getName(), + $this->refinery->byTrying([ + $this->refinery->custom()->transformation( + fn($v): string => $v === ['ALL_OBJECTS'] + ? 'ALL_OBJECTS' + : throw new \UnexpectedValueException() + ), + $this->refinery->kindlyTo()->listOf( + $this->refinery->custom()->transformation( + $this->buildRetrieveUuidClosure() + ) + ), + $this->refinery->always(null) + ]) + ) ?? $this->http->wrapper()->post()->retrieve( + self::INTERRUPTIVE_ITEMS_KEY, + $this->refinery->kindlyTo()->listOf( + $this->refinery->custom()->transformation( + $this->buildRetrieveUuidClosure() + ) + ), + $this->refinery->always(null) + ); + } + + public function getTypeClassHash(): string + { + $type_hash_token = $this->type_hash_token; + if ($type_hash_token === null) { + [,$type_hash_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_TYPE_HASH + ); + } + return $this->retrieveStringValueForToken($type_hash_token); + } + + public function getFormStartSubAction(): string + { + $form_start_command_token = $this->form_start_sub_action_token; + if ($form_start_command_token === null) { + [,$form_start_command_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_FORM_START_SUB_ACTION + ); + } + return $this->retrieveStringValueForToken($form_start_command_token); + } + + public function isCreateModeSimple(): bool + { + $create_mode_token = $this->create_mode_token; + if ($create_mode_token === null) { + [, $create_mode_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_CREATE_MODE + ); + } + + return $this->http->wrapper()->query()->has( + $create_mode_token->getName() + ); + } + + /** + * + * @param array<\ILIAS\Questions\AnswerForm\Capabilities\Action> $additional_actions + */ + public function setEditAnswerFormTabs( + array $additional_actions + ): void { + $this->tabs_gui->addTab( + self::TAB_ID_ANSWER_FORM, + $this->lng->txt('answer_form'), + $this->withDefaultSubAction()->getUrlBuilder()->buildURI()->__toString() + ); + + foreach ($additional_actions as $action) { + $action->addTab( + $this, + $this->tabs_gui, + $this->lng + ); + } + + $this->tabs_gui->addSubTab( + self::TAB_ID_ANSWER_FORM, + $this->lng->txt('overview'), + $this->withDefaultSubAction()->getUrlBuilder()->buildURI()->__toString() + ); + + $this->tabs_gui->activateTab(self::TAB_ID_ANSWER_FORM); + $this->tabs_gui->activateSubTab(self::TAB_ID_ANSWER_FORM); + } + + public function preserveParametersForPageEditorCmds(): void + { + $this->setQuestionIdParamterForPageEditorCmds($this->getQuestionId()); + } + + public function setParamtersForSimpleCreateCmd( + Uuid $question_id + ): void { + $this->setQuestionIdParamterForPageEditorCmds($question_id); + + $this->ctrl->setParameterByClass( + \QstsQuestionPageGUI::class, + self::PARAMETER_STRING_HIER_ID, + '1' + ); + + [, $create_mode_token] = $this->url_builder->acquireParameter( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_CREATE_MODE + ); + + $this->ctrl->setParameterByClass( + \QstsQuestionPageGUI::class, + $create_mode_token->getName(), + '1' + ); + } + + public function isCreateAndNewAction(): bool + { + return $this->http->wrapper()->query()->has( + $this->buildURLBuilderTokenForCreateAndNew()->getName() + ); + } + + public function buildURLBuilderTokenForCreateAndNew(): URLBuilderToken + { + return new URLBuilderToken( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_CREATE_AND_NEW + ); + } + + private function setQuestionIdParamterForPageEditorCmds( + Uuid $question_id + ): void { + $this->ctrl->setParameterByClass( + \QstsQuestionPageGUI::class, + $this->question_id_token->getName(), + $question_id->toString() + ); + } + + private function buildEditAnswerFormBackUrl(): URLBuilder + { + if (!$this->is_in_creation_context) { + return $this->withDefaultSubAction()->getUrlBuilder(); + } + + if (!$this->isCreateModeSimple()) { + return new URLBuilder( + new URI( + ILIAS_HTTP_PATH . '/' . $this->ctrl->getLinkTargetByClass( + \QstsQuestionPageGUI::class, + 'edit' + ) + ) + ); + } + + return $this->withActionParameter( + Edit::ACTION_DELETE_QUESTIONS + )->withSubActionParameter( + Edit::ACTION_DELETE_QUESTIONS + )->getUrlBuilder()->withParameter( + $this->table_row_token, + [$this->getQuestionId()->toString()] + ); + } + + private function acquireURLBuilderAndParameters( + URI $base_uri + ): void { + [ + $this->url_builder, + $this->table_row_token, + $this->question_id_token + ] = (new URLBuilder($base_uri)) + ->acquireParameters( + self::QUERY_PARAMETER_NAME_SPACE, + self::TOKEN_STRING_TABLE_ROW_ID, + self::TOKEN_STRING_QUESTION_ID + ); + } + + private function retrieveStringValueForToken( + URLBuilderToken $token + ): string { + return $this->http->wrapper()->query()->retrieve( + $token->getName(), + $this->buildStringTrafo() + ); + } + + private function buildStringTrafo(): Transformation + { + return $this->refinery->byTrying([ + $this->refinery->kindlyTo()->string(), + $this->refinery->always('') + ]); + } + + private function buildRetrieveUuidClosure(): \Closure + { + return fn($v): Uuid => is_string($v) + ? $this->uuid_factory->fromString($v) + : throw new \UnexpectedValueException(); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Definitions/Editability.php b/components/ILIAS/Questions/src/Presentation/Definitions/Editability.php new file mode 100644 index 000000000000..f7ca340fb0d8 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Definitions/Editability.php @@ -0,0 +1,28 @@ +storable; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Definitions/HasClientSideRepresentation.php b/components/ILIAS/Questions/src/Presentation/Definitions/HasClientSideRepresentation.php new file mode 100644 index 000000000000..23044ae7c3fd --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Definitions/HasClientSideRepresentation.php @@ -0,0 +1,26 @@ +value + => $column_factory->link($lng->txt('title')), + OverviewTableColumns::AnswerFormTypes->value + => $column_factory->text( + $lng->txt('contained_answer_form_types') + )->withIsOptional(true, true) + ->withIsSortable(false), + ]; + } + + public static function getFilterInputs( + Language $lng, + FieldFactory $field_factory, + array $answer_form_types_array_for_select + ): array { + return [ + self::Title->value => $field_factory->text( + $lng->txt('title') + ), + self::AnswerFormTypes->value => $field_factory->multiSelect( + $lng->txt('contains_answer_form_types'), + $answer_form_types_array_for_select + )->withRequired(true), + ]; + } + + public function getDatabaseColumn( + PersistenceFactory $persistence_factory, + TableNameBuilder $table_names_builder + ): ?Column { + return $persistence_factory->column( + $persistence_factory->table( + $table_names_builder, + match($this) { + self::Title => TableTypes::Questions, + self::AnswerFormTypes => AnswerFormGenericTableTypes::AnswerForms + } + ), + $this->value + ); + } + + public function transformFilterValue( + AnswerFormFactory $answer_form_factory, + mixed $value + ): mixed { + return match($this) { + self::AnswerFormTypes => array_map( + fn(string $v): string => $answer_form_factory + ->getTypeDefinitionFromSelectValue($v)::class, + $value + ), + default => $value + }; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Definitions/ViewConfiguration.php b/components/ILIAS/Questions/src/Presentation/Definitions/ViewConfiguration.php new file mode 100644 index 000000000000..787c44159bc4 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Definitions/ViewConfiguration.php @@ -0,0 +1,65 @@ +interactive; + } + + public function showMarks(): bool + { + return $this->show_marks; + } + + public function showBestResponse(): bool + { + return $this->show_best_response; + } + + public function withShowBestResponse(): self + { + $clone = clone $this; + $clone->interactive = false; + $clone->show_best_response = true; + return $clone; + } + + public function showFeedback(): bool + { + return $this->show_feedback; + } + + public function getViewMode(): ViewMode + { + return $this->view_mode; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/Async.php b/components/ILIAS/Questions/src/Presentation/Layout/Async.php new file mode 100644 index 000000000000..b61cd8c18b9e --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/Async.php @@ -0,0 +1,56 @@ +content) + ? $this->content + : $ui_renderer->renderAsync($this->content); + + $this->http->saveResponse( + $this->http->response()->withBody( + Streams::ofString( + $rendered_content + ) + ) + ); + $this->http->sendResponse(); + $this->http->close(); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/EditForm.php b/components/ILIAS/Questions/src/Presentation/Layout/EditForm.php new file mode 100644 index 000000000000..efe26faeb70a --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/EditForm.php @@ -0,0 +1,208 @@ +form = $this->buildForm( + $inputs, + $default_form_action, + $back_form_action + ); + } + + #[\Override] + public function getUI(): array + { + $content = []; + + if ($this->content_before_form !== null) { + $content[] = $this->content_before_form; + } + + if ($this->confirmation !== null) { + $content[] = $this->confirmation->withOnLoad( + $this->confirmation->getShowSignal() + )->withAdditionalOnLoadCode( + function ($id) { + return "var button = {$id}.querySelector('input[type=\"submit\"]'); " + . "button.addEventListener('click', (e) => {e.preventDefault();" + . 'const form = button.closest("dialog").nextElementSibling;' + . "form.action = '{$this->confirmation->getFormAction()}';" + . 'form.submit();});'; + } + ); + } + + if ($this->insert_legacy_text_button !== null) { + $content[] = $this->insert_legacy_text_button; + } + + $content[] = $this->is_final_step + ? $this->form + : $this->form->withSubmitLabel( + $this->lng->txt('next') + ); + + if ($this->content_after_form !== null) { + $content[] = $this->content_after_form; + } + + return $content; + } + + public function isFinalStep(): bool + { + return $this->is_final_step; + } + + public function withIsFinalStep( + bool $is_final_step + ): self { + $clone = clone $this; + $clone->is_final_step = $is_final_step; + return $clone; + } + + public function withContentBeforeForm( + StandardPanel $content + ): self { + $clone = clone $this; + $clone->content_before_form = $content; + return $clone; + } + + public function withContentAfterForm( + StandardPanel $content + ): self { + $clone = clone $this; + $clone->content_after_form = $content; + return $clone; + } + + public function withConfirmation( + InterruptiveModal $confirmation_modal + ): self { + $clone = clone $this; + $clone->confirmation = $confirmation_modal; + return $clone; + } + + public function withInsertLegacyTextsButton( + URLBuilder $target_builder + ): self { + $clone = clone $this; + $clone->insert_legacy_text_button = $this->ui_factory->messageBox()->info( + $this->lng->txt('insert_legacy_texts_info') + )->withButtons([ + $this->ui_factory->button()->standard( + $this->lng->txt('insert_legacy_texts'), + $target_builder->buildURI()->__toString() + ) + ]); + return $clone; + } + + public function withRequest( + ServerRequestInterface $request + ): self { + $clone = clone $this; + $clone->form = $clone->form->withRequest($request); + return $clone; + } + + public function getData(): mixed + { + $data = $this->form->getData(); + return $data[self::MAIN_SECTION_NAME] ?? null; + } + + public function withAdditionalAction( + URLBuilderToken $parameter_token, + string $parameter_value, + string $label + ): self { + $clone = clone $this; + $clone->form = $this->form->withAdditionalFormAction( + $this->default_form_action->buildURI()->withParameter( + $parameter_token->getName(), + $parameter_value + )->__toString(), + $label + ); + return $clone; + } + + private function buildForm( + Input|InputsBuilder $inputs, + URLBuilder $default_form_action, + ?URLBuilder $back_form_action + ): StandardForm { + if ($inputs instanceof InputsBuilder) { + $inputs = $inputs->getInputs(); + } + $form = $this->ui_factory->input()->container()->form()->standard( + $default_form_action->buildURI()->__toString(), + [ + self::MAIN_SECTION_NAME => $inputs + ] + ); + + if ($back_form_action === null) { + return $form; + } + + return $form->withAdditionalFormAction( + $back_form_action->buildURI()->__toString(), + $this->lng->txt('previous') + ); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/EditOverview.php b/components/ILIAS/Questions/src/Presentation/Layout/EditOverview.php new file mode 100644 index 000000000000..003eed35deab --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/EditOverview.php @@ -0,0 +1,120 @@ + $buttons + */ + private array $buttons = []; + private DataTable|OrderingTable|null $table = null; + + public function __construct( + private readonly Environment $environment, + private readonly URLBuilder $target_to_edit_basic_answer_form_properties + ) { + } + + #[\Override] + public function getUI(): array + { + $ui = [ + $this->buildBasicAnswerFormPanel(), + + ]; + + if ($this->view_control !== null) { + $ui[] = $this->view_control; + } + + $ui_with_buttons = [ + ...$ui, + ...$this->buttons + ]; + + if ($this->table !== null) { + $ui_with_buttons[] = $this->table; + } + + return $ui_with_buttons; + } + + public function withViewControl( + ViewControlMode $view_control + ): self { + $clone = clone $this; + $clone->view_control = $view_control; + return $clone; + } + + public function withAdditionalButton( + StandardButton $button + ): self { + $clone = clone $this; + $clone->buttons[] = $button; + return $clone; + } + + public function withTable( + DataTable|OrderingTable $table + ): self { + $clone = clone $this; + $clone->table = $table; + return $clone; + } + + private function buildBasicAnswerFormPanel(): StandardPanel + { + $content = [ + $this->environment->getUIFactory()->listing()->descriptive( + $this->environment->getAnswerFormProperties() + ->getBasicPropertiesForListing( + $this->environment + ) + ) + ]; + + if ($this->environment->getEditability() === Editability::Full) { + $content[] = $this->environment->getUIFactory()->button()->standard( + $this->environment->getLanguage()->txt('edit_basic_answer_form_properties'), + $this->target_to_edit_basic_answer_form_properties + ->buildURI() + ->__toString() + ); + } + + return $this->environment->getUIFactory()->panel()->standard( + $this->environment->getLanguage()->txt('basic_answer_form_properties'), + $content + ); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/Factory.php b/components/ILIAS/Questions/src/Presentation/Layout/Factory.php new file mode 100644 index 000000000000..aead15450bb7 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/Factory.php @@ -0,0 +1,114 @@ +ui_factory, + $this->lng, + $main_section_inputs, + $default_form_action, + $back_form_action + ); + } + + public function getAsync( + InterruptiveModal|RoundTripModal|MessageBox|State|array|string $content + ): Async { + return new Async( + $this->http, + $content + ); + } + + public function getSessionBasedInputsBuilder( + Transformation $to_inputs + ): InputsBuilderSession { + return new InputsBuilderSession( + $to_inputs + ); + } + + public function getUploadHandler( + Environment $environment, + ResourceStakeholder $stakeholder + ): UploadHandler { + return new UploadHandler( + $this->irss, + $this->temp_filesystem, + $this->upload, + $this->sanitizer, + $stakeholder, + $environment + ); + } + + public function getUIFactory(): UIFactory + { + return $this->ui_factory; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/GlobalScreen/LayoutProvider.php b/components/ILIAS/Questions/src/Presentation/Layout/GlobalScreen/LayoutProvider.php new file mode 100755 index 000000000000..590231b8a9c0 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/GlobalScreen/LayoutProvider.php @@ -0,0 +1,165 @@ +context_collection->main(); + } + + protected function isModeEnabled( + CalledContexts $called_contexts + ): bool { + return $called_contexts->current()->getAdditionalData() + ->is(self::MODE_ENABLED, true); + } + + #[\Override] + public function getBreadCrumbsModification( + CalledContexts $called_contexts + ): ?BreadCrumbsModification { + if (!$this->isModeEnabled($called_contexts)) { + return null; + } + + return $this->globalScreen()->layout()->factory()->breadcrumbs() + ->withModification( + function (?Breadcrumbs $current): ?Breadcrumbs { + return null; + } + )->withPriority(self::MODIFICATION_PRIORITY); + } + + #[\Override] + public function getMainBarModification( + CalledContexts $called_contexts + ): ?MainBarModification { + $mainbar = $this->globalScreen()->layout()->factory()->mainbar(); + + if (!$this->isModeEnabled($called_contexts)) { + return null; + } + + return $mainbar + ->withModification( + $this->buildMainBarModification($called_contexts) + )->withPriority(self::MODIFICATION_PRIORITY); + } + + #[\Override] + public function getMetaBarModification( + CalledContexts $called_contexts + ): ?MetaBarModification { + if (!$this->isModeEnabled($called_contexts)) { + return null; + } + + return $this->globalScreen()->layout()->factory()->metabar() + ->withModification( + function (?MetaBar $current): ?MetaBar { + return null; + } + )->withPriority(self::MODIFICATION_PRIORITY); + } + + #[\Override] + public function getPageBuilderDecorator( + CalledContexts $called_contexts + ): ?PageBuilderModification { + if (!$this->isModeEnabled($called_contexts)) { + return null; + } + + $mode_info = $this->dic['ui.factory']->mainControls()->modeInfo( + $this->dic->language()->txt('edit_questions'), + $called_contexts->current()->getAdditionalData()->get(self::URL_CLOSE_MODE_INFO) + ); + + return $this->factory->page() + ->withLowPriority() + ->withModification( + static function (PagePartProvider $parts) use ($mode_info): Page { + $p = new StandardPageBuilder(); + $page = $p->build($parts); + return $page->withModeInfo($mode_info); + } + ); + } + + private function buildMainbarModification( + CalledContexts $called_contexts + ): \Closure { + return function (?MainBar $mainbar) use ($called_contexts): ?MainBar { + if ($mainbar === null) { + return null; + } + + $tools = $mainbar->getToolEntries(); + $new_mainbar = array_reduce( + array_keys($tools), + static fn(MainBar $c, string $v): MainBar => $c->withAdditionalToolEntry($v, $tools[$v]), + $mainbar + ->withClearedEntries() + ->withAdditionalEntry( + 'create_question', + $this->dic['ui.factory']->button()->bulky( + $this->dic['ui.factory']->symbol()->icon()->standard('', '')->withAbbreviation('CQ'), + $this->dic['lng']->txt('create_question'), + $called_contexts->current()->getAdditionalData()->get(self::URL_CREATE_QUESTION)->__toString() + ) + ) + ); + + if ($called_contexts->current()->getAdditionalData()->exists(self::QUESTIONLIST_ENTRY)) { + return $new_mainbar->withAdditionalEntry( + 'question_list', + $called_contexts->current()->getAdditionalData()->get(self::QUESTIONLIST_ENTRY) + ); + } + + return $new_mainbar; + }; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/QuestionsTable.php b/components/ILIAS/Questions/src/Presentation/Layout/QuestionsTable.php new file mode 100644 index 000000000000..009c624f03b4 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/QuestionsTable.php @@ -0,0 +1,189 @@ +getLanguage()->loadLanguageModule('qpl'); + } + + #[\Override] + public function getUI(): array + { + + $content = []; + + if ($this->create_question_button !== null) { + $toolbar = new \ilToolbarGUI(); + $toolbar->addComponent( + $this->create_question_button + ); + $content = [ + $this->environment->getUIFactory()->legacy()->content( + $toolbar->getHTML() + ) + ]; + } + + $content[] = $this->buildTable(); + + return $content; + } + + public function withCreateQuestionButton( + PrimaryButton $create_question_button + ): self { + $clone = clone $this; + $clone->create_question_button = $create_question_button; + return $clone; + } + + #[\Override] + public function getRows( + DataRowBuilder $row_builder, + array $visible_column_ids, + Range $range, + Order $order, + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): \Generator { + $environment_with_action = $this->environment->withActionParameter( + Edit::ACTION_EDIT_QUESTION + ); + foreach ($this->questions_repository->getQuestionDataOnlyForAllQuestions( + $range, + $order, + $filter_data + ) as $question) { + $table_row = $question->toTableRow( + $row_builder, + $environment_with_action, + $this->required_capabilities + ); + + if ($table_row !== null) { + yield $table_row; + } + } + } + + #[\Override] + public function getTotalRowCount( + mixed $additional_viewcontrol_data, + mixed $filter_data, + mixed $additional_parameters + ): ?int { + return $this->questions_repository->getQuestionsCount($filter_data); + } + + private function buildTable(): array + { + $filter = $this->buildFilter( + $this->environment->getUrlBuilder()->buildURI()->__toString() + ); + + return [ + $filter, + $this->environment->getUIFactory()->table()->data( + $this, + $this->environment->getLanguage()->txt('questions'), + OverviewTableColumns::getTableColums( + $this->environment->getLanguage(), + $this->environment->getUIFactory()->table()->column() + ), + )->withActions( + $this->getActions() + )->withRange(new Range(0, 20)) + ->withFilter( + $this->ui_service->filter()->getData($filter) + )->withRequest($this->environment->getHttpServices()->request()) + ]; + } + + private function buildFilter( + string $action + ): Filter { + $filter_inputs = OverviewTableColumns::getFilterInputs( + $this->environment->getLanguage(), + $this->environment->getUIFactory()->input()->field(), + $this->answer_form_factory->getAnswerFormTypesArrayForSelect( + $this->environment->getLanguage() + ) + ); + + $active = array_fill(0, count($filter_inputs), true); + + $filter = $this->ui_service->filter()->standard( + 'question_table_filter_id', + $action, + $filter_inputs, + $active, + true, + true + ); + + $request = $this->environment->getHttpServices()->request(); + return $request->getMethod() === 'POST' + ? $filter->withRequest($request) + : $filter; + } + + private function getActions(): array + { + return [ + 'clone' => $this->environment->getUIFactory()->table()->action()->standard( + $this->environment->getLanguage()->txt('copy'), + $this->environment->withActionParameter(Edit::ACTION_CLONE_QUESTION) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + ), + 'delete' => $this->environment->getUIFactory()->table()->action()->standard( + $this->environment->getLanguage()->txt('delete'), + $this->environment->withActionParameter(Edit::ACTION_DELETE_QUESTIONS) + ->getUrlBuilder(), + $this->environment->getTableRowIdToken() + )->withAsync(true) + ]; + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/Tools/InputsBuilder.php b/components/ILIAS/Questions/src/Presentation/Layout/Tools/InputsBuilder.php new file mode 100644 index 000000000000..65adcb355ab4 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/Tools/InputsBuilder.php @@ -0,0 +1,28 @@ +carry = $carry; + return $clone; + } + + public function persistCarry(): void + { + if ($this->carry === null) { + $this->loadCarryFromSessionAndClear(); + } + \ilSession::set(self::STORAGE_KEY, $this->carry); + } + + public function resetCarry(): void + { + \ilSession::clear(self::STORAGE_KEY); + } + + public function retrieveCarry( + Transformation $transformation + ): mixed { + if ($this->carry === null) { + $this->loadCarryFromSessionAndClear(); + } + + return $transformation->transform($this->carry); + } + + public function getInputs(): Section + { + if ($this->carry === null) { + $this->loadCarryFromSessionAndClear(); + } + return $this->to_inputs->transform($this->carry); + } + + private function loadCarryFromSessionAndClear(): void + { + $this->carry = \ilSession::get(self::STORAGE_KEY); + \ilSession::clear(self::STORAGE_KEY); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/Tools/UploadHandler.php b/components/ILIAS/Questions/src/Presentation/Layout/Tools/UploadHandler.php new file mode 100644 index 000000000000..7aa22a75af85 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/Tools/UploadHandler.php @@ -0,0 +1,364 @@ +environment + ->withSubActionParameter(self::SUB_ACTION_UPLOAD) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getFileRemovalURL(): string + { + return $this->environment + ->withSubActionParameter(self::SUB_ACTION_REMOVE) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getExistingFileInfoURL(): string + { + return $this->environment + ->withSubActionParameter(self::SUB_ACTION_INFO) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + #[\Override] + public function getInfoForExistingFiles( + array $file_ids + ): array { + return array_map( + fn($file_id): FileInfoResult => $this->getInfoResult($file_id), + $file_ids + ); + } + + #[\Override] + public function getInfoResult( + string $identifier + ): ?FileInfoResult { + $title = $mime = 'unknown'; + $size = 0; + $id = $this->irss->manage()->find($identifier); + if ($id !== null) { + $revision = $this->irss->manage()->getCurrentRevision($id)->getInformation(); + $title = $revision->getTitle(); + $size = $revision->getSize(); + $mime = $revision->getMimeType(); + } + + return new BasicFileInfoResult( + $this->getFileIdentifierParameterName(), + $identifier, + $title, + $size, + $mime + ); + } + + #[\Override] + public function supportsChunkedUploads(): bool + { + return true; + } + + #[\Override] + public function can( + string $sub_action + ): bool { + $has_file_identifier = $this->hasFileIdentifier(); + + return $sub_action === self::SUB_ACTION_UPLOAD + || $sub_action === self::SUB_ACTION_REMOVE && $has_file_identifier + || $sub_action === self::SUB_ACTION_INFO && $has_file_identifier; + } + + #[\Override] + public function do( + string $action + ): Async { + $response = match($action) { + self::SUB_ACTION_UPLOAD => $this->upload(), + self::SUB_ACTION_REMOVE => $this->remove(), + self::SUB_ACTION_INFO => $this->info(), + default => '' + }; + + return $this->environment->getPresentationFactory()->getAsync($response); + } + + private function upload(): string + { + try { + $this->readChunkedInformation(); + return json_encode($this->getUploadResult()); + } catch (\Throwable $t) { + return json_encode( + new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + BasicHandlerResult::STATUS_FAILED, + '', + $t->getMessage() + ) + ); + } + } + + private function remove(): string + { + return json_encode( + $this->getRemoveResult( + $this->retrieveFileIdentifier() + ) + ); + } + + private function info(): string + { + return json_encode( + $this->getInfoResult( + $this->retrieveFileIdentifier() + ) + ); + } + + private function readChunkedInformation(): void + { + $body = $this->environment->getHttpServices()->request()->getParsedBody(); + $this->chunk_id = $body['dzuuid'] ?? null; + $this->amount_of_chunks = (int) ($body['dztotalchunkcount'] ?? 0); + $this->chunk_index = (int) ($body['dzchunkindex'] ?? 0); + $this->chunk_total_size = (int) ($body['dztotalfilesize'] ?? 0); + $this->is_chunked = ($this->chunk_id !== null && $this->amount_of_chunks > 0); + } + + private function getUploadResult(): HandlerResult + { + $this->upload->process(); + + $result_array = $this->upload->getResults(); + $result = end($result_array); + + $identifier = ''; + $status = HandlerResult::STATUS_FAILED; + $message = $this->environment->getLanguage()->txt( + 'msg_info_blacklisted' + ); + if ($result instanceof UploadResult && $result->isOK()) { + if ($this->is_chunked) { + return $this->processChunckedUpload($result); + } + + $identifier = $this->irss->manage()->upload( + $result, + $this->stakeholder + )->serialize(); + $status = HandlerResult::STATUS_OK; + $message = "file upload OK"; + } + + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + $status, + $identifier, + $message + ); + } + + private function getRemoveResult( + string $identifier + ): HandlerResult { + $status = HandlerResult::STATUS_OK; + $message = "file with identifier '{$identifier}' doesn't exist, nothing to do."; + + $id = $this->irss->manage()->find($identifier); + if ($id !== null) { + $this->irss->manage()->remove( + $id, + $this->stakeholder + ); + $status = HandlerResult::STATUS_OK; + $message = "file removal OK"; + } + + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + $status, + $identifier, + $message + ); + } + + private function processChunckedUpload( + UploadResult $result + ): HandlerResult { + $temp_path = $this->sanitizer->sanitize( + "{$this->chunk_id}/{$result->getName()}" + ); + + try { + $this->writeChunkedTempFile( + $result, + $temp_path + ); + } catch (\Throwable $t) { + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_FAILED, + '', + $t->getMessage() + ); + } + + if (($this->chunk_index + 1) === $this->amount_of_chunks) { + return $this->storeChunkedUpload( + $result, + $temp_path + ); + } + + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_PARTIAL, + '', + 'chunk upload OK' + ); + } + + private function writeChunkedTempFile( + UploadResult $result, + string $temp_path + ): void { + if ($this->temp_filesystem->has($temp_path)) { + fwrite( + fopen( + $this->temp_filesystem->readStream($temp_path) + ->getMetadata()['uri'], + 'ab' + ), + file_get_contents( + $result->getPath() + ) + ); + return; + } + + $this->temp_filesystem->write( + $temp_path, + file_get_contents( + $result->getPath() + ) + ); + } + + private function storeChunkedUpload( + UploadResult $result, + string $temp_path + ): HandlerResult { + $id = $this->irss->manage()->stream( + $this->temp_filesystem->readStream($temp_path), + $this->stakeholder, + $result->getName() + ); + + return new BasicHandlerResult( + $this->getFileIdentifierParameterName(), + HandlerResult::STATUS_OK, + $id->serialize(), + 'file upload OK' + ); + } + + private function hasFileIdentifier(): bool + { + return $this->environment + ->getHttpServices() + ->wrapper() + ->query() + ->has($this->getFileIdentifierParameterName()); + } + + private function retrieveFileIdentifier(): string + { + if (!$this->hasFileIdentifier()) { + return ''; + } + + return $this->environment + ->getHttpServices() + ->wrapper() + ->query() + ->retrieve( + $this->getFileIdentifierParameterName(), + $this->environment->getRefinery()->kindlyTo()->string() + ); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Layout/Viewable.php b/components/ILIAS/Questions/src/Presentation/Layout/Viewable.php new file mode 100644 index 000000000000..a2cf6f879584 --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Layout/Viewable.php @@ -0,0 +1,32 @@ + + */ + public function getUI(): array|Component; +} diff --git a/components/ILIAS/Questions/src/Presentation/Views/Edit.php b/components/ILIAS/Questions/src/Presentation/Views/Edit.php new file mode 100644 index 000000000000..ae99915b8a8e --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Views/Edit.php @@ -0,0 +1,917 @@ +> $capability_identifiers + */ + public function __construct( + private readonly Language $lng, + private readonly \ilObjUser $current_user, + private readonly Refinery $refinery, + private readonly UIFactory $ui_factory, + private readonly UIRenderer $ui_renderer, + private readonly GlobalScreen $global_screen, + private readonly GlobalTemplate $global_tpl, + private readonly ContentStyle $content_style, + private readonly \ilCtrl $ctrl, + private readonly HTTP $http, + private readonly \ilTabsGUI $tabs_gui, + private readonly \ilUIService $ui_services, + private readonly UuidFactory $uuid_factory, + private readonly ConfigurationRepository $configuration_repository, + private readonly AnswerFormFactory $answer_form_factory, + private readonly Repository $questions_repository, + private readonly AttemptRepository $attempt_repository, + private readonly LayoutFactory $layout_factory, + private readonly CapabilitiesFactory $capabilities_factory, + array $capability_identifiers, + private readonly int $owner_object_id + ) { + $this->required_capabilities = $this->capabilities_factory->get( + $capability_identifiers + ); + } + + public function withEditable( + Editability $editability + ): self { + $clone = clone $this; + $clone->editability = $editability; + return $clone; + } + + public function withOrderingEnabled( + bool $enable + ): self { + $clone = clone $this; + $clone->ordering_enabled = $enable; + return $clone; + } + + public function getUI( + URI $base_uri, + int $ref_id + ): array|Component { + $this->content_style->gui()->addCss( + $this->global_tpl, + $ref_id + ); + + $environment = $this->buildEnvironment($base_uri); + + $view = match($environment->getAction()) { + self::ACTION_CREATE_QUESTION => $this->createQuestion( + $environment->withIsInCreationContext(true) + ), + self::ACTION_EDIT_QUESTION => $this->editQuestion($environment), + self::ACTION_CLONE_QUESTION => $this->cloneQuestion($environment), + self::ACTION_DELETE_QUESTIONS => $this->deleteQuestions($environment), + default => $this->showTable($environment) + }; + + if ($view instanceof Async) { + $view->render($this->ui_renderer); + } + + return $view->getUI(); + } + + public function forwardPageCmds( + URI $base_uri, + int $ref_id + ): void { + $environment = $this->buildEnvironment($base_uri); + + if ($this->ctrl->getCmd() === 'insert' + && $environment->getAction() === self::ACTION_DELETE_QUESTIONS) { + $this->deleteQuestions($environment); + return; + } + + $this->initializeEditMode($environment); + $environment->preserveParametersForPageEditorCmds(); + + $this->content_style->gui()->addCss( + $this->global_tpl, + $ref_id + ); + + $this->global_tpl->setContent( + $this->ctrl->forwardCommand( + new \QstsQuestionPageGUI( + $this->questions_repository->getForQuestionId( + $environment->getQuestionId() + ), + $this->owner_object_id, + $this->required_capabilities, + new ViewConfiguration( + true, + false, + false, + false + ) + )->withEditView( + $this + )->withReturnURI( + $environment + ->withActionParameter(self::ACTION_EDIT_QUESTION) + ->withQuestionIdParameter($environment->getQuestionId()) + ->getUrlBuilder() + ->buildURI() + ) + ) + ); + } + + public function getCreateAnswerForm( + URI $base_uri, + Question $question, + \ilPCAnswerForm $content_object + ): array|Component { + $environment = $this->buildEnvironment($base_uri) + ->withIsInCreationContext(true) + ->withQuestionIdParameter($question->getId()); + + $environment->setEditAnswerFormBackTarget(); + + if ($this->configuration_repository->isCreateModeSimple($environment)) { + $environment = $environment->withCreateModeParameter(); + } + + $answer_form_type_class_hash = $environment->getTypeClassHash(); + + if ($answer_form_type_class_hash !== '') { + $type_definition = $this->answer_form_factory + ->getTypeDefinitionFromSelectValue($answer_form_type_class_hash); + + return $this->forwardCreateAnswerFormCmd( + $environment->withAnswerFormProperties( + $type_definition->buildProperties( + $this->answer_form_factory->getDefaultTypeGenericProperties( + $question->getId(), + $type_definition, + $environment->getAnswerFormId(), + ), + null + ) + )->withAnswerFormTypeHashParameter($answer_form_type_class_hash), + $question, + $content_object, + $type_definition->getEditView() + )->getUI(); + } + + return match($environment->getAction()) { + self::ACTION_CREATE_ANSWER_FORM => $this->processCreateAnswerForm( + $environment, + $question, + $content_object + )->getUI(), + default => $this->buildCreateAnswerForm($environment)->getUI() + }; + } + + public function getEditAnswerForm( + URI $base_uri, + Question $question, + AnswerFormProperties $answer_form_properties, + Definition $type_definition + ): array|Component { + $environment = $this->buildEnvironment($base_uri) + ->withAnswerFormProperties($answer_form_properties) + ->withQuestionIdParameter($question->getId()); + + $action = $environment->getAction(); + $edit_view = $type_definition->getEditView(); + + $from_capabilites = $this->required_capabilities->edit( + $this->tabs_gui, + $environment, + $edit_view, + $action + ); + + if ($from_capabilites instanceof AnswerFormProperties) { + $this->updateAnswerFormAndRedirect( + $environment, + $question, + $from_capabilites + ); + } + + if ($from_capabilites instanceof Async) { + $from_capabilites->render($this->ui_renderer); + } + + if ($from_capabilites instanceof Viewable) { + return $from_capabilites->getUI(); + } + + if ($action === self::ACTION_OTHER_ANSWER_FORM) { + return $this->processOtherAnswerFormAction( + $environment->withActionParameter(self::ACTION_OTHER_ANSWER_FORM), + $question, + $edit_view + )->getUI(); + } + + $from_edit_view = $edit_view->edit($environment); + if ($from_edit_view instanceof EditForm + && $this->required_capabilities->additionalAnswerFormStepsRequired()) { + return $from_edit_view->withIsFinalStep(false)->getUI(); + } + + if ($from_edit_view instanceof Async) { + $from_edit_view->render($this->ui_renderer); + } + + if ($from_edit_view instanceof Viewable) { + return $from_edit_view->getUI(); + } + + if ($from_edit_view instanceof ForImmediateStorage) { + $this->updateAnswerFormAndRedirect( + $environment, + $question, + $from_edit_view->unpack() + ); + } + + $return_form_step_actions = $this->required_capabilities + ->doFirstFormStepAction( + $environment->withAnswerFormProperties($from_edit_view), + $edit_view + ); + + if ($return_form_step_actions instanceof Async) { + $return_form_step_actions->render($this->ui_renderer); + } + + if ($return_form_step_actions instanceof Viewable) { + return $return_form_step_actions->getUI(); + } + + $this->updateAnswerFormAndRedirect( + $environment, + $question, + $from_edit_view + ); + } + + private function createQuestion( + DefaultEnvironment $environment + ): EditForm { + $this->initializeEditMode($environment); + $this->tabs_gui->setBackTarget( + $this->lng->txt('cancel'), + $environment->withDefaultSubAction()->getUrlBuilder() + ->buildURI() + ->__toString() + ); + + $create = $this->questions_repository->getNew( + $environment->getParentObjId() + )->getEditView( + $this->current_user, + $this->ctrl, + $this->http->wrapper()->post(), + $this->ui_renderer, + $this->uuid_factory, + $this->configuration_repository, + $this->attempt_repository, + $this->required_capabilities + )->create( + $environment->withActionParameter(self::ACTION_CREATE_QUESTION) + ); + + if ($create instanceof EditForm) { + return $create; + } + + $this->questions_repository->create([$create]); + $this->ctrl->redirectToURL( + $this->buildAfterQuestionCreationRedirectUri( + $environment, + $create->getCreateMode(), + $create->getId() + ) + ); + + } + + private function editQuestion( + DefaultEnvironment $environment + ): EditForm { + $this->initializeEditMode($environment); + $this->tabs_gui->setBackTarget( + $this->lng->txt('back'), + $environment->withDefaultSubAction()->getUrlBuilder()->buildURI()->__toString() + ); + + $question_id = $environment->getQuestionId(); + $question = $this->questions_repository->getForQuestionId($question_id); + $environment_with_question_parameter = $environment + ->withQuestionIdParameter($question_id); + + $edit = $question->getEditView( + $this->current_user, + $this->ctrl, + $this->http->wrapper()->post(), + $this->ui_renderer, + $this->uuid_factory, + $this->configuration_repository, + $this->attempt_repository, + $this->required_capabilities + )->edit( + $environment_with_question_parameter + ->withActionParameter(self::ACTION_EDIT_QUESTION) + ); + + if ($edit instanceof EditForm) { + return $edit; + } + + $this->questions_repository->update([$edit]); + return $this->buildEditStartView( + $environment_with_question_parameter + ->withDefaultSubAction() + ->withActionParameter(self::ACTION_EDIT_QUESTION), + $edit + ); + } + + private function cloneQuestion( + DefaultEnvironment $environment + ): QuestionsTable { + $question_to_clone = $environment->getQuestionIds(); + + if (!isset($question_to_clone[0])) { + return $this->showTable($environment); + } + + $question = $this->questions_repository->getForQuestionId( + $question_to_clone[0] + ); + $this->questions_repository->create( + [ + $question->clone( + $this->uuid_factory, + [ + 'parent_obj_id' => $environment->getParentObjId(), + 'new_question_page_id' => $this->questions_repository + ->getNextAvailableQuestionPageId(), + 'required_capabilities' => $this->required_capabilities + ] + )->withParentObjId($environment->getParentObjId()) + ] + ); + + $this->ctrl->redirectToURL( + $environment->getUrlBuilder()->buildURI()->__toString() + ); + } + + private function deleteQuestions( + DefaultEnvironment $environment + ): Async { + $question_ids = $environment->getQuestionIds(); + + if ($question_ids === null) { + return $environment->getPresentationFactory()->getAsync( + $this->ui_factory->messageBox()->failure( + $this->lng->txt('msg_no_questions_selected') + ) + ); + } + + if ($environment->getSubAction() === self::ACTION_DELETE_QUESTIONS) { + $this->deleteSelectedQuestions($question_ids); + $this->ctrl->redirectToURL( + $environment->getUrlBuilder()->buildURI()->__toString() + ); + } + + return $environment->getPresentationFactory()->getAsync( + $this->ui_factory->modal()->interruptive( + $this->lng->txt('confirm'), + $this->lng->txt('confirm_delete_questions'), + $environment->withActionParameter( + self::ACTION_DELETE_QUESTIONS + )->withSubActionParameter( + self::ACTION_DELETE_QUESTIONS + )->getUrlBuilder()->buildURI()->__toString() + )->withAffectedItems( + $this->buildAffectedItems($question_ids) + ) + ); + } + + private function showTable( + DefaultEnvironment $environment + ): QuestionsTable { + $this->questions_repository->migrateQuestionPages(); + + return new QuestionsTable( + $this->ui_services, + $this->answer_form_factory, + $this->questions_repository, + $environment, + $this->required_capabilities + )->withCreateQuestionButton( + $this->ui_factory->button()->primary( + $this->lng->txt('create'), + $environment->withActionParameter(self::ACTION_CREATE_QUESTION) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ) + ); + } + + private function processCreateAnswerForm( + DefaultEnvironment $environment, + Question $question, + \ilPCAnswerForm $content_object + ): EditForm { + $form = $this->buildCreateAnswerForm($environment) + ->withRequest($this->http->request()); + + $data = $form->getData(); + if ($data === null) { + return $form; + } + + if ($this->configuration_repository->isCreateModeSimple($environment)) { + $question_page = new \QstsQuestionPage($question->getPageId()); + $question_page->setQuestion($question); + $question_page->addQuestionText($data['question_text']); + } + + $type_definition = $data['type']; + return $this->forwardCreateAnswerFormCmd( + $environment->withAnswerFormProperties( + $type_definition->buildProperties( + $this->answer_form_factory->getDefaultTypeGenericProperties( + $question->getId(), + $type_definition + ), + null + ) + )->withAnswerFormTypeHashParameter( + $this->answer_form_factory->getHashedClass($type_definition::class) + ), + $question, + $content_object, + $type_definition->getEditView() + ); + } + + private function forwardCreateAnswerFormCmd( + DefaultEnvironment $environment, + Question $question, + \ilPCAnswerForm $content_object, + AnswerFormEditView $answer_form_edit_view + ): ?EditForm { + $action = $environment->getAction(); + + $from_capabilites = $this->required_capabilities->create( + $this->tabs_gui, + $environment, + $answer_form_edit_view, + $action + ); + + if ($from_capabilites instanceof Async) { + $from_capabilites->render($this->ui_renderer); + } + + if ($from_capabilites instanceof EditForm) { + return $this->addSaveAndNewToAnswerFormCreateIfNeeded( + $environment, + $from_capabilites + ); + } + + if ($from_capabilites instanceof AnswerFormProperties) { + $this->createAnswerFormAndRedirect( + $environment, + $question->withAnswerFormProperties($from_capabilites), + $content_object + ); + } + + $from_edit_view = $answer_form_edit_view->create( + $environment->withAnswerFormIdParameter( + $environment->getAnswerFormId() + ) + ); + + if ($from_edit_view instanceof Async) { + return $from_edit_view->render($this->ui_renderer); + } + + if ($from_edit_view instanceof EditForm) { + return $this->addSaveAndNewToAnswerFormCreateIfNeeded( + $environment, + $this->required_capabilities->additionalAnswerFormStepsRequired() + ? $from_edit_view->withIsFinalStep(false) + : $from_edit_view + ); + } + + $from_capabilities_first_step = $this->required_capabilities + ->doFirstFormStepAction( + $environment->withAnswerFormProperties($from_edit_view), + $answer_form_edit_view + ); + + if ($from_capabilities_first_step instanceof EditForm) { + return $this->addSaveAndNewToAnswerFormCreateIfNeeded( + $environment, + $from_capabilities_first_step + ); + } + + $this->createAnswerFormAndRedirect( + $environment, + $question->withAnswerFormProperties($from_capabilities_first_step), + $content_object + ); + } + + private function processOtherAnswerFormAction( + Environment $environment, + Question $question, + AnswerFormEditView $edit_view + ): Viewable { + $from_edit_view = $edit_view->other($environment); + + if ($from_edit_view instanceof Viewable) { + return $from_edit_view; + } + + if ($from_edit_view instanceof Async) { + $from_edit_view->render($this->ui_renderer); + } + + $this->updateAnswerFormAndRedirect( + $environment, + $question, + $from_edit_view + ); + } + + private function updateAnswerFormAndRedirect( + Environment $environment, + Question $question, + AnswerFormProperties $properties + ): never { + $this->questions_repository->update( + [$question->withAnswerFormProperties($properties)] + ); + + $this->required_capabilities->onAnswerFormUpdate($properties); + + $this->ctrl->redirectToURL( + $environment->getUrlBuilder()->buildURI()->__toString() + ); + } + + private function createAnswerFormAndRedirect( + Environment $environment, + Question $question, + \ilPCAnswerForm $content_object + ): never { + $this->questions_repository->update( + [$question] + ); + + $content_object->create( + $environment->getAnswerFormProperties()->getAnswerFormId() + ); + $content_object->getPage()->update(); + + $this->ctrl->redirectToURL( + $this->buildAfterAnswerFormCreationRedirectUri($environment) + ); + + } + + private function initializeEditMode( + DefaultEnvironment $environment + ): void { + $this->tabs_gui->clearTargets(); + + $this->global_screen->tool()->context()->current()->addAdditionalData( + LayoutProvider::MODE_ENABLED, + true + ); + $this->global_screen->tool()->context()->current()->addAdditionalData( + LayoutProvider::QUESTIONLIST_ENTRY, + $this->buildQuestionListSlate($environment) + ); + $this->global_screen->tool()->context()->current()->addAdditionalData( + LayoutProvider::URL_CLOSE_MODE_INFO, + $environment->getUrlBuilder()->buildURI() + ); + $this->global_screen->tool()->context()->current()->addAdditionalData( + LayoutProvider::URL_CREATE_QUESTION, + $environment + ->withActionParameter(self::ACTION_CREATE_QUESTION) + ->getUrlBuilder() + ->buildURI() + ); + } + + private function buildQuestionListSlate( + DefaultEnvironment $environment + ): LegacySlate { + return $this->ui_factory->mainControls()->slate()->legacy( + $this->lng->txt('questionlist'), + $this->ui_factory->symbol()->icon()->standard('', '')->withAbbreviation('QL'), + $this->ui_factory->legacy()->content( + $this->ui_renderer->render( + $this->ui_factory->panel()->secondary()->listing( + $this->lng->txt('questionlist'), + [ + $this->buildItemGroupForQuestionListSlate($environment) + ] + ) + ) + ) + ); + } + + private function buildItemGroupForQuestionListSlate( + DefaultEnvironment $environment + ): ItemGroup { + return $this->ui_factory->item()->group( + '', + $this->builEditLinksForQuestionListSlate($environment) + ); + } + + private function builEditLinksForQuestionListSlate( + Environment $environment + ): array { + $links = []; + foreach ($this->questions_repository->getQuestionDataOnlyForAllQuestions() as $question) { + $links[] = $this->ui_factory->item()->standard( + $question->toEditLink( + $this->ui_factory->link(), + $environment->withActionParameter(self::ACTION_EDIT_QUESTION) + ) + ); + } + return $links; + } + + private function buildEditStartView( + DefaultEnvironment $environment, + Question $question + ): EditForm { + return $question->getEditView( + $this->current_user, + $this->ctrl, + $this->http->wrapper()->post(), + $this->ui_renderer, + $this->uuid_factory, + $this->configuration_repository, + $this->attempt_repository, + $this->required_capabilities + )->edit( + $environment + ); + } + + private function buildCreateAnswerForm( + DefaultEnvironment $environment + ): EditForm { + $if = $this->ui_factory->input(); + + $inputs = []; + if ($this->configuration_repository->isCreateModeSimple($environment)) { + $inputs['question_text'] = $if->field()->textarea( + $this->lng->txt('question_text') + )->withRequired(true); + } + + return $environment->getPresentationFactory()->getEditForm( + $if->field()->section( + $inputs + [ + 'type' => $if->field()->select( + $this->lng->txt('select_answer_form_type'), + $this->answer_form_factory + ->getAnswerFormTypesArrayForSelect($this->lng) + )->withRequired(true) + ->withAdditionalTransformation( + $this->refinery->custom()->transformation( + fn(string $v): ?Definition => $this->answer_form_factory + ->getTypeDefinitionFromSelectValue($v) + ) + ) + ], + $this->lng->txt('create_answer_form') + ), + $environment->withActionParameter( + self::ACTION_CREATE_ANSWER_FORM + )->getUrlBuilder(), + null + ); + } + + /** + * + * @param string|array<\ILIAS\Data\UUID\Uuid> $question_ids + * @return array<\ILIAS\UI\Component\Modal\InterruptiveItem\Standard> + */ + private function buildAffectedItems( + string|array $question_ids + ): array { + $questions = $question_ids === 'ALL_OBJECTS' + ? $this->questions_repository->getQuestionDataOnlyForAllQuestions() + : $this->questions_repository->getQuestionDataOnlyForQuestionIds($question_ids); + $affected_items = []; + foreach ($questions as $question) { + $affected_items[] = $this->ui_factory->modal()->interruptiveItem()->standard( + $question->getId()->toString(), + $question->getTitle() + ); + } + return $affected_items; + } + + private function deleteSelectedQuestions( + array $question_ids + ): void { + $questions_to_delete = []; + foreach ($this->questions_repository->getForQuestionIds($question_ids) as $question) { + if (count($questions_to_delete) < 100) { + $questions_to_delete[] = $question; + continue; + } + + $this->questions_repository->delete($questions_to_delete); + $questions_to_delete = []; + } + + $this->questions_repository->delete($questions_to_delete); + } + + private function addSaveAndNewToAnswerFormCreateIfNeeded( + Environment $environment, + EditForm $edit_form + ): EditForm { + if ($edit_form->isFinalStep() && $environment->isCreateModeSimple()) { + $edit_form = $edit_form->withAdditionalAction( + $environment->buildURLBuilderTokenForCreateAndNew(), + '1', + $this->lng->txt('save_and_new') + ); + } + + return $edit_form; + } + + private function buildEnvironment( + URI $base_uri, + ): DefaultEnvironment { + return new DefaultEnvironment( + $this->ctrl, + $this->http, + $this->refinery, + $this->lng, + $this->tabs_gui, + $this->uuid_factory, + $this->layout_factory, + $this->editability, + $this->required_capabilities, + $this->owner_object_id, + $base_uri + ); + } + + private function buildAfterQuestionCreationRedirectUri( + DefaultEnvironment $environment, + CreateModes $create_mode, + Uuid $question_uuid + ): string { + if ($create_mode !== CreateModes::Simple) { + return $environment + ->withDefaultSubAction() + ->withActionParameter(self::ACTION_EDIT_QUESTION) + ->withQuestionIdParameter($question_uuid) + ->getUrlBuilder() + ->buildURI() + ->__toString(); + } + + $environment->setParamtersForSimpleCreateCmd($question_uuid); + + return $this->ctrl->getLinkTargetByClass( + [ + \QstsQuestionPageGUI::class, + \ilPageEditorGUI::class, + \ilPCAnswerFormGUI::class + ], + 'insert' + ); + } + + private function buildAfterAnswerFormCreationRedirectUri( + DefaultEnvironment $environment, + ): string { + if (!$this->configuration_repository->isCreateModeSimple($environment)) { + return $this->ctrl->getLinkTargetByClass( + \QstsQuestionPageGUI::class, + 'edit' + ); + } + + $additonal_data = $this->global_screen + ->tool() + ->context() + ->current() + ->getAdditionalData(); + + if ($environment->isCreateAndNewAction()) { + return $additonal_data + ->get(LayoutProvider::URL_CREATE_QUESTION) + ->__toString(); + } + + return $additonal_data + ->get(LayoutProvider::URL_CLOSE_MODE_INFO) + ->__toString(); + } +} diff --git a/components/ILIAS/Questions/src/Presentation/Views/Participant.php b/components/ILIAS/Questions/src/Presentation/Views/Participant.php new file mode 100644 index 000000000000..5e4c8eeda37f --- /dev/null +++ b/components/ILIAS/Questions/src/Presentation/Views/Participant.php @@ -0,0 +1,173 @@ +> $capability_identifiers + */ + public function __construct( + private readonly Language $lng, + private readonly Refinery $refinery, + private readonly UIFactory $ui_factory, + private readonly HTTP $http, + private readonly QuestionRepository $question_repository, + private readonly AttemptRepository $attempt_repository, + private readonly CapabilitiesFactory $capabilities_factory, + array $capability_identifiers, + private readonly int $owner_object_id + ) { + $this->required_capabilities = $this->capabilities_factory->get( + $capability_identifiers + ); + } + + public function getPresentationIdentifier(): Uuid + { + return $this->presentation_identifier; + } + + public function withShuffleQuestionOrder( + bool $shuffle_question_order + ): self { + $clone = clone $this; + $clone->shuffle_question_order = $shuffle_question_order; + return $clone; + } + + public function getQuestionView( + Uuid $question_id, + ?Uuid $attempt_id, + bool $interactive, + bool $show_marks, + bool $show_best_response, + bool $show_feedback + ): QuestionParticipantView { + $question = $this->question_repository->getForQuestionId( + $question_id + ); + + $marking_required = $this->required_capabilities->isMarkingRequired(); + + if ($attempt_id === null + || !isset($this->attempt_cache[$attempt_id->toString()][$question_id->toString()])) { + $attempt = $this->attempt_repository->getAttemptFor( + $attempt_id, + [$question] + ); + $attempt_id = $attempt->getId(); + $this->attempt_cache[$attempt_id->toString()][$question_id->toString()] = $attempt; + } + + return $question->getParticipantView( + $this->lng, + $this->refinery, + $this->ui_factory, + $this->required_capabilities, + $this->attempt_cache[$attempt_id->toString()][$question_id->toString()], + $interactive, + $show_marks && $marking_required, + $show_best_response && $marking_required, + $show_feedback && $this->required_capabilities->isCapabilityRequired( + TextFeedback::getIdentifier() + ) + ); + } + + public function persistResponse( + Uuid $question_id, + Uuid $attempt_id + ): void { + $question = $this->question_repository->getForQuestionId( + $question_id + ); + + $attempt_data = $this->attempt_repository->getAttemptFor( + $attempt_id, + [$question] + ); + + if ($attempt_data === null) { + throw new \UnexpectedValueException( + 'The provided attempt identifier is invalid. Response cannot be persisted.' + ); + } + + $response = $this->attempt_repository->getNewResponseFor( + $question_id, + $attempt_id + ); + + $response_with_values_from_post = array_reduce( + $question->retrieveAnswerFormResponsesFromPost( + $this->required_capabilities, + $this->http->wrapper()->post(), + $response->getId() + ), + fn(Response $c, AnswerFormResponse $v): Response + => $c->withAnswerFormResponse($v), + $response + ); + + if ($this->required_capabilities->isMarkingRequired()) { + $response_with_values_from_post = $question->addAwardedPointsToResponse( + $response_with_values_from_post + ); + } + + $this->attempt_repository->storeResponse( + $response_with_values_from_post + ); + } + + public function deleteResponsesFor( + Uuid $attempt_id, + Uuid $question_id + ): void { + $this->attempt_repository->deleteResponsesFor( + $attempt_id, + $this->question_repository->getForQuestionId( + $question_id + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/PublicInterface.php b/components/ILIAS/Questions/src/PublicInterface.php new file mode 100644 index 000000000000..78902c6bc939 --- /dev/null +++ b/components/ILIAS/Questions/src/PublicInterface.php @@ -0,0 +1,46 @@ +> $required_capabilities_class_names + */ + public function getParticipantView( + array $required_capabilities_class_names, + int $owner_obj_id + ): Participant; + + /** + * + * @param list> $required_capabilities_class_names + */ + public function getEditView( + array $required_capabilities_class_names, + int $owner_obj_id + ): Edit; +} diff --git a/components/ILIAS/Questions/src/Question/Definitions/Lifecycle.php b/components/ILIAS/Questions/src/Question/Definitions/Lifecycle.php new file mode 100644 index 000000000000..43184f62a9f7 --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Definitions/Lifecycle.php @@ -0,0 +1,31 @@ +addAnswerFormStatementsToManipulate( + $manipulate + ->withAdditionalStatement( + $this->buildInsertLinkingStatement( + $manipulate->getTableNameBuilder(null), + $question_id, + $parent_obj_id, + $position + ) + )->withAdditionalStatement( + $this->buildInsertQuestionStatement( + $manipulate->getTableNameBuilder(null), + $question_id, + $page_id, + $title, + $author, + $lifecycle, + $remarks, + $original_id + ) + ), + $answer_forms + ); + } + + public function addUpdateStatementsToManipulation( + Manipulate $manipulate, + bool $self_updated, + bool $linking_information_updated, + bool $page_id_updated, + Uuid $question_id, + ?int $page_id, + string $title, + string $author, + Lifecycle $lifecycle, + string $remarks, + ?Uuid $original_id, + int $parent_obj_id, + ?int $position, + array $new_answer_forms, + array $updated_answer_forms, + array $deleted_answer_forms + ): Manipulate { + $table_names_builder = $manipulate->getTableNameBuilder(null); + + if ($linking_information_updated) { + $manipulate = $manipulate + ->withAdditionalStatement( + $this->buildUpdateLinkingStatement( + $table_names_builder, + $question_id, + $parent_obj_id, + $position + ) + ); + } + + if ($self_updated) { + $manipulate = $manipulate->withAdditionalStatement( + $this->buildUpdateQuestionStatement( + $table_names_builder, + $question_id, + $title, + $author, + $lifecycle, + $remarks, + $original_id + ) + ); + } + + if ($page_id_updated) { + $manipulate = $manipulate->withAdditionalStatement( + $this->buildUpdatePageIdStatement( + $table_names_builder, + $question_id, + $page_id + ) + ); + } + + if ($deleted_answer_forms !== []) { + $manipulate = $this->addDeleteAnswerFormsStatementsToManipulate( + $manipulate, + $deleted_answer_forms + ); + } + + return $this->addAnswerFormStatementsToManipulate( + $manipulate, + $new_answer_forms, + $updated_answer_forms + ); + } + + public function addDeleteAnswerFormsStatementsToManipulate( + Manipulate $manipulate, + array $answer_forms_to_delete + ): Manipulate { + return array_reduce( + $answer_forms_to_delete, + fn(Manipulate $c, AnswerFormProperties $v): Manipulate => $v->toDelete( + $this->persistence_factory, + $v->getTypeGenericProperties()->toDelete( + $this->persistence_factory, + $this->answer_form_generic_table_definitions, + $c, + ) + ), + $manipulate + ); + } + + public function buildDeleteQuestionStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id + ): Delete { + $table_type = TableTypes::Questions; + return $this->persistence_factory->delete( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } + + public function buildDeleteLinkingStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id + ): Delete { + $table_type = TableTypes::Linking; + return $this->persistence_factory->delete( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } + + /** + * @todo skergomard, 2026-01-86: This we only need while the migrations exist, after + * this MUST go! + */ + public function buildDeleteMigrationStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id + ): Delete { + $table_type = TableTypes::MigrationsTable; + return $this->persistence_factory->delete( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } + + private function addAnswerFormStatementsToManipulate( + Manipulate $manipulate, + array $new_answer_forms, + array $updated_answer_forms = [] + ): Manipulate { + $manipulate_with_new_answer_form_statements = array_reduce( + $new_answer_forms, + fn(Manipulate $c, AnswerFormProperties $v): Manipulate => + $this->addAnswerFormStatementToManipulate( + $v, + ManipulationType::Create, + $c + ), + $manipulate + ); + + return array_reduce( + $updated_answer_forms, + fn(Manipulate $c, AnswerFormProperties $v): Manipulate => + $this->addAnswerFormStatementToManipulate( + $v, + ManipulationType::Update, + $c + ), + $manipulate_with_new_answer_form_statements + ); + } + + private function addAnswerFormStatementToManipulate( + AnswerFormProperties $answer_form_properties, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + $manipulate_with_generic_properties = $answer_form_properties->getTypeGenericProperties() + ->toStorage( + $this->persistence_factory, + $this->answer_form_generic_table_definitions, + $manipulation_type, + $manipulate + ); + + return $answer_form_properties->toStorage( + $this->persistence_factory, + $manipulation_type, + $manipulate_with_generic_properties + ); + } + + private function buildInsertLinkingStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id, + int $parent_obj_id, + ?int $position + ): Insert { + return $this->persistence_factory->insert( + $this->question_tables_definitions->getColumns( + $table_names_builder, + TableTypes::Linking + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $parent_obj_id + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $position + ) + ] + ); + } + + private function buildInsertQuestionStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id, + ?int $page_id, + string $title, + string $author, + Lifecycle $lifecycle, + string $remarks, + ?Uuid $original_id + ): Insert { + return $this->persistence_factory->insert( + $this->question_tables_definitions->getColumns( + $table_names_builder, + TableTypes::Questions + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $page_id + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $title + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $author + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $lifecycle->value + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $remarks + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $original_id?->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + time() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + time() + ) + ] + ); + } + + private function buildUpdateLinkingStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id, + int $parent_obj_id, + ?int $position + ): Update { + $table_type = TableTypes::Linking; + return $this->persistence_factory->update( + $this->question_tables_definitions->getColumns( + $table_names_builder, + $table_type, + [TableTypes::LINKING_TABLE_ID_COLUMN] + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $parent_obj_id + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $position + ) + ], + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } + + private function buildUpdateQuestionStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id, + string $title, + string $author, + Lifecycle $lifecycle, + string $remarks, + ?Uuid $original_id + ): Update { + $table_type = TableTypes::Questions; + return $this->persistence_factory->update( + $this->question_tables_definitions->getColumns( + $table_names_builder, + $table_type, + [ + 'id', + 'page_id', + 'created' + ] + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $title + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $author + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $lifecycle->value + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $remarks + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $original_id?->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + time() + ) + ], + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } + + /** + * @todo skergomard, 2026-01-26: This we only need while the migrations exist, after + * this a question MUST never change the page assigned to it after its creation! + */ + private function buildUpdatePageIdStatement( + TableNameBuilder $table_names_builder, + Uuid $question_id, + ?int $page_id + ): Update { + $table_type = TableTypes::Questions; + return $this->persistence_factory->update( + [ + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + 'page_id' + ), + $this->persistence_factory->column( + $this->persistence_factory->table( + $table_names_builder, + $table_type + ), + 'last_update' + ) + ], + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $page_id + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + time() + ) + ], + [ + $this->persistence_factory->where( + $this->question_tables_definitions->getIdColumn( + $table_names_builder, + $table_type + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ) + ) + ] + ); + } +} diff --git a/components/ILIAS/Questions/src/Question/Persistence/Repository.php b/components/ILIAS/Questions/src/Question/Persistence/Repository.php new file mode 100644 index 000000000000..c10e6f14f454 --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Persistence/Repository.php @@ -0,0 +1,702 @@ +core_table_names_builder = new TableNameBuilder( + self::COMPONENT_NAMESPACE, + null + ); + } + + public function getNew( + int $parent_obj_id + ): Question { + return new Question( + $this->buildAvailableUuid(), + $parent_obj_id + ); + } + + /** + * @return \Generator<\ILIAS\Questions\Question\QuestionImplementation> + */ + public function getQuestionDataOnlyForAllQuestions( + ?DataRange $range = null, + ?DataOrder $order = null, + array $filter_data = [] + ): \Generator { + $questions_query = $this->addFilterToQuery( + $this->buildQuestionsQuery( + $this->buildMainOrder($order) + ), + $filter_data + ); + + if ($range !== null) { + $questions_query = $questions_query->withRange($range); + } + + + + foreach ($questions_query->withGroupBy( + $this->buildGroupByColumn() + )->getRecords() as $query_with_record) { + yield $this->retrieveQuestionFromQuery( + $query_with_record, + $this->retrieveAnswerFormsFromQuery($query_with_record, true) + ); + } + } + + public function getQuestionsCount( + array $filter_data + ): int { + $id_column = $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ); + + $query = "SELECT count({$id_column->getColumnString()}) cnt FROM {$id_column->getTableName()}"; + + return $this->db->fetchObject( + $filter_data === [] || $filter_data['title'] === null + ? $this->db->query($query) + : $this->buildCountStatementWithWhereClause($query, $filter_data) + )->cnt; + } + + /** + * @return \Generator<\ILIAS\Questions\Question\QuestionImplementation> + */ + public function getQuestionDataOnlyForQuestionIds( + array $question_ids + ): \Generator { + foreach ($this->buildQuestionsQuery()->withAdditionalWhere( + $this->persistence_factory->where( + $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + array_map( + fn(Uuid $v): string => $v->toString(), + $question_ids + ) + ), + Operator::In + ) + )->withGroupBy( + $this->buildGroupByColumn() + )->getRecords() as $query_with_record) { + yield $this->retrieveQuestionFromQuery( + $query_with_record, + $this->retrieveAnswerFormsFromQuery($query_with_record, true) + ); + } + } + + public function getForQuestionId( + Uuid $question_id + ): ?Question { + return $this->getForBaseQuery( + $this->buildQuestionsQuery()->withAdditionalWhere( + $this->persistence_factory->where( + $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $question_id->toString() + ), + Operator::Equal + ) + ), + [$question_id] + )->current(); + } + + /** + * + * @param list<\ILIAS\Data\Uuid> $question_ids + * @return \Generator<\ILIAS\Questions\Question\QuestionImplementation> + */ + public function getForQuestionIds( + array $question_ids + ): \Generator { + yield from $this->getForBaseQuery( + $this->buildQuestionsQuery()->withAdditionalWhere( + $this->persistence_factory->where( + $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + array_map( + fn(Uuid $v): string => $v->toString(), + $question_ids + ) + ), + Operator::In + ) + ), + $question_ids + ); + } + + /** + * @param array<\ILIAS\Questions\Question\QuestionImplementation> $questions + */ + public function create( + array $questions + ): void { + $this->store( + array_map( + fn(Question $v): Question => $v->getPageId() === null + ? $v->withPageId( + $this->buildQuestionPage( + $v->getParentObjId() + ) + ) : $v, + $questions + ), + ManipulationType::Create, + $this->buildManipulate() + ); + } + + /** + * @param array<\ILIAS\Questions\Question\QuestionImplementation> $questions + */ + public function update( + array $questions + ): void { + $this->store( + $questions, + ManipulationType::Update, + $this->buildManipulate() + ); + } + + public function delete( + array $questions + ): void { + array_reduce( + $questions, + fn(Manipulate $c, Question $v): Manipulate + => $v->toDelete( + $this->database_statement_builder, + $c + ), + $this->buildManipulate() + )->run(); + + foreach ($questions as $question) { + (new \QstsQuestionPage($question->getPageId()))->delete(); + } + } + + public function getQuestionForAnswerFormId( + Uuid $answer_form_id + ): ?Question { + $question_id = $this->db->fetchObject( + $this->db->query( + "SELECT question_id FROM qsts_answer_forms" . PHP_EOL + . "WHERE id = {$this->db->quote($answer_form_id->toString(), FieldDefinition::T_TEXT)}" + ) + )?->question_id; + + if ($question_id === null) { + return null; + } + + return $this->getForQuestionId( + $this->uuid_factory->fromString($question_id) + ); + } + + public function migrateQuestionPages(): void + { + $questions_table_name = $this->core_table_names_builder + ->getTableNameFor(TableTypes::Questions); + $migration_table_name = $this->core_table_names_builder + ->getTableNameFor(TableTypes::MigrationsTable); + + $query = $this->db->query( + "SELECT new_question_id, old_question_id, question_id" . PHP_EOL + . "FROM {$questions_table_name}" . PHP_EOL + . "INNER JOIN {$migration_table_name} ON id = new_question_id" . PHP_EOL + . 'LEFT OUTER JOIN qpl_questions ON old_question_id = question_id' . PHP_EOL + . "WHERE page_id = 0" + ); + while (($row = $this->db->fetchObject($query)) !== null) { + $question = $this->getForQuestionId( + $this->uuid_factory->fromString($row->new_question_id) + ); + if ($row->question_id === null) { + $this->delete([$question]); + continue; + } + $this->migrateQuestionPage( + $question, + $row->old_question_id + ); + } + } + + public function getNextAvailableQuestionPageId(): int + { + + $last_id = $this->db->fetchObject( + $this->db->query( + 'SELECT MAX(page_id) AS last FROM page_object ' + . 'WHERE parent_type = "qsts"' + ) + )->last; + if ($last_id === null) { + return 1; + } + + return $last_id + 1; + } + + /** + * @param array<\ILIAS\Data\Uuid> $question_ids + * @return \Generator<\ILIAS\Questions\Question\QuestionImplementation> + */ + private function getForBaseQuery( + Query $query, + array $question_ids + ): \Generator { + $query_with_answer_forms = array_reduce( + $this->getAnswerFormTypesForQuestionIds($question_ids), + fn(Query $c, AnswerFormDefinition $v) => $v->getTableDefinitions()->completeQuestionQuery( + $c, + $this->answer_form_generic_table_definitions->getIdColumn( + $this->core_table_names_builder, + AnswerFormGenericTableTypes::AnswerForms + ) + ), + $query + ); + + foreach ($query_with_answer_forms->withGroupBy( + $this->buildGroupByColumn() + )->getRecords() as $query_with_record) { + yield $this->retrieveQuestionFromQuery( + $query_with_record, + $this->retrieveAnswerFormsFromQuery($query_with_record) + ); + } + } + + /** + * $param array<\ILIAS\Questions\AnswerForms\Properties> $answer_forms + */ + private function retrieveQuestionFromQuery( + Query $query, + array $answer_forms + ): Question { + $linking_info = $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->core_table_names_builder, + TableTypes::Linking + ), + $this->refinery->identity() + ); + + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->core_table_names_builder, + TableTypes::Questions, + ), + $this->refinery->custom()->transformation( + fn(array $vs): Question => new Question( + $this->uuid_factory->fromString($vs[0]['id']), + $linking_info[0]['obj_id'], + $linking_info[0]['position'], + $vs[0]['page_id'], + $vs[0]['title'], + $vs[0]['author'], + Lifecycle::from($vs[0]['lifecycle']), + $vs[0]['remarks'], + $vs[0]['original_id'] === null + ? null + : $this->uuid_factory->fromString($vs[0]['original_id']), + new \DateTimeImmutable('@' . $vs[0]['last_update'], new \DateTimeZone('UTC')), + new \DateTimeImmutable('@' . $vs[0]['created'], new \DateTimeZone('UTC')), + $answer_forms + ) + ) + ); + } + + /** + * @return array<\ILIAS\Questions\AnswerForms\Properties> + */ + private function retrieveAnswerFormsFromQuery( + Query $query, + bool $only_generic_data = false + ): array { + return $query->retrieveCurrentRecord( + $this->persistence_factory->table( + $this->core_table_names_builder, + AnswerFormGenericTableTypes::AnswerForms + ), + $this->refinery->custom()->transformation( + function (array $vs) use ($query, $only_generic_data): array { + if (count($vs) === 1 && $vs[0]['type'] === null) { + return []; + } + + $answer_forms = []; + $previous_answer_form_id = null; + foreach ($vs as $data_set) { + if ($data_set['id'] === $previous_answer_form_id) { + continue; + } + $previous_answer_form_id = $data_set['id']; + $definition = $this->answer_form_factory + ->getDefinitionForClass($data_set['type']); + $answer_forms[] = $definition->buildProperties( + $this->answer_form_factory->buildTypeGenericPropertiesFromDatabase($data_set), + $only_generic_data ? null : $query + ); + } + return $answer_forms; + } + ) + ); + } + + /** + * @param array<\ILIAS\Data\Uuid> $question_ids + * @return array<\ILIAS\Questions\AnswerForm\Definition> + */ + private function getAnswerFormTypesForQuestionIds( + array $question_ids + ): array { + $table_name = $this->core_table_names_builder + ->getTableNameFor(AnswerFormGenericTableTypes::AnswerForms); + + $query = $this->db->query( + "SELECT DISTINCT type FROM {$table_name}" . PHP_EOL + . "WHERE {$this->db->in( + 'question_id', + $question_ids, + false, + FieldDefinition::T_TEXT + )}" + ); + $answer_form_types = []; + while (($type_class = $this->db->fetchObject($query)?->type) !== null) { + $answer_form_types[] = $this->answer_form_factory->getDefinitionForClass($type_class); + } + return $answer_form_types; + } + + /** + * @param array<\ILIAS\Questions\Question\QuestionImplementation> $questions + */ + private function store( + array $questions, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): void { + array_reduce( + $questions, + fn(Manipulate $c, Question $v): Manipulate => $v->toStorage( + $this->database_statement_builder, + $manipulation_type, + $c + ), + $manipulate + )->run(); + } + + private function buildQuestionsQuery( + ?Order $main_sort_order = null + ): Query { + $base_query = new Query( + $this->db, + $this->refinery, + self::COMPONENT_NAMESPACE, + $this->persistence_factory->table( + $this->core_table_names_builder, + TableTypes::Linking + ) + ); + + if ($main_sort_order !== null) { + $base_query = $base_query->withAdditionalOrder($main_sort_order); + } + + return $this->answer_form_generic_table_definitions->completeQuestionQuery( + $this->question_table_definitions->completeLoadQuestionQuery($base_query), + $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ) + ); + } + + private function addFilterToQuery( + Query $question_query, + array $filter_data + ): Query { + foreach ($filter_data as $key => $value) { + [ + 'column' => $column, + 'operator' => $operator, + 'value' => $transformed_value + ] = $this->prepareFilterData($key, $value); + + if ($column === null) { + continue; + } + + $question_query = $question_query->withAdditionalWhere( + $this->persistence_factory->where( + $column, + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $transformed_value + ), + $operator + ) + ); + } + + return $question_query; + } + + private function buildCountStatementWithWhereClause( + string $query, + array $filter_data + ): \ilDBStatement { + $where_string = []; + $types = []; + $values = []; + foreach ($filter_data as $key => $value) { + [ + 'column' => $column, + 'operator' => $operator, + 'value' => $transformed_value + ] = $this->prepareFilterData($key, $value); + + if ($column === null) { + continue; + } + + $where = $this->persistence_factory->where( + $column, + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $transformed_value + ), + $operator + ); + $right = $where->getRight(); + + $where_string[] = $where->toSql(); + $types[] = $right->getType(); + $values[] = is_array($right->getValue()) + ? implode(', ', $right->getValue()) + : $right->getValue(); + } + + return $this->db->queryF( + "{$query} WHERE " . implode(' AND ', $where_string), + $types, + $values + ); + } + + private function prepareFilterData( + string $key, + mixed $value + ): array { + $empty_set = [ + 'column' => null, + 'operator' => null, + 'value' => null + ]; + + if ($value === null || $value === '' || $value === []) { + return $empty_set; + } + + $column_definition = OverviewTableColumns::tryFrom($key); + + $column = $column_definition?->getDatabaseColumn( + $this->persistence_factory, + $this->core_table_names_builder, + $this->answer_form_factory + ); + if ($column === null) { + return $empty_set; + } + + $operator = Operator::Equal; + if (is_string($value)) { + $operator = Operator::Like; + $value = "%{$value}%"; + } + + return [ + 'column' => $column, + 'operator' => $operator, + 'value' => $column_definition->transformFilterValue( + $this->answer_form_factory, + $value + ) + ]; + } + + private function buildManipulate(): Manipulate + { + return new Manipulate( + $this->db, + self::COMPONENT_NAMESPACE + ); + } + + private function buildMainOrder( + ?DataOrder $order + ): ?Order { + if ($order === null) { + return null; + } + + $order_array = $order->get(); + + return $this->persistence_factory->order( + OverviewTableColumns::tryFrom( + array_key_first($order_array) + )->getDatabaseColumn( + $this->persistence_factory, + $this->core_table_names_builder + ), + OrderDirection::tryFrom( + array_shift($order_array) + ) + ); + } + + private function buildGroupByColumn(): Column + { + return $this->question_table_definitions->getIdColumn( + $this->core_table_names_builder, + TableTypes::Questions + ); + } + + private function buildAvailableUuid(): Uuid + { + do { + $uuid = $this->uuid_factory->uuid4(); + if ($this->checkAvailabilityOfId($uuid)) { + return $uuid; + } + } while (true); + } + + private function checkAvailabilityOfId( + Uuid $uuid + ): bool { + $table_name = $this->core_table_names_builder + ->getTableNameFor(TableTypes::Questions); + + return $this->db->fetchObject( + $this->db->query( + "SELECT COUNT(*) as cnt FROM {$table_name}" . PHP_EOL + . "WHERE id='{$uuid->toString()}'" + ) + )->cnt === 0; + } + + private function buildQuestionPage( + int $parent_obj_id + ): int { + $page = new \QstsQuestionPage(); + $page->setId($this->getNextAvailableQuestionPageId()); + $page->setParentId($parent_obj_id); + $page->createFromXML(); + return $page->getId(); + } + + private function migrateQuestionPage( + Question $question, + int $old_question_id + ): Question { + $new_page_id = $this->getNextAvailableQuestionPageId(); + $old_qsts_page = new \ilAssQuestionPage($old_question_id); + $old_qsts_page->setQuestion($question); + $old_qsts_page->copyToAnswerForm($new_page_id, $question); + + $new_question = $question->withPageId($new_page_id); + + $this->update([$new_question]); + + return $new_question; + } +} diff --git a/components/ILIAS/Questions/src/Question/Persistence/TableDefinitions.php b/components/ILIAS/Questions/src/Question/Persistence/TableDefinitions.php new file mode 100644 index 000000000000..41e4c1e1a7cc --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Persistence/TableDefinitions.php @@ -0,0 +1,170 @@ +persistence_factory->table( + $table_names_builder, + $table_type + ); + + return array_map( + fn(string $v): Column => $this->persistence_factory->column( + $table, + $v + ), + array_values( + array_filter( + match($table_type) { + TableTypes::Questions => self::QUESTION_TABLE_COLUMNS, + TableTypes::Linking => self::LINKING_TABLE_COLUMNS, + TableTypes::MigrationsTable => self::MIGRATIONS_TABLE_COLUMNS + }, + fn(string $v) => !in_array($v, $columns_to_skip) + ) + ) + ); + } + + public function getIdColumn( + TableNameBuilder $table_names_builder, + TableTypesInterface $table_type + ): Column { + $table = $this->persistence_factory->table( + $table_names_builder, + $table_type + ); + + return match($table_type) { + TableTypes::Questions => $this->persistence_factory->column( + $table, + self::QUESTION_TABLE_ID_COLUMN + ), + TableTypes::Linking => $this->persistence_factory->column( + $table, + self::LINKING_TABLE_ID_COLUMN + ), + TableTypes::MigrationsTable => $this->persistence_factory->column( + $table, + self::MIGRATIONS_TABLE_ID_COLUMN + ) + }; + } + + public function completeLoadQuestionQuery( + Query $query + ): Query { + $table_names_builder = $query->getTableNameBuilder(null); + $questions_id_column = $this->getIdColumn( + $table_names_builder, + TableTypes::Questions + ); + + return $query->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::Linking + ) + ) + )->withAdditionalSelect( + $this->persistence_factory->select( + $this->getColumns( + $table_names_builder, + TableTypes::Questions + ) + ) + )->withAdditionalJoin( + $this->persistence_factory->join( + $this->getIdColumn( + $table_names_builder, + TableTypes::Linking + ), + $questions_id_column, + JoinType::Inner + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $questions_id_column + ) + )->withAdditionalOrder( + $this->persistence_factory->order( + $this->getIdColumn( + $table_names_builder, + TableTypes::Linking + ) + ) + ); + } +} diff --git a/components/ILIAS/Questions/src/Question/Persistence/TableTypes.php b/components/ILIAS/Questions/src/Question/Persistence/TableTypes.php new file mode 100644 index 000000000000..49229b969564 --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Persistence/TableTypes.php @@ -0,0 +1,31 @@ +answer_forms = array_reduce( + $answer_forms, + function (array $c, AnswerFormProperties $v): array { + $c[$v->getAnswerFormId()->toString()] = $v; + return $c; + }, + [] + ); + } + + public function getId(): ?Uuid + { + return $this->id; + } + + public function getParentObjId(): int + { + return $this->parent_obj_id; + } + + public function withParentObjId( + int $parent_obj_id + ): self { + $clone = clone $this; + $clone->parent_obj_id = $parent_obj_id; + $clone->linking_information_updated = true; + return $clone; + } + + public function withPosition( + int $position + ): self { + $clone = clone $this; + $clone->position = $position; + $clone->linking_information_updated = true; + return $clone; + } + + public function getPageId(): ?int + { + return $this->page_id; + } + + public function withPageId( + int $page_id + ): self { + $clone = clone $this; + $clone->page_id = $page_id; + $clone->page_id_updated = true; + return $clone; + } + + public function getTitle(): string + { + return $this->title; + } + + public function withTitle( + string $title + ): self { + $clone = clone $this; + $clone->title = $title; + $clone->self_updated = true; + return $clone; + } + + public function getAuthor(): string + { + return $this->author; + } + + public function withAuthor( + string $author + ): self { + $clone = clone $this; + $clone->author = $author; + $clone->self_updated = true; + return $clone; + } + + public function getLifecycle(): Lifecycle + { + return $this->lifecycle; + } + + public function withLifecycle( + Lifecycle $lifecycle + ): self { + $clone = clone $this; + $clone->lifecycle = $lifecycle; + $clone->self_updated = true; + return $clone; + } + + public function getRemarks(): string + { + return $this->remarks; + } + + public function withRemarks( + string $remarks + ): self { + $clone = clone $this; + $clone->remarks = $remarks; + $clone->self_updated = true; + return $clone; + } + + public function getOriginalId(): ?Uuid + { + return $this->original_id; + } + + public function withOriginalId( + Uuid $original_id + ): self { + $clone = clone $this; + $clone->original_id = $original_id; + $clone->self_updated = true; + return $clone; + } + + public function getLastUpdate(): ?\DateTimeImmutable + { + return $this->last_update; + } + + public function getCreated(): ?\DateTimeImmutable + { + return $this->created; + } + + #[\Override] + public function clone( + UuidFactory $uuid_factory, + array $environment = [] + ): static { + $clone = clone $this; + $clone->id = $uuid_factory->uuid4(); + $clone->parent_obj_id = $environment['parent_obj_id']; + $clone->page_id = $environment['new_question_page_id']; + $mapping = []; + $clone->answer_forms = array_map( + function ( + AnswerFormProperties $v + ) use ( + $uuid_factory, + $environment, + $clone, + &$mapping + ): AnswerFormProperties { + $old_answer_form_id = $v->getAnswerFormId()->toString(); + + $cloned_answer_form = $v->clone( + $uuid_factory, + [ + 'new_question_id' => $clone->id, + 'answer_form_id' => $uuid_factory->uuid4() + ] + ); + + $mapping[$old_answer_form_id] = $cloned_answer_form + ->getAnswerFormId()->toString(); + + $environment['required_capabilities']->onAnswerFormClone( + $uuid_factory, + $v, + $cloned_answer_form + ); + + return $cloned_answer_form; + }, + $this->answer_forms + ); + \QstsQuestionPage::setAnswerFormMapping($mapping); + $question_page = new \QstsQuestionPage($this->page_id); + $question_page->copy($clone->page_id); + return $clone; + } + + /** + * @todo skergomard, 2026-06-08: This we only need while the migrations exist, after + * this a question MUST never change the page assigned to it after its creation! + */ + public function getFirstAnswerFormIdForMigration(): Uuid + { + return reset($this->answer_forms)->getAnswerFormId(); + } + + public function getAnswerFormPropertiesByIdString( + string $form_id + ): ?AnswerFormProperties { + return $this->answer_forms[$form_id] ?? null; + } + + public function withAnswerFormProperties( + AnswerFormProperties $answer_form + ): self { + $clone = clone $this; + if (isset($clone->answer_forms[$answer_form->getAnswerFormId()->toString()])) { + $clone->updated_answer_forms[] = $answer_form; + } else { + $clone->new_answer_forms[] = $answer_form; + } + $clone->answer_forms[$answer_form->getAnswerFormId()->toString()] = $answer_form; + return $clone; + } + + public function withoutDeletedAnswerForms( + array $found_answer_form_ids + ): self { + $clone = clone $this; + foreach (array_keys($this->answer_forms) as $answer_form_id) { + if (!in_array($answer_form_id, $found_answer_form_ids)) { + $clone->deleted_answer_forms[] = $clone->answer_forms[$answer_form_id]; + unset($clone->answer_forms[$answer_form_id]); + } + } + + return $clone; + } + + /** + * Checks whether the question is a clone of another question or not + */ + public function isClone(): bool + { + return $this->original_id !== null; + } + + public function getCreateMode(): ?CreateModes + { + return $this->create_mode; + } + + public function withCreateMode( + CreateModes $create_mode + ): self { + $clone = clone $this; + $clone->create_mode = $create_mode; + return $clone; + } + + public function getListOfContainedAnswerFormTypeLabels( + Language $lng + ): array { + return array_map( + fn(AnswerFormDefinition $v): string => $v->getLabel($lng), + $this->getListOfContainedAnswerFormTypes() + ); + } + + public function getEditView( + \ilObjUser $current_user, + \ilCtrl $ctrl, + RequestWrapper $post_wrapper, + UIRenderer $ui_renderer, + UuidFactory $uuid_factory, + ConfigurationRepository $configuration_repository, + AttemptRepository $attempt_repository, + RequiredCapabilities $required_capabilities + ): Views\Edit { + if (!$required_capabilities->areAllCapabilitiesSupportedByAnswerForms($this->answer_forms)) { + throw new \UnexpectedValueException( + "The Question does not support all required Capabilities." + ); + } + + return new Views\Edit( + $current_user, + $ctrl, + $post_wrapper, + $ui_renderer, + $uuid_factory, + $configuration_repository, + $attempt_repository, + $required_capabilities, + $this + ); + } + + public function getParticipantView( + Language $lng, + Refinery $refinery, + UIFactory $ui_factory, + RequiredCapabilities $required_capabilities, + ?Attempt $attempt_data, + bool $interactive = true, + bool $show_marks = false, + bool $show_best_response = false, + bool $show_feedback = false + ): Views\Participant { + if (!$required_capabilities->areAllCapabilitiesSupportedByAnswerForms($this->answer_forms)) { + throw new \UnexpectedValueException( + "The Question does not support all required Capabilities." + ); + } + + return new Views\Participant( + $lng, + $refinery, + $ui_factory, + $required_capabilities, + $this, + $attempt_data, + new ViewConfiguration( + $interactive, + $show_marks, + $show_best_response, + $show_feedback + ) + ); + } + + public function initializeAttemptData( + Attempt $attempt + ): Attempt { + return array_reduce( + $this->answer_forms, + fn(Attempt $c, AnswerFormProperties $v): Attempt + => $v->getDefinition()->initializeAttemptData($c, $v), + $attempt + ); + } + + public function toEditLink( + LinkFactory $link_factory, + DefaultEnvironment $environment + ): StandardLink { + return $link_factory->standard( + $this->title, + $environment->withQuestionIdParameter($this->id) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ); + } + + public function toTableRow( + DataRowBuilder $row_builder, + DefaultEnvironment $environment, + RequiredCapabilities $required_capabilities + ): ?DataRow { + if (!$required_capabilities->areAllCapabilitiesSupportedByAnswerForms($this->answer_forms)) { + return null; + } + + return $row_builder->buildDataRow( + $this->id->toString(), + [ + OverviewTableColumns::Title->value => $environment + ->getUIFactory()->link()->standard( + $this->title, + $environment->withQuestionIdParameter( + $this->id + )->getUrlBuilder() + ->buildURI() + ->__toString() + ), + OverviewTableColumns::AnswerFormTypes->value => implode( + '
', + $this->getListOfContainedAnswerFormTypeLabels( + $environment->getLanguage() + ) + ) + ] + ); + } + + public function toStorage( + DatabaseStatementBuilder $database_statement_builder, + ManipulationType $manipulation_type, + Manipulate $manipulate + ): Manipulate { + return $manipulation_type === ManipulationType::Create + ? $database_statement_builder->addInsertStatementsToManipulation( + $manipulate, + $this->id, + $this->page_id, + $this->title, + $this->author, + $this->lifecycle, + $this->remarks, + $this->original_id, + $this->parent_obj_id, + $this->position, + $this->answer_forms + ) : $database_statement_builder->addUpdateStatementsToManipulation( + $manipulate, + $this->self_updated, + $this->linking_information_updated, + $this->page_id_updated, + $this->id, + $this->page_id, + $this->title, + $this->author, + $this->lifecycle, + $this->remarks, + $this->original_id, + $this->parent_obj_id, + $this->position, + $this->new_answer_forms, + $this->updated_answer_forms, + $this->deleted_answer_forms + ); + } + + public function toDelete( + DatabaseStatementBuilder $database_statement_builder, + Manipulate $manipulate + ): Manipulate { + $table_names_builder = $manipulate->getTableNameBuilder(null); + + return $database_statement_builder->addDeleteAnswerFormsStatementsToManipulate( + $manipulate->withAdditionalStatement( + $database_statement_builder->buildDeleteQuestionStatement( + $table_names_builder, + $this->id + ) + )->withAdditionalStatement( + $database_statement_builder->buildDeleteLinkingStatement( + $table_names_builder, + $this->id + ) + )->withAdditionalStatement( + $database_statement_builder->buildDeleteMigrationStatement( + $table_names_builder, + $this->id + ) + ), + $this->answer_forms + ); + } + + public function completeResponseQuery( + Query $query, + Column $base_table_id_column + ): Query { + return array_reduce( + $this->getListOfContainedAnswerFormTypes(), + fn(Query $c, AnswerFormDefinition $v): Query => $v + ->getTableDefinitions() + ->completeResponseQuery( + $c, + $base_table_id_column + ), + $query + ); + } + + public function retrieveAnswerFormResponsesFromQuery( + Uuid $response_id, + Query $query + ): array { + return array_map( + fn(AnswerFormProperties $v): AnswerFormResponse => $v + ->getDefinition() + ->buildResponse( + $response_id, + $v, + $query + ), + $this->answer_forms + ); + } + + public function retrieveAnswerFormResponsesFromPost( + RequiredCapabilities $required_capabilities, + RequestWrapper $post_wrapper, + Uuid $response_id + ): array { + return array_map( + fn(AnswerFormProperties $v): AnswerFormResponse => $required_capabilities + ->getParticipantViewProvider() + ->getParticipantView($v) + ->retrieveResponse( + $response_id, + $v, + $post_wrapper + ), + $this->answer_forms + ); + } + + public function retrieveAnswerFormResponsesFromPreviewData( + Uuid $response_id, + array $preview_data + ): array { + return array_map( + fn(AnswerFormProperties $v): AnswerFormResponse => $v + ->getDefinition() + ->buildResponseFromPreviewData( + $response_id, + $v, + $preview_data[$v->getAnswerFormId()->toString()] ?? [] + ), + $this->answer_forms + ); + } + + public function addAwardedPointsToResponse( + Response $response + ): Response { + return $response->withAwardedPoints( + array_reduce( + $this->answer_forms, + function (?float $c, AnswerFormProperties $v) use ($response): ?float { + /** @var Marking $marking */ + $marking = $v->getDefinition()->getCapability( + MarkingAllowingPartialPoints::getIdentifier() + ); + + if ($marking === null) { + return $c; + } + + $points_from_form = $marking->calculateAwardedPoints( + $v, + $response->getAnswerFormResponse($v->getAnswerFormId()) + ); + + if ($points_from_form === null) { + return $c; + } + + if ($c === null) { + return $points_from_form; + } + + return $c + $points_from_form; + } + ) + ); + } + + private function getListOfContainedAnswerFormTypes(): array + { + return array_reduce( + $this->answer_forms, + function ( + array $c, + AnswerFormProperties $v + ): array { + $definition = $v->getDefinition(); + if (!array_key_exists($definition::class, $c)) { + $c[$definition::class] = $definition; + } + return $c; + }, + [] + ); + } +} diff --git a/components/ILIAS/Questions/src/Question/Views/Edit.php b/components/ILIAS/Questions/src/Question/Views/Edit.php new file mode 100644 index 000000000000..25582f7ee9ec --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Views/Edit.php @@ -0,0 +1,429 @@ +getSubAction()) { + self::CMD_SAVE_QUESTION => $this->processBasicPropertiesCreateForm( + $environment + ), + default => $this->buildBasicPropertiesCreateForm($environment) + }; + } + + public function edit( + DefaultEnvironment $environment, + ): EditForm|Question { + return match ($environment->getSubAction()) { + self::CMD_SAVE_QUESTION => $this->processBasicPropertiesEditingForm( + $environment + ), + self::CMD_SEND_RESPONSE => $this->sendResponse( + $environment + ), + self::CMD_RESET_PREVIEW => $this->resetPreview( + $environment + ), + default => $this->buildBasicPropertiesEditingForm($environment) + ->withContentAfterForm( + $this->buildPreviewPanel($environment) + ) + }; + } + + private function buildBasicPropertiesCreateForm( + DefaultEnvironment $environment + ): EditForm { + $ff = $environment->getUIFactory()->input()->field(); + + $inputs = [ + 'question' => $ff->group( + $this->buildBasicPropertiesInputs( + $environment->getUIFactory()->input()->field(), + $environment->getLanguage() + ) + )->withAdditionalTransformation( + $this->buildAddBasicPropertiesToQuestionTrafo( + $environment->getRefinery() + ) + )->withValue( + $this->buildBasicPropertiesBasicValuesArray() + ) + ]; + + if ($this->configuration_repository->isCreateModeChangeableByUser()) { + $inputs['create_mode'] = $this->configuration_repository->getInputForCreateMode( + $ff, + $environment->getLanguage(), + $environment->getRefinery() + )->withAdditionalTransformation( + $environment->getRefinery()->custom()->transformation( + fn(string $v): CreateModes => CreateModes::tryFrom($v) + ?? $this->configuration_repository->getGlobalCreateMode() + ) + ); + } + + return $environment->getPresentationFactory()->getEditForm( + $ff->section( + $inputs, + $environment->getLanguage()->txt('edit_basic_question_properties') + ), + $environment + ->withSubActionParameter(self::CMD_SAVE_QUESTION) + ->getUrlBuilder(), + null + ); + } + + private function processBasicPropertiesCreateForm( + DefaultEnvironment $environment + ): EditForm|Question { + $form = $this->buildBasicPropertiesCreateForm( + $environment + )->withRequest($environment->getHttpServices()->request()); + + $data = $form->getData(); + return $data === null + ? $form + : $data['question']->withCreateMode($data['create_mode']); + } + + private function buildBasicPropertiesEditingForm( + DefaultEnvironment $environment + ): EditForm { + return $environment->getPresentationFactory()->getEditForm( + $environment->getUIFactory()->input()->field()->section( + $this->buildBasicPropertiesInputs( + $environment->getUIFactory()->input()->field(), + $environment->getLanguage() + ), + $environment->getLanguage()->txt('edit_basic_question_properties') + )->withAdditionalTransformation( + $this->buildAddBasicPropertiesToQuestionTrafo( + $environment->getRefinery() + ) + )->withValue( + $this->buildBasicPropertiesBasicValuesArray() + ), + $environment + ->withSubActionParameter(self::CMD_SAVE_QUESTION) + ->getUrlBuilder(), + null + )->withIsFinalStep(true); + } + + private function processBasicPropertiesEditingForm( + DefaultEnvironment $environment + ): EditForm|Question { + $form = $this->buildBasicPropertiesEditingForm( + $environment + )->withRequest($environment->getHttpServices()->request()); + + $data = $form->getData(); + return $data === null + ? $form + : $data; + } + + private function buildBasicPropertiesInputs( + FieldFactory $field_factory, + Language $lng + ): array { + return [ + 'title' => $field_factory->text($lng->txt('title')) + ->withRequired(true), + 'author' => $field_factory->text($lng->txt('author')), + 'lifecycle' => $field_factory->select( + $lng->txt('qst_lifecycle'), + array_reduce( + Lifecycle::cases(), + function (array $c, Lifecycle $v) use ($lng): array { + $c[$v->value] = $lng->txt("qst_lifecycle_{$v->value}"); + return $c; + }, + [] + ) + )->withRequired(true), + 'remarks' => $field_factory->textarea($lng->txt('qst_remarks')) + ]; + } + + private function buildBasicPropertiesBasicValuesArray(): array + { + return [ + 'title' => $this->question->getTitle(), + 'author' => $this->question->getAuthor() !== '' + ? $this->question->getAuthor() + : $this->current_user->getFullname(), + 'lifecycle' => $this->question->getLifecycle()->value, + 'remarks' => $this->question->getRemarks() + ]; + } + + private function buildAddBasicPropertiesToQuestionTrafo( + Refinery $refinery + ): Transformation { + return $refinery->custom()->transformation( + function (array $vs): Question { + $question = $this->question + ->withTitle($vs['title']) + ->withAuthor($vs['author']) + ->withRemarks($vs['remarks']); + + $lifecycle = Lifecycle::tryFrom($vs['lifecycle']); + if ($lifecycle !== null) { + return $question->withLifecycle($lifecycle); + } + + return $question; + } + ); + } + + private function buildPreviewPanel( + DefaultEnvironment $environment + ): StandardPanel { + $environment->preserveParametersForPageEditorCmds(); + + $session_key = $this->buildPreviewSessionKey(); + + $attempt_data = $this->attempt_repository->getAttemptFromPreviewData( + $this->question, + \ilSession::get($session_key) ?? '' + ); + + if (!\ilSession::has($session_key)) { + \ilSession::set( + $session_key, + $attempt_data->toPreviewStorage() + ); + } + + return $environment->getUIFactory()->panel()->standard( + $environment->getLanguage()->txt('preview'), + [ + $environment->getUIFactory()->button()->primary( + $environment->getLanguage()->txt('edit'), + $this->ctrl->getLinkTargetByClass(\QstsQuestionPageGUI::class, 'edit') + ), + $environment->getUIFactory()->button()->standard( + $environment->getLanguage()->txt('reset_preview'), + $environment + ->withSubActionParameter(self::CMD_RESET_PREVIEW) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ), + ...$this->buildPreviewPanelQuestionContent( + $environment, + $attempt_data + ) + ] + ); + } + + private function buildPreviewPanelQuestionContent( + DefaultEnvironment $environment, + Attempt $attempt_data + ): array { + $content = [ + $environment->getUIFactory()->legacy()->content( + $this->buildQuestionForm( + $environment, + $attempt_data + ) + ) + ]; + + if ($attempt_data->getResponseForQuestion($this->question->getId()) !== null) { + $content[] = $environment->getUIFactory()->divider()->horizontal(); + $content[] = $environment->getUIFactory()->panel()->standard( + $environment->getLanguage()->txt('feedback'), + $this->question->getParticipantView( + $environment->getLanguage(), + $environment->getRefinery(), + $environment->getUIFactory(), + $this->required_capabilities, + $attempt_data, + false, + true, + true, + true + )->getUI() + ); + } + + return $content; + } + + private function buildQuestionForm( + DefaultEnvironment $environment, + Attempt $attempt_data + ): string { + $tpl = new \ilTemplate( + 'tpl.qsts_preview_presentation_interactive.html', + true, + true, + 'components/ILIAS/Questions' + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_FORM_ACTION, + $environment + ->withSubActionParameter(self::CMD_SEND_RESPONSE) + ->getUrlBuilder() + ->buildURI() + ->__toString() + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_QUESTION_OUTPUT, + $this->ui_renderer->render( + $this->question->getParticipantView( + $environment->getLanguage(), + $environment->getRefinery(), + $environment->getUIFactory(), + $this->required_capabilities, + $attempt_data + )->getUI() + ) + ); + + $tpl->setVariable( + self::TEMPLATE_VARIABLE_SUBMIT_BUTTON_LABEL, + $environment->getLanguage()->txt('send') + ); + + return $tpl->get(); + } + + private function sendResponse( + DefaultEnvironment $environment + ) { + $session_key = $this->buildPreviewSessionKey(); + $attempt = $this->attempt_repository->getAttemptFromPreviewData( + $this->question, + \ilSession::get($session_key) ?? '' + ); + + \ilSession::set( + $session_key, + $attempt->withResponse( + $this->retrieveResponse() + )->toPreviewStorage() + ); + + return $this->buildBasicPropertiesEditingForm($environment) + ->withContentAfterForm( + $this->buildPreviewPanel($environment) + ); + } + + private function resetPreview( + DefaultEnvironment $environment + ): EditForm { + \ilSession::clear($this->buildPreviewSessionKey()); + return $this->buildBasicPropertiesEditingForm($environment) + ->withContentAfterForm( + $this->buildPreviewPanel($environment) + ); + } + + private function retrieveResponse(): Response + { + $response = $this->attempt_repository->getNewResponseFor( + $this->question->getId(), + $this->uuid_factory->uuid4() + ); + + $response_with_data = array_reduce( + $this->question->retrieveAnswerFormResponsesFromPost( + $this->required_capabilities, + $this->post_wrapper, + $response->getId() + ), + fn(Response $c, AnswerFormResponse $v): Response + => $c->withAnswerFormResponse($v), + $response + ); + + if ($this->required_capabilities->isMarkingRequired()) { + return $this->question->addAwardedPointsToResponse($response_with_data); + } + + return $response_with_data; + } + + private function buildPreviewSessionKey(): string + { + return self::SESSION_VAR_RESPONSE_DATA + . "_{$this->question->getId()->toString()}"; + } +} diff --git a/components/ILIAS/Questions/src/Question/Views/Participant.php b/components/ILIAS/Questions/src/Question/Views/Participant.php new file mode 100644 index 000000000000..40385e1e1f26 --- /dev/null +++ b/components/ILIAS/Questions/src/Question/Views/Participant.php @@ -0,0 +1,82 @@ +attempt_data?->getId(); + } + + #[\Override] + public function getUI(): array + { + $question_page = new \QstsQuestionPageGUI( + $this->question, + $this->question->getParentObjId(), + $this->required_capabilities, + $this->view_configuration + )->withAttemptData($this->attempt_data); + $question_page->setPresentationTitle($this->question->getTitle()); + + + if ($this->view_configuration->showMarks()) { + $content[] = $this->ui_factory->listing()->characteristicValue()->text( + [ + $this->lng->txt('awarded_points') => $this->refinery->kindlyTo()->string()->transform( + $this->attempt_data?->getResponseForQuestion( + $this->question->getId() + )?->getAwardedPoints() ?? 0 + ) + ] + ); + $content[] = $this->ui_factory->divider()->horizontal(); + } + + $content[] = $this->ui_factory->legacy()->content( + $question_page->presentation() + ); + + return $content; + } +} diff --git a/components/ILIAS/Questions/src/Setup/Agent.php b/components/ILIAS/Questions/src/Setup/Agent.php new file mode 100644 index 000000000000..266e1c1071f1 --- /dev/null +++ b/components/ILIAS/Questions/src/Setup/Agent.php @@ -0,0 +1,166 @@ + $answer_form_migrations + * @param array<\ILIAS\Questions\AnswerForm\Capabilities\Migration> $capability_migrations + */ + public function __construct( + private readonly PersistenceFactory $persistence_factory, + private readonly TableNameBuilder $question_table_names_builder, + private readonly array $answer_form_migrations, + private readonly array $capability_migrations + ) { + } + + public function hasConfig(): bool + { + return false; + } + + public function getArrayToConfigTransformation(): Transformation + { + throw new LogicException(self::class . ' has no Config.'); + } + + #[\Override] + public function getUpdateObjective( + ?Config $config = null + ): Objective { + return new ObjectiveCollection( + 'Database is updated for ILIAS\Questions', + false, + new \ilDatabaseUpdateStepsExecutedObjective( + new OverarchingQuestionTables( + $this->question_table_names_builder + ) + ), + new \ilDatabaseUpdateStepsExecutedObjective( + new ClozeQuestionTables( + new SetupTableNameBuilder( + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ), + new ClozeTableDefinitions( + $this->persistence_factory, + new TableSubNameSpace( + 'ILIAS', + 'cloze' + ) + ) + ) + ), + new \ilDatabaseUpdateStepsExecutedObjective( + new TempTables() + ), + new \ilTreeAdminNodeAddedObjective( + 'qsts', + 'Questions' + ) + ); + } + + #[\Override] + public function getStatusObjective( + Storage $storage + ): Objective { + return new ObjectiveCollection( + 'ILIAS\Questions', + true, + new \ilDatabaseUpdateStepsMetricsCollectedObjective( + $storage, + new OverarchingQuestionTables( + $this->question_table_names_builder + ) + ), + new \ilDatabaseUpdateStepsMetricsCollectedObjective( + $storage, + new ClozeQuestionTables( + new SetupTableNameBuilder( + new TableSubNameSpaceCore('cloze') + ) + ) + ) + ); + } + + #[\Override] + public function getMigrations(): array + { + return [ + new QuestionsMigration( + $this->persistence_factory, + $this->question_table_names_builder, + new QuestionTableDefinitions( + $this->persistence_factory + ), + new AnswerFormGenericTableDefinitions( + $this->persistence_factory + ), + $this->answer_form_migrations, + $this->capability_migrations + ) + ]; + } + + #[\Override] + public function getBuildObjective(): Objective + { + return new NullObjective(); + } + + #[\Override] + public function getInstallObjective( + ?Config $config = null + ): Objective { + return new NullObjective(); + } + + + #[\Override] + public function getNamedObjectives( + ?Config $config = null + ): array { + return new NullObjective(); + } +} diff --git a/components/ILIAS/Questions/src/Setup/ClozeQuestionTables.php b/components/ILIAS/Questions/src/Setup/ClozeQuestionTables.php new file mode 100644 index 000000000000..ab3f17b0db7c --- /dev/null +++ b/components/ILIAS/Questions/src/Setup/ClozeQuestionTables.php @@ -0,0 +1,300 @@ +db = $db; + } + + public function step_1(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::TypeSpecificAnswerForms + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'scoring_identical_responses' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 32, + 'notnull' => true + ], + 'combinations_enabled' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 1, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['answer_form_id'])) { + $this->db->addPrimaryKey($table_name, ['answer_form_id']); + } + } + + public function step_2(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::AnswerInputs + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'position' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => true + ], + 'gap_type' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 32, + 'notnull' => true + ], + 'max_chars' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => false + ], + 'step_size' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ], + 'text_matching_method' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 32, + 'notnull' => false + ], + 'min_autocomplete' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => false + ], + 'shuffle_answer_options' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 1, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['answer_form_id'])) { + $this->db->addIndex($table_name, ['answer_form_id'], 'af'); + } + } + + public function step_3(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::AnswerOptions + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_input_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'position' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => true + ], + 'text_value' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => false + ], + 'lower_limit' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ], + 'upper_limit' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ], + 'points' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['answer_input_id'])) { + $this->db->addIndex($table_name, ['answer_input_id'], 'ai'); + } + } + + public function step_4(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationsTableIdentifier() + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'points' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['answer_form_id'])) { + $this->db->addIndex($table_name, ['answer_form_id'], 'ai'); + } + } + + public function step_5(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::Additional, + $this->table_definitions->getCombinationToAnswerOptionsTableIdentifier() + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'combination_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'gap_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_option_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'in_range' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 16, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['combination_id', 'gap_id'])) { + $this->db->addPrimaryKey($table_name, ['combination_id', 'gap_id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['combination_id'])) { + $this->db->addIndex($table_name, ['combination_id'], 'ci'); + } + } + + public function step_6(): void + { + $table_name = $this->table_names_builder->getTableNameFor( + AnswerFormSpecificTableTypes::Responses + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'response_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_input_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'selected_answer_option' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => false + ], + 'text' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['response_id', 'answer_input_id'])) { + $this->db->addPrimaryKey($table_name, ['response_id', 'answer_input_id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['response_id'])) { + $this->db->addIndex($table_name, ['response_id'], 'r'); + } + } +} diff --git a/components/ILIAS/Questions/src/Setup/OverarchingQuestionTables.php b/components/ILIAS/Questions/src/Setup/OverarchingQuestionTables.php new file mode 100644 index 000000000000..82ce74a091e2 --- /dev/null +++ b/components/ILIAS/Questions/src/Setup/OverarchingQuestionTables.php @@ -0,0 +1,465 @@ +db = $db; + } + + public function step_1(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + QuestionTableTypes::Questions + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'page_id' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 4, + 'notnull' => true + ], + 'title' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 512, + 'notnull' => true + ], + 'author' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 512, + 'notnull' => false + ], + 'lifecycle' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 16, + 'notnull' => true + ], + 'remarks' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => false + ], + 'original_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => false + ], + 'last_update' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 8, + 'notnull' => true + ], + 'created' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 8, + 'notnull' => true + ], + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + } + + public function step_2(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + AnswerFormGenericTableTypes::AnswerForms + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'type' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => true + ], + 'question_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'available_points' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ], + 'image_size' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => false + ], + 'shuffle_answer_options' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 1, + 'notnull' => false + ], + 'additional_text' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ], + 'additional_text_legacy' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['question_id'])) { + $this->db->addIndex($table_name, ['question_id'], 'q'); + } + } + + public function step_3(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + QuestionTableTypes::Responses + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'attempt_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'question_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'create_timestamp' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 8, + 'notnull' => true + ], + 'awarded_points' => [ + 'type' => FieldDefinition::T_FLOAT, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['question_id'])) { + $this->db->addIndex($table_name, ['question_id'], 'q'); + } + } + + public function step_4(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + QuestionTableTypes::Linking + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'question_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'obj_id' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 4, + 'notnull' => true + ], + 'position' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 2, + 'notnull' => false + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['question_id'])) { + $this->db->addPrimaryKey($table_name, ['question_id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['obj_id'])) { + $this->db->addIndex($table_name, ['obj_id'], 'o'); + } + } + + public function step_5(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + QuestionTableTypes::MigrationsTable + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'new_question_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'old_question_id' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 4, + 'notnull' => false + ], + 'success' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 1, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields( + $table_name, + ['old_question_id'] + )) { + $this->db->addPrimaryKey( + $table_name, + ['old_question_id'] + ); + } + } + + public function step_6(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + TextFeedbackTableTypes::FeedbackGeneric + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'feedback_best_response' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ], + 'feedback_best_response_legacy' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ], + 'feedback_other_response' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ], + 'feedback_other_response_legacy' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields( + $table_name, + ['answer_form_id'] + )) { + $this->db->addPrimaryKey( + $table_name, + ['answer_form_id'] + ); + } + } + + public function step_7(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + TextFeedbackTableTypes::FeedbackSpecific + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'parent_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'condition' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => false + ], + 'feedback' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ], + 'feedback_legacy' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields( + $table_name, + ['id'] + )) { + $this->db->addPrimaryKey( + $table_name, + ['id'], + ); + } + + $this->db->manipulate( + "CREATE UNIQUE INDEX IF NOT EXISTS apc_idx ON {$table_name}" . PHP_EOL + . '(`answer_form_id`, `parent_id`, `condition`)' + ); + } + + public function step_8(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + SuggestedContentTableTypes::SuggestedLearningContent + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'answer_form_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'type' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 32, + 'notnull' => false + ], + 'content' => [ + 'type' => FieldDefinition::T_CLOB, + 'notnull' => true + ] + ]); + } + + if (!$this->db->primaryExistsByFields( + $table_name, + ['answer_form_id'] + )) { + $this->db->addPrimaryKey( + $table_name, + ['answer_form_id'], + ); + } + } + + public function step_9(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + AttemptTableTypes::AttemptData + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'shuffler_seed' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 8, + 'notnull' => true + ], + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['id'])) { + $this->db->addPrimaryKey($table_name, ['id']); + } + } + + public function step_10(): void + { + $table_name = $this->basic_table_names_builder->getTableNameFor( + AttemptTableTypes::AdditionalAttemptData + ); + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'attempt_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'parent_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'data' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => true + ], + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['attempt_id', 'parent_id'])) { + $this->db->addPrimaryKey($table_name, ['attempt_id', 'parent_id']); + } + + if (!$this->db->indexExistsByFields($table_name, ['attempt_id'])) { + $this->db->addIndex($table_name, ['attempt_id'], 'aid'); + } + } +} diff --git a/components/ILIAS/Questions/src/Setup/QuestionsMigration.php b/components/ILIAS/Questions/src/Setup/QuestionsMigration.php new file mode 100644 index 000000000000..afc5b0741b8a --- /dev/null +++ b/components/ILIAS/Questions/src/Setup/QuestionsMigration.php @@ -0,0 +1,460 @@ + $answer_form_migrations + * @param array<\ILIAS\Questions\AnswerForm\Capabilities\Migration> $capability_migrations + */ + public function __construct( + private readonly PersistenceFactory $persistence_factory, + private readonly TableNameBuilder $question_table_names_builder, + private readonly QuestionTableDefinitions $question_table_definitions, + private readonly AnswerFormGenericTableDefinitions $answer_form_generic_table_definitions, + array $answer_form_migrations, + private readonly array $capability_migrations + ) { + $this->answer_form_migrations = array_reduce( + $answer_form_migrations, + function (array $c, AnswerFormMigration $v): array { + $c[$v->getOldQuestionTypeIdentifier()] = $v; + return $c; + }, + [] + ); + } + + #[\Override] + public function getLabel(): string + { + return 'Migrate questions to Questions Component.'; + } + + #[\Override] + public function getDefaultAmountOfStepsPerRun(): int + { + return 100; + } + + #[\Override] + public function getPreconditions(Environment $environment): array + { + return [new \ilDatabaseInitializedObjective()]; + } + + #[\Override] + public function prepare(Environment $environment): void + { + $this->db = $environment->getResource(Setup\Environment::RESOURCE_DATABASE); + $this->io = $environment->getResource(Setup\Environment::RESOURCE_ADMIN_INTERACTION); + $this->uuid_factory = new UuidFactory(); + } + + #[\Override] + public function step( + Environment $environment + ): void { + $db_values = $this->fetchValidRecord(); + + if ($db_values === null) { + return; + } + + if ($db_values->obj_fi === 0) { + $db_values->obj_fi = $this->getObjIdFromLearningModulMapping($db_values->question_id); + } + + if ($db_values->obj_fi === null) { + $this->io->error( + "The question with the id {$db_values->question_id} could not be " + . "migrated as it doesn't belong to any object." + ); + return; + } + + /** @var \ILIAS\Questions\AnswerForm\Migration\Migration $answer_form_migration */ + $answer_form_migration = $this->answer_form_migrations[$db_values->type_tag]; + + $new_question_id = $this->uuid_factory->uuid4(); + + $migration_insert = $answer_form_migration->completeMigrationInsert( + $environment, + $this->buildMigrationInsert( + $answer_form_migration, + [ + $this->buildInsertLinkingStatement( + $new_question_id, + $db_values->obj_fi, + $db_values->sequence + ), + $this->buildInsertQuestionStatement( + $new_question_id, + $db_values->title, + $db_values->author, + Lifecycle::tryFrom($db_values->lifecycle), + $db_values->description, + $db_values->original_id, + $db_values->created + ), + $this->buildInsertMigrationStatement( + $db_values->question_id, + $new_question_id + ) + ], + $new_question_id, + $db_values + ) + ); + + if ($migration_insert === null) { + $this->db->manipulate( + $this->buildInsertMigrationStatement( + $db_values->question_id, + null + )->toManipulateString($this->db) + ); + $this->io->inform( + "{$db_values->question_id} could not be migrated due to missing question data." + ); + return; + } + + array_reduce( + $this->capability_migrations, + fn(AnswerFormMigrationInsert $c, CapabilityMigration $v): AnswerFormMigrationInsert + => $v->completeMigrationInsert( + $environment, + $answer_form_migration, + $c + ), + $migration_insert + )->run(); + $this->io->inform("{$new_question_id->toString()} successfully migrated."); + } + + #[\Override] + public function getRemainingAmountOfSteps(): int + { + $migration_table_name = $this->question_table_names_builder + ->getTableNameFor(QuestionTableTypes::MigrationsTable); + + $query = $this->db->query( + 'SELECT COUNT(question_id) cnt FROM ' . self::OLD_QUESTIONS_TABLE . ' q' . PHP_EOL + . 'JOIN ' . self::OLD_QUESTION_TYPE_TABLE . ' t ON q.question_type_fi = t.question_type_id' . PHP_EOL + . "LEFT JOIN {$migration_table_name}" + . ' m ON q.question_id = m.old_question_id' . PHP_EOL + . 'WHERE t.type_tag IN (' + . implode( + ', ', + array_map( + fn(AnswerFormMigration $v): string => "'{$v->getOldQuestionTypeIdentifier()}'", + $this->answer_form_migrations + ) + ) . ')' . PHP_EOL + . 'AND q.complete = 1' . PHP_EOL + . 'AND m.old_question_id IS NULL' + ); + return $this->db->fetchObject( + $query + )->cnt; + } + + private function fetchValidRecord(): ?\stdClass + { + $migration_table_name = $this->question_table_names_builder + ->getTableNameFor(QuestionTableTypes::MigrationsTable); + + $query = $this->db->query( + 'SELECT q.*, t.type_tag, s.sequence FROM ' . self::OLD_QUESTIONS_TABLE . ' q' . PHP_EOL + . 'JOIN ' . self::OLD_QUESTION_TYPE_TABLE . ' t ON q.question_type_fi = t.question_type_id' . PHP_EOL + . "LEFT JOIN {$migration_table_name}" + . ' m ON q.question_id = m.old_question_id' . PHP_EOL + . 'LEFT JOIN ' . self::TEST_QUESTIONS_SEQUENCE_TABLE . ' s ON q.question_id = s.question_fi' . PHP_EOL + . 'WHERE t.type_tag IN (' + . implode( + ', ', + array_map( + fn(AnswerFormMigration $v): string => "'{$v->getOldQuestionTypeIdentifier()}'", + $this->answer_form_migrations + ) + ) . ')' . PHP_EOL + . 'AND q.complete = 1' . PHP_EOL + . 'AND m.old_question_id IS NULL' + ); + + do { + $db_values = $this->db->fetchObject($query); + if ($db_values === null) { + return null; + } + } while (!$this->areDbValuesValid($db_values)); + + $db_values->original_id = $this->cleanupAndMigrateOriginalId($db_values->original_id); + return $db_values; + } + + private function areDbValuesValid( + \stdClass $db_values + ): bool { + if ($db_values->original_id === null) { + return true; + } + + if ($this->allready_migrated_questions === null) { + $this->loadAlreadyMigratedQuestions(); + } + + if (isset($this->allready_migrated_questions[$db_values->original_id])) { + return true; + } + + return false; + } + + private function cleanupAndMigrateOriginalId( + ?int $original_id + ): ?Uuid { + if ($original_id === null + || in_array($original_id, $this->allready_migrated_questions_in_qpls)) { + return null; + } + return $this->uuid_factory->fromString( + $this->allready_migrated_questions[$original_id] + ); + } + + private function loadAlreadyMigratedQuestions(): void + { + $migration_table_name = $this->question_table_names_builder + ->getTableNameFor(QuestionTableTypes::MigrationsTable); + $linking_table_name = $this->question_table_names_builder + ->getTableNameFor(QuestionTableTypes::Linking); + + $query = $this->db->query( + "SELECT m.*, o.type FROM {$migration_table_name} m" . PHP_EOL + . "JOIN {$linking_table_name} l" . PHP_EOL + . 'ON m.new_question_id = l.question_id' . PHP_EOL + . 'JOIN object_data o ON l.obj_id = o.obj_id' . PHP_EOL + ); + + $this->allready_migrated_questions = []; + $this->allready_migrated_questions_in_qpls = []; + while (($row = $this->db->fetchObject($query)) !== null) { + $this->allready_migrated_questions[$row->old_question_id] = $row->new_question_id; + if ($row->type === 'qpl') { + $this->allready_migrated_questions_in_qpls[] = $row->new_question_id; + } + } + } + + private function getObjIdFromLearningModulMapping( + int $question_id + ): ?int { + if ($this->question_to_learning_module_mapping === null) { + $this->loadQuestionsToLearningModuleMapping(); + } + + return $this->question_to_learning_module_mapping[$question_id] ?? null; + } + + private function loadQuestionsToLearningModuleMapping(): void + { + + $query = $this->db->query( + 'SELECT question_id, obj_id FROM page_question pq' . PHP_EOL + . 'JOIN page_object po ON pq.page_id = po.page_id' . PHP_EOL + . 'AND pq.page_parent_type = po.parent_type' . PHP_EOL + . 'JOIN object_data o ON po.parent_id = o.obj_id' . PHP_EOL + . 'WHERE page_parent_type = "lm"' + ); + + $this->question_to_learning_module_mapping = []; + while (($row = $this->db->fetchObject($query)) !== null) { + $this->question_to_learning_module_mapping[$row->question_id] = $row->obj_id; + } + } + + private function buildInsertLinkingStatement( + Uuid $new_question_id, + int $obj_id, + ?int $position + ): Insert { + return $this->persistence_factory->insert( + $this->question_table_definitions->getColumns( + $this->question_table_names_builder, + QuestionTableTypes::Linking + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $new_question_id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $obj_id + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $position + ) + ] + ); + } + + private function buildInsertQuestionStatement( + Uuid $id, + string $title, + string $author, + Lifecycle $lifecycle, + string $remarks, + ?Uuid $original_id, + int $create_date + ): Insert { + return $this->persistence_factory->insert( + $this->question_table_definitions->getColumns( + $this->question_table_names_builder, + QuestionTableTypes::Questions + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $id->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + 0 + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $title + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $author + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $lifecycle->value + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $remarks + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $original_id?->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + time() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $create_date + ) + ] + ); + } + + private function buildInsertMigrationStatement( + int $old_question_id, + ?Uuid $new_question_id + ): Insert { + return $this->persistence_factory->insert( + $this->question_table_definitions->getColumns( + $this->question_table_names_builder, + QuestionTableTypes::MigrationsTable + ), + [ + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $old_question_id + ), + $this->persistence_factory->value( + FieldDefinition::T_TEXT, + $new_question_id?->toString() + ), + $this->persistence_factory->value( + FieldDefinition::T_INTEGER, + $new_question_id === null + ? '0' + : '1' + ) + ] + ); + } + + private function buildMigrationInsert( + AnswerFormMigration $answer_form_migration, + array $question_inserts, + Uuid $new_question_id, + \stdClass $db_values + ): AnswerFormMigrationInsert { + return new AnswerFormMigrationInsert( + $this->db, + $this->io, + $this->uuid_factory, + $this->persistence_factory, + $this->answer_form_generic_table_definitions, + QuestionRepository::COMPONENT_NAMESPACE, + $question_inserts, + $db_values->question_id, + $new_question_id, + $this->uuid_factory->uuid4(), + $answer_form_migration->getDefinitionClass(), + $db_values->add_cont_edit_mode === \assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_IPE + ); + } +} diff --git a/components/ILIAS/Questions/src/Setup/SetupTableNameBuilder.php b/components/ILIAS/Questions/src/Setup/SetupTableNameBuilder.php new file mode 100644 index 000000000000..e1d97883d442 --- /dev/null +++ b/components/ILIAS/Questions/src/Setup/SetupTableNameBuilder.php @@ -0,0 +1,35 @@ +db = $db; + } + + public function step_1(): void + { + $table_name = AttemptRepository::TABLE_NAME; + + if (!$this->db->tableExists($table_name)) { + $this->db->createTable($table_name, [ + 'user_id' => [ + 'type' => FieldDefinition::T_INTEGER, + 'length' => 4, + 'notnull' => true + ], + 'attempt_id' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 64, + 'notnull' => true + ], + 'solved_questions' => [ + 'type' => FieldDefinition::T_TEXT, + 'length' => 4000, + 'notnull' => true, + 'default' => '' + ] + ]); + } + + if (!$this->db->primaryExistsByFields($table_name, ['user_id'])) { + $this->db->addPrimaryKey($table_name, ['user_id']); + } + } +} diff --git a/components/ILIAS/Questions/src/UserSettings/CreateMode.php b/components/ILIAS/Questions/src/UserSettings/CreateMode.php new file mode 100644 index 000000000000..e44c5266b3b6 --- /dev/null +++ b/components/ILIAS/Questions/src/UserSettings/CreateMode.php @@ -0,0 +1,180 @@ +settings = new \ilSetting('questions'); + } + #[\Override] + public function getIdentifier(): string + { + return 'question_create_mode'; + } + + #[\Override] + public function isAvailable(): bool + { + return true; + } + + #[\Override] + public function getLabel(Language $lng): string + { + return $lng->txt('question_create_mode'); + } + + #[\Override] + public function getSettingsPage(): AvailablePages + { + return AvailablePages::MainSettings; + } + + #[\Override] + public function getSection(): AvailableSections + { + return AvailableSections::Additional; + } + + #[\Override] + public function getInput( + FieldFactory $field_factory, + Language $lng, + Refinery $refinery, + \ilSetting $settings, + ?\ilObjUser $user = null + ): Input { + $lng->loadLanguageModule('questions'); + return array_reduce( + CreateModes::cases(), + fn(Radio $c, CreateModes $v): Radio => $c->withOption( + $v->value, + $v->getLabelForInput($lng), + $v->getBylineForInput($lng) + ), + $field_factory->radio( + $lng->txt('question_create_mode') + ) + )->withValue( + $user !== null + ? $this->retrieveValueFromUser($user) + : $this->settings->get( + 'default_create_mode', + CreateModes::getDefaultMode()->value + ) + ); + } + + #[\Override] + public function getLegacyInput( + Language $lng, + \ilSetting $settings, + ?\ilObjUser $user = null + ): \ilFormPropertyGUI { + $lng->loadLanguageModule('questions'); + $input = array_reduce( + CreateModes::cases(), + function ( + \ilRadioGroupInputGUI $c, + CreateModes $v + ) use ($lng): \ilRadioGroupInputGUI { + $c->addOption( + new \ilRadioOption( + $v->getLabelForInput($lng), + $v->value, + $v->getBylineForInput($lng) + ) + ); + return $c; + }, + new \ilRadioGroupInputGUI($lng->txt('question_create_mode')) + ); + + $input->setValue( + $user !== null + ? $this->retrieveValueFromUser($user) + : $this->settings->get( + 'default_create_mode', + CreateModes::getDefaultMode()->value + ) + ); + return $input; + } + + #[\Override] + public function getDefaultValueForDisplay( + Language $lng, + \ilSetting $settings + ): string { + return CreateModes::getDefaultMode()->getLabelForInput($lng); + } + + #[\Override] + public function hasUserPersonalizedSetting( + \ilSetting $settings, + \ilObjUser $user + ): bool { + return $this->retrieveValueFromUser($user) + !== $this->settings->get( + 'default_create_mode', + CreateModes::getDefaultMode()->value + ); + } + + #[\Override] + public function persistUserInput( + \ilObjUser $user, + mixed $input + ): \ilObjUser { + $user->setPref( + 'question_create_mode', + $input !== null + ? $input + : $this->settings->get( + 'default_create_mode', + CreateModes::getDefaultMode()->value + ) + ); + return $user; + } + + #[\Override] + public function retrieveValueFromUser(\ilObjUser $user): string + { + return $user->getPref('question_create_mode') + ?? $this->settings->get( + 'default_create_mode', + CreateModes::getDefaultMode()->value + ); + } +} diff --git a/components/ILIAS/Questions/src/UserSettings/CreateModes.php b/components/ILIAS/Questions/src/UserSettings/CreateModes.php new file mode 100644 index 000000000000..ee6e8c97169f --- /dev/null +++ b/components/ILIAS/Questions/src/UserSettings/CreateModes.php @@ -0,0 +1,46 @@ +txt("create_mode_{$this->value}"); + } + + public function getBylineForInput( + Language $lng + ): string { + return $lng->txt("byline_create_mode_{$this->value}"); + } + + public static function getDefaultMode(): self + { + return self::Simple; + } +} diff --git a/components/ILIAS/Questions/src/UserSettings/Settings.php b/components/ILIAS/Questions/src/UserSettings/Settings.php new file mode 100644 index 000000000000..959f42df91b3 --- /dev/null +++ b/components/ILIAS/Questions/src/UserSettings/Settings.php @@ -0,0 +1,34 @@ + + + {ICON_OK} + \ No newline at end of file diff --git a/components/ILIAS/Questions/templates/default/tpl.cloze_gap_numeric.html b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_numeric.html new file mode 100755 index 000000000000..26110f460c00 --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_numeric.html @@ -0,0 +1,2 @@ + size="{TEXT_GAP_SIZE}" maxlength="{TEXT_GAP_SIZE}" /> + diff --git a/components/ILIAS/Questions/templates/default/tpl.cloze_gap_select.html b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_select.html new file mode 100755 index 000000000000..fd86a5c57dfb --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_select.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/components/ILIAS/Questions/templates/default/tpl.cloze_gap_static.html b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_static.html new file mode 100755 index 000000000000..e5cf7503b46f --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_static.html @@ -0,0 +1 @@ +{SOLUTION_VALUE} \ No newline at end of file diff --git a/components/ILIAS/Questions/templates/default/tpl.cloze_gap_text.html b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_text.html new file mode 100755 index 000000000000..bf213ad6472d --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.cloze_gap_text.html @@ -0,0 +1 @@ + size="{TEXT_GAP_SIZE}" maxlength="{TEXT_GAP_SIZE}"/> \ No newline at end of file diff --git a/components/ILIAS/Questions/templates/default/tpl.qsts_async.html b/components/ILIAS/Questions/templates/default/tpl.qsts_async.html new file mode 100644 index 000000000000..2df34a01b580 --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.qsts_async.html @@ -0,0 +1,7 @@ +
+
+ {ANSWER_FORM} +
+ {CHECK_BUTTON} + +
\ No newline at end of file diff --git a/components/ILIAS/Questions/templates/default/tpl.qsts_preview_presentation_interactive.html b/components/ILIAS/Questions/templates/default/tpl.qsts_preview_presentation_interactive.html new file mode 100644 index 000000000000..96a915b096ec --- /dev/null +++ b/components/ILIAS/Questions/templates/default/tpl.qsts_preview_presentation_interactive.html @@ -0,0 +1,8 @@ +
+
+
+ {QUESTION_OUTPUT} +
+ +
+
\ No newline at end of file diff --git a/components/ILIAS/Registration/classes/class.ilAccountRegistrationGUI.php b/components/ILIAS/Registration/classes/class.ilAccountRegistrationGUI.php index 2f2ac83172bb..c69d418373c8 100755 --- a/components/ILIAS/Registration/classes/class.ilAccountRegistrationGUI.php +++ b/components/ILIAS/Registration/classes/class.ilAccountRegistrationGUI.php @@ -500,8 +500,6 @@ protected function createUser(int $a_role): string $this->userObj->updateOwner(); // setup user preferences - $this->userObj->setLanguage($this->form->getInput('usr_language')); - global $DIC; $DIC['legalDocuments']->selfRegistration()->userCreation($this->userObj); diff --git a/components/ILIAS/Repository/Administration/class.ilModulesTableGUI.php b/components/ILIAS/Repository/Administration/class.ilModulesTableGUI.php index ff9855007cc9..f3706b884100 100755 --- a/components/ILIAS/Repository/Administration/class.ilModulesTableGUI.php +++ b/components/ILIAS/Repository/Administration/class.ilModulesTableGUI.php @@ -131,7 +131,7 @@ public function getComponents(): void if ($this->obj_definition->isSystemObject($id)) { continue; } - if (in_array($id, ["lng", "rolt", "sty", "tax", "usr"])) { + if (in_array($id, ["lng", "rolt", "sty", "tax", "usr", "gdtr"])) { continue; } $obj_types[$id] = [ diff --git a/components/ILIAS/Repository/PluginSlot/class.ilObjectPluginListGUI.php b/components/ILIAS/Repository/PluginSlot/class.ilObjectPluginListGUI.php index 3ec73f1a4477..6960341f1cca 100755 --- a/components/ILIAS/Repository/PluginSlot/class.ilObjectPluginListGUI.php +++ b/components/ILIAS/Repository/PluginSlot/class.ilObjectPluginListGUI.php @@ -82,7 +82,7 @@ public function txt(string $a_str): string public function getCommandFrame(string $cmd): string { - return ilFrameTargetInfo::_getFrame("MainContent"); + return ""; } public function getProperties(): array diff --git a/components/ILIAS/Repository/Service/Form/TagsSpaceTransformation.php b/components/ILIAS/Repository/Service/Form/TagsSpaceTransformation.php new file mode 100644 index 000000000000..efc1061a17d0 --- /dev/null +++ b/components/ILIAS/Repository/Service/Form/TagsSpaceTransformation.php @@ -0,0 +1,45 @@ +values[$key] = $value; - $field = $this->ui->factory()->input()->field()->text($title, $description); + $field = $this->ui->factory()->input()->field()->text($title, $description) + ->withoutStripTags() + ->withAdditionalTransformation(new TagsSpaceTransformation()); if ($max_length > 0) { $field = $field->withMaxLength($max_length); } @@ -253,7 +255,9 @@ public function textarea( ?string $value = null ): self { $this->values[$key] = $value; - $field = $this->ui->factory()->input()->field()->textarea($title, $description); + $field = $this->ui->factory()->input()->field()->textarea($title, $description) + ->withoutStripTags() + ->withAdditionalTransformation(new TagsSpaceTransformation()); if (!is_null($value)) { $field = $field->withValue($value); } diff --git a/components/ILIAS/Repository/Service/IRSS/CollectionWrapperGUI.php b/components/ILIAS/Repository/Service/IRSS/CollectionWrapperGUI.php index f1e68d09e6b8..389d2f7af737 100755 --- a/components/ILIAS/Repository/Service/IRSS/CollectionWrapperGUI.php +++ b/components/ILIAS/Repository/Service/IRSS/CollectionWrapperGUI.php @@ -23,6 +23,7 @@ use ILIAS\ResourceStorage\Stakeholder\ResourceStakeholder; use ILIAS\components\ResourceStorage\Collections\View\Configuration; use ILIAS\components\ResourceStorage\Collections\View\Mode; +use ILIAS\components\ResourceStorage\Collections\View\OnDuplicate; class CollectionWrapperGUI { @@ -38,7 +39,8 @@ public function getResourceCollectionGUI( ResourceStakeholder $stakeholder, string $rcid, string $caption, - bool $write = false + bool $write = false, + OnDuplicate $on_duplicate = OnDuplicate::REPLACE ): \ilResourceCollectionGUI { if ($rcid === "") { throw new \LogicException("No resource collection ID given."); @@ -53,7 +55,7 @@ public function getResourceCollectionGUI( 100, $write, $write, - true + $on_duplicate ) ); } diff --git a/components/ILIAS/Repository/Service/Permission/CmdEntity.php b/components/ILIAS/Repository/Service/Permission/CmdEntity.php new file mode 100644 index 000000000000..c1209be11d6f --- /dev/null +++ b/components/ILIAS/Repository/Service/Permission/CmdEntity.php @@ -0,0 +1,40 @@ +type; + } + + public function getId(): string + { + return $this->id; + } +} diff --git a/components/ILIAS/Repository/Service/Permission/CmdPermission.php b/components/ILIAS/Repository/Service/Permission/CmdPermission.php new file mode 100644 index 000000000000..67d5640be4cf --- /dev/null +++ b/components/ILIAS/Repository/Service/Permission/CmdPermission.php @@ -0,0 +1,138 @@ +ctrl)) { + return false; + } + return $this->isCommandPermitted( + $this->getRequestCommand(), + $this->getRequestNodeId(), + (string) $this?->getRequestEntity()->getType(), + (string) $this?->getRequestEntity()->getId() + ); + } + + public function isTableCommandPermitted(string $cmd, string $entity_id): bool + { + if (is_null($this->ctrl)) { + return false; + } + return $this->isCommandPermitted( + $cmd, + $this->getRequestNodeId(), + (string) $this?->getRequestEntity()->getType(), + $entity_id + ); + } + + public function getPermittedCommand(): string + { + if ($this->isRequestCommandPermitted()) { + return $this->getRequestCommand(); + } + return ""; + } + + public function getRequestCommand(): string + { + return $this->ctrl->getCmd($this->getDefaultCommand()); + } + + protected function isClass(string $class): bool + { + if (is_null($this->ctrl)) { + return false; + } + $cmd_class = $this->ctrl->getCmdClass(); + return $cmd_class === strtolower($class); + } + + public function getDefaultCommand(): string + { + return ""; + } + + + /** + * @throws \ILIAS\Repository\Permission\ilNoCmdPermissionException + */ + public function checkCommand(string $cmd, int $node_id, string $entity, string $entity_id = ""): void + { + if (!$this->isCommandPermitted($cmd, $node_id, $entity, $entity_id)) { + throw new \ILIAS\Repository\Permission\ilNoCmdPermissionException("No permission to execute command $cmd on $entity $entity_id"); + } + } + + protected function cmdEntity( + string $type, + string $id = "" + ): CmdEntity { + return new CmdEntity( + $type, + $id + ); + } + + public function forwardPermitted( + object $from_gui, + object $to_gui + ): mixed { + if (is_null($this->ctrl)) { + return null; + } + if ($this->isForwardPermitted(get_class($from_gui), get_class($to_gui))) { + return $this->ctrl->forwardCommand($to_gui); + } + if ($this->access->checkAccess("read", "", ROOT_FOLDER_ID)) { + $this->tpl->setOnScreenMessage('failure', $this->lng->txt('permission_denied'), true); + $this->ctrl->setParameterByClass("ilRepositoryGUI", "ref_id", ROOT_FOLDER_ID); + $this->ctrl->redirectByClass("ilRepositoryGUI"); + } + throw new \ilPermissionException($this->lng->txt("permission_denied")); + } + + /** + * For intermediate solutions that don't implement the concept for all subclasses yet + */ + public function classImplementsMethodDirectly(string $className, string $method): bool + { + try { + $class = new \ReflectionClass($className); + } catch (\Exception $e) { + return false; + } + + return $class->hasMethod($method) + && $class->getMethod($method)->getDeclaringClass()->getName() === $class->getName(); + } +} diff --git a/components/ILIAS/Repository/Service/Permission/CmdPermissionInterface.php b/components/ILIAS/Repository/Service/Permission/CmdPermissionInterface.php new file mode 100644 index 000000000000..1d34015a994f --- /dev/null +++ b/components/ILIAS/Repository/Service/Permission/CmdPermissionInterface.php @@ -0,0 +1,72 @@ +archives = $archives; $this->legacy_archives = $legacy_archives; + $this->file_service_settings = $file_service_settings; } public function zip(): ZipAdapter { return new ZipAdapter( $this->archives, - $this->legacy_archives + $this->legacy_archives, + $this->file_service_settings ); } } diff --git a/components/ILIAS/Repository/Service/Resources/ZipAdapter.php b/components/ILIAS/Repository/Service/Resources/ZipAdapter.php index ec7638ce78f6..c85010871d68 100644 --- a/components/ILIAS/Repository/Service/Resources/ZipAdapter.php +++ b/components/ILIAS/Repository/Service/Resources/ZipAdapter.php @@ -21,37 +21,131 @@ namespace ILIAS\Repository\Resources; use ILIAS\Filesystem\Util\Archive\Archives; -use ILIAS\Filesystem\Util\Archive\UnzipOptions; use ILIAS\Filesystem\Stream\Streams; use ILIAS\Export\ImportStatus\Exception\ilException; use ILIAS\Filesystem\Util\Archive\LegacyArchives; use ILIAS\Filesystem\Util\Archive\ZipDirectoryHandling; +use RuntimeException; class ZipAdapter { protected Archives $archives; protected LegacyArchives $legacy_archives; + protected \ilFileServicesSettings $file_service_settings; public function __construct( Archives $archives, - LegacyArchives $legacy_archives + LegacyArchives $legacy_archives, + \ilFileServicesSettings $file_service_settings ) { $this->archives = $archives; $this->legacy_archives = $legacy_archives; + $this->file_service_settings = $file_service_settings; } public function unzipFile(string $filepath): void { - $unzip = $this->archives->unzip( - Streams::ofResource(fopen($filepath, 'rb')), - $this->archives->unzipOptions() - ->withZipOutputPath(dirname($filepath)) - ->withOverwrite(false) - ->withDirectoryHandling(ZipDirectoryHandling::KEEP_STRUCTURE) - ); - if (!$unzip->extract()) { - throw new ilException("Unzip failed."); + $destination_path = dirname($filepath); + $temporary_directory = $this->createTemporaryExtractionDirectory(); + + try { + $unzip = $this->archives->unzip( + Streams::ofResource(fopen($filepath, 'rb')), + $this->archives->unzipOptions() + ->withZipOutputPath($temporary_directory) + ->withOverwrite(false) + ->withDirectoryHandling(ZipDirectoryHandling::KEEP_STRUCTURE) + ); + + foreach (iterator_to_array($unzip->getPaths(), false) as $zip_path) { + $this->assertZipPathIsSafe($zip_path); + } + + if (!$unzip->extract()) { + throw new ilException("Unzip failed."); + } + + foreach (iterator_to_array($unzip->getFiles(), false) as $zip_file) { + if (!$this->isWhitelistedFile($zip_file)) { + continue; + } + $this->moveExtractedFile($temporary_directory, $destination_path, $zip_file); + } + } finally { + $this->removeDirectory($temporary_directory); + } + } + + protected function createTemporaryExtractionDirectory(): string + { + $tmp_directory = rtrim(CLIENT_DATA_DIR, '/') . '/temp/' . + 'tmp_' . bin2hex(random_bytes(16)); + \ilFileUtils::makeDirParents($tmp_directory); + return $tmp_directory; + } + + protected function assertZipPathIsSafe(string $path): void + { + $normalized_path = $this->normalizeZipPath($path); + + if ( + $normalized_path === '' + || str_contains($normalized_path, "\0") + || str_starts_with($normalized_path, '/') + || preg_match('/^[A-Za-z]:\//', $normalized_path) === 1 + ) { + throw new ilException('Zip contains an unsafe path.'); + } + + foreach (explode('/', rtrim($normalized_path, '/')) as $segment) { + if ($segment === '' || $segment === '.' || $segment === '..') { + throw new ilException('Zip contains an unsafe path.'); + } + } + } + + protected function isWhitelistedFile(string $path): bool + { + $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + return in_array($extension, $this->file_service_settings->getWhiteListedSuffixes(), true); + } + + protected function moveExtractedFile(string $temporary_directory, string $destination_path, string $zip_file): void + { + $normalized_zip_file = $this->normalizeZipPath($zip_file); + $source = $temporary_directory . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $normalized_zip_file); + $target = $destination_path . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $normalized_zip_file); + + if (!is_file($source)) { + return; + } + + $target_directory = dirname($target); + if (!is_dir($target_directory)) { + \ilFileUtils::makeDirParents($target_directory); + } + + if (file_exists($target)) { + return; + } + + if (!rename($source, $target)) { + throw new RuntimeException(sprintf('File "%s" could not be moved to "%s"', $source, $target)); + } + } + + protected function normalizeZipPath(string $path): string + { + return str_replace('\\', '/', $path); + } + + protected function removeDirectory(string $directory): void + { + if (!is_dir($directory)) { + return; } + \ilFileUtils::delDir($directory); } public function zipDirectoryToFile(string $directory, string $zip_file): void diff --git a/components/ILIAS/Repository/Service/Table/TableAdapterGUI.php b/components/ILIAS/Repository/Service/Table/TableAdapterGUI.php index 15829b48e271..14e941d83a63 100755 --- a/components/ILIAS/Repository/Service/Table/TableAdapterGUI.php +++ b/components/ILIAS/Repository/Service/Table/TableAdapterGUI.php @@ -137,7 +137,7 @@ public function linkListingColumn( string $title, bool $sortable = false ): self { - $column = $this->ui->factory()->table()->column()->linkListing($title)->withIsSortable($sortable); + $column = $this->ui->factory()->table()->column()->listing($title)->withIsSortable($sortable); $this->addColumn($key, $column); return $this; } diff --git a/components/ILIAS/Repository/Service/trait.GlobalDICDomainServices.php b/components/ILIAS/Repository/Service/trait.GlobalDICDomainServices.php index 879d1589eaf4..c332d3b1c27c 100755 --- a/components/ILIAS/Repository/Service/trait.GlobalDICDomainServices.php +++ b/components/ILIAS/Repository/Service/trait.GlobalDICDomainServices.php @@ -134,7 +134,8 @@ public function resources(): DomainService { return new DomainService( $this->DIC->archives(), - $this->DIC->legacyArchives() + $this->DIC->legacyArchives(), + $this->DIC->fileServiceSettings() ); } diff --git a/components/ILIAS/ResourceStorage/IRSS_STORAGE_AUDIT.md b/components/ILIAS/ResourceStorage/IRSS_STORAGE_AUDIT.md new file mode 100644 index 000000000000..f4d8c4aab330 --- /dev/null +++ b/components/ILIAS/ResourceStorage/IRSS_STORAGE_AUDIT.md @@ -0,0 +1,358 @@ +# IRSS Storage Audit — Components Still Storing Files Outside the IRSS + +**Goal:** map which ILIAS components still persist/read files by legacy means (`ilFileSystemGUI`, +`ilFileUtils`/`ilUtil`, raw PHP `fopen`/`file_put_contents`/`mkdir`, or `ILIAS\Filesystem` used +*directly*) instead of routing all binary content through the **IRSS** (ILIAS Resource Storage Service), +which is meant to become the single storage entry point. + +**Scope:** all 182 dirs under `components/ILIAS/`. Generated by a per-component grep signal matrix +followed by a domain-grouped read of every component with a file-storage signal. Branch: `trunk` +(`ILIAS 12.0_alpha`). Date: 2026-07-02. + +> **⚠ Note:** This report was AI-generated and may deviate from reality. Component classifications, +> verdicts, effort estimates and `file:line` references reflect an automated audit of the code at the time +> of writing and can contain errors, omissions or stale citations. Verify against the current source before +> acting on any finding. + +--- + +## How to read this + +- **IRSS** = target. Markers: `resourceStorage()`, `ResourceStorage\`, `IRSSServices`, `ResourceBuilder`, + `StorableResource`, `AbstractResourceStakeholder`, a persisted `rid` column. +- **Legacy** = anything else that touches disk for *persistent domain content*: + 1. `ilFileSystemGUI` (legacy file browser) + 2. `ilFileUtils::` / `ilUtil::` file helpers (`makeDir`, `moveUploadedFile`, `getWebspaceDir`, `delDir`, `zip`, …) + 3. raw PHP fs (`fopen`, `fwrite`, `file_put_contents`, `move_uploaded_file`, `mkdir`, `copy`, `unlink`, …) + 4. `ILIAS\Filesystem` service used **directly** (`$DIC->filesystem()->web()/storage()/temp()`) — note IRSS + uses this service *internally*, so calling it directly is a bypass. + +### Architectural ground truth + +> IRSS never touches disk itself. `ResourceStorage` orchestrates; it injects a `Filesystem $fs` into its +> storage handlers (`ResourceStorage/src/StorageHandler/FileSystemBased/AbstractFileSystemStorageHandler.php:54`), +> which wraps `league/flysystem`'s `LocalFilesystemAdapter` +> (`Filesystem/src/Provider/FlySystem/FlySystemLocalFilesystemFactory.php:68`). So **Filesystem is the backend, +> ResourceStorage is IRSS, FileUpload is ingest, VirusScanner is a scan preprocessor, FileDelivery is egress, +> WebAccessChecker is legacy egress being retired.** Everything else is a consumer. + +### Verdict legend + +| Verdict | Meaning | +|---|---| +| **MIGRATED** | Persistent domain files stored via IRSS. Remaining disk I/O is only transient (temp/zip/export). | +| **PARTIAL** | Some persistent content on IRSS, some still on legacy disk. | +| **LEGACY** | Persistent domain content stored on disk, no IRSS. | +| **N/A** | No persistent file storage of its own (DB-backed, delegates to another component, or pure infra/temp). | +| **INFRA** | Part of the storage stack itself (backend / ingest / egress / scan / setup). | + +--- + +## Master table + +### Still to migrate — LEGACY (persistent content on disk, no IRSS) + +| Component | What persists on disk (legacy) | Mechanism | ~sites | Effort | +|---|---|---|---|---| +| **Course** | course file attachments (info tab), member exports, info HTML | `ilFSStorageCourse` / `ilFileDataCourse` (`ilFileSystemAbstractionStorage`) + raw fs | ~20 | high | +| **ScormAicc** | SCORM/AICC package tree `public/data/…/lm_data/lm_`, manifest | base `ilObjSAHSLearningModule::getDataDirectory` + **`ilFileSystemGUI`** + raw fs | ~30 | high | +| **Scorm2004** | SCORM 2004 package (webspace), imsmanifest, per-user tracking logs on disk | inherits SAHS dir + `fopen`/`fwrite`/`file_put_contents`; **`ilFileSystemGUI`** wired | ~30 | high | +| **LearningModule** | `lm_data/lm_` import/export/offline tree, subtitles | `ilFileUtils::makeDir/delDir/zip` + `fopen`/`fwrite` | ~25 | medium | +| **SurveyQuestionPool** | question images + material uploads (`CLIENT_WEB_DIR/survey/…`) | `ilFileUtils::moveUploadedFile` + `getImagePathWeb` | ~29 | medium | +| **Survey** | survey export/import dirs (`svy_data`), uploaded import files | `ilFileUtils` dir tree + `fopen` | ~24 | medium | +| **CmiXapi** | cmi5/xAPI content extracted into webspace object dir | `$DIC->filesystem()->web()` **direct** + `ilFileUtils` | ~10 | medium | +| **Verification** | certificate verification PDFs | `ilVerificationStorageFile extends ilFileSystemAbstractionStorage` + `file_put_contents`/`mkdir` | ~4 | medium | +| **Language** | `.lang` files in `CLIENT_DATA_DIR/lang_data` | `fopen`/`fwrite` + `ilFileUtils::makeDir` | ~9 | medium | +| **Container** | container header/custom icons `webspace/container_data/obj_` | `ilFileUtils::getWebspaceDir/makeDir` + Object custom-icon layer | ~6 | medium | +| **DidacticTemplate** | template icons (user-uploaded SVG) in web dir | `ILIAS\Filesystem` **direct** (`webDirectory->write/copy`) | ~4 | medium | +| **LearningSequence** | LSO intro/extro images | `move_uploaded_file` → `STORAGE_WEB` | ~2 | medium | +| **Saml** | SimpleSAMLphp `config.php`/`authsources.php`, IdP metadata XML, discovery | `file_put_contents` + `ILIAS\Filesystem` direct (lib expects real paths) | ~7 | high | +| **OpenIdConnect** | one login-page element image | `$DIC->filesystem()->web()` **direct** | ~4 | low | +| **LTIConsumer** | LTI provider icons (`lti_data/provider_icon/`) | `$DIC->filesystem()->web()->put` **direct** | ~9 | low–med | +| **Authentication** | apache-auth allowed-domains `.txt` | `file_put_contents`/`file_get_contents` | ~6 | low | +| **Chatroom** | chat-server config file only (not user content) | `fopen`/`fwrite` + `ilFileUtils::getDataDir` | ~4 | low | +| **Category** | category-import staging dir only | `ilFileUtils::getDataDir()."/cat_import"` | ~1 | low | +| **WebServices** | transient REST/ECS payloads (`ilRestFileStorage` small durable store) | `ilTempnam`/`fopen`/`fwrite` | ~13 | low | + +### PARTIAL (IRSS for the primary payload, legacy remnants) + +| Component | On IRSS | Still legacy | ~sites | Effort | +|---|---|---|---|---| +| **Mail** | compose-time upload handler (bridge only) | **canonical attachment store on disk** (`ilFileDataMail`/`ilFSStorageMail`), ZIP delivery, cron cleanup | ~20 | high | +| **Export** | finished export **artifact** + registry (`export_files` table) + download + public-access → IRSS (`export_handler` stakeholder); one central pipeline, no runtime fallback (see appendix) | zip **assembly** on a disk run-dir (then ingested), import **extraction** on data dir; per-component `ilExporter` reused unchanged; `ilImportDirectory` uses Filesystem direct | ~25 | high | +| **Test** | export / results / PDF-archive final zips | assessment question images, `tst_data` dirs, participant answer dirs, `ilTestArchiver` builds tree on disk | ~64 | high | +| **TestQuestionPool** | only `assFileUpload` answer files | question **image uploads** across ~7 question classes, suggested solutions, qpl export dirs; even `assFileUpload` keeps legacy preview uploads | ~122 | high | +| **Style** | content styles + content-style images (IRSS container) | `ilObjStyleSheet` legacy `/sty` image+export dirs; whole system-style/skin subsystem on disk | ~35 | high | +| **Certificate** | template files, template zips, bg/tile images | **portfolio certificate PDFs** on `$DIC->filesystem()->storage()` direct; bulk-zip + upload helpers | ~10 | medium | +| **User** | profile pictures (`usr_data.rid`), new-account-mail attachment | user-list exports (CSV/XML/Excel), personal-data export ZIP, HTML export, legacy-avatar cleanup remnant | ~18 | medium | +| **Badge** | badge + template images (`image_rid`) | `pub_badges/` public OpenBadges publishing tree, residual `getImagePath()` disk paths | ~13 | medium | +| **StudyProgramme** | programme **type** icons | object custom icon (Object service), member-export (`ilFSStoragePRG`) | ~5 | medium | +| **DataCollection** | record **file fields** (`rid`) | MOB field media (delegated), XLSX/content export temp | ~7 | low–med | +| **OrgUnit** | **type** icons | import XML reads, export zip | ~5 | low | +| **Calendar** | appointment attachments (read from IRSS) | temp/zip staging for download bundles, ICS import staging | ~13 | low | +| **ILIASObject** | TileImage via IRSS stakeholder | import upload + custom-icon staging on disk first | ~6 | medium | +| **COPage** | (content is DB-native XML) | HTML/offline export builder, TeX-render image cache in `webspace/output`, layout import scratch | ~45 | medium | + +### MIGRATED (persistent content on IRSS; only transient disk left) + +| Component | Notes | +|---|---| +| **File** (`ilObjFile`) | versions/revisions + icons + previews all IRSS. Legacy only in XML import/export interchange, setup default-icon scan, transient chunked upload. | +| **MediaObjects** | mob payload is an IRSS container (`mob_data.rid`) since ILIAS 10 (`ilMobMigration`); writes + reads route through the IRSS-backed manager/repo. Legacy tail: `exportFiles()` rCopy, multi-SRT staging, empty-dir `createDirectory()`, WAC disk fallback. See appendix. | +| **Exercise** | submissions, tutor(team) feedback, instruction files, sample solutions, peer-review criteria all IRSS (+ setup migrations). Legacy = zip/download/temp only. | +| **Forum** | post + draft attachments IRSS (`ResourceCollection`); old `ilFileDataForum` is now a delegating wrapper. Legacy = export dir plumbing. | +| **HTMLLearningModule** | whole HTML package is an IRSS container zip (`file_based_lm.rid`) + `ilHTLMMigration`. Reference pattern for the SCORM family. | +| **AdvancedMetaData** | record file-fields + record-XML exports IRSS (`Record/File/`). Legacy = import staging + one parse temp. | +| **Bibliographic** | source `.bib`/`.ris` in IRSS. Minor direct-Filesystem copy + dataset export leftovers. | +| **IndividualAssessment** | grading files IRSS; legacy `ilIndividualAssessmentFileStorage` marked `@deprecated … only used for migration`. | +| **Poll** | poll images + thumbnails in IRSS with crop flavour + `ilPollImagesMigration`. | +| **WOPI** | pure IRSS consumer (Collabora/OnlyOffice); stores nothing itself. Good reference. | +| **WebDAV** | protocol layer; content flows through IRSS (`IRSSStreamHandler`). Legacy `StreamHandler` fallback remains. | + +### N/A (no own persistent file storage) + +| Component | Why | +|---|---| +| ContentPage, Glossary, Wiki, Blog, Portfolio | content = COPage (DB); media = MediaObjects (IRSS); only transient exports touch disk | +| MediaCast, MediaPool | delegate all media to MediaObjects (IRSS); only transient download/import zips | +| News | media delegated to MediaObjects (IRSS); no direct fs | +| Contact, Notes, OnScreenChat | DB-backed; no file content | +| PersonalWorkspace, WorkspaceFolder | wrap `ilObjFile`; only temp export assembly | +| WebResource | web links in DB; only on-the-fly `bookmarks.html` | +| soap | protocol/adapter layer (+ third-party nuSOAP) | +| Repository | *provides* the Repository-level IRSS facade (`IRSSWrapper`) | +| Group, Excel, Form, RTE | export/temp staging, framework upload plumbing, editor config | +| BackgroundTasks_, Database, Logging, Html, Xml, Init, GlobalScreen, Search, Refinery, UI, UICore, UIComponent | infra/temp/cache/asset/read-only | +| Migration | DB-update helper, never touches fs | + +### INFRA (the storage stack itself) + +| Component | Role | +|---|---| +| **ResourceStorage** | IS IRSS | +| **Filesystem** | IRSS backend (flysystem local adapter); still also ships legacy `ilFileSystemGUI`, `ilFileData`, `ilUploadFiles` | +| **FileUpload** | upload ingest → `UploadResult` consumed by IRSS | +| **VirusScanner** | upload `PreProcessor` (scan scratch only) | +| **FileDelivery** | egress; new `src` is stream/IRSS-aligned, legacy `FileDeliveryTypes` remain (PARTIAL) | +| **WebAccessChecker** | legacy secure `/data` egress, being retired as IRSS makes it obsolete | +| **FileServices** | **hosts the legacy `ilFileUtils` toolbox** (`classes/class.ilFileUtils.php`) used repo-wide + IRSS upload/policy/sanitizer services | +| **Setup** | provisions & validates the on-disk directory layout | + +--- + +## Shared legacy substrates (fix once, many benefit) + +These non-IRSS storage layers are leaned on by multiple components — migrating them unblocks several: + +1. **`ilFileSystemAbstractionStorage`** — object-id-keyed on-disk tree. + Used by: **Course** (`ilFSStorageCourse`), **StudyProgramme** (`ilFSStoragePRG`), **Verification** + (`ilVerificationStorageFile`), Mail (`ilFSStorageMail`), Group (`ilFSStorageGroup`). +2. **Object custom-icon layer** (`webspace/container_data/obj_`, `object.customicons.factory`). + Used by: **Container**, **Category**, **StudyProgramme** (object icon). +3. **`ilFileUtils` toolbox** (`FileServices/classes/class.ilFileUtils.php`) — every `ilFileUtils::` call + in every component resolves here. It is infrastructure, not a per-component store, but retiring it is + the endgame. +4. **Export/Import zip build/extract on data dir** (`ilExport`/`ilExportContainer`/`ilImport`/`ilImportDirectory`) + — core infra; the disk-based assembly step sits under many components' export features. + +**Already covered:** MediaObjects payload (`mobs/mm_`) lives in IRSS since ILIAS 10, so the media of +Glossary / Wiki / Blog / Portfolio / News / MediaCast / MediaPool already sits in IRSS. Those components only +need residual `_getDirectory` / `_getURL` call-site cleanup, not a data migration. + +--- + +## Suggested migration priority + +**Tier 1 — real user content, high value, self-contained-ish** +- **Mail** attachments (deeply disk-coupled, but pure user content) +- **Course** attachments +- **SCORM family** (ScormAicc/Scorm2004/CmiXapi) — follow the **HTMLLearningModule** IRSS-container pattern + (migration already scaffolded on branch `feature/12/scorm-irss`) + +**Tier 2 — clean, bounded, low effort (good "Poll-style" stakeholder migrations)** +- **OpenIdConnect** login image +- **LTIConsumer** provider icons +- **Verification** cert PDFs +- **LearningSequence** intro/extro images +- **DidacticTemplate** icons +- **Badge** `pub_badges/` + +**Tier 3 — finish the PARTIALs** +- **TestQuestionPool** / **Test** question images + archiver (largest surface, ~186 sites combined) +- **Style** `ilObjStyleSheet` legacy path +- **Certificate** portfolio PDF · **User** exports +- **StudyProgramme** / **OrgUnit** object icons + member export + +**Tier 4 — shared substrates & infra** +- Retire `ilFileSystemAbstractionStorage`, the Object custom-icon layer, and eventually the `ilFileUtils` + toolbox; stream-ify Export/Import zip handling; drop `WebAccessChecker` and legacy `FileDeliveryTypes`. + +**Not IRSS targets (leave as-is):** Saml (bundled lib needs real paths), Language files, Chatroom server +config, Authentication domains file, setup probes, DB dumps, logs, caches, and all transient export/zip/temp +scaffolding. + +--- + +## Appendix: MediaObjects — detailed IRSS state + +MediaObjects payload is stored in IRSS, migrated in the ILIAS 10 cycle +(`components/ILIAS/MediaObjects/classes/Setup/class.ilMobMigration.php`, commit `2d78e5a9628`, +2024-10-23, registered in `class.ilMediaObjectSetupAgent.php`). The `mobs/mm_` dir API remains in the code +but is no longer the store of record. + +### What the migration does +- `ilMobMigration::step()` moves `CLIENT_WEB_DIR/mobs/mm_` into an **IRSS container resource** via + `ilResourceStorageMigrationHelper::moveDirectoryToContainerResource()`, persists the `rid` in + `mob_data.rid`, then **deletes the source dir** (`recursiveRmDir`). Empty/absent dirs get `rid = '-'`. + +### Runtime is IRSS-first +- **Writes** — every ingest path routes to the IRSS-backed manager/repo: + `addMediaItemFromUpload/FromLocalFile/FromLegacyUpload`, `replaceMediaItemFromUpload`, + `uploadAdditionalFile` → `MediaObjectManager::addFile*` → `MediaObjectRepository` (IRSS container). +- **Reads** — `MediaObjectManager::getLocalSrc()` → `repo->getLocalSrc()` → + `irss->getContainerUri($rid, $location)` (`MediaObjectRepository.php:186`). Falls back to a WAC-signed + legacy `_getURL()` path only when the container returns nothing (un-migrated / offline). +- `ilObjMediaObject::getXML()` `IL_MODE_OUTPUT` is dual-mode: the `// pre irss file` branch + (`class.ilObjMediaObject.php:522-536`) uses `ilWACSignedPath::signFile()` on the legacy disk file **only + if it still exists**, otherwise `manager->getLocalSrc()` (IRSS). Correct back-compat, not a leak. + +### Residual legacy call-sites (cleanup, ~6) +| Site | `path:line` | Note | +|---|---|---| +| `exportFiles()` | `class.ilObjMediaObject.php:736-737` | `rCopy` from `mobs/mm_`. The central XML export no longer uses it (mob DataSet emits an `rscontainer` field, streamed IRSS→IRSS), but it is **still called by other components' standalone exporters** (Test `ExportImport/Export.php:253,262`, Forum `ilForumXMLWriter.php:204`, Survey `ilSurveyExport.php:123,131`, LearningModule `ilObjContentObject.php:1457,1472`, TestQuestionPool `ilQuestionpoolExport.php:180`). After `ilMobMigration` deletes `mobs/mm_`, those `rCopy` from a missing source → embedded media silently dropped. **Latent cross-component gap.** | +| multi-SRT upload | `getMultiSrtUploadDir():1735`, `uploadMultipleSubtitleFile():1751-1755`, `getMultiSrtFiles():1775` | stages + unzips the multi-VTT zip inside `mobs/mm_/srt/tmp` on disk, then reads it back — bypasses IRSS | +| `createDirectory()` | `:433-440`, called at `:1323` + `ilMediaCreationGUI.php:414/604` + `ilObjMediaPoolGUI.php:1493` | creates an **empty** legacy dir; content is written via the IRSS manager, so the dir/`$mob_dir`/`$file` locals (`:1324-1326`) are vestigial | +| `getVideoPreviewPic(true)` | `:1695-1711` | filename-only lookup still `is_file()`-probes the legacy dir; primary `getVideoPreviewPic()` uses `thumbs->getPreviewSrc()` (IRSS) | +| static path helpers | `_getDirectory():378`, `_getRelativeDirectory():387`, `_getURL():395`, `_lookupItemPath():404`, `getDataDirectory():1301` | still return `mobs/mm_` strings; kept for the fallback + the sites above | + +### Downstream delegators +Glossary / Wiki / Blog / Portfolio / News / MediaCast / MediaPool store their media **as media objects**, so +that content lives in IRSS. Their remaining `_getDirectory` / `_getURL` references +(e.g. `Blog/Posting/class.ilBlogPostingGUI.php:788,806`, `News/classes/class.ilNewsItem.php:1820`, +`MediaCast/classes/class.ilObjMediaCastAccess.php:154` `dirsize`, `MediaPool/classes/class.ilObjMediaPoolGUI.php:1493` +`createDirectory`) hit the fallback/vestigial path — call-site cleanup, not a data migration. + +**Net state:** MediaObjects payload is on IRSS since ILIAS 10; the only functional gap is `exportFiles()` + +multi-SRT staging still touching the now-removed webspace dir. + +--- + +## Appendix: Export component — detailed IRSS state + +**On IRSS:** the finished export **artifact** (the completed zip) plus its **registry, download and +public-access** live in IRSS as a container resource owned by the `export_handler` stakeholder +(`ExportHandler/Repository/Stakeholder/Handler.php:37`), created via +`manageContainer()->containerFromStream()` (`ExportHandler/Repository/Wrapper/IRSS/Handler.php:62`) and +served with `consume()->download()` (`ExportHandler/Repository/Element/Wrapper/IRSS/Handler.php:202-209`). +The old disk-scanned `export_file_info` registry was replaced by table `export_files(object_id, rid, +owner_id, timestamp)`; a one-off migration ingests each existing on-disk zip into IRSS +(`Setup/…/ilExportFilesToIRSSMigration.php:97-125`, registered `Setup/ilExportSetupAgent.php:51`). + +**Still on disk:** the zip is **assembled on a data-dir "export run dir" first**, then streamed into the +IRSS container and deleted (`ExportHandler/Manager/Handler.php:180-204`: +`makeDirParents` → exporters write in → `writeDirectoryRecursive` → `delDir`). Even `createEmptyContainer` +builds a temp zip on disk before ingest (`Repository/Wrapper/IRSS/Handler.php:52-64`). Import extraction is +still fully on the data dir (`ilImport`/`ilImportDirectory`, the latter injecting `ILIAS\Filesystem` directly). + +**One central pipeline, no fallback.** `ilExportGUI` always delegates to the IRSS `ExportHandler` — +`class.ilExportGUI.php:285-286` (`createXMLExport`) and `:333-356` (`createXMLContainerExport`). There is no +runtime `if(legacy) … else …` branch and no feature flag. The legacy `ilExport::exportObject()/exportEntity()` +survive only for a few direct non-GUI callers: Style (`class.ilObjStyleSheetGUI.php:414`), COPage layout admin +(`class.ilPageLayoutAdministrationGUI.php:371`), LearningModule entity export +(`class.ilContObjectExport.php:175`). + +**Per-component exporters are reused, not rewritten.** Both the new and legacy paths resolve the same +`ilExporter` (`ilXmlExporter` subclass) via `ilImportExportFactory::getExporterClass` +(`class.ilImportExportFactory.php:29-65`; new path at `ExportHandler/Manager/Handler.php:73`) and call +`getXmlRepresentation()` + head/tail dependency recursion. Binary payloads are emitted by `ilDataSet` as +typed fields (`Export/DataSet/class.ilDataSet.php:307-348`): +- **`rscollection` / `rscontainer`** → copied **IRSS-container-to-IRSS-container, no disk** + (`Consumer/ExportWriter/Handler.php:161-165`). This is how migrated components (e.g. MediaObjects, + File, Forum) export their binaries. +- legacy **`directory`** / `exportFiles()` output → still written into the disk run-dir, then ingested. + +**Standalone exports** (plugged into `ilExportGUI` as export *options* but managing their own files, mostly +disk via `ExportHandler/Consumer/ExportOption/BasicLegacyHandler.php:56,87` + `deliverFileLegacy`, or fully +independent): HTML exports (`ilCOPageHTMLExport`, `ilWikiUserHTMLExport`, `ilSystemStyleHTMLExport`, +`ilHTLMExportOptionHTML`), Test (`ilTestExportOptionARC`, `ilTestExportOptionXMLRES`), DataCollection +(`ilDataCollectionExportOptionsXLSX`), member exports (`StudyProgramme`, `Membership`). + +**Cross-component gap:** `ilObjMediaObject::exportFiles()` still `rCopy`s from the deleted `mobs/mm_` dir +and is called by the standalone/on-disk exporters of Test, Forum, Survey, LearningModule and TestQuestionPool +— so embedded media in *those* exports can be silently dropped after the mob migration. The central pipeline +is unaffected (it uses the `rscontainer` field). + +--- + +## Migration history by release + +When each component's IRSS storage **first shipped**. Resolved by finding the commit that introduced the +component's earliest IRSS anchor (a `*Stakeholder` class or a Setup IRSS migration) — following file renames +across the pre-ILIAS-10 `Modules/`+`Services/` → `components/ILIAS/` restructure via +`git log --follow -S "class "` — then mapping that commit to the earliest release tag that contains it +(`git tag --contains … | grep '^v(7|8|9|1[0-9])\.[0-9]+$' | sort -V | head -1`; the `N>=7` filter drops a +spurious `v3.8` SVN-import tag). The **release is authoritative** (via `tag --contains`); the **date** is the +commit's author date, which routinely precedes the release by 1–2 years because features land on trunk long +before the release is cut. For components with several stakeholders across releases, this is the *earliest* +one; PARTIAL components added further pieces later and still carry legacy remnants (see the tables above). + +IRSS launched in **ILIAS 7** with `ilObjFile` as the pilot, then spread release by release. + +### ILIAS 7 (v7.0, ~2021) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| File | file object versions/revisions | `class.ilObjFileStakeholder.php` ("Implemented File Object Migration") | 2020-11-12 | + +### ILIAS 8 (v8.1, ~2023) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| Bibliographic | source `.bib`/`.ris` file | `class.ilObjBibliographicStakeholder.php` | 2021-07-28 | +| IndividualAssessment | grading files | `class.ilIndiviualAssessmentGradingStakeholder.php` | 2022-01-04 | + +### ILIAS 9 (v9.0, ~2024) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| Forum | post + draft attachments | `class.ilForumPostingFileStakeholder.php` | 2022-09-14 | +| User | profile pictures / avatars | `class.ilUserProfilePictureStakeholder.php` | 2023-02-28 | +| DataCollection | record file fields | `class.ilDataCollectionStorageMigration.php` | 2023-03-18 | +| Exercise | submissions, feedback, instructions, solutions, criteria | `class.ilExcInstructionFilesStakeholder.php` | 2023-08-29 | +| TestQuestionPool | `assFileUpload` answer files | `class.ilTestQuestionPoolFileUploadQuestionMigration.php` | 2023-10-06 | + +### ILIAS 10 (v10.0, ~2025) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| StudyProgramme | programme type icons | `ilStudyProgrammeTypeStakeholder.php` | 2023-11-24 | +| OrgUnit | type icons | `ilOrgUnitTypeStakeholder.php` | 2023-11-28 | +| Calendar | appointment attachments *(consumer — reads IRSS)* | `class.ilCalendarCopyFilesToTempDirectoryJob.php` | 2023-12-14 | +| WOPI | edited office documents | `WOPIStakeholder` | 2024-05-02 | +| HTMLLearningModule | HTML package container | `class.ilHTLMMigration.php` | 2024-09-13 | +| Style | content styles + images | `class.ilContentStyleStakeholder.php` | 2024-10-22 | +| Poll | poll images | `class.ilPollImagesMigration.php` | 2024-10-22 | +| MediaObjects | mob payload → IRSS container | `class.ilMobMigration.php` | 2024-10-23 | +| AdvancedMetaData | record file-fields + record-XML | `Record/File/.../Stakeholder`, `RecordFilesMigration.php` | 2024-10-24 | +| Certificate | template files + background/tile images | `ilCertificateTemplateStakeholder.php` | 2024-10-24 | +| Badge | badge + template images | `ilBadgeTemplatesFilesMigration.php` | 2024-10-25 | + +### ILIAS 11 (v11.0, ~2026) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| Export | export HTML + finished artifact/registry | `class.ilExportHTMLStakeholder.php`, `ilExportFilesToIRSSMigration.php` | 2025-01-07 | +| Test | results / export / PDF-archive artifacts | `ResultsExportStakeholder.php` | 2025-03-22 | +| ILIASObject | TileImage | `Properties/CoreProperties/TileImage/Stakeholder.php` | 2025-03-25 | +| Mail | compose-time attachment upload (bridge) | `class.ilMailAttachmentStakeholder.php` | 2025-06-16 | + +### trunk (unreleased — ILIAS 12) + +| Component | Migrated content | Anchor | Commit | +|---|---|---|---| +| WebDAV | routes object content through IRSS *(consumer)* | `src/Objects/IRSSStreamHandler.php` | 2026-05-01 | + +**Not yet migrated (no release):** every component in the LEGACY table above (Course, ScormAicc, Scorm2004, +LearningModule, Survey, SurveyQuestionPool, CmiXapi, Verification, Language, Container, DidacticTemplate, +LearningSequence, Saml, OpenIdConnect, LTIConsumer, Authentication, Chatroom, Category, WebServices) has no +IRSS migration. diff --git a/components/ILIAS/ResourceStorage/MIGRATIONS.md b/components/ILIAS/ResourceStorage/MIGRATIONS.md index 2fca945a4714..1d5f57fb375c 100755 --- a/components/ILIAS/ResourceStorage/MIGRATIONS.md +++ b/components/ILIAS/ResourceStorage/MIGRATIONS.md @@ -5,7 +5,7 @@ With ILIAS 7 the possibility of migrations was introduced in the setup. Among other things, these are used to transfer files from old structures to the ILIAS Resource Storage Service (IRSS). -Information about migrations in general can be found at [setup_/README](../../setup_/README.md). +Information about migrations in general can be found at [Setup/README](../../Setup/README.md). ## General approach @@ -67,7 +67,7 @@ public function step_3(): void } ``` -The actual migration consists is structured as described in [setup_/README](../../setup_/README.md). The following two +The actual migration consists is structured as described in [Setup/README](../../Setup/README.md). The following two methods are the most relevant for the migration: - public function getPreconditions(Environment $environment): array diff --git a/components/ILIAS/ResourceStorage/classes/Collections/View/Configuration.php b/components/ILIAS/ResourceStorage/classes/Collections/View/Configuration.php index fe8d979cad08..3b63cd13dd23 100755 --- a/components/ILIAS/ResourceStorage/classes/Collections/View/Configuration.php +++ b/components/ILIAS/ResourceStorage/classes/Collections/View/Configuration.php @@ -36,7 +36,7 @@ public function __construct( private int $items_per_page = 100, private bool $user_can_upload = false, private bool $user_can_administrate = false, - private bool $append_duplicate_filenames_as_revision = false + private OnDuplicate $on_duplicate = OnDuplicate::ALLOW ) { } @@ -80,8 +80,8 @@ public function canUserAdministrate(): bool return $this->user_can_administrate; } - public function preventDuplicates(): bool + public function getOnDuplicate(): OnDuplicate { - return $this->append_duplicate_filenames_as_revision; + return $this->on_duplicate; } } diff --git a/components/ILIAS/ResourceStorage/classes/Collections/View/OnDuplicate.php b/components/ILIAS/ResourceStorage/classes/Collections/View/OnDuplicate.php new file mode 100644 index 000000000000..2c4d40f6aede --- /dev/null +++ b/components/ILIAS/ResourceStorage/classes/Collections/View/OnDuplicate.php @@ -0,0 +1,54 @@ + + */ +enum OnDuplicate: int +{ + /** + * Allow duplicates: the file is always stored as a new, separate resource, + * even if another resource with the same name already exists. + */ + case ALLOW = 1; + + /** + * On duplicate, overwrite the existing resource with a new revision and + * delete all previous revisions (no history is kept). + */ + case REPLACE = 2; + + /** + * On duplicate, overwrite the existing resource by appending a new revision + * while keeping the previous revisions as history. + */ + case APPEND_REVISION = 3; + + /** + * On duplicate, reject the uploaded file: the existing resource is left + * untouched and the new file is not stored. + */ + case REJECT = 4; +} diff --git a/components/ILIAS/ResourceStorage/classes/Collections/View/Request.php b/components/ILIAS/ResourceStorage/classes/Collections/View/Request.php index ddc3cdb2144a..b4ed099c887a 100755 --- a/components/ILIAS/ResourceStorage/classes/Collections/View/Request.php +++ b/components/ILIAS/ResourceStorage/classes/Collections/View/Request.php @@ -198,8 +198,8 @@ public function canUserAdministrate(): bool return $this->view_configuration->canUserAdministrate(); } - public function preventDuplicates(): bool + public function getOnDuplicate(): OnDuplicate { - return $this->view_configuration->preventDuplicates(); + return $this->view_configuration->getOnDuplicate(); } } diff --git a/components/ILIAS/ResourceStorage/classes/Collections/View/UploadStorer.php b/components/ILIAS/ResourceStorage/classes/Collections/View/UploadStorer.php new file mode 100644 index 000000000000..a648b2cc6547 --- /dev/null +++ b/components/ILIAS/ResourceStorage/classes/Collections/View/UploadStorer.php @@ -0,0 +1,89 @@ + + */ +final readonly class UploadStorer +{ + public function __construct( + private Manager $manage, + private Collections $collections + ) { + } + + /** + * @return ResourceIdentification|null the identification of the affected + * resource, or null if the upload was rejected (OnDuplicate::REJECT) + * and therefore not stored. + */ + public function store( + ResourceCollection $collection, + ResourceStakeholder $stakeholder, + OnDuplicate $on_duplicate, + UploadResult $result + ): ?ResourceIdentification { + // an existing resource with the same name is only relevant if duplicates + // are not simply allowed + $existing_rid = $on_duplicate === OnDuplicate::ALLOW + ? null + : $this->collections->findIdentificationByNameIn($collection, $result->getName()); + + if ($existing_rid === null) { + // no name clash (or duplicates allowed): store as a new, separate resource + $rid = $this->manage->upload($result, $stakeholder); + $collection->add($rid); + return $rid; + } + + switch ($on_duplicate) { + case OnDuplicate::REJECT: + // leave the existing resource untouched, do not store the upload + return null; + case OnDuplicate::REPLACE: + // overwrite with a new revision and drop all previous revisions + $this->manage->replaceWithUpload($existing_rid, $result, $stakeholder); + return $existing_rid; + case OnDuplicate::APPEND_REVISION: + // overwrite by appending a new revision while keeping the previous ones as history + $this->manage->appendNewRevision($existing_rid, $result, $stakeholder); + return $existing_rid; + } + + // OnDuplicate::ALLOW never reaches this point ($existing_rid is null above) + return $existing_rid; + } +} diff --git a/components/ILIAS/ResourceStorage/classes/Collections/class.ilResourceCollectionGUI.php b/components/ILIAS/ResourceStorage/classes/Collections/class.ilResourceCollectionGUI.php index 3d5afb0d39a1..6de5db748e9a 100755 --- a/components/ILIAS/ResourceStorage/classes/Collections/class.ilResourceCollectionGUI.php +++ b/components/ILIAS/ResourceStorage/classes/Collections/class.ilResourceCollectionGUI.php @@ -29,6 +29,7 @@ use ILIAS\FileUpload\Handler\FileInfoResult; use ILIAS\components\ResourceStorage\Collections\View\Configuration; use ILIAS\components\ResourceStorage\Collections\View\Request; +use ILIAS\components\ResourceStorage\Collections\View\UploadStorer; use ILIAS\components\ResourceStorage\Collections\View\ViewFactory; use ILIAS\components\ResourceStorage\Collections\DataProvider\TableDataProvider; use ILIAS\components\ResourceStorage\BinToHexSerializer; @@ -225,30 +226,21 @@ public function upload(): void return; } $collection = $this->view_request->getCollection(); + $stakeholder = $this->view_configuration->getStakeholder(); + $on_duplicate = $this->view_request->getOnDuplicate(); + $storer = new UploadStorer($this->irss->manage(), $this->irss->collection()); + $rid = null; foreach ($this->upload->getResults() as $result) { if (!$result->isOK()) { continue; } - // if activated, prevent duplicate files by checking filenames. in thjis case a new revision gets appended - if ($this->view_request->preventDuplicates()) { - $existing_rid = $this->irss->collection()->findIdentificationByNameIn( - $this->view_request->getCollection(), - $result->getName() - ); - if ($existing_rid !== null) { - $this->irss->manage()->appendNewRevision( - $existing_rid, - $upload_result, - $this->view_configuration->getStakeholder() - ); - } - } - $rid = $existing_rid ?? $this->irss->manage()->upload( - $result, - $this->view_configuration->getStakeholder() - ); - $collection->add($rid); + $stored_rid = $storer->store($collection, $stakeholder, $on_duplicate, $result); + if ($stored_rid === null) { + // the upload was rejected (OnDuplicate::REJECT), nothing was stored + continue; + } + $rid = $stored_rid; // ensure flavour $this->irss->flavours()->ensure( @@ -260,7 +252,7 @@ public function upload(): void $upload_result = new BasicHandlerResult( self::P_RESOURCE_ID, BasicHandlerResult::STATUS_OK, - $rid->serialize(), + $rid?->serialize() ?? '', '' ); $response = $this->http->response()->withBody(Streams::ofString(json_encode($upload_result))); @@ -299,7 +291,14 @@ private function unzip(): void $unzip_options = $this->archive->unzipOptions() ->withDirectoryHandling(ZipDirectoryHandling::FLAT_STRUCTURE); - foreach ($this->archive->unzip($zip_stream, $unzip_options)->getFileStreams() as $stream) { + $unzip = $this->archive->unzip($zip_stream, $unzip_options); + if (!$unzip->isWithinLimits()) { + // the archive exceeds the configured extraction limits, see UnzipOptions + $this->main_tpl->setOnScreenMessage('failure', $this->language->txt('cannot_unzip_file'), true); + $this->ctrl->redirect($this, self::CMD_INDEX); + } + + foreach ($unzip->getFileStreams() as $stream) { $rid = $this->irss->manage()->stream( Streams::ofString($stream->getContents()), $this->view_configuration->getStakeholder(), diff --git a/components/ILIAS/ResourceStorage/classes/Container/Wrapper/ContainerWrapper.php b/components/ILIAS/ResourceStorage/classes/Container/Wrapper/ContainerWrapper.php index d139b0d1df93..f5d4b57f23b6 100755 --- a/components/ILIAS/ResourceStorage/classes/Container/Wrapper/ContainerWrapper.php +++ b/components/ILIAS/ResourceStorage/classes/Container/Wrapper/ContainerWrapper.php @@ -25,6 +25,7 @@ use ILIAS\FileDelivery\Delivery\Disposition; use ILIAS\Filesystem\Stream\Streams; use ILIAS\Filesystem\Stream\ZIPStream; +use ILIAS\Filesystem\Util\Archive\Archives; /** * @author Fabian Schmid @@ -44,6 +45,7 @@ final class ContainerWrapper private bool $use_flavour = true; private ZipReader $reader; private \ILIAS\FileDelivery\Services $file_delivery; + private Archives $archives; public function __construct( private ResourceIdentification $rid, @@ -53,6 +55,7 @@ public function __construct( // dependencies $this->irss = $DIC->resourceStorage(); $this->file_delivery = $DIC->fileDelivery(); + $this->archives = $DIC->archives(); $this->reader = new ZipReader( $this->irss->consume()->stream($rid)->getStream() ); @@ -127,28 +130,38 @@ public function unzip(string $path_inside_zip): bool // save stream to temporary file $tmp_directory = defined('CLIENT_DATA_DIR') ? \CLIENT_DATA_DIR . '/temp' : sys_get_temp_dir(); $tmp_file = tempnam($tmp_directory, 'ilias_zip_'); - - /** @var ZIPStream $stream */ - $return = file_put_contents($tmp_file, $stream->detach()); - - $zip_reader = new ZipReader( - Streams::ofResource(fopen($tmp_file, 'rb')) - ); - - foreach ($zip_reader->getStructure() as $append_path_inside_zip => $item) { - if ($item['is_dir']) { - continue; + $tmp_extract_directory = $tmp_file . '_extracted'; + + try { + /** @var ZIPStream $stream */ + file_put_contents($tmp_file, $stream->detach()); + + // extract first: this keeps the memory footprint flat and allows the + // container archive to be rewritten a single time below + $extracted = $this->archives->unzip( + Streams::ofResource(fopen($tmp_file, 'rb')), + $this->archives->unzipOptions()->withZipOutputPath($tmp_extract_directory) + )->extract(); + + // an archive beyond the configured extraction limits (see UnzipOptions) writes + // nothing, so it has to be rejected instead of adding an empty directory + if (!$extracted) { + return false; } - [$stream, $info] = $zip_reader->getItem($append_path_inside_zip, $this->data); - $this->irss->manageContainer()->addStreamToContainer( + + return $this->irss->manageContainer()->addDirectoryToContainer( $this->rid, - $stream, - $this->current_level . '/' . ltrim($append_path_inside_zip, './') + $tmp_extract_directory, + $this->current_level ); + } finally { + if (is_file($tmp_file)) { + unlink($tmp_file); + } + if (is_dir($tmp_extract_directory)) { + \ilFileUtils::delDir($tmp_extract_directory); + } } - - unlink($tmp_file); - return true; } public function getEntries(): \Generator diff --git a/components/ILIAS/ResourceStorage/classes/Container/class.ilContainerResourceGUI.php b/components/ILIAS/ResourceStorage/classes/Container/class.ilContainerResourceGUI.php index c4d1a5c03e9a..90293f02db0b 100755 --- a/components/ILIAS/ResourceStorage/classes/Container/class.ilContainerResourceGUI.php +++ b/components/ILIAS/ResourceStorage/classes/Container/class.ilContainerResourceGUI.php @@ -396,12 +396,18 @@ private function unzip(): void $this->abortWithPermissionDenied(); return; } - $paths = $this->getPathsFromRequest()[0]; - $this->view_request->getWrapper()->unzip( - $paths + $paths = $this->getPathsFromRequest(); + + // the message has to reflect what unzip() actually did, a hardcoded one + // reports a success even when nothing was added to the container + $success = $paths !== [] && $this->view_request->getWrapper()->unzip($paths[0]); + + $this->main_tpl->setOnScreenMessage( + $success ? 'success' : 'failure', + $this->language->txt($success ? 'rids_appended' : 'rids_appended_failed'), + true ); - $this->main_tpl->setOnScreenMessage('success', $this->language->txt('rids_appended'), true); $this->ctrl->redirect($this, self::CMD_INDEX); } diff --git a/components/ILIAS/Logging/classes/Setup/class.ilLoggingUpdateSteps8.php b/components/ILIAS/ResourceStorage/classes/Setup/DB/UpdateStepsV12.php old mode 100755 new mode 100644 similarity index 57% rename from components/ILIAS/Logging/classes/Setup/class.ilLoggingUpdateSteps8.php rename to components/ILIAS/ResourceStorage/classes/Setup/DB/UpdateStepsV12.php index 2691489aa5c4..d2b063c57e8e --- a/components/ILIAS/Logging/classes/Setup/class.ilLoggingUpdateSteps8.php +++ b/components/ILIAS/ResourceStorage/classes/Setup/DB/UpdateStepsV12.php @@ -17,27 +17,24 @@ *********************************************************************/ declare(strict_types=1); -/** - * Class ilLoggingUpdateSteps8 - * contains update steps for release 8 - * @author Stefan Meyer - */ -class ilLoggingUpdateSteps8 implements ilDatabaseUpdateSteps + +namespace ILIAS\ResourceStorage\Setup\DB; + +class UpdateStepsV12 implements \ilDatabaseUpdateSteps { - protected ilDBInterface $db; + private \ilDBInterface $db; - public function prepare(ilDBInterface $db): void + public function prepare(\ilDBInterface $db): void { $this->db = $db; } - /** - * Add consent table - */ public function step_1(): void { - $query = 'DELETE from log_components ' . - 'WHERE component_id = ' . $this->db->quote('lchk', ilDBConstants::T_TEXT); - $this->db->manipulate($query); + $this->db->modifyTableColumn('il_resource_flavour', 'variant', [ + 'notnull' => false, + 'length' => 638, + 'type' => \ilDBConstants::T_TEXT, + ]); } } diff --git a/components/ILIAS/ResourceStorage/classes/Setup/class.ilResourceStorageSetupAgent.php b/components/ILIAS/ResourceStorage/classes/Setup/class.ilResourceStorageSetupAgent.php index b29e61b845b1..87dd4233da11 100755 --- a/components/ILIAS/ResourceStorage/classes/Setup/class.ilResourceStorageSetupAgent.php +++ b/components/ILIAS/ResourceStorage/classes/Setup/class.ilResourceStorageSetupAgent.php @@ -25,6 +25,8 @@ use ILIAS\Setup\Config; use ILIAS\Setup\Objective; use ILIAS\Setup\ObjectiveCollection; +use ILIAS\ResourceStorage\Setup\DB\UpdateStepsV12; +use ILIAS\Setup\Objective\ObjectiveWithPreconditions; /** * Class ilResourceStorageSetupAgent @@ -65,9 +67,10 @@ public function getUpdateObjective(?Config $config = null): Objective new ilDatabaseUpdateStepsExecutedObjective( new ilResourceStorageDB80() ), - new ilDatabaseUpdateStepsExecutedObjective( - new ilResourceStorageDB90() - ) + new ObjectiveWithPreconditions( + new ilDatabaseUpdateStepsExecutedObjective(new UpdateStepsV12()), + new ilDatabaseUpdateStepsExecutedObjective(new ilResourceStorageDB90()), + ), ); } diff --git a/components/ILIAS/ResourceStorage/src/Flavour/Definition/FlavourDefinition.php b/components/ILIAS/ResourceStorage/src/Flavour/Definition/FlavourDefinition.php index e26ea0311a5b..335863676eda 100755 --- a/components/ILIAS/ResourceStorage/src/Flavour/Definition/FlavourDefinition.php +++ b/components/ILIAS/ResourceStorage/src/Flavour/Definition/FlavourDefinition.php @@ -51,7 +51,7 @@ public function getInternalName(): string; * such variants must be distinguishable. For example, a variant name may contain "{height}x{width}" * if these are configurable values. * - * The Variant-Name MUST be less than 768 characters long! + * The Variant-Name MUST be less than 638 characters long! */ public function getVariantName(): ?string; diff --git a/components/ILIAS/ResourceStorage/src/Flavour/FlavourBuilder.php b/components/ILIAS/ResourceStorage/src/Flavour/FlavourBuilder.php index ce6f558a7ca8..f9df49ba95ea 100755 --- a/components/ILIAS/ResourceStorage/src/Flavour/FlavourBuilder.php +++ b/components/ILIAS/ResourceStorage/src/Flavour/FlavourBuilder.php @@ -44,7 +44,7 @@ */ class FlavourBuilder { - public const VARIANT_NAME_MAX_LENGTH = 768; + public const VARIANT_NAME_MAX_LENGTH = 638; private array $current_revision_cache = []; private array $resources_cache = []; diff --git a/components/ILIAS/ResourceStorage/src/Manager/ContainerManager.php b/components/ILIAS/ResourceStorage/src/Manager/ContainerManager.php index edccca7b515b..f66fb30b006d 100755 --- a/components/ILIAS/ResourceStorage/src/Manager/ContainerManager.php +++ b/components/ILIAS/ResourceStorage/src/Manager/ContainerManager.php @@ -106,6 +106,23 @@ public function addUploadToContainer( ); } + /** + * Adds all files of a local directory to the container in one go. Prefer this + * over repeated addStreamToContainer() calls: the container archive is + * rewritten once instead of once per file. + */ + public function addDirectoryToContainer( + ResourceIdentification $container, + string $local_directory, + string $path_inside_container, + ): bool { + return $this->resource_builder->addDirectoryToContainer( + $this->getResource($container), + $local_directory, + $this->normalizePath($path_inside_container) + ); + } + public function addStreamToContainer( ResourceIdentification $container, FileStream $stream, diff --git a/components/ILIAS/ResourceStorage/src/Resource/ResourceBuilder.php b/components/ILIAS/ResourceStorage/src/Resource/ResourceBuilder.php index 00dd9737e7ed..fa34b3df0520 100755 --- a/components/ILIAS/ResourceStorage/src/Resource/ResourceBuilder.php +++ b/components/ILIAS/ResourceStorage/src/Resource/ResourceBuilder.php @@ -633,10 +633,33 @@ private function ensurePathInZIP(\ZipArchive $zip, string $path, bool $is_file): return $path_inside_container . '/' . $filename; } + /** + * Entries have been stored with a leading slash before Mantis 45580 / 47237, + * e.g. "/style.css" instead of "style.css". Both variants of an entry can exist + * side by side in containers of that age, so removing an entry has to cover both - + * otherwise the legacy entry stays in the container forever (Mantis 48047). + * + * @return string[] empty if the given path does not address an entry at all + */ + private function pathVariantsInZIP(string $path): array + { + $path = ltrim($path, '/'); + if ($path === '') { + return []; + } + + return [$path, '/' . $path]; + } + public function removePathInsideContainer( StorableContainerResource $container, string $path_inside_container, ): bool { + $paths_to_remove = $this->pathVariantsInZIP($path_inside_container); + if ($paths_to_remove === []) { + return false; + } + $revision = $container->getCurrentRevisionIncludingDraft(); $stream = $this->extractStream($revision); @@ -645,15 +668,21 @@ public function removePathInsideContainer( $zip = new \ZipArchive(); $zip->open($stream->getMetadata()['uri']); - $return = $zip->deleteName($path_inside_container); + $return = false; + foreach ($paths_to_remove as $path_to_remove) { + $return = $zip->deleteName($path_to_remove) || $return; + } // remove all files inside the directory for ($i = 0; $i < $zip->numFiles; $i++) { $path = $zip->getNameIndex($i); if ($path === false) { continue; } - if (str_starts_with($path, $path_inside_container)) { - $zip->deleteIndex($i); + foreach ($paths_to_remove as $path_to_remove) { + if (str_starts_with($path, $path_to_remove)) { + $zip->deleteIndex($i); + break; + } } } @@ -686,7 +715,9 @@ public function addUploadToContainer( $parent_path_inside_container = $this->ensurePathInZIP($zip, $parent_path_inside_container, false); - $path_inside_zip = rtrim($parent_path_inside_container, '/') . '/' . $result->getName(); + // an empty parent path must not result in an entry like "/file.txt", + // entries are stored relative since Mantis 45580 / 47237 + $path_inside_zip = ltrim(rtrim($parent_path_inside_container, '/') . '/' . $result->getName(), '/'); $return = $zip->addFile( $result->getPath(), @@ -707,6 +738,86 @@ public function addUploadToContainer( return true; } + /** + * Adds a whole local directory to a container. The archive is opened, written + * and stored exactly once, regardless of how many files the directory holds. + * Adding the files one by one instead rewrites the complete archive per file, + * since ZipArchive::close() never appends in place. + */ + public function addDirectoryToContainer( + StorableContainerResource $container, + string $local_directory, + string $path_inside_container, + ): bool { + if (!is_dir($local_directory)) { + return false; + } + + $revision = $container->getCurrentRevisionIncludingDraft(); + $uri = $this->extractStream($revision)->getMetadata()['uri']; + + try { + $zip = new \ZipArchive(); + if ($zip->open($uri) !== true) { + return false; + } + + $added = $this->addDirectoryToZIP($zip, $local_directory, $path_inside_container); + + // close() is where libzip actually writes the archive, a failure here + // means nothing was persisted at all + if (!$zip->close() || $added === 0) { + return false; + } + + // cleanup revision and flavours + $this->storage_handler_factory->getHandlerForRevision($revision)->clearFlavours($revision); + $revision->getInformation()->setSize(filesize($uri)); + $this->storeRevision($revision); + + return true; + } catch (\Throwable) { + // the caller reports the failure to the user + return false; + } + } + + /** + * Adds every file below $local_directory to an already opened archive, + * keeping the directory structure relative to $local_directory. + * @return int the number of files added + */ + private function addDirectoryToZIP( + \ZipArchive $zip, + string $local_directory, + string $path_inside_container, + ): int { + $local_directory = rtrim($local_directory, DIRECTORY_SEPARATOR); + $added = 0; + + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($local_directory, \FilesystemIterator::SKIP_DOTS) + ); + foreach ($iterator as $file) { + if (!$file->isFile()) { + continue; + } + $relative_path = str_replace( + DIRECTORY_SEPARATOR, + '/', + substr($file->getPathname(), strlen($local_directory) + 1) + ); + // libzip reads the source file lazily on close(), therefore the + // contents are never held in memory (unlike addFromString) + $added += (int) $zip->addFile( + $file->getPathname(), + $this->ensurePathInZIP($zip, $path_inside_container . '/' . $relative_path, true) + ); + } + + return $added; + } + public function addStreamToContainer( StorableContainerResource $container, FileStream $stream, diff --git a/components/ILIAS/ResourceStorage/src/StorageHandler/FileSystemBased/AbstractFileSystemStorageHandler.php b/components/ILIAS/ResourceStorage/src/StorageHandler/FileSystemBased/AbstractFileSystemStorageHandler.php index 41754310c0a8..7afd56887b60 100755 --- a/components/ILIAS/ResourceStorage/src/StorageHandler/FileSystemBased/AbstractFileSystemStorageHandler.php +++ b/components/ILIAS/ResourceStorage/src/StorageHandler/FileSystemBased/AbstractFileSystemStorageHandler.php @@ -291,8 +291,7 @@ public function cleanUpContainer(StorableResource $resource): void $first_level = strtok($container_path, "/"); if (!empty($first_level)) { $full_first_level = $storage_path . '/' . $first_level; - $number_of_files = $this->fs->finder()->files()->in([$full_first_level])->count(); - if ($number_of_files === 0) { + if (!$this->fs->finder()->files()->in([$full_first_level])->hasAny()) { $this->fs->deleteDir($full_first_level); } } diff --git a/components/ILIAS/ResourceStorage/tests/Collections/View/ConfigurationTest.php b/components/ILIAS/ResourceStorage/tests/Collections/View/ConfigurationTest.php new file mode 100644 index 000000000000..0e6d6f1751e9 --- /dev/null +++ b/components/ILIAS/ResourceStorage/tests/Collections/View/ConfigurationTest.php @@ -0,0 +1,72 @@ + + */ +final class ConfigurationTest extends TestCase +{ + public function testDefaultOnDuplicateIsAllow(): void + { + $configuration = new Configuration( + $this->createStub(ResourceCollection::class), + $this->createStub(ResourceStakeholder::class), + 'title' + ); + + $this->assertSame(OnDuplicate::ALLOW, $configuration->getOnDuplicate()); + } + + #[DataProvider('onDuplicateProvider')] + public function testOnDuplicateIsPassedThrough(OnDuplicate $on_duplicate): void + { + $configuration = new Configuration( + $this->createStub(ResourceCollection::class), + $this->createStub(ResourceStakeholder::class), + 'title', + Mode::DATA_TABLE, + 100, + true, + true, + $on_duplicate + ); + + $this->assertSame($on_duplicate, $configuration->getOnDuplicate()); + } + + public static function onDuplicateProvider(): \Iterator + { + yield 'allow' => [OnDuplicate::ALLOW]; + yield 'replace' => [OnDuplicate::REPLACE]; + yield 'append revision' => [OnDuplicate::APPEND_REVISION]; + yield 'reject' => [OnDuplicate::REJECT]; + } +} diff --git a/components/ILIAS/ResourceStorage/tests/Collections/View/UploadStorerTest.php b/components/ILIAS/ResourceStorage/tests/Collections/View/UploadStorerTest.php new file mode 100644 index 000000000000..1c6a2e1e3a0f --- /dev/null +++ b/components/ILIAS/ResourceStorage/tests/Collections/View/UploadStorerTest.php @@ -0,0 +1,211 @@ + + */ +final class UploadStorerTest extends TestCase +{ + private const FILE_NAME = 'feedback.pdf'; + + private Manager&MockObject $manage; + private Collections&MockObject $collections; + private ResourceCollection&MockObject $collection; + private ResourceStakeholder&MockObject $stakeholder; + private UploadResult $result; + private UploadStorer $storer; + + protected function setUp(): void + { + parent::setUp(); + $this->manage = $this->createMock(Manager::class); + $this->collections = $this->createMock(Collections::class); + $this->collection = $this->createMock(ResourceCollection::class); + $this->stakeholder = $this->createMock(ResourceStakeholder::class); + $this->result = new UploadResult( + self::FILE_NAME, + 123, + 'application/pdf', + new EntryLockingStringMap(), + new ProcessingStatus(ProcessingStatus::OK, 'ok'), + 'dummy/path' + ); + $this->storer = new UploadStorer($this->manage, $this->collections); + } + + // ALLOW: never dedupes, always stores a new, separate resource + + public function testAllowStoresNewResourceWithoutLookupEvenWhenNameExists(): void + { + $new_rid = new ResourceIdentification('new'); + + // ALLOW must not even ask whether a same-name resource exists + $this->collections->expects($this->never())->method('findIdentificationByNameIn'); + $this->manage->expects($this->never())->method('replaceWithUpload'); + $this->manage->expects($this->never())->method('appendNewRevision'); + + $this->manage->expects($this->once()) + ->method('upload') + ->with($this->result, $this->stakeholder) + ->willReturn($new_rid); + $this->collection->expects($this->once())->method('add')->with($new_rid); + + $this->assertSame( + $new_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::ALLOW, $this->result) + ); + } + + // REJECT: on a name clash nothing is stored, the existing resource is untouched + + public function testRejectLeavesExistingResourceUntouchedAndStoresNothing(): void + { + $existing_rid = new ResourceIdentification('existing'); + $this->givenExistingResource($existing_rid); + + $this->manage->expects($this->never())->method('upload'); + $this->manage->expects($this->never())->method('replaceWithUpload'); + $this->manage->expects($this->never())->method('appendNewRevision'); + $this->collection->expects($this->never())->method('add'); + + $this->assertNull( + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::REJECT, $this->result) + ); + } + + public function testRejectStoresNewResourceWhenNoNameClash(): void + { + $new_rid = new ResourceIdentification('new'); + $this->givenNoExistingResource(); + + $this->manage->expects($this->never())->method('replaceWithUpload'); + $this->manage->expects($this->never())->method('appendNewRevision'); + $this->manage->expects($this->once())->method('upload')->willReturn($new_rid); + $this->collection->expects($this->once())->method('add')->with($new_rid); + + $this->assertSame( + $new_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::REJECT, $this->result) + ); + } + + // REPLACE: on a name clash overwrite the existing resource, drop the history + + public function testReplaceOverwritesExistingResource(): void + { + $existing_rid = new ResourceIdentification('existing'); + $this->givenExistingResource($existing_rid); + + $this->manage->expects($this->never())->method('upload'); + $this->manage->expects($this->never())->method('appendNewRevision'); + $this->collection->expects($this->never())->method('add'); + $this->manage->expects($this->once()) + ->method('replaceWithUpload') + ->with($existing_rid, $this->result, $this->stakeholder) + ->willReturn($this->createStub(Revision::class)); + + $this->assertSame( + $existing_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::REPLACE, $this->result) + ); + } + + public function testReplaceStoresNewResourceWhenNoNameClash(): void + { + $new_rid = new ResourceIdentification('new'); + $this->givenNoExistingResource(); + + $this->manage->expects($this->never())->method('replaceWithUpload'); + $this->manage->expects($this->once())->method('upload')->willReturn($new_rid); + $this->collection->expects($this->once())->method('add')->with($new_rid); + + $this->assertSame( + $new_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::REPLACE, $this->result) + ); + } + + // APPEND_REVISION: on a name clash append a new revision, keep the history + + public function testAppendRevisionAddsRevisionToExistingResource(): void + { + $existing_rid = new ResourceIdentification('existing'); + $this->givenExistingResource($existing_rid); + + $this->manage->expects($this->never())->method('upload'); + $this->manage->expects($this->never())->method('replaceWithUpload'); + $this->collection->expects($this->never())->method('add'); + $this->manage->expects($this->once()) + ->method('appendNewRevision') + ->with($existing_rid, $this->result, $this->stakeholder) + ->willReturn($this->createStub(Revision::class)); + + $this->assertSame( + $existing_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::APPEND_REVISION, $this->result) + ); + } + + public function testAppendRevisionStoresNewResourceWhenNoNameClash(): void + { + $new_rid = new ResourceIdentification('new'); + $this->givenNoExistingResource(); + + $this->manage->expects($this->never())->method('appendNewRevision'); + $this->manage->expects($this->once())->method('upload')->willReturn($new_rid); + $this->collection->expects($this->once())->method('add')->with($new_rid); + + $this->assertSame( + $new_rid, + $this->storer->store($this->collection, $this->stakeholder, OnDuplicate::APPEND_REVISION, $this->result) + ); + } + + private function givenExistingResource(ResourceIdentification $existing_rid): void + { + $this->collections->method('findIdentificationByNameIn') + ->with($this->collection, self::FILE_NAME) + ->willReturn($existing_rid); + } + + private function givenNoExistingResource(): void + { + $this->collections->method('findIdentificationByNameIn') + ->with($this->collection, self::FILE_NAME) + ->willReturn(null); + } +} diff --git a/components/ILIAS/ResourceStorage/tests/Flavours/FlavourTest.php b/components/ILIAS/ResourceStorage/tests/Flavours/FlavourTest.php index b95a422e676b..f8a7c0859dea 100755 --- a/components/ILIAS/ResourceStorage/tests/Flavours/FlavourTest.php +++ b/components/ILIAS/ResourceStorage/tests/Flavours/FlavourTest.php @@ -85,7 +85,7 @@ public function testDefinitionVariantNameLengths(): void $flavour_definition = $this->createMock(FlavourDefinition::class); $flavour_definition->expects($this->exactly(2)) ->method('getVariantName') - ->willReturn(str_repeat('a', 768)); + ->willReturn(str_repeat('a', 638)); $flavour_builder->has( new ResourceIdentification('1'), diff --git a/components/ILIAS/ResourceStorage/tests/Resource/AddDirectoryToZipTest.php b/components/ILIAS/ResourceStorage/tests/Resource/AddDirectoryToZipTest.php new file mode 100644 index 000000000000..2d062c543abb --- /dev/null +++ b/components/ILIAS/ResourceStorage/tests/Resource/AddDirectoryToZipTest.php @@ -0,0 +1,171 @@ + + */ +final class AddDirectoryToZipTest extends TestCase +{ + private string $zip_file; + private string $source_directory; + private ZipArchive $zip; + + protected function setUp(): void + { + parent::setUp(); + $this->zip_file = tempnam(sys_get_temp_dir(), 'irss_dir_test_'); + $this->zip = new ZipArchive(); + $this->zip->open($this->zip_file, ZipArchive::OVERWRITE); + + $this->source_directory = $this->zip_file . '_source'; + mkdir($this->source_directory . '/docs/nested', 0777, true); + file_put_contents($this->source_directory . '/root.txt', 'root'); + file_put_contents($this->source_directory . '/docs/one.txt', 'one'); + file_put_contents($this->source_directory . '/docs/nested/two.txt', 'two'); + } + + protected function tearDown(): void + { + parent::tearDown(); + if ($this->zip->filename !== '') { + @$this->zip->close(); + } + @unlink($this->zip_file); + $this->removeDirectory($this->source_directory); + } + + private function removeDirectory(string $directory): void + { + if (!is_dir($directory)) { + return; + } + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($iterator as $file) { + $file->isDir() ? @rmdir($file->getPathname()) : @unlink($file->getPathname()); + } + @rmdir($directory); + } + + private function invoke(string $source_directory, string $path_inside_container): int + { + $method = new \ReflectionMethod(ResourceBuilder::class, 'addDirectoryToZIP'); + $builder = (new \ReflectionClass(ResourceBuilder::class))->newInstanceWithoutConstructor(); + + return $method->invoke($builder, $this->zip, $source_directory, $path_inside_container); + } + + /** + * @return string[] + */ + private function fileEntries(): array + { + $verify = new ZipArchive(); + $verify->open($this->zip_file); + $names = []; + for ($i = 0; $i < $verify->numFiles; $i++) { + $name = $verify->getNameIndex($i); + if (!str_ends_with($name, '/')) { + $names[] = $name; + } + } + $verify->close(); + sort($names); + + return $names; + } + + public function testAllFilesAreAddedKeepingTheDirectoryStructure(): void + { + $added = $this->invoke($this->source_directory, ''); + $this->zip->close(); + + $this->assertSame(3, $added); + $this->assertSame( + ['docs/nested/two.txt', 'docs/one.txt', 'root.txt'], + $this->fileEntries() + ); + } + + public function testEntriesArePrefixedWithTheCurrentLevel(): void + { + $added = $this->invoke($this->source_directory, 'target'); + $this->zip->close(); + + $this->assertSame(3, $added); + $this->assertSame( + ['target/docs/nested/two.txt', 'target/docs/one.txt', 'target/root.txt'], + $this->fileEntries() + ); + } + + public function testATrailingSeparatorOnTheSourceDirectoryDoesNotAffectTheEntries(): void + { + $this->invoke($this->source_directory . DIRECTORY_SEPARATOR, ''); + $this->zip->close(); + + $this->assertSame( + ['docs/nested/two.txt', 'docs/one.txt', 'root.txt'], + $this->fileEntries() + ); + } + + public function testNoEntryStartsWithASlash(): void + { + $this->invoke($this->source_directory, '/'); + $this->zip->close(); + + $entries = $this->fileEntries(); + $this->assertNotEmpty($entries); + foreach ($entries as $entry) { + $this->assertStringStartsNotWith('/', $entry, "ZIP entry must not start with '/': {$entry}"); + } + } + + public function testExistingEntriesAreKept(): void + { + $this->zip->addFromString('existing.txt', 'already in the container'); + + $this->invoke($this->source_directory, ''); + $this->zip->close(); + + $this->assertContains('existing.txt', $this->fileEntries()); + } + + public function testAnEmptyDirectoryAddsNothing(): void + { + $empty_directory = $this->source_directory . '/empty'; + mkdir($empty_directory); + + $this->assertSame(0, $this->invoke($empty_directory, '')); + } +} diff --git a/components/ILIAS/ResourceStorage/tests/Resource/EnsurePathInZipTest.php b/components/ILIAS/ResourceStorage/tests/Resource/EnsurePathInZipTest.php index d7829479466a..844c7d43d088 100644 --- a/components/ILIAS/ResourceStorage/tests/Resource/EnsurePathInZipTest.php +++ b/components/ILIAS/ResourceStorage/tests/Resource/EnsurePathInZipTest.php @@ -108,4 +108,28 @@ public function testWritingRootFileProducesRelativeEntry(): void } $this->assertContains('index.html', $names); } + + /** + * Mantis 48047: containers written before the fix above still contain entries + * like "/style.css" next to the relative entry of the same file. Removing an + * entry has to cover both variants, otherwise the legacy one stays forever. + */ + #[DataProvider('pathVariantProvider')] + public function testPathVariantsCoverLegacyEntries(string $input, array $expected): void + { + $method = new \ReflectionMethod(ResourceBuilder::class, 'pathVariantsInZIP'); + $builder = (new \ReflectionClass(ResourceBuilder::class))->newInstanceWithoutConstructor(); + + $this->assertSame($expected, $method->invoke($builder, $input)); + } + + public static function pathVariantProvider(): \Iterator + { + yield 'root file' => ['style.css', ['style.css', '/style.css']]; + yield 'root file, leading slash' => ['/style.css', ['style.css', '/style.css']]; + yield 'nested file' => ['images/header.png', ['images/header.png', '/images/header.png']]; + yield 'directory' => ['images/', ['images/', '/images/']]; + yield 'empty path' => ['', []]; + yield 'slash only' => ['/', []]; + } } diff --git a/components/ILIAS/Saml/classes/class.ilAuthProviderSaml.php b/components/ILIAS/Saml/classes/class.ilAuthProviderSaml.php index 81afe48f9496..7931e46c1ef7 100755 --- a/components/ILIAS/Saml/classes/class.ilAuthProviderSaml.php +++ b/components/ILIAS/Saml/classes/class.ilAuthProviderSaml.php @@ -40,7 +40,7 @@ class ilAuthProviderSaml extends ilAuthProvider implements ilAuthProviderAccount private bool $force_new_account = false; private string $migration_account = ''; /** - * @var array|null + * @var array|null */ private ?array $user_defined_fields = null; @@ -269,7 +269,7 @@ private function handleSamlAuth(ilAuthStatus $status): bool return true; } - ilLoggerFactory::getLogger(self::LOG_COMPONENT)->debug("SAML user synchronisation is not enabled, auth failed."); + ilLoggerFactory::getLogger(self::LOG_COMPONENT)->debug('SAML user synchronisation is not enabled, auth failed.'); $this->handleAuthenticationFail($status, 'err_auth_saml_no_ilias_user'); return false; @@ -345,7 +345,7 @@ private function importUser(?string $a_internal_login, string $a_external_accoun 'Action' => 'Assign' ]); - $xml_writer->xmlElement('Active', [], "true"); + $xml_writer->xmlElement('Active', [], 'true'); $xml_writer->xmlElement('TimeLimitOwner', [], USER_FOLDER_ID); $xml_writer->xmlElement('TimeLimitUnlimited', [], 1); $xml_writer->xmlElement('TimeLimitFrom', [], time()); @@ -511,7 +511,7 @@ private function buildUserAttributeXml( $field = $this->user_defined_fields[$udf_data[1]] ?? null; if ($field === null) { ilLoggerFactory::getLogger('auth')->warning(sprintf( - "Invalid/Orphaned UD field mapping detected: %s", + 'Invalid/Orphaned UD field mapping detected: %s', $rule->getAttribute() )); break; diff --git a/components/ILIAS/Search/classes/GUI/Direct/SearcherImpl.php b/components/ILIAS/Search/classes/GUI/Direct/SearcherImpl.php index 7780781956db..d140e4040cc9 100755 --- a/components/ILIAS/Search/classes/GUI/Direct/SearcherImpl.php +++ b/components/ILIAS/Search/classes/GUI/Direct/SearcherImpl.php @@ -129,7 +129,7 @@ protected function renderResults( string $term, ViewControlInfos $view_control_infos ): void { - if ($results->getResults()) { + if ($results->getResults() || $view_control_infos->currentPage() > 1) { $result_panel_and_modals = $this->presenter->getDirectSearchResultAsPanel( $results, $view_control_infos diff --git a/components/ILIAS/Search/classes/GUI/Lucene/SearcherImpl.php b/components/ILIAS/Search/classes/GUI/Lucene/SearcherImpl.php index 509139c554fc..9b77e0ab69c8 100755 --- a/components/ILIAS/Search/classes/GUI/Lucene/SearcherImpl.php +++ b/components/ILIAS/Search/classes/GUI/Lucene/SearcherImpl.php @@ -164,7 +164,10 @@ protected function renderResults( string $term, ViewControlInfos $view_control_infos ): void { - if ($filter->getResults() && $highlighter !== null) { + if ( + ($filter->getResults() && $highlighter !== null) || + $view_control_infos->currentPage() > 1 + ) { $result_panel_and_modals = $this->presenter->getLuceneSearchResultAsPanel( $filter, $highlighter, diff --git a/components/ILIAS/Search/classes/GUI/class.ilSearchGUI.php b/components/ILIAS/Search/classes/GUI/class.ilSearchGUI.php index 06978fc17a30..1c3dc17c22df 100755 --- a/components/ILIAS/Search/classes/GUI/class.ilSearchGUI.php +++ b/components/ILIAS/Search/classes/GUI/class.ilSearchGUI.php @@ -237,10 +237,10 @@ protected function renderSearchInput(string $term): void $this->tpl->setVariable("FORM_ACTION", $this->actions->search()); $this->tpl->setVariable("TERM", ilLegacyFormElementsUtil::prepareFormOutput($term)); - $this->tpl->setVariable("SEARCH_LABEL", $this->lng->txt("search")); + $this->tpl->setVariable("SEARCH_LABEL", $this->lng->txt("search_field")); $btn = ilSubmitButton::getInstance(); $btn->setCommand("performSearch"); - $btn->setCaption("search"); + $btn->setCaption("btn_search"); $this->tpl->setVariable("SUBMIT_BTN", $btn->render()); } @@ -261,12 +261,12 @@ protected function fillHeaderAndTabs(): void // tabs $this->tabs->addTab( 'search', - $this->lng->txt('search'), + $this->lng->txt('search_tab_content'), (string) $this->actions->showSavedResults() ); if ($this->settings->enabledLucene() && $this->settings->isLuceneUserSearchEnabled()) { $this->tabs->addTarget( - 'search_user', + 'search_tab_user', $this->ctrl->getLinkTargetByClass(ilLuceneUserSearchGUI::class) ); } diff --git a/components/ILIAS/Search/classes/Presentation/Result/ResultPresenter.php b/components/ILIAS/Search/classes/Presentation/Result/ResultPresenter.php index b19193488890..9522a56aaf2c 100755 --- a/components/ILIAS/Search/classes/Presentation/Result/ResultPresenter.php +++ b/components/ILIAS/Search/classes/Presentation/Result/ResultPresenter.php @@ -43,7 +43,7 @@ public function getDirectSearchResultAsPanel( */ public function getLuceneSearchResultAsPanel( ilLuceneSearchResultFilter $result, - ilLuceneHighlighterResultParser $highlighter, + ?ilLuceneHighlighterResultParser $highlighter, ViewControlInfos $view_control_infos ): array; diff --git a/components/ILIAS/Search/classes/Presentation/Result/ResultPresenterImpl.php b/components/ILIAS/Search/classes/Presentation/Result/ResultPresenterImpl.php index 336fafa2e146..a532f1b3b514 100755 --- a/components/ILIAS/Search/classes/Presentation/Result/ResultPresenterImpl.php +++ b/components/ILIAS/Search/classes/Presentation/Result/ResultPresenterImpl.php @@ -110,6 +110,11 @@ public function getDirectSearchResultAsPanel( $items = $this->sortObjectItems($view_control_infos->sortation(), ...$items_with_sort_data); + if ($items->current() === null) { + // currently only relevant when the total hits are a multiple of max page size (47885) + $items = [$this->component_factory->getNoResultItem()]; + } + return [ $this->component_factory->getPanel( $view_control_infos, @@ -154,14 +159,18 @@ protected function getItemsForSubitemsFromDirectSearch( */ public function getLuceneSearchResultAsPanel( ilLuceneSearchResultFilter $result, - ilLuceneHighlighterResultParser $highlighter, + ?ilLuceneHighlighterResultParser $highlighter, ViewControlInfos $view_control_infos ): array { $items = []; $subitem_modals = []; $items_with_sort_data = []; - foreach ($result->getResults() as $ref_id => $obj_id) { + $results = $result->getResults(); + if ($highlighter === null) { + $results = []; + } + foreach ($results as $ref_id => $obj_id) { $creation_date = $this->obj_properties->lookupCreationDate($obj_id); $type = $this->obj_properties->lookupType($obj_id); $title_no_highlights = $this->obj_properties->lookupTitle($obj_id); @@ -205,6 +214,11 @@ public function getLuceneSearchResultAsPanel( $items = $this->sortObjectItems($view_control_infos->sortation(), ...$items_with_sort_data); + if ($items->current() === null) { + // currently only relevant when the total hits are a multiple of max page size (47885) + $items = [$this->component_factory->getNoResultItem()]; + } + return [ $this->component_factory->getPanel( $view_control_infos, diff --git a/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactory.php b/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactory.php index 2b52080c81f4..216f0a225508 100755 --- a/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactory.php +++ b/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactory.php @@ -63,4 +63,6 @@ public function getModalForSubitems( bool $show_too_many_items_warning, Item ...$items ): ?Modal; + + public function getNoResultItem(): Item; } diff --git a/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactoryImpl.php b/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactoryImpl.php index 5908b3492613..f487850e11b7 100755 --- a/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactoryImpl.php +++ b/components/ILIAS/Search/classes/Presentation/Result/UI/ComponentFactoryImpl.php @@ -213,4 +213,9 @@ public function getItemForSubitem( ->withDescription($this->sanitizer->sanitizeAndSetUpPlaceholders($content)) ->withProperties($properties); } + + public function getNoResultItem(): Item + { + return $this->ui_factory->item()->shy($this->lng->txt('search_no_further_match')); + } } diff --git a/components/ILIAS/Search/classes/class.ilMainMenuSearchGUI.php b/components/ILIAS/Search/classes/class.ilMainMenuSearchGUI.php index 9713961fe160..9a149c745f29 100755 --- a/components/ILIAS/Search/classes/class.ilMainMenuSearchGUI.php +++ b/components/ILIAS/Search/classes/class.ilMainMenuSearchGUI.php @@ -108,9 +108,9 @@ public function getHTML(): string } $this->tpl->setVariable( 'FORMACTION', - $this->buildSearchLink('remoteSearch', false) + $this->buildSearchLink('remoteSearch') ); - $this->tpl->setVariable('BTN_SEARCH', $this->lng->txt('search')); + $this->tpl->setVariable('BTN_SEARCH', $this->lng->txt('btn_search')); $this->tpl->setVariable('SEARCH_INPUT_LABEL', $this->lng->txt('search_field')); $this->tpl->setVariable('IMG_MM_SEARCH', ilUtil::img( @@ -125,7 +125,6 @@ public function getHTML(): string ); $this->tpl->setVariable('TXT_SEARCH_LINK', $this->lng->txt("last_search_result")); } - $this->tpl->setVariable('TXT_SEARCH', $this->lng->txt("search")); return $this->tpl->get(); } diff --git a/components/ILIAS/Search/classes/class.ilSearchFilterGUI.php b/components/ILIAS/Search/classes/class.ilSearchFilterGUI.php index d7c6a48797a5..32f4a02b449b 100644 --- a/components/ILIAS/Search/classes/class.ilSearchFilterGUI.php +++ b/components/ILIAS/Search/classes/class.ilSearchFilterGUI.php @@ -55,7 +55,7 @@ public function __construct(URI $action, bool $for_lucene) } $scope_options[(string) $item["ref_id"]] = strip_tags($item["title"]); } - $inputs["search_scope"] = $field_factory->select($txt("scope"), $scope_options) + $inputs["search_scope"] = $field_factory->select($txt("search_area_filter"), $scope_options) ->withRequired(true) ->withValue(ROOT_FOLDER_ID); $inputs_activated[] = true; diff --git a/components/ILIAS/Session/tests/EventItemsTest.php b/components/ILIAS/Session/tests/EventItemsTest.php index 3fcbc88e1da0..c2e97b045a33 100755 --- a/components/ILIAS/Session/tests/EventItemsTest.php +++ b/components/ILIAS/Session/tests/EventItemsTest.php @@ -48,8 +48,8 @@ protected function setUp(): void $dic = new ILIAS\DI\Container(); $GLOBALS['DIC'] = $dic; - $db = $this->createMock(ilDBInterface::class); - $tree = $this->createMock(ilTree::class); + $db = $this->createStub(ilDBInterface::class); + $tree = $this->createStub(ilTree::class); $this->setGlobalVariable( "ilDB", diff --git a/components/ILIAS/Setup/README.md b/components/ILIAS/Setup/README.md index fecdde1e99d6..3e9e8265f22e 100755 --- a/components/ILIAS/Setup/README.md +++ b/components/ILIAS/Setup/README.md @@ -202,3 +202,578 @@ determine which classes to use for which task: $this->class_loader = include "vendor/ilias/Artifacts/global_screen_providers.php"; } ``` + + +--- + +# Use the Command Line to Manage ILIAS + +The ILIAS command line app can be called via `php setup\setup.php`. It contains four +main commands to manage ILIAS installations: + +* `install` will [set an installation up](#install-ilias) +* `update` will [update an installation](#update-ilias) +* `status` will [report status of an installation](#report-status-of-ilias) +* `build` [recreates static assets](#build-static-assets) of an installation +* `achieve` [a named objective](#achieve-a-named-objective) of an agent +* `migrate` will run [needed migrations](#migrations) + +`install` and `update` also supply switches and options for a granular control of the inclusion of plugins: + +* `--skip-legacy-plugin +* There are also named objectives for **import** and **export**. ` will exclude the named legacy plugin from the command +* `--no-legacy-plugins` will exclude all plugins from the command +* `install ` (or `update ` respectively) will update or install the specified legacy plugin + +`install` requires a [configuration file](#about-the-config-file) to do the job. +`update` can be used without this file for updating the installation only, but is +required to transfer any modified setting from this file to the installation. +The app also supports a `help` command that lists arguments and +options of the available commands. + + +## Install ILIAS + +To install ILIAS with all plugins from the command line, call `php cli/setup.php install config.json` +from within the ILIAS folder you checked out from GitHub (or downloaded from elsewhere). +`config.json` can be the path to some [configuration file](#about-the-config-file) +which does not need to reside in the ILIAS folder. Also, `cli/setup.php` could be +the path to the `setup.php` when the command is called from somewhere else. + +You most probably want to execute the setup with the user that also executes your +webserver to avoid problems with filesystem permissions. The installation creates +directories and files that the webserver will need to read and sometimes even modify. +If you need to run setup as another user, please make sure that the user that executes +the webserver has the necessary filesystem permissions (e.g. by using chown), to +avoid some errors which may be difficult to troubleshoot. + +The setup will ask you to confirm some assumptions during the setup process, where +you will have to type `yes` (or `no`, of course). These checks can be overwritten +with the `--yes` option, which confirm any assumption for you automatically. + +There might be cases where the setup aborts for some reasons. These reasons might +require further actions on your side which the setup cannot perform. Make sure you +read messages from the setup carefully and act accordingly. If you do not change the +config file, it is safe to execute the installation process a second time for the +same installation a during the initial setup process. + +Do not discard the `config.json` you use for the installation, you will need it later +on to update that installation. If you want to overwrite specific fields in the +configuration file you can use the `--config="="` option, even several +times. If you e.g. use `--config="database.password=XYZ"` the field `database.password` +from the original config will be overwritten with `XYZ`. This allows to use one +configuration for multiple setups and overwrite it from the CLI or even share +configs without secrets. + +The setup will also install plugins of the installation, unless the plugin explicitely +defines that it cannot be installed via CLI setup. If you still want to skip a plugin +for installation, use the skip-option: `php cli/setup.php install --skip-legacy-plugin config.json`. +The option can be repeated to cover multiple plugins. If you want to skip plugins +alltogether, use the `--no-legacy-plugins` option. If you only want to install a specific +plugin, use `php cli/setup.php install config.json `. + +The install command also offers the option to import a zip file during setup. The +zip file must have been previously exported from another instance via export +(see [a name objective](#achieve-method)). +The command `php cli/setup.php install --import-file config.json` +will install the data from the export to this instance. + +## Update ILIAS + +To update ILIAS from the command line, call `php cli/setup.php update` +from within your ILIAS folder. This will update ILIAS as well as update the +database of the installation or do other necessary task for the update. +This does not update the source code. +If there are changes in your config.json file call `php cli/setup.php update config.json` +from within your ILIAS folder. This will also update the configuration of ILIAS according +to the provided configuration. + +Plugins are updated just as the core of ILIAS (if the plugin does not exclude itself), +where the plugins can be controlled with the same options as for `install`. + +Sometimes it might happen that the database update steps detect some edge case +or warn about a possible loss of data. In this case the update is aborted with +a message and can be resumed after the messages were read carefully and acted +upon. +You may use the `--ignore-db-update-messages` at your own risk if you want +to silence the messages. + +When an update step failed, you might get a message about inconsistent order +of already performed steps when resuming the setup: +> step 2 was started last, but step 1 was finished last. +> Aborting because of that mismatch. + +You may reset the records for those steps by running: +``` +php setup/setup.php achieve database.resetFailedSteps +``` +However, be sure to understand the cause for the failing steps and tend to it before +resetting and re-running the update. + +## Report Status of ILIAS + +Via `php cli/setup.php status` you can get a status of your ILIAS installation. +The command uses a best effort approach, so according to the status of your +system the output might contain more or less fields. When calling this for a +system where ILIAS was not installed, for example, the output only contains the +information that ilias is not installed. The command also reports on the configuration +of the installation. + +The output of the command is formatted as YAML to be easily readable by people and +machines. So we encourage you to use this command for monitoring your system and +also request status information via our feature process that you are interested in. + +Like for `install` and `update`, plugins are included here, but can be controlled +via options. + + +## Build Static Assets + +There are two types of assets that ILIAS needs to function: + +* **Artifacts** are source code files that are created based on the ILIAS source tree. +* The **Public Folder** is filled with resources from the ILIAS components to be + served on the web. + +You can refresh them by calling `php cli/setup.php build` from your +installation. Make sure you run the command with the webserver user or adjust +filesystem permissions later on, because the webserver will need to access the +generated files. Please do not invoke this function unless it is explicitly stated +in update or patch instructions or you know what you are doing. + +Like for `install` and `update`, plugins are included here, but can be controlled +via options. + + +## Achieve a Named Objective + +Some components of ILIAS will publish named objectives to the setup via their +agent. The most notorious example for this is the component `UICore` which provides +the objective `buildIlCtrlArtifacts` that will generate routing information for the +GUI. To achieve a single objective from an agent, e.g. for control structure reload, +run `php cli/setup.php achieve $AGENT_NAME.$OBJECTIVE_NAME`, e.g. +`php cli/setup.php achieve uicore.buildIlCtrlArtifacts` to generate the necessary +artifacts for the control structure. The agent might need to a config file to work, +which may be added as last parameter: +`php cli/setup.php achieve uicore.buildIlCtrlArtifacts config.json` + +There is also a named objective for **export**. The command +`php cli/setup.php achieve common.buildExportZip config.json` creates a zip file 'ILIAS_EXPORT.zip' at the +location of the call. The export also changes the name of the client directory to +'default' so that the import can work with the files. The objective +'ilFileSystemClientDirectoryRenamedObjective.php' takes care of the renaming. + +The ILIAS export mechanism can be extended with ExportHooks. This allows you to influence the exported database during the export. +The ExportHooks file must be a PHP file and can be placed anywhere. It only has to be ensured that ILIAS has access to this file. +The path to the file can either be set permanently in config.json under the namespace common. +```bash +"common" : { + "client_id" : "ilias", + "master_password" : "ilias", + "server_timezone" : "Europe/Berlin", + "export_hooks_path" : "/var/ilias/export.php" + } +``` +Or you can specify it once when calling up the export command. +```bash +php cli/setup.php achieve common.buildExportZip --config="common.export_hooks_path=/var/ilias/export.php" config.json -y +``` +This [mysqldump](https://github.com/ifsnop/mysqldump-php#changing-values-when-exporting) hooks can be used in the export hooks file. +An example file could look like this (the variable $dumper is indirectly available). +```php +setTransformTableRowHook(function ($tableName, array $row) { + if ($tableName === 'write_event') { + if ($row['obj_id'] == 100) { + $row['usr_id'] = -1; + } + } + + return $row; +}); +``` +The zip file can then be imported using the install command. + +## List available objectives +Calling `php cli/setup.php achieve` without any arguments and options +or calling `php cli/setup.php achieve --list` will list all available objectives. + + +# Migrations + +Migrations are major changes in the ILIAS database or file system that are +necessary after an update. Migrations can take quite a long time, which is +why they are available separately as a command. The advantage is that you can +perform migrations after the update when the installation is already online again. +For more information, see [https://docu.ilias.de/goto_docu_wiki_wpage_6399_1357.html](https://docu.ilias.de/goto_docu_wiki_wpage_6399_1357.html) + +The command lists available migrations: + +`php cli/setup.php migrate` + + +``` +! [NOTE] There are 1 to run: + +ilFileObjectMigrationAgent.ilFileObjectToStorageMigration: Migration of File-Objects to Storage service [remaining steps: 1110] +``` + +Individual migrations can then be started as follows, e.g.: + +`php cli/setup.php migrate --run ilFileObjectMigrationAgent.ilFileObjectToStorageMigration` + +A migration must be confirmed in each case, e.g.: + +``` +Do you really want to run the following migration? Make sure you have a backup +of all your data. You will run this migration on your own risk. + +Please type 'ilFileObjectToStorageMigration' to confirm and start.: +> +``` + +With `--yes` migrations can be confirmed automatically. + +Migrations are divided into individual steps, of which there can be many depending +on the migration. A default number of steps is executed in each case; the number +can be increased or set with `--steps=...`. + +## About the Config File + +The config file is a json file with the following structure. **Mandatory fields +are printed bold**, all other fields might be omitted. A minimal example is +[here](minimal-config.json). + +* **common** (type: object) settings relevant for the complete installation, e.g.: + ``` + "common" : { + "client_id" : "test7", + "server_timezone" : "Europe/Berlin", + "register_nic" : true, + "export_hooks_path" : "/var/ilias/export_hooks.php" + } + ``` + * **client_id** (type: string) is the identifier to be used for the installation + * *server_timezone* (type: string) where the installation resides, given as `region/city`, + e.g. `Europe/Berlin`, defaults to `UTC` + * *register_nic* (boolean) sends the identification number of the installation to a server + of the ILIAS society together with some information about the installation, defaults to `false` + * *export_hooks_path* (type: string) The path to the PHP export hooks file, not required and defaults to null if absent. Setting to an empty string results in an error during export. +* *backgroundtasks* (type: object) is a service to run tasks for users in separate processes, e.g.: + ``` + "backgroundtasks" : { + "type" : "sync", + "max_number_of_concurrent_tasks" : 3 + }, + ``` + * *type* (type: string) might be `async` or `sync`, defaults to `sync`; async requires SOAP (c.f. webservices) to be enabled + * *max_number_of_concurrent_tasks* (type: number) that all users can run together, defaults to `1` +* **database** (type: object) is required to connect to the database, e.g.: + ``` + "database" : { + "type" : "innodb", + "host" : "192.168.47.11", + "port" : 3306, + "database" : "db_test7", + "user" : "test7_homer", + "password" : "homers-secret", + "create_database" : true + }, + ``` + * *type* (type: string) of the database, `innodb`, defaults + to `innodb` + * *host* (type: string) the database server runs on, defaults to `localhost` + * *port* (type: string or number) the database server uses, defaults to `3306` + * *database* (type: string) name to be used, defaults to `ilias` + * **user** (type: string) to be used to connect to the database + * *password* (type: string) to be used to connect to the database + * *create_database* (type: boolean) if a database with the given name does not exist? Defaults to `true`. +* **filesystem** (type: object) configuration, e.g.: + ``` + "filesystem" : { + "data_dir" : "/var/ilias_external_data/test7" + }, + ``` + * **data_dir** (type: string) outside the web directory where ILIAS puts some data +* *globalcache* (type: object) is a service for caching various information, e.g.: + ``` + "globalcache" : { + "service" : "static", + "components" : "all" + }, + ``` + or + ``` + "globalcache" : { + "service" : "apc", + "components" : { + "clng" : true, + "comp" : true, + "events" : true, + "global_screen" : true, + "obj_def" : true, + "ilctrl" : true, + "tpl" : true, + "tpl_blocks" : true, + "tpl_variables" : true + } + }, + ``` + or + ``` + "globalcache" : { + "service" : "memcached", + "components" : "all", + "memcached_nodes" : [ + { + "active" : true, + "host" : "example1.com", + "port" : 4711, + "weight" : 10 + }, + { + "active" : false, + "host" : "example2.com", + "port" : 4712, + "weight" : 90 + } + ] + }, + ``` + * *service* (type: string) to be used for caching. Either `none`, `static`, `memcached` + or `apc`, defaults to `static`. + * *components* (type: string or object) that should use caching. Can be `all` or any list of components that + support caching, (must be set too, if *service* is set) + * *memcached_nodes* (type: array of objects) if *service* equals `memcached` place your nodes here +* **http** (type: object) configuration, e.g.: + ``` + "http" : { + "path" : "https://test7.ilias.de/", + "https_autodetection" : { + "header_name" : "my-header-name", + "header_value" : "my-header-value" + }, + "proxy" : { + "host" : "webproxy.ilias.de", + "port" : "8088" + }, + "allowed_hosts" : [ + "red.ilias.de", + "blue.ilias.de", + "www.ilias.de" + ] + }, + ``` + * **path** (type: string) to your installation on the internet + * *https_autodetection* (type: object) allows ILIAS to be run behind a proxy that terminates ssl + connections + * *header_name* (type: string) that the proxy sets to indicate ssl connections + * *header_value* (type: string) that the proxy sets for said header + * *proxy* (type: object) for outgoing http connections + * *host* (type: string) the proxy runs on + * *port* (type: string or number) the proxy listens on + * *allowed_hosts* (type: an `array`/list of strings, or `null`) A list of valid hosts which is used to + validate the `HTTP_HOST` header of incoming web requests. If the host header does not match any of + the allowed hosts, the request is rejected. If `null` is set or an empty list is provided, the host + header is only validated against the host of the `path` setting + (stored in the "ilias.ini.php" as `http_path`), which is always considered allowed. + This also applies for the optionally configurable host used for the WSDL path definition + in the SOAP web service configuration and for "localhost". +* *logging* (type: object) configuration if logging should be used + ``` + "logging" : { + "enable" : true, + "path_to_logfile" : "/var/log/ilias_test7.log", + "errorlog_dir" : "/var/log/ilias_errorlogs/" + }, + ``` + * *enable* (type: boolean) the logging, defaults to `false` + * *path_to_logfile* (type: string) to be used for logging + * *errorlog_dir* (type: string) to put error logs in +* *preview* (type: object) contains settings for ILIAS/Preview + ``` + "preview" : { + "path_to_ghostscript" : "/usr/bin/gs" + }, + ``` + * *path_to_ghostscript* (type: string) executable +* *mediaobject* (type: object) contains settings for ILIAS/MediaObjects + ``` + "mediaobject" : { + "path_to_ffmpeg" : "/usr/bin/ffmpeg" + }, + ``` + * *path_to_ffmpeg* (type: string) executable +* *style* (type: obejct) configuration to change the ILIAS look + ``` + "style" : { + "manage_system_styles" : true, + "path_to_scss" : "/usr/bin/scss" + }, + ``` + * *manage_system_styles* (type: boolean) via a GUI in the installation, defaults to `false` + * *path_to_scss* (type: string) to compile scss to css +* **systemfolder** (type: object) settings for ILIAS/SystemFolder + ``` + "systemfolder" : { + "client" : { + "name" : "test7", + "description" : "Test Installation for ILIAS 7", + "institution" : "Atomic Powerplant Springfield" + }, + "contact" : { + "firstname" : "Homer", + "lastname" : "Simpson", + "title" : "Sir", + "position" : "Security Inspector Sector 7G", + "institution" : "Atomic Powerplant Springfield", + "street" : "742 Evergreen Terrace", + "zipcode" : "12345", + "city" : "Springfield", + "country" : "USA", + "phone" : "(939) 555-0113", + "email" : "Chunkylover53@aol.com" + } + }, + ``` + * *client* (type: string) information + * *name* (type: string) of the ILIAS installation + * *description* (type: string) of the installation + * *institution* (type: string) that provides the installation + * **contact** (type: string) to a person behind the installation + * **firstname** (type: string) of said person + * **lastname** (type: string) of said person + * *title* (type: string) of said person + * *position* (type: string) of said person + * *institution* (type: string) of said person + * *street* (type: string) of said person + * *zipcode* (type: string) of said person + * *city* (type: string) of said person + * *country* (type: string) of said person + * *phone* (type: string) of said person + * **email** (type: string) of said person +* *utilities* (type: object) contains settings for ILIAS/Utilities + ``` + "utilities" : { + "path_to_convert" : "/usr/bin/convert", + "path_to_zip" : "/usr/bin/zip", + "path_to_unzip" : "/usr/bin/unzip" + }, + ``` + * *path_to_convert* (type: string) from ImageMagick, to resize images + * *path_to_zip*" (type: string) to zip files + * *path_to_unzip*" (type: string) to unzip files +* *virusscanner* (type: object) configuration + ``` + "virusscanner" : { + "virusscanner" : "clamav", + "path_to_scan" : "/usr/bin/clamdscan", + "path_to_clean" : "/usr/bin/clamdscan --remove=yes", + }, + ``` + or + ``` + "virusscanner" : { + "virusscanner" : "icap", + "icap_host" : "192.168.47.12", + "icap_port" : 4712, + "icap_service_name" : "icap-name", + "icap_client_path" : "icap-client-path" + }, + ``` + * *virusscanner* (type: string) to be used. Either `none`, `sophos`, `antivir`, `clamav` or `icap` + * *path_to_scan* (type: string) command of the scanner + * *path_to_clean* (type: string) command of the scanner + * *icap_host* (type: string) host address of the icap scanner + * *icap_port* (type: string or number) port if the icap scanner + * *icap_service_name* (type: string) service name of the icap scanner + * *icap_client_path* (type: string) path to the `c-icap-client`, if this is left empty, a php client will be used +* *privacysecurity* (type: object) + ``` + "privacysecurity" : { + "https_enabled" : true, + "auth_duration" : 3000, + "account_assistance_duration" : 3000, + "registration_duration" : 3000, + }, + ``` + * *https_enabled* (type: boolean) forces https on login page, defaults to `false` + * *auth_duration* (type: integer) stretches the auth-duration on logins to the given amount in ms, defaults to `null` + * *account_assistance_duration* (type: integer) stretches the password- and username-assistance duration to the given amount in ms, defaults to `null` + * *registration_duration* (type: integer) stretches registration duration to the given amount in ms, defaults to `null` +* *webservices* (type: object) + ``` + "webservices" : { + "soap_user_administration" : true, + "soap_wsdl_path" : "https://test7.ilias.de/public/soap/server.php?wsdl", + "soap_connect_timeout" : 30, + "rpc_server_host" : "192.168.47.13", + "rpc_server_port" : "11112", + "soap_internal_wsdl_path": "https://localhost/public/soap/server.php?wsdl", + "soap_internal_wsdl_verify_peer": false, + "soap_internal_wsdl_verify_peer_name": false, + "soap_internal_wsdl_allow_self_signed": false + }, + ``` + * *soap_user_administration* (type: boolean) enable administration per soap, defaults to `false` + * *soap_wsdl_path* (type: string) path to the ilias wsdl file, default is `http:///public/soap/server.php?wsdl` + * *soap_connect_timeout* (type: number) maximum time in seconds until a connection attempt to the SOAP-Webservice is interrupted, defaults to `10` + * *rpc_server_host* (type: string) Java-Server host (must be set too, if *rpc_server_port* is set) + * *rpc_server_port* (type: string or number) Java-Server port (must be set too, if *rpc_server_host* is set) + * *soap_internal_wsdl_path* (type: string) path to the ilias wsdl file for internal usage (for calls from ilias to ilias itself), default is *soap_wsdl_path* + * *soap_internal_wsdl_verify_peer* (type: bool) verify peer for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php for more information) + * *soap_internal_wsdl_verify_peer_name* (type: bool) verify peer name for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php) + * *soap_internal_wsdl_allow_self_signed* (type: bool) allow self signed certificates for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php) +* *chatroom* (type: object) see also [Chat Server Setup](/components/ILIAS/Chatroom/README.md), eg.: + ``` + "chatroom" : { + "address" : "192.168.47.14", + "port" : 8081, + "sub_directory" : "/chat", + "https" : { + "cert" : "/etc/ssl/certs/server.pem", + "key" : "/etc/ssl/private/server.key", + "dhparam" : "/etc/ssl/private/dhparam.pem" + }, + "log" : "/var/log/ilias_onscreenchat/access.log", + "log_level" : "info", + "error_log" : "/var/log/ilias_onscreenchat/error.log", + "ilias_proxy" : { + "ilias_url" : "https://chat-ilias-proxy.ilias.de" + }, + "client_proxy" : { + "client_url" : "https://chat-client-proxy.ilias.de" + }, + "deletion_interval" : { + "deletion_unit" : "months", + "deletion_value" : "6", + "deletion_time" : "23:45" + } + } + ``` + * *address* (type: string) IP-Address/FQN of Chat Server + * *port* (type: string or number) of the chat server, possible value from `1` to `65535` + * *sub_directory* (type: string) http(s)://[IP/Domain]/[SUB_DIRECTORY] + * *https* (type: object) adding this enables https + * *cert* (type: string) absolute server path to the SSL certificate file e.g. `/etc/ssl/certs/server.pem` + * *key* (type: string) absolute server path to the private key file e.g. `/etc/ssl/private/server.key` + * *dhparam* (type: string) absolute server path to a file e.g. `/etc/ssl/private/dhparam.pem` + * *log* (type: string) absolute server path to the chat server's log file e.g. `/var/www/ilias/data/chat.log` + * *log_level* (type: string) possible values are `emerg`, `alert`, `crit` `error`, `warning`, `notice`, `info`, `debug`, `silly`, defaults to `warning` + * *error_log* (type: string) absolute server path to the chat server's error log file e.g. `/var/www/ilias/data/chat_error.log` + * *ilias_proxy* (type: object) ILIAS to Server Connection + * *ilias_url* (type: string) URL for the Server connection + * *client_proxy* (type: object) Client to Server Connection + * *client_url* URL for the Server connection + * *deletion_interval* (type: object) + * *deletion_unit* (type: string) possible values are `days`, `weeks`, `months`, `years` + * *deletion_value* (type: string or number) depending on `deletion_unit` possible values are `days max 31`, `weeks max 52`, `months max 12`, `years no max` + * *deletion_time* (type: string) with format `HH:MM e.g. 23:30` +* *authentication* (type: object) + ``` + "authentication" : { + "session_max_idle": 1800 + } + ``` + * *session_max_idle* (type: number) maximum session idle (in seconds) diff --git a/components/ILIAS/setup_/classes/class.ilCommonSetupAgent.php b/components/ILIAS/Setup/classes/class.ilCommonSetupAgent.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilCommonSetupAgent.php rename to components/ILIAS/Setup/classes/class.ilCommonSetupAgent.php diff --git a/components/ILIAS/setup_/classes/class.ilExportMetadataGatheredObjective.php b/components/ILIAS/Setup/classes/class.ilExportMetadataGatheredObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilExportMetadataGatheredObjective.php rename to components/ILIAS/Setup/classes/class.ilExportMetadataGatheredObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilExportZipBuiltObjective.php b/components/ILIAS/Setup/classes/class.ilExportZipBuiltObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilExportZipBuiltObjective.php rename to components/ILIAS/Setup/classes/class.ilExportZipBuiltObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilIniFilesLoadedObjective.php b/components/ILIAS/Setup/classes/class.ilIniFilesLoadedObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilIniFilesLoadedObjective.php rename to components/ILIAS/Setup/classes/class.ilIniFilesLoadedObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilInstIdDefaultStoredObjective.php b/components/ILIAS/Setup/classes/class.ilInstIdDefaultStoredObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilInstIdDefaultStoredObjective.php rename to components/ILIAS/Setup/classes/class.ilInstIdDefaultStoredObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilMakeInstallationAccessibleObjective.php b/components/ILIAS/Setup/classes/class.ilMakeInstallationAccessibleObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilMakeInstallationAccessibleObjective.php rename to components/ILIAS/Setup/classes/class.ilMakeInstallationAccessibleObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilNICKeyRegisteredObjective.php b/components/ILIAS/Setup/classes/class.ilNICKeyRegisteredObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilNICKeyRegisteredObjective.php rename to components/ILIAS/Setup/classes/class.ilNICKeyRegisteredObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilNICKeyStoredObjective.php b/components/ILIAS/Setup/classes/class.ilNICKeyStoredObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilNICKeyStoredObjective.php rename to components/ILIAS/Setup/classes/class.ilNICKeyStoredObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilNoMajorVersionSkippedConditionObjective.php b/components/ILIAS/Setup/classes/class.ilNoMajorVersionSkippedConditionObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilNoMajorVersionSkippedConditionObjective.php rename to components/ILIAS/Setup/classes/class.ilNoMajorVersionSkippedConditionObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilNoVersionDowngradeConditionObjective.php b/components/ILIAS/Setup/classes/class.ilNoVersionDowngradeConditionObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilNoVersionDowngradeConditionObjective.php rename to components/ILIAS/Setup/classes/class.ilNoVersionDowngradeConditionObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilOverwritesExistingInstallationConfirmed.php b/components/ILIAS/Setup/classes/class.ilOverwritesExistingInstallationConfirmed.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilOverwritesExistingInstallationConfirmed.php rename to components/ILIAS/Setup/classes/class.ilOverwritesExistingInstallationConfirmed.php diff --git a/components/ILIAS/setup_/classes/class.ilOwnRiskConfirmedObjective.php b/components/ILIAS/Setup/classes/class.ilOwnRiskConfirmedObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilOwnRiskConfirmedObjective.php rename to components/ILIAS/Setup/classes/class.ilOwnRiskConfirmedObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilSetupConfig.php b/components/ILIAS/Setup/classes/class.ilSetupConfig.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilSetupConfig.php rename to components/ILIAS/Setup/classes/class.ilSetupConfig.php diff --git a/components/ILIAS/setup_/classes/class.ilSetupConfigStoredObjective.php b/components/ILIAS/Setup/classes/class.ilSetupConfigStoredObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilSetupConfigStoredObjective.php rename to components/ILIAS/Setup/classes/class.ilSetupConfigStoredObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilSetupMetricsCollectedObjective.php b/components/ILIAS/Setup/classes/class.ilSetupMetricsCollectedObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilSetupMetricsCollectedObjective.php rename to components/ILIAS/Setup/classes/class.ilSetupMetricsCollectedObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilSetupObjective.php b/components/ILIAS/Setup/classes/class.ilSetupObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilSetupObjective.php rename to components/ILIAS/Setup/classes/class.ilSetupObjective.php diff --git a/components/ILIAS/setup_/classes/class.ilUseRootConfirmed.php b/components/ILIAS/Setup/classes/class.ilUseRootConfirmed.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilUseRootConfirmed.php rename to components/ILIAS/Setup/classes/class.ilUseRootConfirmed.php diff --git a/components/ILIAS/setup_/classes/class.ilVersionWrittenToSettingsObjective.php b/components/ILIAS/Setup/classes/class.ilVersionWrittenToSettingsObjective.php similarity index 100% rename from components/ILIAS/setup_/classes/class.ilVersionWrittenToSettingsObjective.php rename to components/ILIAS/Setup/classes/class.ilVersionWrittenToSettingsObjective.php diff --git a/components/ILIAS/setup_/minimal-config.json b/components/ILIAS/Setup/minimal-config.json similarity index 59% rename from components/ILIAS/setup_/minimal-config.json rename to components/ILIAS/Setup/minimal-config.json index 41d9260ed3d5..fb56a291e991 100755 --- a/components/ILIAS/setup_/minimal-config.json +++ b/components/ILIAS/Setup/minimal-config.json @@ -9,13 +9,13 @@ "data_dir" : "/var/lib/ilias" }, "http" : { - "path" : "http://demo1.cat06.de" + "path" : "http://www.example.com" }, "systemfolder" : { "contact" : { - "firstname" : "Richard", - "lastname" : "Klees", - "email" : "richard.klees@concepts-and-training.de" + "firstname" : "Lucy", + "lastname" : "Snowe", + "email" : "lucysnowe@ilias.de" } } } diff --git a/components/ILIAS/Setup/src/AbstractOfFinder.php b/components/ILIAS/Setup/src/AbstractOfFinder.php index df9ecb077656..3ccd7024a183 100755 --- a/components/ILIAS/Setup/src/AbstractOfFinder.php +++ b/components/ILIAS/Setup/src/AbstractOfFinder.php @@ -51,7 +51,7 @@ abstract class AbstractOfFinder '.*/components/ILIAS/Types/tests/', '.*/components/ILIAS/UI/tests/', '.*/components/ILIAS/VirusScanner/tests/', - '.*/components/ILIAS/setup_/', + '.*/components/ILIAS/Setup/classes/', // Classes using unknown '.*ilPDExternalFeedBlockGUI.*', ]; diff --git a/components/ILIAS/Skill/Table/classes/class.AssignMaterialsTable.php b/components/ILIAS/Skill/Table/classes/class.AssignMaterialsTable.php index f13a28acb197..d78033815bad 100755 --- a/components/ILIAS/Skill/Table/classes/class.AssignMaterialsTable.php +++ b/components/ILIAS/Skill/Table/classes/class.AssignMaterialsTable.php @@ -100,7 +100,7 @@ protected function getColumns(): array ->withIsSortable(false), "description" => $this->ui_fac->table()->column()->text($this->lng->txt("description")) ->withIsSortable(false), - "resources" => $this->ui_fac->table()->column()->linkListing($this->lng->txt("skmg_materials")) + "resources" => $this->ui_fac->table()->column()->listing($this->lng->txt("skmg_materials")) ->withIsSortable(false) ]; diff --git a/components/ILIAS/Survey/Editing/class.ilSurveyEditorGUI.php b/components/ILIAS/Survey/Editing/class.ilSurveyEditorGUI.php index 60b941a8f1c9..be28acdba425 100755 --- a/components/ILIAS/Survey/Editing/class.ilSurveyEditorGUI.php +++ b/components/ILIAS/Survey/Editing/class.ilSurveyEditorGUI.php @@ -16,6 +16,8 @@ * *********************************************************************/ +declare(strict_types=1); + use ILIAS\Survey\Editing\EditManager; use ILIAS\Survey\Editing\EditingGUIRequest; @@ -48,6 +50,7 @@ class ilSurveyEditorGUI protected ilObjSurveyGUI $parent_gui; protected ilObjSurvey $object; protected array $print_options; + protected \ilHtmlPurifierInterface $purifier; public function __construct(ilObjSurveyGUI $a_parent_gui) { @@ -72,6 +75,7 @@ public function __construct(ilObjSurveyGUI $a_parent_gui) $this->tpl = $tpl; $this->ctrl->saveParameter($this, array("pgov", "pgov_pos")); + $this->purifier = new ilSvyStandardPurifier(); $this->print_options = array( //0 => $this->lng->txt('none'), @@ -224,7 +228,7 @@ public function questionsObject(): void $ilToolbar->setFormAction($this->ctrl->getFormAction($this)); $types = new ilSelectInputGUI($this->lng->txt("create_new"), "sel_question_types"); $types->setOptions($qtypes); - $ilToolbar->addStickyItem($types, ""); + $ilToolbar->addStickyItem($types, false); $this->gui->button( $this->lng->txt("svy_create_question"), @@ -289,7 +293,7 @@ protected function gatherSelectedTableItems( ): array { $block_map = array(); foreach ($this->object->getSurveyQuestions() as $item) { - $block_map[$item["question_id"]] = $item["questionblock_id"]; + $block_map[(int) $item["question_id"]] = (int) $item["questionblock_id"]; } $questions = $blocks = $headings = array(); @@ -300,16 +304,16 @@ protected function gatherSelectedTableItems( if ($allow_questions && preg_match("/cb_(\d+)/", $key, $matches)) { if (($allow_questions_in_blocks || !$block_map[$matches[1]]) && !in_array($block_map[$matches[1]], $blocks)) { - $questions[] = $matches[1]; + $questions[] = (int) $matches[1]; } } // blocks if ($allow_blocks && preg_match("/cb_qb_(\d+)/", $key, $matches)) { - $blocks[] = $matches[1]; + $blocks[] = (int) $matches[1]; } // headings if ($allow_headings && preg_match("/cb_tb_(\d+)/", $key, $matches)) { - $headings[] = $matches[1]; + $headings[] = (int) $matches[1]; } } } @@ -370,7 +374,7 @@ public function moveQuestionsObject(): void $move_questions = $items["questions"]; foreach ($items["blocks"] as $block_id) { - foreach ($this->object->getQuestionblockQuestionIds($block_id) as $qid) { + foreach ($this->object->getQuestionblockQuestionIds((int) ($block_id)) as $qid) { $move_questions[] = $qid; } } @@ -418,7 +422,7 @@ protected function insertQuestions( } } if (!$insert_id && preg_match("/^cb_qb_(\d+)$/", $target, $matches)) { - $ids = $this->object->getQuestionblockQuestionIds($matches[1]); + $ids = $this->object->getQuestionblockQuestionIds((int) $matches[1]); if (count($ids)) { if ($insert_mode === 0) { $insert_id = $ids[0]; @@ -475,7 +479,7 @@ public function removeQuestionsForm( $cgui->addItem( "q_id[]", - $data["question_id"], + (string) $data["question_id"], $type . ": " . $data["title"] ); } elseif ((in_array($data["questionblock_id"], $checked_questionblocks))) { @@ -483,13 +487,13 @@ public function removeQuestionsForm( $cgui->addItem( "cb[" . $data["questionblock_id"] . "]", - $data["questionblock_id"], + (string) $data["questionblock_id"], $data["questionblock_title"] . " - " . $type . ": " . $data["title"] ); } elseif (in_array($data["question_id"], $checked_headings)) { $cgui->addItem( "heading[" . $data["question_id"] . "]", - $data["question_id"], + (string) $data["question_id"], $data["heading"] ); } @@ -524,7 +528,7 @@ public function copyQuestionsToPoolObject(): void // gather questions from blocks $copy_questions = $items["questions"]; foreach ($items["blocks"] as $block_id) { - foreach ($this->object->getQuestionblockQuestionIds($block_id) as $qid) { + foreach ($this->object->getQuestionblockQuestionIds((int) $block_id) as $qid) { $copy_questions[] = $qid; } } @@ -533,7 +537,7 @@ public function copyQuestionsToPoolObject(): void // only if not already in pool if (count($copy_questions)) { foreach ($copy_questions as $idx => $question_id) { - $question = ilObjSurvey::_instanciateQuestion($question_id); + $question = ilObjSurvey::_instanciateQuestion((int) $question_id); if ($question->getOriginalId()) { unset($copy_questions[$idx]); } @@ -691,7 +695,7 @@ public function changeDatatypeObject(): void { $ilUser = $this->user; - $ilUser->writePref('svy_insert_type', $this->request->getDataType()); + $ilUser->writePref('svy_insert_type', (string) $this->request->getDataType()); switch ($this->request->getDataType()) { case 2: @@ -893,7 +897,7 @@ protected function initQuestionblockForm( if ($a_question_ids) { foreach ($a_question_ids as $q_id) { $hidden = new ilHiddenInputGUI("qids[]"); - $hidden->setValue($q_id); + $hidden->setValue((string) $q_id); $form->addItem($hidden); } } @@ -915,9 +919,9 @@ public function saveDefineQuestionblockObject(): void $form = $this->initQuestionblockForm($block_id); if ($form->checkInput()) { $title = $form->getInput("title"); - $show_questiontext = $form->getInput("show_questiontext"); - $show_blocktitle = $form->getInput("show_blocktitle") ; - $compress_view = $form->getInput("compress_view") ; + $show_questiontext = (bool) $form->getInput("show_questiontext"); + $show_blocktitle = (bool) $form->getInput("show_blocktitle"); + $compress_view = (bool) $form->getInput("compress_view"); if ($block_id) { $this->object->modifyQuestionblock( $block_id, @@ -962,6 +966,8 @@ protected function initHeadingForm( $heading->setRows(10); $heading->setCols(80); $heading->setRequired(true); + $heading->usePurifier(true); + $heading->setPurifier($this->purifier); $form->addItem($heading); $insertbefore = new ilSelectInputGUI($this->lng->txt("insert"), "insertbefore"); @@ -1027,12 +1033,11 @@ public function saveHeadingObject(): void $form = $this->initHeadingForm($q_id); if ($form->checkInput()) { - $purifier = new ilSvyStandardPurifier(); - $heading = $form->getInput("heading"); - - $heading = $purifier->purify($heading); - - $this->object->saveHeading($heading, $form->getInput("insertbefore")); + $heading = $this->purifier->purify($form->getInput("heading")); + $this->object->saveHeading( + $heading, + (int) $form->getInput("insertbefore") + ); $this->ctrl->redirect($this, "questions"); } diff --git a/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php b/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php index f34921b212bb..77bd940b0f2c 100755 --- a/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php +++ b/components/ILIAS/Survey/Evaluation/class.ilSurveyEvaluationGUI.php @@ -296,7 +296,7 @@ public function exportCumulatedResults( ): void { $finished_ids = null; if ($this->object->get360Mode()) { - $appr_id = $this->request->getAppraiseeId(); + $appr_id = $this->getAppraiseeId(); if (!$appr_id) { $this->ctrl->redirect($this, $details ? "evaluationdetails" : "evaluation"); } @@ -1069,7 +1069,7 @@ public function exportEvaluationUser(): void $finished_ids = null; if ($this->object->get360Mode()) { - $appr_id = $this->request->getAppraiseeId(); + $appr_id = $this->getAppraiseeId(); if (!$appr_id) { $this->ctrl->redirect($this, "evaluationuser"); } diff --git a/components/ILIAS/Survey/Evaluation/templates/default/tpl.il_svy_svy_results_details.html b/components/ILIAS/Survey/Evaluation/templates/default/tpl.il_svy_svy_results_details.html index 902e2272d0f3..4247bcd3412e 100755 --- a/components/ILIAS/Survey/Evaluation/templates/default/tpl.il_svy_svy_results_details.html +++ b/components/ILIAS/Survey/Evaluation/templates/default/tpl.il_svy_svy_results_details.html @@ -1,2 +1,2 @@ -
{PANEL_TOC}
+
{PANEL_TOC}
{PANEL_REPORT} diff --git a/components/ILIAS/Survey/Evaluation/templates/default/tpl.svy_results_details_panel.html b/components/ILIAS/Survey/Evaluation/templates/default/tpl.svy_results_details_panel.html index fb77d8bd7b0f..0d8dc0365099 100755 --- a/components/ILIAS/Survey/Evaluation/templates/default/tpl.svy_results_details_panel.html +++ b/components/ILIAS/Survey/Evaluation/templates/default/tpl.svy_results_details_panel.html @@ -1,5 +1,5 @@ -
+
{TABLE} {CHART} {TEXT} diff --git a/components/ILIAS/Survey/Execution/class.ilSurveyExecutionGUI.php b/components/ILIAS/Survey/Execution/class.ilSurveyExecutionGUI.php index 4a9ea5ed3301..68c68c54f1ea 100755 --- a/components/ILIAS/Survey/Execution/class.ilSurveyExecutionGUI.php +++ b/components/ILIAS/Survey/Execution/class.ilSurveyExecutionGUI.php @@ -149,7 +149,7 @@ public function executeCommand(): string protected function checkAuth( bool $a_may_start = false, - bool $a_ignore_status = false + bool $a_finished_run = false ): void { $rbacsystem = $this->rbacsystem; $ilUser = $this->user; @@ -162,8 +162,12 @@ protected function checkAuth( } - if (!$this->access_manager->canStartSurvey()) { - // only with read access it is possible to run the test + if ($a_finished_run && + !$this->access_manager->canRead() && + !$this->participant_manager->isExternalRater()) { + throw new ilSurveyException($this->lng->txt("cannot_read_survey")); + } + if (!$a_finished_run && !$this->access_manager->canStartSurvey()) { throw new ilSurveyException($this->lng->txt("cannot_read_survey")); } @@ -211,7 +215,11 @@ protected function checkAuth( //$_SESSION["appr_id"][$this->object->getId()] = $appr_id; - if (!$a_ignore_status) { + if ($a_finished_run) { + if (!$this->run_manager->hasFinished()) { + throw new ilSurveyException($this->lng->txt("cannot_read_survey")); + } + } else { // completed if ($this->run_manager->hasFinished()) { $this->tpl->setOnScreenMessage('failure', $this->lng->txt("already_completed_survey"), true); diff --git a/components/ILIAS/Survey/Settings/class.SettingsFormGUI.php b/components/ILIAS/Survey/Settings/class.SettingsFormGUI.php index 5bc33bcd02bf..3568823bf0ef 100755 --- a/components/ILIAS/Survey/Settings/class.SettingsFormGUI.php +++ b/components/ILIAS/Survey/Settings/class.SettingsFormGUI.php @@ -39,13 +39,15 @@ class SettingsFormGUI protected \ILIAS\Survey\Mode\FeatureConfig $feature_config; protected \ilRbacSystem $rbacsystem; private \ilGlobalTemplateInterface $main_tpl; + protected \ilHtmlPurifierInterface $purifier; public function __construct( InternalGUIService $ui_service, InternalDomainService $domain_service, \ilObjectService $object_service, \ilObjSurvey $survey, - UIModifier $modifier + UIModifier $modifier, + \ilHtmlPurifierInterface $purifier ) { global $DIC; $this->main_tpl = $DIC->ui()->mainTemplate(); @@ -58,6 +60,7 @@ public function __construct( $this->domain_service = $domain_service; $this->modifier = $modifier; $this->feature_config = $this->domain_service->modeFeatureConfig($survey->getMode()); + $this->purifier = $purifier; } public function checkForm(\ilPropertyFormGUI $form): bool @@ -333,6 +336,9 @@ public function withBeforeStart( $intro->setUseRte(true); $intro->setRteTagSet("mini"); } + $intro->usePurifier(true); + $intro->setPurifier(new \ilSvyStandardPurifier()); + $form->addItem($intro); return $form; @@ -451,6 +457,8 @@ public function withAfterEnd( $finalstatement->setUseRte(true); $finalstatement->setRteTagSet("mini"); } + $finalstatement->usePurifier(true); + $finalstatement->setPurifier(new \ilSvyStandardPurifier()); $form->addItem($finalstatement); // mail notification @@ -884,14 +892,10 @@ public function saveForm( } else { $survey->setEndDate(""); } + $introduction = $this->purifier->purify($form->getInput('introduction')); - $purifier = new ilSvyStandardPurifier(); - - $introduction = $form->getInput("introduction"); - $introduction = $purifier->purify($introduction); $survey->setIntroduction($introduction); - $outro = $form->getInput("outro"); - $outro = $purifier->purify($outro); + $outro = $this->purifier->purify($form->getInput('outro')); $survey->setOutro($outro); $survey->setShowQuestionTitles((bool) $form->getInput("show_question_titles")); diff --git a/components/ILIAS/Survey/Settings/class.UIFactory.php b/components/ILIAS/Survey/Settings/class.UIFactory.php index c75f313f2035..e3394524deab 100755 --- a/components/ILIAS/Survey/Settings/class.UIFactory.php +++ b/components/ILIAS/Survey/Settings/class.UIFactory.php @@ -48,7 +48,8 @@ public function __construct( $this->domain_service, $object_service, $survey, - $mode_ui_modifier + $mode_ui_modifier, + new \ilSvyStandardPurifier() ); } diff --git a/components/ILIAS/Survey/classes/class.ilObjSurveyGUI.php b/components/ILIAS/Survey/classes/class.ilObjSurveyGUI.php index a4d333aea3d0..12117831cb8a 100755 --- a/components/ILIAS/Survey/classes/class.ilObjSurveyGUI.php +++ b/components/ILIAS/Survey/classes/class.ilObjSurveyGUI.php @@ -16,6 +16,8 @@ * *********************************************************************/ +declare(strict_types=1); + use ILIAS\Survey\Participants; use ILIAS\Survey\InternalGUIService; use ILIAS\User\Profile\PublicProfileGUI; @@ -306,7 +308,7 @@ public function executeCommand(): void protected function noPermission(): void { - throw new ilObjectException($this->lng->txt("permission_denied")); + $this->checkPermission("read"); } protected function addToNavigationHistory(): void @@ -769,12 +771,16 @@ public static function _goto( if ($a_access_code === "" && isset($t_arr[1])) { $a_access_code = $t_arr[1]; } + $lang = $t_arr[2] ?? ""; + // see ilObjSurveyAccess::_checkGoto() if ($a_access_code !== '') { - $sess = $DIC->survey()->internal()->repo() - ->execution()->runSession(); + $sess = $DIC->survey()->internal()->repo()->execution()->runSession(); $sess->setCode(ilObject::_lookupObjId($ref_id), $a_access_code); $ctrl->setParameterByClass("ilObjSurveyGUI", "ref_id", $ref_id); + if ($lang !== "") { + $ctrl->setParameterByClass("ilObjSurveyGUI", "lang", $lang); + } $ctrl->redirectByClass("ilObjSurveyGUI", "run"); } diff --git a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMatrixQuestionEvaluation.php b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMatrixQuestionEvaluation.php index 0916eb896527..fed06fa1a1d5 100755 --- a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMatrixQuestionEvaluation.php +++ b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMatrixQuestionEvaluation.php @@ -22,6 +22,23 @@ */ class SurveyMatrixQuestionEvaluation extends SurveyQuestionEvaluation { + protected function parseResults( + ilSurveyEvaluationResults $a_results, + array $a_answers, + ?SurveyCategories $a_categories = null + ): void { + parent::parseResults($a_results, $a_answers, $a_categories); + + $total = $sum = 0; + foreach ($a_results->getAnswers() as $answer) { + $total++; + $sum += $answer->value; + } + if ($total > 0) { + $a_results->setMean($sum / $total); + } + } + // // RESULTS // diff --git a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMetricQuestion.php b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMetricQuestion.php index c9a1f174b96d..febea6415cc3 100755 --- a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMetricQuestion.php +++ b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMetricQuestion.php @@ -176,11 +176,7 @@ public function saveToDb(int $original_id = 0): int array($this->getId()) ); - if (preg_match("/[\D]/", $this->maximum) or (strcmp($this->maximum, "∞") == 0)) { - $max = -1; - } else { - $max = $this->getMaximum(); - } + $max = $this->getMaximum(); $next_id = $ilDB->nextId('svy_variable'); $ilDB->manipulateF( "INSERT INTO svy_variable (variable_id, category_fi, question_fi, value1, value2, sequence, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)", diff --git a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMultipleChoiceQuestion.php b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMultipleChoiceQuestion.php index 7a13d54a54a6..3c86196bc892 100755 --- a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMultipleChoiceQuestion.php +++ b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyMultipleChoiceQuestion.php @@ -459,10 +459,17 @@ public function getPreconditionValueOutput( // #18136 $category = $this->categories->getCategoryForScale((int) $value + 1); + $scale = ""; + $title = ""; + if ($category) { + $scale = $category->scale; + $title = $category->title; + } + // #17895 - see getPreconditionOptions() - return $category->scale . + return $scale . " - " . - ((strlen($category->title ?? "")) ? $category->title : $this->lng->txt('other_answer')); + ((strlen($title)) ? $title : $this->lng->txt('other_answer')); } public function getCategories(): SurveyCategories diff --git a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyQuestionGUI.php b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyQuestionGUI.php index 072870353935..62122aa57bbb 100755 --- a/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyQuestionGUI.php +++ b/components/ILIAS/SurveyQuestionPool/Questions/class.SurveyQuestionGUI.php @@ -16,6 +16,8 @@ * *********************************************************************/ +declare(strict_types=1); + use ILIAS\SurveyQuestionPool\Editing\EditingGUIRequest; use ILIAS\SurveyQuestionPool\Editing\EditManager; @@ -44,6 +46,7 @@ abstract class SurveyQuestionGUI protected string $parent_url = ""; protected ilLogger $log; public ?SurveyQuestion $object = null; + protected \ilHtmlPurifierInterface $purifier; public function __construct($a_id = -1) { @@ -90,6 +93,7 @@ public function __construct($a_id = -1) ->editing(); $this->gui = $DIC->survey()->internal()->gui(); $this->domain = $DIC->survey()->internal()->domain(); + $this->purifier = new ilSvyStandardPurifier(); } abstract protected function initObject(): void; @@ -264,11 +268,13 @@ protected function initEditForm(): ilPropertyFormGUI $question->setUseRte(true); $question->setRteTagSet("mini"); } + $question->usePurifier(true); + $question->setPurifier($this->purifier); $form->addItem($question); // obligatory $shuffle = new ilCheckboxInputGUI($this->lng->txt("obligatory"), "obligatory"); - $shuffle->setValue(1); + $shuffle->setValue("1"); $shuffle->setRequired(false); $form->addItem($shuffle); @@ -329,13 +335,11 @@ protected function saveForm(): bool $this->object->setAuthor($form->getInput("author")); $this->object->setDescription($form->getInput("description")); - $purifier = new ilSvyStandardPurifier(); - $question = $form->getInput("question"); - - $question = $purifier->purify($question); + $this->object->setQuestiontext( + $this->purifier->purify($form->getInput("question")) + ); - $this->object->setQuestiontext($question); - $this->object->setObligatory($form->getInput("obligatory")); + $this->object->setObligatory((bool) $form->getInput("obligatory")); $this->importEditFormValues($form); diff --git a/components/ILIAS/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolGUI.php b/components/ILIAS/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolGUI.php index 44c96721e67e..ba5836229de9 100755 --- a/components/ILIAS/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolGUI.php +++ b/components/ILIAS/SurveyQuestionPool/classes/class.ilObjSurveyQuestionPoolGUI.php @@ -268,7 +268,7 @@ public function deleteQuestionsObject(): void } $cgui = new ilConfirmationGUI(); - $cgui->setHeaderText($this->lng->txt("qpl_confirm_delete_questions")); + $cgui->setHeaderText($this->lng->txt("confirm_delete_questions")); $cgui->setFormAction($this->ctrl->getFormAction($this)); $cgui->setCancel($this->lng->txt("cancel"), "cancelDeleteQuestions"); diff --git a/components/ILIAS/SystemCheck/tests/ilSystemCheckTaskTest.php b/components/ILIAS/SystemCheck/tests/ilSystemCheckTaskTest.php index 9efd05f50bd9..f3c9893975e4 100755 --- a/components/ILIAS/SystemCheck/tests/ilSystemCheckTaskTest.php +++ b/components/ILIAS/SystemCheck/tests/ilSystemCheckTaskTest.php @@ -44,9 +44,7 @@ public function testConstruct(): void public function testLastUpdate(): void { - $this->getMockBuilder(ilDateTime::class) - ->disableOriginalConstructor() - ->getMock(); + $this->createStub(ilDateTime::class); $task = new ilSCTask(); $last_update = $task->getLastUpdate(); @@ -70,16 +68,11 @@ protected function initDependencies(): void $GLOBALS['DIC'] = $this->dic; $this->setGlobalVariable( 'ilDB', - $this->createMock(ilDBInterface::class) + $this->createStub(ilDBInterface::class) ); - $logger = $this->getMockBuilder(ilLogger::class) - ->disableOriginalConstructor() - ->getMock(); + $logger = $this->createStub(ilLogger::class); - $logger_factory = $this->getMockBuilder(ilLoggerFactory::class) - ->disableOriginalConstructor() - ->onlyMethods(['getComponentLogger']) - ->getMock(); + $logger_factory = $this->createStub(ilLoggerFactory::class); $logger_factory->method('getComponentLogger')->willReturn($logger); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); } diff --git a/components/ILIAS/Test/PRIVACY.md b/components/ILIAS/Test/PRIVACY.md new file mode 100644 index 000000000000..e4c1616016f5 --- /dev/null +++ b/components/ILIAS/Test/PRIVACY.md @@ -0,0 +1,248 @@ +# Test Privacy + +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories).** + +## General information + +The Test component is used to create, manage and run tests, which includes creating and managing questions. There are many use cases for the Test component, which is why it has so many settings. The most common scenarios are likely to be self-assessment tests and examinations. + +To ensure that this functionality meets the expectations of all stakeholders, a great deal of data needs to be stored and displayed within this component. + +The Test component and the TestQuestionPool component are still tied together in most intricate ways. The primary component of concern in regards to privacy related evaluations is the Test. As the lines between these components are blurred, it is advised to never look at only one of the components but always at both. + +## Integrated components + +The Test component employs the following components, please consult the respective privacy.mds + + - [AccessControl](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/AccessControl/PRIVACY.md) + - [Certificate](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Certificate/PRIVACY.md): Is used for certificate creation and uses test-specific placeholders [RESULT_PASSED], [RESULT_PERCENT], [MAX_POINTS], [RESULT_MARK_SHORT], [RESULT_MARK_LONG] + - [COPage](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/COPage/PRIVACY.md): Is used for content creation/presentation within questions, Introduction and Concluding Remarks and is able to store, present and delete personal data. + - [CSV](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/CSV) + - [Excel](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Excel) + - [Export](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/Export) + - [InfoScreen](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/InfoScreen/PRIVACY.md) + - [KioskMode](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/KioskMode/PRIVACY.md) + - [LTI Provider](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/LTIProvider/PRIVACY.md): Is used to provide the Test via LTI and is able to present personal data. + - [Metadata](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/MetaData/Privacy.md): Stores the full name of the author of the test. + - [Notes](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Notes/Privacy.md) + - [Object](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/ILIASObject) + - [Skill (Competence) Service](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Skill/PRIVACY.md) + - [Taxonomy](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Taxonomy/PRIVACY.md) + - [TestQuestionPool](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/TestQuestionPool/PRIVACY.md) + - [Tracking](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/Tracking) + - [User](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/User): Provides information about the account being used using the Test component in order to store those. + +## Configuration + +### Administration > Repository and Objects > Test and Assessment + +At the Administration node for Test and Assessment accounts having 'Edit Settings' permissions are able to configure some functionality, which has an impact on personal data handling. + +At Administration > Repository and Objects > Test and Assessment > Settings it is possible to select which 'Unique user criteria' is used in test imports/exports. The selected type of personal data will be included in export type 'XML incl. Participants Results' of a test for each account. Options are: usr_id, login, email, matriculation, ext_account. This personal data is required to match accounts results when importing an export file at the same or another platform. + +At Administration > Repository and Objects > Test and Assessment > Log Data accounts with 'Edit Settings' permission can activate the History-tab via the checkbox 'Activate Test and Assessment Logging'. Additionally the setting 'Log IP' allows for logging the IP-adress of participants along with the interactions as well as specific settings of said test during the interaction. +The purpose of both options is to store important events and information for configuring and performing tests. This gives the possibility to check those information in case of issues or concerns after performing tests. + +### Test > Settings > General + +At the subtab Test > Settings > General for accounts with 'Edit Settings' permission it is possible to choose one of the following options for the field 'Privacy': +- Results with names (pre-selected) +- Results without names / anonymous test + +If the second option is selected, no personal data of test attempts is presented at the test. If the user is not logged in while performing the test attempt, additionally no personal data is stored. Please have a look at the detailled information at the following sections. + +In addition the 'Exam View' and it's sub-option 'Show Name of Participant' can be activated by accounts with 'Edit Settings' permission, which has an impact on the presented personal data. + +### Test > Settings > Scoring and Results + +At the subtab Test > Settings > Scoring and Results accounts having 'Edit Settings' permission are able to specify whether accounts have access to their own test results (and therefore to their own personal data). When activating the access to the accounts own results, it is possible to dedicated activate the presented data: + +- ‘Passed’ / ‘Failed’ Status +- Grade +- Detailed Results (these contain all given answers and points scored) + +In addition accounts with 'Edit Settings' permission are able to activate the 'Rankings' functionality, which potentially presents personal data to all participating accounts. There are several sub-settings for 'Rankings', which specify the presented personal data: + +- Mode: Own Position, Top Ranks, Own Position and Top Ranks +- Number of Top Ranks +- Without Names: prevents the presentation of accounts names +- Date / Time: additional column in the rankings table showing when the test was finished +- Point Score +- Percentage Score +- Time Spent: additional column in the ranking table showing the time taken to complete the test + +## Data being stored + +### Test > Test - data being stored while performing a test + +While an account performs a test, the following data is stored. After finishing the test, this data is presented at various other tabs (see [Data being presented](#Data being presented)). This is needed in order to provide the functionality of the test component. All listed data is at least linked to the 'User ID'. + +- User ID +- Client IP +- Starting time stamp of the test attempt +- Last access time stamp of the test attempt +- Duration of the test attempt +- Answer content and timestamp of answer content submission +- Status of questions (Not answered/Answered) +- Scoring for questions (achieved points) ? +- Mark and status of the test attempt ? +- Log Entry Type and Interaction Type + +### Test > Settings + +In general the change of settings at the tab Test > Settings is logged. Therefore the 'User ID', the 'Log Entry Type' and 'Interaction Type' is stored. + +At the creation process of a template at Test > Settings > Personal Test Settings Templates the field 'Author' is prefilled with the full name of the account, which is creating the template. If this value is not changed, the name of the account is stored. In addition the 'Creation Date' of the template and the User-ID is stored. Those information are needed in order to present the origin of a Personal Test Settings Template. + +### Test > Questions + +In genereal the creation, change and deletion of questions at the tab Test > Questions is stored as log entry. Therefore the 'User ID', the 'Log Entry Type' and 'Interaction Type' is stored. + +At the creation and editing process of questions the field 'Author' is prefilled with the full name of the account, which is creating the question. If this value is not changed, the name of the account is stored. If the value is changed and personal data is entered, it will be stored. By storing (and presenting) the value for 'Author' it is possible to contact the account, if there are problems with the question or the configuration of it. In addition it supports the collaborative development of questions. + +Owners of questions (accounts which have created a question) are stored in the Test as references to the ‘User ID’. This data is required to manage detailed access and permissions for the usage and editing of the question. + +### Test > Participants + +An account having ‘Edit Settings’ permission is able to assign accounts as participants of a test at the tab Test > Participants. In addition, accounts which perform a test are added as participants automatically. For all accounts that are assigned as participants, the ‘User ID’ is stored as a link to the test. If a ‘Client IP Range’ is set for a participant, the entered value is stored, linked to the ‘User ID’. Those pieces of information are needed in order to manage access to the test. + +For some actions, which are offered at this tab, log entries are stored. Therefore the 'User ID' (of the account with 'Edit Settings' permission), the 'Log Entry Type' and 'Interaction Type' is stored. + +### Test > Scoring + +If the Scoring of a test attempt is changed at the tab Test > Scoring, this event is logged. Therefore the 'User ID' (of the account with 'Edit Settings' permission), the 'Log Entry Type' and 'Interaction Type' is stored. This ensures the traceability of test results. + +## Data being presented + +### Test > Test - data being presented while performing a test + +While performing a test, the 'Name' of the participant himself is shown, if the 'Exam View' and it's sub-option 'Show Name of Participant' is activated. When a test is performed in person, the presentation of this information can be used for validating the logged in account. + +### Test > Settings > Personal Test Settings Templates + +The values of the field 'Author' for all Personal Test Settings Templates at the subtab Test > Settings > Personal Test Settings Templates are presented, which may contain personal data. The 'Creation Date' of the template is also presented, which is directly linked to the value for 'Author'. + +### Test > Questions + +At the overview of the questions at the tab Test > Questions, the values of the field 'Author' for all questions are shown, which may contain personal data. + +When using the 'Statistics' action from a question, the 'Author' of other tests is displayed at the table 'This question is used in the following tests', if the question is used in other tests, too. This information originates from the metadata component (see above). + +When using the 'Print Answers' action from a question, all answers to a question with the 'Name' of the participating accounts are presented here. If the test is set to anonymous (see above), this data is not presented. + +### Test > Participants + +The table ‘Participants’ at the tab Test > Participants shows the following personal data linked to the test attempt. This data is also shown if the action ‘Show Results’ is used. The purpose of the presentation is to give accounts with ‘Edit Settings’ or ‘Test Results’ permission an overview of all test attempts and the related data. + +- Name (originates from the user component) +- Login (originates from the user component) +- Matriculation Number (originates from the user component) +- Starting time stamp +- Duration +- Number of Attempts Made +- Status of the test attempt +- Scored points +- Number of questions answered +- Percentage Score +- Passed-status +- Grade +- Scoring completed- +- Last access time stamp of the test attempt + +If the test is set to anonymous (see above), 'Name', 'Login' and 'Matriculation Number' are not presented. + +### Test > My Results + +At the subtabs Test > My Results > Test Results and Test > My Results > Printable List of Answers accounts are able to access their own test results. This data contains their ‘Name’ and ‘Matriculation Number’. If the test is set to anonymous (see above), the ‘Name’ and ‘Matriculation Number’ are not presented. + +### Test > Scoring + +The tab Test > Scoring shows the following personal data linked to the test attempt for accounts with ‘Edit Settings’ permission. This is needed in order to review and possibly change the scoring of test attempts. If the test is set to anonymous (see above), the ‘Name’ and ‘Login’ are replaced by the ‘Test ID’. + +Accounts with 'Score anonymously' permission are able to access the tab Test > Scoring, but are not able to see 'Name' and 'Login'. + +- Name +- Login +- Test ID +- Number of the Scored Test Attempt +- Scored points for all questions +- Scoring completed + +### Test > History + +At the tab Test > History log entries are shown, which originate from changes to the test settings and questions or from participation in the test. The purpose of the tab ‘History’ is mainly to check events in case of issues or concerns after performing tests. The following personal data is presented: + +- Date and Time of the event +- Name and Login of Author or Participant +- Client IP (of participants) +- Log Entry Type +- Interaction Type + +Some examples for Interaction Types are 'Test Run Started', 'Question Shown', 'Answer Submitted' and 'Test Run Finished' for participating accounts and 'Main Settings Modified', 'Run of Participant Closed', 'Grading Reset' and 'Participant Data Removed' for accounts with 'Edit Settings' permission. + +If the test is set to anonymous, no entries are shown for the participation of the test. + +### Administration > Repository and Objects > Test and Assessment > Log Data > Log Data Output + +Accounts with the ‘Edit Settings’ permission for the administration node Administration > Repository and Objects > Test and Assessment > Log Data > Log Data Output are able to list the same personal data for all tests on the platform as listed in the section ‘History’ of any test. + +## Data being deleted + +In general, only accounts with 'Edit Settings' permission are able to delete data. Exceptions are explicitly listed. + +At the tab Test > Questions it is possible to delete questions, and thereby the personal data in the field ‘Author’ is deleted. + +At the tab Test > Participants the test results of participants and all linked personal data can be deleted. Additionally, the assignment of accounts as participants can be cancelled, which deletes all linked personal data. + +Accounts with the ‘Edit Settings’ permission for the tab Administration > Repository and Objects > Test and Assessment > Log Data > Log Data Output are able to delete any log entries and all linked personal data from all tests on the platform. + +Accounts with ‘Read’ permission are able to delete their own answers, which are linked to their ‘User ID’, while performing a test at the tab Test > Test. The answers are not linked to a ‘User ID’ if the test is set to anonymous and is performed without being logged in. + +If the option 'Allow Deletion of Non-Scoring Attempts' at Settings > Scoring and Results > Access to Test Results is activated, accounts with 'Read' permission are able to delete their own non-scoring test attempts and all linked personal data at the tab Test > My Results. + +## Data being exported + +In general, only accounts with the 'Edit Settings' permission are able to export data. Exceptions are explicitly listed. + +When exporting a Personal Test Settings Template at Test > Settings > Personal Test Settings Templates, the fields 'Author', 'Creation Date' and "User-ID" are exported. This secures being able to identify the origin of a Personal Test Settings Template after importing it to an account. + +At the tab Test > Participants the export files 'Scored Test Attempt', 'All test attempts' and 'as Certificate (PDF)' are available. The purpose of the different export files is to extract the dedicated test results of one or more accounts. This can, for example, be used for discussing the results with the participant. Those export files contain the following personal data of the participants, which all originate from the user component (see above): + +- Name +- Login +- E-Mail +- Matriculation Number +- Salutation +- Street +- City, State +- Zip Code / Post Code +- Country +- Institution +- Department + +At the tab Test > History the 'Export Legacy Log Data' is available, which can be used for historical purposes, and any data shown at the table can be exported (see above for details). + +At the subtabs Test > My Results > Test Results and Test > My Results > Printable List of Answers accounts with 'Read' permission are able to download their own data via the button 'Print'. This data contains their ‘Name’ and ‘Matriculation Number’. If the test is set to anonymous (see above), the ‘Name’ and ‘Matriculation Number’ are not included. + +### Test > Export + +There are three export files at the tab Test > Export which contain personal data (see below). If export files are created, they contain the personal data that is available at the time of their creation. If personal data is deleted after the creation of an export file (which contains such data), the export file must also be deleted. + +The ‘Archive file’ contains all personal data which is being stored and presented in the test (see above). Its purpose is to have this data easily accessible outside of ILIAS, e.g. for long-term archiving of the data. + +The 'XML' export contains the personal data 'Author' of the questions and of the test itself within the metadata (see above). Its purpose is to be imported into ILIAS again, although the contained personal data is easily accessible. + +The ‘XML export incl. Participant Results’ contains all personal data which is being stored and presented in the test (see above). The data in the ‘History’ tab is an exception; it is not included. Its purpose is to be imported into ILIAS again, although the contained personal data is easily accessible. This export file can be used to, e.g., provide the test results to the participants at another ILIAS installation. + +### Administration > Repository and Objects > Test and Assessment > Log Data > Log Data Output + +Accounts with the ‘Edit Settings’ permission for the administration node Administration > Repository and Objects > Test and Assessment > Log Data > Log Data Output are able to export any log entries and all linked personal data from all tests on the platform. + +## Summary + +| Data | Stored in DB | Presented to accounts with 'Read' Permission | Presented to accounts with 'Edit Settings' Permission | Presented to accounts with 'Test Results' Permission | Presented to accounts with 'Score anonymously' Permission | Exported | Deleted with removing test attempt | Deleted with removing test object | special settings | +|------|---------------|---------------------------------------------|------------------------------------------------------|----------------------------------------------------------------|------------------------------------------------------|------------------------------------------------------|------------------------------------|--------------------------------------|-------------------| +| test attempt data (e.g. account, timestamps, scoring) | reference to by ID | if activated | yes | yes | yes, but anonymised| yes | yes | yes | anonymous test without account presentation, gamification with presentation to all accounts | +| question data (e.g. author, statistics) | yes & reference to by ID | no | yes | no | no | yes | no | if question only was used at the deleted test object | value for author can be changed manually | +| assignment of account as 'Participant' | reference to by ID | if setting 'Select Participants Manually' is used | yes | yes | no | yes | no, but with deletion of assignment | yes | anonymous test without account presentation | +| Personal Test Settings Templates author | yes & reference to by ID | no | only own templates | only own templates | only own templates | yes | no | no, can be deleted separately | diff --git a/components/ILIAS/Test/classes/Notifications/class.ilTestManScoringParticipantNotification.php b/components/ILIAS/Test/classes/Notifications/class.ilTestManScoringParticipantNotification.php index 3e332f894529..78cce6992b8a 100755 --- a/components/ILIAS/Test/classes/Notifications/class.ilTestManScoringParticipantNotification.php +++ b/components/ILIAS/Test/classes/Notifications/class.ilTestManScoringParticipantNotification.php @@ -29,6 +29,7 @@ public function __construct($userId, $testRefId) $this->initLanguage($this->getRecipient()); $this->getLanguage()->loadLanguageModule('assessment'); + $this->getLanguage()->loadLanguageModule('qsts'); $this->initMail(); } diff --git a/components/ILIAS/Test/classes/Screen/class.ilTestPlayerLayoutProvider.php b/components/ILIAS/Test/classes/Screen/class.ilTestPlayerLayoutProvider.php index 55cc8b484af7..0b41e55cb29e 100755 --- a/components/ILIAS/Test/classes/Screen/class.ilTestPlayerLayoutProvider.php +++ b/components/ILIAS/Test/classes/Screen/class.ilTestPlayerLayoutProvider.php @@ -88,7 +88,7 @@ public function getMainBarModification(CalledContexts $called_contexts): ?MainBa $question_listing = $f->legacy()->content($r->render($question_listing)); - $label = $lng->txt('mainbar_button_label_questionlist'); + $label = $lng->txt('questionlist'); $entry = $f->maincontrols()->slate()->legacy( $label, $f->symbol()->icon()->standard('tst', $label), diff --git a/components/ILIAS/Test/classes/Screen/ilTestPlayerToolProvider.php b/components/ILIAS/Test/classes/Screen/ilTestPlayerToolProvider.php index a0cb5bf56989..f739551acbb6 100644 --- a/components/ILIAS/Test/classes/Screen/ilTestPlayerToolProvider.php +++ b/components/ILIAS/Test/classes/Screen/ilTestPlayerToolProvider.php @@ -48,7 +48,7 @@ public function getToolsForContextStack(CalledContexts $called_contexts): array $this->factory->tool( $this->identification_provider->contextAwareIdentifier('tst_qst_list') )->withSymbol($ui->factory()->symbol()->icon()->standard('tst', $lng->txt('more'))) - ->withTitle($lng->txt('mainbar_button_label_questionlist')) + ->withTitle($lng->txt('questionlist')) ->withContent( $ui->factory()->legacy()->content( $ui->renderer()->render( diff --git a/components/ILIAS/Test/classes/class.ilObjTest.php b/components/ILIAS/Test/classes/class.ilObjTest.php index e324175b584e..b075d81b97b6 100755 --- a/components/ILIAS/Test/classes/class.ilObjTest.php +++ b/components/ILIAS/Test/classes/class.ilObjTest.php @@ -193,7 +193,8 @@ public function __construct(int $id = 0, bool $a_call_by_reference = true) parent::__construct($id, $a_call_by_reference); - $this->lng->loadLanguageModule("assessment"); + $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $this->score_settings = null; $this->question_set_config_factory = new ilTestQuestionSetConfigFactory( diff --git a/components/ILIAS/Test/classes/class.ilObjTestAccess.php b/components/ILIAS/Test/classes/class.ilObjTestAccess.php index 434fced9b3b5..682c856ff660 100755 --- a/components/ILIAS/Test/classes/class.ilObjTestAccess.php +++ b/components/ILIAS/Test/classes/class.ilObjTestAccess.php @@ -186,6 +186,7 @@ public static function _getCommands(): array { global $DIC; $DIC->language()->loadLanguageModule('assessment'); + $DIC->language()->loadLanguageModule('qsts'); return [ [ diff --git a/components/ILIAS/Test/classes/class.ilObjTestFolderGUI.php b/components/ILIAS/Test/classes/class.ilObjTestFolderGUI.php index ccdb44413a7b..31874d33fca9 100755 --- a/components/ILIAS/Test/classes/class.ilObjTestFolderGUI.php +++ b/components/ILIAS/Test/classes/class.ilObjTestFolderGUI.php @@ -62,6 +62,7 @@ public function __construct( } $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); } private function getTestFolder(): ilObjTestFolder diff --git a/components/ILIAS/Test/classes/class.ilObjTestGUI.php b/components/ILIAS/Test/classes/class.ilObjTestGUI.php index ceebd6d9f0d7..dadb8082d5fa 100755 --- a/components/ILIAS/Test/classes/class.ilObjTestGUI.php +++ b/components/ILIAS/Test/classes/class.ilObjTestGUI.php @@ -1737,7 +1737,7 @@ private function buildQuestionCreationForm(): Form $inputs['pool_selection'] = $this->buildInputPoolSelection(); $section = [ - $this->ui_factory->input()->field()->section($inputs, $this->lng->txt('ass_create_question')) + $this->ui_factory->input()->field()->section($inputs, $this->lng->txt('create_question')) ]; $form = $this->ui_factory->input()->container()->form()->standard( @@ -1928,7 +1928,7 @@ private function setupToolBarAndMessage(bool $has_started_test_runs): void return; } - $this->toolbar->addButton($this->lng->txt('ass_create_question'), $this->ctrl->getLinkTarget($this, 'createQuestionForm')); + $this->toolbar->addButton($this->lng->txt('create_question'), $this->ctrl->getLinkTarget($this, 'createQuestionForm')); $this->toolbar->addSeparator(); $this->populateQuestionBrowserToolbarButtons($this->toolbar); } diff --git a/components/ILIAS/Test/classes/class.ilTestEvaluationGUI.php b/components/ILIAS/Test/classes/class.ilTestEvaluationGUI.php index 6bc1c4c6953c..96975d98d223 100755 --- a/components/ILIAS/Test/classes/class.ilTestEvaluationGUI.php +++ b/components/ILIAS/Test/classes/class.ilTestEvaluationGUI.php @@ -18,6 +18,7 @@ declare(strict_types=1); +use ILIAS\Test\Participants\Participant; use ILIAS\Test\Participants\ParticipantRepository; use ILIAS\Test\Results\Presentation\TitlesBuilder as ResultsTitlesBuilder; use ILIAS\Test\Presentation\PrintLayoutProvider; @@ -133,20 +134,19 @@ public function printResults(): void true ); - $selected_active_ids = explode(',', $this->testrequest->strVal('active_ids')); + $selected_participants = $this->retrieveSelectedParticipants(); $results_panel = $this->ui_factory->panel()->report( $this->lng->txt('tst_results'), array_map( - function (string $v): SubPanel { - $value = (int) $v; - $attempt_id = ilObjTest::_getResultPass($value); - $components = $this->buildAttemptComponents($value, $attempt_id, false, true); + function (int $v) use ($selected_participants): SubPanel { + $attempt_id = ilObjTest::_getResultPass($v); + $components = $this->buildAttemptComponents($v, $attempt_id, false, true); return $this->ui_factory->panel()->sub( - $this->buildResultsTitle($value, $attempt_id), + $this->buildResultsTitle($selected_participants[$v], $attempt_id), $components ); }, - $selected_active_ids + array_keys($selected_participants) ) ); @@ -165,15 +165,16 @@ public function showResults(): void { $this->setCss(); $this->ctrl->saveParameterByClass(self::class, 'active_ids'); - $selected_active_ids = explode(',', $this->testrequest->strVal('active_ids')); + + $selected_participants = $this->retrieveSelectedParticipants(); $this->addPrintResultsButtonToToolbar(); $this->addToggleBestSolutionButtonToToolbar(); - $current_active_id = (int) $selected_active_ids[0]; - if (count($selected_active_ids) > 1 + $current_active_id = array_key_first($selected_participants); + if (count($selected_participants) > 1 && ($selected_active_id = $this->testrequest->getActiveId()) > 0 - && array_search($selected_active_id, $selected_active_ids) !== false) { + && array_key_exists($selected_active_id, $selected_participants) !== false) { $current_active_id = $selected_active_id; } @@ -184,7 +185,10 @@ public function showResults(): void } $results_panel = $this->ui_factory->panel()->report( - $this->buildResultsTitle($current_active_id, $attempt_id), + $this->buildResultsTitle( + $selected_participants[$current_active_id], + $attempt_id + ), $this->buildAttemptComponents($current_active_id, $attempt_id, true, false) ); @@ -202,8 +206,8 @@ public function showResults(): void ]); } - if (count($selected_active_ids) > 1) { - $this->addParticipantSelectorToToolbar($selected_active_ids, $current_active_id); + if (count($selected_participants) > 1) { + $this->addParticipantSelectorToToolbar($selected_participants, $current_active_id); } $this->tpl->setVariable( @@ -325,7 +329,13 @@ public function outUserPassDetails(): void true ), $settings, - $this->buildResultsTitle($active_id, $pass), + $this->buildResultsTitle( + $this->participant_repository->getParticipantByActiveId( + $this->object->getTestId(), + $active_id + )->getDisplayName($this->lng), + $pass + ), false ); @@ -791,7 +801,7 @@ protected function sendPage(string $page) $this->http->close(); } - protected function buildResultsTitle(int $active_id, int $pass): string + private function buildResultsTitle(string $participant_name, int $pass): string { if ($this->object->getAnonymity()) { return sprintf( @@ -802,7 +812,7 @@ protected function buildResultsTitle(int $active_id, int $pass): string return sprintf( $this->lng->txt('tst_result_user_name_pass'), $pass + 1, - $this->participant_repository->getParticipantByActiveId($this->object->getTestId(), $active_id)->getDisplayName($this->lng) + $participant_name ); } @@ -946,29 +956,30 @@ private function addToggleBestSolutionButtonToToolbar(): void } private function addParticipantSelectorToToolbar( - array $selected_active_ids, + array $selected_participants, int $current_active_id ): void { $this->toolbar->addSeparator(); $this->toolbar->addComponent( $this->ui_factory->dropdown() ->standard( - $this->buildParticipantSelectorArray($selected_active_ids, $current_active_id) + $this->buildParticipantSelectorArray($selected_participants, $current_active_id) )->withLabel($this->lng->txt('tst_res_jump_to_participant_hint_opt')) ); } private function buildParticipantSelectorArray( - array $selected_active_ids, + array $selected_participants, int $current_active_id ): array { + $selected_active_ids = array_keys($selected_participants); $this->ctrl->setParameterByClass(self::class, 'active_ids', implode(',', $selected_active_ids)); unset($selected_active_ids[array_search($current_active_id, $selected_active_ids)]); $available_user_links = array_map( - function (int $v): StandardLink { + function (int $v) use ($selected_participants): StandardLink { $this->ctrl->setParameterByClass(self::class, 'active_id', $v); return $this->ui_factory->link()->standard( - ilObjUser::_lookupFullname($this->object->_getUserIdFromActiveId($v)), + $selected_participants[$v], $this->ctrl->getLinkTargetByClass(self::class, 'showResults') ); }, @@ -1012,4 +1023,26 @@ function (array $c, int $v): array { $this->lng->txt('select_attempt') )->withActive("{$this->lng->txt('tst_attempt')} {$selected_attempt}"); } + + /** + * @return array Array with the active_id as key and the + * display name as value + */ + private function retrieveSelectedParticipants(): array + { + $int_trafo = $this->refinery->kindlyTo()->int(); + $selected_participants = []; + foreach ($this->participant_repository->getParticipants( + $this->object->getTestId(), + [ + 'active_ids' => array_map( + fn(string $v): int => $int_trafo->transform($v), + explode(',', $this->testrequest->strVal('active_ids')) + ) + ] + ) as $participant) { + $selected_participants[$participant->getActiveId()] = $participant->getDisplayName($this->lng); + } + return $selected_participants; + } } diff --git a/components/ILIAS/Test/classes/class.ilTestFixedQuestionSetConfig.php b/components/ILIAS/Test/classes/class.ilTestFixedQuestionSetConfig.php index 2f429f9fcb02..92db879f27f7 100755 --- a/components/ILIAS/Test/classes/class.ilTestFixedQuestionSetConfig.php +++ b/components/ILIAS/Test/classes/class.ilTestFixedQuestionSetConfig.php @@ -71,12 +71,19 @@ public function cloneQuestionSetRelatedData(ilObjTest $clone_test_obj): void foreach ($this->test_obj->questions as $key => $question_id) { $question_orig = assQuestion::instantiateQuestion($question_id); - $clone_test_obj->questions[$key] = $question_orig->duplicate(true, '', '', -1, $clone_test_obj->getId()); - - $original_id = $this->questionrepository->getForQuestionId($question_id)->getOriginalId(); - - $question_clone = assQuestion::instantiateQuestion($clone_test_obj->questions[$key]); - $question_clone->saveToDb($original_id); + $clone_test_obj->questions[$key] = $question_orig->duplicate( + false, + '', + '', + -1, + $clone_test_obj->getId() + ); + $question_clone = assQuestion::instantiateQuestion( + $clone_test_obj->questions[$key] + ); + $question_clone->updateOriginalId( + $question_orig->getOriginalId() + ); // Save the mapping of old question id <-> new question id // This will be used in class.ilObjCourse::cloneDependencies to copy learning objectives diff --git a/components/ILIAS/Test/classes/class.ilTestPlayerAbstractGUI.php b/components/ILIAS/Test/classes/class.ilTestPlayerAbstractGUI.php index 194abaa4eb24..658847ff87d7 100755 --- a/components/ILIAS/Test/classes/class.ilTestPlayerAbstractGUI.php +++ b/components/ILIAS/Test/classes/class.ilTestPlayerAbstractGUI.php @@ -1853,7 +1853,7 @@ protected function showSideList($current_sequence_element): void } $question_listing = $this->ui_factory->listing()->workflow()->linear( - $this->lng->txt('mainbar_button_label_questionlist'), + $this->lng->txt('questionlist'), $questions )->withActive($active); @@ -3058,8 +3058,12 @@ protected function getTestPlayerTitle(): string // this is a placeholder solution with inline html tags to differentiate the different elements // should be removed when a title component with grouping and visual weighting is available // see: https://github.com/ILIAS-eLearning/ILIAS/pull/7311 - $pax_name_value = "" - . $this->user->getFullname() . ""; + $pax_name_value = $this->ui_factory->legacy( + sprintf( + "%s", + $this->refinery->encode()->htmlSpecialCharsAsEntities()->transform($this->user->getFullname()) + ) + ); $title_content = $title_content->withProperty($pax_name_label, $pax_name_value, false); } diff --git a/components/ILIAS/Test/classes/class.ilTestResultsImportParser.php b/components/ILIAS/Test/classes/class.ilTestResultsImportParser.php index 86e4e3c68364..ce95d671e3cc 100755 --- a/components/ILIAS/Test/classes/class.ilTestResultsImportParser.php +++ b/components/ILIAS/Test/classes/class.ilTestResultsImportParser.php @@ -135,7 +135,7 @@ public function handlerBeginTag($a_xml_parser, $a_name, $a_attribs): void $this->db->insert('tst_active', [ 'active_id' => [ilDBConstants::T_INTEGER, $next_id], 'user_fi' => [ilDBConstants::T_INTEGER, $usr_id], - 'anonymous_id' => [ilDBConstants::T_TEXT, $a_attribs['anonymous_id'] ?: null], + 'anonymous_id' => [ilDBConstants::T_TEXT, $a_attribs['anonymous_id'] ?? null], 'test_fi' => [ilDBConstants::T_INTEGER, $this->test_obj->getTestId()], 'lastindex' => [ilDBConstants::T_INTEGER, $a_attribs['lastindex']], 'tries' => [ilDBConstants::T_INTEGER, $a_attribs['tries']], diff --git a/components/ILIAS/Test/src/Logging/AdditionalInformationGenerator.php b/components/ILIAS/Test/src/Logging/AdditionalInformationGenerator.php index e466d9f7cbc9..a31d8210dfbf 100644 --- a/components/ILIAS/Test/src/Logging/AdditionalInformationGenerator.php +++ b/components/ILIAS/Test/src/Logging/AdditionalInformationGenerator.php @@ -263,6 +263,7 @@ public function __construct( private readonly GeneralQuestionPropertiesRepository $questions_repo ) { $lng->loadLanguageModule('assessment'); + $lng->loadLanguageModule('qsts'); $lng->loadLanguageModule('crs'); $this->tags = $this->buildTags(); } diff --git a/components/ILIAS/Test/src/Participants/Participant.php b/components/ILIAS/Test/src/Participants/Participant.php index 21bf4258b985..d51eaf4f4b93 100644 --- a/components/ILIAS/Test/src/Participants/Participant.php +++ b/components/ILIAS/Test/src/Participants/Participant.php @@ -253,12 +253,16 @@ public function getDisplayName(Language $language, bool $anonymous_test = false) return $language->txt('anonymous'); } + if ($this->login === '' && $this->firstname === '' && $this->lastname === '') { + return $language->txt('user_deleted'); + } + $display_name = ''; - if ($this->firstname) { + if ($this->firstname !== '') { $display_name .= $this->firstname . ' '; } - if ($this->lastname) { + if ($this->lastname !== '') { $display_name .= $this->lastname; } diff --git a/components/ILIAS/Test/src/Participants/ParticipantRepository.php b/components/ILIAS/Test/src/Participants/ParticipantRepository.php index 553b99256877..5348282fd163 100755 --- a/components/ILIAS/Test/src/Participants/ParticipantRepository.php +++ b/components/ILIAS/Test/src/Participants/ParticipantRepository.php @@ -278,6 +278,15 @@ private function applyFilter( $values = array_merge($values, ["%{$filter['ip_range']}%", "%{$filter['ip_range']}%"]); } + if ($this->isFilterSet($filter, 'active_ids')) { + $where[] = $this->database->in( + 'participants.active_id', + $filter['active_ids'], + false, + \ilDBConstants::T_INTEGER + ); + } + return [$where, $types, $values]; } @@ -302,7 +311,8 @@ private function applyOrder(?Order $order): string private function isFilterSet(array $filter, string $key): bool { - return isset($filter[$key]) && trim($filter[$key]) !== ""; + return isset($filter[$key]) + && (is_array($filter[$key]) || trim($filter[$key]) !== ''); } diff --git a/components/ILIAS/Test/src/Questions/Presentation/QuestionsOfAttemptTable.php b/components/ILIAS/Test/src/Questions/Presentation/QuestionsOfAttemptTable.php index 7ba58cbdaf2a..de061939dc99 100644 --- a/components/ILIAS/Test/src/Questions/Presentation/QuestionsOfAttemptTable.php +++ b/components/ILIAS/Test/src/Questions/Presentation/QuestionsOfAttemptTable.php @@ -139,7 +139,6 @@ protected function getColumns(): array $icon_factory = $this->ui_factory->symbol()->icon(); $icon_checked = $icon_factory->custom('assets/images/standard/icon_checked.svg', $this->lng->txt('yes')); $icon_unchecked = $icon_factory->custom('assets/images/standard/icon_unchecked.svg', $this->lng->txt('no')); - $icon_marked = $icon_factory->custom('assets/images/object/marked.svg', $this->lng->txt('tst_question_marked')); $columns = [ 'order' => $column_factory->number($this->lng->txt('tst_qst_order')), @@ -148,7 +147,7 @@ protected function getColumns(): array 'postponed' => $column_factory->boolean(ucfirst($this->lng->txt('postponed')), $this->lng->txt('yes'), ''), 'points' => $column_factory->number($this->lng->txt('tst_maximum_points'))->withUnit($this->lng->txt('points_short')), 'answered' => $column_factory->boolean($this->lng->txt('answered'), $icon_checked, $icon_unchecked), - 'marked' => $column_factory->boolean($this->lng->txt('tst_question_marker'), $icon_marked, ''), + 'marked' => $column_factory->boolean($this->lng->txt('tst_question_marker'), $icon_checked, $icon_unchecked), ]; $optional_columns = [ diff --git a/components/ILIAS/Test/src/Scoring/Manual/TestScoring.php b/components/ILIAS/Test/src/Scoring/Manual/TestScoring.php index 097c5ed5b0f9..ae33c7ea5fbc 100755 --- a/components/ILIAS/Test/src/Scoring/Manual/TestScoring.php +++ b/components/ILIAS/Test/src/Scoring/Manual/TestScoring.php @@ -133,7 +133,12 @@ private function recalculatePass( $reached_points_changed = false; foreach ($passdata->getAnsweredQuestions() as $question_data) { if ($this->getQuestionId() !== 0 || $this->getQuestionId() === $question_data['id']) { - $reached_points_changed = $reached_points_changed || $this->recalculateQuestionScore($user_id, $active_id, $pass, $question_data); + $reached_points_changed = $this->recalculateQuestionScore( + $user_id, + $active_id, + $pass, + $question_data + ) || $reached_points_changed; } } $this->updatePassResultsTable($active_id, $pass, $reached_points_changed); diff --git a/components/ILIAS/Test/src/Scoring/Manual/class.ConsecutiveScoringGUI.php b/components/ILIAS/Test/src/Scoring/Manual/class.ConsecutiveScoringGUI.php index dd35b321f8eb..b26c550c3c95 100644 --- a/components/ILIAS/Test/src/Scoring/Manual/class.ConsecutiveScoringGUI.php +++ b/components/ILIAS/Test/src/Scoring/Manual/class.ConsecutiveScoringGUI.php @@ -552,6 +552,7 @@ protected function getScoringForm(string $action, int $question_id, int $usr_act ) ) ) + ->withStepSize(0.0001) ->withAdditionalTransformation($this->refinery->kindlyTo()->float()) ->withValue($score); diff --git a/components/ILIAS/Test/tests/Scoring/Settings/ScoreSettingsTest.php b/components/ILIAS/Test/tests/Scoring/Settings/ScoreSettingsTest.php index 62f8e4d68bdd..8ab4e626f326 100755 --- a/components/ILIAS/Test/tests/Scoring/Settings/ScoreSettingsTest.php +++ b/components/ILIAS/Test/tests/Scoring/Settings/ScoreSettingsTest.php @@ -223,12 +223,20 @@ public function testScoreSettingsSectionScoring(): void public function getUIFactory(): NoUIFactory { - return new class () extends NoUIFactory { + $language_mock = $this->createMock(\ILIAS\Language\Language::class); + $language_mock->method('txt')->willReturnArgument(0); + + return new class ($language_mock) extends NoUIFactory { + public function __construct( + protected \ILIAS\Language\Language $language, + ) { + } + public function symbol(): S\Factory { return new S\Factory( new S\Icon\Factory(), - new S\Glyph\Factory(), + new S\Glyph\Factory($this->language), new S\Avatar\Factory() ); } diff --git a/components/ILIAS/TestQuestionPool/PRIVACY.md b/components/ILIAS/TestQuestionPool/PRIVACY.md index 73d75d63fcd9..afcf3ed4c589 100755 --- a/components/ILIAS/TestQuestionPool/PRIVACY.md +++ b/components/ILIAS/TestQuestionPool/PRIVACY.md @@ -1,50 +1,46 @@ -## TestQuestionPool Privacy -Insert caveat: *This documentation does not warrant completeness or correctness. -Please report any missing or wrong information using the ILIAS issue tracker.* +# TestQuestionPool Privacy -### Note: -The module TestQuestionPool and the module Test are still tied together in most intricate ways. The primary -component of concern in regards to privacy related evaluations is the Test. As the lines between these components -are blurred - which makes them subject for refactoring, too - it is advised to never look at only one of the components -but always at both. +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories).** + +## General information + +The TestQuestionPool component is used to create, continuously update and manage a collection of questions. This is useful when questions are to be reused in multiple tests. They can be categorised, e.g. using taxonomies and the lifecycle. To run tests using questions from the TestQuestionPool component, the Test component must be used. + +The TestQuestionPool component and the Test component are still tied together in most intricate ways. The primary component of concern in regards to privacy related evaluations is the Test. As the lines between these components are blurred, it is advised to never look at only one of the components but always at both. + +## Integrated components + +The TestQuestionPool component employs the following services, please consult the respective privacy.mds. + + - [AccessControl](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/AccessControl/PRIVACY.md) + - [COPage](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/COPage/PRIVACY.md): Is used for content creation/presentation within questions and is able to store, present and delete personal data. + - [Export](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/Export) + - [InfoScreen](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/InfoScreen/PRIVACY.md) + - [Metadata](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/MetaData/Privacy.md) + - [Notes](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Notes/Privacy.md): Is used to create, edit and present comments for questions and the question pool. + - [Object](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/ILIASObject) + - [Skill (Competence) Service](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Skill/PRIVACY.md) + - [Taxonomy](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Taxonomy/PRIVACY.md) + - [Test](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/components/ILIAS/Test/PRIVACY.md) + - [User](https://github.com/ILIAS-eLearning/ILIAS/tree/trunk/components/ILIAS/User): Provides information about the account being used when creating questions. ## Data being stored -- **Authorship of Questions**: - Authors of questions are stored in the TestQuestionPool as reference to the users id. - The data is required for copyright purposes as well as to enable communication with the author. - -- **Ownership of Questions**: - Owners of questions are stored in the TestQuestionPool as reference to the users id. - The data is required to manage detailed access and permissions on usage and editing of the question. - -- The TestQuestions Pool component employs the following services, please consult the respective privacy.mds: [Skill](../../ILIAS/Skill/PRIVACY.md), [Metadata](../../ILIAS/MetaData/Privacy.md), [AccessControl](../../ILIAS/AccessControl/PRIVACY.md) - - -## Data being presented -- **Authorship of Questions**: -The authors of questions are revealed in editing forms of questions as well as tabular -overviews to accounts with the edit permission to the test question pool object. -- **Ownership of Questions**: -The owners of questions are revealed in editing forms of questions as well as tabular -- overviews to accounts with the edit permission to the test question pool object. - -## Data being deleted -- **Authorship of Questions**: -The storage of this information is tied to the lifecycle of the question it is attached -to and so the deletion happens in the removal of a question by a user account with edit permissions to the question -pool the questions resides in. -- **Ownership of Questions**: -The storage of this information is tied to the lifecycle of the question it is attached - to and so the deletion happens in the removal of a question by a user account with edit permissions to the question - pool the questions resides in. - - -## Data being exported -- **Authorship of Questions**: - Authorship of questions is exported with the questions. In the test question pool, this is the case when questions or -the pool as a whole is exported by account with edit permissions on the test question pool object. -In the test object, questions can be exported by accounts with edit permission in the context of the test. -- **Ownership of Questions**: - Ownership of questions is exported with the questions. In the test question pool, this is the case when questions or - the pool as a whole is exported by account with edit permissions on the test question pool object. - In the test object, questions can be exported by accounts with edit permission in the context of the test. + +- At the creation process of questions the field 'Author' is prefilled with the full name of the account, which is creating the question. If this value is not changed, the name of the account is stored. +- At the editing of questions the field 'Author' contains the previous saved value. If the value is changed and personal data is entered, it will be stored. +- By storing (and presenting) the value for 'Author' it is possible to contact the account, if there are problems with the question or the configuration of it. In addition it supports the collaborative development of questions. +- Ownership of Questions: Owners of questions are stored in the TestQuestionPool as reference to the 'User ID'. The data is required to manage detailed access and permissions on usage and editing of the question. + +## Data being presented + +- At the overview of the questions of a question pool, the values of the field 'Author' for all questions are shown, which may contain personal data. +- At the 'Statistics' of a question, the 'Author' of tests is displayed at the table 'This question is used in the following tests', if the question is used in tests. This information originates from the metadata service (see above). + +## Data being deleted + +It is possible to delete questions. Within this the personal data at the field 'Author' and the ownership of the question is deleted. + +## Data being exported + +- The XML export of the question pool contains the personal data 'Author' of the questions and of the question pool itself within the metadata. +- It's purpose is to being imported in ILIAS again, although the contained personal data is easily accesible. Including this information ensures that the authorship of the question is not lost after import. In addition it is possible to contact the author, e.g. if there are problems with the question or the configuration of it. diff --git a/components/ILIAS/TestQuestionPool/classes/class.assClozeTest.php b/components/ILIAS/TestQuestionPool/classes/class.assClozeTest.php index 34adaf3e51e6..a7934c1a21c2 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assClozeTest.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assClozeTest.php @@ -889,12 +889,8 @@ public function deleteGap($gap_index): void */ public function getTextgapPoints($a_original, $a_entered, $max_points): float { - global $DIC; - $refinery = $DIC->refinery(); - $result = 0; - $gaprating = $this->getTextgapRating(); - - switch ($gaprating) { + $result = 0.0; + switch ($this->textgap_rating) { case assClozeGap::TEXTGAP_RATING_CASEINSENSITIVE: if (strcmp(ilStr::strToLower($a_original), ilStr::strToLower($a_entered)) == 0) { $result = $max_points; @@ -906,19 +902,19 @@ public function getTextgapPoints($a_original, $a_entered, $max_points): float } break; case assClozeGap::TEXTGAP_RATING_LEVENSHTEIN1: - $transformation = $refinery->string()->levenshtein()->standard($a_original, 1); + $transformation = $this->refinery->string()->levenshtein()->standard($a_original, 1); break; case assClozeGap::TEXTGAP_RATING_LEVENSHTEIN2: - $transformation = $refinery->string()->levenshtein()->standard($a_original, 2); + $transformation = $this->refinery->string()->levenshtein()->standard($a_original, 2); break; case assClozeGap::TEXTGAP_RATING_LEVENSHTEIN3: - $transformation = $refinery->string()->levenshtein()->standard($a_original, 3); + $transformation = $this->refinery->string()->levenshtein()->standard($a_original, 3); break; case assClozeGap::TEXTGAP_RATING_LEVENSHTEIN4: - $transformation = $refinery->string()->levenshtein()->standard($a_original, 4); + $transformation = $this->refinery->string()->levenshtein()->standard($a_original, 4); break; case assClozeGap::TEXTGAP_RATING_LEVENSHTEIN5: - $transformation = $refinery->string()->levenshtein()->standard($a_original, 5); + $transformation = $this->refinery->string()->levenshtein()->standard($a_original, 5); break; } @@ -929,6 +925,50 @@ public function getTextgapPoints($a_original, $a_entered, $max_points): float return $result; } + /** + * + * @param array $answer_options + */ + public function getAnswerOptionIndexForTextGapAnswer( + array $answer_options, + string $response + ): ?int { + $levenshtein_distance = match ($this->textgap_rating) { + assClozeGap::TEXTGAP_RATING_LEVENSHTEIN1 => 1, + assClozeGap::TEXTGAP_RATING_LEVENSHTEIN2 => 2, + assClozeGap::TEXTGAP_RATING_LEVENSHTEIN3 => 3, + assClozeGap::TEXTGAP_RATING_LEVENSHTEIN4 => 4, + assClozeGap::TEXTGAP_RATING_LEVENSHTEIN5 => 5, + default => null + }; + + if ($levenshtein_distance !== null) { + foreach ($answer_options as $answer_index => $answer_option) { + if ($this->refinery->string()->levenshtein()->standard( + $answer_option->getAnswertext(), + $levenshtein_distance + )->transform($response) >= 0) { + return $answer_index; + } + } + } elseif ($this->textgap_rating === assClozeGap::TEXTGAP_RATING_CASEINSENSITIVE) { + $response_to_lower = strtolower($response); + foreach ($answer_options as $answer_index => $answer_option) { + if (strtolower($answer_option->getAnswertext()) === $response_to_lower) { + return $answer_index; + } + } + } elseif ($this->textgap_rating === assClozeGap::TEXTGAP_RATING_CASESENSITIVE) { + foreach ($answer_options as $answer_index => $answer_option) { + if ($answer_option->getAnswertext() === $response) { + return $answer_index; + } + } + } + + return null; + } + /** * Returns the points for a text gap and compares the given solution with diff --git a/components/ILIAS/TestQuestionPool/classes/class.assKprimChoice.php b/components/ILIAS/TestQuestionPool/classes/class.assKprimChoice.php index c8356c52e5b6..f881f4064b8f 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assKprimChoice.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assKprimChoice.php @@ -710,6 +710,7 @@ protected function lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigra public function toJSON(): string { $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $result = []; $result['id'] = $this->getId(); diff --git a/components/ILIAS/TestQuestionPool/classes/class.assMatchingQuestion.php b/components/ILIAS/TestQuestionPool/classes/class.assMatchingQuestion.php index fa5c34243f11..85e14711684a 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assMatchingQuestion.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assMatchingQuestion.php @@ -1176,6 +1176,7 @@ public function toJSON(): string $result['mobs'] = $mobs; $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $result['reset_button_label'] = $this->lng->txt("reset_terms"); return json_encode($result); diff --git a/components/ILIAS/TestQuestionPool/classes/class.assOrderingQuestionGUI.php b/components/ILIAS/TestQuestionPool/classes/class.assOrderingQuestionGUI.php index 7aaaef0dadf3..898434bd277e 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assOrderingQuestionGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assOrderingQuestionGUI.php @@ -343,7 +343,7 @@ protected function addEditSubtabs($active = self::TAB_EDIT_QUESTION) $this->ctrl->getLinkTarget($this, self::CMD_EDIT_NESTING) ); } - $tabs->setTabActive('edit_question'); + $tabs->setTabActive(self::TAB_EDIT_QUESTION); $tabs->setSubTabActive($active); } diff --git a/components/ILIAS/TestQuestionPool/classes/class.assQuestion.php b/components/ILIAS/TestQuestionPool/classes/class.assQuestion.php index 8a8cf44b2daf..5fe7dd438d73 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assQuestion.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assQuestion.php @@ -816,20 +816,14 @@ public function deleteAnswers(int $question_id): void public function deleteAdditionalTableData(int $question_id): void { - $additional_table_name = $this->getAdditionalTableName(); + $table_name = $this->getAdditionalTableName(); - if (!is_array($additional_table_name)) { - $additional_table_name = [$additional_table_name]; - } - - foreach ($additional_table_name as $table) { - if (strlen($table)) { - $this->db->manipulateF( - "DELETE FROM $table WHERE question_fi = %s", - ['integer'], - [$question_id] - ); - } + if (strlen($table_name)) { + $this->db->manipulateF( + "DELETE FROM $table_name WHERE question_fi = %s", + [ilDBConstants::T_INTEGER], + [$question_id] + ); } } @@ -1228,8 +1222,27 @@ public function saveQuestionDataToDb(?int $original_id = null): void ]); } + /** + * + * @deprecated This is a momentary helper function to update the original id, + * when cloning a test. Do not use anywhere else. 2026-06-25, sk + */ + public function updateOriginalId(?int $original_id = null): void + { + $this->original_id = $original_id; + $this->db->update( + 'qpl_questions', + [ + 'original_id' => [ilDBConstants::T_INTEGER, $original_id], + ], + [ + 'question_id' => [ilDBConstants::T_INTEGER, $this->getId()] + ] + ); + } + public function duplicate( - bool $for_test = true, + bool $set_original_id = true, string $title = '', string $author = '', int $owner = -1, @@ -1256,7 +1269,7 @@ public function duplicate( if ($owner) { $clone->setOwner($owner); } - if ($for_test) { + if ($set_original_id) { $clone->saveToDb($this->id); } else { $clone->saveToDb(); diff --git a/components/ILIAS/TestQuestionPool/classes/class.assQuestionGUI.php b/components/ILIAS/TestQuestionPool/classes/class.assQuestionGUI.php index 8b484bfac5f4..dbdf43b26ee0 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assQuestionGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assQuestionGUI.php @@ -1259,7 +1259,7 @@ public function suggestedsolution(bool $save = false): void $formchange = new ilPropertyFormGUI(); $formchange->setFormAction($this->ctrl->getFormAction($this)); - $title = $solution ? $this->lng->txt('changeSuggestedSolution') : $this->lng->txt('addSuggestedSolution'); + $title = $solution ? $this->lng->txt('changeSuggestedSolution') : $this->lng->txt('suggested_learning_content'); $formchange->setTitle($title); $formchange->setMultipart(false); $formchange->setTableWidth('100%'); diff --git a/components/ILIAS/TestQuestionPool/classes/class.assTextQuestionGUI.php b/components/ILIAS/TestQuestionPool/classes/class.assTextQuestionGUI.php index 5cc1f00df162..1f6a372a9b75 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.assTextQuestionGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.assTextQuestionGUI.php @@ -449,7 +449,7 @@ public function getPreview( if (is_object($this->getPreviewSession())) { $template->setVariable( "ESSAY", - ilLegacyFormElementsUtil::prepareFormOutput( + $this->prepareUserSolutionForAnswerFormOutput( (string) $this->getPreviewSession()->getParticipantsSolution() ) ); @@ -480,15 +480,14 @@ public function getTestOutput( $user_solution = ""; if ($active_id) { $solutions = $this->object->getUserSolutionPreferingIntermediate($active_id, $pass); - foreach ($solutions as $solution_value) { - $user_solution = $solution_value["value1"]; - } - if ($this->tiny_mce_enabled) { - $user_solution = htmlentities($user_solution); + $raw_user_solution = ''; + foreach ($solutions as $solution_value) { + $raw_user_solution = $solution_value["value1"]; } - - $user_solution = str_replace(['{', '}', '\\'], ['{', '}', '\'], $user_solution); + $user_solution = $this->prepareUserSolutionForAnswerFormOutput( + $raw_user_solution + ); } $template = new ilTemplate("tpl.il_as_qpl_text_question_output.html", true, true, "components/ILIAS/TestQuestionPool"); @@ -799,4 +798,14 @@ public function saveCorrectionsFormProperties(ilPropertyFormGUI $form): void $this->writeQuestionSpecificPostData($form); $this->writeAnswerSpecificPostData($form); } + + private function prepareUserSolutionForAnswerFormOutput( + string $solution + ): string { + if ($this->tiny_mce_enabled) { + $solution = htmlentities($solution); + } + + return str_replace(['{', '}', '\\'], ['{', '}', '\'], $solution); + } } diff --git a/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPage.php b/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPage.php index ba7b5c1ef0c2..80b2a2a72bb1 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPage.php +++ b/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPage.php @@ -16,17 +16,15 @@ * *********************************************************************/ -/** - * Question page object - * - * @author Alex Killing - * - * @version $Id$ - * - * @ingroup components\ILIASTestQuestionPool - */ +declare(strict_types=1); + +use ILIAS\Questions\Question\Question; +use ILIAS\Data\UUID\Uuid; + class ilAssQuestionPage extends ilPageObject { + private readonly Question $question; + /** * Get parent type * @return string parent type @@ -35,4 +33,92 @@ public function getParentType(): string { return "qpl"; } + + public function setQuestion( + Question $question + ): void { + $this->question = $question; + } + + public function copyToAnswerForm( + int $new_id, + Question $question + ): void { + $this->buildDom(); + $this->migrateQuestionElementToAnswerForm(); + + $new_page_object = new QstsQuestionPage(); + $new_page_object->setParentId($this->getParentId()); + $new_page_object->setId($new_id); + $new_page_object->setXMLContent($this->copyXMLContent(false, $this->getParentId())); + $new_page_object->setActive($this->getActive()); + $new_page_object->setActivationStart($this->getActivationStart()); + $new_page_object->setActivationEnd($this->getActivationEnd()); + $new_page_object->setQuestion($question); + $new_page_object->create(false); + } + + private function migrateQuestionElementToAnswerForm(): void + { + global $DIC; + $DIC->copage() + ->internal() + ->domain() + ->domUtil() + ->path($this->getDomDoc(), '//Question') + ->item(0)->parentNode->replaceWith( + $this->buildLegacyAnswerFormTextNode(), + $this->buildAnswerFormNode( + $this->question->getFirstAnswerFormIdForMigration() + ) + ); + $this->xml = $this->getXMLFromDom(); + } + + private function buildLegacyAnswerFormTextNode(): DOMNode + { + $legacy_answer_form_text_node = new ilPCLegacyAnswerFormText($this); + $legacy_answer_form_text_node->createPageContentNode(); + $legacy_answer_form_text_node->writePCId($this->generatePCId()); + $legacy_answer_form_text_node->create( + $this->retrieveLegacyPageElementContent() + ); + + return $legacy_answer_form_text_node->getDomNode(); + } + + private function buildAnswerFormNode( + Uuid $answer_form_id + ): DOMNode { + $answer_form_node = new ilPCAnswerForm($this); + $answer_form_node->createPageContentNode(); + $answer_form_node->writePCId($this->generatePCId()); + $answer_form_node->create($answer_form_id); + + return $answer_form_node->getDomNode(); + } + + private function retrieveLegacyPageElementContent(): string + { + $question_info = $this->db->fetchObject( + $this->db->query( + "SELECT add_cont_edit_mode, question_text FROM qpl_questions WHERE question_id = {$this->id}" + ) + ); + + $purified_content = ilHtmlPurifierFactory::getInstanceByType('qpl_usersolution') + ->purify($question_info->question_text); + + if ($question_info->add_cont_edit_mode === assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_IPE + || !(new ilSetting('advanced_editing'))->get('advanced_editing_javascript_editor') === 'tinymce') { + $purified_content = nl2br($purified_content); + } + return base64_encode( + ilLegacyFormElementsUtil::prepareTextareaOutput( + $purified_content, + true, + true + ) + ); + } } diff --git a/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPreviewGUI.php b/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPreviewGUI.php index 1b74c1325ff5..c08225138906 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPreviewGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.ilAssQuestionPreviewGUI.php @@ -373,7 +373,7 @@ private function populateToolbar(): void $this->toolbar->addComponent( $this->ui_factory->button()->standard( - $this->lng->txt('qpl_reset_preview'), + $this->lng->txt('reset_preview'), $this->ctrl->getLinkTargetByClass(ilAssQuestionPreviewGUI::class, self::CMD_RESET) ) ); diff --git a/components/ILIAS/TestQuestionPool/classes/class.ilObjQuestionPoolGUI.php b/components/ILIAS/TestQuestionPool/classes/class.ilObjQuestionPoolGUI.php index c1e066ff7ed8..cd4181f2e853 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.ilObjQuestionPoolGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.ilObjQuestionPoolGUI.php @@ -136,6 +136,7 @@ public function __construct() $this->ctrl->saveParameterByClass('ilobjquestionpoolgui', 'consumer_context'); $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $here_uri = $this->data_factory->uri($this->request->getUri()->__toString()); $url_builder = new URLBuilder($here_uri); @@ -371,15 +372,6 @@ public function executeCommand(): void $question_gui->setObject($question); $question_gui->setQuestionTabs(); - if ($this->questionrepository->isInActiveTest($question_gui->getObject()->getObjId())) { - $this->tpl->setOnScreenMessage( - 'failure', - $this->lng->txt('question_is_part_of_running_test'), - true - ); - $this->ctrl->redirectByClass('ilAssQuestionPreviewGUI', ilAssQuestionPreviewGUI::CMD_SHOW); - } - $this->help->setScreenIdComponent('qpl'); if ($this->object->getType() == 'qpl' && $write_access) { @@ -973,7 +965,7 @@ public function confirmDeleteQuestions(array $ids): void $this->ctrl->redirect($this, self::DEFAULT_CMD); } - $this->tpl->setOnScreenMessage('question', $this->lng->txt('qpl_confirm_delete_questions')); + $this->tpl->setOnScreenMessage('question', $this->lng->txt('confirm_delete_questions')); $deleteable_questions = $this->object->getDeleteableQuestionDetails($questionIdsToDelete); $table_gui = new ilQuestionBrowserTableGUI($this, self::DEFAULT_CMD, (($rbacsystem->checkAccess('write', $this->request_data_collector->getRefId()) ? true : false)), true); $table_gui->setShowRowsSelector(false); @@ -1001,7 +993,7 @@ public function deleteQuestionsObject(): void $this->ctrl->redirect($this, self::DEFAULT_CMD); } - $this->tpl->setOnScreenMessage('question', $this->lng->txt('qpl_confirm_delete_questions')); + $this->tpl->setOnScreenMessage('question', $this->lng->txt('confirm_delete_questions')); $deleteable_questions = &$this->object->getDeleteableQuestionDetails($questionIdsToDelete); $table_gui = new ilQuestionBrowserTableGUI( $this, @@ -1100,7 +1092,7 @@ public function questionsObject(?RoundTripModal $import_questions_modal = null): $out = []; if ($this->rbac_system->checkAccess('write', $this->request_data_collector->getRefId())) { $btn = $this->ui_factory->button()->primary( - $this->lng->txt('ass_create_question'), + $this->lng->txt('create_question'), $this->ctrl->getLinkTargetByClass([ilRepositoryGUI::class, self::class], 'createQuestionForm') ); $this->toolbar->addComponent($btn); @@ -1163,7 +1155,7 @@ private function buildQuestionCreationForm(): Form $inputs['editing_type'] = $this->buildInputEditingType(); $section = [ - $this->ui_factory->input()->field()->section($inputs, $this->lng->txt('ass_create_question')) + $this->ui_factory->input()->field()->section($inputs, $this->lng->txt('create_question')) ]; $form = $this->ui_factory->input()->container()->form()->standard( diff --git a/components/ILIAS/TestQuestionPool/classes/class.ilQuestionEditGUI.php b/components/ILIAS/TestQuestionPool/classes/class.ilQuestionEditGUI.php index d6c7af521379..27a925769082 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.ilQuestionEditGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.ilQuestionEditGUI.php @@ -85,6 +85,7 @@ public function __construct() $this->setQuestionId($this->request->getQuestionId()); $this->setQuestionType($this->request->raw('q_type')); $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); $this->ctrl->saveParameter($this, ['qpool_ref_id', 'qpool_obj_id', 'q_id', 'q_type']); @@ -158,15 +159,19 @@ public function executeCommand(): string } } - $this->tabs->activateTab('question'); if ($cmd !== 'save') { return (string) $this->ctrl->forwardCommand($question_gui); } - if ($question_gui->saveQuestion()) { - $this->main_tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true); + + $result = $question_gui->saveQuestion(); + + if (!$result) { + return ''; } - return (string) $question_gui->editQuestion(); + $this->main_tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true); + $question_gui->editQuestion(); + return ''; } } diff --git a/components/ILIAS/TestQuestionPool/classes/class.ilUnitConfigurationGUI.php b/components/ILIAS/TestQuestionPool/classes/class.ilUnitConfigurationGUI.php index fac027de50c8..913bf774ffb3 100755 --- a/components/ILIAS/TestQuestionPool/classes/class.ilUnitConfigurationGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/class.ilUnitConfigurationGUI.php @@ -47,6 +47,7 @@ public function __construct( $this->request = $local_dic['request_data_collector']; $this->lng->loadLanguageModule('assessment'); + $this->lng->loadLanguageModule('qsts'); } abstract protected function getDefaultCommand(): string; diff --git a/components/ILIAS/TestQuestionPool/classes/feedback/class.ilAssClozeTestFeedback.php b/components/ILIAS/TestQuestionPool/classes/feedback/class.ilAssClozeTestFeedback.php index 904101ec42f9..9534acfe456e 100755 --- a/components/ILIAS/TestQuestionPool/classes/feedback/class.ilAssClozeTestFeedback.php +++ b/components/ILIAS/TestQuestionPool/classes/feedback/class.ilAssClozeTestFeedback.php @@ -821,17 +821,16 @@ public function determineAnswerIndexForAnswerValue(assClozeGap $gap, string $ans return self::FB_TEXT_GAP_EMPTY_INDEX; } - $items = $gap->getItems($this->randomGroup()->dontShuffle()); - - foreach ($items as $answerIndex => $answer) { - /* @var assAnswerCloze $answer */ - - if ($answer->getAnswertext() == $answerValue) { - return $answerIndex; - } - } + $index = $this->questionOBJ->getAnswerOptionIndexForTextGapAnswer( + $gap->getItems( + $this->randomGroup()->dontShuffle() + ), + $answerValue + ); - return self::FB_TEXT_GAP_NOMATCH_INDEX; + return $index === null + ? self::FB_TEXT_GAP_NOMATCH_INDEX + : $index; case assClozeGap::TYPE_SELECT: if ($answerValue !== '') { diff --git a/components/ILIAS/TestQuestionPool/classes/forms/class.ilAssLongmenuCorrectionsInputGUI.php b/components/ILIAS/TestQuestionPool/classes/forms/class.ilAssLongmenuCorrectionsInputGUI.php index 5dd73db6c22d..c841e2df7e3c 100755 --- a/components/ILIAS/TestQuestionPool/classes/forms/class.ilAssLongmenuCorrectionsInputGUI.php +++ b/components/ILIAS/TestQuestionPool/classes/forms/class.ilAssLongmenuCorrectionsInputGUI.php @@ -55,7 +55,7 @@ public function insert(ilTemplate $a_tpl): void $this->answer_options_modal = $this->ui->factory()->modal()->lightbox( $this->ui->factory()->modal()->lightboxTextPage( $inp->render(), - $this->lng->txt('answer_options') + "{$this->lng->txt('answer_options')}:" ) ); @@ -72,7 +72,7 @@ public function insert(ilTemplate $a_tpl): void ) ) ); - $tpl->setVariable('TXT_ANSWERS', $this->lng->txt('answer_options')); + $tpl->setVariable('TXT_ANSWERS', "{$this->lng->txt('answer_options')}:"); $tpl->setVariable('TXT_CORRECT_ANSWERS', $this->lng->txt('correct_answers') . ':'); $tpl->setVariable('POSTVAR', $this->getPostVar()); diff --git a/components/ILIAS/TestQuestionPool/tests/assQuestionTest.php b/components/ILIAS/TestQuestionPool/tests/assQuestionTest.php index 96e8a43ff484..99ecf3210d54 100644 --- a/components/ILIAS/TestQuestionPool/tests/assQuestionTest.php +++ b/components/ILIAS/TestQuestionPool/tests/assQuestionTest.php @@ -69,7 +69,7 @@ public function getQuestionType(): string return ''; } - public function duplicate(bool $for_test = true, string $title = "", string $author = "", int $owner = -1, $testObjId = null): int + public function duplicate(bool $set_original_id = true, string $title = "", string $author = "", int $owner = -1, $testObjId = null): int { return 0; } diff --git a/components/ILIAS/Tracking/tests/ilLPStatusIconsTest.php b/components/ILIAS/Tracking/tests/ilLPStatusIconsTest.php index 1181ee365682..8fed1e19830a 100755 --- a/components/ILIAS/Tracking/tests/ilLPStatusIconsTest.php +++ b/components/ILIAS/Tracking/tests/ilLPStatusIconsTest.php @@ -38,7 +38,7 @@ class ilLPStatusIconsTest extends TestCase protected function getUIFactory(): UIFactory { - $custom_icon = $this->createMock(Custom::class); + $custom_icon = $this->createStub(Custom::class); $custom_icon->method('getIconPath') ->willReturn($this->path); $custom_icon->method('getSize') @@ -46,15 +46,15 @@ protected function getUIFactory(): UIFactory $custom_icon->method('getLabel') ->willReturn($this->alt); - $icon_factory = $this->createMock(IconFactory::class); + $icon_factory = $this->createStub(IconFactory::class); $icon_factory->method('custom') ->willReturn($custom_icon); - $symbol_factory = $this->createMock(SymbolFactory::class); + $symbol_factory = $this->createStub(SymbolFactory::class); $symbol_factory->method('icon') ->willReturn($icon_factory); - $factory = $this->createMock(UIFactory::class); + $factory = $this->createStub(UIFactory::class); $factory->method('symbol') ->willReturn($symbol_factory); @@ -63,7 +63,7 @@ protected function getUIFactory(): UIFactory protected function getUIRenderer(): UIRenderer { - $renderer = $this->createMock(UIRenderer::class); + $renderer = $this->createStub(UIRenderer::class); $renderer->method('render') ->willReturnCallback(function ($arg) { return 'rendered: path(' . $arg->getIconPath() . @@ -104,13 +104,9 @@ public function testTripleton(): array public function testGetInstanceForInvalidVariant(): void { - $renderer = $this->getMockBuilder(UIRenderer::class) - ->disableOriginalConstructor() - ->getMock(); + $renderer = $this->createStub(UIRenderer::class); - $factory = $this->getMockBuilder(UIFactory::class) - ->disableOriginalConstructor() - ->getMock(); + $factory = $this->createStub(UIFactory::class); $this->expectException(ilLPException::class); ilLPStatusIcons::getInstance(793, $renderer, $factory); diff --git a/components/ILIAS/Tracking/tests/ilTrackingCollectionTest.php b/components/ILIAS/Tracking/tests/ilTrackingCollectionTest.php index 542e95367506..8d00b7b9e156 100755 --- a/components/ILIAS/Tracking/tests/ilTrackingCollectionTest.php +++ b/components/ILIAS/Tracking/tests/ilTrackingCollectionTest.php @@ -62,16 +62,11 @@ protected function initDependencies(): void $GLOBALS['DIC'] = $this->dic; $this->setGlobalVariable( 'ilDB', - $this->createMock(ilDBInterface::class) + $this->createStub(ilDBInterface::class) ); - $logger = $this->getMockBuilder(ilLogger::class) - ->disableOriginalConstructor() - ->getMock(); + $logger = $this->createStub(ilLogger::class); - $logger_factory = $this->getMockBuilder(ilLoggerFactory::class) - ->disableOriginalConstructor() - ->onlyMethods(['getComponentLogger']) - ->getMock(); + $logger_factory = $this->createStub(ilLoggerFactory::class); $logger_factory->method('getComponentLogger')->willReturn($logger); $this->setGlobalVariable('ilLoggerFactory', $logger_factory); } diff --git a/components/ILIAS/Tree/classes/class.ilTreeTrashQueries.php b/components/ILIAS/Tree/classes/class.ilTreeTrashQueries.php index 73112c857aa5..c4548b9593eb 100755 --- a/components/ILIAS/Tree/classes/class.ilTreeTrashQueries.php +++ b/components/ILIAS/Tree/classes/class.ilTreeTrashQueries.php @@ -143,7 +143,8 @@ public function getTrashNodeForContainer( $order = ' '; if ($order_field) { - $order = 'ORDER BY ' . $order_field . ' ' . $order_direction; + $valid_direction = strtolower($order_direction) === 'desc' ? 'DESC' : 'ASC'; + $order = 'ORDER BY ' . $this->db->quoteIdentifier($order_field) . ' ' . $valid_direction; } $query = $select . $from . $this->appendTrashNodeForContainerQueryFilter($filter) . $order; diff --git a/components/ILIAS/UI/UI.php b/components/ILIAS/UI/UI.php index 403eb59ea7e8..1fd13c1e888f 100644 --- a/components/ILIAS/UI/UI.php +++ b/components/ILIAS/UI/UI.php @@ -444,7 +444,7 @@ public function init( $internal[UI\Implementation\Component\Symbol\Icon\Factory::class] = static fn() => new UI\Implementation\Component\Symbol\Icon\Factory(); $internal[UI\Implementation\Component\Symbol\Glyph\Factory::class] = static fn() => - new UI\Implementation\Component\Symbol\Glyph\Factory(); + new UI\Implementation\Component\Symbol\Glyph\Factory($use[Language\Language::class]); $internal[UI\Implementation\Component\Symbol\Avatar\Factory::class] = static fn() => new UI\Implementation\Component\Symbol\Avatar\Factory(); @@ -551,6 +551,16 @@ public function init( $use[UI\HelpTextRetriever::class], $internal[UI\Implementation\Component\Input\UploadLimitResolver::class], ), + new UI\Implementation\Component\Listing\ListingRendererFactory( + $use[UI\Implementation\FactoryInternal::class], + $internal[UI\Implementation\Render\TemplateFactory::class], + $use[Language\Language::class], + $internal[UI\Implementation\Render\JavaScriptBinding::class], + $use[UI\Implementation\Render\ImagePathResolver::class], + $pull[Data\Factory::class], + $use[UI\HelpTextRetriever::class], + $internal[UI\Implementation\Component\Input\UploadLimitResolver::class], + ), ) ) ); @@ -593,6 +603,8 @@ public function init( new Component\Resource\ComponentJS($this, "js/Input/Field/input.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "js/Item/dist/notification.js"); + $contribute[Component\Resource\PublicAsset::class] = fn() => + new Component\Resource\ComponentJS($this, "js/Listing/dist/listing.min.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "js/MainControls/dist/mainbar.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => diff --git a/components/ILIAS/UI/docs/ROADMAP.md b/components/ILIAS/UI/docs/ROADMAP.md index 221a2c996e9c..392c064b4ee1 100755 --- a/components/ILIAS/UI/docs/ROADMAP.md +++ b/components/ILIAS/UI/docs/ROADMAP.md @@ -362,6 +362,19 @@ different to system administrators, who want to find specific data fast, than fo browse the data slowly. There could be such enumerations that are viable for all components, but also enumerations which are specific to a component. Appropriate namespaces should be chosen. +### Implement external link safeguard (beginner, ~2d) + +The `UI\Component\Link` component family should provide a possible safeguard for links that point to +external resources. The safeguard should be used whenever such a link is built and the safeguard should +prompt the user to confirm, whether its OK to open this link or not. + +Since the factory accepts `string` and `Data\URI` for resources, we cannot easily derive this information +without some obscure dependencies to ILIAS. Therefore we may introduce an additional flag inside each +factory method, that stays optional but should be required in the future. + +The safeguard itself could be implemented as prompt, modal, or even as a popover. Some research and +accessibility evaluations should provide some insight into what is most suitable there. + ## Long Term ### Mark Some Components as Internal diff --git a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.eot b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.eot index 5799dffedf80..532560f32a9a 100644 Binary files a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.eot and b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.eot differ diff --git a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.json b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.json index 5a149efa4407..83140c647041 100644 --- a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.json +++ b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.json @@ -1,1233 +1,1243 @@ { "selection": [ { - "order": 215, + "order": 222, "ligatures": "", "prevSize": 32, "name": "user-female" }, { - "order": 216, + "order": 223, "ligatures": "", "prevSize": 32, "name": "people" }, { - "order": 217, + "order": 224, "ligatures": "", "prevSize": 32, "name": "user-follow" }, { - "order": 218, + "order": 225, "ligatures": "", "prevSize": 32, "name": "user-following" }, { - "order": 219, + "order": 226, "ligatures": "", "prevSize": 32, "name": "user-unfollow" }, { - "order": 220, + "order": 227, "ligatures": "", "prevSize": 32, "name": "user" }, { - "order": 221, + "order": 228, "ligatures": "", "prevSize": 32, "name": "trophy" }, { - "order": 222, + "order": 229, "ligatures": "", "prevSize": 32, "name": "speedometer" }, { - "order": 223, + "order": 230, "ligatures": "", "prevSize": 32, "name": "social-youtube" }, { - "order": 224, + "order": 231, "ligatures": "", "prevSize": 32, "name": "social-twitter" }, { - "order": 225, + "order": 232, "ligatures": "", "prevSize": 32, "name": "social-tumblr" }, { - "order": 226, + "order": 233, "ligatures": "", "prevSize": 32, "name": "social-facebook" }, { - "order": 227, + "order": 234, "ligatures": "", "prevSize": 32, "name": "social-dropbox" }, { - "order": 228, + "order": 235, "ligatures": "", "prevSize": 32, "name": "social-dribbble" }, { - "order": 229, + "order": 236, "ligatures": "", "prevSize": 32, "name": "shield" }, { - "order": 230, + "order": 237, "ligatures": "", "prevSize": 32, "name": "screen-tablet" }, { - "order": 231, + "order": 238, "ligatures": "", "prevSize": 32, "name": "screen-smartphone" }, { - "order": 232, + "order": 239, "ligatures": "", "prevSize": 32, "name": "screen-desktop" }, { - "order": 233, + "order": 240, "ligatures": "", "prevSize": 32, "name": "plane" }, { - "order": 234, + "order": 241, "ligatures": "", "prevSize": 32, "name": "notebook" }, { - "order": 235, + "order": 242, "ligatures": "", "prevSize": 32, "name": "mustache" }, { - "order": 236, + "order": 243, "ligatures": "", "prevSize": 32, "name": "mouse" }, { - "order": 237, + "order": 244, "ligatures": "", "prevSize": 32, "name": "magnet" }, { - "order": 238, + "order": 245, "ligatures": "", "prevSize": 32, "name": "magic-wand" }, { - "order": 239, + "order": 246, "ligatures": "", "prevSize": 32, "name": "hourglass" }, { - "order": 240, + "order": 247, "ligatures": "", "prevSize": 32, "name": "graduation" }, { - "order": 241, + "order": 248, "ligatures": "", "prevSize": 32, "name": "ghost" }, { - "order": 242, + "order": 249, "ligatures": "", "prevSize": 32, "name": "game-controller" }, { - "order": 243, + "order": 250, "ligatures": "", "prevSize": 32, "name": "fire" }, { - "order": 244, + "order": 251, "ligatures": "", "prevSize": 32, "name": "eyeglass" }, { - "order": 245, + "order": 252, "ligatures": "", "prevSize": 32, "name": "envelope-open" }, { - "order": 246, + "order": 253, "ligatures": "", "prevSize": 32, "name": "envolope-letter" }, { - "order": 247, + "order": 254, "ligatures": "", "prevSize": 32, "name": "energy" }, { - "order": 248, + "order": 255, "ligatures": "", "prevSize": 32, "name": "emotsmile" }, { - "order": 249, + "order": 256, "ligatures": "", "prevSize": 32, "name": "disc" }, { - "order": 250, + "order": 257, "ligatures": "", "prevSize": 32, "name": "cursor-move" }, { - "order": 251, + "order": 258, "ligatures": "", "prevSize": 32, "name": "crop" }, { - "order": 252, + "order": 259, "ligatures": "", "prevSize": 32, "name": "credit-card" }, { - "order": 253, + "order": 260, "ligatures": "", "prevSize": 32, "name": "chemistry" }, { - "order": 254, + "order": 261, "ligatures": "", "prevSize": 32, "name": "bell" }, { - "order": 255, + "order": 262, "ligatures": "", "prevSize": 32, "name": "badge" }, { - "order": 256, + "order": 263, "ligatures": "", "prevSize": 32, "name": "anchor" }, { - "order": 257, + "order": 264, "ligatures": "", "prevSize": 32, "name": "wallet" }, { - "order": 258, + "order": 265, "ligatures": "", "prevSize": 32, "name": "vector" }, { - "order": 259, + "order": 266, "ligatures": "", "prevSize": 32, "name": "speech" }, { - "order": 260, + "order": 267, "ligatures": "", "prevSize": 32, "name": "puzzle" }, { - "order": 261, + "order": 268, "ligatures": "", "prevSize": 32, "name": "printer" }, { - "order": 262, + "order": 269, "ligatures": "", "prevSize": 32, "name": "present" }, { - "order": 263, + "order": 270, "ligatures": "", "prevSize": 32, "name": "playlist" }, { - "order": 264, + "order": 271, "ligatures": "", "prevSize": 32, "name": "pin" }, { - "order": 265, + "order": 272, "ligatures": "", "prevSize": 32, "name": "picture" }, { - "order": 266, + "order": 273, "ligatures": "", "prevSize": 32, "name": "map" }, { - "order": 267, + "order": 274, "ligatures": "", "prevSize": 32, "name": "layers" }, { - "order": 268, + "order": 275, "ligatures": "", "prevSize": 32, "name": "handbag" }, { - "order": 269, + "order": 276, "ligatures": "", "prevSize": 32, "name": "globe-alt" }, { - "order": 270, + "order": 277, "ligatures": "", "prevSize": 32, "name": "globe" }, { - "order": 271, + "order": 278, "ligatures": "", "prevSize": 32, "name": "frame" }, { - "order": 272, + "order": 279, "ligatures": "", "prevSize": 32, "name": "folder-alt" }, { - "order": 273, + "order": 280, "ligatures": "", "prevSize": 32, "name": "film" }, { - "order": 274, + "order": 281, "ligatures": "", "prevSize": 32, "name": "feed" }, { - "order": 275, + "order": 282, "ligatures": "", "prevSize": 32, "name": "earphones-alt" }, { - "order": 276, + "order": 283, "ligatures": "", "prevSize": 32, "name": "earphones" }, { - "order": 277, + "order": 284, "ligatures": "", "prevSize": 32, "name": "drop" }, { - "order": 278, + "order": 285, "ligatures": "", "prevSize": 32, "name": "drawar" }, { - "order": 279, + "order": 286, "ligatures": "", "prevSize": 32, "name": "docs" }, { - "order": 280, + "order": 287, "ligatures": "", "prevSize": 32, "name": "directions" }, { - "order": 281, + "order": 288, "ligatures": "", "prevSize": 32, "name": "direction" }, { - "order": 282, + "order": 289, "ligatures": "", "prevSize": 32, "name": "diamond" }, { - "order": 283, + "order": 290, "ligatures": "", "prevSize": 32, "name": "cup" }, { - "order": 284, + "order": 291, "ligatures": "", "prevSize": 32, "name": "compass" }, { - "order": 285, + "order": 292, "ligatures": "", "prevSize": 32, "name": "call-out" }, { - "order": 286, + "order": 293, "ligatures": "", "prevSize": 32, "name": "call-in" }, { - "order": 287, + "order": 294, "ligatures": "", "prevSize": 32, "name": "call-end" }, { - "order": 288, + "order": 295, "ligatures": "", "prevSize": 32, "name": "calculator" }, { - "order": 289, + "order": 296, "ligatures": "", "prevSize": 32, "name": "bubbles" }, { - "order": 290, + "order": 297, "ligatures": "", "prevSize": 32, "name": "briefcase" }, { - "order": 291, + "order": 298, "ligatures": "", "prevSize": 32, "name": "book-open" }, { - "order": 292, + "order": 299, "ligatures": "", "prevSize": 32, "name": "basket-loaded" }, { - "order": 293, + "order": 300, "ligatures": "", "prevSize": 32, "name": "basket" }, { - "order": 294, + "order": 301, "ligatures": "", "prevSize": 32, "name": "bag" }, { - "order": 295, + "order": 302, "ligatures": "", "prevSize": 32, "name": "action-undo" }, { - "order": 296, + "order": 303, "ligatures": "", "prevSize": 32, "name": "action-redo" }, { - "order": 297, + "order": 304, "ligatures": "", "prevSize": 32, "name": "wrench" }, { - "order": 298, + "order": 305, "ligatures": "", "prevSize": 32, "name": "umbrella" }, { - "order": 299, + "order": 306, "ligatures": "", "prevSize": 32, "name": "trash" }, { - "order": 300, + "order": 307, "ligatures": "", "prevSize": 32, "name": "tag" }, { - "order": 301, + "order": 308, "ligatures": "", "prevSize": 32, "name": "support" }, { - "order": 302, + "order": 309, "ligatures": "", "prevSize": 32, "name": "size-fullscreen" }, { - "order": 303, + "order": 310, "ligatures": "", "prevSize": 32, "name": "size-actual" }, { - "order": 304, + "order": 311, "ligatures": "", "prevSize": 32, "name": "shuffle" }, { - "order": 305, + "order": 312, "ligatures": "", "prevSize": 32, "name": "share-alt" }, { - "order": 306, + "order": 313, "ligatures": "", "prevSize": 32, "name": "share" }, { - "order": 307, + "order": 314, "ligatures": "", "prevSize": 32, "name": "launch" }, { - "order": 308, + "order": 315, "ligatures": "", "prevSize": 32, "name": "question" }, { - "order": 309, + "order": 316, "ligatures": "", "prevSize": 32, "name": "pie-chart" }, { - "order": 310, + "order": 317, "ligatures": "", "prevSize": 32, "name": "pencil" }, { - "order": 311, + "order": 318, "ligatures": "", "prevSize": 32, "name": "note" }, { - "order": 312, + "order": 319, "ligatures": "", "prevSize": 32, "name": "music-tone-alt" }, { - "order": 313, + "order": 320, "ligatures": "", "prevSize": 32, "name": "music-tone" }, { - "order": 314, + "order": 321, "ligatures": "", "prevSize": 32, "name": "microphone" }, { - "order": 315, + "order": 322, "ligatures": "", "prevSize": 32, "name": "loop" }, { - "order": 316, + "order": 323, "ligatures": "", "prevSize": 32, "name": "logout" }, { - "order": 317, + "order": 324, "ligatures": "", "prevSize": 32, "name": "login" }, { - "order": 318, + "order": 325, "ligatures": "", "prevSize": 32, "name": "list" }, { - "order": 319, + "order": 326, "ligatures": "", "prevSize": 32, "name": "like" }, { - "order": 320, + "order": 327, "ligatures": "", "prevSize": 32, "name": "home" }, { - "order": 321, + "order": 328, "ligatures": "", "prevSize": 32, "name": "grid" }, { - "order": 322, + "order": 329, "ligatures": "", "prevSize": 32, "name": "graph" }, { - "order": 323, + "order": 330, "ligatures": "", "prevSize": 32, "name": "equalizer" }, { - "order": 324, + "order": 331, "ligatures": "", "prevSize": 32, "name": "dislike" }, { - "order": 325, + "order": 332, "ligatures": "", "prevSize": 32, "name": "cursor" }, { - "order": 326, + "order": 333, "ligatures": "", "prevSize": 32, "name": "control-start" }, { - "order": 327, + "order": 334, "ligatures": "", "prevSize": 32, "name": "control-rewind" }, { - "order": 328, + "order": 335, "ligatures": "", "prevSize": 32, "name": "control-play" }, { - "order": 329, + "order": 336, "ligatures": "", "prevSize": 32, "name": "control-pause" }, { - "order": 330, + "order": 337, "ligatures": "", "prevSize": 32, "name": "control-forward" }, { - "order": 331, + "order": 338, "ligatures": "", "prevSize": 32, "name": "control-end" }, { - "order": 332, + "order": 339, "ligatures": "", "prevSize": 32, "name": "calender" }, { - "order": 333, + "order": 340, "ligatures": "", "prevSize": 32, "name": "bulb" }, { - "order": 334, + "order": 341, "ligatures": "", "prevSize": 32, "name": "chart" }, { - "order": 335, + "order": 342, "ligatures": "", "prevSize": 32, "name": "arrow-up-circle" }, { - "order": 336, + "order": 343, "ligatures": "", "prevSize": 32, "name": "arrow-right-circle" }, { - "order": 337, + "order": 344, "ligatures": "", "prevSize": 32, "name": "arrow-left-circle" }, { - "order": 338, + "order": 345, "ligatures": "", "prevSize": 32, "name": "arrow-down-circle" }, { - "order": 339, + "order": 346, "ligatures": "", "prevSize": 32, "name": "ban" }, { - "order": 340, + "order": 347, "ligatures": "", "prevSize": 32, "name": "bubble" }, { - "order": 341, + "order": 348, "ligatures": "", "prevSize": 32, "name": "camrecorder" }, { - "order": 342, + "order": 349, "ligatures": "", "prevSize": 32, "name": "camera" }, { - "order": 343, + "order": 350, "ligatures": "", "prevSize": 32, "name": "ok" }, { - "order": 344, + "order": 351, "ligatures": "", "prevSize": 32, "name": "clock" }, { - "order": 345, + "order": 352, "ligatures": "", "prevSize": 32, "name": "close" }, { - "order": 346, + "order": 353, "ligatures": "", "prevSize": 32, "name": "cloud-download" }, { - "order": 347, + "order": 354, "ligatures": "", "prevSize": 32, "name": "cloud-upload" }, { - "order": 348, + "order": 355, "ligatures": "", "prevSize": 32, "name": "doc" }, { - "order": 349, + "order": 356, "ligatures": "", "prevSize": 32, "name": "envolope" }, { - "order": 350, + "order": 357, "ligatures": "", "prevSize": 32, "name": "eye" }, { - "order": 351, + "order": 358, "ligatures": "", "prevSize": 32, "name": "flag" }, { - "order": 352, + "order": 359, "ligatures": "", "prevSize": 32, "name": "folder" }, { - "order": 353, + "order": 360, "ligatures": "", "prevSize": 32, "name": "heart" }, { - "order": 354, + "order": 361, "ligatures": "", "prevSize": 32, "name": "info" }, { - "order": 355, + "order": 362, "ligatures": "", "prevSize": 32, "name": "key" }, { - "order": 356, + "order": 363, "ligatures": "", "prevSize": 32, "name": "link" }, { - "order": 357, + "order": 364, "ligatures": "", "prevSize": 32, "name": "lock" }, { - "order": 358, + "order": 365, "ligatures": "", "prevSize": 32, "name": "lock-open" }, { - "order": 359, + "order": 366, "ligatures": "", "prevSize": 32, "name": "magnifier" }, { - "order": 360, + "order": 367, "ligatures": "", "prevSize": 32, "name": "magnifier-add" }, { - "order": 361, + "order": 368, "ligatures": "", "prevSize": 32, "name": "magnifier-remove" }, { - "order": 362, + "order": 369, "ligatures": "", "prevSize": 32, "name": "paper-clip" }, { - "order": 363, + "order": 370, "ligatures": "", "prevSize": 32, "name": "paper-plane" }, { - "order": 364, + "order": 371, "ligatures": "", "prevSize": 32, "name": "plus" }, { - "order": 365, + "order": 372, "ligatures": "", "prevSize": 32, "name": "location-pin" }, { - "order": 366, + "order": 373, "ligatures": "", "prevSize": 32, "name": "power" }, { - "order": 367, + "order": 374, "ligatures": "", "prevSize": 32, "name": "refresh" }, { - "order": 368, + "order": 375, "ligatures": "", "prevSize": 32, "name": "reload" }, { - "order": 369, + "order": 376, "ligatures": "", "prevSize": 32, "name": "settings" }, { - "order": 370, + "order": 377, "ligatures": "", "prevSize": 32, "name": "star" }, { - "order": 371, + "order": 378, "ligatures": "", "prevSize": 32, "name": "symble-female" }, { - "order": 372, + "order": 379, "ligatures": "", "prevSize": 32, "name": "symbol-male" }, { - "order": 373, + "order": 380, "ligatures": "", "prevSize": 32, "name": "target" }, { - "order": 374, + "order": 381, "ligatures": "", "prevSize": 32, "name": "volume-1" }, { - "order": 375, + "order": 382, "ligatures": "", "prevSize": 32, "name": "volume-2" }, { - "order": 376, + "order": 383, "ligatures": "", "prevSize": 32, "name": "volume-off" }, { - "order": 377, + "order": 384, "ligatures": "", "prevSize": 32, "name": "phone" }, { - "order": 378, + "order": 385, "ligatures": "", "prevSize": 32, "name": "menu" }, { - "order": 379, + "order": 386, "ligatures": "", "prevSize": 32, "name": "options-vertical" }, { - "order": 380, + "order": 387, "ligatures": "", "prevSize": 32, "name": "options" }, { - "order": 381, + "order": 388, "ligatures": "", "prevSize": 32, "name": "arrow-down" }, { - "order": 382, + "order": 389, "ligatures": "", "prevSize": 32, "name": "arrow-left" }, { - "order": 383, + "order": 390, "ligatures": "", "prevSize": 32, "name": "arrow-right" }, { - "order": 384, + "order": 391, "ligatures": "", "prevSize": 32, "name": "arrow-up" }, { - "order": 385, + "order": 392, "ligatures": "", "prevSize": 32, "name": "paypal" }, { - "order": 386, + "order": 393, "ligatures": "", "prevSize": 32, "name": "social-instagram" }, { - "order": 387, + "order": 394, "ligatures": "", "prevSize": 32, "name": "social-linkedin" }, { - "order": 388, + "order": 395, "ligatures": "", "prevSize": 32, "name": "social-pintarest" }, { - "order": 389, + "order": 396, "ligatures": "", "prevSize": 32, "name": "social-github" }, { - "order": 390, + "order": 397, "ligatures": "", "prevSize": 32, "name": "social-google" }, { - "order": 391, + "order": 398, "ligatures": "", "prevSize": 32, "name": "social-reddit" }, { - "order": 392, + "order": 399, "ligatures": "", "prevSize": 32, "name": "social-skype" }, { - "order": 393, + "order": 400, "ligatures": "", "prevSize": 32, "name": "social-behance" }, { - "order": 394, + "order": 401, "ligatures": "", "prevSize": 32, "name": "social-foursqare" }, { - "order": 395, + "order": 402, "ligatures": "", "prevSize": 32, "name": "social-soundcloud" }, { - "order": 396, + "order": 403, "ligatures": "", "prevSize": 32, "name": "social-spotify" }, { - "order": 397, + "order": 404, "ligatures": "", "prevSize": 32, "name": "social-stumbleupon" }, { - "order": 398, + "order": 405, "ligatures": "", "prevSize": 32, "name": "minus" }, { - "order": 399, + "order": 406, "ligatures": "", "prevSize": 32, "name": "organization" }, { - "order": 400, + "order": 407, "ligatures": "", "prevSize": 32, "name": "exclamation" }, { - "order": 401, + "order": 408, "ligatures": "", "prevSize": 32, "name": "lang" }, { - "order": 402, + "order": 409, "ligatures": "", "prevSize": 32, "name": "event" }, { - "order": 403, + "order": 410, "ligatures": "", "prevSize": 32, "name": "social-steam" }, { - "order": 404, + "order": 411, "name": "bulletlist", "prevSize": 32 }, { - "order": 405, + "order": 412, "prevSize": 32, "name": "numberedlist" }, { - "order": 406, + "order": 413, "name": "listindent", "prevSize": 32 }, { - "order": 407, + "order": 414, "name": "listoutdent", "prevSize": 32 }, { - "order": 408, + "order": 415, "name": "filter", "prevSize": 32 }, { - "order": 409, + "order": 416, "name": "columnselection", "prevSize": 32 }, { - "order": 410, + "order": 417, "name": "enlarge", "prevSize": 32 }, { - "order": 411, + "order": 418, "name": "preview", "prevSize": 32 }, { - "order": 412, + "order": 419, "name": "ListView", "prevSize": 32 }, { - "order": 413, + "order": 420, "name": "TileView", "prevSize": 32 }, { - "order": 414, + "order": 421, "name": "reset", "prevSize": 32 }, { - "order": 415, + "order": 422, "name": "sort", "prevSize": 32 }, { - "order": 416, + "order": 423, "name": "apply", "prevSize": 32 }, { - "order": 417, + "order": 424, "name": "drag-drop-handle", "prevSize": 32 }, { - "order": 418, + "order": 425, "name": "unselect", "prevSize": 32 }, { - "order": 419, + "order": 426, "name": "select", "prevSize": 32 }, { - "order": 420, + "order": 427, "name": "clear", "prevSize": 32 }, { - "order": 421, + "order": 428, "name": "checked", "prevSize": 32 }, { - "order": 422, + "order": 429, "name": "unchecked", "prevSize": 32 + }, + { + "order": 430, + "name": "presenter", + "prevSize": 32 + }, + { + "order": 431, + "name": "owner", + "prevSize": 32 } ], "metadata": { @@ -1236,7 +1246,7 @@ "width": 320, "height": 320 }, - "iconsHash": 1953044038 + "iconsHash": 138035486 }, "height": 1024, "prevSize": 32, @@ -2419,7 +2429,12 @@ }, { "paths": [ - "M960 95.888l-256.224 0.001v-63.776c0-17.68-14.32-32-32-32s-32 14.32-32 32v63.76h-256v-63.76c0-17.68-14.32-32-32-32s-32 14.32-32 32v63.76h-255.776c-35.344 0-64 28.656-64 64v800c0 35.344 28.656 64 64 64h896c35.344 0 64-28.656 64-64v-800c0-35.328-28.656-63.984-64-63.984zM960 959.873l-896-0.001v-800h255.776v32.24c0 17.68 14.32 32 32 32s32-14.32 32-32v-32.224h256v32.24c0 17.68 14.32 32 32 32s32-14.32 32-32v-32.24h256.224v799.984zM736 511.888h64c17.664 0 32-14.336 32-32v-64c0-17.664-14.336-32-32-32h-64c-17.664 0-32 14.336-32 32v64c0 17.664 14.336 32 32 32zM736 767.872h64c17.664 0 32-14.32 32-32v-64c0-17.664-14.336-32-32-32h-64c-17.664 0-32 14.336-32 32v64c0 17.696 14.336 32 32 32zM544 639.872h-64c-17.664 0-32 14.336-32 32v64c0 17.68 14.336 32 32 32h64c17.664 0 32-14.32 32-32v-64c0-17.648-14.336-32-32-32zM544 383.888h-64c-17.664 0-32 14.336-32 32v64c0 17.664 14.336 32 32 32h64c17.664 0 32-14.336 32-32v-64c0-17.68-14.336-32-32-32zM288 383.888h-64c-17.664 0-32 14.336-32 32v64c0 17.664 14.336 32 32 32h64c17.664 0 32-14.336 32-32v-64c0-17.68-14.336-32-32-32zM288 639.872h-64c-17.664 0-32 14.336-32 32v64c0 17.68 14.336 32 32 32h64c17.664 0 32-14.32 32-32v-64c0-17.648-14.336-32-32-32z" + "M155.187-2.125c-0.037 0-0.081 0-0.125 0-17.629 0-31.929 14.256-32 31.868v101.132h-43c-43.804 0-80.062 36.009-80.062 79.812v163.25c0 0.037 0 0.081 0 0.125s0 0.088 0 0.132v-0.007 568.562c0 43.804 36.259 80.062 80.062 80.062h863.875c43.804 0 80.062-36.259 80.062-80.062v-568.562c0-0.037 0-0.081 0-0.125s0-0.088 0-0.132v0.007-163.25c0-43.804-36.259-79.812-80.062-79.812h-42.5v-99c-0.071-17.597-14.335-31.84-31.934-31.875h-0.003c-0.037 0-0.081 0-0.125 0-17.629 0-31.929 14.256-32 31.868v99.007h-650.312v-101.125c-0.071-17.576-14.299-31.804-31.868-31.875h-0.007zM80.062 194.875h863.875c9.216 0 16.062 6.597 16.062 15.812v131.375h-896v-131.375c0-9.216 6.847-15.812 16.062-15.812zM64 406.062h896v536.687c0 9.216-6.847 16.063-16.062 16.063h-863.875c-9.216 0-16.062-6.847-16.062-16.063v-536.687zM277.812 449.312c-17.646 0.035-31.938 14.349-31.938 32 0 0.044 0 0.088 0 0.132v-0.007 75.312h-86.187c-0.037 0-0.081 0-0.125 0-17.651 0-31.964 14.291-32 31.934v0.003c0 0.037 0 0.081 0 0.125 0 17.673 14.327 32 32 32 0.044 0 0.088 0 0.132 0h86.18v126.375h-86.187c-0.037 0-0.081 0-0.125 0-17.629 0-31.929 14.256-32 31.869v0.007c0 0.037 0 0.081 0 0.125 0 17.673 14.327 32 32 32 0.044 0 0.088 0 0.132 0h86.18v71.125c0.071 17.597 14.335 31.84 31.934 31.875h0.003c0.037 0 0.081 0 0.125 0 17.629 0 31.929-14.256 32-31.868v-71.132h167.687v71.125c0.071 17.619 14.371 31.875 32 31.875 0.044 0 0.088 0 0.132 0h-0.007c17.576-0.071 31.804-14.299 31.875-31.868v-71.132h172.5v71.125c0.071 17.619 14.371 31.875 32 31.875 0.044 0 0.088 0 0.132 0h-0.007c17.576-0.071 31.804-14.299 31.875-31.868v-71.132h86.187c0.037 0 0.081 0 0.125 0 17.673 0 32-14.327 32-32 0-0.044 0-0.088 0-0.132v0.007c-0.071-17.619-14.371-31.875-32-31.875-0.044 0-0.088 0-0.132 0h-86.18v-126.375h86.187c0.037 0 0.081 0 0.125 0 17.673 0 32-14.327 32-32 0-0.044 0-0.088 0-0.132v0.007c-0.035-17.646-14.349-31.938-32-31.938-0.044 0-0.088 0-0.132 0h-86.18v-75.312c0-0.037 0-0.081 0-0.125 0-17.629-14.256-31.929-31.868-32h-0.007c-0.037 0-0.081 0-0.125 0-17.673 0-32 14.327-32 32 0 0.044 0 0.088 0 0.132v-0.007 75.312h-172.5v-75.312c0-0.037 0-0.081 0-0.125 0-17.629-14.256-31.929-31.868-32h-0.007c-0.037 0-0.081 0-0.125 0-17.673 0-32 14.327-32 32 0 0.044 0 0.088 0 0.132v-0.007 75.312h-167.687v-75.312c0-0.037 0-0.081 0-0.125 0-17.673-14.327-32-32-32-0.044 0-0.088 0-0.132 0h0.007zM309.937 620.812h167.687v126.375h-167.687v-126.375zM541.625 620.812h172.5v126.375h-172.5v-126.375z" + ], + "attrs": [ + { + "opacity": 0.96 + } ], "tags": [ "calender" @@ -3119,7 +3134,12 @@ }, { "paths": [ - "M676 862c-16 0-28-13-28-29v-142c0-16 12-28 28-28h142c16 0 29 12 29 28v142c0 16-13 29-29 29h-142zM818 691h-142v142h142v-142zM960 96c35 0 64 29 64 64v800c0 35-29 64-64 64h-896c-35 0-64-29-64-64v-800c0-35 29-64 64-64h256v-64c0-18 14-32 32-32s32 14 32 32v64h256v-64c0-18 14-32 32-32s32 14 32 32v64h256zM64 960h896v-800h-256v32c0 18-14 32-32 32s-32-14-32-32v-32h-256v32c0 18-14 32-32 32s-32-14-32-32v-32h-256v800z" + "M155.187-2.125c-0.037 0-0.081 0-0.125 0-17.629 0-31.929 14.256-32 31.868v101.132h-43c-43.804 0-80.062 36.009-80.062 79.812v163.25c0 0.037 0 0.081 0 0.125s0 0.088 0 0.132v-0.007 568.562c0 43.804 36.259 80.062 80.062 80.062h863.875c43.804 0 80.062-36.259 80.062-80.062v-568.562c0-0.037 0-0.081 0-0.125s0-0.088 0-0.132v0.007-163.25c0-43.804-36.259-79.812-80.062-79.812h-42.5v-99c-0.071-17.597-14.335-31.84-31.934-31.875h-0.003c-0.037 0-0.081 0-0.125 0-17.629 0-31.929 14.256-32 31.868v99.007h-650.312v-101.125c-0.071-17.576-14.299-31.804-31.868-31.875h-0.007zM80.062 194.875h863.875c9.216 0 16.062 6.597 16.062 15.812v131.375h-896v-131.375c0-9.216 6.847-15.812 16.062-15.812zM64 406.062h896v536.687c0 9.216-6.847 16.063-16.062 16.063h-863.875c-9.216 0-16.062-6.847-16.062-16.063v-536.687zM221.812 465.812c-0.036 0-0.079 0-0.122 0-17.63 0-31.93 14.255-32.003 31.868v150.007c0 0.036 0 0.079 0 0.122 0 17.675 14.328 32.003 32.003 32.003 0.043 0 0.086 0 0.129 0h152.618c17.62-0.073 31.875-14.373 31.875-32.003 0-0.043 0-0.086 0-0.129v0.007-150c-0.073-17.575-14.3-31.802-31.868-31.875h-152.632z" + ], + "attrs": [ + { + "opacity": 0.96 + } ], "tags": [ "event" @@ -3363,6 +3383,26 @@ ], "defaultCode": 59668, "grid": 0 + }, + { + "paths": [ + "M857.875 142.438c-0.283-0.008-0.615-0.013-0.949-0.013-7.96 0-15.316 2.584-21.277 6.958l0.1-0.070-120.25 87.375c-9.059 6.619-14.877 17.205-14.877 29.151 0 7.954 2.58 15.305 6.948 21.263l-0.071-0.101c6.617 9.083 17.217 14.918 29.18 14.918 7.941 0 15.281-2.571 21.234-6.926l-0.101 0.071 120.25-87.438c9.059-6.619 14.877-17.205 14.877-29.151 0-7.954-2.579-15.305-6.948-21.263l0.070 0.101c-6.431-8.809-16.607-14.553-28.138-14.874l-0.050-0.001zM392.375 153.313c-79.224 2.093-140.484 39.963-176.25 92.562s-48.406 117.918-43 180c7.736 88.837 62.195 139.371 112.25 170.375-2.691 4.45-3.526 11.816-8.313 15.062-9.427 6.394-25.096 11.224-42 15.875-34.358 9.453-96.801 9.707-146 59.063-30.025 30.12-63.894 71.968-82.187 178.812-0.327 1.824-0.515 3.923-0.515 6.065 0 17.768 12.872 32.529 29.8 35.466l0.215 0.031c1.82 0.326 3.916 0.513 6.055 0.513 17.789 0 32.565-12.904 35.477-29.862l0.030-0.214c16.71-97.596 33.48-111.326 62.125-140.062 26.661-26.746 65.533-27.005 114.125-40.375 16.23-4.466 40.175-10.058 63.313-25.75s43.636-44.74 47.437-82.187c0.12-1.103 0.188-2.381 0.188-3.676 0-14.419-8.476-26.858-20.718-32.606l-0.22-0.093c-39.498-17.944-92.741-58.069-99.25-132.813-4.156-47.729 6.455-97.457 30.75-133.187s59.939-59.388 118.562-60.938c54.465-1.439 92.722 18.13 120 50.313s42.445 78.504 41.313 129.188c-1.92 85.908-10.438 123.165-87.125 182.375-8.602 6.646-14.088 16.964-14.088 28.564 0 13.087 6.983 24.543 17.426 30.846l0.162 0.090c69.821 41.712 136.525 49.51 175.063 69.687 3.14 1.644 15.231 19.645 24.312 51.75s16.787 73.375 31 112.437c5.172 13.948 18.364 23.709 33.835 23.709 4.457 0 8.724-0.81 12.663-2.29l-0.248 0.082c13.916-5.188 23.648-18.364 23.648-33.813 0-4.395-0.787-8.605-2.229-12.499l0.081 0.249c-11.314-31.095-19.105-70.75-29.5-107.5s-21.603-75.64-60.25-95.875c-43.872-22.971-88.278-34.628-131.813-52.187 51.923-57.491 77.445-118.787 79.125-193.937 1.476-66.048-18.12-129.725-58.562-177.437s-102.63-77.769-176.688-75.812zM985.25 337.813c-0.128-0.002-0.279-0.003-0.431-0.003-1.5 0-2.979 0.092-4.431 0.27l0.174-0.017-205.5 24.312c-17.938 2.228-31.683 17.378-31.683 35.738 0 1.48 0.089 2.939 0.263 4.372l-0.017-0.173c2.142 18.024 17.334 31.868 35.76 31.868 1.472 0 2.923-0.088 4.349-0.26l-0.172 0.017 205.5-24.312c17.938-2.228 31.683-17.378 31.683-35.738 0-1.48-0.089-2.939-0.263-4.372l0.017 0.173c-2.116-17.855-17.037-31.608-35.223-31.875l-0.027-0zM745.188 484.375c-11.585 0.271-21.784 5.973-28.18 14.651l-0.070 0.099c-4.337 5.874-6.942 13.259-6.942 21.251 0 11.892 5.766 22.437 14.656 28.992l0.099 0.070 120 87.875c5.874 4.337 13.259 6.942 21.251 6.942 11.892 0 22.437-5.766 28.992-14.656l0.070-0.099c4.337-5.874 6.942-13.259 6.942-21.251 0-11.892-5.766-22.437-14.656-28.992l-0.099-0.070-120-87.875c-5.876-4.34-13.262-6.947-21.257-6.947-0.283 0-0.566 0.003-0.847 0.010l0.042-0.001z" + ], + "tags": [ + "glyph_presenter" + ], + "defaultCode": 59662, + "grid": 0 + }, + { + "paths": [ + "M342.947 0.080c-70.426 1.861-124.831 35.679-156.625 82.437s-43.056 104.75-38.25 159.937c6.871 78.902 55.223 123.798 99.688 151.375-2.39 3.943-3.065 10.619-7.312 13.5-8.38 5.684-22.098 10.053-37.125 14.187-30.542 8.403-86.203 8.563-129.938 52.438-26.69 26.775-56.676 63.959-72.937 158.938-0.284 1.602-0.447 3.446-0.447 5.328 0 15.778 11.418 28.888 26.442 31.519l0.192 0.028c1.599 0.283 3.439 0.445 5.318 0.445 15.799 0 28.924-11.45 31.53-26.504l0.027-0.191c14.854-86.757 29.786-98.892 55.25-124.438 23.7-23.776 58.18-24.052 101.375-35.938 14.428-3.97 35.62-8.925 56.187-22.875s38.933-39.711 42.313-73c0.109-0.993 0.172-2.144 0.172-3.309 0-12.816-7.533-23.872-18.413-28.983l-0.196-0.083c-35.112-15.952-82.589-51.682-88.375-118.125-3.695-42.428 5.84-86.55 27.437-118.312s53.199-52.998 105.313-54.375c48.416-1.279 82.564 16.267 106.812 44.875s37.82 69.758 36.813 114.812c-1.707 76.368-9.267 109.428-77.438 162.063-7.684 5.906-12.587 15.101-12.587 25.441 0 15.224 10.63 27.965 24.873 31.206l0.215 0.041c57.197 12.836 85.062 22.871 109.625 30.938 26.548 8.718 40.89 18.79 47.688 28.375 5.872 8.197 15.366 13.475 26.093 13.475 6.949 0 13.381-2.215 18.628-5.978l-0.096 0.066c8.214-5.87 13.505-15.374 13.505-26.114 0-6.967-2.227-13.415-6.007-18.669l0.065 0.095c-18.294-25.796-46.629-40.959-80.062-51.938-13.531-4.443-44.018-12.38-67.563-19.125 43.312-50.023 65.671-103.384 67.125-168.437 1.312-58.713-16.299-115.149-52.25-157.562s-91.229-69.302-157.062-67.562zM428.197 584.517c-87.963 0-159.438 72.802-159.438 161.312s71.475 161.312 159.438 161.312c77.127 0 141.602-55.978 156.313-129.437h240.812v57.875c-0 0.037-0 0.081-0 0.125 0 17.629 14.256 31.929 31.868 32l0.007 0c0.037 0 0.081 0 0.125 0 17.673 0 32-14.327 32-32 0-0.044-0-0.088-0-0.132l0 0.007v-57.875h70.625v105.125c0.071 17.576 14.299 31.804 31.868 31.875l0.007 0c0.037 0 0.081 0 0.125 0 17.629 0 31.929-14.256 32-31.868l0-0.007v-137c0-0.037 0-0.081 0-0.125 0-17.673-14.327-32-32-32-0.044 0-0.088 0-0.132 0l0.007-0h-407.375c-14.802-73.343-79.206-129.187-156.25-129.187zM428.197 648.267c52.787 0 95.587 43.026 95.688 97.375-0 0.028-0 0.061-0 0.094s0 0.066 0 0.099l-0-0.005c0 54.44-42.838 97.312-95.688 97.312s-95.437-42.872-95.437-97.312c0-54.44 42.588-97.562 95.437-97.562z" + ], + "tags": [ + "glyph_owner" + ], + "defaultCode": 59663, + "grid": 0 } ], "colorThemes": [], @@ -3390,8 +3430,7 @@ "useClassSelector": true, "color": 0, "bgColor": 16777215, - "classSelector": ".icon", - "name": "icomoon" + "classSelector": ".icon" }, "historySize": 50, "showCodes": true, diff --git a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.svg b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.svg index 1a6ce8888a27..99f0dd8b7880 100644 --- a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.svg +++ b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.svg @@ -124,7 +124,7 @@ - + @@ -194,7 +194,7 @@ - + @@ -210,6 +210,8 @@ + + diff --git a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.ttf b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.ttf index 7de5f9df5c51..e80272ac083c 100644 Binary files a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.ttf and b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.ttf differ diff --git a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.woff b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.woff index ad247bb355d5..d7b9d34ca70d 100644 Binary files a/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.woff and b/components/ILIAS/UI/resources/fonts/Iconfont/il-icons.woff differ diff --git a/components/ILIAS/UI/resources/images/standard/icon_qsts.svg b/components/ILIAS/UI/resources/images/standard/icon_qsts.svg new file mode 100755 index 000000000000..a47443e9b27c --- /dev/null +++ b/components/ILIAS/UI/resources/images/standard/icon_qsts.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js b/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js index 7deb8976abeb..da1c5d9c02a9 100644 --- a/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js +++ b/components/ILIAS/UI/resources/js/Dropdown/dist/dropdown.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(t){"use strict";class e{#t;#e;#i;#n;constructor(t){if(this.#e=t,this.#t=t.ownerDocument,this.#i=this.#e.querySelector(":scope > button"),null===this.#i)throw new Error("Dropdown: Expected exactly one button in dropdown element.",this.#e);if(this.#n=this.#e.querySelector(".dropdown-menu"),null===this.#n)throw new Error("Dropdown: Expected exactly a dropdown element.",this.#e);this.#i.addEventListener("click",this.#s)}#o=t=>{27===t.key&&this.hide()};#s=t=>{t.stopPropagation(),this.show()};#d=()=>{this.hide()};#h=t=>{this.#e.contains(t.relatedTarget)||this.hide()};#l=()=>{const t=this.#t.documentElement.clientWidth;this.#i.getBoundingClientRect().left+this.#n.getBoundingClientRect().width>t?(this.#n.classList.remove("dropdown-menu__right"),this.#n.classList.add("dropdown-menu__left")):(this.#n.classList.remove("dropdown-menu__left"),this.#n.classList.add("dropdown-menu__right"))};show(){il.UI.dropdown.opened?.hide(),il.UI.dropdown.opened=this,this.#n.style.display="block",this.#l(),this.#i.setAttribute("aria-expanded","true"),this.#t.addEventListener("keydown",this.#o),this.#t.addEventListener("click",this.#d),this.#e.addEventListener("focusout",this.#h),this.#i.removeEventListener("click",this.#s)}hide(){this.#n.style.display="none",this.#i.setAttribute("aria-expanded","false"),this.#t.removeEventListener("keydown",this.#o),this.#t.removeEventListener("click",this.#d),this.#e.removeEventListener("focusout",this.#h),this.#i.addEventListener("click",this.#s)}}t.UI=t.UI||{},t.UI.dropdown={},t.UI.dropdown.opened=null,t.UI.dropdown.init=function(t){return new e(t)}}(il); +!function(t){"use strict";class e{#t;#e;#i;#n;constructor(t){if(this.#e=t,this.#t=t.ownerDocument,this.#i=this.#e.querySelector(":scope > button"),null===this.#i)throw new Error("Dropdown: Expected exactly one button in dropdown element.",this.#e);if(this.#n=this.#e.querySelector(".dropdown-menu"),null===this.#n)throw new Error("Dropdown: Expected exactly a dropdown element.",this.#e);this.#i.addEventListener("click",this.#s)}#o=t=>{"Escape"===t.key&&this.hide()};#s=t=>{t.stopPropagation(),this.show()};#d=()=>{this.hide()};#h=t=>{this.#e.contains(t.relatedTarget)||this.hide()};#l=()=>{const t=this.#t.documentElement.clientWidth;this.#i.getBoundingClientRect().left+this.#n.getBoundingClientRect().width>t?(this.#n.classList.remove("dropdown-menu__right"),this.#n.classList.add("dropdown-menu__left")):(this.#n.classList.remove("dropdown-menu__left"),this.#n.classList.add("dropdown-menu__right"))};show(){il.UI.dropdown.opened?.hide(),il.UI.dropdown.opened=this,this.#n.style.display="block",this.#l(),this.#i.setAttribute("aria-expanded","true"),this.#t.addEventListener("keydown",this.#o),this.#t.addEventListener("click",this.#d),this.#e.addEventListener("focusout",this.#h),this.#i.removeEventListener("click",this.#s)}hide(){this.#n.style.display="none",this.#i.setAttribute("aria-expanded","false"),this.#t.removeEventListener("keydown",this.#o),this.#t.removeEventListener("click",this.#d),this.#e.removeEventListener("focusout",this.#h),this.#i.addEventListener("click",this.#s)}}t.UI=t.UI||{},t.UI.dropdown={},t.UI.dropdown.opened=null,t.UI.dropdown.init=function(t){return new e(t)}}(il); diff --git a/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js b/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js index b87a1a10f158..249b3bca0ac3 100644 --- a/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js +++ b/components/ILIAS/UI/resources/js/Dropdown/src/Dropdown.js @@ -58,7 +58,7 @@ export default class Dropdown { * @type {function(KeyboardEvent)} */ #hideOnEscape = (/** @param {KeyboardEvent} event */ event) => { - if (event.key === 27) { // ESCAPE + if (event.key === 'Escape') { this.hide(); } }; diff --git a/components/ILIAS/UI/resources/js/Listing/dist/listing.min.js b/components/ILIAS/UI/resources/js/Listing/dist/listing.min.js new file mode 100644 index 000000000000..eb2203dc7cb3 --- /dev/null +++ b/components/ILIAS/UI/resources/js/Listing/dist/listing.min.js @@ -0,0 +1,15 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + */ +!function(t,e){"use strict";t.UI=t.UI||{},t.UI.Listing={createExpandableList:i=>function(t,e){const i=e.parentElement.querySelector(`[aria-controls="${e.id}"]`);if(!i)throw new Error("Could not find button associated with list.");if(!e.hasAttribute("data-max-items"))throw new Error("Could not find max items attribute.");const a=parseInt(e.getAttribute("data-max-items"),10),n=e.querySelectorAll("li");i.addEventListener("click",()=>{!function(t,e,i,a){const n=e.hasAttribute("aria-expanded")&&"true"===e.getAttribute("aria-expanded");i.forEach((t,e)=>{e>a-1&&(n?t.classList.replace("visible","hidden"):t.classList.replace("hidden","visible"))}),n?(e.setAttribute("aria-expanded","false"),e.textContent=t.txt("show_more")):(e.setAttribute("aria-expanded","true"),e.textContent=t.txt("show_less"))}(t,i,n,a)})}({txt:e=>t.Language.txt(e)},e.getElementById(i))}}(il,document); diff --git a/components/ILIAS/UI/resources/js/Listing/rollup.config.js b/components/ILIAS/UI/resources/js/Listing/rollup.config.js new file mode 100755 index 000000000000..bd092843e631 --- /dev/null +++ b/components/ILIAS/UI/resources/js/Listing/rollup.config.js @@ -0,0 +1,43 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + */ + +import terser from '@rollup/plugin-terser'; +import copyright from '../../../../../../scripts/Copyright-Checker/copyright.js'; +import preserveCopyright from '../../../../../../scripts/Copyright-Checker/preserveCopyright.js'; + +export default { + input: './src/listing.js', + external: [ + 'ilias', + 'document', + ], + output: { + // file: '../../../../../../public/assets/js/listing.min.js', + file: './dist/listing.min.js', + format: 'iife', + banner: copyright, + globals: { + ilias: 'il', + document: 'document', + }, + plugins: [ + terser({ + format: { + comments: preserveCopyright, + }, + }), + ], + }, +}; diff --git a/components/ILIAS/UI/resources/js/Listing/src/createExpandableList.js b/components/ILIAS/UI/resources/js/Listing/src/createExpandableList.js new file mode 100644 index 000000000000..a2008ce771f6 --- /dev/null +++ b/components/ILIAS/UI/resources/js/Listing/src/createExpandableList.js @@ -0,0 +1,74 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + * + * @author Thibeau Fuhrer + */ + +/** + * @param {{ txt: function(string): string }} + * @param {HTMLButtonElement} button + * @param {HTMLLIElement[]} listItems + * @param {number} maxItemCount + */ +function toggleListItems( + language, + button, + listItems, + maxItemCount, +) { + const isExpanded = button.hasAttribute('aria-expanded') + && button.getAttribute('aria-expanded') === 'true'; + + listItems.forEach((item, index) => { + if (index > (maxItemCount - 1)) { + if (isExpanded) { + item.classList.replace('visible', 'hidden'); + } else { + item.classList.replace('hidden', 'visible'); + } + } + }); + if (isExpanded) { + button.setAttribute('aria-expanded', 'false'); + button.textContent = language.txt('show_more'); + } else { + button.setAttribute('aria-expanded', 'true'); + button.textContent = language.txt('show_less'); + } +} + +/** + * @param {{ txt: function(string): string }} + * @param {HTMLUListElement|HTMLOListElement} list + */ +export default function createExpandableList(language, list) { + const button = list.parentElement.querySelector(`[aria-controls="${list.id}"]`); + if (!button) { + throw new Error('Could not find button associated with list.'); + } + if (!list.hasAttribute('data-max-items')) { + throw new Error('Could not find max items attribute.'); + } + const maxItemCount = parseInt(list.getAttribute('data-max-items'), 10); + const listItems = list.querySelectorAll('li'); + + button.addEventListener('click', () => { + toggleListItems( + language, + button, + listItems, + maxItemCount, + ); + }); +} diff --git a/components/ILIAS/UI/resources/js/Listing/src/listing.js b/components/ILIAS/UI/resources/js/Listing/src/listing.js new file mode 100755 index 000000000000..5802d3f6c917 --- /dev/null +++ b/components/ILIAS/UI/resources/js/Listing/src/listing.js @@ -0,0 +1,27 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + */ + +import il from 'ilias'; +import document from 'document'; +import createExpandableList from './createExpandableList.js'; + +il.UI = il.UI || {}; + +il.UI.Listing = { + createExpandableList: (id) => createExpandableList( + { txt: (key) => il.Language.txt(key) }, + document.getElementById(id), + ), +}; diff --git a/components/ILIAS/UI/resources/js/Table/dist/table.min.js b/components/ILIAS/UI/resources/js/Table/dist/table.min.js index 823b92627136..a1d8ba5f94ca 100644 --- a/components/ILIAS/UI/resources/js/Table/dist/table.min.js +++ b/components/ILIAS/UI/resources/js/Table/dist/table.min.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(e,t){"use strict";class s{#e;#t;#s;#i;#a;#o;#n;#r;constructor(e,t,s,i){if(this.#s=document.getElementById(i),null===this.#s)throw new Error(`Could not find a DataTable for id '${i}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no in the component's HTML.");this.#i=this.#s.getElementsByClassName("c-table-data__async_modal_container").item(0),this.#a=this.#s.getElementsByClassName("c-table-data__async_message").item(0),this.#o=this.#a.getElementsByClassName("c-table-data__async_messageresponse").item(0),this.#e=e,this.#t={actionId:t,rowId:s},this.#r={},this.#s.addEventListener("keydown",(e=>this.navigateCellsWithArrowKeys(e)));const a=this.#n.getElementsByClassName("c-table-data__row-selector");for(let e=0;ethis.selectionChange()))}}registerAction(e,t,s,i){this.#r[e]={async:t,urlBuilder:s,urlTokens:i}}selectionChange(){this.#l(!this.#c())}#c(){const{urlBuilder:e}=this.#r[Object.keys(this.#r).at(0)],{urlTokens:t}=this.#r[Object.keys(this.#r).at(0)],s=t.values().next().value,i=this.collectSelectedRowIds();i.push(i[0]),e.writeParameter(s,i);try{e.getUrl().toString()}catch(e){return!1}return!0}#h(){const e=this.#s.querySelector("dialog.c-table-data__multiaction-warning");il.UI.modal.showModal(e,{},{id:e.id})}#l(e){this.#n.getElementsByClassName("c-table-data__row-selector").forEach((t=>{t.disabled=!0===e&&!t.checked}))}selectAll(e){const t=this.#n.getElementsByClassName("c-table-data__row-selector"),s=this.#n.getElementsByClassName("c-table-data__selection_all").item(0),i=this.#n.getElementsByClassName("c-table-data__selection_none").item(0);for(let s=0;s{e.checked&&t.push(e.value)})),t}doMultiAction(e){this.doAction(e,this.collectSelectedRowIds())}doSingleAction(e){const t=e.options[this.#t.rowId];this.doAction(e,[t])}doActionForAll(e){const t=e.parentNode.parentNode.parentNode,s=t.getElementsByClassName("close").item(0),i=t.getElementsByClassName("modal-body")[0].getElementsByTagName("select")[0].value;if(i in this.#r){const e=this.#t.actionId,t={options:{}};t.options[e]=i,s.click(),this.doAction(t,["ALL_OBJECTS"])}}doAction(e,t){const s=e.options[this.#t.actionId],i=this.#r[s],a=i.urlTokens.values().next().value;i.urlBuilder.writeParameter(a,t);const o=decodeURI(i.urlBuilder.getUrl().toString());i.async?this.asyncAction(o):window.location.href=o}asyncAction(e){this.#e.ajax({url:e,dataType:"html"}).done((e=>{if("SCRIPT"===this.#e(e).first().prop("tagName"))this.#e.globalEval(this.#e(e).first().text());else{let t;this.#e(e).first().hasClass("c-modal")?(this.#i.innerHTML=e,t=this.#i.firstChild):(this.#o.innerHTML=e,t=this.#a);this.#e(`
${e}
`).find("[data-replace-marker='script']").each(((e,t)=>this.#e.globalEval(t.innerHTML))),il.UI.modal.showModal(t,{},{id:t.id})}}))}navigateCellsWithArrowKeys(e){if(37!==e.which&&38!==e.which&&39!==e.which&&40!==e.which)return;const t=e.target.closest("td, th"),s=t.closest("tr");let{cellIndex:i}=t,{rowIndex:a}=s;switch(e.which){case 37:i-=1;break;case 39:i+=1;break;case 38:a-=1;break;case 40:a+=1}a<0||i<0||a>=this.#n.rows.length||i>=s.cells.length||this.focusCell(t,a,i)}focusCell(e,t,s){const i=this.#n.rows[t].cells[s];i.focus(),e.setAttribute("tabindex",-1),i.setAttribute("tabindex",0)}}class i{#s;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a PresentationTable for id '${e}'.`)}expandRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("collapsed"),t.classList.add("expanded")}collapseRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("expanded"),t.classList.add("collapsed")}toggleRow(e){this.#s.querySelector(`#${e}`).classList.contains("expanded")?this.collapseRow(e):this.expandRow(e)}expandAll(e){const t=this.#s.querySelectorAll(".il-table-presentation-row");e.options.expand?t.forEach((e=>this.expandRow(e.id))):t.forEach((e=>this.collapseRow(e.id)))}}class a{#s;#n;#d;#g;#w;#m;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a OrderingTable for id '${e}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");this.#p(),this.#d.forEach((e=>this.#u(e)))}#p(){this.#d=Array.from(this.#n.rows),this.#d.shift(),this.#d.pop()}#u(e){e.addEventListener("dragstart",(e=>this.dragstart(e))),e.addEventListener("dragover",(e=>this.dragover(e))),e.addEventListener("dragend",(e=>this.dragend(e))),e.addEventListener("touchstart",(e=>this.touchstart(e))),e.addEventListener("touchmove",(e=>this.touchmove(e))),e.addEventListener("touchend",(e=>this.touchend(e))),e.addEventListener("touchcancel",(e=>this.touchend(e)))}dragstart(e){this.#s.classList.add("dragInProgress"),this.#g=e.target.closest("tr"),e.dataTransfer.clearData(),e.dataTransfer.setData("text/html",this.#g.outerHTML),e.dataTransfer.setData("text/plain",this.#g.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim()),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--drag-image"),this.#w.style.top="-9999px",this.#s.appendChild(this.#w),e.dataTransfer.setDragImage(this.#w,0,0),this.#m=this.#g.cloneNode(!0),this.#m.addEventListener("dragover",(e=>this.dragover(e))),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#g.classList.add("c-table-data__row--drag-origin")}dragover(e){if(!this.#b())return;e.preventDefault(),e.dataTransfer.effectAllowed="copyMove";const t=e.target.closest("tr");t&&t!==this.#m&&(this.#d.indexOf(t)>this.#d.indexOf(this.#g)?t.after(this.#m):t.before(this.#m))}dragend(e){e.preventDefault(),this.#w&&this.#s.contains(this.#w)&&(this.#s.removeChild(this.#w),this.#w=null),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#g.classList.add("c-table-data__row--drag-settle"),this.#g.addEventListener("animationend",(()=>this.#y()),{once:!0}),this.#s.classList.remove("dragInProgress"),this.#p(),this.#R()}#y(){this.#g.classList.remove("c-table-data__row--drag-settle")}#b(){return this.#d.includes(this.#g)}touchstart(e){this.#g=e.target.closest("tr"),this.#m=this.#g.cloneNode(!0),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--touch-drag-image"),this.#s.appendChild(this.#w),this.#g.classList.add("c-table-data__row--drag-origin")}touchmove(e){e.preventDefault();const t=e.touches[0];this.#w.style.left=`${t.clientX+-50}px`,this.#w.style.top=`${t.clientY}px`;const s=document.elementFromPoint(t.clientX,t.clientY)?.closest("tr");s&&this.#d.includes(s)&&(this.#d.indexOf(s)>this.#d.indexOf(this.#g)?s.after(this.#m):s.before(this.#m)),t.clientY<100?this.#f(-8):t.clientY>window.innerHeight-100?this.#f(8):this.#v()}touchend(){this.#s.removeChild(this.#w),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#p(),this.#R()}#R(){let e=10;this.#n.querySelectorAll('input[type="number"]').forEach((t=>{t.value=e,e+=10}))}#f(e){this.scrollInterval||(this.scrollInterval=setInterval((()=>{window.scrollBy(0,e)}),16))}#v(){this.scrollInterval&&(clearInterval(this.scrollInterval),this.scrollInterval=null)}}e.UI=e.UI||{},e.UI.table=e.UI.table||{},e.UI.table.data=new class{#e;#E=[];constructor(e){this.#e=e}init(e,t,i){if(void 0!==this.#E[e])throw new Error(`DataTable with id '${e}' has already been initialized.`);this.#E[e]=new s(this.#e,t,i,e)}get(e){return this.#E[e]??null}}(t),e.UI.table.presentation=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`PresentationTable with input-id '${e}' has already been initialized.`);this.#E[e]=new i(e)}get(e){return this.#E[e]??null}},e.UI.table.ordering=new class{#E=[];init(e){if(void 0!==this.#E[e])throw new Error(`OrderingTable with id '${e}' has already been initialized.`);this.#E[e]=new a(e)}get(e){return this.#E[e]??null}}}(il,$); +!function(e,t){"use strict";class s{#e;#t;#s;#i;#a;#o;#n;#r;constructor(e,t,s,i){if(this.#s=document.getElementById(i),null===this.#s)throw new Error(`Could not find a DataTable for id '${i}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");this.#i=this.#s.getElementsByClassName("c-table-data__async_modal_container").item(0),this.#a=this.#s.getElementsByClassName("c-table-data__async_message").item(0),this.#o=this.#a.getElementsByClassName("c-table-data__async_messageresponse").item(0),this.#e=e,this.#t={actionId:t,rowId:s},this.#r={},this.#s.addEventListener("keydown",(e=>this.navigateCellsWithArrowKeys(e)));const a=this.#n.getElementsByClassName("c-table-data__row-selector");for(let e=0;ethis.selectionChange()))}}registerAction(e,t,s,i){this.#r[e]={async:t,urlBuilder:s,urlTokens:i}}selectionChange(){this.#l(!this.#c())}#c(){const{urlBuilder:e}=this.#r[Object.keys(this.#r).at(0)],{urlTokens:t}=this.#r[Object.keys(this.#r).at(0)],s=t.values().next().value,i=this.collectSelectedRowIds();i.push(i[0]),e.writeParameter(s,i);try{e.getUrl().toString()}catch(e){return!1}return!0}#d(){const e=this.#s.querySelector("dialog.c-table-data__multiaction-warning");il.UI.modal.showModal(e,{},{id:e.id})}#l(e){this.#n.getElementsByClassName("c-table-data__row-selector").forEach((t=>{t.disabled=!0===e&&!t.checked}))}selectAll(e){const t=this.#n.getElementsByClassName("c-table-data__row-selector"),s=this.#n.getElementsByClassName("c-table-data__selection_all").item(0),i=this.#n.getElementsByClassName("c-table-data__selection_none").item(0);for(let s=0;s{e.checked&&t.push(e.value)})),t}doMultiAction(e){this.doAction(e,this.collectSelectedRowIds())}doSingleAction(e){const t=e.options[this.#t.rowId];this.doAction(e,[t])}doActionForAll(e){const t=e.parentNode.parentNode.parentNode,s=t.getElementsByClassName("close").item(0),i=t.getElementsByClassName("modal-body")[0].getElementsByTagName("select")[0].value;if(i in this.#r){const e=this.#t.actionId,t={options:{}};t.options[e]=i,s.click(),this.doAction(t,["ALL_OBJECTS"])}}doAction(e,t){const s=e.options[this.#t.actionId],i=this.#r[s],a=i.urlTokens.values().next().value;i.urlBuilder.writeParameter(a,t);const o=decodeURI(i.urlBuilder.getUrl().toString());i.async?this.asyncAction(o):window.location.href=o}asyncAction(e){this.#e.ajax({url:e,dataType:"html"}).done((e=>{if("SCRIPT"===this.#e(e).first().prop("tagName"))this.#e.globalEval(this.#e(e).first().text());else{let t;this.#e(e).first().hasClass("c-modal")?(this.#i.innerHTML=e,t=this.#i.firstChild):(this.#o.innerHTML=e,t=this.#a);this.#e(`
${e}
`).find("[data-replace-marker='script']").each(((e,t)=>this.#e.globalEval(t.innerHTML))),il.UI.modal.showModal(t,{},{id:t.id})}}))}navigateCellsWithArrowKeys(e){if(37!==e.which&&38!==e.which&&39!==e.which&&40!==e.which)return;const t=e.target.closest("td, th"),s=t.closest("tr");let{cellIndex:i}=t,{rowIndex:a}=s;switch(e.which){case 37:i-=1;break;case 39:i+=1;break;case 38:a-=1;break;case 40:a+=1}a<0||i<0||a>=this.#n.rows.length||i>=s.cells.length||this.focusCell(t,a,i)}focusCell(e,t,s){const i=this.#n.rows[t].cells[s];i.focus(),e.setAttribute("tabindex",-1),i.setAttribute("tabindex",0)}}class i{#s;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a PresentationTable for id '${e}'.`)}expandRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("collapsed"),t.classList.add("expanded")}collapseRow(e){const t=this.#s.querySelector(`#${e}`);t.classList.remove("expanded"),t.classList.add("collapsed")}toggleRow(e){this.#s.querySelector(`#${e}`).classList.contains("expanded")?this.collapseRow(e):this.expandRow(e)}expandAll(e){const t=this.#s.querySelectorAll(".il-table-presentation-row");e.options.expand?t.forEach((e=>this.expandRow(e.id))):t.forEach((e=>this.collapseRow(e.id)))}}class a{#s;#n;#h;#g;#w;#m;constructor(e){if(this.#s=document.getElementById(e),null===this.#s)throw new Error(`Could not find a OrderingTable for id '${e}'.`);if(this.#n=this.#s.getElementsByTagName("table").item(0),null===this.#n)throw new Error("There is no
in the component's HTML.");this.#p(),this.#h.forEach((e=>this.#u(e))),this.#y()}#y(){this.#n.querySelectorAll('input[type="number"]').forEach((e=>{e.addEventListener("keydown",(e=>{"Enter"===e.key&&e.preventDefault()}))}))}#p(){this.#h=Array.from(this.#n.rows),this.#h.shift(),this.#h.pop()}#u(e){e.addEventListener("dragstart",(e=>this.dragstart(e))),e.addEventListener("dragover",(e=>this.dragover(e))),e.addEventListener("dragend",(e=>this.dragend(e))),e.addEventListener("touchstart",(e=>this.touchstart(e))),e.addEventListener("touchmove",(e=>this.touchmove(e))),e.addEventListener("touchend",(e=>this.touchend(e))),e.addEventListener("touchcancel",(e=>this.touchend(e)))}dragstart(e){this.#s.classList.add("dragInProgress"),this.#g=e.target.closest("tr"),e.dataTransfer.clearData(),e.dataTransfer.setData("text/html",this.#g.outerHTML),e.dataTransfer.setData("text/plain",this.#g.textContent.replace(/[\n\r]+|[\s]{2,}/g," ").trim()),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--drag-image"),this.#w.style.top="-9999px",this.#s.appendChild(this.#w),e.dataTransfer.setDragImage(this.#w,0,0),this.#m=this.#g.cloneNode(!0),this.#m.addEventListener("dragover",(e=>this.dragover(e))),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#g.classList.add("c-table-data__row--drag-origin")}dragover(e){if(!this.#b())return;e.preventDefault(),e.dataTransfer.effectAllowed="copyMove";const t=e.target.closest("tr");t&&t!==this.#m&&(this.#h.indexOf(t)>this.#h.indexOf(this.#g)?t.after(this.#m):t.before(this.#m))}dragend(e){e.preventDefault(),this.#w&&this.#s.contains(this.#w)&&(this.#s.removeChild(this.#w),this.#w=null),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#g.classList.add("c-table-data__row--drag-settle"),this.#g.addEventListener("animationend",(()=>this.#R()),{once:!0}),this.#s.classList.remove("dragInProgress"),this.#p(),this.#f()}#R(){this.#g.classList.remove("c-table-data__row--drag-settle")}#b(){return this.#h.includes(this.#g)}touchstart(e){this.#g=e.target.closest("tr"),this.#m=this.#g.cloneNode(!0),this.#m.classList.add("c-table-data__row--placeholder"),Array.from(this.#m.getElementsByTagName("td")).forEach((e=>{e.innerHTML=""})),this.#w=this.#g.cloneNode(!0),this.#w.classList.add("c-table-data__row--touch-drag-image"),this.#s.appendChild(this.#w),this.#g.classList.add("c-table-data__row--drag-origin")}touchmove(e){e.preventDefault();const t=e.touches[0];this.#w.style.left=`${t.clientX+-50}px`,this.#w.style.top=`${t.clientY}px`;const s=document.elementFromPoint(t.clientX,t.clientY)?.closest("tr");s&&this.#h.includes(s)&&(this.#h.indexOf(s)>this.#h.indexOf(this.#g)?s.after(this.#m):s.before(this.#m)),t.clientY<100?this.#v(-8):t.clientY>window.innerHeight-100?this.#v(8):this.#E()}touchend(){this.#s.removeChild(this.#w),this.#m.replaceWith(this.#g),this.#g.classList.remove("c-table-data__row--drag-origin"),this.#p(),this.#f()}#f(){let e=10;this.#n.querySelectorAll('input[type="number"]').forEach((t=>{t.value=e,e+=10}))}#v(e){this.scrollInterval||(this.scrollInterval=setInterval((()=>{window.scrollBy(0,e)}),16))}#E(){this.scrollInterval&&(clearInterval(this.scrollInterval),this.scrollInterval=null)}}e.UI=e.UI||{},e.UI.table=e.UI.table||{},e.UI.table.data=new class{#e;#I=[];constructor(e){this.#e=e}init(e,t,i){if(void 0!==this.#I[e])throw new Error(`DataTable with id '${e}' has already been initialized.`);this.#I[e]=new s(this.#e,t,i,e)}get(e){return this.#I[e]??null}}(t),e.UI.table.presentation=new class{#I=[];init(e){if(void 0!==this.#I[e])throw new Error(`PresentationTable with input-id '${e}' has already been initialized.`);this.#I[e]=new i(e)}get(e){return this.#I[e]??null}},e.UI.table.ordering=new class{#I=[];init(e){if(void 0!==this.#I[e])throw new Error(`OrderingTable with id '${e}' has already been initialized.`);this.#I[e]=new a(e)}get(e){return this.#I[e]??null}}}(il,$); diff --git a/components/ILIAS/UI/resources/js/Table/src/orderingtable.class.js b/components/ILIAS/UI/resources/js/Table/src/orderingtable.class.js index 61ba0a0a7ce8..846814a0fbff 100644 --- a/components/ILIAS/UI/resources/js/Table/src/orderingtable.class.js +++ b/components/ILIAS/UI/resources/js/Table/src/orderingtable.class.js @@ -70,6 +70,17 @@ export default class OrderingTable { } this.#indexRows(); this.#rows.forEach((row) => this.#addDraglisteners(row)); + this.#initInputHandling(); + } + + #initInputHandling() { + this.#table.querySelectorAll('input[type="number"]').forEach((input) => { + input.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + } + }); + }); } #indexRows() { diff --git a/components/ILIAS/UI/resources/ui-examples/images/Image/mountains_widescreen-thumbnail.jpg b/components/ILIAS/UI/resources/ui-examples/images/Image/mountains_widescreen-thumbnail.jpg new file mode 100644 index 000000000000..c62994e2ddab Binary files /dev/null and b/components/ILIAS/UI/resources/ui-examples/images/Image/mountains_widescreen-thumbnail.jpg differ diff --git a/components/ILIAS/UI/resources/ui-examples/images/Image/sanfrancisco_widescreen-thumbnail.jpg b/components/ILIAS/UI/resources/ui-examples/images/Image/sanfrancisco_widescreen-thumbnail.jpg new file mode 100644 index 000000000000..06bb7428bbc2 Binary files /dev/null and b/components/ILIAS/UI/resources/ui-examples/images/Image/sanfrancisco_widescreen-thumbnail.jpg differ diff --git a/components/ILIAS/UI/resources/ui-examples/images/Image/ski_widescreen-thumbnail.jpg b/components/ILIAS/UI/resources/ui-examples/images/Image/ski_widescreen-thumbnail.jpg new file mode 100644 index 000000000000..8f31cce2aa87 Binary files /dev/null and b/components/ILIAS/UI/resources/ui-examples/images/Image/ski_widescreen-thumbnail.jpg differ diff --git a/components/ILIAS/UI/src/Component/Entity/Entity.php b/components/ILIAS/UI/src/Component/Entity/Entity.php index 1fd4b1140b26..1ed2beaef8d5 100755 --- a/components/ILIAS/UI/src/Component/Entity/Entity.php +++ b/components/ILIAS/UI/src/Component/Entity/Entity.php @@ -21,14 +21,14 @@ namespace ILIAS\UI\Component\Entity; use ILIAS\UI\Component\Component; -use ILIAS\UI\Component\Image\Image; -use ILIAS\UI\Component\Symbol\Symbol; use ILIAS\UI\Component\Symbol\Glyph\Glyph; +use ILIAS\UI\Component\Button\Standard as StandardButton; use ILIAS\UI\Component\Button\Shy; use ILIAS\UI\Component\Button\Tag; use ILIAS\UI\Component\Legacy\Content; use ILIAS\UI\Component\Listing\Property as PropertyListing; use ILIAS\UI\Component\Link\Standard as StandardLink; +use ILIAS\UI\Component\Listing\Workflow; /** * This describes an Entity @@ -70,15 +70,14 @@ public function withMainDetails( * Another way of distinguishing Reactions might be the availability/significance * for everybody in contrast to the current user (e.g. rating vs. my favorite) */ - public function withPrioritizedReactions(Glyph | Tag ...$prio_reactions): self; - + public function withPrioritizedReactions(Glyph | Tag | StandardButton | Shy ...$prio_reactions): self; //Further Areas /** * Reactions that are less prominent than Prioritized Reactions go here. */ - public function withReactions(Glyph | Tag ...$reactions): self; + public function withReactions(Glyph | Tag | Shy | StandardButton ...$reactions): self; /** * Properties that could potentially limit a users access to the object @@ -98,8 +97,13 @@ public function withDetails( ): self; /** - * Actions are the things you can actually _do_ with the entity, - * e.g. in context of repository items: view, copy, delete, etc. + * ManagingActions are the things an owner or admin can actually do _with_ the entity, + * e.g. in context of repository items: view, copy, delete, set online etc. + */ + public function withManagingActions(Shy ...$managing_actions): static; + + /** + * @deprecated for semantic reasons, "actions" is not precise enough. */ public function withActions(Shy ...$actions): self; @@ -111,4 +115,11 @@ public function withActions(Shy ...$actions): self; public function withPersonalStatus( PropertyListing | Content ...$personal_status ): self; + + /** + * This Workflow is used to create buttons on the entity. + * Only Workflow Steps which are AVAILABLE and either NOT_STARTED or IN_PROGRESS + * will be rendered as buttons. + */ + public function withWorkflow(Workflow\Linear $workflow): static; } diff --git a/components/ILIAS/UI/src/Component/Listing/Entity/Factory.php b/components/ILIAS/UI/src/Component/Listing/Entity/Factory.php index 86f9db97115c..ce6f9930ebfa 100755 --- a/components/ILIAS/UI/src/Component/Listing/Entity/Factory.php +++ b/components/ILIAS/UI/src/Component/Listing/Entity/Factory.php @@ -29,11 +29,36 @@ interface Factory * --- * description: * purpose: > - * The Entity Listing yields uniform Entities according to a consumer - * defined concept and lists them one after the other. + * The Entity Listing yields uniform Entities according to a consumer + * defined concept and lists them one after the other. + * composition: > + * Entities are stacked one after the other. On very large screens the layout will have multiple columns to use + * the space optimally. The design of the entity is one that favors a more horizontal representation. * * --- + * @param \ILIAS\UI\Component\Listing\Entity\RecordToEntity $entity_mapping * @return \ILIAS\UI\Component\Listing\Entity\Standard */ public function standard(RecordToEntity $entity_mapping): Standard; + + /** + * --- + * description: + * purpose: > + * The Entity Listing yields uniform Entities according to a consumer + * defined concept and lists them in a grid. + * composition: + * Shows a grid of many entities in a card-style design. Images, Symbols and other secondary identifiers are + * stacked to favor a vertical representation. + * rules: + * usage: + * 1: > + * If you want all entity secondary identifier images to take on the same height, you must provide images + * with the same height. + * + * --- + * @param \ILIAS\UI\Component\Listing\Entity\RecordToEntity $entity_mapping + * @return \ILIAS\UI\Component\Listing\Entity\Grid + */ + public function grid(RecordToEntity $entity_mapping): Grid; } diff --git a/components/ILIAS/UI/src/Component/Listing/Entity/Grid.php b/components/ILIAS/UI/src/Component/Listing/Entity/Grid.php new file mode 100644 index 000000000000..b9e060d93529 --- /dev/null +++ b/components/ILIAS/UI/src/Component/Listing/Entity/Grid.php @@ -0,0 +1,25 @@ + + * Inline Lists are used to display a set of elements next to each other when the available + * space allows for it. The elements belong to a group of similar items and have about equal + * relevance. + * composition: > + * Inline Lists string up the items horizontally breaking into the next line if necessary. + * They are separated by a comma. + * rivals: + * Unordered List, Ordered Listing: > + * If there is enough space for a vertical list, Unordered and Ordered Listing should + * be preferred. Line by line items are better suited when the user is expected to be + * exploring or engaging with the list for longer than a casual glance. + * Property Listing: > + * To display key-value pairs in a row, use the Property Listing. + * + * context: + * - Inline Listings can be used as values in a Property Listing. + * + * rules: + * usage: + * - You MUST use the Inline Listing only when another component around it gives it a + * context or headline clarifying what is being listed. + * - You MUST only add items belonging to the same group or type. + * - The Inline Listing MAY be the value of a property listing item. + * - You MUST NOT use this component as a layout tool to force unrelated components next + * to each other. + * - You MAY change the comma delimiter in your component using CSS. + * ---- + * @param array $items + * @return \ILIAS\UI\Component\Listing\Inline + */ + public function inline(array $items): Inline; + /** * --- * description: @@ -160,16 +199,38 @@ public function entity(): Entity\Factory; * Entries are listed as label/value pair in one line. * Since the focus is strongly on the value, which might be * self-explaining, visibility of the label is optional. - * The value is a string, or one or several Symbols, Links or Legacy Components. + * The label is a string. A Symbol may be shown in its place. + * The value is a string, Links or Legacy Components. + * A Symbol may be shown as the value. + * Very long value strings will turn into a truncated paragraph + * with a clickable Show more/less toggle. * rivals: * Characteristic Value: > - * In Charakteristic Values, label/value pairs are displayed in a + * In Characteristic Values, label/value pairs are displayed in a * tabular way; labels cannot be omitted for display. * Descriptive: > * The Descriptive's (visual) emphasis is on the key, not the value. + * * context: - * - Property Listing is used in Entities + * - Property Listing is used in Entities * + * rules: + * usage: + * - You MUST NOT use html code as a value string as it may get truncated in + * unexpected ways. + * - With more than 6 properties, you SHOULD use multiple Property Listing's + * to segment properties into multiple visual groups/lines. Each new + * property component starts a new line. + * - You SHOULD use properties with short values (e.g. not full paragraphs). + * You SHOULD split off long properties into their own Property component so + * it will always start a new line. + * - When using a Symbol as a label and/or value, the chosen icon + * MUST be self-explanatory and easily understood by users. + * - When using a Symbol as a label, it SHOULD not have an action. + * accessibility: + * - When using a Symbol, you still MUST enter a label with a text that can + * be understood when read through a screen reader independently of any + * visuals. This label is passed onto the Symbol as the aria-label. * ---- * @return \ILIAS\UI\Component\Listing\Property */ diff --git a/components/ILIAS/UI/src/Component/Listing/Inline.php b/components/ILIAS/UI/src/Component/Listing/Inline.php new file mode 100644 index 000000000000..d38ebcc21786 --- /dev/null +++ b/components/ILIAS/UI/src/Component/Listing/Inline.php @@ -0,0 +1,26 @@ + * The Settings Glyph symbolizes opening a dropdown that allows to edit settings of the displayed block. * composition: > - * The Settings Glyph uses the glyphicon-cog. + * The Settings Glyph uses the CSS class glyphicon-cog. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking triggers the opening of a settings Dropdown. * @@ -55,6 +56,8 @@ public function settings(): Glyph; * some neighbouring Container Collection, such as the content of a Dropdown or an Accordion currently shown. * composition: > * The Collapse Glyph is composed of a triangle pointing to the bottom indicating that content is currently shown. + * It uses the CSS class glyphicon-triangle-bottom. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking hides the display of some Container Collection. * rivals: @@ -82,6 +85,8 @@ public function collapse(): Glyph; * some neighbouring Container Collection, such as the content of a Dropdown or an Accordion currently shown. * composition: > * The Expand Glyph is composed of a triangle pointing to the right indicating that content is currently collapsed. + * It uses the CSS class glyphicon-triangle-up. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking displays some Container Collection. * rivals: @@ -108,7 +113,8 @@ public function expand(): Glyph; * The Add Glyph serves as a replacement for the respective textual * button in very crowded screens. It allows adding a new item. * composition: > - * The Add Glyph uses the glyphicon-plus-sign. + * The Add Glyph uses the CSS class glyphicon-plus-sign. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking adds a new input to a form or an event to the calendar. * @@ -143,7 +149,8 @@ public function add(): Glyph; * The Remove Glyph serves as a replacement for the respective textual * button in very crowded screens. It allows removing an item. * composition: > - * The Remove Glyph uses the glyphicon-minus-sign. + * The Remove Glyph uses the CSS class glyphicon-minus-sign. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking deletes an existing input from a form. * @@ -176,8 +183,10 @@ public function remove(): Glyph; * The Up Glyph allows for manually arranging rows in tables embedded in forms. * It allows moving an item up. * composition: > - * The Up Glyph uses the glyphicon-circle-arrow-up. The Up Glyph - * can be combined with the Add/Remove Glyph. + * The Up Glyph uses the CSS class glyphicon-circle-arrow-up. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). + * The Up Glyph can be combined with the Add/Remove Glyph. * effect: > * When placed in a Button or Link, clicking moves an item up. * @@ -212,7 +221,9 @@ public function up(): Glyph; * The Down Glyph allows for manually arranging rows in tables embedded in forms. * It allows moving an item down. * composition: > - * The Down Glyph uses the glyphicon-circle-arrow-down. The Down Glyph + * The Down Glyph uses the CSS class glyphicon-circle-arrow-down. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). The Down Glyph * can be combined with the Add/Remove Glyph. * effect: > * When placed in a Button or Link, clicking moves an item down. @@ -247,7 +258,9 @@ public function down(): Glyph; * purpose: > * The Back Glyph indicates a possible change of the view. The view change leads back to some previous view. * composition: > - * The chevron-left glyphicon is used. + * The Back Glyph uses the CSS class glyphicon-chevron-left. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * The click on a Back Glyph leads back to a previous view. * @@ -277,7 +290,9 @@ public function back(): Glyph; * purpose: > * The Next Glyph indicates a possible change of the view. The view change leads back to some previous view. * composition: > - * The chevron-right glyphicon is used. + * The Next Glyph uses the css-class glyphicon-chevron-right. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * The click on a Next Glyph opens a new view. * context: @@ -308,6 +323,8 @@ public function next(): Glyph; * Only one Glyph is shown at a time. When placed in a Button or Link, clicking reverses the sorting direction. * composition: > * The Sort Ascending Glyph uses glyphicon-arrow-up. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking reverses the direction of ordering in a table. * @@ -327,7 +344,9 @@ public function sortAscending(): Glyph; * The Sorting Glyphs indicate the current sorting direction of a column in a table as ascending (up) or descending (down). * Only one Glyph is shown at a time. When placed in a Button or Link, clicking reverses the sorting direction. * composition: > - * The Sort Descending Glyph uses glyphicon-arrow-descending. + * The Sort Descending Glyph uses the CSS class glyphicon-arrow-descending. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking reverses the direction of ordering in a table. * @@ -346,7 +365,8 @@ public function sortDescending(): Glyph; * purpose: > * The Briefcase Glyph symbolizes some ongoing work that is done. It was introduced for the background tasks. * composition: > - * The Briefcase Glyph uses glyphicon-briefcase. + * The Briefcase Glyph uses the CSS class glyphicon-briefcase. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * A click on the Briefcase Glyph opens a popup that shows the background tasks. * @@ -366,7 +386,8 @@ public function briefcase(): Glyph; * The User Glyph symbolizes the “Who is online?” Popover in the Top Navigation. * The User Glyph indicates the number of pending contact requests and users online via the the Novelty Counter and Status Counter respectively. * composition: > - * The User Glyph uses the glyphicon-user. + * The User Glyph uses the CSS class glyphicon-user. + * The glyph's design is rendered using the il-icons font which was based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking opens the “Who is online?” Popover. * @@ -386,7 +407,8 @@ public function user(): Glyph; * purpose: > * The Mail Glyph provides a shortcut to the mail service. The Mail Glyph indicates the number of new mails received. * composition: > - * The Mail Glyph uses the glyphicon-envelope. + * The Mail Glyph uses the CSS class glyphicon-envelope. + * The glyph's design is rendered using the il-icons font which was based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking transfers the user to the full-screen mail service. * rivals: @@ -411,6 +433,8 @@ public function mail(): Glyph; * composition: > * If used to toggle the notifications at an individual object, the Notification Glyph uses link-color to * indicate inactivity and the brand-warning color to indicate activity. + * It uses the CSS class glyphicon-bell. + * The glyph's design is rendered using the il-icons font which was based on the simplelineicons font. * * rules: * accessibility: @@ -427,7 +451,9 @@ public function notification(): Glyph; * purpose: > * The Tag Glyph is used to indicate the possibility of adding tags to an object. * composition: > - * The Tag Glyph uses the glyphicon-tag. + * The Tag Glyph uses the CSS class glyphicon-tag. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking opens the Round Trip Modal to add new Tags. * @@ -449,7 +475,9 @@ public function tag(): Glyph; * purpose: > * The Note Glyph is used to indicate the possibility of adding notes to an object. * composition: > - * The Note Glyph uses the glyphicon-pushpin. + * The Note Glyph uses the CSS class glyphicon-pushpin. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking opens the Round Trip Modal to add new notes. * @@ -471,7 +499,9 @@ public function note(): Glyph; * purpose: > * The Comment Glyph is used to indicate the possibility of adding comments to an object. * composition: > - * The Comment Glyph uses the glyphicon-comment. + * The Comment Glyph uses the CSS class glyphicon-comment. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking opens the Round Trip Modal to add new comments. * @@ -494,6 +524,7 @@ public function comment(): Glyph; * The Like Glyph symbolizes a user approving an item, e.g. a posting. * composition: > * The Like Glyph uses the "thumbs up" unicode emoji U+1F44D, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The glyph rendered is from the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Like Glyph acts as a toggle: A first click adds a Like to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Like away, which is also reflected in colour and counter. * @@ -519,6 +550,7 @@ public function like(): Glyph; * The Love Glyph symbolizes a user adoring an item, e.g. a posting. * composition: > * The Love Glyph uses the "red heart" unicode emoji U+2764, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The glyph rendered is from the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Love Glyph acts as a toggle: A first click adds a Love to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Love away, which is also reflected in colour and counter. * @@ -544,6 +576,7 @@ public function love(): Glyph; * The Dislike Glyph symbolizes a user disapproving an item, e.g. a posting. * composition: > * The Dislike Glyph uses the "thumbs down" unicode emoji U+1F44E, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The glyph rendered is from the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Dislike Glyph acts as a toggle: A first click adds a Dislike to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Dislike away, which is also reflected in colour and counter. * @@ -569,6 +602,7 @@ public function dislike(): Glyph; * The Laugh Glyph symbolizes a user finding an item hilarious, e.g. a posting. * composition: > * The Laugh Glyph uses the "grinning face with smiling eyes" unicode emoji U+1F604, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The glyph rendered is from the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Laugh Glyph acts as a toggle: A first click adds a Laugh to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Laugh away, which is also reflected in colour and counter. * @@ -594,6 +628,7 @@ public function laugh(): Glyph; * The Astounded Glyph symbolizes a user finding an item surprising, e.g. a posting. * composition: > * The Astounded Glyph uses the "face with open mouth" unicode emoji U+1F62E, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The design rendered is from the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Astounded Glyph acts as a toggle: A first click adds an Astounded to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Astounded away, which is also reflected in colour and counter. * @@ -619,6 +654,7 @@ public function astounded(): Glyph; * The Sad Glyph symbolizes a user finding an item disconcerting, e.g. a posting. * composition: > * The Sad Glyph uses the "sad but relieved face" unicode emoji U+1F625, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The design presented is through the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Sad Glyph acts as a toggle: A first click adds a Sad to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Sad away, which is also reflected in colour and counter. * @@ -644,6 +680,7 @@ public function sad(): Glyph; * The Angry Glyph symbolizes a user finding an item outraging, e.g. a posting. * composition: > * The Angry Glyph uses the "angry face" unicode emoji U+1F620, see https://unicode.org/emoji/charts/full-emoji-list.html. + * The design presented is through the Open Sans Emoji font. * effect: > * When placed in a Button or Link, the Angry Glyph acts as a toggle: A first click adds an Angry to the respective item, which is reflected in the colour of the Glyph and in the counter. A second click takes the Angry away, which is also reflected in colour and counter. * @@ -669,7 +706,9 @@ public function angry(): Glyph; * The Eye Closed Glyph is used to toggle the revelation-mode of password fields. * With the Eye Closed Glyph shown, the field is currently unmasked. * composition: > - * The Eye Closed Glyph uses the glyphicon-eye-close. + * The Eye Closed Glyph uses the CSS class glyphicon-eye-close. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When clicked, the password-field is masked, thus hiding the input. * @@ -695,7 +734,9 @@ public function eyeclosed(): Glyph; * The Eye Open Glyph is used to toggle the revelation-mode of password fields. * With the Eye Open Glyph shown, the field is currently masked. * composition: > - * The Eye Open Glyph uses the glyphicon-eye-open. + * The Eye Open Glyph uses the CSS class glyphicon-eye-open. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When clicked, the password-field is unmasked, thus revealing the input. * @@ -720,7 +761,8 @@ public function eyeopen(): Glyph; * purpose: > * The Attachment Glyph indicates that a file is attached or can be attached to an object or entity. * composition: > - * The Attachment Glyph uses the glyphicon-paperclip. + * The Attachment Glyph uses the CSS class glyphicon-paperclip. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking executes an action which delivers these attachments to the actor OR initiates a process to add new attachments. * context: @@ -744,7 +786,8 @@ public function attachment(): Glyph; * The Reset Glyph is used to indicate the possibilty of resetting changes made by the user * within a control back to a previous state. * composition: > - * The Reset Glyph uses the glyphicon-repeat. + * The Reset Glyph uses the CSS class glyphicon-repeat. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking reloads the related control immediately and goes back to state * before the user changes. @@ -777,7 +820,8 @@ public function reset(): Glyph; * The Apply Glyph is used to indicate the possibilty of applying changes which the user has made * within a control, i.e. a filter. * composition: > - * The Apply Glyph uses the glyphicon-ok. + * The Apply Glyph uses the CSS class glyphicon-ok. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking reloads the page immediately with the updated content reflected in the control. In case of * a filter, it means that the entries in a table change in accordance with the filter values set by the user. @@ -809,7 +853,8 @@ public function apply(): Glyph; * purpose: > * The Search Glyph is used to trigger a search dialog. * composition: > - * The Search Glyph uses the glyphicon-search. + * The Search Glyph uses the CSS class glyphicon-search. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking opens a search dialog. * Since the context for the Search Glyph primarily is the Meta Bar, @@ -833,7 +878,8 @@ public function search(): Glyph; * purpose: > * The Help Glyph opens a context-sensitive help screen. * composition: > - * The Help Glyph uses the glyphicon-question-sign. + * The Help Glyph uses the CSS class glyphicon-question-sign. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When clicked, the user is provided with explanations or * instructions for the usage of the current context. @@ -858,7 +904,8 @@ public function help(): Glyph; * purpose: > * The Calendar glyph is used to symbolize date-related actions or alerts. * composition: > - * The Calendar Glyph uses the glyphicon-calendar. + * The Calendar Glyph uses the CSS class glyphicon-calendar. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking usually opens a date-picker. * @@ -878,9 +925,11 @@ public function calendar(): Glyph; * --- * description: * purpose: > - * The Time Glyph is used to symbolize time-related actions or alerts. + * The Time Glyph is used to symbolize time-related actions or alerts. * composition: > - * The Time Glyph uses the glyphicon-time. + * The Time Glyph uses the CSS class glyphicon-time. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking usually opens a time-picker. * @@ -903,7 +952,8 @@ public function time(): Glyph; * The Close Glyph is used to symbolize an action that closes something * or leaves a previously initiated context. * composition: > - * The Close Glyph uses the glyphicon-remove. + * The Close Glyph uses the CSS class glyphicon-remove. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking closes an overlay or changes the view. * @@ -925,12 +975,13 @@ public function close(): Glyph; * The More glyph offers viewing the rest of the shortened set of * entries so that the entire set becomes visible. * composition: > - * The More Glyph uses the glyphicon-option-horizontal. + * The More Glyph uses the CSS class glyphicon-option-horizontal. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking shows the rest of the set of entries. * rivals: * Disclosure Glyph: > - * The Disclosure Glyph hides the complete set of entries, wherear the + * The Disclosure Glyph hides the complete set of entries, whereas the * More Glyph only hides parts of it. * Mini Action Dropdown: > * The Dropdown in the ListGUI without text is used to offer a @@ -981,7 +1032,8 @@ public function more(): Glyph; * are too long to be presented fully or would be overwhelming. * The Disclosure Glyphs offers viewing the entirety of the hidden set of entries. * composition: > - * The Disclosure Glyph uses the glyphicon-option-vertical. + * The Disclosure Glyph uses the CSS class glyphicon-option-vertical. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking shows the entire set of entries. * rivals: @@ -1035,7 +1087,8 @@ public function disclosure(): Glyph; * The Language Glyph is used to indicate the option to switch languages * by some shorthand workflow without navigating to the personal settings. * composition: > - * The Language Glyph uses the glyphicon-lang from the il-icons set. + * The Language Glyph uses the CSS class glyphicon-lang. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When clicked, the user is shown a set of active languages to choose from. * rivals: @@ -1065,7 +1118,8 @@ public function language(): Glyph; * The Login Glyph is used to trigger the login interaction. * It is displayed in the Meta Bar of the user is not yet logged in. * composition: > - * The Login Glyph uses the login glyph from the il-icons font. + * The Login Glyph uses the CSS class glyphicon-login. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking triggers the interaction to authenticate and login. * rivals: @@ -1094,7 +1148,8 @@ public function login(): Glyph; * The Logout Glyph is used to trigger the logout interaction. * It is displayed in the Slate triggered by clicking on the User Avatar in the Meta Bar. * composition: > - * The Logout Glyph uses the logout glyph from the il-icons font. + * The Logout Glyph uses the CSS class glyphicon-logout. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking triggers the interaction to logout. * rivals: @@ -1121,7 +1176,8 @@ public function logout(): Glyph; * The Bullet List Glyph is used to indicate the possibility to group related content together * and organize vertically, when you don’t need to convey a specific order for list items. * composition: > - * The Bullet List Glyph uses the glyphicon-listbullet. + * The Bullet List Glyph uses the CSS class glyphicon-listbullet. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking groups a list of entries with bullet points. * rivals: @@ -1147,7 +1203,8 @@ public function bulletlist(): Glyph; * and organize vertically, where you need to convey a priority, hierarchy, * or sequence between list items. * composition: > - * The Numbered List Glyph uses the glyphicon-listnumbered. + * The Numbered List Glyph uses the CSS class glyphicon-listnumbered. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking groups a list of entries with enumeration number. * rivals: @@ -1175,7 +1232,8 @@ public function numberedlist(): Glyph; * It leads to an increased indentation and thus gives the impression of a * subordinate level. * composition: > - * The Indent List Glyph uses the glyphicon-listindent. + * The Indent List Glyph uses the CSS class glyphicon-listindent. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking indents the content to the next subordinate level of the list. * rivals: @@ -1200,7 +1258,8 @@ public function listindent(): Glyph; * The Outdent Glyph is used to define the gradation of a structured list. * It leads to a decreased indentation and thus gives the impression of a superordinate level. * composition: > - * The Outdent List Glyph uses the glyphicon-listoutdent. + * The Outdent List Glyph uses the CSS class glyphicon-listoutdent. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking outdents the content to the next superordinate level of the list. * rivals: @@ -1224,7 +1283,8 @@ public function listoutdent(): Glyph; * purpose: > * The Filter Glyph is used to trigger a filter action. * composition: > - * The Filter Glyph uses the glyphicon-filter. + * The Filter Glyph uses the CSS class glyphicon-filter. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking filters a list of entries. * rivals: @@ -1253,6 +1313,7 @@ public function filter(): Glyph; * indicated by a left-triangle than by a down-triangle. * composition: > * The Collapse Horizontal Glyph is composed of a triangle pointing to the left. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When placed in a Button or Link, clicking hides the display of some Container Collection. * It might simultaneously trigger the display of another Container Collection. @@ -1282,6 +1343,8 @@ public function collapseHorizontal(): Glyph; * transforms some text from or into a heading. * composition: > * The Heading Glyph is composed of the letter H. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking may insert or transform some text into a heading. * rivals: @@ -1309,6 +1372,8 @@ public function header(): Glyph; * transforms some text from or into cursive one. * composition: > * The Italic Glyph is composed of the letter I. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking may insert or transform some text into cursive one. * rivals: @@ -1336,6 +1401,8 @@ public function italic(): Glyph; * transforms some text from or into bold one. * composition: > * The Bold Glyph is composed of the letter B. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking may insert or transform some text into bold one. * rivals: @@ -1364,6 +1431,9 @@ public function bold(): Glyph; * composition: > * The Link Glyph is composed out of two linked chain-pieces that ilustrate the official * URL symbol. + * It uses the CSS class glyphicon-link. + * The glyph's design is rendered using the Glyphicons-Halflings font which + * originated from Bootstrap 3 (deprecated symbol source). * effect: > * When placed in a Button or Link, clicking may insert or transform some text into a link. * rivals: @@ -1390,7 +1460,8 @@ public function link(): Glyph; * The Launch Glyph indicates a process to start, e.g. subscribing to a * Course or triggering a SCORM Module. * composition: > - * The Launch Glyph uses the glyphicon plane. + * The Launch Glyph uses the CSS-class glyphicon-plane. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking will immediately start or continue the process; this * may manifest as a Modal to open or the redirection to the appropriate Page. @@ -1414,7 +1485,8 @@ public function launch(): Glyph; * purpose: > * The Enlarge glyph indicates the possibility of enlarging the content to see more details or to improve the display. * composition: > - * The Enlarge Glyph uses the glyphicon-enlarge. + * The Enlarge Glyph uses the CSS class glyphicon-enlarge. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking triggers an interaction that displays an enlarged version of the content just seen. * This can be a modal with an enlarged display of an image. @@ -1440,7 +1512,8 @@ public function enlarge(): Glyph; * The List View Glyph displays data stacked on top of each other in a list. * The glyph is suitable for views that are read from top to bottom and where the focus is on text. * composition: > - * The List View Glyph uses the glyphicon-ListView. + * The List View Glyph uses the CSS class glyphicon-listView. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When placed in a Button or Link, clicking displays the collection of data as a list. * rivals: @@ -1464,7 +1537,8 @@ public function listView(): Glyph; * The Preview Glyph indicates the possibility to display a preview or a short preview of a * content before the user performs a final action. * composition: > - * The Preview Glyph uses the glyphicon-preview. + * The Preview Glyph uses the CSS class glyphicon-preview. + * The glyph's design is rendered using the il-icons font and is based on the simplelineicons font. * effect: > * When a user clicks on the "Preview" icon, a preview of the content is displayed without a permanent * change or a larger display. This can be a modal with several pages of a file preview. @@ -1488,7 +1562,8 @@ public function preview(): Glyph; * purpose: > * The Sort Glyph indicates the possibility of changing the order of elements within a list, table or other structured data. * composition: > - * The Sort Glyph uses the glyphicon-sort. + * The Sort Glyph uses the CSS class glyphicon-sort. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When a user clicks on the "Sort" icon, all possible sorting options are displayed. * The elements will be reordered based on a specific criterion, such as alphabet, date or size. @@ -1511,7 +1586,8 @@ public function sort(): Glyph; * purpose: > * The Column Selection Glyph shows the option of displaying or hiding columns in a table. * composition: > - * The Column Selection Glyph uses the glyphicon-columnselection. + * The Column Selection Glyph uses the CSS class glyphicon-columnselection. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * If a user clicks on the Colum Selection symbol, an overview is displayed showing which columns are * already visible and which are hidden. @@ -1533,7 +1609,8 @@ public function columnSelection(): Glyph; * The Tile View Glyph displays data in cells arrayed in vertical and horizontal layouts. * The glyph works well for collections that are read from side-to-side and where images are the main focus. * composition: > - * The Tile View Glyph uses the glyphicon-TileView. + * The Tile View Glyph uses the CSS class glyphicon-TileView. + * The glyph's design is rendered using the il-icons font and was created by the community. * effect: > * When you click on the glyph, the displayed data is shown in a grid view. * rivals: @@ -1562,6 +1639,8 @@ public function tileView(): Glyph; * The glyph works best when there is a background or border indicating the dimension of the element that is * draggable. * composition: > + * The Drag Handle Glyph uses the CSS class glyphicon-dragHandle. + * The glyph's design is rendered using the il-icons font and was created by the community. * The cells of the Ordering Table use this glyph. * effect: > * When you click and hold on the glyph, the item it is on can be dragged and dropped. @@ -1569,7 +1648,7 @@ public function tileView(): Glyph; * No glyph: > * In some instances the design and context of an element might already sufficiently indicate that it can * be dragged. However, if an element could be confused with a non-draggable counterpart or is draggable - * only some of the time, you SHOULD use the glyph to indicate when it is draggable or otherwise change the + * only some of the time, you SHOULD use the glyph to indicate when it is draggable. or otherwise change the * appearance to communicate the drag and drop functionality. * context: * - The Drag Glyph communicates the drag and drop feature on the Ordering Table cells. @@ -1631,4 +1710,125 @@ public function checked(): Glyph; * @return \ILIAS\UI\Component\Symbol\Glyph\Glyph */ public function unchecked(): Glyph; + + + /** + * --- + * description: + * purpose: > + * The presenter glyph represents the individual or organization hosting or offering + * a piece of content. On a button, it indicates that the name of one or more + * presenters can be edited, or it can set a corresponding role for a user. + * As a link it may lead to the list of all content featuring this presenter. + * composition: > + * The presenter glyph uses the CSS class glyphicon-presenter. + * The glyph's design is rendered using the il-icons font and was created by the community. + * effect: > + * As part of a button, it opens an input to define the user who is presenting some content. + * It can also be used to apply the presenter role to a user or filter for a specific presenter. + * rivals: + * User: > + * If the referenced entity is not clearly a person or institution tasked with presenting, + * hosting or creating content, you might want to use the more general user glyph instead. + * Owner: > + * Consider choosing the owner glyph to represent entities and roles managing an object + * instead of being the creators or face of a piece of content + * context: + * - The presenter glyph MAY appear with other object actions or metadata properties. + * - It also MAY be one of multiple options for the role of a user. + * rules: + * accessibility: + * 1: > + * The aria-label MUST be 'Presenter'. + * --- + * @param string|null $action + * @return \ILIAS\UI\Component\Symbol\Glyph\Glyph + */ + public function presenter(): Glyph; + + /** + * --- + * description: + * purpose: > + * The owner glyph represents the individual responsible for managing a piece of content. + * On a button, it indicates that the name of one or more owners can be edited, or it can set + * a corresponding role for a user. + * composition: > + * The owner glyph uses the CSS class glyphicon-owner. + * The glyph's design is rendered using the il-icons font and was created by the community. + * effect: > + * As part of a button, it opens an input to define the owner of some content. + * It can also be used to set the owner of an object or other access roles. + * rivals: + * User: > + * If the referenced entity is not clearly a person or institution managing or being in some + * other way responsible for it, you might want to use the more general user glyph instead. + * context: + * - The owner glyph MAY appear with other object actions or metadata properties. + * - It also may be one of multiple options for the role of a user. + * rules: + * accessibility: + * 1: > + * The aria-label MUST be 'Owner'. + * --- + * @param string|null $action + * @return \ILIAS\UI\Component\Symbol\Glyph\Glyph + */ + public function owner(): Glyph; + + /** + * --- + * description: + * purpose: > + * The date glyph indicates a single specific date e.g. on a button opening a date picker + * or switching a view to the current date. + * composition: > + * The date glyph uses the CSS class glyphicon-date. + * The glyph's design is rendered using the il-icons font and was created by the community. + * effect: > + * In a form, it opens a date picker. In a calendar view it switches to the current day. + * rivals: + * Calendar: > + * There is a calendar glyph more suitable for symbolizing a calendar view. + * context: + * - The date glyph may be part of a date picker + * - As part of some View Controls, it switches to the current date. + * rules: + * usage: + * 1: > + * The date glyph MUST always refer to a single date, not a range. + * accessibility: + * 1: > + * The aria-label MUST be 'Date'. + * --- + * @param string|null $action + * @return \ILIAS\UI\Component\Symbol\Glyph\Glyph + */ + public function date(): Glyph; + + /** + * --- + * description: + * purpose: > + * The location glyph indicates postal addresses, specific buildings, rooms, or geo-coordinates. + * composition: > + * The location glyph uses the CSS class glyphicon-owner. + * The glyph's design is rendered using the il-icons font and was created by the community. + * effect: > + * As part of a button, it opens a dropdown of preset locations or modal with a searchable map. + * It can also be used in filters or meta-data properties to filter for a specific location. + * rivals: + * Mail: > + * Use the mail glyph when referring to digital addresses in connection to the Mail Service + * context: + * - It may appear in combination with maps, location booking and similar services + * rules: + * accessibility: + * 1: > + * The aria-label MUST be 'Location'. + * --- + * @param string|null $action + * @return \ILIAS\UI\Component\Symbol\Glyph\Glyph + */ + public function location(): Glyph; } diff --git a/components/ILIAS/UI/src/Component/Symbol/Glyph/Glyph.php b/components/ILIAS/UI/src/Component/Symbol/Glyph/Glyph.php index 40bc0fe6b384..0bdce5618dd9 100755 --- a/components/ILIAS/UI/src/Component/Symbol/Glyph/Glyph.php +++ b/components/ILIAS/UI/src/Component/Symbol/Glyph/Glyph.php @@ -86,6 +86,15 @@ interface Glyph extends Symbol public const DRAG_HANDLE = "dragHandle"; public const CHECKED = "checked"; public const UNCHECKED = "unchecked"; + public const PRESENTER = "presenter"; + public const OWNER = "owner"; + public const DATE = "date"; + public const LOCATION = "location"; + + /** + * Override the default label text with a more specific one + */ + public function withLabel(string $label): Glyph; /** * Get the type of the glyph. diff --git a/components/ILIAS/UI/src/Component/Symbol/Icon/Standard.php b/components/ILIAS/UI/src/Component/Symbol/Icon/Standard.php index f27efd55ac11..c405aacc3452 100755 --- a/components/ILIAS/UI/src/Component/Symbol/Icon/Standard.php +++ b/components/ILIAS/UI/src/Component/Symbol/Icon/Standard.php @@ -184,7 +184,7 @@ interface Standard extends Icon public const GCON = 'gcon'; //Group Conversaion public const FILS = 'fils'; //File System Service public const TALA = 'tala'; //Employee Talk Template Admin - public const QST = 'ques'; //Question + public const QSTS = 'qsts'; //Question Component public const GSFO = 'gsfo'; //Footer Administration public const STUS = 'stus'; //Shortlink public const ADMA = 'adma'; //Administration - General Settings diff --git a/components/ILIAS/UI/src/Component/Table/Column/Factory.php b/components/ILIAS/UI/src/Component/Table/Column/Factory.php index d97c6b92ab7f..61f211de251b 100755 --- a/components/ILIAS/UI/src/Component/Table/Column/Factory.php +++ b/components/ILIAS/UI/src/Component/Table/Column/Factory.php @@ -136,12 +136,21 @@ public function link(string $title): Link; * --- * description: * purpose: > - * The LinkListing Column features an Ordered or Unordered Listing of Standard Links. - * - * --- - * @return \ILIAS\UI\Component\Table\Column\LinkListing + * The Listing Column is used for representing lists inside a table. To + * account for large lists, the Listing Column caps the amount of items + * which are initially visible and provides a toggle to show/hide them. + * composition: > + * The Listing Column either consists of an Unordered or Ordered Listing. + * If the Listing contains many items, some of them will be initially + * hidden and a Shy Button appears below the Listing. + * effect: > + * Clicking the Shy Button will toggle the visibility of initially hidden + * items of the Listing. + * --- + * @param string $title + * @return \ILIAS\UI\Component\Table\Column\Listing */ - public function linkListing(string $title): LinkListing; + public function listing(string $title): Listing; /** * --- diff --git a/components/ILIAS/UI/src/Component/Table/Column/LinkListing.php b/components/ILIAS/UI/src/Component/Table/Column/Listing.php similarity index 94% rename from components/ILIAS/UI/src/Component/Table/Column/LinkListing.php rename to components/ILIAS/UI/src/Component/Table/Column/Listing.php index b02c08c1cc01..fa80d9810da6 100755 --- a/components/ILIAS/UI/src/Component/Table/Column/LinkListing.php +++ b/components/ILIAS/UI/src/Component/Table/Column/Listing.php @@ -20,6 +20,6 @@ namespace ILIAS\UI\Component\Table\Column; -interface LinkListing extends Column +interface Listing extends Column { } diff --git a/components/ILIAS/UI/src/Component/ViewControl/Factory.php b/components/ILIAS/UI/src/Component/ViewControl/Factory.php index b15f3e2a9d7b..f9386cd424c0 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Factory.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Factory.php @@ -26,6 +26,8 @@ /** * This is how the factory for UI elements looks. + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Factory} */ interface Factory { @@ -47,10 +49,12 @@ interface Factory * 1: The HTML container enclosing the buttons of the Mode View Control MUST cary the role-attribute "group". * 2: The HTML container enclosing the buttons of the Mode View Control MUST set an aria-label describing the element. Eg. "Mode View Control" * --- - * @param array $labelled_actions Set of labelled actions (string|string)[]. The label of the action is used as key, the action itself as value. - * The first of the actions will be activated by default. - * @param string $aria_label Defines the functionality. + * @param array $labelled_actions Set of labelled actions (string|string)[]. The label of the action is used as key, the action itself as value. + * The first of the actions will be activated by default. + * @param string $aria_label Defines the functionality. * @return \ILIAS\UI\Component\ViewControl\Mode + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Mode} */ public function mode(array $labelled_actions, string $aria_label): Mode; @@ -68,10 +72,12 @@ public function mode(array $labelled_actions, string $aria_label): Mode; * Clicking on the Buttons left or right changes the selection of the displayed data by a fixed interval. Clicking * the Button in the middle opens the sections hinted by the label of the button (e.g. "Today"). * --- - * @param \ILIAS\UI\Component\Button\Button $previous_action Button to be placed in the left. - * @param \ILIAS\UI\Component\Button\Button|\ILIAS\UI\Component\Button\Month $button Button to be placed in the middle (Month Button or Default Button). - * @param \ILIAS\UI\Component\Button\Button $next_action Button to be placed in the right. + * @param \ILIAS\UI\Component\Button\Button $previous_action Button to be placed in the left. + * @param \ILIAS\UI\Component\Button\Button|\ILIAS\UI\Component\Button\Month $button Button to be placed in the middle (Month Button or Default Button). + * @param \ILIAS\UI\Component\Button\Button $next_action Button to be placed in the right. * @return \ILIAS\UI\Component\ViewControl\Section + * + * @deprecated no alternative (yet). */ public function section(Button $previous_action, Component $button, Button $next_action): Section; @@ -109,9 +115,11 @@ public function section(Button $previous_action, Component $button, Button $next * https://mantis.ilias.de/view.php?id=26634 * * --- - * @param array $options a dictionary with value=>title - * @param string $selected a value from $options + * @param array $options a dictionary with value=>title + * @param string $selected a value from $options * @return \ILIAS\UI\Component\ViewControl\Sortation + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Sortation} */ public function sortation(array $options, string $selected): Sortation; @@ -153,6 +161,8 @@ public function sortation(array $options, string $selected): Sortation; * * --- * @return \ILIAS\UI\Component\ViewControl\Pagination + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Pagination} */ public function pagination(): Pagination; } diff --git a/components/ILIAS/UI/src/Component/ViewControl/HasViewControls.php b/components/ILIAS/UI/src/Component/ViewControl/HasViewControls.php index 7970100ba228..19de8890f9bc 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/HasViewControls.php +++ b/components/ILIAS/UI/src/Component/ViewControl/HasViewControls.php @@ -24,6 +24,8 @@ /** * Trait for adding view controls to a component + * + * @deprecated moves to {@see \ILIAS\UI\Component\Input\Container\ViewControl} */ interface HasViewControls extends Component { diff --git a/components/ILIAS/UI/src/Component/ViewControl/Mode.php b/components/ILIAS/UI/src/Component/ViewControl/Mode.php index 77d4bb054be2..819189513e9e 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Mode.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Mode.php @@ -24,6 +24,8 @@ /** * This describes a Mode Control + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Mode} */ interface Mode extends Component { diff --git a/components/ILIAS/UI/src/Component/ViewControl/Pagination.php b/components/ILIAS/UI/src/Component/ViewControl/Pagination.php index 5893a4b2fdc9..8ef5b3c3aed5 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Pagination.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Pagination.php @@ -28,6 +28,8 @@ /** * This describes a Pagination Control + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Pagination} */ interface Pagination extends Component, JavaScriptBindable, Triggerer { diff --git a/components/ILIAS/UI/src/Component/ViewControl/Section.php b/components/ILIAS/UI/src/Component/ViewControl/Section.php index 2f1fe21d73c1..877d69e48fba 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Section.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Section.php @@ -25,6 +25,8 @@ /** * This describes a Section Control + * + * @deprecated no alternative (yet). */ interface Section extends Component { diff --git a/components/ILIAS/UI/src/Component/ViewControl/Sortation.php b/components/ILIAS/UI/src/Component/ViewControl/Sortation.php index 03fc1cc8f3a6..019ada8671dd 100755 --- a/components/ILIAS/UI/src/Component/ViewControl/Sortation.php +++ b/components/ILIAS/UI/src/Component/ViewControl/Sortation.php @@ -27,6 +27,8 @@ /** * This describes a Sortation Control + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Sortation} */ interface Sortation extends Component, JavaScriptBindable, Triggerer { diff --git a/components/ILIAS/UI/src/Factory.php b/components/ILIAS/UI/src/Factory.php index ee0630e2a60a..8ddaa0856df1 100755 --- a/components/ILIAS/UI/src/Factory.php +++ b/components/ILIAS/UI/src/Factory.php @@ -403,6 +403,9 @@ public function breadcrumbs(array $crumbs): Breadcrumbs; * effect: Interacting with a view control changes to display in some content area. * --- * @return \ILIAS\UI\Component\ViewControl\Factory + * + * @deprecated use {@see \ILIAS\UI\Component\Input\ViewControl\Factory} + * via {@see \ILIAS\UI\Factory::input()} */ public function viewControl(): C\ViewControl\Factory; diff --git a/components/ILIAS/UI/src/Implementation/Component/Button/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Button/Renderer.php index 39cdf90d444e..f52c0e294aa1 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Button/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Button/Renderer.php @@ -177,7 +177,6 @@ public function registerResources(ResourceRegistry $registry): void { parent::registerResources($registry); $registry->register('assets/js/button.js'); - $registry->register("./assets/js/moment-with-locales.min.js"); } protected function renderClose(Component\Button\Close $component): string diff --git a/components/ILIAS/UI/src/Implementation/Component/Entity/Entity.php b/components/ILIAS/UI/src/Implementation/Component/Entity/Entity.php index ad0020d42a9b..04ae7352e2b2 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Entity/Entity.php +++ b/components/ILIAS/UI/src/Implementation/Component/Entity/Entity.php @@ -27,9 +27,11 @@ use ILIAS\UI\Component\Button\Shy; use ILIAS\UI\Component\Button\Tag; use ILIAS\UI\Component\Legacy\Content; +use ILIAS\UI\Component\Button\Standard as StandardButton; use ILIAS\UI\Component\Listing\Property as PropertyListing; use ILIAS\UI\Component\Link\Standard as StandardLink; use ILIAS\UI\Implementation\Component\ComponentHelper; +use ILIAS\UI\Component\Listing\Workflow; abstract class Entity implements I\Entity { @@ -66,12 +68,14 @@ abstract class Entity implements I\Entity /** * @var Shy[] */ - protected array $actions = []; + protected array $managing_actions = []; /** * @var array */ protected array $personal_status = []; + protected ?Workflow\Linear $workflow = null; + public function __construct( protected Symbol | Image | Shy | StandardLink | string $primary_identifier, protected Symbol | Image | Shy | StandardLink | string $secondary_identifier @@ -157,12 +161,12 @@ public function getMainDetails(): array /** * @inheritdoc */ - public function withPrioritizedReactions(Glyph | Tag ...$prio_reactions): self + public function withPrioritizedReactions(Glyph | Tag | StandardButton | Shy ...$prio_reactions): self { $this->checkArgListElements( "Entity Prioritized Reactions", $prio_reactions, - [Glyph::class, Tag::class] + [Glyph::class, Tag::class, StandardButton::class, Shy::class] ); $clone = clone $this; $clone->prio_reactions = $prio_reactions; @@ -179,12 +183,12 @@ public function getPrioritizedReactions(): array /** * @inheritdoc */ - public function withReactions(Glyph | Tag ...$reactions): self + public function withReactions(Glyph | Tag | Shy | StandardButton ...$reactions): self { $this->checkArgListElements( "Entity Reactions", $reactions, - [Glyph::class, Tag::class] + [Glyph::class, Tag::class, Shy::class, StandardButton::class] ); $clone = clone $this; @@ -235,21 +239,27 @@ public function getDetails(): array return $this->details; } + public function withManagingActions(Shy ...$managing_actions): static + { + $clone = clone $this; + $clone->managing_actions = $managing_actions; + return $clone; + } + /** * @inheritdoc */ public function withActions(Shy ...$actions): self { - $clone = clone $this; - $clone->actions = $actions; - return $clone; + return $this->withManagingActions(...$actions); } + /** * @return Shy[] */ - public function getActions(): array + public function getManagingActions(): array { - return $this->actions; + return $this->managing_actions; } /** @@ -269,4 +279,16 @@ public function getPersonalStatus(): array { return $this->personal_status; } + + public function withWorkflow(Workflow\Linear $workflow): static + { + $clone = clone $this; + $clone->workflow = $workflow; + return $clone; + } + + public function getWorkflow(): ?Workflow\Linear + { + return $this->workflow; + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Entity/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Entity/Renderer.php index 878cd345346a..3bb4ff664005 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Entity/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Entity/Renderer.php @@ -20,12 +20,9 @@ namespace ILIAS\UI\Implementation\Component\Entity; -//use ILIAS\UI\Component\JavaScriptBindable; use ILIAS\UI\Implementation\Render\AbstractComponentRenderer; use ILIAS\UI\Renderer as RendererInterface; use ILIAS\UI\Component; -use ILIAS\UI\Implementation\Render\ResourceRegistry; -use ILIAS\UI\Implementation\Render\Template; class Renderer extends AbstractComponentRenderer { @@ -34,7 +31,7 @@ class Renderer extends AbstractComponentRenderer */ public function render(Component\Component $component, RendererInterface $default_renderer): string { - if ($component instanceof Component\Entity\Entity) { + if ($component instanceof Entity) { return $this->renderEntity($component, $default_renderer); } $this->cannotHandleComponent($component); @@ -49,11 +46,11 @@ protected function renderEntity(Entity $component, RendererInterface $default_re $tpl->touchBlock('secondid_string'); } elseif ($secondary_identifier instanceof Component\Image\Image) { $tpl->touchBlock('secondid_image'); - } elseif ($secondary_identifier instanceof Component\Image\Symbol) { + } elseif ($secondary_identifier instanceof Component\Symbol\Symbol) { $tpl->touchBlock('secondid_symbol'); - } elseif ($secondary_identifier instanceof Component\Image\Link) { + } elseif ($secondary_identifier instanceof Component\Link\Link) { $tpl->touchBlock('secondid_link'); - } elseif ($secondary_identifier instanceof Component\Image\Shy) { + } elseif ($secondary_identifier instanceof Component\Button\Shy) { $tpl->touchBlock('secondid_shy'); } @@ -62,6 +59,7 @@ protected function renderEntity(Entity $component, RendererInterface $default_re $primary_identifier = $component->getPrimaryIdentifier(); $primary_identifier = is_string($primary_identifier) ? $primary_identifier : $this->maybeRender($default_renderer, $primary_identifier); $tpl->setVariable('PRIMARY_IDENTIFIER', $primary_identifier); + $tpl->setVariable('PRIMARY_IDENTIFIER_ID', $this->createId()); $tpl->setVariable('BLOCKING_CONDITIONS', $this->maybeRender($default_renderer, ...$component->getBlockingAvailabilityConditions())); $tpl->setVariable('FEATURES', $this->maybeRender($default_renderer, ...$component->getFeaturedProperties())); @@ -70,9 +68,13 @@ protected function renderEntity(Entity $component, RendererInterface $default_re $tpl->setVariable('AVAILABILITY', $this->maybeRender($default_renderer, ...$component->getAvailability())); $tpl->setVariable('DETAILS', $this->maybeRender($default_renderer, ...$component->getDetails())); - if ($actions = $component->getActions()) { + if (null !== $component->getWorkflow()) { + $button_components = $this->createUnfinishedWorkflowActions($component->getWorkflow()); + $tpl->setVariable('WORKFLOW_ACTIONS', $default_renderer->render($button_components)); + } + if ($actions = $component->getManagingActions()) { $actions_dropdown = $this->getUIFactory()->dropdown()->standard($actions); - $tpl->setVariable('ACTIONS', $default_renderer->render($actions_dropdown)); + $tpl->setVariable('MANAGING_ACTIONS', $default_renderer->render($actions_dropdown)); } if ($reactions = $component->getReactions()) { $tpl->setVariable('REACTIONS', $default_renderer->render($reactions)); @@ -93,4 +95,21 @@ protected function maybeRender(RendererInterface $default_renderer, Component\Co return $default_renderer->render($values); } + + /** @return Component\Button\Standard[] */ + protected function createUnfinishedWorkflowActions(Component\Listing\Workflow\Workflow $workflow): array + { + $actions = []; + foreach ($workflow->getSteps() as $step) { + if (null === $step->getAction() || + $step->getAvailability() !== Component\Listing\Workflow\Step::AVAILABLE || + ($step->getStatus() !== Component\Listing\Workflow\Step::NOT_STARTED && + $step->getStatus() !== Component\Listing\Workflow\Step::IN_PROGRESS) + ) { + continue; + } + $actions[] = $this->getUIFactory()->button()->standard($step->getLabel(), $step->getAction()); + } + return $actions; + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Text.php b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Text.php index 46c1e5a765a0..749e8dc3911e 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Text.php +++ b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Text.php @@ -67,6 +67,11 @@ public function getMaxLength(): ?int return $this->max_length; } + public function withValue($value): self + { + return parent::withValue($value ?? ""); + } + /** * @inheritdoc */ diff --git a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Textarea.php b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Textarea.php index 9a9682c28352..2dbab9a14c46 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Textarea.php +++ b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Textarea.php @@ -101,6 +101,11 @@ public function getMinLimit(): ?int return $this->min_limit; } + public function withValue($value): self + { + return parent::withValue($value ?? ""); + } + /** * @inheritdoc */ diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Factory.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Factory.php index 49008e8fbd4f..e8fe586bdceb 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Factory.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Factory.php @@ -28,4 +28,9 @@ public function standard(I\RecordToEntity $mapping): Standard { return new Standard($mapping); } + + public function grid(I\RecordToEntity $mapping): Grid + { + return new Grid($mapping); + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Grid.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Grid.php new file mode 100644 index 000000000000..fcfb4b95da2c --- /dev/null +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Entity/Grid.php @@ -0,0 +1,27 @@ +renderEntityListing($component, $default_renderer); + if ($component instanceof Standard) { + return $this->renderEntityListingStandard($component, $default_renderer); + } + if ($component instanceof Grid) { + return $this->renderEntityListingGrid($component, $default_renderer); } $this->cannotHandleComponent($component); } - protected function renderEntityListing(EntityListing $component, RendererInterface $default_renderer): string + protected function renderEntityListingStandard(EntityListing $component, RendererInterface $default_renderer): string { $tpl = $this->getTemplate('tpl.entitylisting.html', true, true); @@ -52,4 +55,17 @@ protected function renderEntityListing(EntityListing $component, RendererInterfa } return $tpl->get(); } + protected function renderEntityListingGrid(EntityListing $component, RendererInterface $default_renderer): string + { + $tpl = $this->getTemplate('tpl.entitylistinggrid.html', true, true); + + foreach ($component->getEntities( + $this->getUIFactory(), + ) as $entity) { + $tpl->setCurrentBlock('entry'); + $tpl->setVariable('ENTITY', $default_renderer->render($entity)); + $tpl->parseCurrentBlock(); + } + return $tpl->get(); + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Factory.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Factory.php index a4d6c219b5c1..d6260c1a05ea 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Factory.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Factory.php @@ -46,6 +46,14 @@ public function descriptive(array $items): Descriptive return new Descriptive($items); } + public function inline(array $items): Inline + { + return new Inline($items); + } + + /** + * @inheritdoc + */ public function workflow(): Workflow\Factory { return $this->workflow_factory; diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Inline.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Inline.php new file mode 100644 index 000000000000..87ac67c4aba4 --- /dev/null +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Inline.php @@ -0,0 +1,28 @@ + + */ +class ListingRendererFactory extends DefaultRendererFactory +{ + /** @var string[] cannonical names of table components */ + protected const array TABLE_COLUMN_CONTEXTS = [ + 'OrderingRowTable', + 'DataRowTable', + ]; + + public function getRendererInContext(Component $component, array $contexts): ComponentRenderer + { + if (!empty(array_intersect(self::TABLE_COLUMN_CONTEXTS, $contexts))) { + return new TableColumnContextRenderer( + $this->ui_factory, + $this->tpl_factory, + $this->lng, + $this->js_binding, + $this->image_path_resolver, + $this->data_factory, + $this->help_text_retriever, + $this->upload_limit_resolver, + ); + } + + return parent::getRendererInContext($component, $contexts); + } +} diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Ordered.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Ordered.php index 6bbda158f88a..6d1f2bc3c6e7 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Ordered.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Ordered.php @@ -21,6 +21,7 @@ namespace ILIAS\UI\Implementation\Component\Listing; use ILIAS\UI\Component as C; +use ILIAS\UI\Implementation\Component\JavaScriptBindable; /** * Class Listing @@ -28,4 +29,5 @@ */ class Ordered extends Listing implements C\Listing\Ordered { + use JavaScriptBindable; } diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Property.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Property.php index 8b6333444355..af138ef25ff0 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Property.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Property.php @@ -33,11 +33,6 @@ class Property extends Listing implements IListing\Property { use ComponentHelper; - protected const ALLOWED_VALUE_TYPES = [ - Symbol::class, - Content::class, - StandardLink::class - ]; public function __construct() { @@ -58,13 +53,10 @@ public function withItems(array $items): self } public function withProperty( - string $label, - string | Symbol | Content | StandardLink $value, - bool $show_label = true + string | Symbol $label, + string | Symbol | Content | StandardLink | IListing\Inline $value, + bool $show_label = true, ): self { - if (is_array($value)) { - $this->checkArgListElements("value", $value, self::ALLOWED_VALUE_TYPES); - } $clone = clone $this; $clone->items[] = [$label, $value, $show_label]; return $clone; diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Renderer.php index 1a2aced57f96..da00b21b1f3c 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Renderer.php @@ -23,6 +23,7 @@ use ILIAS\UI\Implementation\Render\AbstractComponentRenderer; use ILIAS\UI\Renderer as RendererInterface; use ILIAS\UI\Component; +use ILIAS\UI\Implementation\Render\Template; /** * Class Renderer @@ -30,28 +31,34 @@ */ class Renderer extends AbstractComponentRenderer { + /** @var int amount of characters that fits into one line on desktop. */ + protected const MAX_CHARS_IN_LINE = 260; + /** * @inheritdocs */ public function render(Component\Component $component, RendererInterface $default_renderer): string { - if ($component instanceof Component\Listing\Descriptive) { - return $this->render_descriptive($component, $default_renderer); + if ($component instanceof Descriptive) { + return $this->renderDescriptiveList($component, $default_renderer); } - if ($component instanceof Component\Listing\Property) { - return $this->renderProperty($component, $default_renderer); + if ($component instanceof Property) { + return $this->renderPropertyList($component, $default_renderer); } - if ($component instanceof Component\Listing\Listing) { - return $this->render_simple($component, $default_renderer); + if ($component instanceof Unordered || + $component instanceof Ordered || + $component instanceof Inline + ) { + return $this->renderList($component, $default_renderer); } $this->cannotHandleComponent($component); } - protected function render_descriptive( - Component\Listing\Descriptive $component, + protected function renderDescriptiveList( + Descriptive $component, RendererInterface $default_renderer ): string { $tpl = $this->getTemplate("tpl.descriptive.html", true, true); @@ -73,52 +80,71 @@ protected function render_descriptive( return $tpl->get(); } - protected function render_simple(Component\Listing\Listing $component, RendererInterface $default_renderer): string + protected function renderList(Unordered|Ordered|Inline $component, RendererInterface $default_renderer): string { - $tpl_name = ""; - - if ($component instanceof Component\Listing\Ordered) { - $tpl_name = "tpl.ordered.html"; - } - if ($component instanceof Component\Listing\Unordered) { + if ($component instanceof Unordered) { $tpl_name = "tpl.unordered.html"; + } elseif ($component instanceof Ordered) { + $tpl_name = "tpl.ordered.html"; + } elseif ($component instanceof Inline) { + $tpl_name = "tpl.inline.html"; + } else { + $this->cannotHandleComponent($component); } $tpl = $this->getTemplate($tpl_name, true, true); - if (count($component->getItems()) > 0) { - foreach ($component->getItems() as $item) { - $tpl->setCurrentBlock("item"); - if (is_string($item)) { - $tpl->setVariable("ITEM", $item); - } else { - $tpl->setVariable("ITEM", $default_renderer->render($item)); - } - $tpl->parseCurrentBlock(); + foreach ($component->getItems() as $item) { + $tpl->setCurrentBlock("item"); + if (is_string($item)) { + $tpl->setVariable("ITEM", $item); + } else { + $tpl->setVariable("ITEM", $default_renderer->render($item)); } + $tpl->parseCurrentBlock(); } + + $this->bindAndApplyJavaScript($component, $tpl); + return $tpl->get(); } - protected function renderProperty( - Component\Listing\Property $component, + protected function renderPropertyList( + Property $component, RendererInterface $default_renderer ): string { $tpl = $this->getTemplate("tpl.propertylisting.html", true, true); - foreach ($component->getItems() as $property) { - list($label, $value, $show_label) = $property; - if (! is_string($value)) { - $value = $default_renderer->render($value); - } - + foreach ($component->getItems() as [$label, $value, $show_label]) { $tpl->setCurrentBlock("property"); - $tpl->setVariable("VALUE", $value); if ($show_label) { - $tpl->setVariable("LABEL", $label); + if ($label instanceof Component\Component) { + $tpl->setVariable('LABEL', $default_renderer->render($label)); + } else { + $tpl->setVariable('LABEL', $this->convertSpecialCharacters($label)); + } + } + if (is_string($value) && self::MAX_CHARS_IN_LINE <= mb_strlen($value)) { + $tpl->setVariable("ID_SHOW_MORE_TOGGLE", $this->createId()); + $tpl->setVariable("MORE", $this->txt("show_more")); + $tpl->setVariable("LESS", $this->txt("show_less")); + $tpl->setVariable("LONG_VALUE", $this->convertSpecialCharacters($value)); + $tpl->parseCurrentBlock(); + } elseif (is_string($value)) { + $tpl->setVariable("SHORT_VALUE", $this->convertSpecialCharacters($value)); + } elseif ($value instanceof Component\Component) { + $tpl->setVariable("SHORT_VALUE", $default_renderer->render($value)); } $tpl->parseCurrentBlock(); } return $tpl->get(); } + + protected function bindAndApplyJavaScript(Component\JavaScriptBindable $component, Template $template): void + { + $id = $this->bindJavaScript($component); + if (null !== $id) { + $template->setVariable('ID', $id); + } + } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/TableColumnContextRenderer.php b/components/ILIAS/UI/src/Implementation/Component/Listing/TableColumnContextRenderer.php new file mode 100644 index 000000000000..9b486c473636 --- /dev/null +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/TableColumnContextRenderer.php @@ -0,0 +1,80 @@ + + */ +class TableColumnContextRenderer extends Renderer +{ + protected const int LIST_DISPLAY_LIMIT = 3; + + public function registerResources(ResourceRegistry $registry): void + { + $registry->register('assets/js/listing.min.js'); + } + + protected function renderList(Ordered|Unordered|Inline $component, RendererInterface $default_renderer): string + { + if ($component instanceof Inline || self::LIST_DISPLAY_LIMIT >= count($component->getItems())) { + return parent::renderList($component, $default_renderer); + } + + $template = $this->getTemplate('tpl.table_column_context.html', true, true); + $template->setVariable('DISPLAY_LIMIT', self::LIST_DISPLAY_LIMIT); + $template->setVariable('SHOW_MORE_LABEL', $this->txt('show_more')); + + if ($component instanceof Ordered) { + $template->setVariable('LIST_TYPE', 'ol'); + } else { + $template->setVariable('LIST_TYPE', 'ul'); + } + + // array_values() ensures we can use $index for count + foreach (array_values($component->getItems()) as $index => $item) { + $template->setCurrentBlock("item"); + if (is_string($item)) { + $template->setVariable("ITEM", $item); + } else { + $template->setVariable("ITEM", $default_renderer->render($item)); + } + if (self::LIST_DISPLAY_LIMIT > $index) { + $template->setVariable('VISIBILITY', 'visible'); + } else { + $template->setVariable('VISIBILITY', 'hidden'); + } + $template->parseCurrentBlock(); + } + + $enriched_component = $component->withAdditionalOnLoadCode( + static fn($id) => "il.UI.Listing.createExpandableList('$id');", + ); + + $this->bindAndApplyJavaScript($enriched_component, $template); + + $this->toJS('show_more'); + $this->toJS('show_less'); + + return $template->get(); + } +} diff --git a/components/ILIAS/UI/src/Implementation/Component/Listing/Unordered.php b/components/ILIAS/UI/src/Implementation/Component/Listing/Unordered.php index d983880eebf6..099c75b7c88d 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Listing/Unordered.php +++ b/components/ILIAS/UI/src/Implementation/Component/Listing/Unordered.php @@ -21,6 +21,7 @@ namespace ILIAS\UI\Implementation\Component\Listing; use ILIAS\UI\Component as C; +use ILIAS\UI\Implementation\Component\JavaScriptBindable; /** * Class Listing @@ -28,4 +29,5 @@ */ class Unordered extends Listing implements C\Listing\Unordered { + use JavaScriptBindable; } diff --git a/components/ILIAS/UI/src/Implementation/Component/MainControls/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/MainControls/Renderer.php index 9c88d35df7f0..f2f517fb157a 100755 --- a/components/ILIAS/UI/src/Implementation/Component/MainControls/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/MainControls/Renderer.php @@ -44,6 +44,9 @@ class Renderer extends AbstractComponentRenderer public const BLOCK_MAINBAR_TOOLS = 'tool_trigger_item'; public const BLOCK_METABAR_ENTRIES = 'meta_element'; + protected const FOOTER_SECTION_SIZE_MEDIUM = 'md'; + protected const FOOTER_SECTION_SIZE_SMALL = 'sm'; + private array $trigger_signals = []; /** @@ -445,7 +448,12 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ $template->setCurrentBlock('with_additional_item'); $template->setVariable('ITEM_CONTENT', $this->permanentLink((string) $permanent_url, $default_renderer)); $template->parseCurrentBlock(); - $this->parseFooterSection($template, 'permanent-link', $this->txt('footer_permanent_link')); + $this->parseFooterSection( + $template, + 'permanent-link', + $this->txt('footer_permanent_link'), + self::FOOTER_SECTION_SIZE_MEDIUM, + ); } // maybe render section 2 (link groups): @@ -462,6 +470,7 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ 'link-groups', $this->txt('footer_link_groups'), $link_groups, + self::FOOTER_SECTION_SIZE_SMALL, ); } @@ -475,6 +484,7 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ 'links', $this->txt('footer_links'), $links, + self::FOOTER_SECTION_SIZE_SMALL, ); } @@ -498,7 +508,8 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ $default_renderer, 'icons', $this->txt('footer_icons'), - $icons + $icons, + self::FOOTER_SECTION_SIZE_SMALL, ); } @@ -512,6 +523,7 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ 'texts', $this->txt('footer_texts'), $texts, + self::FOOTER_SECTION_SIZE_MEDIUM, ); } @@ -522,13 +534,15 @@ protected function renderFooter(I\Footer $component, RendererInterface $default_ /** * @param array $section_items (use as [$content, $title] = ) + * @param string $section_size (self::FOOTER_SECTION_SIZE_MEDIUM|self::FOOTER_SECTION_SIZE_SMALL) */ protected function parseAdditionalFooterSectionItems( Template $template, RendererInterface $default_renderer, string $section_type, string $section_label, - array $section_items = [], + array $section_items, + string $section_size, ): void { foreach ($section_items as [$content, $title]) { $template->setCurrentBlock('with_additional_item'); @@ -544,18 +558,20 @@ protected function parseAdditionalFooterSectionItems( $template->parseCurrentBlock(); } - $this->parseFooterSection($template, $section_type, $section_label); + $this->parseFooterSection($template, $section_type, $section_label, $section_size); } /** * @param array $section_icons + * @param string $section_size (self::FOOTER_SECTION_SIZE_MEDIUM|self::FOOTER_SECTION_SIZE_SMALL) */ protected function parseAdditionalFooterSectionIcons( Template $template, RendererInterface $default_renderer, string $section_type, string $section_label, - array $section_icons = [], + array $section_icons, + string $section_size, ): void { foreach ($section_icons as $icon) { $template->setCurrentBlock('with_additional_icon'); @@ -563,17 +579,20 @@ protected function parseAdditionalFooterSectionIcons( $template->parseCurrentBlock(); } - $this->parseFooterSection($template, $section_type, $section_label); + $this->parseFooterSection($template, $section_type, $section_label, $section_size); } + /** @param string $section_size (self::FOOTER_SECTION_SIZE_MEDIUM|self::FOOTER_SECTION_SIZE_SMALL) */ protected function parseFooterSection( Template $template, string $section_type, string $section_label, + string $section_size, ): void { $template->setCurrentBlock('with_additional_section'); $template->setVariable('SECTION_TYPE', $section_type); $template->setVariable('SECTION_LABEL', $section_label); + $template->setVariable('SECTION_SIZE', $section_size); $template->parseCurrentBlock(); } diff --git a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Factory.php b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Factory.php index c55ad835f9cd..e62b547f2ca9 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Factory.php +++ b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Factory.php @@ -24,303 +24,328 @@ class Factory implements G\Factory { - public function settings(): Glyph + public function __construct( + protected \ILIAS\Language\Language $language, + ) { + } + + public function settings(): G\Glyph { - return new Glyph(G\Glyph::SETTINGS, "settings"); + return new Glyph(G\Glyph::SETTINGS, $this->language->txt("settings")); } public function collapse(): Glyph { - return new Glyph(G\Glyph::COLLAPSE, "collapse_content"); + return new Glyph(G\Glyph::COLLAPSE, $this->language->txt("collapse_content")); } public function expand(): Glyph { - return new Glyph(G\Glyph::EXPAND, "expand_content"); + return new Glyph(G\Glyph::EXPAND, $this->language->txt("expand_content")); } public function add(): Glyph { - return new Glyph(G\Glyph::ADD, "add"); + return new Glyph(G\Glyph::ADD, $this->language->txt("add")); } public function remove(): Glyph { - return new Glyph(G\Glyph::REMOVE, "remove"); + return new Glyph(G\Glyph::REMOVE, $this->language->txt("remove")); } public function up(): Glyph { - return new Glyph(G\Glyph::UP, "up"); + return new Glyph(G\Glyph::UP, $this->language->txt("up")); } public function down(): Glyph { - return new Glyph(G\Glyph::DOWN, "down"); + return new Glyph(G\Glyph::DOWN, $this->language->txt("down")); } public function back(): Glyph { - return new Glyph(G\Glyph::BACK, "back"); + return new Glyph(G\Glyph::BACK, $this->language->txt("back")); } public function next(): Glyph { - return new Glyph(G\Glyph::NEXT, "next"); + return new Glyph(G\Glyph::NEXT, $this->language->txt("next")); } public function sortAscending(): Glyph { - return new Glyph(G\Glyph::SORT_ASCENDING, "sort_ascending"); + return new Glyph(G\Glyph::SORT_ASCENDING, $this->language->txt("sort_ascending")); } public function briefcase(): Glyph { - return new Glyph(G\Glyph::BRIEFCASE, "briefcase"); + return new Glyph(G\Glyph::BRIEFCASE, $this->language->txt("briefcase")); } public function sortDescending(): Glyph { - return new Glyph(G\Glyph::SORT_DESCENDING, "sort_descending"); + return new Glyph(G\Glyph::SORT_DESCENDING, $this->language->txt("sort_descending")); } public function user(): Glyph { - return new Glyph(G\Glyph::USER, "show_who_is_online"); + return new Glyph(G\Glyph::USER, $this->language->txt("show_who_is_online")); } public function mail(): Glyph { - return new Glyph(G\Glyph::MAIL, "mail"); + return new Glyph(G\Glyph::MAIL, $this->language->txt("mail")); } public function notification(): Glyph { - return new Glyph(G\Glyph::NOTIFICATION, "notifications"); + return new Glyph(G\Glyph::NOTIFICATION, $this->language->txt("notifications")); } public function tag(): Glyph { - return new Glyph(G\Glyph::TAG, "tags"); + return new Glyph(G\Glyph::TAG, $this->language->txt("tags")); } public function note(): Glyph { - return new Glyph(G\Glyph::NOTE, "notes"); + return new Glyph(G\Glyph::NOTE, $this->language->txt("notes")); } public function comment(): Glyph { - return new Glyph(G\Glyph::COMMENT, "comments"); + return new Glyph(G\Glyph::COMMENT, $this->language->txt("comments")); } public function like(): Glyph { - return new Glyph(G\Glyph::LIKE, "like"); + return new Glyph(G\Glyph::LIKE, $this->language->txt("like")); } public function love(): Glyph { - return new Glyph(G\Glyph::LOVE, "love"); + return new Glyph(G\Glyph::LOVE, $this->language->txt("love")); } public function dislike(): Glyph { - return new Glyph(G\Glyph::DISLIKE, "dislike"); + return new Glyph(G\Glyph::DISLIKE, $this->language->txt("dislike")); } public function laugh(): Glyph { - return new Glyph(G\Glyph::LAUGH, "laugh"); + return new Glyph(G\Glyph::LAUGH, $this->language->txt("laugh")); } public function astounded(): Glyph { - return new Glyph(G\Glyph::ASTOUNDED, "astounded"); + return new Glyph(G\Glyph::ASTOUNDED, $this->language->txt("astounded")); } public function sad(): Glyph { - return new Glyph(G\Glyph::SAD, "sad"); + return new Glyph(G\Glyph::SAD, $this->language->txt("sad")); } public function angry(): Glyph { - return new Glyph(G\Glyph::ANGRY, "angry"); + return new Glyph(G\Glyph::ANGRY, $this->language->txt("angry")); } public function eyeopen(): Glyph { - return new Glyph(G\Glyph::EYEOPEN, "eyeopened"); + return new Glyph(G\Glyph::EYEOPEN, $this->language->txt("eyeopened")); } public function eyeclosed(): Glyph { - return new Glyph(G\Glyph::EYECLOSED, "eyeclosed"); + return new Glyph(G\Glyph::EYECLOSED, $this->language->txt("eyeclosed")); } public function attachment(): Glyph { - return new Glyph(G\Glyph::ATTACHMENT, "attachment"); + return new Glyph(G\Glyph::ATTACHMENT, $this->language->txt("attachment")); } public function reset(): Glyph { - return new Glyph(G\Glyph::RESET, "reset"); + return new Glyph(G\Glyph::RESET, $this->language->txt("reset")); } public function apply(): Glyph { - return new Glyph(G\Glyph::APPLY, "apply"); + return new Glyph(G\Glyph::APPLY, $this->language->txt("apply")); } public function search(): Glyph { - return new Glyph(G\Glyph::SEARCH, "search"); + return new Glyph(G\Glyph::SEARCH, $this->language->txt("search")); } public function help(): Glyph { - return new Glyph(G\Glyph::HELP, "help"); + return new Glyph(G\Glyph::HELP, $this->language->txt("help")); } public function calendar(): Glyph { - return new Glyph(G\Glyph::CALENDAR, "calendar"); + return new Glyph(G\Glyph::CALENDAR, $this->language->txt("calendar")); } public function time(): Glyph { - return new Glyph(G\Glyph::TIME, "time"); + return new Glyph(G\Glyph::TIME, $this->language->txt("time")); } public function close(): Glyph { - return new Glyph(G\Glyph::CLOSE, "close"); + return new Glyph(G\Glyph::CLOSE, $this->language->txt("close")); } public function more(): Glyph { - return new Glyph(G\Glyph::MORE, "show_more"); + return new Glyph(G\Glyph::MORE, $this->language->txt("show_more")); } public function disclosure(): Glyph { - return new Glyph(G\Glyph::DISCLOSURE, "disclose"); + return new Glyph(G\Glyph::DISCLOSURE, $this->language->txt("disclose")); } public function language(): Glyph { - return new Glyph(G\Glyph::LANGUAGE, "switch_language"); + return new Glyph(G\Glyph::LANGUAGE, $this->language->txt("switch_language")); } public function login(): Glyph { - return new Glyph(G\Glyph::LOGIN, "log_in"); + return new Glyph(G\Glyph::LOGIN, $this->language->txt("log_in")); } public function logout(): Glyph { - return new Glyph(G\Glyph::LOGOUT, "log_out"); + return new Glyph(G\Glyph::LOGOUT, $this->language->txt("log_out")); } public function bulletlist(): Glyph { - return new Glyph(G\Glyph::BULLETLIST, "bulletlist_action"); + return new Glyph(G\Glyph::BULLETLIST, $this->language->txt("bulletlist_action")); } public function numberedlist(): Glyph { - return new Glyph(G\Glyph::NUMBEREDLIST, "numberedlist_action"); + return new Glyph(G\Glyph::NUMBEREDLIST, $this->language->txt("numberedlist_action")); } public function listindent(): Glyph { - return new Glyph(G\Glyph::LISTINDENT, "listindent"); + return new Glyph(G\Glyph::LISTINDENT, $this->language->txt("listindent")); } public function listoutdent(): Glyph { - return new Glyph(G\Glyph::LISTOUTDENT, "listoutdent"); + return new Glyph(G\Glyph::LISTOUTDENT, $this->language->txt("listoutdent")); } public function filter(): Glyph { - return new Glyph(G\Glyph::FILTER, "filter"); + return new Glyph(G\Glyph::FILTER, $this->language->txt("filter")); } public function collapseHorizontal(): Glyph { - return new Glyph(G\Glyph::COLLAPSE_HORIZONTAL, "collapse/back"); + return new Glyph(G\Glyph::COLLAPSE_HORIZONTAL, $this->language->txt("collapse/back")); } public function header(): Glyph { - return new Glyph(G\Glyph::HEADER, "header_action"); + return new Glyph(G\Glyph::HEADER, $this->language->txt("header_action")); } public function italic(): Glyph { - return new Glyph(G\Glyph::ITALIC, "italic_action"); + return new Glyph(G\Glyph::ITALIC, $this->language->txt("italic_action")); } public function bold(): Glyph { - return new Glyph(G\Glyph::BOLD, "bold_action"); + return new Glyph(G\Glyph::BOLD, $this->language->txt("bold_action")); } public function link(): Glyph { - return new Glyph(G\Glyph::LINK, "link_action"); + return new Glyph(G\Glyph::LINK, $this->language->txt("link_action")); } public function launch(): Glyph { - return new Glyph(G\Glyph::LAUNCH, "launch"); + return new Glyph(G\Glyph::LAUNCH, $this->language->txt("launch")); } public function enlarge(): Glyph { - return new Glyph(G\Glyph::ENLARGE, "enlarge"); + return new Glyph(G\Glyph::ENLARGE, $this->language->txt("enlarge")); } public function listView(): Glyph { - return new Glyph(G\Glyph::LIST_VIEW, "list_view"); + return new Glyph(G\Glyph::LIST_VIEW, $this->language->txt("list_view")); } public function preview(): Glyph { - return new Glyph(G\Glyph::PREVIEW, "preview"); + return new Glyph(G\Glyph::PREVIEW, $this->language->txt("preview")); } public function sort(): Glyph { - return new Glyph(G\Glyph::SORT, "sort"); + return new Glyph(G\Glyph::SORT, $this->language->txt("sort")); } public function columnSelection(): Glyph { - return new Glyph(G\Glyph::COLUMN_SELECTION, "column_selection"); + return new Glyph(G\Glyph::COLUMN_SELECTION, $this->language->txt("column_selection")); } public function tileView(): Glyph { - return new Glyph(G\Glyph::TILE_VIEW, "tile_view"); + return new Glyph(G\Glyph::TILE_VIEW, $this->language->txt("tile_view")); } public function dragHandle(): G\Glyph { - return new Glyph(G\Glyph::DRAG_HANDLE, "drag_handle"); + return new Glyph(G\Glyph::DRAG_HANDLE, $this->language->txt("drag_handle")); } public function checked(): G\Glyph { - return new Glyph(G\Glyph::CHECKED, "checked"); + return new Glyph(G\Glyph::CHECKED, $this->language->txt("checked")); } public function unchecked(): G\Glyph { - return new Glyph(G\Glyph::UNCHECKED, "unchecked"); + return new Glyph(G\Glyph::UNCHECKED, $this->language->txt("unchecked")); + } + + public function presenter(): G\Glyph + { + return new Glyph(G\Glyph::PRESENTER, "presenter"); + } + + public function owner(): G\Glyph + { + return new Glyph(G\Glyph::OWNER, "owner"); + } + + public function date(): G\Glyph + { + return new Glyph(G\Glyph::DATE, "date"); + } + + public function location(): G\Glyph + { + return new Glyph(G\Glyph::LOCATION, "location"); } } diff --git a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Glyph.php b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Glyph.php index 2f5836091f39..9f60a4740936 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Glyph.php +++ b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Glyph.php @@ -91,6 +91,10 @@ class Glyph implements C\Symbol\Glyph\Glyph self::DRAG_HANDLE, self::CHECKED, self::UNCHECKED, + self::PRESENTER, + self::OWNER, + self::DATE, + self::LOCATION, ]; private string $type; diff --git a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Renderer.php index 709d07a9c835..f8058992dfb7 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Symbol/Glyph/Renderer.php @@ -45,8 +45,7 @@ public function render(Component\Component $component, RendererInterface $defaul $label = $component->getLabel(); if ('' !== $label) { $tpl->touchBlock('with_aria_label'); - // @todo: move translation to factory, this breaks custom labels... - $tpl->setVariable("LABEL", $this->txt($label)); + $tpl->setVariable("LABEL", $label); $tpl->touchBlock('with_role'); } else { // glyph must be hidden if there is no label (semantic meaning) diff --git a/components/ILIAS/UI/src/Implementation/Component/Symbol/Icon/Standard.php b/components/ILIAS/UI/src/Implementation/Component/Symbol/Icon/Standard.php index ae2788bb5693..134cb392eba1 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Symbol/Icon/Standard.php +++ b/components/ILIAS/UI/src/Implementation/Component/Symbol/Icon/Standard.php @@ -152,7 +152,7 @@ class Standard extends Icon implements C\Symbol\Icon\Standard self::CON, self::FILS, self::TALA, - self::QST, + self::QSTS, self::STUS, self::GSFO, self::ADMA, diff --git a/components/ILIAS/UI/src/Implementation/Component/Table/Column/Factory.php b/components/ILIAS/UI/src/Implementation/Component/Table/Column/Factory.php index 7d8aaeb666e1..c46f15baf895 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Table/Column/Factory.php +++ b/components/ILIAS/UI/src/Implementation/Component/Table/Column/Factory.php @@ -81,9 +81,9 @@ public function link(string $title): Link return new Link($this->lng, $title); } - public function linkListing(string $title): LinkListing + public function listing(string $title): Listing { - return new LinkListing($this->lng, $title); + return new Listing($this->lng, $title); } public function breadcrumb(string $title): I\Breadcrumb diff --git a/components/ILIAS/UI/src/Implementation/Component/Table/Column/LinkListing.php b/components/ILIAS/UI/src/Implementation/Component/Table/Column/Listing.php similarity index 81% rename from components/ILIAS/UI/src/Implementation/Component/Table/Column/LinkListing.php rename to components/ILIAS/UI/src/Implementation/Component/Table/Column/Listing.php index 3d672128a001..64e42b060507 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Table/Column/LinkListing.php +++ b/components/ILIAS/UI/src/Implementation/Component/Table/Column/Listing.php @@ -21,19 +21,16 @@ namespace ILIAS\UI\Implementation\Component\Table\Column; use ILIAS\UI\Component\Table\Column as C; -use ILIAS\UI\Component\Link\Standard; use ILIAS\UI\Component\Listing\Ordered; use ILIAS\UI\Component\Listing\Unordered; use ILIAS\UI\Component\Component; -class LinkListing extends Column implements C\LinkListing +class Listing extends Column implements C\Listing { public function format($value): string|Component { $listing = $this->toArray($value); - $this->checkArgListElements("value", $listing, [Ordered::class, Unordered::class]); - $listing_items = $value->getItems(); - $this->checkArgListElements("list items", $listing_items, Standard::class); + $this->checkArgListElements('value', $listing, [Ordered::class, Unordered::class]); return $value; } diff --git a/components/ILIAS/UI/src/Implementation/Render/FSLoader.php b/components/ILIAS/UI/src/Implementation/Render/FSLoader.php index e7e5ff088705..851679081989 100755 --- a/components/ILIAS/UI/src/Implementation/Render/FSLoader.php +++ b/components/ILIAS/UI/src/Implementation/Render/FSLoader.php @@ -28,6 +28,7 @@ use ILIAS\UI\Implementation\Component\MessageBox\MessageBox; use ILIAS\UI\Implementation\Component\Input\Container\Form\Form; use ILIAS\UI\Implementation\Component\Menu\Menu; +use ILIAS\UI\Implementation\Component\Listing\Listing; /** * Loads renderers for components from the file system. @@ -51,6 +52,7 @@ public function __construct( private RendererFactory $message_box_renderer_factory, private RendererFactory $form_renderer_factory, private RendererFactory $menu_renderer_factory, + private RendererFactory $listing_renderer_factory, ) { } @@ -84,6 +86,10 @@ public function getRendererFactoryFor(Component $component): RendererFactory if ($component instanceof Button) { return $this->button_renderer_factory; } + if ($component instanceof Listing) { + return $this->listing_renderer_factory; + } + return $this->default_renderer_factory; } } diff --git a/components/ILIAS/UI/src/examples/Entity/Standard/base.php b/components/ILIAS/UI/src/examples/Entity/Standard/base.php index 0c4298c3faa2..33b6dd521876 100755 --- a/components/ILIAS/UI/src/examples/Entity/Standard/base.php +++ b/components/ILIAS/UI/src/examples/Entity/Standard/base.php @@ -22,21 +22,23 @@ /** * --- + * description: > + * Entities being used to show a made up event object. * expected output: > * Entities arrange information about e.g. an object into semantic groups; - * this example focusses on the possible contents of those groups and shows + * this example focuses on the possible contents of those groups and shows * a possible representation of a made up event. * From top to bottom, left to right: + * - An icon indents the following. * - There is a precondition; it links to ilias.de. * - An action-dropdown is available with two entries linking to ilias/github. - * - An icon indents the following. - * - Prominently featured is the event's date proptery. * - Only after that, the title of the event is displayed in bold. + * - Prominently featured is the event's date property. * - A progress meter ("in progress") is followed by detailed properties: * - Room information * - Description * - in one line: Available seats and availability of the event - * - in the next line: duration and the information of available redording + * - in the next line: duration and the information of available recording * - The bottom "row" shows two tags on the left * - and two glyphs on the right, the first one with status counter, the second one with * both status- and novelty counter. @@ -69,7 +71,7 @@ function base() $f->button()->shy("ILIAS", "https://www.ilias.de"), $f->button()->shy("GitHub", "https://www.github.com") ]; - $entity = $entity->withActions(...$actions); + $entity = $entity->withManagingActions(...$actions); /* * Logic for Pulling Availabilty Properties to Blocking Conditions diff --git a/components/ILIAS/UI/src/examples/Entity/Standard/semantic_groups.php b/components/ILIAS/UI/src/examples/Entity/Standard/semantic_groups.php index 32e67f7aa118..36ff079ce184 100755 --- a/components/ILIAS/UI/src/examples/Entity/Standard/semantic_groups.php +++ b/components/ILIAS/UI/src/examples/Entity/Standard/semantic_groups.php @@ -22,13 +22,17 @@ /** * --- + * description: > + * The different semantic locations on an entity. * expected output: > * This example shows/identifies the semantic groups of entites; * from top to bottom, left to right, the order of groups is this: - * - blocking conditions (left) and actions in a dropdown (right) * - secondary indentifier (it indents all the latter) and featured properties + * - blocking conditions (left) and actions in a dropdown (right) * - primary identifier + * - featured properties * - personal status + * - a workflow step button * - main details * - availability * - details @@ -43,15 +47,33 @@ function semantic_groups() $entity = $f->entity()->standard('Primary Identifier', 'Secondary Identifier') ->withBlockingAvailabilityConditions($f->legacy()->content('Blocking Conditions')) - ->withFeaturedProperties($f->legacy()->content('Featured_properties')) + ->withFeaturedProperties($f->legacy()->content('Featured Properties')) ->withPersonalStatus($f->legacy()->content('Personal Status')) ->withMainDetails($f->legacy()->content('Main Details')) ->withAvailability($f->legacy()->content('Availability')) ->withDetails($f->legacy()->content('Details')) ->withReactions($f->button()->tag('reaction', '#')) - ->withPrioritizedReactions($f->symbol()->glyph()->like()) - ->withActions($f->button()->shy('action', '#')) + ->withPrioritizedReactions($f->button()->shy("Prioritized Reaction", "#")->withSymbol($f->symbol()->glyph()->like())) + ->withManagingActions($f->button()->shy('managing actions', '#')) ; + // to get buttons, they need to be created from a Workflow + $workflow_factory = $f->listing()->workflow(); + $dummy_step = $workflow_factory->step('', ''); + + // Creating Workflow Steps + $steps = [ + $workflow_factory->step("Workflow Step not longer available", "", "#") + ->withAvailability($dummy_step::NOT_ANYMORE)->withStatus($dummy_step::SUCCESSFULLY), + $workflow_factory->step("Start available Workflow Step", "", "#") + ->withAvailability($dummy_step::AVAILABLE)->withStatus($dummy_step::NOT_STARTED), + $workflow_factory->step("Workflow Step not yet available", "", "#") + ->withAvailability($dummy_step::NOT_AVAILABLE)->withStatus($dummy_step::NOT_AVAILABLE), + ]; + + $video_workflow = $workflow_factory->linear("Workflow", $steps); + + $entity = $entity->withWorkflow($video_workflow); + return $renderer->render($entity); } diff --git a/components/ILIAS/UI/src/examples/Entity/Standard/video_object.php b/components/ILIAS/UI/src/examples/Entity/Standard/video_object.php new file mode 100644 index 000000000000..1c53f7dadc8d --- /dev/null +++ b/components/ILIAS/UI/src/examples/Entity/Standard/video_object.php @@ -0,0 +1,111 @@ + + * Full example showing how the entity could be used to describe a video object with all of its features. + * + * expected output: > + * This example shows a representation of a made up video object. + * - A thumbnail is shown as a secondary identifier that indents all following elements + * - the title as primary identifier + * - a dropdown with managing options + * - upload date and publisher as Featured Property + * - Workflow buttons + * - duration adn a description as main details + * Below is an example workflow that was given to the entity to generate the workflow buttons on this entity. + * Two of the four steps are marked as not completed and available. These two options are rendered as buttons inside + * the entity. + * --- + */ +function video_object() +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + /* + * Basic Construction + */ + + $primary_id = "Mountains through the ages - the formation of giants"; + $secondary_id = $f->image()->responsive("assets/ui-examples/images/Image/mountains.jpg", "Some mountains in the dusk"); + + // creating the entity object now so it can be filled in the logic section + $entity = $f->entity()->standard( + $primary_id, + $secondary_id + ); + + /* + * Priority Areas + */ + + $glyph_calendar = $f->symbol()->glyph()->calendar()->withLabel("Published on"); + $glyph_user = $f->symbol()->glyph()->user()->withLabel("Created by"); + + $featured_properties = $f->listing()->property() + ->withProperty($glyph_calendar, '24.01.2025') + ->withProperty($glyph_user, 'BBC England, Co-Production: ARD/ZDF, Canal Plus') + ; + + $entity = $entity + ->withFeaturedProperties($featured_properties) + ; + + /* + * Dropdown Actions + */ + + $managing_actions = [ + $f->button()->shy("Copy", "https://www.ilias.de"), + $f->button()->shy("Delete", "https://www.github.com") + ]; + $entity = $entity->withManagingActions(...$managing_actions); + + /* + * Generating Action Buttons from Workflow + */ + + $workflow_factory = $f->listing()->workflow(); + $dummy_step = $workflow_factory->step('', ''); + + // Creating Workflow Steps + $steps = [ + $workflow_factory->step("Upload video file", "Upload an .mp4 file or start a recording.", "#") + ->withAvailability($dummy_step::NOT_ANYMORE)->withStatus($dummy_step::SUCCESSFULLY), + $workflow_factory->step("Cut video", "Trim or remove parts of the video.", "#") + ->withAvailability($dummy_step::AVAILABLE)->withStatus($dummy_step::NOT_STARTED), + $workflow_factory->step("Add subtitles", "You must upload or generate subtitles for every video.", "#") + ->withAvailability($dummy_step::AVAILABLE)->withStatus($dummy_step::NOT_STARTED), + $workflow_factory->step("Publish", "Set who can see this video.", "#") + ->withAvailability($dummy_step::NOT_AVAILABLE)->withStatus($dummy_step::NOT_AVAILABLE), + ]; + + $video_workflow = $workflow_factory->linear("Video Curation", $steps); + + $entity = $entity->withWorkflow($video_workflow); + + /* + * All Other Semantic Groups + */ + + $glyph_time = $f->symbol()->glyph()->time()->withLabel("Duration"); + + $main_details_01 = $f->listing()->property() + ->withProperty($glyph_time, '45:00') + ; + $main_details_02 = $f->listing()->property() + ->withProperty('Description', "A fascinating look on the forces of nature that are able to move unimaginable tons of rocks. Find out how seemingly immovable landscape has transformed drastically through the incredible forces set free by earthquakes, vulcanos and water. This award-winning documentary traces the movement of the world's greatest mountain ranges throughout millions of years.", false) + ; + + $entity = $entity + ->withMainDetails($main_details_01, $main_details_02) + ; + + return $renderer->render([$entity]); +} diff --git a/components/ILIAS/UI/src/examples/Link/Standard/with_open_in_new_viewport.php b/components/ILIAS/UI/src/examples/Link/Standard/with_open_in_new_viewport.php new file mode 100644 index 000000000000..6a3c1838d241 --- /dev/null +++ b/components/ILIAS/UI/src/examples/Link/Standard/with_open_in_new_viewport.php @@ -0,0 +1,27 @@ + + * Example for rendering a standard link that opens to a new viewport. + * + * expected output: > + * ILIAS shows a link with the title "Goto ILIAS in new tab/window". + * Clicking the link opens the website ilias.ch in a new browser window or tab. + * --- + */ +function with_open_in_new_viewport(): string +{ + global $DIC; + $factory = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $link = $factory->link()->standard("Goto ILIAS", "http://ilias.ch"); + $link = $link->withOpenInNewViewport(true); + + return $renderer->render($link); +} diff --git a/components/ILIAS/UI/src/examples/Listing/Entity/Grid/base.php b/components/ILIAS/UI/src/examples/Listing/Entity/Grid/base.php new file mode 100644 index 000000000000..ee98483ace68 --- /dev/null +++ b/components/ILIAS/UI/src/examples/Listing/Entity/Grid/base.php @@ -0,0 +1,128 @@ + + * A card-style grid presenting many entity objects side by side. + * + * expected output: > + * ILIAS shows a grid of entities looking like cards. Each card has a thumbnail image, title and some video related + * properties and actions. The grid reacts flexibly to the available space. If there is a lot of space, the grid + * will have more columns. With little available space, the cards will stack. + * --- + */ +function base(): string +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $record_to_entity = new class () implements RecordToEntity { + public function map(UIFactory $ui_factory, mixed $record): Entity + { + $glyph_user = $ui_factory->symbol()->glyph()->user() + ->withLabel("Created by"); + + $glyph_calendar = $ui_factory->symbol()->glyph()->calendar() + ->withLabel("Upload date"); + + $glyph_duration = $ui_factory->symbol()->glyph()->time() + ->withLabel("Duration"); + + list($title, $thumbnail_url, $creator, $availability, $description, $duration, $add_workflow, $date) = $record; + $managing_actions = [ + $ui_factory->button()->shy("Edit", "#"), + $ui_factory->button()->shy("Move", "#"), + ]; + $entity = $ui_factory->entity()->standard( + $ui_factory->link()->standard($title, ""), + $ui_factory->image()->responsive($thumbnail_url, $title)->withAction("#") + ) + ->withFeaturedProperties( + $ui_factory->listing()->property() + ->withProperty($glyph_user, $creator) + ) + ->withManagingActions(...$managing_actions) + ->withMainDetails( + $ui_factory->listing()->property() + ->withProperty($glyph_duration, $description, false) + ->withProperty($glyph_duration, $duration) + ->withProperty($glyph_calendar, $date) + ) + ->withPrioritizedReactions($ui_factory->button()->shy("Like", "#")->withSymbol($ui_factory->symbol()->glyph()->like())) + ; + if ($availability) { + $entity = $entity->withBlockingAvailabilityConditions( + $ui_factory->listing()->property() + ->withProperty("Status", $ui_factory->legacy()->content($availability), false) + ); + } + if ($add_workflow) { + $workflow_factory = $ui_factory->listing()->workflow(); + $dummy_step = $workflow_factory->step('', ''); + + $steps = [ + $workflow_factory->step("Upload video file", "Upload an .mp4 file or start a recording.", "#") + ->withAvailability($dummy_step::NOT_ANYMORE)->withStatus($dummy_step::SUCCESSFULLY), + $workflow_factory->step("Cut video", "Trim or remove parts of the video.", "#") + ->withAvailability($dummy_step::NOT_ANYMORE)->withStatus($dummy_step::NOT_STARTED), + $workflow_factory->step("Add subtitles", "You must upload or generate subtitles for every video.", "#") + ->withAvailability($dummy_step::AVAILABLE)->withStatus($dummy_step::SUCCESSFULLY), + $workflow_factory->step("Publish", "Set who can see this video.", "#") + ->withAvailability($dummy_step::AVAILABLE)->withStatus($dummy_step::NOT_STARTED), + ]; + + $video_workflow = $workflow_factory->linear("Video Curation", $steps); + + $entity = $entity->withWorkflow($video_workflow); + } + return $entity; + } + }; + + $glyph_eye_closed = $f->symbol()->glyph()->eyeclosed(); + $glyph_with_text = $renderer->render($glyph_eye_closed) . " offline"; + $card_data = [ + ['Snowboarding for beginners - How to avoid falling on your face', 'assets/ui-examples/images/Image/ski_widescreen-thumbnail.jpg', "Bobby's School of Snowboarding Austria", null, 'This is the perfect start for anyone wanting to get on a snowboard. We talk the best gear and the best locations for a beginner. And no worries - it is not expensive: Renting equipment will work just fine. Then we end with some first exercises to get the stability needed to tackle your first slope', '23 min', false, '01.01.2026'], + ['The History of Bridges', 'assets/ui-examples/images/Image/sanfrancisco_widescreen-thumbnail.jpg', 'BBC England', $glyph_with_text,'One of the most monumental achievements of human kind is the invention of bridges. Crossing streets, rivers and sometimes oceans became a huge pillar for our our modern infrastructure. This documentary looks at the different types of bridges and how they have been developed and engineered throughout different cultures and centuries','90 min', true, "01.11.2026"], + ['Mountains through the ages - the formation of giants', 'assets/ui-examples/images/Image/mountains_widescreen-thumbnail.jpg','ARD/ZDF, Canal Plus', null, "A fascinating look on the forces of nature that are able to move unimaginable tons of rocks. Find out how seemingly immovable landscape has transformed drastically through the incredible forces set free by earthquakes, vulcanos and water. This award-winning documentary traces the movement of the world's greatest mountain ranges throughout millions of years.", "45 min", false, "11.10.2026"], + ['Snowboarding for beginners - How to avoid falling on your face', 'assets/ui-examples/images/Image/ski_widescreen-thumbnail.jpg', "Bobby's School of Snowboarding Austria", null, 'This is the perfect start for anyone wanting to get on a snowboard. We talk the best gear and the best locations for a beginner. And no worries - it is not expensive: Renting equipment will work just fine. Then we end with some first exercises to get the stability needed to tackle your first slope', '23 min', false, "28.02.2026"], + ['The History of Bridges', 'assets/ui-examples/images/Image/sanfrancisco_widescreen-thumbnail.jpg', 'BBC England', $glyph_with_text,'One of the most monumental achievements of human kind is the invention of bridges. Crossing streets, rivers and sometimes oceans became a huge pillar for our our modern infrastructure. This documentary looks at the different types of bridges and how they have been developed and engineered throughout different cultures and centuries','90 min', true, "15.12.2025"], + ['Mountains through the ages - the formation of giants', 'assets/ui-examples/images/Image/mountains_widescreen-thumbnail.jpg','ARD/ZDF, Canal Plus', null, "A fascinating look on the forces of nature that are able to move unimaginable tons of rocks. Find out how seemingly immovable landscape has transformed drastically through the incredible forces set free by earthquakes, vulcanos and water. This award-winning documentary traces the movement of the world's greatest mountain ranges throughout millions of years.", "45 min", false, "09.06.2026"] + ]; + + $data = new class ($card_data) implements DataRetrieval { + protected array $data = []; + + public function __construct($card_data) + { + $this->data = $card_data; + } + + public function getEntities( + Mapping $mapping, + ?Range $range, + ?array $additional_parameters + ): \Generator { + foreach ($this->data as $vid) { + yield $mapping->map($vid); + } + } + }; + + $listing = $f->listing()->entity()->grid($record_to_entity) + ->withData($data); + + return $renderer->render($listing); +} diff --git a/components/ILIAS/UI/src/examples/Listing/Entity/Standard/base.php b/components/ILIAS/UI/src/examples/Listing/Entity/Standard/base.php index 2f2bdac4cdbd..3e445f019dcc 100755 --- a/components/ILIAS/UI/src/examples/Listing/Entity/Standard/base.php +++ b/components/ILIAS/UI/src/examples/Listing/Entity/Standard/base.php @@ -29,8 +29,11 @@ /** * --- + * description: > + * A component to list many entities. Has multiple columns on very large screens. * expected output: > - * ILIAS shows the rendered Component. + * ILIAS shows a list of entities. If there is a lot of space available, the list will switch to a layout with two + * columns. * --- */ function base() diff --git a/components/ILIAS/UI/src/examples/Listing/Inline/base.php b/components/ILIAS/UI/src/examples/Listing/Inline/base.php new file mode 100644 index 000000000000..fe9a7012b43c --- /dev/null +++ b/components/ILIAS/UI/src/examples/Listing/Inline/base.php @@ -0,0 +1,30 @@ + + * Example for rendering an inline list. + * + * expected output: > + * ILIAS shows the elements of a list horizontally in a row, separated by commas. + * --- + */ +function base(): string +{ + //Init Factory and Renderer + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + //Generate List + $inline = $f->listing()->inline( + ["Apple","Banana","Milk", "Toast", "Pumpkin Pie", "Bread"] + ); + + //Render + return $renderer->render($inline); +} diff --git a/components/ILIAS/UI/src/examples/Listing/Inline/property_listing.php b/components/ILIAS/UI/src/examples/Listing/Inline/property_listing.php new file mode 100644 index 000000000000..599f81fd0dc5 --- /dev/null +++ b/components/ILIAS/UI/src/examples/Listing/Inline/property_listing.php @@ -0,0 +1,46 @@ + + * Example for rendering an inline list inside a property list. + * + * expected output: > + * ILIAS shows two properties in a single row (if space allows for it). + * One is a "Languages" property followed with flag icons. + * The other property lists video resolutions as text. + * The values are separated by commas. + * --- + */ +function property_listing(): string +{ + //Init Factory and Renderer + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + + $flag_de = $f->symbol()->icon()->custom( + "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGlkPSJmbGFnLWljb25zLWRlIiB2aWV3Qm94PSIwIDAgNjQwIDQ4MCI+CiAgPHBhdGggZmlsbD0iI2ZjMCIgZD0iTTAgMzIwaDY0MHYxNjBIMHoiLz4KICA8cGF0aCBmaWxsPSIjMDAwMDAxIiBkPSJNMCAwaDY0MHYxNjBIMHoiLz4KICA8cGF0aCBmaWxsPSJyZWQiIGQ9Ik0wIDE2MGg2NDB2MTYwSDB6Ii8+Cjwvc3ZnPgo=", + "German" + ); + + $flag_gb = $f->symbol()->icon()->custom( + "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGlkPSJmbGFnLWljb25zLWdiIiB2aWV3Qm94PSIwIDAgNjQwIDQ4MCI+CiAgPHBhdGggZmlsbD0iIzAxMjE2OSIgZD0iTTAgMGg2NDB2NDgwSDB6Ii8+CiAgPHBhdGggZmlsbD0iI0ZGRiIgZD0ibTc1IDAgMjQ0IDE4MUw1NjIgMGg3OHY2Mkw0MDAgMjQxbDI0MCAxNzh2NjFoLTgwTDMyMCAzMDEgODEgNDgwSDB2LTYwbDIzOS0xNzhMMCA2NFYweiIvPgogIDxwYXRoIGZpbGw9IiNDODEwMkUiIGQ9Im00MjQgMjgxIDIxNiAxNTl2NDBMMzY5IDI4MXptLTE4NCAyMCA2IDM1TDU0IDQ4MEgwek02NDAgMHYzTDM5MSAxOTFsMi00NEw1OTAgMHpNMCAwbDIzOSAxNzZoLTYwTDAgNDJ6Ii8+CiAgPHBhdGggZmlsbD0iI0ZGRiIgZD0iTTI0MSAwdjQ4MGgxNjBWMHpNMCAxNjB2MTYwaDY0MFYxNjB6Ii8+CiAgPHBhdGggZmlsbD0iI0M4MTAyRSIgZD0iTTAgMTkzdjk2aDY0MHYtOTZ6TTI3MyAwdjQ4MGg5NlYweiIvPgo8L3N2Zz4K", + "English" + ); + + $languages = $f->listing()->inline([$flag_de, $flag_gb]); + $resolutions = $f->listing()->inline(["480p", "720p", "1080p", "4k"]); + + $video_properties = $f->listing()->property() + ->withProperty("Languages", $languages) + ->withProperty("Resolutions", $resolutions); + + //Render + return $renderer->render($video_properties); +} diff --git a/components/ILIAS/UI/src/examples/Listing/Property/base.php b/components/ILIAS/UI/src/examples/Listing/Property/base.php index ccb0618cc478..f296ad64ba2d 100755 --- a/components/ILIAS/UI/src/examples/Listing/Property/base.php +++ b/components/ILIAS/UI/src/examples/Listing/Property/base.php @@ -22,8 +22,18 @@ /** * --- + * description: > + * Example of differently used properties. + * * expected output: > - * ILIAS shows the rendered Component. + * ILIAS shows the rendered Component. The following options are showcased at least once: + * - Key is a text string, value is a text string + * - Key is not shown, value is a Learning Progress status image followed by text + * - Key is a Glyph, value is a (date) text string + * - Key is a text string, value is a long text with a show more/less toggle + * - Key is a text string, value is a clickable link + * - Key is a text string, value is a Glyph + * * --- */ function base() @@ -32,26 +42,40 @@ function base() $f = $DIC->ui()->factory(); $renderer = $DIC->ui()->renderer(); + $some_legacy_code = $f->legacy()->content( + $renderer->render( + $f->symbol()->icon()->custom('./assets/images/learning_progress/in_progress.svg', 'incomplete'), + ) . ' in progress' + ); + + $glyph_calendar = $f->symbol()->glyph()->calendar()->withLabel("date of upload"); + $props = $f->listing()->property() ->withProperty('Title', 'Some Title') ->withProperty('number', '7') ->withProperty( 'status', - $renderer->render( - $f->symbol()->icon()->custom('./assets/images/learning_progress/in_progress.svg', 'incomplete'), - ) . ' in progress', + $some_legacy_code, false - ); + ) + ->withProperty($glyph_calendar, "21.03.2026", false); + + $props2 = $f->listing()->property() + ->withProperty("Description", "Heads up, this is a very long description. It is always a challenge: You have more to say, but there is so little space. And we still want this text to be shown with all the other properties. For this case we have the automatic text collapsing feature. This way we get the best of both worlds: The text doesn't expand beyond one line, but you can see the rest if you need to. A good use case is on the entity. As the entity might be used to show course entities with lengthy descriptions. Those will take up less space initially. Isn't that sweet? And the crazy thing is: It does not need JavaScript. It's pure HTML and CSS only. Isn't that nice?", false); + + $yes_checkmark = $f->symbol()->glyph()->apply()->withLabel("yes, approved"); - $props2 = $props->withItems([ + $props3 = $props->withItems([ ['a', "1"], ['y', "25", false], - ['link', $f->link()->standard('Goto ILIAS', 'http://www.ilias.de')] + ['link', $f->link()->standard('Goto ILIAS', 'http://www.ilias.de')], + ['approved', $yes_checkmark], ]); return $renderer->render([ $props, + $props2, $f->divider()->horizontal(), - $props2 + $props3 ]); } diff --git a/components/ILIAS/UI/src/examples/Symbol/Glyph/Date/date.php b/components/ILIAS/UI/src/examples/Symbol/Glyph/Date/date.php new file mode 100644 index 000000000000..4066e2aca433 --- /dev/null +++ b/components/ILIAS/UI/src/examples/Symbol/Glyph/Date/date.php @@ -0,0 +1,35 @@ + + * Example for rendering a Date Glyph. + * + * expected output: > + * Standard: + * ILIAS shows a monochrome symbol on a grey background. + * + * Highlighted: + * ILIAS shows the same symbol, but it's highlighted particularly. + * --- + */ +function date() +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $glyph = $f->symbol()->glyph()->date(); + + //Showcase the various states of this Glyph + $list = $f->listing()->descriptive([ + "Active" => $glyph, + "Highlighted" => $glyph->withHighlight() + ]); + + return $renderer->render($list); +} diff --git a/components/ILIAS/UI/src/examples/Symbol/Glyph/Location/location.php b/components/ILIAS/UI/src/examples/Symbol/Glyph/Location/location.php new file mode 100644 index 000000000000..0030d719d998 --- /dev/null +++ b/components/ILIAS/UI/src/examples/Symbol/Glyph/Location/location.php @@ -0,0 +1,35 @@ + + * Example for rendering a Owner Glyph. + * + * expected output: > + * Standard: + * ILIAS shows a monochrome symbol on a grey background. + * + * Highlighted: + * ILIAS shows the same symbol, but it's highlighted particularly. + * --- + */ +function location() +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $glyph = $f->symbol()->glyph()->location(); + + //Showcase the various states of this Glyph + $list = $f->listing()->descriptive([ + "Active" => $glyph, + "Highlighted" => $glyph->withHighlight() + ]); + + return $renderer->render($list); +} diff --git a/components/ILIAS/UI/src/examples/Symbol/Glyph/Owner/owner.php b/components/ILIAS/UI/src/examples/Symbol/Glyph/Owner/owner.php new file mode 100644 index 000000000000..c5ec941b39db --- /dev/null +++ b/components/ILIAS/UI/src/examples/Symbol/Glyph/Owner/owner.php @@ -0,0 +1,35 @@ + + * Example for rendering a Owner Glyph. + * + * expected output: > + * Standard: + * ILIAS shows a monochrome symbol on a grey background. + * + * Highlighted: + * ILIAS shows the same symbol, but it's highlighted particularly. + * --- + */ +function owner() +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $glyph = $f->symbol()->glyph()->owner(); + + //Showcase the various states of this Glyph + $list = $f->listing()->descriptive([ + "Active" => $glyph, + "Highlighted" => $glyph->withHighlight() + ]); + + return $renderer->render($list); +} diff --git a/components/ILIAS/UI/src/examples/Symbol/Glyph/Presenter/presenter.php b/components/ILIAS/UI/src/examples/Symbol/Glyph/Presenter/presenter.php new file mode 100644 index 000000000000..6ef0e37a74db --- /dev/null +++ b/components/ILIAS/UI/src/examples/Symbol/Glyph/Presenter/presenter.php @@ -0,0 +1,35 @@ + + * Example for rendering a Presenter Glyph. + * + * expected output: > + * Standard: + * ILIAS shows a monochrome symbol on a grey background. + * + * Highlighted: + * ILIAS shows the same symbol, but it's highlighted particularly. + * --- + */ +function presenter() +{ + global $DIC; + $f = $DIC->ui()->factory(); + $renderer = $DIC->ui()->renderer(); + + $glyph = $f->symbol()->glyph()->presenter(); + + //Showcase the various states of this Glyph + $list = $f->listing()->descriptive([ + "Active" => $glyph, + "Highlighted" => $glyph->withHighlight() + ]); + + return $renderer->render($list); +} diff --git a/components/ILIAS/UI/src/examples/Table/Column/LinkListing/base.php b/components/ILIAS/UI/src/examples/Table/Column/Listing/base.php similarity index 69% rename from components/ILIAS/UI/src/examples/Table/Column/LinkListing/base.php rename to components/ILIAS/UI/src/examples/Table/Column/Listing/base.php index 5fd76c9f9538..7dafa2327fa1 100755 --- a/components/ILIAS/UI/src/examples/Table/Column/LinkListing/base.php +++ b/components/ILIAS/UI/src/examples/Table/Column/Listing/base.php @@ -18,7 +18,7 @@ declare(strict_types=1); -namespace ILIAS\UI\examples\Table\Column\LinkListing; +namespace ILIAS\UI\examples\Table\Column\Listing; use ILIAS\UI\Component\Table as I; use ILIAS\Data\Range; @@ -32,28 +32,39 @@ */ function base(): string { + /** @var \ILIAS\DI\Container $DIC */ global $DIC; $f = $DIC->ui()->factory(); $r = $DIC->ui()->renderer(); $columns = [ - 'l1' => $f->table()->column()->linkListing("a link list column") + 'l1' => $f->table()->column()->listing('A list column') ]; - $some_link = $f->link()->standard('ILIAS Homepage', 'http://www.ilias.de'); - $some_linklisting = $f->listing()->unordered([$some_link, $some_link, $some_link]); - - $dummy_records = [ - ['l1' => $some_linklisting], - ['l1' => $some_linklisting] + $records = [ + [ + 'l1' => $f->listing()->unordered([ + 'Apples', + 'Oranges', + 'Bananas', + 'Pears' + ]) + ], + [ + 'l1' => $f->listing()->unordered([ + 'Bun', + 'Croissant', + 'Pumpernickel' + ]) + ] ]; - $data_retrieval = new class ($dummy_records) implements I\DataRetrieval { + $data_retrieval = new class ($records) implements I\DataRetrieval { protected array $records; - public function __construct(array $dummy_records) + public function __construct(array $records) { - $this->records = $dummy_records; + $this->records = $records; } public function getRows( @@ -80,7 +91,7 @@ public function getTotalRowCount( } }; - $table = $f->table()->data($data_retrieval, 'Link List Columns', $columns) + $table = $f->table()->data($data_retrieval, 'List Columns', $columns) ->withRequest($DIC->http()->request()); return $r->render($table); } diff --git a/components/ILIAS/UI/src/templates/default/Entity/tpl.entity.html b/components/ILIAS/UI/src/templates/default/Entity/tpl.entity.html index 42c1276d76d1..7dc8de0067b1 100755 --- a/components/ILIAS/UI/src/templates/default/Entity/tpl.entity.html +++ b/components/ILIAS/UI/src/templates/default/Entity/tpl.entity.html @@ -1,46 +1,76 @@ -
- -
{BLOCKING_CONDITIONS}
- +
+ + + - -
{ACTIONS}
- + - - -
{PRIMARY_IDENTIFIER}
- - + -
{PERSONAL_STATUS}
+
{PERSONAL_STATUS}
+ +
{WORKFLOW_ACTIONS}
+ + -
{MAIN_DETAILS}
+
{MAIN_DETAILS}
-
{AVAILABILITY}
+
{AVAILABILITY}
-
{DETAILS}
+
{DETAILS}
- -
{REACTIONS}
- + - - - -
+ +
+
+
+
+ +
{REACTIONS}
+ +
+
+
+ + + +
+
+
+ + diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.entitylistinggrid.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.entitylistinggrid.html new file mode 100644 index 000000000000..18f073d65d9b --- /dev/null +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.entitylistinggrid.html @@ -0,0 +1,5 @@ +
    + +
  • {ENTITY}
  • + +
diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.inline.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.inline.html new file mode 100644 index 000000000000..04e9b86140b3 --- /dev/null +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.inline.html @@ -0,0 +1,5 @@ +
    + +
  • {ITEM}
  • + +
diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.ordered.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.ordered.html index c1a592268983..f0797ccc861e 100755 --- a/components/ILIAS/UI/src/templates/default/Listing/tpl.ordered.html +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.ordered.html @@ -1,5 +1,5 @@ -
    +id="{ID}">
  1. {ITEM}
  2. -
\ No newline at end of file + diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.propertylisting.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.propertylisting.html index ac941ceb9b36..52b4c8e05011 100755 --- a/components/ILIAS/UI/src/templates/default/Listing/tpl.propertylisting.html +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.propertylisting.html @@ -2,9 +2,17 @@
- {LABEL} +
{LABEL}
- {VALUE} + + +
{LONG_VALUE}
+ + +
{SHORT_VALUE}
+
diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.table_column_context.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.table_column_context.html new file mode 100644 index 000000000000..0cbb547f6c7e --- /dev/null +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.table_column_context.html @@ -0,0 +1,10 @@ +
+ <{LIST_TYPE} id="{ID}" data-max-items="{DISPLAY_LIMIT}"> + +
  • {ITEM}
  • + + + +
    diff --git a/components/ILIAS/UI/src/templates/default/Listing/tpl.unordered.html b/components/ILIAS/UI/src/templates/default/Listing/tpl.unordered.html index 594abfe9a720..3239b2ed9924 100755 --- a/components/ILIAS/UI/src/templates/default/Listing/tpl.unordered.html +++ b/components/ILIAS/UI/src/templates/default/Listing/tpl.unordered.html @@ -1,5 +1,5 @@ -
      +id="{ID}">
    • {ITEM}
    • -
    \ No newline at end of file + diff --git a/components/ILIAS/UI/src/templates/default/MainControls/tpl.footer.html b/components/ILIAS/UI/src/templates/default/MainControls/tpl.footer.html index d1b5aecd5b98..7f4b0aa41b62 100755 --- a/components/ILIAS/UI/src/templates/default/MainControls/tpl.footer.html +++ b/components/ILIAS/UI/src/templates/default/MainControls/tpl.footer.html @@ -1,6 +1,6 @@
    -
    @@ -193,7 +193,7 @@ public function testRenderWithAdditionalIcon(): void $expected_html = << -
    - +
    EOT; $this->assertEquals($this->brutallyTrimHTML($expected), $this->brutallyTrimHTML($actual)); diff --git a/components/ILIAS/UI/tests/Component/Table/PresentationTest.php b/components/ILIAS/UI/tests/Component/Table/PresentationTest.php index a565735cf06d..9b26f13c4983 100755 --- a/components/ILIAS/UI/tests/Component/Table/PresentationTest.php +++ b/components/ILIAS/UI/tests/Component/Table/PresentationTest.php @@ -30,6 +30,8 @@ */ class PresentationTest extends TableTestBase { + use LanguageStubs; + private function getFactory(): I\Component\Table\Factory { return new I\Component\Table\Factory( @@ -98,9 +100,14 @@ public function testRowConstruction(): void public function getUIFactory(): NoUIFactory { - $factory = new class () extends NoUIFactory { + $factory = new class ($this->createRelayArgumentLanguageStub()) extends NoUIFactory { public I\Component\SignalGenerator $sig_gen; + public function __construct( + protected \ILIAS\Language\Language $language, + ) { + } + public function button(): I\Component\Button\Factory { return new I\Component\Button\Factory(); @@ -109,7 +116,7 @@ public function symbol(): I\Component\Symbol\Factory { return new I\Component\Symbol\Factory( new I\Component\Symbol\Icon\Factory(), - new I\Component\Symbol\Glyph\Factory(), + new I\Component\Symbol\Glyph\Factory($this->language), new I\Component\Symbol\Avatar\Factory() ); } diff --git a/components/ILIAS/UI/tests/Component/Table/TableRendererTestBase.php b/components/ILIAS/UI/tests/Component/Table/TableRendererTestBase.php index 6b0a2d778651..728bcc1cc7bd 100644 --- a/components/ILIAS/UI/tests/Component/Table/TableRendererTestBase.php +++ b/components/ILIAS/UI/tests/Component/Table/TableRendererTestBase.php @@ -31,6 +31,8 @@ */ class TableRendererTestBase extends TableTestBase { + use LanguageStubs; + protected function getActionFactory() { return new I\Table\Action\Factory(); @@ -62,9 +64,13 @@ public function getDataFactory(): Data\Factory public function getUIFactory(): NoUIFactory { - $factory = new class ($this->getTableFactory()) extends NoUIFactory { + $factory = new class ( + $this->getTableFactory(), + $this->createRelayArgumentLanguageStub(), + ) extends NoUIFactory { public function __construct( - protected Component\Table\Factory $table_factory + protected Component\Table\Factory $table_factory, + protected \ILIAS\Language\Language $language, ) { } public function button(): I\Button\Factory @@ -79,7 +85,7 @@ public function symbol(): I\Symbol\Factory { return new I\Symbol\Factory( new I\Symbol\Icon\Factory(), - new I\Symbol\Glyph\Factory(), + new I\Symbol\Glyph\Factory($this->language), new I\Symbol\Avatar\Factory() ); } diff --git a/components/ILIAS/UI/tests/Component/ViewControl/PaginationTest.php b/components/ILIAS/UI/tests/Component/ViewControl/PaginationTest.php index aa8df81bc1d2..5bb633d8daca 100755 --- a/components/ILIAS/UI/tests/Component/ViewControl/PaginationTest.php +++ b/components/ILIAS/UI/tests/Component/ViewControl/PaginationTest.php @@ -31,14 +31,21 @@ */ class PaginationTest extends ILIAS_UI_TestBase { + use LanguageStubs; + public function getUIFactory(): NoUIFactory { - return new class () extends NoUIFactory { + return new class ($this->createRelayArgumentLanguageStub()) extends NoUIFactory { + public function __construct( + protected \ILIAS\Language\Language $language, + ) { + } + public function symbol(): IC\Symbol\Factory { return new IC\Symbol\Factory( new IC\Symbol\Icon\Factory(), - new IC\Symbol\Glyph\Factory(), + new IC\Symbol\Glyph\Factory($this->language), new IC\Symbol\Avatar\Factory() ); } diff --git a/components/ILIAS/UI/tests/InitUIFramework.php b/components/ILIAS/UI/tests/InitUIFramework.php index 95fae03ffecc..b5425805726e 100755 --- a/components/ILIAS/UI/tests/InitUIFramework.php +++ b/components/ILIAS/UI/tests/InitUIFramework.php @@ -230,7 +230,9 @@ public function getRefreshIntervalInMs(): int ); }; $c["ui.factory.symbol.glyph"] = function ($c) { - return new ILIAS\UI\Implementation\Component\Symbol\Glyph\Factory(); + return new ILIAS\UI\Implementation\Component\Symbol\Glyph\Factory( + $c["lng"], + ); }; $c["ui.factory.symbol.icon"] = function ($c) { return new ILIAS\UI\Implementation\Component\Symbol\Icon\Factory(); @@ -379,6 +381,16 @@ public function getRefreshIntervalInMs(): int $c["help.text_retriever"], $c["ui.upload_limit_resolver"] ), + new ILIAS\UI\Implementation\Component\Listing\ListingRendererFactory( + $c["ui.factory"], + $c["ui.template_factory"], + $c["lng"], + $c["ui.javascript_binding"], + $c["ui.pathresolver"], + $c["ui.data_factory"], + $c["help.text_retriever"], + $c["ui.upload_limit_resolver"], + ), ) ) ); diff --git a/components/ILIAS/UI/tests/LanguageStubs.php b/components/ILIAS/UI/tests/LanguageStubs.php new file mode 100644 index 000000000000..cf9fba608749 --- /dev/null +++ b/components/ILIAS/UI/tests/LanguageStubs.php @@ -0,0 +1,46 @@ + + */ +trait LanguageStubs +{ + protected function createFixedLanguageStub(string $translation): Language&MockObject + { + $stub = $this->createMock(Language::class); + $stub->method('txt')->willReturn($translation); + return $stub; + } + + protected function createRelayArgumentLanguageStub(): Language&MockObject + { + $stub = $this->createMock(Language::class); + $stub->method('txt')->willReturnArgument(0); + return $stub; + } +} diff --git a/components/ILIAS/UI/tests/Renderer/FSLoaderTest.php b/components/ILIAS/UI/tests/Renderer/FSLoaderTest.php index 689fbfd80d76..634360242a54 100755 --- a/components/ILIAS/UI/tests/Renderer/FSLoaderTest.php +++ b/components/ILIAS/UI/tests/Renderer/FSLoaderTest.php @@ -41,6 +41,7 @@ class FSLoaderTest extends TestCase protected RendererFactory & MockObject $message_box_renderer_factory; protected RendererFactory & MockObject $form_renderer_factory; protected RendererFactory & MockObject $menu_renderer_factory; + protected RendererFactory & MockObject $list_renderer_factory; protected FSLoader $fs_loader; @@ -52,6 +53,7 @@ protected function setUp(): void $this->message_box_renderer_factory = $this->createMock(RendererFactory::class); $this->form_renderer_factory = $this->createMock(RendererFactory::class); $this->menu_renderer_factory = $this->createMock(RendererFactory::class); + $this->list_renderer_factory = $this->createMock(RendererFactory::class); $this->fs_loader = new FSLoader( $this->default_renderer_factory, @@ -60,6 +62,7 @@ protected function setUp(): void $this->message_box_renderer_factory, $this->form_renderer_factory, $this->menu_renderer_factory, + $this->list_renderer_factory, ); parent::setUp(); diff --git a/components/ILIAS/UICore/classes/class.ilGlobalTemplate.php b/components/ILIAS/UICore/classes/class.ilGlobalTemplate.php index b218923e4c1c..acda194b103b 100755 --- a/components/ILIAS/UICore/classes/class.ilGlobalTemplate.php +++ b/components/ILIAS/UICore/classes/class.ilGlobalTemplate.php @@ -192,6 +192,8 @@ protected function getMessageTextForType(string $type): ?string public function addJavaScript(string $a_js_file, bool $a_add_version_parameter = true, int $a_batch = 2): void { + $a_js_file = $this->toWebPath($a_js_file); + // three batches currently if ($a_batch < 1 || $a_batch > 3) { $a_batch = 2; @@ -317,6 +319,8 @@ protected function fillJavascriptFile(string $file, string $vers): void public function addCss(string $a_css_file, string $media = "screen"): void { + $a_css_file = $this->toWebPath($a_css_file); + if (!array_key_exists($a_css_file . $media, $this->css_files)) { $this->css_files[$a_css_file . $media] = [ "file" => $a_css_file, @@ -325,6 +329,27 @@ public function addCss(string $a_css_file, string $media = "screen"): void } } + /** + * Resources are delivered relative to the web root, but components which know their own + * location - plugins in particular, see ilPlugin::getDirectory() - only have an absolute + * one at hand. Such a path would be written into the markup verbatim and could never be + * requested by a browser, so cut the web root off instead. + */ + private function toWebPath(string $path): string + { + if (!defined('ILIAS_ABSOLUTE_PATH')) { + return $path; + } + + $web_root = rtrim(ILIAS_ABSOLUTE_PATH, '/') . '/public/'; + + if (str_starts_with($path, $web_root)) { + return substr($path, strlen($web_root)); + } + + return $path; + } + public function addInlineCss(string $a_css, string $media = "screen"): void { $this->inline_css[] = [ diff --git a/components/ILIAS/User/classes/Gallery/class.ilUsersGalleryParticipants.php b/components/ILIAS/User/classes/Gallery/class.ilUsersGalleryParticipants.php index c1843a755106..9ee49ceb882e 100755 --- a/components/ILIAS/User/classes/Gallery/class.ilUsersGalleryParticipants.php +++ b/components/ILIAS/User/classes/Gallery/class.ilUsersGalleryParticipants.php @@ -43,6 +43,10 @@ protected function getUsers(array $usr_ids): array continue; } + if (!ilObjUser::userExists([$usr_id])) { + continue; + } + if (!($user = ilObjectFactory::getInstanceByObjId($usr_id, false)) || !($user instanceof ilObjUser)) { continue; } diff --git a/components/ILIAS/User/classes/class.ilObjUser.php b/components/ILIAS/User/classes/class.ilObjUser.php index 9a30e81a24a4..f7e6d356f8ea 100755 --- a/components/ILIAS/User/classes/class.ilObjUser.php +++ b/components/ILIAS/User/classes/class.ilObjUser.php @@ -3123,7 +3123,7 @@ public static function _lookupFeedHash( [$a_user_id] ); if ($rec = $ilDB->fetchAssoc($set)) { - if (strlen($rec['feed_hash']) == 32) { + if (strlen($rec['feed_hash'] ?? '') == 32) { return $rec['feed_hash']; } elseif ($a_create) { $hash = md5(random_int(1, 9999999) + str_replace(' ', '', microtime())); diff --git a/components/ILIAS/User/classes/class.ilObjUserFolderGUI.php b/components/ILIAS/User/classes/class.ilObjUserFolderGUI.php index 4c2c429bc94b..260c86ee91a9 100755 --- a/components/ILIAS/User/classes/class.ilObjUserFolderGUI.php +++ b/components/ILIAS/User/classes/class.ilObjUserFolderGUI.php @@ -58,6 +58,8 @@ class ilObjUserFolderGUI extends ilObjectGUI { use ilTableCommandHelper; + private const string REDIRECT_TO_SETTINGS_CMD = 'showSettings'; + public const USER_FIELD_TRANSLATION_MAPPING = [ 'visible' => 'user_visible_in_profile', 'changeable' => 'changeable', @@ -335,6 +337,10 @@ public function executeCommand(): void $this->ctrl->forwardCommand($perm_gui); break; default: + if ($cmd === self::REDIRECT_TO_SETTINGS_CMD) { + $this->ctrl->redirectByClass(AdminSettingsGUI::class, 'show'); + } + if (!$cmd) { $cmd = 'view'; } @@ -815,8 +821,8 @@ public function confirmdeleteObject(): void 'show' ); } else { - $this->ctrl->redirect( - $this, + $this->ctrl->redirectByClass( + self::class, 'view' ); } @@ -2315,7 +2321,7 @@ public function addToExternalSettingsForm(int $a_form_id): array // Missing arra ]; $fields['ps_security_protection'] = [null, null, $subitems]; - return [['generalSettings', $fields]]; + return [[self::REDIRECT_TO_SETTINGS_CMD, $fields]]; } return []; } diff --git a/components/ILIAS/User/src/Setup/Agent.php b/components/ILIAS/User/src/Setup/Agent.php index dde989898e59..ab90067f3602 100755 --- a/components/ILIAS/User/src/Setup/Agent.php +++ b/components/ILIAS/User/src/Setup/Agent.php @@ -79,7 +79,7 @@ public function getUpdateObjective(?Setup\Config $config = null): Setup\Objectiv 'Updates for User', false, new \ilDatabaseUpdateStepsExecutedObjective( - new DBUpdateSteps11() + new DBUpdateSteps12() ), new AddReadAllAccountsPermissionObjective(), new CollectSettingsObjective($this->user_settings_contributions), @@ -92,7 +92,7 @@ public function getStatusObjective(Setup\Metrics\Storage $storage): Setup\Object { return new \ilDatabaseUpdateStepsMetricsCollectedObjective( $storage, - new DBUpdateSteps11() + new DBUpdateSteps12() ); } diff --git a/components/ILIAS/User/src/Setup/DBUpdateSteps11.php b/components/ILIAS/User/src/Setup/DBUpdateSteps11.php deleted file mode 100755 index 65af574b8c4a..000000000000 --- a/components/ILIAS/User/src/Setup/DBUpdateSteps11.php +++ /dev/null @@ -1,586 +0,0 @@ -db = $db; - $this->uuid_factory = new UUIDFactory(); - } - - private function insertSetting( - string $keyword, - string $value - ): void { - if ($this->db->fetchObject( - $this->db->query( - "SELECT COUNT(*) cnt FROM settings WHERE module = 'common' AND keyword='{$keyword}'" - ) - )?->cnt > 0 - ) { - return; - } - - $this->db->insert( - 'settings', - [ - 'module' => [ - \ilDBConstants::T_TEXT, - 'common' - ], - 'keyword' => [ - \ilDBConstants::T_TEXT, - $keyword - ], - 'value' => [ - \ilDBConstants::T_TEXT, - $value - ], - ] - ); - } - - private function migrateBadges( - string $old_value, - string $new_value - ): void { - $query = $this->db->query("SELECT id, conf FROM badge_badge WHERE type_id='user/profile' AND conf LIKE '%$old_value%'"); - while (($badge = $this->db->fetchObject($query)) !== null) { - $config_array = unserialize($badge->conf, ['allowed_classes' => false]); - if (!array_key_exists('profile', $config_array)) { - continue; - } - $config_array['profile'] = array_map( - static function (string $v) use ($old_value, $new_value): string { - if ($v !== "chk_{$old_value}") { - return $v; - } - - return "chk_{$new_value}"; - }, - $config_array['profile'] - ); - $this->db->update( - 'badge_badge', - [ - 'conf' => [\ilDBConstants::T_TEXT, serialize($config_array)] - ], - [ - 'id' => [\ilDBConstants::T_INTEGER, $badge->id] - ] - ); - } - } - - public function step_1(): void - { - if (!$this->db->tableColumnExists('mail_template', 'att_rid')) { - $this->db->addTableColumn( - 'mail_template', - 'att_rid', - [ - 'type' => \ilDBConstants::T_TEXT, - 'length' => 64 - ] - ); - } - } - - public function step_2(): void - { - if ($this->db->tableExists('usr_data_multi') - && !$this->db->tableExists('usr_profile_data')) { - $this->db->renameTable( - 'usr_data_multi', - 'usr_profile_data' - ); - } - if ($this->db->tableExists('usr_profile_data')) { - $this->db->modifyTableColumn('usr_profile_data', 'value', ['type' => \ilDBConstants::T_CLOB]); - } - if ($this->db->sequenceExists('usr_profile_data')) { - $this->db->dropSequence('usr_profile_data'); - } - if ($this->db->tableExists('usr_profile_data') - && $this->db->tableColumnExists('usr_profile_data', 'id')) { - $this->db->dropTableColumn('usr_profile_data', 'id'); - } - if ($this->db->tableExists('usr_profile_data') - && !$this->db->indexExistsByFields('usr_profile_data', ['usr_id', 'field_id'])) { - $this->db->addIndex('usr_profile_data', ['usr_id', 'field_id'], 'uf'); - } - } - - public function step_3(): void - { - if ($this->db->tableExists('udf_data')) { - $this->db->dropTable('udf_data'); - } - - if ($this->db->sequenceExists('udf_definition')) { - /* - * 2025-07-17, sk: This needs to be done here, as we absolutely need - * the change to be ready for the next steps - */ - $this->db->modifyTableColumn('ldap_attribute_mapping', 'keyword', ['length' => 68]); - $this->db->modifyTableColumn('settings', 'keyword', ['length' => 74]); - - $this->db->renameTableColumn('udf_definition', 'field_id', 'old_field_id'); - $this->db->manipulate('ALTER TABLE udf_definition ADD COLUMN field_id VARCHAR(64) NOT NULL FIRST'); - $this->db->modifyTableColumn('udf_clob', 'field_id', ['type' => 'text', 'length' => 64]); - $this->db->modifyTableColumn('udf_text', 'field_id', ['type' => 'text', 'length' => 64]); - $fields_query = $this->db->query('SELECT old_field_id FROM udf_definition'); - while (($row = $this->db->fetchObject($fields_query))) { - $uuid = $this->uuid_factory->uuid4AsString(); - $this->db->manipulate( - "UPDATE udf_definition SET field_id = '{$uuid}' WHERE old_field_id = '{$row->old_field_id}'" - ); - $this->db->manipulate( - "UPDATE udf_clob SET field_id = '{$uuid}' WHERE field_id = '{$row->old_field_id}'" - ); - $this->db->manipulate( - "UPDATE udf_text SET field_id = '{$uuid}' WHERE field_id = '{$row->old_field_id}'" - ); - $this->db->manipulate( - "UPDATE ldap_attribute_mapping SET keyword = 'udf_{$uuid}' WHERE keyword = 'udf_{$row->old_field_id}'" - ); - $this->db->manipulate( - "UPDATE settings SET keyword = 'pmap_udf_{$uuid}' WHERE keyword = 'pmap_udf_{$row->old_field_id}'" - ); - $this->db->manipulate( - "UPDATE settings SET keyword = 'pumap_udf_{$uuid}' WHERE keyword = 'pumap_udf_{$row->old_field_id}'" - ); - - $this->migrateBadges("udf_{$row->old_field_id}", $uuid); - } - $this->db->dropTableColumn('udf_definition', 'old_field_id'); - $this->db->addPrimaryKey('udf_definition', ['field_id']); - $this->db->dropSequence('udf_definition'); - } - } - - public function step_4(): void - { - if ($this->db->tableExists('udf_text')) { - $this->db->manipulate('INSERT INTO usr_profile_data SELECT * FROM udf_text'); - $this->db->dropTable('udf_text'); - } - - if ($this->db->tableExists('udf_clob')) { - $this->db->manipulate('INSERT INTO usr_profile_data SELECT * FROM udf_clob'); - $this->db->dropTable('udf_clob'); - } - } - - public function step_5(): void - { - if (!$this->db->tableExists('usr_field_config')) { - $this->db->createTable( - 'usr_field_config', - [ - 'field_id' => [ - 'type' => \ilDBConstants::T_TEXT, - 'length' => 64, - 'notnull' => true - ], - 'visible_in_registration' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'visible_to_user' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'visible_in_lua' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'visible_in_crss' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'visible_in_grps' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'visible_in_prgs' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'changeable_by_user' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'changeable_in_lua' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'required' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'export' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'searchable' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - 'available_in_certs' => [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true - ], - ] - ); - $this->db->addPrimaryKey('usr_field_config', ['field_id']); - $this->db->insert( - 'usr_field_config', - [ - 'field_id' => [\ilDBConstants::T_TEXT, 'location'], - 'visible_in_registration' => [\ilDBConstants::T_INTEGER, 0], - 'visible_to_user' => [\ilDBConstants::T_INTEGER, 1], - 'visible_in_lua' => [\ilDBConstants::T_INTEGER, 0], - 'visible_in_crss' => [\ilDBConstants::T_INTEGER, 0], - 'visible_in_grps' => [\ilDBConstants::T_INTEGER, 0], - 'visible_in_prgs' => [\ilDBConstants::T_INTEGER, 0], - 'changeable_by_user' => [\ilDBConstants::T_INTEGER, 1], - 'changeable_in_lua' => [\ilDBConstants::T_INTEGER, 0], - 'required' => [\ilDBConstants::T_INTEGER, 0], - 'export' => [\ilDBConstants::T_INTEGER, 0], - 'searchable' => [\ilDBConstants::T_INTEGER, 0], - 'available_in_certs' => [\ilDBConstants::T_INTEGER, 0] - ] - ); - } - } - - public function step_6(): void - { - $this->db->modifyTableColumn( - 'udf_definition', - 'field_type', - [ - 'type' => \ilDBConstants::T_TEXT, - 'length' => 4000 - ] - ); - $this->db->update( - 'udf_definition', - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - \ILIAS\User\Profile\Fields\Custom\Text::class - ] - ], - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - '1' - ] - ] - ); - $this->db->update( - 'udf_definition', - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - \ILIAS\User\Profile\Fields\Custom\Select::class - ] - ], - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - '2' - ] - ] - ); - $this->db->update( - 'udf_definition', - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - \ILIAS\User\Profile\Fields\Custom\TextArea::class - ] - ], - [ - 'field_type' => [ - \ilDBConstants::T_TEXT, - '3' - ] - ] - ); - } - - public function step_7(): void - { - if (!$this->db->tableColumnExists('udf_definition', 'section')) { - $this->db->addTableColumn( - 'udf_definition', - 'section', - [ - 'type' => \ilDBConstants::T_TEXT, - 'length' => 64, - 'notnull' => true, - 'default' => AvailableSections::Other->value - ] - ); - } - } - - public function step_8(): void - { - if ($this->db->fetchObject( - $this->db->query( - 'SELECT COUNT(*) cnt FROM settings WHERE module = "common"' . PHP_EOL - . 'AND keyword="usr_settings_changeable_by_user_new_mail_notification"' - ) - )?->cnt <= 0 - ) { - $this->db->manipulate( - 'INSERT INTO settings (module, keyword, value) VALUES ' - . '("common", "usr_settings_changeable_by_user_new_mail_notification", "1"), ' - . '("common", "usr_settings_changeable_lua_new_mail_notification", "1"), ' - . '("common", "usr_settings_export_new_mail_notification", "1")' - ); - } - - $renamed_fields = [ - 'hide_own_online_status' => 'awrn_user_show', - 'bs_allow_to_contact_me' => 'allow_contact_request', - 'mail_incoming_mail' => 'incoming_mail', - 'skin_style' => 'style', - 'upload' => 'avatar', - 'sel_country' => 'selcountry', - 'country' => 'old_country', - 'selcountry' => 'country' - ]; - - foreach ($renamed_fields as $old_id => $new_id) { - $settings_query = $this->db->query( - "SELECT keyword FROM settings WHERE {$this->db->like('keyword', \ilDBConstants::T_TEXT, "%_{$old_id}")}" - ); - while (($row = $this->db->fetchObject($settings_query)) !== null) { - if ($row->keyword === 'admin_country') { - continue; - } - $this->db->update( - 'settings', - [ - 'keyword' => [ - \ilDBConstants::T_TEXT, - str_replace("_{$old_id}", "_{$new_id}", $row->keyword) - ] - ], - [ - 'module' => [ - \ilDBConstants::T_TEXT, - 'common' - ], - 'keyword' => [ - \ilDBConstants::T_TEXT, - $row->keyword - ] - ] - ); - } - - $user_query = $this->db->query( - "SELECT DISTINCT keyword FROM usr_pref WHERE {$this->db->like('keyword', \ilDBConstants::T_TEXT, "%_{$old_id}")}" - ); - while (($row = $this->db->fetchObject($user_query)) !== null) { - $this->db->update( - 'usr_pref', - [ - 'keyword' => [ - \ilDBConstants::T_TEXT, - str_replace("_{$old_id}", "_{$new_id}", $row->keyword) - ] - ], - [ - 'keyword' => [ - \ilDBConstants::T_TEXT, - $row->keyword - ] - ] - ); - } - } - - $this->migrateBadges('upload', 'avatar'); - $this->migrateBadges('selcountry', 'country'); - } - - public function step_9(): void - { - $query = $this->db->query( - "SELECT usr_id, keyword FROM usr_pref WHERE {$this->db->like('keyword', \ilDBConstants::T_TEXT, 'public_udf_%')}" - ); - while (($row = $this->db->fetchObject($query)) !== null) { - $this->db->update( - 'usr_pref', - [ - 'keyword' => [ - \ilDBConstants::T_TEXT, - str_replace('public_udf_', 'public_', $row->keyword) - ] - ], - [ - 'usr_id' => [ - \ilDBConstants::T_INTEGER, - $row->usr_id - ], - 'keyword' => [ - \ilDBConstants::T_TEXT, - $row->keyword - ] - ] - ); - } - } - - public function step_10(): void - { - if ($this->db->tableColumnExists('usr_data', 'sel_country')) { - $this->db->renameTableColumn('usr_data', 'country', 'old_country'); - $this->db->renameTableColumn('usr_data', 'sel_country', 'country'); - } - } - - public function step_11(): void - { - $this->db->modifyTableColumn('usr_pref', 'keyword', ['length' => 74]); - } - - public function step_12(): void - { - if ($this->db->fetchObject( - $this->db->query( - 'SELECT COUNT(*) cnt FROM settings WHERE module = "common"' . PHP_EOL - . 'AND keyword="usr_settings_changeable_by_user_starting_point"' - ) - )?->cnt <= 0 - ) { - $this->db->update( - 'settings', - [ - 'keyword' => [ - \ilDBConstants::T_TEXT, - 'usr_settings_changeable_by_user_starting_point' - ] - ], - [ - 'module' => [ - \ilDBConstants::T_TEXT, - 'common' - ], - 'keyword' => [ - \ilDBConstants::T_TEXT, - 'usr_starting_point_personal' - ] - ] - ); - } else { - $this->db->manipulate( - 'DELETE FROM settings WHERE module = "common" AND keyword= "usr_starting_point_personal"' - ); - } - - $this->insertSetting('usr_settings_changeable_lua_starting_point', '1'); - $this->insertSetting('usr_settings_export_starting_point', '1'); - - foreach ([ - 'last_visited', - 'timezone', - 'date_format', - 'time_format' - ] as $setting) { - $this->insertSetting("usr_settings_changeable_by_user_{$setting}", '1'); - $this->insertSetting("usr_settings_changeable_lua_{$setting}", '1'); - $this->insertSetting("usr_settings_export_{$setting}", '1'); - } - } - - public function step_13(): void - { - $this->db->update( - 'usr_pref', - ['keyword' => [\ilDBConstants::T_TEXT, 'public_avatar']], - ['keyword' => [\ilDBConstants::T_TEXT, 'public_upload']] - ); - } - - public function step_14(): void - { - if (!$this->db->tableColumnExists('usr_data', 'expiration_reminder_sent')) { - $this->db->addTableColumn( - 'usr_data', - 'expiration_reminder_sent', - [ - 'type' => \ilDBConstants::T_INTEGER, - 'length' => 1, - 'notnull' => true, - 'default' => 0 - ] - ); - } - - if ($this->db->tableColumnExists('usr_data', 'time_limit_message')) { - $this->db->update( - 'usr_data', - [ - 'expiration_reminder_sent' => [ - \ilDBConstants::T_INTEGER, - 1 - ] - ], - [ - 'time_limit_message' => [ - \ilDBConstants::T_TEXT, - 1 - ] - ] - ); - $this->db->dropTableColumn('usr_data', 'time_limit_message'); - } - - } -} diff --git a/components/ILIAS/User/src/Setup/DBUpdateSteps12.php b/components/ILIAS/User/src/Setup/DBUpdateSteps12.php new file mode 100755 index 000000000000..ae13dd802dc6 --- /dev/null +++ b/components/ILIAS/User/src/Setup/DBUpdateSteps12.php @@ -0,0 +1,42 @@ +db = $db; + $this->uuid_factory = new UUIDFactory(); + } + + public function step_1(): void + { + if ($this->db->tableExists('udf_field_id_map')) { + $this->db->dropTable('udf_field_id_map'); + } + } +} diff --git a/components/ILIAS/WebResource/classes/Repository/class.ilWebLinkDatabaseRepository.php b/components/ILIAS/WebResource/classes/Repository/class.ilWebLinkDatabaseRepository.php index 5bd4ff628c2b..014da3954889 100755 --- a/components/ILIAS/WebResource/classes/Repository/class.ilWebLinkDatabaseRepository.php +++ b/components/ILIAS/WebResource/classes/Repository/class.ilWebLinkDatabaseRepository.php @@ -134,7 +134,7 @@ public function createList(ilWebLinkDraftList $list): ilWebLinkList self::LISTS_TABLE, [ 'webr_id' => ['integer', $new_list->getWebrId()], - 'title' => ['text', $new_list->getTitle()], + 'title' => ['text', mb_substr($new_list->getTitle(), 0, 127)], 'description' => ['text', $new_list->getDescription() ?? ''], 'create_date' => ['integer', $new_list->getCreateDate() ->getTimestamp()], @@ -422,7 +422,7 @@ public function updateList( $this->db->update( self::LISTS_TABLE, [ - 'title' => ['text', $drafted_list->getTitle()], + 'title' => ['text', mb_substr($drafted_list->getTitle(), 0, 127)], 'description' => ['text', $drafted_list->getDescription() ?? ''], 'last_update' => ['integer', $this->getCurrentTime()] ], diff --git a/components/ILIAS/WebResource/tests/ilWebResourceDatabaseRepositoryTest.php b/components/ILIAS/WebResource/tests/ilWebResourceDatabaseRepositoryTest.php index edd1660cb667..624fc6274e74 100644 --- a/components/ILIAS/WebResource/tests/ilWebResourceDatabaseRepositoryTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceDatabaseRepositoryTest.php @@ -20,6 +20,7 @@ use PHPUnit\Framework\TestCase; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; use ILIAS\DI\Container; /** @@ -44,9 +45,7 @@ protected function initDependencies(): void $this->dic = is_object($DIC) ? clone $DIC : $DIC; $GLOBALS['DIC'] = new Container(); - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user = $this->createMock(ilObjUser::class); $user->expects($this->never()) ->method($this->anything()); @@ -55,10 +54,10 @@ protected function initDependencies(): void } /** - * @param ilDBInterface&MockObject $mock_db + * @param ilDBInterface&Stub $mock_db * @param int $webr_id * @param int $current_time - * @param DateTimeImmutable&MockObject[] $datetimes + * @param DateTimeImmutable[] $datetimes * @return void */ protected function setGlobalDBAndRepo( @@ -93,7 +92,7 @@ protected function setGlobalDBAndRepo( ->willReturnOnConsecutiveCalls(...$datetimes); } - protected function setGlobal(string $name, MockObject $obj): void + protected function setGlobal(string $name, MockObject|Stub $obj): void { global $DIC; @@ -112,14 +111,11 @@ protected function tearDown(): void } /** - * @return DateTimeImmutable&MockObject + * @return DateTimeImmutable */ - protected function getNewDateTimeMock(int $timestamp): MockObject + protected function getNewDateTimeMock(int $timestamp): Stub { - $datetime = $this->getMockBuilder(DateTimeImmutable::class) - ->disableOriginalConstructor() - ->onlyMethods(['getTimestamp']) - ->getMock(); + $datetime = $this->createStub(DateTimeImmutable::class); $datetime->method('getTimestamp') ->willReturn($timestamp); @@ -134,9 +130,7 @@ protected function getNewDateTimeMock(int $timestamp): MockObject #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] public function testCreateExternalItem(): void { - $mock_db = $this->getMockBuilder(ilDBInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $mock_db = $this->createMock(ilDBInterface::class); $mock_db->expects($this->exactly(3)) ->method('nextId') @@ -260,9 +254,7 @@ public function testCreateExternalItem(): void #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] public function testCreateInternalItemWithBrokenParameter(): void { - $mock_db = $this->getMockBuilder(ilDBInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $mock_db = $this->createMock(ilDBInterface::class); $mock_db->expects($this->exactly(3)) ->method('nextId') ->willReturn(7, 71, 72); @@ -364,9 +356,7 @@ public function testCreateInternalItemWithBrokenParameter(): void #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] public function testCreateItemBrokenInternalLinkException(): void { - $mock_db = $this->getMockBuilder(ilDBInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $mock_db = $this->createMock(ilDBInterface::class); $mock_db->expects($this->once()) ->method('nextId') @@ -414,11 +404,10 @@ public function testCreateItemBrokenInternalLinkException(): void #[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)] #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] + #[\PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations] public function testCreateList(): void { - $mock_db = $this->getMockBuilder(ilDBInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $mock_db = $this->createMock(ilDBInterface::class); $mock_db->expects($this->never()) ->method('nextId'); @@ -465,11 +454,10 @@ public function testCreateList(): void #[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)] #[\PHPUnit\Framework\Attributes\RunInSeparateProcess] + #[\PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations] public function testCreateAllItemsInDraftContainer(): void { - $mock_db = $this->getMockBuilder(ilDBInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $mock_db = $this->createStub(ilDBInterface::class); $datetime1 = $this->getNewDateTimeMock(12345678); $datetime2 = $this->getNewDateTimeMock(12345678); diff --git a/components/ILIAS/WebResource/tests/ilWebResourceItemExternalTest.php b/components/ILIAS/WebResource/tests/ilWebResourceItemExternalTest.php index 9833325bff25..7da8a932c94f 100755 --- a/components/ILIAS/WebResource/tests/ilWebResourceItemExternalTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceItemExternalTest.php @@ -28,29 +28,21 @@ class ilWebResourceItemExternalTest extends TestCase { public function testGetResolvedLink(): void { - $param1 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['appendToLink', 'getValue']) - ->getMock(); + $param1 = $this->createMock(ilWebLinkParameter::class); $param1->expects($this->once()) ->method('appendToLink') ->with('target') ->willReturn('target?param1'); - $param1->expects($this->any()) - ->method('getValue') + $param1->method('getValue') ->willReturn(1); - $param2 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['appendToLink', 'getValue']) - ->getMock(); + $param2 = $this->createMock(ilWebLinkParameter::class); $param2->expects($this->once()) ->method('appendToLink') ->with('target?param1') ->willReturn('target?param1¶m2'); - $param2->expects($this->any()) - ->method('getValue') + $param2->method('getValue') ->willReturn(1); $item = new ilWebLinkItemExternal( diff --git a/components/ILIAS/WebResource/tests/ilWebResourceItemInternalTest.php b/components/ILIAS/WebResource/tests/ilWebResourceItemInternalTest.php index acbca2912cbb..2288ff26d1b0 100644 --- a/components/ILIAS/WebResource/tests/ilWebResourceItemInternalTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceItemInternalTest.php @@ -19,6 +19,7 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\Stub; /** * Unit tests for ilWebLinkItemInternal @@ -26,9 +27,9 @@ */ class ilWebResourceItemInternalTest extends TestCase { - protected function getItem(string $target, ilWebLinkParameter ...$parameters): ilWebLinkItemInternal + protected function getItem(string $target, ilWebLinkParameter ...$parameters): ilWebLinkItemInternal|Stub { - $item = $this->getMockBuilder(ilWebLinkItemInternal::class) + $item = $this->getStubBuilder(ilWebLinkItemInternal::class) ->setConstructorArgs([ 0, 1, @@ -41,7 +42,7 @@ protected function getItem(string $target, ilWebLinkParameter ...$parameters): i $parameters ]) ->onlyMethods(['appendParameter', 'getStaticLink']) - ->getMock(); + ->getStub(); $item->method('appendParameter')->willReturnCallback( fn(string $link, string $key, string $value) => $link . '.' . $key . '.' . $value ); @@ -53,18 +54,12 @@ protected function getItem(string $target, ilWebLinkParameter ...$parameters): i public function testGetResolvedLink(): void { - $param1 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['appendToLink']) - ->getMock(); + $param1 = $this->createMock(ilWebLinkParameter::class); $param1->expects($this->once()) ->method('appendToLink') ->with('tar:13') ->willReturn('tar:13?param1'); - $param2 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['appendToLink']) - ->getMock(); + $param2 = $this->createMock(ilWebLinkParameter::class); $param2->expects($this->once()) ->method('appendToLink') ->with('tar:13?param1') diff --git a/components/ILIAS/WebResource/tests/ilWebResourceItemTest.php b/components/ILIAS/WebResource/tests/ilWebResourceItemTest.php index 994a545eb0c8..5dc513e56d03 100755 --- a/components/ILIAS/WebResource/tests/ilWebResourceItemTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceItemTest.php @@ -28,10 +28,7 @@ class ilWebResourceItemTest extends TestCase { public function testToXML(): void { - $writer = $this->getMockBuilder(ilXmlWriter::class) - ->disableOriginalConstructor() - ->onlyMethods(['xmlStartTag', 'xmlElement', 'xmlEndTag']) - ->getMock(); + $writer = $this->createMock(ilXmlWriter::class); $writer->expects($this->once()) ->method('xmlStartTag') ->with('WebLink', [ @@ -58,17 +55,11 @@ public function testToXML(): void ->method('xmlEndTag') ->with('WebLink'); - $param1 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['toXML']) - ->getMock(); + $param1 = $this->createMock(ilWebLinkParameter::class); $param1->expects($this->once()) ->method('toXML') ->with($writer); - $param2 = $this->getMockBuilder(ilWebLinkParameter::class) - ->disableOriginalConstructor() - ->onlyMethods(['toXML']) - ->getMock(); + $param2 = $this->createMock(ilWebLinkParameter::class); $param2->expects($this->once()) ->method('toXML') ->with($writer); diff --git a/components/ILIAS/WebResource/tests/ilWebResourceItemsContainerTest.php b/components/ILIAS/WebResource/tests/ilWebResourceItemsContainerTest.php index 227eb742bd7f..061d3d229517 100644 --- a/components/ILIAS/WebResource/tests/ilWebResourceItemsContainerTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceItemsContainerTest.php @@ -19,7 +19,7 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; -use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Stub; /** * Unit tests for ilWebLinkItemsContainer @@ -28,23 +28,20 @@ class ilWebResourceItemsContainerTest extends TestCase { /** - * @return ilWebLinkItem&MockObject + * @return ilWebLinkItem&Stub */ protected function createItemMock( bool $internal, string $title, int $link_id - ): MockObject { + ): Stub { if ($internal) { $class = ilWebLinkItemInternal::class; } else { $class = ilWebLinkItemExternal::class; } - $item = $this->getMockBuilder($class) - ->disableOriginalConstructor() - ->onlyMethods(['getTitle','getLinkId']) - ->getMock(); + $item = $this->createStub($class); $item->method('getTitle')->willReturn($title); $item->method('getLinkId')->willReturn($link_id); diff --git a/components/ILIAS/WebResource/tests/ilWebResourceParameterTest.php b/components/ILIAS/WebResource/tests/ilWebResourceParameterTest.php index 76c72351e9dc..9709582ba2d7 100755 --- a/components/ILIAS/WebResource/tests/ilWebResourceParameterTest.php +++ b/components/ILIAS/WebResource/tests/ilWebResourceParameterTest.php @@ -29,10 +29,7 @@ class ilWebResourceParameterTest extends TestCase { protected function initDependencies(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->onlyMethods(['getLogin', 'getId', 'getMatriculation']) - ->getMock(); + $user = $this->createStub(ilObjUser::class); $user->method('getLogin')->willReturn('login'); $user->method('getId')->willReturn(37); $user->method('getMatriculation')->willReturn('matriculation'); @@ -40,10 +37,7 @@ protected function initDependencies(): void public function testAppendToLink(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->onlyMethods(['getLogin', 'getId', 'getMatriculation']) - ->getMock(); + $user = $this->createStub(ilObjUser::class); $user->method('getLogin')->willReturn('login'); $user->method('getId')->willReturn(37); $user->method('getMatriculation')->willReturn('matriculation'); @@ -108,9 +102,7 @@ public function testAppendToLink(): void public function testAppendToLinkException(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user = $this->createMock(ilObjUser::class); $user->expects($this->never()) ->method($this->anything()); @@ -122,16 +114,11 @@ public function testAppendToLinkException(): void public function testToXML(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user = $this->createMock(ilObjUser::class); $user->expects($this->never()) ->method($this->anything()); - $writer = $this->getMockBuilder(ilXmlWriter::class) - ->disableOriginalConstructor() - ->onlyMethods(['xmlElement']) - ->getMock(); + $writer = $this->createMock(ilXmlWriter::class); /* * willReturnCallback is a workaround to replace withConsecutive. * The return value is irrelevant here, but if an unexpected parameter @@ -192,9 +179,7 @@ public function testToXML(): void public function testGetInfo(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user = $this->createMock(ilObjUser::class); $user->expects($this->never()) ->method($this->anything()); @@ -229,9 +214,7 @@ public function testGetInfo(): void public function testGetInfoException(): void { - $user = $this->getMockBuilder(ilObjUser::class) - ->disableOriginalConstructor() - ->getMock(); + $user = $this->createMock(ilObjUser::class); $user->expects($this->never()) ->method($this->anything()); diff --git a/components/ILIAS/WebServices/ECS/classes/class.ilECSSettingsGUI.php b/components/ILIAS/WebServices/ECS/classes/class.ilECSSettingsGUI.php index c9e71df0c9f6..e5f9beede947 100755 --- a/components/ILIAS/WebServices/ECS/classes/class.ilECSSettingsGUI.php +++ b/components/ILIAS/WebServices/ECS/classes/class.ilECSSettingsGUI.php @@ -302,10 +302,10 @@ protected function initSettingsForm($a_mode = 'update'): void $this->form->addItem($ser); $pro = new ilSelectInputGUI($this->lng->txt('ecs_protocol'), 'protocol'); - // fixed to https - #$pro->setOptions(array(ilECSSetting::PROTOCOL_HTTP => $this->lng->txt('http'), - # ilECSSetting::PROTOCOL_HTTPS => $this->lng->txt('https'))); - $pro->setOptions(array(ilECSSetting::PROTOCOL_HTTPS => 'HTTPS')); + $pro->setOptions(array( + ilECSSetting::PROTOCOL_HTTPS => 'HTTPS', + ilECSSetting::PROTOCOL_HTTP => 'HTTP' + )); $pro->setValue($this->settings->getProtocol()); $pro->setRequired(true); $this->form->addItem($pro); diff --git a/components/ILIAS/setup_/PRIVACY.md b/components/ILIAS/setup_/PRIVACY.md deleted file mode 100644 index fc5dea0d9d2a..000000000000 --- a/components/ILIAS/setup_/PRIVACY.md +++ /dev/null @@ -1,28 +0,0 @@ -# Setup Privacy - -This documentation does not warrant completeness or correctness. Please report any -missing or wrong information using the [ILIAS issue tracker](https://mantis.ilias.de) -or contribute a fix via [Pull Request](../../../docs/development/contributing.md#pull-request-to-the-repositories). - -## Integrated Services - -- The Component component employs the following services, please consult the respective privacy.mds - - [Data](../../ILIAS/Data/PRIVACY.md) - - [Refinery](../../ILIAS/Refinery/PRIVACY.md) - - [Setup](../../ILIAS/Setup/PRIVACY.md) - - UI - - -## Data being stored - -- The Setup component itself does not store any personal data. - - -## Data presentation - -- The Setup itself does not present any personal data. - - -## Data Deletion - -- The Setup itself does not store or delete any personal data. diff --git a/components/ILIAS/setup_/README.md b/components/ILIAS/setup_/README.md deleted file mode 100755 index 5f8d87c6c2ac..000000000000 --- a/components/ILIAS/setup_/README.md +++ /dev/null @@ -1,571 +0,0 @@ -# Use the Command Line to Manage ILIAS - -The ILIAS command line app can be called via `php setup\setup.php`. It contains four -main commands to manage ILIAS installations: - -* `install` will [set an installation up](#install-ilias) -* `update` will [update an installation](#update-ilias) -* `status` will [report status of an installation](#report-status-of-ilias) -* `build` [recreates static assets](#build-static-assets) of an installation -* `achieve` [a named objective](#achieve-a-named-objective) of an agent -* `migrate` will run [needed migrations](#migrations) - -`install` and `update` also supply switches and options for a granular control of the inclusion of plugins: - -* `--skip-legacy-plugin -* There are also named objectives for **import** and **export**. ` will exclude the named legacy plugin from the command -* `--no-legacy-plugins` will exclude all plugins from the command -* `install ` (or `update ` respectively) will update or install the specified legacy plugin - -`install` requires a [configuration file](#about-the-config-file) to do the job. -`update` can be used without this file for updating the installation only, but is -required to transfer any modified setting from this file to the installation. -The app also supports a `help` command that lists arguments and -options of the available commands. - - -## Install ILIAS - -To install ILIAS with all plugins from the command line, call `php cli/setup.php install config.json` -from within the ILIAS folder you checked out from GitHub (or downloaded from elsewhere). -`config.json` can be the path to some [configuration file](#about-the-config-file) -which does not need to reside in the ILIAS folder. Also, `cli/setup.php` could be -the path to the `setup.php` when the command is called from somewhere else. - -You most probably want to execute the setup with the user that also executes your -webserver to avoid problems with filesystem permissions. The installation creates -directories and files that the webserver will need to read and sometimes even modify. -If you need to run setup as another user, please make sure that the user that executes -the webserver has the necessary filesystem permissions (e.g. by using chown), to -avoid some errors which may be difficult to troubleshoot. - -The setup will ask you to confirm some assumptions during the setup process, where -you will have to type `yes` (or `no`, of course). These checks can be overwritten -with the `--yes` option, which confirm any assumption for you automatically. - -There might be cases where the setup aborts for some reasons. These reasons might -require further actions on your side which the setup cannot perform. Make sure you -read messages from the setup carefully and act accordingly. If you do not change the -config file, it is safe to execute the installation process a second time for the -same installation a during the initial setup process. - -Do not discard the `config.json` you use for the installation, you will need it later -on to update that installation. If you want to overwrite specific fields in the -configuration file you can use the `--config="="` option, even several -times. If you e.g. use `--config="database.password=XYZ"` the field `database.password` -from the original config will be overwritten with `XYZ`. This allows to use one -configuration for multiple setups and overwrite it from the CLI or even share -configs without secrets. - -The setup will also install plugins of the installation, unless the plugin explicitely -defines that it cannot be installed via CLI setup. If you still want to skip a plugin -for installation, use the skip-option: `php cli/setup.php install --skip-legacy-plugin config.json`. -The option can be repeated to cover multiple plugins. If you want to skip plugins -alltogether, use the `--no-legacy-plugins` option. If you only want to install a specific -plugin, use `php cli/setup.php install config.json `. - -The install command also offers the option to import a zip file during setup. The -zip file must have been previously exported from another instance via export -(see [a name objective](#achieve-method)). -The command `php cli/setup.php install --import-file config.json` -will install the data from the export to this instance. - -## Update ILIAS - -To update ILIAS from the command line, call `php cli/setup.php update` -from within your ILIAS folder. This will update ILIAS as well as update the -database of the installation or do other necessary task for the update. -This does not update the source code. -If there are changes in your config.json file call `php cli/setup.php update config.json` -from within your ILIAS folder. This will also update the configuration of ILIAS according -to the provided configuration. - -Plugins are updated just as the core of ILIAS (if the plugin does not exclude itself), -where the plugins can be controlled with the same options as for `install`. - -Sometimes it might happen that the database update steps detect some edge case -or warn about a possible loss of data. In this case the update is aborted with -a message and can be resumed after the messages were read carefully and acted -upon. -You may use the `--ignore-db-update-messages` at your own risk if you want -to silence the messages. - -When an update step failed, you might get a message about inconsistent order -of already performed steps when resuming the setup: -> step 2 was started last, but step 1 was finished last. -> Aborting because of that mismatch. - -You may reset the records for those steps by running: -``` -php setup/setup.php achieve database.resetFailedSteps -``` -However, be sure to understand the cause for the failing steps and tend to it before -resetting and re-running the update. - -## Report Status of ILIAS - -Via `php cli/setup.php status` you can get a status of your ILIAS installation. -The command uses a best effort approach, so according to the status of your -system the output might contain more or less fields. When calling this for a -system where ILIAS was not installed, for example, the output only contains the -information that ilias is not installed. The command also reports on the configuration -of the installation. - -The output of the command is formatted as YAML to be easily readable by people and -machines. So we encourage you to use this command for monitoring your system and -also request status information via our feature process that you are interested in. - -Like for `install` and `update`, plugins are included here, but can be controlled -via options. - - -## Build Static Assets - -There are two types of assets that ILIAS needs to function: - -* **Artifacts** are source code files that are created based on the ILIAS source tree. -* The **Public Folder** is filled with resources from the ILIAS components to be - served on the web. - -You can refresh them by calling `php cli/setup.php build` from your -installation. Make sure you run the command with the webserver user or adjust -filesystem permissions later on, because the webserver will need to access the -generated files. Please do not invoke this function unless it is explicitly stated -in update or patch instructions or you know what you are doing. - -Like for `install` and `update`, plugins are included here, but can be controlled -via options. - - -## Achieve a Named Objective - -Some components of ILIAS will publish named objectives to the setup via their -agent. The most notorious example for this is the component `UICore` which provides -the objective `buildIlCtrlArtifacts` that will generate routing information for the -GUI. To achieve a single objective from an agent, e.g. for control structure reload, -run `php cli/setup.php achieve $AGENT_NAME.$OBJECTIVE_NAME`, e.g. -`php cli/setup.php achieve uicore.buildIlCtrlArtifacts` to generate the necessary -artifacts for the control structure. The agent might need to a config file to work, -which may be added as last parameter: -`php cli/setup.php achieve uicore.buildIlCtrlArtifacts config.json` - -There is also a named objective for **export**. The command -`php cli/setup.php achieve common.buildExportZip config.json` creates a zip file 'ILIAS_EXPORT.zip' at the -location of the call. The export also changes the name of the client directory to -'default' so that the import can work with the files. The objective -'ilFileSystemClientDirectoryRenamedObjective.php' takes care of the renaming. - -The ILIAS export mechanism can be extended with ExportHooks. This allows you to influence the exported database during the export. -The ExportHooks file must be a PHP file and can be placed anywhere. It only has to be ensured that ILIAS has access to this file. -The path to the file can either be set permanently in config.json under the namespace common. -```bash -"common" : { - "client_id" : "ilias", - "master_password" : "ilias", - "server_timezone" : "Europe/Berlin", - "export_hooks_path" : "/var/ilias/export.php" - } -``` -Or you can specify it once when calling up the export command. -```bash -php cli/setup.php achieve common.buildExportZip --config="common.export_hooks_path=/var/ilias/export.php" config.json -y -``` -This [mysqldump](https://github.com/ifsnop/mysqldump-php#changing-values-when-exporting) hooks can be used in the export hooks file. -An example file could look like this (the variable $dumper is indirectly available). -```php -setTransformTableRowHook(function ($tableName, array $row) { - if ($tableName === 'write_event') { - if ($row['obj_id'] == 100) { - $row['usr_id'] = -1; - } - } - - return $row; -}); -``` -The zip file can then be imported using the install command. - -## List available objectives -Calling `php cli/setup.php achieve` without any arguments and options -or calling `php cli/setup.php achieve --list` will list all available objectives. - - -# Migrations - -Migrations are major changes in the ILIAS database or file system that are -necessary after an update. Migrations can take quite a long time, which is -why they are available separately as a command. The advantage is that you can -perform migrations after the update when the installation is already online again. -For more information, see [https://docu.ilias.de/goto_docu_wiki_wpage_6399_1357.html](https://docu.ilias.de/goto_docu_wiki_wpage_6399_1357.html) - -The command lists available migrations: - -`php cli/setup.php migrate` - - -``` -! [NOTE] There are 1 to run: - -ilFileObjectMigrationAgent.ilFileObjectToStorageMigration: Migration of File-Objects to Storage service [remaining steps: 1110] -``` - -Individual migrations can then be started as follows, e.g.: - -`php cli/setup.php migrate --run ilFileObjectMigrationAgent.ilFileObjectToStorageMigration` - -A migration must be confirmed in each case, e.g.: - -``` -Do you really want to run the following migration? Make sure you have a backup -of all your data. You will run this migration on your own risk. - -Please type 'ilFileObjectToStorageMigration' to confirm and start.: -> -``` - -With `--yes` migrations can be confirmed automatically. - -Migrations are divided into individual steps, of which there can be many depending -on the migration. A default number of steps is executed in each case; the number -can be increased or set with `--steps=...`. - -## About the Config File - -The config file is a json file with the following structure. **Mandatory fields -are printed bold**, all other fields might be omitted. A minimal example is -[here](minimal-config.json). - -* **common** (type: object) settings relevant for the complete installation, e.g.: - ``` - "common" : { - "client_id" : "test7", - "server_timezone" : "Europe/Berlin", - "register_nic" : true, - "export_hooks_path" : "/var/ilias/export_hooks.php" - } - ``` - * **client_id** (type: string) is the identifier to be used for the installation - * *server_timezone* (type: string) where the installation resides, given as `region/city`, - e.g. `Europe/Berlin`, defaults to `UTC` - * *register_nic* (boolean) sends the identification number of the installation to a server - of the ILIAS society together with some information about the installation, defaults to `false` - * *export_hooks_path* (type: string) The path to the PHP export hooks file, not required and defaults to null if absent. Setting to an empty string results in an error during export. -* *backgroundtasks* (type: object) is a service to run tasks for users in separate processes, e.g.: - ``` - "backgroundtasks" : { - "type" : "sync", - "max_number_of_concurrent_tasks" : 3 - }, - ``` - * *type* (type: string) might be `async` or `sync`, defaults to `sync`; async requires SOAP (c.f. webservices) to be enabled - * *max_number_of_concurrent_tasks* (type: number) that all users can run together, defaults to `1` -* **database** (type: object) is required to connect to the database, e.g.: - ``` - "database" : { - "type" : "innodb", - "host" : "192.168.47.11", - "port" : 3306, - "database" : "db_test7", - "user" : "test7_homer", - "password" : "homers-secret", - "create_database" : true - }, - ``` - * *type* (type: string) of the database, `innodb`, defaults - to `innodb` - * *host* (type: string) the database server runs on, defaults to `localhost` - * *port* (type: string or number) the database server uses, defaults to `3306` - * *database* (type: string) name to be used, defaults to `ilias` - * **user** (type: string) to be used to connect to the database - * *password* (type: string) to be used to connect to the database - * *create_database* (type: boolean) if a database with the given name does not exist? Defaults to `true`. -* **filesystem** (type: object) configuration, e.g.: - ``` - "filesystem" : { - "data_dir" : "/var/ilias_external_data/test7" - }, - ``` - * **data_dir** (type: string) outside the web directory where ILIAS puts some data -* *globalcache* (type: object) is a service for caching various information, e.g.: - ``` - "globalcache" : { - "service" : "static", - "components" : "all" - }, - ``` - or - ``` - "globalcache" : { - "service" : "apc", - "components" : { - "clng" : true, - "comp" : true, - "events" : true, - "global_screen" : true, - "obj_def" : true, - "ilctrl" : true, - "tpl" : true, - "tpl_blocks" : true, - "tpl_variables" : true - } - }, - ``` - or - ``` - "globalcache" : { - "service" : "memcached", - "components" : "all", - "memcached_nodes" : [ - { - "active" : true, - "host" : "example1.com", - "port" : 4711, - "weight" : 10 - }, - { - "active" : false, - "host" : "example2.com", - "port" : 4712, - "weight" : 90 - } - ] - }, - ``` - * *service* (type: string) to be used for caching. Either `none`, `static`, `memcached` - or `apc`, defaults to `static`. - * *components* (type: string or object) that should use caching. Can be `all` or any list of components that - support caching, (must be set too, if *service* is set) - * *memcached_nodes* (type: array of objects) if *service* equals `memcached` place your nodes here -* **http** (type: object) configuration, e.g.: - ``` - "http" : { - "path" : "https://test7.ilias.de/", - "https_autodetection" : { - "header_name" : "my-header-name", - "header_value" : "my-header-value" - }, - "proxy" : { - "host" : "webproxy.ilias.de", - "port" : "8088" - }, - "allowed_hosts" : [ - "red.ilias.de", - "blue.ilias.de", - "www.ilias.de" - ] - }, - ``` - * **path** (type: string) to your installation on the internet - * *https_autodetection* (type: object) allows ILIAS to be run behind a proxy that terminates ssl - connections - * *header_name* (type: string) that the proxy sets to indicate ssl connections - * *header_value* (type: string) that the proxy sets for said header - * *proxy* (type: object) for outgoing http connections - * *host* (type: string) the proxy runs on - * *port* (type: string or number) the proxy listens on - * *allowed_hosts* (type: an `array`/list of strings, or `null`) A list of valid hosts which is used to - validate the `HTTP_HOST` header of incoming web requests. If the host header does not match any of - the allowed hosts, the request is rejected. If `null` is set or an empty list is provided, the host - header is only validated against the host of the `path` setting - (stored in the "ilias.ini.php" as `http_path`), which is always considered allowed. - This also applies for the optionally configurable host used for the WSDL path definition - in the SOAP web service configuration and for "localhost". -* *logging* (type: object) configuration if logging should be used - ``` - "logging" : { - "enable" : true, - "path_to_logfile" : "/var/log/ilias_test7.log", - "errorlog_dir" : "/var/log/ilias_errorlogs/" - }, - ``` - * *enable* (type: boolean) the logging, defaults to `false` - * *path_to_logfile* (type: string) to be used for logging - * *errorlog_dir* (type: string) to put error logs in -* *preview* (type: object) contains settings for ILIAS/Preview - ``` - "preview" : { - "path_to_ghostscript" : "/usr/bin/gs" - }, - ``` - * *path_to_ghostscript* (type: string) executable -* *mediaobject* (type: object) contains settings for ILIAS/MediaObjects - ``` - "mediaobject" : { - "path_to_ffmpeg" : "/usr/bin/ffmpeg" - }, - ``` - * *path_to_ffmpeg* (type: string) executable -* *style* (type: obejct) configuration to change the ILIAS look - ``` - "style" : { - "manage_system_styles" : true, - "path_to_scss" : "/usr/bin/scss" - }, - ``` - * *manage_system_styles* (type: boolean) via a GUI in the installation, defaults to `false` - * *path_to_scss* (type: string) to compile scss to css -* **systemfolder** (type: object) settings for ILIAS/SystemFolder - ``` - "systemfolder" : { - "client" : { - "name" : "test7", - "description" : "Test Installation for ILIAS 7", - "institution" : "Atomic Powerplant Springfield" - }, - "contact" : { - "firstname" : "Homer", - "lastname" : "Simpson", - "title" : "Sir", - "position" : "Security Inspector Sector 7G", - "institution" : "Atomic Powerplant Springfield", - "street" : "742 Evergreen Terrace", - "zipcode" : "12345", - "city" : "Springfield", - "country" : "USA", - "phone" : "(939) 555-0113", - "email" : "Chunkylover53@aol.com" - } - }, - ``` - * *client* (type: string) information - * *name* (type: string) of the ILIAS installation - * *description* (type: string) of the installation - * *institution* (type: string) that provides the installation - * **contact** (type: string) to a person behind the installation - * **firstname** (type: string) of said person - * **lastname** (type: string) of said person - * *title* (type: string) of said person - * *position* (type: string) of said person - * *institution* (type: string) of said person - * *street* (type: string) of said person - * *zipcode* (type: string) of said person - * *city* (type: string) of said person - * *country* (type: string) of said person - * *phone* (type: string) of said person - * **email** (type: string) of said person -* *utilities* (type: object) contains settings for ILIAS/Utilities - ``` - "utilities" : { - "path_to_convert" : "/usr/bin/convert", - "path_to_zip" : "/usr/bin/zip", - "path_to_unzip" : "/usr/bin/unzip" - }, - ``` - * *path_to_convert* (type: string) from ImageMagick, to resize images - * *path_to_zip*" (type: string) to zip files - * *path_to_unzip*" (type: string) to unzip files -* *virusscanner* (type: object) configuration - ``` - "virusscanner" : { - "virusscanner" : "clamav", - "path_to_scan" : "/usr/bin/clamdscan", - "path_to_clean" : "/usr/bin/clamdscan --remove=yes", - }, - ``` - or - ``` - "virusscanner" : { - "virusscanner" : "icap", - "icap_host" : "192.168.47.12", - "icap_port" : 4712, - "icap_service_name" : "icap-name", - "icap_client_path" : "icap-client-path" - }, - ``` - * *virusscanner* (type: string) to be used. Either `none`, `sophos`, `antivir`, `clamav` or `icap` - * *path_to_scan* (type: string) command of the scanner - * *path_to_clean* (type: string) command of the scanner - * *icap_host* (type: string) host address of the icap scanner - * *icap_port* (type: string or number) port if the icap scanner - * *icap_service_name* (type: string) service name of the icap scanner - * *icap_client_path* (type: string) path to the `c-icap-client`, if this is left empty, a php client will be used -* *privacysecurity* (type: object) - ``` - "privacysecurity" : { - "https_enabled" : true, - "auth_duration" : 3000, - "account_assistance_duration" : 3000, - "registration_duration" : 3000, - }, - ``` - * *https_enabled* (type: boolean) forces https on login page, defaults to `false` - * *auth_duration* (type: integer) stretches the auth-duration on logins to the given amount in ms, defaults to `null` - * *account_assistance_duration* (type: integer) stretches the password- and username-assistance duration to the given amount in ms, defaults to `null` - * *registration_duration* (type: integer) stretches registration duration to the given amount in ms, defaults to `null` -* *webservices* (type: object) - ``` - "webservices" : { - "soap_user_administration" : true, - "soap_wsdl_path" : "https://test7.ilias.de/public/soap/server.php?wsdl", - "soap_connect_timeout" : 30, - "rpc_server_host" : "192.168.47.13", - "rpc_server_port" : "11112", - "soap_internal_wsdl_path": "https://localhost/public/soap/server.php?wsdl", - "soap_internal_wsdl_verify_peer": false, - "soap_internal_wsdl_verify_peer_name": false, - "soap_internal_wsdl_allow_self_signed": false - }, - ``` - * *soap_user_administration* (type: boolean) enable administration per soap, defaults to `false` - * *soap_wsdl_path* (type: string) path to the ilias wsdl file, default is `http:///public/soap/server.php?wsdl` - * *soap_connect_timeout* (type: number) maximum time in seconds until a connection attempt to the SOAP-Webservice is interrupted, defaults to `10` - * *rpc_server_host* (type: string) Java-Server host (must be set too, if *rpc_server_port* is set) - * *rpc_server_port* (type: string or number) Java-Server port (must be set too, if *rpc_server_host* is set) - * *soap_internal_wsdl_path* (type: string) path to the ilias wsdl file for internal usage (for calls from ilias to ilias itself), default is *soap_wsdl_path* - * *soap_internal_wsdl_verify_peer* (type: bool) verify peer for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php for more information) - * *soap_internal_wsdl_verify_peer_name* (type: bool) verify peer name for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php) - * *soap_internal_wsdl_allow_self_signed* (type: bool) allow self signed certificates for calls from ilias to ilias itself (see https://www.php.net/manual/en/context.ssl.php) -* *chatroom* (type: object) see also [Chat Server Setup](/components/ILIAS/Chatroom/README.md), eg.: - ``` - "chatroom" : { - "address" : "192.168.47.14", - "port" : 8081, - "sub_directory" : "/chat", - "https" : { - "cert" : "/etc/ssl/certs/server.pem", - "key" : "/etc/ssl/private/server.key", - "dhparam" : "/etc/ssl/private/dhparam.pem" - }, - "log" : "/var/log/ilias_onscreenchat/access.log", - "log_level" : "info", - "error_log" : "/var/log/ilias_onscreenchat/error.log", - "ilias_proxy" : { - "ilias_url" : "https://chat-ilias-proxy.ilias.de" - }, - "client_proxy" : { - "client_url" : "https://chat-client-proxy.ilias.de" - }, - "deletion_interval" : { - "deletion_unit" : "months", - "deletion_value" : "6", - "deletion_time" : "23:45" - } - } - ``` - * *address* (type: string) IP-Address/FQN of Chat Server - * *port* (type: string or number) of the chat server, possible value from `1` to `65535` - * *sub_directory* (type: string) http(s)://[IP/Domain]/[SUB_DIRECTORY] - * *https* (type: object) adding this enables https - * *cert* (type: string) absolute server path to the SSL certificate file e.g. `/etc/ssl/certs/server.pem` - * *key* (type: string) absolute server path to the private key file e.g. `/etc/ssl/private/server.key` - * *dhparam* (type: string) absolute server path to a file e.g. `/etc/ssl/private/dhparam.pem` - * *log* (type: string) absolute server path to the chat server's log file e.g. `/var/www/ilias/data/chat.log` - * *log_level* (type: string) possible values are `emerg`, `alert`, `crit` `error`, `warning`, `notice`, `info`, `debug`, `silly`, defaults to `warning` - * *error_log* (type: string) absolute server path to the chat server's error log file e.g. `/var/www/ilias/data/chat_error.log` - * *ilias_proxy* (type: object) ILIAS to Server Connection - * *ilias_url* (type: string) URL for the Server connection - * *client_proxy* (type: object) Client to Server Connection - * *client_url* URL for the Server connection - * *deletion_interval* (type: object) - * *deletion_unit* (type: string) possible values are `days`, `weeks`, `months`, `years` - * *deletion_value* (type: string or number) depending on `deletion_unit` possible values are `days max 31`, `weeks max 52`, `months max 12`, `years no max` - * *deletion_time* (type: string) with format `HH:MM e.g. 23:30` -* *authentication* (type: object) - ``` - "authentication" : { - "session_max_idle": 1800 - } - ``` - * *session_max_idle* (type: number) maximum session idle (in seconds) diff --git a/components/ILIAS/soap/classes/class.ilSoapCourseAdministration.php b/components/ILIAS/soap/classes/class.ilSoapCourseAdministration.php index 5ee22de949dc..25394d1111b2 100755 --- a/components/ILIAS/soap/classes/class.ilSoapCourseAdministration.php +++ b/components/ILIAS/soap/classes/class.ilSoapCourseAdministration.php @@ -371,8 +371,6 @@ public function updateCourse(string $sid, int $course_id, string $xml) return $this->raiseError('Check access failed. No permission to write course', 'Server'); } - ilCourseParticipants::_deleteAllEntries($tmp_course->getId()); - ilCourseWaitingList::_deleteAll($tmp_course->getId()); diff --git a/components/ILIAS/soap/classes/class.ilSoapFileAdministration.php b/components/ILIAS/soap/classes/class.ilSoapFileAdministration.php index 0340f4364ac8..fb5ac305859f 100755 --- a/components/ILIAS/soap/classes/class.ilSoapFileAdministration.php +++ b/components/ILIAS/soap/classes/class.ilSoapFileAdministration.php @@ -58,6 +58,15 @@ public function addFile(string $sid, int $target_id, string $file_xml) // create object, put it into the tree and use the parser to update the settings + // SECURITY (ILIAS10-025) - defence in depth: COPY/REST modes are internal + // import/zip mechanisms and must not be reachable via externally supplied XML. + if (preg_match('/\bmode="(?:COPY|REST)"/i', $file_xml)) { + return $this->raiseError( + 'mode="COPY" and mode="REST" are not permitted in SOAP addFile.', + 'Client' + ); + } + $file = new ilObjFile(); try { $fileXMLParser = new ilFileXMLParser($file, $file_xml); diff --git a/components/ILIAS/soap/classes/class.ilSoapObjectAdministration.php b/components/ILIAS/soap/classes/class.ilSoapObjectAdministration.php index 6ca6cb56e500..4c09817df2dc 100755 --- a/components/ILIAS/soap/classes/class.ilSoapObjectAdministration.php +++ b/components/ILIAS/soap/classes/class.ilSoapObjectAdministration.php @@ -168,13 +168,17 @@ public function getObjectByReference(string $sid, int $a_ref_id, ?int $user_id = return $this->raiseError("Object with ID $a_ref_id has been deleted.", 'Client'); } + global $DIC; + $access = $DIC['ilAccess']; + $xml_writer = new ilObjectXMLWriter(); $xml_writer->enablePermissionCheck(true); if (is_int($user_id)) { $xml_writer->setUserId($user_id); $xml_writer->enableOperations(true); } - $xml_writer->setObjects(array($tmp_obj)); + $objs = $access->checkAccess("read", "", $a_ref_id) ? array($tmp_obj) : array(); + $xml_writer->setObjects($objs); if ($xml_writer->start()) { return $xml_writer->getXML(); } @@ -220,6 +224,9 @@ public function getObjectsByTitle(string $sid, string $a_title, ?int $user_id = $res->filter(ROOT_FOLDER_ID, true); + global $DIC; + $access = $DIC['ilAccess']; + $objs = array(); foreach ($res->getUniqueResults() as $entry) { if ($entry['type'] === 'role' || $entry['type'] === 'rolt') { @@ -228,7 +235,8 @@ public function getObjectsByTitle(string $sid, string $a_title, ?int $user_id = } continue; } - if ($tmp = ilObjectFactory::getInstanceByRefId($entry['ref_id'], false)) { + if (($tmp = ilObjectFactory::getInstanceByRefId($entry['ref_id'], false)) && + $access->checkAccess("read", "", (int) $entry['ref_id'])) { $objs[] = $tmp; } } @@ -268,6 +276,9 @@ public function searchObjects(string $sid, ?array $types, string $key, string $c ); } + global $DIC; + $access = $DIC['ilAccess']; + $highlighter = null; if (ilSearchSettings::getInstance()->enabledLucene()) { ilSearchSettings::getInstance()->setMaxHits(25); @@ -300,7 +311,7 @@ public function searchObjects(string $sid, ?array $types, string $key, string $c $objs[ROOT_FOLDER_ID] = ilObjectFactory::getInstanceByRefId(ROOT_FOLDER_ID, false); foreach ($result_ids as $ref_id => $obj_id) { $obj = ilObjectFactory::getInstanceByRefId($ref_id, false); - if ($obj instanceof ilObject) { + if ($obj instanceof ilObject && $access->checkAccess("read", "", (int) $ref_id)) { $objs[] = $obj; } } @@ -332,7 +343,7 @@ public function searchObjects(string $sid, ?array $types, string $key, string $c $objs = array(); foreach ($res->getUniqueResults() as $entry) { $obj = ilObjectFactory::getInstanceByRefId($entry['ref_id'], false); - if ($obj instanceof ilObject) { + if ($obj instanceof ilObject && $access->checkAccess("read", "", (int) $entry['ref_id'])) { $objs[] = $obj; } } @@ -381,6 +392,7 @@ public function getTreeChilds(string $sid, int $ref_id, ?array $types = null, ?i global $DIC; $tree = $DIC['tree']; + $access = $DIC['ilAccess']; if (!$target_obj = ilObjectFactory::getInstanceByRefId($ref_id, false)) { return $this->raiseError( @@ -403,7 +415,8 @@ public function getTreeChilds(string $sid, int $ref_id, ?array $types = null, ?i foreach ($tree->getChilds($ref_id, 'title') as $child) { if ($all || in_array($child['type'], $types, true)) { - if ($tmp = ilObjectFactory::getInstanceByRefId($child['ref_id'], false)) { + if (($tmp = ilObjectFactory::getInstanceByRefId($child['ref_id'], false)) && + $access->checkAccess("read", "", (int) $child['ref_id'])) { $objs[] = $tmp; } } diff --git a/components/ILIAS/soap/lib/nusoap.php b/components/ILIAS/soap/lib/nusoap.php index 40a4d1fb25f4..811f3c9e85ba 100755 --- a/components/ILIAS/soap/lib/nusoap.php +++ b/components/ILIAS/soap/lib/nusoap.php @@ -2370,7 +2370,7 @@ public function connect($connection_timeout = 0, $response_timeout = 30) // set response timeout $this->debug('set response timeout to ' . $response_timeout); - socket_set_timeout($this->fp, $response_timeout); + stream_set_timeout($this->fp, $response_timeout); $this->debug('socket connected'); return true; diff --git a/composer.json b/composer.json index f5ddfa36d6ae..5dacbc8bd126 100755 --- a/composer.json +++ b/composer.json @@ -90,17 +90,16 @@ "./public/Customizing/global/plugins", "./components", "./vendor/ilias", - "./components/ILIAS/soap", - "./components/ILIAS/setup_/classes" + "./components/ILIAS/soap" ], "exclude-from-classmap": [ "./components/ILIAS/Migration", "./*/*/lib", "./public/Customizing/**/vendor", - "./components/ILIAS/setup_/sql", + "./components/ILIAS/Database/sql", "./cli/setup.php", - "./components/ILIAS/setup_/client.master.ini.php", - "./components/ILIAS/setup_/ilias.master.ini.php" + "./components/ILIAS/Init/resources/client.master.ini.php", + "./components/ILIAS/Init/resources/ilias.master.ini.php" ] }, "extra": { diff --git a/docs/configuration/install.md b/docs/configuration/install.md index cadff0c83459..845dea32bf8d 100755 --- a/docs/configuration/install.md +++ b/docs/configuration/install.md @@ -1,8 +1,8 @@ # ILIAS Installation -This is the installation guide for ILIAS 11, providing step-by-step instructions to set up all necessary components, -including the web server, database, and ILIAS code. Follow these instructions carefully to ensure a successful -installation of the e-learning software. Each section will guide you through the required configurations and setups +This is the installation guide for ILIAS 11, providing step-by-step instructions to set up all necessary components, +including the web server, database, and ILIAS code. Follow these instructions carefully to ensure a successful +installation of the e-learning software. Each section will guide you through the required configurations and setups for a fully functional ILIAS environment. # Table of Contents @@ -10,36 +10,36 @@ for a fully functional ILIAS environment. - [System Requirements](#system-requirements) - * [Hardware](#hardware) - * [Supported Software Setup and Reference System](#supported-system) + * [Hardware](#hardware) + * [Supported Software Setup and Reference System](#supported-system) - [Installation on Ubuntu 24.04](#installation-on-linux) - * [Install Dependencies](#install-dependencies) - * [Webserver Installation/Configuration](#install-webserver) - * [Database Installation/Configuration](#install-database) - * [Get the Code and Install ILIAS](#get-code) - * [Install ILIAS](#install-ilias) - * [Install Further Components](#install-further) - * [Install Plugins and Styles](#install-plugins-and-styles) + * [Install Dependencies](#install-dependencies) + * [Webserver Installation/Configuration](#install-webserver) + * [Database Installation/Configuration](#install-database) + * [Get the Code and Install ILIAS](#get-code) + * [Install ILIAS](#install-ilias) + * [Install Further Components](#install-further) + * [Install Plugins and Styles](#install-plugins-and-styles) - [Backup ILIAS](#backup-ilias) - [Upgrading ILIAS](#upgrading-ilias) - * [Minor Upgrade](#minor-upgrade) - * [Major Upgrade](#major-upgrade) - * [Update the Database](#update-the-database) - * [Information on Updates](#information-updates) + * [Minor Upgrade](#minor-upgrade) + * [Major Upgrade](#major-upgrade) + * [Update the Database](#update-the-database) + * [Information on Updates](#information-updates) - [Connect and Contribute](#connect-and-contribute) - [Appendix](#appendix) - * [Upgrading Dependencies](#upgrading-dependencies) - * [Configure Cron Jobs](#configurate-cron) - * [Configure WebDAV](#webdav-configuration) - * [Hardening and Security Guidance](#hardening-and-security-guidance) - * [MySQL Strict Mode (5.7+)](#mysql-strict-mode-57) + * [Upgrading Dependencies](#upgrading-dependencies) + * [Configure Cron Jobs](#configure-cron) + * [Configure WebDAV](#webdav-configuration) + * [Hardening and Security Guidance](#hardening-and-security-guidance) + * [MySQL Strict Mode (5.7+)](#mysql-strict-mode-57) # System Requirements -The necessary hardware to run an ILIAS installation is always dependent from the number of users and the kind of usage. +The necessary hardware to run an ILIAS installation always depends on the number of users and the kind of usage. ## Hardware @@ -58,7 +58,7 @@ few GBs for the database. ## Supported Software Setup and Reference System -The following software versions are required/supported for ILIAS 11. The table below lists these versions alongside the +The following software versions are required/supported for ILIAS 11. The table below lists these versions alongside the current configuration of the [ILIAS test server](https://test11.ilias.de), which serves as a reference system. | Package | Version | Reference System | @@ -84,20 +84,20 @@ Package names may vary depending on the Linux distribution. # Installation on Ubuntu 24.04 Depending on your Linux Distribution, you have several ways to install the required -dependencies. We recommend to always use your distributions package manager to -easily keep your packages up to date avoiding security issues. +dependencies. We recommend that you always use your distribution's package manager in order +to keep your packages up to date and avoid security issues. -In this guide we choose Ubuntu 24.04 because it already meets the recommended PHP version 8.3. -For other Ubuntu or Debian-based Linux systems, we recommend using [DEB.SURY.ORG](https://deb.sury.org/) to install the correct +In this guide we have chosen Ubuntu 24.04 because it already meets the recommended PHP version 8.3. +For other Ubuntu or Debian-based Linux systems, we recommend using [DEB.SURY.ORG](https://deb.sury.org/) to install the correct PHP version later on. ## Install Dependencies -`openjdk-21-jdk` and `maven` are optional and are used for the ILIAS RPC server for search indexing and certificate generation. +`openjdk-21-jdk` and `maven` are optional and are used for the ILIAS RPC server for search indexing and certificate generation. `git` is required if the source code is obtained directly from GitHub. `nodejs` and `npm` are required as well if you get the source directly to download the javascript dependencies in the installation process. -Alternatively, they can be obtained directly from the distribution package at [Nodesource](https://deb.nodesource.com/) to select appropriate nodejs versions according to the [Recommended Setup for Running ILIAS](#recommended-setup-for-running-ilias). +Alternatively, they can be obtained directly from the distribution package at [Nodesource](https://nodejs.org/en/download) to select appropriate nodejs versions according to the [Recommended Setup for Running ILIAS](#recommended-setup-for-running-ilias). `ffmpeg` is optionally used to optimise media files, and `ghostscript` is optionally used to create file previews. ```shell @@ -108,7 +108,7 @@ apt update zip unzip openjdk-21-jdk maven ffmpeg git ghostscript nodejs npm ## Webserver Installation/Configuration -In this guide, we use Apache2 as the web server, utilizing `libapache2-mod-php` to process PHP files. +In this guide, we use Apache2 as the web server, utilizing `libapache2-mod-php` to process PHP files. Other web servers capable of processing PHP, such as Nginx or Apache2 with FCGI and PHP-FPM, can also be used. **Required PHP Extensions:** @@ -118,27 +118,29 @@ gd, dom, xsl, pdo, pdo_mysql, curl, json, simplexml, libxml, xml, zip, imagick, **Optional PHP Extensions:** -* `soap` for SOAP user administration +* `soap` for SOAP user administration * `ldap` for LDAP user authentication -The PHP packet manager Composer is necessary to download all external PHP dependencies and for PHP autoloading. -Alternatively, it can be obtained directly from [getcomposer.org](https://getcomposer.org/download/). +The PHP packet manager Composer is necessary to download all external PHP dependencies and for PHP autoloading. +Alternatively, it can be obtained directly from [getcomposer.org](https://getcomposer.org/download/). Composer may be optional when using the prepacked ILIAS from [Download & Releases](https://docu.ilias.de/go/pg/197851_35), but it is necessary when using plugins to rebuild the PHP autoload classmap. ```shell apt install apache2 libapache2-mod-php php php-gd php-xsl php-imagick php-curl php-mysql php-soap php-ldap composer ``` -Create a directory for the html sources (e.g. `/var/www/ilias`) which is referenced in the apache2 vhost and also a directory outside the web servers docroot (e.g. `/var/www/files`) for files stored by ILIAS. -Make sure that the web server is the owner of the files and directories that were created by changing the group and owner to www-data (on Debian/Ubuntu) or apache (on RHEL). +Create a directory for the html sources (e.g. `/var/www/ilias`) which is referenced in the apache2 vhost (the apache2 vhost will use `/var/www/ilias/public`) and also a directory outside the web server's docroot (e.g. `/var/www/files`) for files stored by ILIAS. +Make sure that the web server user is the owner of the files and directories that were created by changing the group and owner to `www-data` (on Debian/Ubuntu), `apache` (on RHEL) or `wwwrun` (on SLES). In addition to the file folder, ILIAS also needs a place to create the log files (e.g. `/var/www/logs`). The 'ilias.log' can be viewed there later, as well as all error_log files, which are created in case of errors and are referenced in ILIAS by an errorcode. -Also, to store the ILIAS configuration, which is later used to configurate ILIAS, we create the folder /var/www/config. To prevent future issues with npm we create /var/www/.npm with webowner rights. +Also, to store the ILIAS configuration, which is later used to configure ILIAS, +we need to create the folder `/var/www/config`. To prevent future issues with npm we +also need to create `/var/www/.npm` which needs to be writable by the web server user. ```shell mkdir /var/www/ilias @@ -153,7 +155,7 @@ chown www-data:www-data /var/www/.npm ``` Usually Apache ships with a default configuration (e.g. `/etc/apache2/sites-enabled/000-default.conf` on Debian based -systems). A minimal configuration for ILIAS may look as follows: +systems). A minimal configuration for ILIAS may look like this: ```apacheconf @@ -182,17 +184,18 @@ a2enmod rewrite systemctl restart apache2.service ``` -To check if the installation was successfull create the file `/var/www/ilias/phpinfo.php` with the following contents: +To check if the installation was successful, create the file `/var/www/ilias/public/phpinfo.php` with the following contents: ``` ## Database Installation/Configuration @@ -251,7 +254,7 @@ apt install mariadb-server > Please note that installing ILIAS in utf8mb4-collations is currently not supported! > ILIAS supports utf8-collations with 3 bytes per character, such as `utf8_general_ci`, only. -We **strongly recommend** to use MariaDB with the following settings: +We **strongly recommend** using MariaDB with the following settings: * InnoDB storage engine (default) * `character-set-server` = `utf8mb3` @@ -269,7 +272,7 @@ is set to `COMPACT`. systemctl restart mariadb.service ``` -We recommend to create a dedicated database user for ILIAS: +We recommend creating a dedicated database user for ILIAS: ```shell mysql -e "CREATE DATABASE ilias CHARACTER SET utf8 COLLATE utf8_general_ci;" @@ -287,22 +290,22 @@ ILIAS release or clone it from [GitHub](https://github.com/ILIAS-eLearning/ILIAS For production use make sure to checkout the latest stable release, not the trunk, which is the development branch of the repository. -We recommend to clone from GitHub and use git to update the code, since this simplifies +We recommend cloning from GitHub and using git to update the code, since this simplifies the update to future releases and versions. -Clone the code to the web servers docroot (e.g. `/var/www/html`) with the following +Clone the code to the web server's docroot (e.g. `/var/www/ilias`) with the following commands: ```shell -cd /var/www/ilias/ -sudo -uwww-data git clone https://github.com/ILIAS-eLearning/ILIAS.git . --single-branch -b release_11 +cd /var/www +sudo -u www-data git clone -b release_11 https://github.com/ILIAS-eLearning/ILIAS.git ilias ```
    If you use tags to directly reference ILIAS versions ```shell -cd /var/www/ilias/ -sudo -uwww-data git clone https://github.com/ILIAS-eLearning/ILIAS.git . --single-branch -b v11.X +cd /var/www +sudo -u www-data git clone -b v11.X https://github.com/ILIAS-eLearning/ILIAS.git ilias ```
    @@ -312,20 +315,22 @@ sudo -uwww-data git clone https://github.com/ILIAS-eLearning/ILIAS.git . --singl Download the file from the [Download & Releases](https://docu.ilias.de/go/lm/35) page. ```shell -sudo -uwww-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz -sudo -uwww-data tar -xzf ILIAS-11.X.tar.gz -C /var/www/ilias --strip-components=1 ILIAS-11.X/ +sudo -u www-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz +sudo -u www-data tar -xzf ILIAS-11.X.tar.gz -C /var/www/ilias --strip-components=1 ILIAS-11.X/ ``` -The GitHub repository of ILIAS doesn't contain all code that is required to run. To download the required PHP-dependencies and -to create static artifacts from the source, run the following in your ILIAS folder: +The GitHub repository of ILIAS doesn't contain all code that is required to run. To download the required dependencies and +to create static artifacts from the source, run the following in your ILIAS directory (the directory that contains +the composer.lock and package-lock.json). This will create a new directory called public which is the root +directory of your webserver: ```shell -sudo -uwww-data npm clean-install --omit=dev --ignore-scripts -sudo -uwww-data composer install --no-dev +sudo -u www-data npm clean-install --omit=dev --ignore-scripts +sudo -u www-data composer install --no-dev ``` > [!IMPORTANT] -> We recommend restricting the rights of the ILIAS code in the production system so that the web server only has +> We recommend restricting the permissions of the ILIAS code in the production system so that the web server only has > read access to the code. For this and other important security considerations, please refer to the security > instructions in the [Security Guide](./secure.md). @@ -333,15 +338,15 @@ sudo -uwww-data composer install --no-dev ## Install ILIAS After having all dependencies installed and configured you should be able to run -the [ILIAS Setup on the command-line](../../components/ILIAS/setup_/README.md). +the [ILIAS Setup on the command-line](../../components/ILIAS/Setup/README.md). -To do so, create a configuration file for the setup by copying the [minimal-config.json](../../components/ILIAS/setup_/minimal-config.json) +To do so, create a configuration file for the setup by copying the [minimal-config.json](../../components/ILIAS/Setup/minimal-config.json) to a location outside your docroot. Fill in the configuration fields that are already -contained in the minimal config. Have a look into the [list of available config options](../../components/ILIAS/setup_/README.md#about-the-config-file) +contained in the minimal config. Have a look at the [list of available config options](../../components/ILIAS/Setup/README.md#about-the-config-file) and add the fields that your environment and installation requires. ```shell -cp /var/www/ilias/components/ILIAS/setup_/minimal-config.json /var/www/config/ilias.json +cp /var/www/ilias/components/ILIAS/Setup/minimal-config.json /var/www/config/ilias.json ``` A typical configuration might look like this afterwards: @@ -353,7 +358,7 @@ A typical configuration might look like this afterwards: }, "database" : { "user" : "ilias", - "password": ">", + "password": "", "database": "ilias", "create_database": true }, @@ -370,9 +375,9 @@ A typical configuration might look like this afterwards: }, "systemfolder" : { "contact" : { - "firstname" : "Richard", - "lastname" : "Klees", - "email" : "richard.klees@concepts-and-training.de" + "firstname" : "Lucy", + "lastname" : "Snowe", + "email" : "lucysnowe@ilias.de" } }, "utilities" : { @@ -391,23 +396,16 @@ Run the ILIAS command line setup from within your ILIAS folder with your configu file (located outside your doc-root!) as a parameter: ```shell -sudo -uwww-data php cli/setup.php install /var/www/config/ilias.json +sudo -u www-data php cli/setup.php install /var/www/config/ilias.json ``` -The installation will display what currently happens and might prompt you with -questions. You might want to have a look into the [documentation of the command line setup](../../components/ILIAS/setup_/README.md) -or into the help of the program itself `php cli/setup.php help`. It is the tool +The installation will display what is currently happening and might prompt you with +questions. You might want to have a look at the [documentation of the command line setup](../../components/ILIAS/Setup/README.md) +or at the help of the program itself `php cli/setup.php help`. It is the tool to manage and monitor your ILIAS installation. -If you are installing from Git, it is possible that ILIAS will already require a few migrations to the initial -database. Run the setup migration and follow the steps shown. This is also necessary whenever you update your code. - -```shell -php cli/setup.php migrate -``` - -Now that you have ILIAS installed, you can start by logging in as root. Go to your http path and log in with the -username `root` and password `homer`. ILIAS will ask you for a new password after the first login. +Now that you have ILIAS installed, you can start by logging in as root. Go to your http path and log in with the +username `root` and password `homer`. ILIAS will ask you for a new password on the first login. ## Install Further Components @@ -415,19 +413,19 @@ username `root` and password `homer`. ILIAS will ask you for a new password afte Optionally you can continue with the installation of further components to get the full functionality of ILIAS: 1. **ILIAS Cron Job** -A cron job can be automatically executed to perform recurring tasks, such as sending notifications or deleting inactive user accounts. -For details on how to configure the automatic execution of cron jobs, see [Configure Cron Jobs](#configurate-cron). + A cron job can be automatically executed to perform recurring tasks, such as sending notifications or deleting inactive user accounts. + For details on how to configure the automatic execution of cron jobs, see [Configure Cron Jobs](#configure-cron). 2. **ILIAS Java RPC server** -It is used for certain optional functions such as Lucene Search -or generating PDF Certificates. See [Lucene RPC-Server](../../components/ILIAS/WebServices/RPC/lib/README.md) for details -on how to install the RPC server. -3. **ILIAS Chat Server** -It is used to provide an interactive chat experience between users. -See [Chat Server](../../components/ILIAS/Chatroom/README.md) for details on how to install the chat server. + This is used for certain optional functions such as Lucene Search + or generating PDF Certificates. See [Lucene RPC-Server](../../components/ILIAS/WebServices/RPC/lib/README.md) for details + on how to install the RPC server. +3. **ILIAS Chat Server** + This is used to provide an interactive chat experience between users. + See [Chat Server](../../components/ILIAS/Chatroom/README.md) for details on how to install the chat server. 4. **E-Mail** -You either use a MTA of your liking to send e-mail generated by ILIAS or configure a SMPT Connection in ILIAS -"Administration > Communication > Settings > Extern" by activating and configuring "Send via SMTP". We recommend -to use a MTA installed to your OS like `postfix`. On Debian/Ubuntu execute and configure it according to their instructions: + You either use an MTA of your liking to send e-mail generated by ILIAS or configure an SMTP Connection in ILIAS + "Administration > Communication > Settings > Extern" by activating and configuring "Send via SMTP". We recommend + to use a MTA installed to your OS like `postfix`. On Debian/Ubuntu execute and configure it according to their instructions: ```shell apt-get install postfix ``` @@ -441,27 +439,27 @@ A variety of free plugins is provided from our community via the [ILIAS Plugin R To develop plugins, you can get started in our [Development Guide](https://docu.ilias.de/go/pg/27030_42). Custom styles are the way to modify the look of your ILIAS installation. Have -a look in the [documentation of the System Styles and Custom Styles](../../templates/Readme.md) +a look at the [documentation of the System Styles and Custom Styles](../../templates/Readme.md) to learn how to build and install them. # Backup ILIAS -There are three places where the ILIAS core system stores data that needs to be backed up in order to restore your +There are three places where the ILIAS core system stores data that needs to be backed up in order to restore your system in case of failure. * Internal data within your webroot `/public/data` in our case `/var/www/ilias/public/data`. * External data, configured in `ilias.json` within `filesystem.data_dir`, in our case `/var/www/files/ilias`. * The database, which can easily be done by running `mysqldump'. ```shell -mysqldump --lock-tables=false -u -p > /path/to/your/backup/folder/ilias-backup.sql +mysqldump --lock-tables=false -u -p > /path/to/your/backup/folder/ilias-backup.sql # Prompt for password ``` -When restoring the ILIAS files to the designated folder, remember to set the correct permissions and ownership of your -web server. To restore the database, drop the old database with `DROP DATABASE ;`, create an empty +When restoring the ILIAS files to the designated folder, remember to set the correct permissions and ownership of your +web server. To restore the database, drop the old database with `DROP DATABASE ;`, create an empty database according to [Database Installation/Configuration](#install-database) and write the database dump to this database: ```shell -mysql -u -p < /path/to/your/backup/folder/ilias-backup.sql +mysql -u -p < /path/to/your/backup/folder/ilias-backup.sql # Prompt for password ``` @@ -472,7 +470,7 @@ The easiest way to update ILIAS is using Git. Please note that this is only poss if you installed ILIAS via Git as advised in this document. If Git wasn't used you can also [download](https://docu.ilias.de/go/lm/35) new releases. -Before you start you should consider to [backup](#backup-ilias). +Before you start we strongly advise you to make a [backup](#backup-ilias). ## Minor Upgrade @@ -481,19 +479,19 @@ To apply a minor update (e.g. v11.1 to v11.2) execute the following command in your ILIAS basepath (e.g. `/var/www/ilias/`): ```shell -sudo -uwww-data git pull origin release_11 -sudo -uwww-data npm clean-install --omit-dev --ignore-scripts -sudo -uwww-data composer install --no-dev +sudo -u www-data git pull origin release_11 +sudo -u www-data npm clean-install --omit-dev --ignore-scripts +sudo -u www-data composer install --no-dev ```
    If you use tags to directly reference ILIAS versions ```shell -sudo -uwww-data git fetch origin v11.X:v11.X -sudo -uwww-data git checkout v11.X -sudo -uwww-data npm clean-install --omit-dev --ignore-scripts -sudo -uwww-data composer install --no-dev +sudo -u www-data git fetch origin v11.X:v11.X +sudo -u www-data git checkout v11.X +sudo -u www-data npm clean-install --omit-dev --ignore-scripts +sudo -u www-data composer install --no-dev ```
    @@ -503,17 +501,17 @@ sudo -uwww-data composer install --no-dev Download the archive of the newest ILIAS minor version on the [Download & Releases](https://docu.ilias.de/go/lm/35) page. ```shell -sudo -uwww-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz -sudo -uwww-data mkdir /tmp/ilias_update -sudo -uwww-data tar -xzf ILIAS-11.X.tar.gz -C /tmp/ilias_update --strip-components=1 ILIAS-11.X/ -sudo -uwww-data rsync -av --exclude='/public/' --exclude='/Customizing/' --exclude='/data/' --exclude='ilias.ini.php' /tmp/ilias_update/ /var/www/ilias/ +sudo -u www-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz +sudo -u www-data mkdir /tmp/ilias_update +sudo -u www-data tar -xzf ILIAS-11.X.tar.gz -C /tmp/ilias_update --strip-components=1 ILIAS-11.X/ +sudo -u www-data rsync -av --exclude='/public/' --exclude='/Customizing/' --exclude='/data/' --exclude='ilias.ini.php' /tmp/ilias_update/ /var/www/ilias/ rm -rf /tmp/ilias_update ``` -If you have plugins installed, you will need to rebuild the classmap, including all plugins. You will need to call +If you have plugins installed, you will need to rebuild the classmap, including all plugins. You will need to call `composer du` to do this. ```shell -sudo -uwww-data composer du +sudo -u www-data composer du ``` @@ -526,24 +524,27 @@ Then complete the update by [updating the database](#update-the-database). ## Major Upgrade +Before running a major upgrade please make sure that you have run all migrations +of your current ILIAS release as explained in the +[Update the Database and run the migrations](#update-the-database) section. To apply a major upgrade (e.g. v11.13 to v12.1) please check that your OS has the [proper dependency versions](#upgrading-dependencies) installed. Note that no major -version can be omitted during the upgrade process. You can upgrade from 11 to 12, +version can be omitted during the upgrade process. You can upgrade from 11 to 12, but not directly from 10 to 12. If everything is fine, change your default skin to Delos and apply this change at least to your root user. Otherwise ILIAS might become unusable due to changes in the layout templates. Then execute the following commands in your ILIAS basepath (e.g. `/var/www/ilias`). ```shell -sudo -uwww-data git fetch origin release_11:release_11 -sudo -uwww-data git checkout release_11 +sudo -u www-data git fetch origin release_11:release_11 +sudo -u www-data git checkout release_11 ```
    If you use tags to directly reference ILIAS versions ```shell -sudo -uwww-data git fetch origin v11.X:v11.X -sudo -uwww-data git checkout v11.X +sudo -u www-data git fetch origin v11.X:v11.X +sudo -u www-data git checkout v11.X ```
    @@ -553,74 +554,71 @@ sudo -uwww-data git checkout v11.X Download the archive of the newest ILIAS minor version from the [Download & Releases](https://docu.ilias.de/go/lm/35) page. ```shell -sudo -uwww-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz -sudo -uwww-data mkdir /tmp/ilias_update -sudo -uwww-data tar -xzf ILIAS-11.X.tar.gz -C /tmp/ilias_update --strip-components=1 ILIAS-11.X/ -sudo -uwww-data rsync -av --exclude='/public/' --exclude='/Customizing/' --exclude='/data/' --exclude='ilias.ini.php' /tmp/ilias_update/ /var/www/ilias/ +sudo -u www-data wget https://github.com/ILIAS-eLearning/ILIAS/releases/download/v11.X/ILIAS-11.X.tar.gz +sudo -u www-data mkdir /tmp/ilias_update +sudo -u www-data tar -xzf ILIAS-11.X.tar.gz -C /tmp/ilias_update --strip-components=1 ILIAS-11.X/ +sudo -u www-data rsync -av --exclude='/public/' --exclude='/Customizing/' --exclude='/data/' --exclude='ilias.ini.php' /tmp/ilias_update/ /var/www/ilias/ rm -rf /tmp/ilias_update ``` -After upgrading the code from ILIAS 10 to ILIAS 11 due to structural changes, you need to move the `/Customizing/global/plugins` -and `/data` folder to its new destination. Both are now located in the newly created `public` folder. - -```shell -sudo -uwww-data mkdir -p public/Customizing/plugins -mv data public/ -mv Customizing/global/plugins/Services/* public/Customizing/plugins/ -mv Customizing/global/plugins/Modules/* public/Customizing/plugins/ -``` Then update the code of your plugins according to their documentation to ensure they are compatible with the new ILIAS version. If you are **not** using the tar.gz archive to upgrade your release, update your javascript and php dependencies. If you are using a tar.gz archive and are using plugins, reload your php classmap with `composer du`. ```shell -sudo -uwww-data npm clean-install --omit-dev --ignore-scripts -sudo -uwww-data composer install --no-dev +sudo -u www-data npm clean-install --omit-dev --ignore-scripts +sudo -u www-data composer install --no-dev ``` Complete the update of the base system by [updating the database](#update-the-database). As a last step, you should log in with a User using your custom skin. If everything -works fine, change back from Delos to your custom system style. If not, you probably +works correctly, change back from Delos to your custom system style. If not, you probably will need to update your style to match the new release. -## Update the Database +## Update the Database and carrying out migrations to IRSS Database updates must be done for both minor and major updates, the schema and content of the database probably won't match the code otherwise. Database updates are performed -via the [command line setup program](../../components/ILIAS/setup_/README.md). The required updates +via the [command line setup program](../../components/ILIAS/Setup/README.md). The required updates are split into two groups. **Updates** are tasks that need to be run immediately to -make your installation work properly. **Migrations** are tasks, that potentially take -some time, but which can also be executed while the installation is in productive use. +make your installation work properly. **Migrations** are tasks that potentially take +some time, but which can also be executed while the installation is live. Run the `status` command on the command line to check if there are any updates available and if ILIAS is responding. After this you need to perform the update. -``` -php cli/setup.php update -``` - -To check if there are migrations, run in your ILIAS folder. +Please make sure to check for migrations before you run the update, especially if it's a +major upgrade. If there are migrations left please make sure to run these before updating. ``` -php cli/setup.php migrate +cd /var/www/ilias +sudo -u www-data php cli/setup.php migrate ``` -The command will show you if there are migrations that need to be run for you -installation. Run them by using the `--run` parameter and have a look into +The command will show you if there are migrations that need to be run for your +installation. Run them by using the `--run` parameter and refering to the help of the command for more details: `php cli/setup.php migrate --help`. -Both commands will display what currently happens and might prompt you with -questions. You might want to have a look into the [documentation of the command line setup](../../components/ILIAS/setup_/README.md) -or into the help of the program itself `php cli/setup.php help`. It is the tool -to manage and monitor your ILIAS installation. +Both commands will display what is currently happening and might prompt you with +questions. You might want to have a look into the [documentation of the command line setup](../../components/ILIAS/Setup/README.md) +or into the help of the program itself `php cli/setup.php help`. This is the tool +for managing and monitoring your ILIAS installation. + +As soon as all migrations are done you can do the database update: +``` +cd /var/www/ilias +sudo -u www-data npm clean-install --omit=dev --ignore-scripts +sudo -u www-data composer install --no-dev +sudo -u www-data php cli/setup.php update +``` Database updates are performed in steps; it might happen that a step fails, e.g. due to some edge case or inconsistency in existing data, files, etc. -In this case, a concecutive command `php setup/setup.php update` will error with -a message like +In this case, a consecutive command `php setup/setup.php update` will indicate +an error error with a message like > step 2 was started last, but step 1 was finished last. > Aborting because of that mismatch. @@ -628,17 +626,17 @@ You may reset the records for those steps by running: ```shell php cli/setup.php achieve database.resetFailedSteps ``` -However, be sure to understand the cause for the failing steps and tend to it before -resetting and running update again. +However, be sure to understand why the steps failed and address the issue +before resetting and rerunning the update. ## Information on Updates To keep your ILIAS Installation secure and healthy it is important that you keep -it up to date. To get informations about updates and security fixes you should -consider subscribing to the [ILIAS Admin Mailing-List](http://lists.ilias.de/cgi-bin/mailman/listinfo/ilias-admins). Information on the -new versions, such as Important Changes, Known Issues, Changed Behaviour and Fixed -Issues, can be found in the release notes in [Download & Releases](https://docu.ilias.de/go/lm/35). +it up to date. To get information about updates and security fixes you should +consider subscribing to the [ILIAS Admin Mailing-List](http://lists.ilias.de/cgi-bin/mailman/listinfo/ilias-admins). Information on the +new versions, such as Important Changes, Known Issues, Changed Behaviour and Fixed +Issues can be found in the release notes in [Download & Releases](https://docu.ilias.de/go/lm/35). # Connect and Contribute @@ -651,7 +649,7 @@ or [ILIAS Development Conferences](https://docu.ilias.de/goto_docu_grp_3721.html We are also looking for [contributions of code](../development/contributing.md), [reports of issues](http://mantis.ilias.de) or [requests in our Feature Wiki](https://docu.ilias.de/goto.php?target=wiki_5307&client_id=docu#ilPageTocA119). -If you have any questions about the installation or the community, please visit us on our [Discord server](https://discord.gg/H9v2v2Ar2T) and join +If you have any questions about the installation or the community, please visit us on our [Discord server](https://discord.gg/H9v2v2Ar2T) and join the discussion! @@ -680,42 +678,42 @@ each ILIAS release. We strongly recommend using MariaDB instead of MySQL due to performance, licensing and compatibility in the future. -| ILIAS Version | MySQL Version | MariaDB Version | -|---------------|---------------------|------------------------| -| 12.0 - 12.x | 8.4.x | 11.4, 11.8, 12.3 | -| 11.0 - 11.x | 8.0.x | 10.4, 10.5, 10.6 | -| 10.0 - 10.x | 8.0.x | 10.4, 10.5, 10.6 | -| 9.0 - 9.x | 8.0.x | 10.3, 10.4, 10.5, 10.6 | -| 8.0 - 8.x | 5.7.x, 8.0.x | 10.2, 10.3, 10.4 | -| 7.0 - 7.x | 5.7.x, 8.0.x | 10.1, 10.2, 10.3 | -| 6.0 - 6.x | 5.6.x, 5.7.x, 8.0.x | 10.0, 10.1, 10.2, 10.3 | - - +| ILIAS Version | MySQL Version | MariaDB Version | +|---------------|---------------------|------------------------------| +| 12.0 - 12.x | 8.4.x | 11.4, 11.8, 12.3 | +| 11.0 - 11.x | 8.0.x | 10.4, 10.5, 10.6, 11.4, 11.8 | +| 10.0 - 10.x | 8.0.x | 10.4, 10.5, 10.6 | +| 9.0 - 9.x | 8.0.x | 10.3, 10.4, 10.5, 10.6 | +| 8.0 - 8.x | 5.7.x, 8.0.x | 10.2, 10.3, 10.4 | +| 7.0 - 7.x | 5.7.x, 8.0.x | 10.1, 10.2, 10.3 | +| 6.0 - 6.x | 5.6.x, 5.7.x, 8.0.x | 10.0, 10.1, 10.2, 10.3 | + + ## Configure Cron Jobs This step configures the execution of the ILIAS Cron Jobs, which can be set to perform tasks, such as sending notifications. -You can manage these jobs in the ILIAS Administration under "Administration > General Settings > Cron Jobs". +You can manage these jobs in the ILIAS Administration under +"Administration > System Settings and Maintenance > Cron Jobs". To test the execution of the Cron Jobs Executable `./cli/cron.php`, the following command can be used: ```shell -php /var/www/ilias/cli/cron.php run-jobs +php /var/www/ilias/cli/cron.php run-jobs ``` The `` is a valid, arbitrary user account within the ILIAS installation. -The `` corresponds to the client ID of the ILIAS installation. -To configure automated Cron Jobs in your system, you need to create an user in ILIAS, for example named `cron`. -Then create a new file in the Linux Cron configuration for ILIAS at `/etc/cron.d/ilias`, -including a line to execute `./cli/cron.php` every 5 minutes. +To configure automated Cron Jobs in your system, you need to create a user in ILIAS, for example named `cron`. +Then create a new file in the Linux Cron configuration for ILIAS at `/etc/cron.d/ilias`, +including a line to execute `./cli/cron.php` every 5 minutes. Other methods for executing Linux cron tasks, such as using the user crontab, can also be utilized. ```cron -*/5 * * * * www-data /usr/bin/php /var/www/ilias/cli/cron.php run-jobs cron myilias > /dev/null 2>&1 +*/5 * * * * www-data /usr/bin/php /var/www/ilias/cli/cron.php run-jobs cron > /dev/null 2>&1 ``` -You can verify the proper automatic execution in the ILIAS Administration section by checking the timestamp -displayed at `Last Start of the Cron Job` after some time. +You can verify the proper automatic execution in the ILIAS Administration section by checking the timestamp +displayed at `Last Automatic Execution of Cron Job Script` after some time. diff --git a/docs/configuration/secure.md b/docs/configuration/secure.md index 277452b95268..0ccda71d1715 100755 --- a/docs/configuration/secure.md +++ b/docs/configuration/secure.md @@ -17,6 +17,7 @@ * [Suppress server signature and PHP version information](#suppress-server-signature-and-php-version-information) * [deny access or restrict to several files or locations](#deny-access-or-restrict-to-several-files-or-locations) + [ILIAS setup](#ilias-setup) + + [Restrict access to the SOAP interface](#restrict-access-to-the-soap-interface) + [Prevent blacklisted files of beeing served by the webserver](#prevent-blacklisted-files-of-beeing-served-by-the-webserver) + [Prevent execution of PHP-Code in data-directory](#prevent-execution-of-php-code-in-data-directory) + [Deny Access to local Git-Directory](#deny-access-to-local-git-directory) @@ -46,6 +47,7 @@ For a better identification, they will describe here: | %EXTERNALDATA% | ILIAS data directory outside of the web document root | | %LOGDIR% | path to the directory containing log files | | %CLIENTID% | the client name of the ILIAS installation | +| %UPSTREAM% | name or address of the ILIAS backend/upstream | ## Firewall @@ -547,6 +549,45 @@ Nginx: Please add the whitelisted ip address (%IPADDRESS%) to grant access to ILIAS setup here. +### Restrict access to the SOAP interface + +ILIAS provides a SOAP web service interface (`/soap/server.php`) which exposes a number of web service functions. To reduce the attack surface, you SHOULD restrict access to this endpoint on the web server level so that only trusted hosts can reach it. If you don't make use of the SOAP interface at all, you MAY additionally disable the SOAP user administration via the ILIAS configuration file and by running the ILIAS update command afterwards. Note that this ILIAS setting does NOT block the `server.php` endpoint itself; a web server restriction is required for that. + +ILIAS uses SOAP internally for some asynchronous operations, most notably the cloning/copying of object trees (`ilClone` via `ilSoapUtils::callNextNode`). These calls are issued against the server's own configured (public) URL and, depending on name resolution on the host, originate either from the loopback address (`127.0.0.1`) or from the server's own IP address. You MUST whitelist this internal source address as well, otherwise these background operations will silently fail while the web interface keeps working. + +Apache2: + +``` + + Require all denied + Require ip %IPADDRESS% + +``` + +Nginx: + +``` + location /soap/ { + allow %IPADDRESS%; + deny all; + } +``` + +Please add all whitelisted ip addresses (%IPADDRESS%) here, including the internal loopback/server address as well as any external consumers (e.g. campus/identity management provisioning, cron-triggered SOAP jobs). + +**note:** +With Nginx, place the `allow`/`deny` directives in the same proxied `location` block as the `proxy_pass` directive. With Apache2, the `` block above also applies to reverse-proxied requests (`ProxyPass`), as access control is evaluated before the request is handed to the proxy handler — no separate configuration is required. + +Nginx: + +``` + location /soap/ { + allow %IPADDRESS%; + deny all; + proxy_pass http://%UPSTREAM%; + } +``` + ### Prevent blacklisted files of beeing served by the webserver If somebody tries to upload a file with a filetype blacklisted by the upload settings, the upload will take place, but the file will be renamed to `filename.sec`. The webserver should not serve this file anymore to it's visitors as the file may consists of malicious software. diff --git a/docs/development/contributing.md b/docs/development/contributing.md index 5e5c630f8388..63c71da31f31 100755 --- a/docs/development/contributing.md +++ b/docs/development/contributing.md @@ -69,7 +69,7 @@ code please make sure: * that your code is understandable and is documented - this will help reviewers as well * that your commit follows the [ILIAS coding - guidelines](https://docu.ilias.de/goto_docu_pg_202_42.html) - this is a + guidelines](./README.md#coding) - this is a bare minimum when it comes to style that we require for new code * you don't introduce new code violations which could have been easily found by importing and running our diff --git a/docs/development/how-to-write-a-privacy.md b/docs/development/how-to-write-a-privacy.md index 4fb3e4f89a53..0b9c6cd8f2c9 100644 --- a/docs/development/how-to-write-a-privacy.md +++ b/docs/development/how-to-write-a-privacy.md @@ -20,7 +20,7 @@ To extend or add the privacy documentation, base your Pull Request on the follow ### [Name of the component] Privacy -> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information via [Pull Request](docs/development/contributing.md#pull-request-to-the-repositories).** +> **Disclaimer: This documentation does not guarantee completeness or accuracy. Please report any missing or incorrect information by submitting a [Pull Request](https://github.com/ILIAS-eLearning/ILIAS/blob/trunk/docs/development/contributing.md#pull-request-to-the-repositories) or, if you prefer, via the [ILIAS bug tracker](https://mantis.ilias.de). When using the bug tracker, please select the corresponding component in the **Category** field.** ### General information diff --git a/docs/development/maintenance.md b/docs/development/maintenance.md index 9ce2fdbf9071..d5e215924d0a 100755 --- a/docs/development/maintenance.md +++ b/docs/development/maintenance.md @@ -218,12 +218,12 @@ of ILIAS. The file contains the following fields: [//]: # (BEGIN BackgroundTasks) * **BackgroundTasks** - * Authority to Sign off on Conceptual Changes: [tjoussen](https://docu.ilias.de/go/usr/103745), [mjansen](https://docu.ilias.de/go/usr/8784) - * Authority to Sign off on Code Changes: [tjoussen](https://docu.ilias.de/go/usr/103745), [mjansen](https://docu.ilias.de/go/usr/8784) + * Authority to Sign off on Conceptual Changes: [thojou](https://docu.ilias.de/go/usr/103745), [mjansen](https://docu.ilias.de/go/usr/8784) + * Authority to Sign off on Code Changes: [thojou](https://docu.ilias.de/go/usr/103745), [mjansen](https://docu.ilias.de/go/usr/8784) * Authority to Curate Test Cases: MISSING - * Authority to (De-)Assign Authorities: [tjoussen (Databay AG)](https://docu.ilias.de/go/usr/103745) - * Assignee for Issues: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Assignee for Security Reports: [tjoussen](https://docu.ilias.de/go/usr/103745) + * Authority to (De-)Assign Authorities: [thojou (Databay AG)](https://docu.ilias.de/go/usr/103745) + * Assignee for Issues: [thojou](https://docu.ilias.de/go/usr/103745) + * Assignee for Security Reports: [thojou](https://docu.ilias.de/go/usr/103745) * Unit-specific Guidelines, Rules, and Regulations: [LINK MISSING]('') [//]: # (END BackgroundTasks) @@ -285,11 +285,11 @@ of ILIAS. The file contains the following fields: * **Booking Pool** * Authority to Sign off on Conceptual Changes: [simon.lowe](https://docu.ilias.de/go/usr/79091), [oliver.samoila](https://docu.ilias.de/go/usr/26160) - * Authority to Sign off on Code Changes: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Authority to Curate Test Cases: [simon.lowe](https://docu.ilias.de/go/usr/79091), [tjoussen](https://docu.ilias.de/go/usr/103745) + * Authority to Sign off on Code Changes: [thojou](https://docu.ilias.de/go/usr/103745) + * Authority to Curate Test Cases: [simon.lowe](https://docu.ilias.de/go/usr/79091), [thojou](https://docu.ilias.de/go/usr/103745) * Authority to (De-)Assign Authorities: [simon.lowe (Databay AG)](https://docu.ilias.de/go/usr/79091), [oliver.samoila (Databay AG)](https://docu.ilias.de/go/usr/26160) - * Assignee for Issues: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Assignee for Security Reports: [tjoussen](https://docu.ilias.de/go/usr/103745) + * Assignee for Issues: [thojou](https://docu.ilias.de/go/usr/103745) + * Assignee for Security Reports: [thojou](https://docu.ilias.de/go/usr/103745) * Unit-specific Guidelines, Rules, and Regulations: [LINK MISSING]('') [//]: # (END BookingPool) @@ -556,7 +556,7 @@ of ILIAS. The file contains the following fields: * **ECS Interface** * Authority to Sign off on Conceptual Changes: [bogen](https://docu.ilias.de/go/usr/13815), [mglaubitz](https://docu.ilias.de/go/usr/28309) - * Authority to Sign off on Code Changes: [sdyhr](https://docu.ilias.de/go/usr/102107) + * Authority to Sign off on Code Changes: [sdyhr](https://docu.ilias.de/go/usr/102107), [thojou](https://docu.ilias.de/go/usr/103745) * Authority to Curate Test Cases: [jheim](https://docu.ilias.de/go/usr/40167), [SIG CampusConnect und ECS(A)](https://docu.ilias.de/go/grp/7893) * Authority to (De-)Assign Authorities: [bogen](https://docu.ilias.de/go/usr/13815), [mglaubitz](https://docu.ilias.de/go/usr/28309) * Assignee for Issues: [sdyhr](https://docu.ilias.de/go/usr/102107) @@ -806,11 +806,11 @@ of ILIAS. The file contains the following fields: * **ItemGroup** * Authority to Sign off on Conceptual Changes: [oliver.samoila](https://docu.ilias.de/go/usr/26160) - * Authority to Sign off on Code Changes: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Authority to Curate Test Cases: [oliver.samoila](https://docu.ilias.de/go/usr/26160), [tjoussen](https://docu.ilias.de/go/usr/103745) + * Authority to Sign off on Code Changes: [thojou](https://docu.ilias.de/go/usr/103745) + * Authority to Curate Test Cases: [oliver.samoila](https://docu.ilias.de/go/usr/26160), [thojou](https://docu.ilias.de/go/usr/103745) * Authority to (De-)Assign Authorities: [oliver.samoila (Databay AG)](https://docu.ilias.de/go/usr/26160) - * Assignee for Issues: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Assignee for Security Reports: [tjoussen](https://docu.ilias.de/go/usr/103745) + * Assignee for Issues: [thojou](https://docu.ilias.de/go/usr/103745) + * Assignee for Security Reports: [thojou](https://docu.ilias.de/go/usr/103745) * Unit-specific Guidelines, Rules, and Regulations: [LINK MISSING]('') [//]: # (END ItemGroup) @@ -819,7 +819,7 @@ of ILIAS. The file contains the following fields: * **KioskMode (aka General Kiosk Mode)** * Authority to Sign off on Conceptual Changes: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) - * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332),[cknof](https://docu.ilias.de/go/usr/90890) + * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332), [cknof](https://docu.ilias.de/go/usr/90890), [dkippKPG](https://docu.ilias.de/go/usr/120714) * Authority to Curate Test Cases: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) * Authority to (De-)Assign Authorities: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) * Assignee for Issues: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) @@ -832,7 +832,7 @@ of ILIAS. The file contains the following fields: * **Language** * Authority to Sign off on Conceptual Changes: [mkunkel](https://docu.ilias.de/go/usr/115) - * Authority to Sign off on Code Changes: [mkunkel](https://docu.ilias.de/go/usr/115), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [ChrisPotter](https://docu.ilias.de/go/usr/90855), [keven.clausen](https://docu.ilias.de/go/usr/100316), [cknof](https://docu.ilias.de/go/usr/90890) + * Authority to Sign off on Code Changes: [mkunkel](https://docu.ilias.de/go/usr/115), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [ChrisPotter](https://docu.ilias.de/go/usr/90855), [keven.clausen](https://docu.ilias.de/go/usr/100316), [cknof](https://docu.ilias.de/go/usr/90890), [dkippKPG](https://docu.ilias.de/go/usr/120714) * Authority to Curate Test Cases: [ChrisPotter](https://docu.ilias.de/go/usr/90855) * Authority to (De-)Assign Authorities: [mkunkel](https://docu.ilias.de/go/usr/115) * Assignee for Issues: [mkunkel](https://docu.ilias.de/go/usr/115) @@ -884,7 +884,7 @@ of ILIAS. The file contains the following fields: * **Learning Sequence** * Authority to Sign off on Conceptual Changes: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) - * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) + * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332), [dkippKPG](https://docu.ilias.de/go/usr/120714) * Authority to Curate Test Cases: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) * Authority to (De-)Assign Authorities: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) * Assignee for Issues: [katrin.grosskopf](https://docu.ilias.de/go/usr/68340) @@ -911,8 +911,8 @@ of ILIAS. The file contains the following fields: * **Like** * Authority to Sign off on Conceptual Changes: [oliver.samoila](https://docu.ilias.de/go/usr/26160) - * Authority to Sign off on Code Changes: [fhelfer](https://docu.ilias.de/go/usr/93367), [tjoussen](https://docu.ilias.de/go/usr/103745) - * Authority to Curate Test Cases: [fhelfer](https://docu.ilias.de/go/usr/93367), [tjoussen](https://docu.ilias.de/go/usr/103745), [oliver.samoila](https://docu.ilias.de/go/usr/26160) + * Authority to Sign off on Code Changes: [fhelfer](https://docu.ilias.de/go/usr/93367), [thojou](https://docu.ilias.de/go/usr/103745) + * Authority to Curate Test Cases: [fhelfer](https://docu.ilias.de/go/usr/93367), [thojou](https://docu.ilias.de/go/usr/103745), [oliver.samoila](https://docu.ilias.de/go/usr/26160) * Authority to (De-)Assign Authorities: [oliver.samoila (Databay AG)](https://docu.ilias.de/go/usr/26160) * Assignee for Issues: [fhelfer](https://docu.ilias.de/go/usr/93367) * Assignee for Security Reports: [fhelfer](https://docu.ilias.de/go/usr/93367) @@ -937,9 +937,9 @@ of ILIAS. The file contains the following fields: * **Login, Auth & Registration** * Authority to Sign off on Conceptual Changes: [mjansen](https://docu.ilias.de/go/usr/8784) - , [tjoussen](https://docu.ilias.de/go/usr/103745) + , [thojou](https://docu.ilias.de/go/usr/103745) * Authority to Sign off on Code Changes: [mjansen](https://docu.ilias.de/go/usr/8784) - , [tjoussen](https://docu.ilias.de/go/usr/103745) + , [thojou](https://docu.ilias.de/go/usr/103745) * Authority to Curate Test Cases: [mjansen](https://docu.ilias.de/go/usr/8784) * Authority to (De-)Assign Authorities: [mjansen (Databay AG)](https://docu.ilias.de/go/usr/8784) * Assignee for Issues: [mjansen](https://docu.ilias.de/go/usr/8784) @@ -1004,7 +1004,7 @@ of ILIAS. The file contains the following fields: * **Maps** * Authority to Sign off on Conceptual Changes: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) - * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) + * Authority to Sign off on Code Changes: [keven.clausen](https://docu.ilias.de/go/usr/100316), [katrin.grosskopf](https://docu.ilias.de/go/usr/68340), [jeanine.auerbach](https://docu.ilias.de/go/usr/101332), [dkippKPG](https://docu.ilias.de/go/usr/120714) * Authority to Curate Test Cases: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) * Authority to (De-)Assign Authorities: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) * Assignee for Issues: [jeanine.auerbach](https://docu.ilias.de/go/usr/101332) @@ -1095,11 +1095,11 @@ of ILIAS. The file contains the following fields: * **News** * Authority to Sign off on Conceptual Changes: [oliver.samoila](https://docu.ilias.de/go/usr/26160) - * Authority to Sign off on Code Changes: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Authority to Curate Test Cases: [tjoussen](https://docu.ilias.de/go/usr/103745), [oliver.samoila](https://docu.ilias.de/go/usr/26160) + * Authority to Sign off on Code Changes: [thojou](https://docu.ilias.de/go/usr/103745) + * Authority to Curate Test Cases: [thojou](https://docu.ilias.de/go/usr/103745), [oliver.samoila](https://docu.ilias.de/go/usr/26160) * Authority to (De-)Assign Authorities: [oliver.samoila (Databay AG)](https://docu.ilias.de/go/usr/26160) - * Assignee for Issues: [tjoussen](https://docu.ilias.de/go/usr/103745) - * Assignee for Security Reports: [tjoussen](https://docu.ilias.de/go/usr/103745) + * Assignee for Issues: [thojou](https://docu.ilias.de/go/usr/103745) + * Assignee for Security Reports: [thojou](https://docu.ilias.de/go/usr/103745) * Unit-specific Guidelines, Rules, and Regulations: [LINK MISSING]('') [//]: # (END News) @@ -1401,7 +1401,7 @@ of ILIAS. The file contains the following fields: * Authority to Sign off on Code Changes: [abrahammordev](https://docu.ilias.de/go/usr/110909), [juanma1331](https://docu.ilias.de/go/usr/107249) * Authority to Curate Test Cases: [jcopado](https://docu.ilias.de/go/usr/30511) * Authority to (De-)Assign Authorities: [jcopado](https://docu.ilias.de/go/usr/30511) - * Assignee for Issues: [jcopado](https://docu.ilias.de/go/usr/30511) + * Assignee for Issues: [abrahammordev](https://docu.ilias.de/go/usr/110909) * Assignee for Security Reports: [jcopado](https://docu.ilias.de/go/usr/30511) * Unit-specific Guidelines, Rules, and Regulations: [LINK MISSING]('') @@ -1479,7 +1479,7 @@ of ILIAS. The file contains the following fields: * Authority to Sign off on Conceptual Changes: [dstrassner](https://docu.ilias.de/go/usr/48931) * Authority to Sign off on Code Changes: [skergomard](https://docu.ilias.de/go/usr/44474) , [dstrassner](https://docu.ilias.de/go/usr/48931) - , [tjoussen](https://docu.ilias.de/go/usr/103745) + , [thojou](https://docu.ilias.de/go/usr/103745) * Authority to Curate Test Cases: [dstrassner](https://docu.ilias.de/go/usr/48931) * Authority to (De-)Assign Authorities: [dstrassner](https://docu.ilias.de/go/usr/48931) * Assignee for Issues: [dstrassner](https://docu.ilias.de/go/usr/48931) diff --git a/docs/development/security.md b/docs/development/security.md index 9881338c2452..bff91440cf39 100755 --- a/docs/development/security.md +++ b/docs/development/security.md @@ -1,4 +1,4 @@ -# ILIAS Security Group +# ILIAS Security Policy ## Table of Contents * [Reporting Security Issues](#reporting-security-issues) diff --git a/docs/development/supported-versions.md b/docs/development/supported-versions.md index 077328007741..db14aedf7099 100755 --- a/docs/development/supported-versions.md +++ b/docs/development/supported-versions.md @@ -1,50 +1,239 @@ # Supported Versions -Every ILIAS version will be **fully supported** until the end of the year after -the year it was released in. **Fully supported** means that every kind of issue -that is reported for the release according to our bugfixing process is eligible -for a fix. *E.g.: A usability issue, reported for ILIAS 10 (released 2025), can -be reported in August 2026 and is eligible for a fix then.* - -Every ILIAS version will then gain **security support** for an additional year -after that. **Security support** means that we are fixing security issues only. -*E.g.: A security issue, reported for ILIAS 10 (release 2025), can be reported -in August 2027 and is eligible for a fix then. A malfunction that does make the -program crash, reported at the same moment, won't be eligible for a fix.* - - -## Timeline per Version - -With that support schedule, every version will have (roughly) the following timeline: - -| Date | ILIAS X | ILIAS (X+1) | ILIAS (X+2) | -|-----------|-------------------------|-------------------------|-------------------------| -| 20X4, Nov | Project Jour Fixe | | | -| 20X5, Oct | Coding Completed | | | -| 20X5, Nov | Start of Beta Phase | Project Jour Fixe | | -| 20X6, Mar | Release | | | -| 20X6, Oct | | Coding Completed | | -| 20X6, Nov | | Start of Beta Phase | Project Jour Fixe | -| 20X7, Mar | | Release | | -| 20X7, Oct | | | Coding Completed | -| 20X7, Dec | End of Full Support | | Start of Beta Phase | -| 20X8, Mar | | | Release | -| 20X8, Dec | End of Security Support | End of Full Support | | -| 20X9, Dec | | End of Security Support | End of Full Support | -| 20Y0, Dec | | | End of Security Support | - - -## Implications - -* If we follow this optimal timeline, users have roughly 3/4 year to update to the - next fully supported version. This can be expanded to 1 3/4 year if users skip - every other fully supported version. -* From the project planning jour fixe to the end of security support, every version is - active for a little more then four years. -* Most of the time, the community will need to keep track of four different version - in different states of their life cycle. -* Most of the changes that fix issues will need to be included in three branches, - fixes for security issues will need to be included in four branches. +> **In a nutshell** +> A new ILIAS version is released roughly every year (usually in spring). +> After its release, each version goes through **two support phases**: +> +> 1. **Full support** – *every* reported issue may be fixed +> (bugs, usability problems, security problems …). +> 2. **Security support** – *only security* issues are fixed. +> +> A simple rule of thumb: +> **Full support covers the release year plus the following year; after that +> comes one more year of security-only support.** +> Then the version reaches its end of life. + +This document explains the exact rules, shows how several versions overlap over +time, and summarises what it means for the different people who work with ILIAS. + + +## How long is a version supported? + +The two phases are defined precisely as follows: + +| Phase | Lasts until … | What gets fixed | +|-----------------------|----------------------------------------------------------|------------------------------------------| +| **Full support** | the **end of the year *after* the release year** | any kind of issue (bug, usability, security …) | +| **Security support** | the **end of the following year** (one more year) | security issues **only** | +| **End of life** | after security support ends | nothing – please upgrade | + +**Examples (ILIAS 10, released in 2025):** + +* A **usability** issue reported in **August 2026** *is* eligible for a fix – + ILIAS 10 is still in **full support** (until the end of 2026). +* A **security** issue reported in **August 2027** *is* eligible for a fix – + ILIAS 10 is then in **security support** (until the end of 2027). +* A **crash / malfunction** reported in **August 2027** is **not** eligible – + in the security phase only security issues are fixed. + + +## The life cycle of a single version + +Every version passes through the same milestones. The months below are given +**relative to its release** (releases usually happen in **March**): + +```mermaid +flowchart LR + JF["Project
    Jour Fixe
    ~16 months before"] --> CC["Coding
    Completed
    ~5 months before"] + CC --> BETA["Beta Phase
    starts
    ~4 months before"] + BETA --> REL["RELEASE
    March"] + REL --> FS["Full Support
    until end of
    next year
    "] + FS --> SEC["Security only
    + 1 more year"] + SEC --> EOL["End of Life"] + + style REL fill:#2e7d32,color:#fff + style FS fill:#1565c0,color:#fff + style SEC fill:#c62828,color:#fff + style EOL fill:#616161,color:#fff +``` + +| Milestone | When (relative to release) | Meaning | +|-------------------------|----------------------------|------------------------------------------------------| +| Project Jour Fixe | ~16 months before release | Planning of the version starts | +| Coding Completed | ~5 months before release | No new features are added; stabilisation begins | +| Start of Beta Phase | ~4 months before release | Testable pre-release available | +| **Release** | **month 0 (March)** | Full support starts | +| End of Full Support | December of *release year + 1* | Switch to security-only support | +| End of Security Support | December of *release year + 2* | End of life | + +From the first planning meeting to the end of security support, a version stays +active for **a little more than four years**. + +### How consecutive versions overlap + +A new version is already being planned and built while the previous one is still +supported, so **several life cycles run in parallel**. The table below is the +classic overview, but with concrete example versions instead of abstract +placeholders. It follows **ILIAS 12, 13 and 14** through every milestone. +Read it **top to bottom for time**; **each column is one version** +*(months are illustrative — the pattern repeats for every version)*: + +| When | ILIAS 12 | ILIAS 13 | ILIAS 14 | +|------------|--------------------------|--------------------------|--------------------------| +| 2025, Nov | Project Jour Fixe | | | +| 2026, Oct | Coding Completed | | | +| 2026, Nov | Start of Beta Phase | Project Jour Fixe | | +| 2027, Mar | **Release** | | | +| 2027, Oct | | Coding Completed | | +| 2027, Nov | | Start of Beta Phase | Project Jour Fixe | +| 2028, Mar | | **Release** | | +| 2028, Oct | | | Coding Completed | +| 2028, Nov | | | Start of Beta Phase | +| 2028, Dec | End of Full Support | | | +| 2029, Mar | | | **Release** | +| 2029, Dec | End of Security Support | End of Full Support | | +| 2030, Dec | | End of Security Support | End of Full Support | +| 2031, Dec | | | End of Security Support | + +### Which version is in which phase each year + +The same information, but viewed **per calendar year** — this is usually the +question administrators and project managers actually ask: *"What is supported +**this** year?"* + +| Year | ILIAS 12 | ILIAS 13 | ILIAS 14 | +|------|-------------------|-------------------|-------------------| +| 2026 | Beta (from Nov) | – | – | +| 2027 | **Full support** | Beta (from Nov) | – | +| 2028 | **Full support** | **Full support** | Beta (from Nov) | +| 2029 | Security only | **Full support** | **Full support** | +| 2030 | End of life | Security only | **Full support** | +| 2031 | End of life | End of life | Security only | + +Reading a single row shows the recurring pattern: in a typical year there are +**two versions in full support** plus **one older version in security-only +support**. For example, in **2029** both ILIAS 13 and ILIAS 14 are fully +supported, while ILIAS 12 only receives security fixes. + + +## Concrete example with real versions + +To avoid abstract placeholders, here is how consecutive versions line up on the +calendar. *(Exact dates are illustrative; the binding rule is the two-phase +definition above.)* + +| Version | Released | Full support until | Security support until | +|-----------|----------|--------------------|------------------------| +| ILIAS 12 | 2027 | end of **2028** | end of **2029** | +| ILIAS 13 | 2028 | end of **2029** | end of **2030** | +| ILIAS 14 | 2029 | end of **2030** | end of **2031** | +| ILIAS 15 | 2030 | end of **2031** | end of **2032** | + +Because the phases overlap, **several versions are supported at the same time**. +The Gantt chart below makes this visible — read it top to bottom (versions) and +left to right (years): + +```mermaid +gantt + title ILIAS Support Phases Over Time (illustrative) + dateFormat YYYY-MM-DD + axisFormat %Y + + section ILIAS 12 + Beta :done, 2026-11-01, 2027-03-01 + Full support :active, 2027-03-01, 2028-12-31 + Security only :crit, 2029-01-01, 2029-12-31 + + section ILIAS 13 + Beta :done, 2027-11-01, 2028-03-01 + Full support :active, 2028-03-01, 2029-12-31 + Security only :crit, 2030-01-01, 2030-12-31 + + section ILIAS 14 + Beta :done, 2028-11-01, 2029-03-01 + Full support :active, 2029-03-01, 2030-12-31 + Security only :crit, 2031-01-01, 2031-12-31 + + section ILIAS 15 + Beta :done, 2029-11-01, 2030-03-01 + Full support :active, 2030-03-01, 2031-12-31 + Security only :crit, 2032-01-01, 2032-12-31 +``` + +**Legend:** grey = beta / pre-release · blue = full support · red = security +only. Draw an imaginary vertical line at any year and you will usually cross +**two versions in full support** and **one version in security-only support**. + + +## What this means for you + +Two very different groups work with these support phases. **Authorities** build +and safeguard ILIAS itself; **Users** run and operate ILIAS in their +organisations. Each group cares about a different part of the cycle. + +### Authorities (Code, Concept, Test Case Curation, Security) + +These are the roles responsible for *producing* and *safeguarding* the software. +Their key concern is **into how many versions a change has to flow**. + +* **Code (maintainers / developers)** + * A normal bug fix typically has to be applied to **three branches** — trunk + plus the **two fully supported versions**. + * Write fixes so they can be cleanly back-ported across these branches. + +* **Concept (product & feature planning)** + * Plan features around the milestones of the *upcoming* version — from + *Project Jour Fixe* to *Coding Completed* (see the life-cycle chapter). + +* **Test Case Curation** + * You decide which scenarios, workflows and edge cases must be covered before a + release can be considered safe. Your test cases should reflect what + institutions actually do with ILIAS — not only what developers build. + * The **Beta Phase** (from ~November before the March release) is when your + curated test cases matter most: new and changed behaviour is available for + verification, but the release is not yet final. + +* **Security** + * A security fix has the widest reach: it typically has to be applied to + **four branches** — trunk plus the two fully supported versions **plus** the + version that is still in security-only support. + * Security is the *only* kind of fix that a version keeps receiving after it + has left full support. + +### Users (Organisation Administrators, Help Desk, Domain Experts) + +These are the roles that *operate* ILIAS at an institution and support its +day-to-day use. Their key concern is **which version to run and when to upgrade**. + +* **Organisation administrators (system operations)** + * You have roughly **¾ of a year** to move to the next fully supported version + before your current one leaves full support. + * If you upgrade only every *other* version, you still stay within full + support, but your planning runway across two cycles shrinks to about + **1¾ years**. + * Once a version is **security only**, plan the upgrade — normal bugs will no + longer be fixed. After end of life, upgrade as soon as possible. + +* **Help Desk / support staff** + * Before promising/requesting a fix, check the version's phase: + * **Full support** → any issue may be fixed. + * **Security only** → only security issues are fixed; other reports are + moved to a still fully supported version (see below). + * **End of life** → the user must upgrade. + +* **Domain experts of institutions** + * You design and run e-learning scenarios (courses, assessments, collaboration + workflows …) and often depend on **new ILIAS features** to realise them. + * New features appear in the **upcoming release** — first in beta, then in the + March release. Plan your scenarios around that rhythm: what you need may not + exist in your current version yet. + * If you stay on an older version (especially one in **security-only** + support), you will **not** receive new features — only security fixes. To + use new capabilities, your institution must upgrade to a fully supported + version. + * Use the beta phase to try out whether a planned scenario works with the new + features before your institution upgrades. + ## Transition to Security Support @@ -52,6 +241,15 @@ When a version transitions from **full support** to **security support** (at the end of the year), open issues in the Mantis bug tracker for this version are handled as follows to ensure that reported problems are not lost: +```mermaid +flowchart TD + A["Version enters
    security-only phase"] --> B{"Issue in an eligible
    status?"} + B -->|no| C["Leave as is"] + B -->|yes| D["Move 'Target Version' to the next
    still fully supported version"] + D --> E["Assignee re-checks whether the
    issue still exists in maintained versions"] + E --> F["Add a comment informing
    the reporter"] +``` + 1. **Eligibility for Transition**: All issues with the following status are considered: `open`, `unassigned`, `feedback`, `needs JF decision`, `postponed`, `funding needed`, `assigned`, `fixing acc to prio`. @@ -68,4 +266,4 @@ are handled as follows to ensure that reported problems are not lost: entered the security-fix-only phase. We have moved this issue to the next maintained version for further investigation." -This applies to issues for ILIAS 10 or greater. \ No newline at end of file +This applies to issues for ILIAS 10 or greater. diff --git a/docs/development/tutorial/02-tools/03-setup.md b/docs/development/tutorial/02-tools/03-setup.md index 43f06beb8206..a4091c72982d 100644 --- a/docs/development/tutorial/02-tools/03-setup.md +++ b/docs/development/tutorial/02-tools/03-setup.md @@ -80,7 +80,7 @@ you have been successfull and can move on to the next step. ### Create a Configuration To install ILIAS you need a configuration file that contains basic configuration -for your installation. Create a copy of the file `components/ILIAS/setup_/minimal-config.json`. +for your installation. Create a copy of the file `components/ILIAS/Setup/minimal-config.json`. Open the file in a text editor and adjust it according to your requirements. Have a look into [the documentation of the setup](../../../../../components/ILIAS/Setup/README.md#about-the-config-file) for additional configuration variables. diff --git a/lang/ilias_ar.lang b/lang/ilias_ar.lang index e1c0c51f7ca6..9d902b3f5c45 100644 --- a/lang/ilias_ar.lang +++ b/lang/ilias_ar.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#تفعيل تسجيل الاختبار والتقييم assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#اضافة حل مقترح assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area assessment#:#add_gap#:#Add Gap Text @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Your solution is correct assessment#:#answer_is_wrong#:#Your solution is wrong assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Answer Text assessment#:#answer_types#:#Answer Types @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions. assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Cloze Text -assessment#:#cloze_textgap_case_insensitive#:#Case Insensitive -assessment#:#cloze_textgap_case_sensitive#:#Case Sensitive -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein Distance of %s assessment#:#code#:#Code assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Concatenation @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Gap assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Glossary Term assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Insert After assessment#:#insert_before#:#Insert Before -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Internal Links assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Maintenance assessment#:#manscoring#:#Manual Scoring assessment#:#manscoring_done#:#Scored Participants @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#You have reached the maximum number o assessment#:#maximum_points#:#Maxium Available Points assessment#:#maxsize#:#Maximum file upload size assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#You must define a minimum percentage of 0 percent! The mark schema wasn't saved. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions. assessment#:#msg_poly_added#:#Polygon added assessment#:#msg_questions_moved#:#Question(s) moved @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence. assessment#:#ordertext#:#Ordering Text assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output assessment#:#output_mode#:#Output Mode assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#هل انت متأكد من أنك تريد حذف السؤال \الاسئلة التالي\ة؟ assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard assessment#:#qpl_delete_rbac_error#:#You have no rights to delete this question! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#The question you are about to edit exists in %s test(s). If you change this question, you will NOT change the question(s) in the test(s), because the system creates a copy of a question when it is inserted in a test! assessment#:#qpl_questions_deleted#:#Question(s) deleted. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Question Title assessment#:#question_type#:#Question Type assessment#:#questionpool_not_entered#:#Please enter a name for a question pool! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#questions from assessment#:#questions_per_page_view#:#Page View assessment#:#random_accept_sample#:#Accept Sample assessment#:#random_another_sample#:#Get another Sample assessment#:#random_selection#:#Random Selection assessment#:#range#:#Range -assessment#:#range_lower_limit#:#Lower Bound assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper Bound assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Search Roles assessment#:#search_term#:#مصطلح البحث assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Select Gap assessment#:#select_max_one_item#:#الرجاء اختيار عنصر واحد فقط assessment#:#select_one_user#:#Please select at least one user. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Answers -assessment#:#shuffle_answers#:#Shuffle Answers assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#انت لا تملك الصلاحية للصق ال common#:#msg_no_perm_paste_object_in_folder#:#%s في المجلد %s انت لا تملك الصلاحية للصق العنصر common#:#msg_no_perm_perm#:#انت لا تملك الصلاحية لتعديل اعدادات الصلاحية common#:#msg_no_perm_read#:#انت لا تملك الصلاحية للوصول الى هذا العنصر -common#:#msg_no_perm_read_item#:# '%s' انت لا تملك الصلاحية للوصول الى العنصر +common#:#msg_no_perm_read_item#:#انت لا تملك الصلاحية للوصول الى العنصر common#:#msg_no_perm_read_lm#:#انت لا تملك الصلاحية لقراءة الوحدة التعليمية هذه common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#انت لا تملك الصلاحية للكتابة @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Cloze Text +qsts#:#cloze_textgapcase_insensitive#:#Case Insensitive +qsts#:#cloze_textgapcase_sensitive#:#Case Sensitive +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein Distance of %s +qsts#:#confirm_delete_questions#:#هل انت متأكد من أنك تريد حذف السؤال \الاسئلة التالي\ة؟ +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Gap +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower Bound +qsts#:#range_upper_limit#:#Upper Bound +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Select Gap +qsts#:#shuffle_answers#:#Shuffle Answers +qsts#:#suggested_learning_content#:#اضافة حل مقترح rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Question Block survey#:#questionblock_inserted#:#Question Block inserted survey#:#questionblocks#:#Question Blocks survey#:#questionblocks_inserted#:#Question Blocks inserted -survey#:#questions#:#Questions survey#:#questions_inserted#:#Question(s) inserted! survey#:#questions_removed#:#Question(s) and/or question block(s) removed! survey#:#questiontype#:#Question Type @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Questions survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_bg.lang b/lang/ilias_bg.lang index ec20f122d166..85a1bdf749ca 100644 --- a/lang/ilias_bg.lang +++ b/lang/ilias_bg.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###26 08 2024 new v assessment#:#activate_logging#:#Активиране записването на теста и оценяването assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Добавяне на текст в празнина @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Вашето решение е правилно assessment#:#answer_is_wrong#:#Вашето решение е грешно assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Текст за отговора assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Затваряне на текста -assessment#:#cloze_textgap_case_insensitive#:#Case insensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_case_sensitive#:#Case sensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable assessment#:#code#:#Код assessment#:#codebase#:#Codebase###25 02 2007 new variable assessment#:#concatenation#:#Concatenation###06 09 2006 new variable @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Празнина assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Термин от речника assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Вмъкване след assessment#:#insert_before#:#Вмъкване преди -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Вътрешни линкове assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Поддръжка assessment#:#manscoring#:#Manual Scoring###25 02 2007 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Достигнали сте макс assessment#:#maximum_points#:#Maxium Available Points###25 02 2007 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Трябва да дефинирате минимален резултат от 0 процента! Схемата с оценките не е съхранена. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 02 2007 new variable assessment#:#output_mode#:#Output Mode###25 02 2007 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Сигурни ли сте, че желаете да изтриете следният въпрос(и)? Ако изтриете заключен въпрос, резултатите от всички тестове, съдържащи заключения въпрос, също ще бъдат изтрити. assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard###03 Nov 2005 new variable assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard###03 Nov 2005 new variable assessment#:#qpl_delete_rbac_error#:#Нямате права, за да изтриете този въпрос! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Въпросът, който желаете да редактирате, съществува в %s тест(а). Ако промените този въпрос, НЯМА да се получи промяна във въпроса(ите) в теста(овете), защото системата създава копие на въпроса, когато той бъде вмъкнат в тест! assessment#:#qpl_questions_deleted#:#Въпросът(ите) изтрит(и). -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Заглавие на въпроса assessment#:#question_type#:#Тип на въпроса assessment#:#questionpool_not_entered#:#Моля, въведете име за набора от въпроси! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#въпроси от assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Приемане на примера assessment#:#random_another_sample#:#Извличане на друг пример assessment#:#random_selection#:#Случаен подбор assessment#:#range#:#Range###25 02 2007 new variable -assessment#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Search Roles###06 09 2006 new variable assessment#:#search_term#:#Search Term###06 09 2006 new variable assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Изберете празнина assessment#:#select_max_one_item#:#Моля, изберете само едно assessment#:#select_one_user#:#Please select at least one user###23 Dec 2005 new variable assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Разбъркване на отговорите assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Нямате разрешени права да з common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Нямате разрешени права да редактирате разрешителните настройки common#:#msg_no_perm_read#:#You have no permission to access this item.###06 09 2006 new variable -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###25 02 2007 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access the object. common#:#msg_no_perm_read_lm#:#Нямате разрешени права да четете от този модул за обучение. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Нямате разрешени права да записвате @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Затваряне на текста +qsts#:#cloze_textgapcase_insensitive#:#Case insensitive###03 Nov 2005 new variable +qsts#:#cloze_textgapcase_sensitive#:#Case sensitive###03 Nov 2005 new variable +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable +qsts#:#confirm_delete_questions#:#Сигурни ли сте, че желаете да изтриете следният въпрос(и)? Ако изтриете заключен въпрос, резултатите от всички тестове, съдържащи заключения въпрос, също ще бъдат изтрити. +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Празнина +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable +qsts#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Изберете празнина +qsts#:#shuffle_answers#:#Разбъркване на отговорите +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Блок въпроси survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Блокове въпроси survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Въпроси survey#:#questions_inserted#:#Въпросът(ите) вмъкнат(и)! survey#:#questions_removed#:#Въпросът(ите) и/или блокът(овете) въпроси премахнат(и)! survey#:#questiontype#:#Тип въпрос @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Въпроси survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_cs.lang b/lang/ilias_cs.lang index 0cd6fb6a5092..f24cf377e7bb 100644 --- a/lang/ilias_cs.lang +++ b/lang/ilias_cs.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Zapnout TinyMCE pro editaci WYSIWYG assessment#:#activate_logging#:#Aktivovat záznam Test a Hodnocení assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Přidat doporučené řešení assessment#:#add_answers#:#Přidat odpovědi assessment#:#add_circle#:#Přidat kruhovou plochu assessment#:#add_gap#:#Přidat textovou mezeru @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Obdržel/a jste body za Vaše assessment#:#answer_is_right#:#Vaše řešení je správné assessment#:#answer_is_wrong#:#Vaše řešení je chybné assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Možnosti odpovědi: assessment#:#answer_question#:#Odpovědět na otázku assessment#:#answer_text#:#Text odpovědi assessment#:#answer_types#:#Typy odpovědi @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Splnit odevzdáním assessment#:#ass_completion_by_submission_info#:#Je-li zapnuto, odevzdání alespoň jednoho souboru způsobí splnění dané otázky s přidělením maximálního počtu bodů této otázky. Tento počet bodů může být později změněn manuálně. Změna tohoto nastavení nemá vliv na již odevzdaná řešení. assessment#:#ass_create_export_file_with_results#:#Vytvořit exportní soubor testu (vč. výsledků účastníků) assessment#:#ass_create_export_test_archive#:#Vytvořit archivní soubor testu -assessment#:#ass_create_question#:#Vytvořit otázku assessment#:#ass_imap_hint#:#Nápověda zobrazena jako nápovědná bublina assessment#:#ass_imap_map_file_not_readable#:#Nahranou obrazovou mapu nelze načíst. assessment#:#ass_imap_no_map_found#:#V nahrané obrazové mapě nelze najít žádný formulář. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Délka textového pole assessment#:#cloze_fixed_textlength_description#:#Pokud vložíte hodnotu větší než 0, všechna textová pole textových i numerických mezer budou vytvářeny s pevnou délkou rovnou této hodnotě. assessment#:#cloze_gap_size_info#:#Pokud zadáte hodnotu větší než 0, bude toto textové pole mezery vytvořeno s pevnou délkou této hodnoty. Pokud nezadáte hodnotu, bude textové pole mezery vytvořeno s hodnotou globální pevné délky. -assessment#:#cloze_text#:#Doplňovaný text -assessment#:#cloze_textgap_case_insensitive#:#Nerozlišuje velká/malá písmena -assessment#:#cloze_textgap_case_sensitive#:#Rozlišuje velká/malá písmena -assessment#:#cloze_textgap_levenshtein_of#:#Vzdálenost Levenshtein %s assessment#:#code#:#Kód assessment#:#codebase#:#Databáze kódu assessment#:#concatenation#:#Sřetězení @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Můžete zadat předem definované proměnné ($v assessment#:#fq_no_restriction_info#:#Desetinná místa i zlomky jsou přijaty jako vstup. assessment#:#fq_precision_info#:#Zadejte počet požadovaných desetinných míst. assessment#:#fq_question_desc#:#Můžete určit proměnné vložením $v1, $v2 ... $vn, výsledky vložením $r1, $r2 .... $rn na požadované místo v textu otázky. Klepněte na tlačítko "Rozbor otázky" k vytvoření ediovaního formuláře pro proměnné a výsledky. -assessment#:#gap#:#Mezera assessment#:#gap_combination#:#Kombinace mezer -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Pojem glosáře assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Vaše výsledná známka je: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Tato otázka již obsahuje obrázky. Nem assessment#:#info_text_upload#:#Vyberte soubor odpovědí, který chcete nahrát assessment#:#insert_after#:#Vložit za assessment#:#insert_before#:#Vložit před -assessment#:#insert_gap#:#Vložit rezervované místo assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Interní odkazy assessment#:#intprecision#:#Dělitelné @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Účastník zadal nesprávné h assessment#:#longmenu#:#Dlouhé menu assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Text dlouhého menu -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Údržba assessment#:#manscoring#:#Manuální hodnocení assessment#:#manscoring_done#:#Vyhodnocení účastníci @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Dosáhl/a jste maximální počet pok assessment#:#maximum_points#:#Maxium dostupných bodů assessment#:#maxsize#:#Maximální velkost ukládaného souboru assessment#:#maxsize_info#:#Vložit maximální velikost v bytech, která je povolena pro ukládané soubory. Pokud necháte toto pole prázdné, bude namísto něj nastavena maximální velikost této instalace. -assessment#:#min_auto_complete#:#Automatické dokončování assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Musíte definovat minimální procento od specifikace 0 procent! Schéma známkování nebylo uloženo. assessment#:#misc#:#Různé možnosti @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Kruh přidán -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Počet výrazů musí být větší, nebo roven počtu definicí. assessment#:#msg_poly_added#:#Polygon přidán assessment#:#msg_questions_moved#:#Otázky přesunuty @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Sekvence odpovědi Vámi zde definovaná bude považována za sekvenci správného řešení. assessment#:#ordertext#:#Řazení textu assessment#:#ordertext_info#:#Vložte prosím text, který má být řazen horizontálně. Řazený text bude oddělen pomocí značek mezer v textu. Pokud potřebujete jiné oddělení, můžete použít separátor %s k oddělení Vašich textových jednotek. -assessment#:#out_of_range#:#Mimo rozsah assessment#:#output#:#Výstup assessment#:#output_mode#:#Výstupní mód assessment#:#parseQuestion#:#Rozbor otázky @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Zrušit -assessment#:#qpl_confirm_delete_questions#:#Jste si jist/a, že chcete smazat následující otázky? assessment#:#qpl_copy_insert_clipboard#:#Vybrané otázky jsou zkopírovány do schránky assessment#:#qpl_copy_select_none#:#Označte alespoň jednu otázku ke zkopírování do schránky assessment#:#qpl_delete_rbac_error#:#Nemáte oprávnění smazat tuto otázku! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Způsobilost assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Celkový součet bodů způsobilosti podle způsobilosti assessment#:#qpl_question_is_in_use#:#Otázka, kterou upravujete, existuje v %s testech. Pokud tuto otázku změníte, NEZMĚNÍTE otázku(y) v testu(ech), protože systém vytváří kopii otázky, která je vložena do testu! assessment#:#qpl_questions_deleted#:#Otázky smazány. -assessment#:#qpl_reset_preview#:#Obnovit náhled assessment#:#qpl_save_skill_assigns_update#:#Uložit přiřazení způsobilosti assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Pokud je zapnuto, pro filtrování jsou zobrazeny možné vytvořené taxonomie. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Počet pokusů @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Název otázky assessment#:#question_type#:#Typ otázky assessment#:#questionpool_not_entered#:#Vložte prosím název zásobníku otázek! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#otázky z assessment#:#questions_per_page_view#:#Zobrazení stránky assessment#:#random_accept_sample#:#Akceptovat příklad assessment#:#random_another_sample#:#Vybrat jiný příklad assessment#:#random_selection#:#Náhodný výběr assessment#:#range#:#Rozmezí -assessment#:#range_lower_limit#:#Spodní hranice assessment#:#range_max#:#Rozmezí (Maximum) assessment#:#range_min#:#Rozmezí (Minimum) -assessment#:#range_upper_limit#:#Horní hranice assessment#:#rated_sign#:#Podpis assessment#:#rated_unit#:#Jednotka assessment#:#rated_value#:#Hodnota @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Vyhledat role assessment#:#search_term#:#Vyhledat termín assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Vybrat mezeru assessment#:#select_max_one_item#:#Vyberte prosím pouze jednu položku assessment#:#select_one_user#:#Vyberte prosím alespoň jednoho uživatele assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Zobrazit přehled označených průchodů assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Zobrazit označené odpovědi uživatelů -assessment#:#shuffle_answers#:#Zamíchat odpovědi assessment#:#skip_question#:#Neodpovídat a Další assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text @@ -1401,7 +1372,7 @@ assessment#:#tst_answered_questions_of_total#:#%s z %s assessment#:#tst_answered_questions_test#:#Zodpovězené otázky v tomto testu assessment#:#tst_attached_xls_file#:#Výsledek testu tohoto účastníka najdete v přiloženém souboru aplikace Excel. assessment#:#tst_attempt#:#Pokus -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#Celkový počet pokusů pro tento test: %s. assessment#:#tst_attempt_started#:#Test spuštěn assessment#:#tst_back_to_pass_details#:#Podrobnosti zpět na průchodu assessment#:#tst_back_to_question_list#:#Zpět na seznam otázek @@ -1452,7 +1423,7 @@ assessment#:#tst_derive_new_pools#:#Odvodit nové zásobníky otázek assessment#:#tst_dont_show_msg_again_in_current_session#:#Znovu nezobrazovat tuto zprávu v mé aktuální relaci. assessment#:#tst_edit_competence_assign#:#Upravit vlastnosti přiřazení assessment#:#tst_edit_scoring#:#Upravit hodnocení -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#Zobrazit „Seznam otázek“ assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#Čas ukončení assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1477,14 +1448,14 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#Zadejte heslo pro spuštění testu. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#Slovo pro průchod testem assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password_label#:#Heslo assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable +assessment#:#tst_exam_start#:#Spustit test +assessment#:#tst_exam_use_previous_answers#:#Použít předchozí odpovědi assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#Pracovní čas účastníka byl zvýšen o %s minut. assessment#:#tst_extratime_info#:#Pokud chcete pro stejného účastníka několikrát přidat pracovní čas, zadejte celkovou dobu, kterou chcete přidat. @@ -1504,7 +1475,7 @@ assessment#:#tst_final_information#:#Dokončení testu: Informace před odeslán assessment#:#tst_finish_confirm_button#:#Ano, chci tento test ukončit assessment#:#tst_finish_confirm_cancel_button#:#Ne, jít zpět na předchozí otázku assessment#:#tst_finish_confirmation_question#:#Hodláte ukončit tento test a dosáhl(a) jste maximálního počtu povolených průchodů testem. Nebudete již moci do tohoto testu vstoupit znovu a změnit své odpovědi. Upravdu chcete tento test ukončit? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Dokončíte tento test a dosáhnete maximálního počtu povolených pokusů. Nebudete se moci k tomuto testu znovu přihlásit a změnit své odpovědi. Opravdu chcete test dokončit? assessment#:#tst_finished#:#Ukončeno assessment#:#tst_form_dynamic_question_set_config#:#Pokračuje výběr otázek assessment#:#tst_gap_analysis#:#Analýza mezer @@ -1591,7 +1562,7 @@ assessment#:#tst_invited_selected_users#:#Vybraní účastníci byli přidáni j assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_launcher_status_message_password#:#Při spuštění testu budete požádáni o heslo. assessment#:#tst_level#:#Úroveň způsobilosti assessment#:#tst_limit_nr_of_tries#:#Maximální počet průchodů testem assessment#:#tst_link_only_unassigned#:#Máte vybránu nejméně jednu otázku, která je již přiřazena k zásobníku otázek. Do zásobníku otázek lze přidávat pouze nepřiřazené otázky. @@ -1696,7 +1667,7 @@ assessment#:#tst_objective_progress_header#:#Postup cíle učení assessment#:#tst_objectives_progress_header#:#Postup cílů učení assessment#:#tst_old_style_rnd_quest_set_broken#:#Tento náhodný test je v nenapravitelném stavu, protože byl smazán jeden připojený zásobník otázek nebo více zásobníků. Proto již účastníci nemohou absolvovat test. assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Otázky týkající se již splněných cílů učení jsou volitelné.

    Chcete přejít na otázku, která se týká již splněného cíle učení.
    Můžete si vybrat:

    pokračujete, můžete pokračovat v práci na těchto otázkách. Nebyly převzaty vaše odpovědi z předchozích pokusů, protože pro tento pokus byly vybrány nové náhodné otázky. Při pokračování v práci na těchto otázkách můžete také zhoršit výsledek cíle učení.

    Pokud se rozhodnete nepokračovat v práci na těchto otázkách, můžete se vrátit zpět. V tomto případě nebudou tyto otázky zohledněny při hodnocení. -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#Čas vyhrazený pro vykonání tohoto testu vypršel. assessment#:#tst_participant#:#Účastník assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s assessment#:#tst_participant_status#:#Účastníkův status @@ -1952,7 +1923,7 @@ assessment#:#tst_text_count_system#:#Systém hodnocení assessment#:#tst_threshold#:#Prahové hodnoty assessment#:#tst_time_already_spent#:#Test již máte spuštěn %s. Maximální doba práce je %s assessment#:#tst_time_already_spent_left#:#Zbývá vám %s. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#Na zodpovězení všech otázek budete mít %s minut. assessment#:#tst_title_output#:#Výstup názvu otázky assessment#:#tst_title_output_full#:#Zobrazit název otázek a dostupné body assessment#:#tst_title_output_hide_points#:#Zobrazit pouze název otázek @@ -4660,7 +4631,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#Oblíbené common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4671,10 +4642,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#Stromové zobrazení +common#:#mm_repo_tree_view_act#:#Aktivovat stromové zobrazení +common#:#mm_repo_tree_view_deact#:#Deaktivovat stromové zobrazení +common#:#mm_repository#:#Úložiště common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nemáte oprávnění vložit následující objekty common#:#msg_no_perm_paste_object_in_folder#:#Nemáte oprávnění vkládat objekt %s do složky %s. common#:#msg_no_perm_perm#:#Nemáte oprávnění měnit nastavení přístupových práv common#:#msg_no_perm_read#:#Nemáte oprávnění přístupu k této položce. -common#:#msg_no_perm_read_item#:#Nemáte oprávnění přístupu k položce '%s'. +common#:#msg_no_perm_read_item#:#Nemáte oprávnění přístupu k položce. common#:#msg_no_perm_read_lm#:#Nemáte oprávnění číst tento výukový modul. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nemáte oprávnění k zápisu @@ -5057,7 +5028,7 @@ common#:#obj_rcat#:#ECS kategorie common#:#obj_rcrs#:#Odkazy kurzu common#:#obj_recf#:#Obnovené objekty common#:#obj_recf_desc#:#Obsahuje obnovené objekty z kontroly systému. -common#:#obj_rep#:#Repository###07 02 2020 new variable +common#:#obj_rep#:#Úložiště common#:#obj_reps#:#Úložiště common#:#obj_reps_desc#:#Obecná nastavení pro úložiště common#:#obj_rfil#:#Soubor ECS @@ -7708,7 +7679,7 @@ crs#:#crs_members_map#:#Mapa členů kurzu crs#:#crs_members_print_title#:#Členové kurzu crs#:#crs_min_one_admin#:#K tomuto kurzu musí být přiřazen alespoň jeden správce. crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable +crs#:#crs_my_courses_groups_enabled#:#Moje kurzy a skupiny crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable crs#:#crs_new_status#:#Váš nový status je: crs#:#crs_new_subscription#:#Uživatel zařazen do kurzu "%s" @@ -8090,15 +8061,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#Oblíbené dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#Moje kurzy a skupiny dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#Oblíbené dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8110,7 +8081,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#Moje kurzy a skupiny dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Možnosti odpovědi +qsts#:#cloze_text#:#Doplňovaný text +qsts#:#cloze_textgapcase_insensitive#:#Nerozlišuje velká/malá písmena +qsts#:#cloze_textgapcase_sensitive#:#Rozlišuje velká/malá písmena +qsts#:#cloze_textgaplevenshtein_of#:#Vzdálenost Levenshtein %s +qsts#:#confirm_delete_questions#:#Jste si jist/a, že chcete smazat následující otázky? +qsts#:#create_question#:#Vytvořit otázku +qsts#:#gap#:#Mezera +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Vložit rezervované místo +qsts#:#min_auto_complete#:#Automatické dokončování +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Mimo rozsah +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Seznam otázek +qsts#:#questions#:#Otázky +qsts#:#range_lower_limit#:#Spodní hranice +qsts#:#range_upper_limit#:#Horní hranice +qsts#:#reset_preview#:#Obnovit náhled +qsts#:#select_gap#:#Vybrat mezeru +qsts#:#shuffle_answers#:#Zamíchat odpovědi +qsts#:#suggested_learning_content#:#Přidat doporučené řešení rating#:#rat_not_rated_yet#:#Dosud nehodnoceno rating#:#rat_nr_ratings#:#%s Hodnocení rating#:#rat_one_rating#:#Jedno hodnocení @@ -15080,10 +15080,10 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable +rep#:#rep_fav_intro1#:#Zatím jste nevybrali žádné oblíbené položky. Chcete-li to provést, musíte provést dva kroky: +rep#:#rep_fav_intro2#:#Klikněte na '%s' a vyberte si z dostupných možností studijní objekt, např. studijní modul nebo fórum. +rep#:#rep_fav_intro3#:#Pokud najdete něco, co vás zajímá, můžete si to snadno přidat do oblíbených. U požadované položky vyberte v nabídce Akce možnost „Přidat do oblíbených“. +rep#:#rep_favourites#:#Oblíbené rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Vítejte v úložišti! @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok otázek survey#:#questionblock_inserted#:#Blok otázek vložen survey#:#questionblocks#:#Bloky otázek survey#:#questionblocks_inserted#:#Bloky otázek vloženy -survey#:#questions#:#Otázky survey#:#questions_inserted#:#Otázky vloženy survey#:#questions_removed#:#Otázky a/nebo bloky otázek odstraněny! survey#:#questiontype#:#Typ otázky @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Skrýt štítky survey#:#svy_print_show_labels#:#Zobrazit štítky survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Otázky survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Šablona pošty diff --git a/lang/ilias_da.lang b/lang/ilias_da.lang index 4a6807934292..03694a36e183 100644 --- a/lang/ilias_da.lang +++ b/lang/ilias_da.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Aktiver logging for Test & Assessment assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Opret løsningsforslag assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Lav cirkelområde assessment#:#add_gap#:#Tilføj hul tekst @@ -447,11 +446,10 @@ assessment#:#answer_is_not_correct_but_positive#:#Du har fået point for din lø assessment#:#answer_is_right#:#Din løsning er rigtig assessment#:#answer_is_wrong#:#Din løsning er forkert assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Besvar tekst assessment#:#answer_types#:#Svartype -assessment#:#answered#:#Answered###07 11 2014 new variable +assessment#:#answered#:#Besvaret assessment#:#answers_multiline#:#Flerlinjers svar assessment#:#answers_of#:#Answers of:###16 09 2013 new variable assessment#:#answers_select#:#Select###30 08 2015 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###16 09 2013 new variable -assessment#:#ass_create_question#:#Create Question###16 09 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Længde på tekstfelt assessment#:#cloze_fixed_textlength_description#:#Hvis du indtaster en værdi der er større end 0 bliver alle numeriske og tekst huller den størrelse. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Luk tekst -assessment#:#cloze_textgap_case_insensitive#:#Ingen forskel på store og små bogstaver -assessment#:#cloze_textgap_case_sensitive#:#Forskel på store og små bogstaver -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein afstand på %s assessment#:#code#:#Kode assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Konkatnering @@ -616,7 +609,7 @@ assessment#:#detailed_evaluation_show#:#Vis detaljeret evaluering assessment#:#detailed_output_printview#:#Detailed output with question printviews assessment#:#detailed_output_solutions#:#Detailed output with question solutions assessment#:#direct_feedback#:#Godkend din løsning -assessment#:#discard_answer#:#Discard Answer###30 08 2015 new variable +assessment#:#discard_answer#:#Kassér svar assessment#:#discard_answer_confirmation#:#Your answer will be finally and completly discarded. The question keeps as unanswered until you submit another answer.

    Would you really like to discard your answer?###30 08 2015 new variable assessment#:#dont_use_questionpool#:#Don't insert the questions in a questionpool (only available in this test)###10 09 2010 new variable assessment#:#download_all_files#:#Download All Files###28 10 2024 new variable @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Hul assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Ordbogsforklaring assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Indsæt efter assessment#:#insert_before#:#Indsæt før -assessment#:#insert_gap#:#Insert Gap###11 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Interne links assessment#:#intprecision#:#Divisible By###16 09 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Vedligeholdelse assessment#:#manscoring#:#Manuelle karakterer assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Du har nået maximum antallet af fors assessment#:#maximum_points#:#Maksimalt opnåelige point assessment#:#maxsize#:#Maksimal størrelse på uploadede filer assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Du skal angive et minimum procentdel af 0 procent! Karakterskemaet er ikke gemt! assessment#:#misc#:#Misc Options###16 09 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Cirkel tilføjet -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon tilføjet assessment#:#msg_questions_moved#:#Spørgsmål flyttet @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Rækkefølgen ovenfor skal være den korrekte besvarelse. assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 10 2006 new variable assessment#:#output_mode#:#Output mode assessment#:#parseQuestion#:#Parse Question###16 09 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Er du sikker på du vil slette følgende spørgsmål? Hvis du sletter låste spørgsmål vil resultater af alle test der bruger et låst spørgsmål også blive slettet. assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard assessment#:#qpl_delete_rbac_error#:#Du har ikke rettigheder til at slette dette spørgsmål! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Spørgsmålet du er ved at ændre findes i %s test. Hvis du ændrer spørgsmålet vil det ikke ændres i disse tests, fordi der laves en kopi af spørgsmålet når det tilføjes. assessment#:#qpl_questions_deleted#:#Spørgsmål slettet. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###16 09 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Antal forsøg @@ -1162,22 +1138,19 @@ assessment#:#question_marking_description#:#Hvis valgt, every participant gets t assessment#:#question_not_answered#:#The question was not answered###25 02 2007 new variable assessment#:#question_saved_for_upload#:#Spørgsmålet blev gemt automatisk for at gemme harddisk plads til at gemme uploaded filer. Hvis du stopper dette nu skal du slette spørgsmålet i spørgsmålsgruppen hvis du ikke ønsker at beholde det! assessment#:#question_summary#:#Liste over spørgsmål -assessment#:#question_summary_btn#:#Processing Status###30 08 2015 new variable +assessment#:#question_summary_btn#:#Oversigt over testforsøg assessment#:#question_title#:#Titel assessment#:#question_type#:#Spørgsmåls type assessment#:#questionpool_not_entered#:#Indtast venligst et navn for spørgsmålsgruppe! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#spørgsmål fra### assessment#:#questions_per_page_view#:#Sidevisning assessment#:#random_accept_sample#:#Accepter prøve assessment#:#random_another_sample#:#Få en anden prøve assessment#:#random_selection#:#Tilfældigt valg assessment#:#range#:#Range -assessment#:#range_lower_limit#:#Lower limit assessment#:#range_max#:#Range (Maximum)###16 09 2013 new variable assessment#:#range_min#:#Range (Minimum)###16 09 2013 new variable -assessment#:#range_upper_limit#:#Upper limit assessment#:#rated_sign#:#Sign###16 09 2013 new variable assessment#:#rated_unit#:#Unit###16 09 2013 new variable assessment#:#rated_value#:#Value###16 09 2013 new variable @@ -1189,7 +1162,7 @@ assessment#:#rating_value#:#Rate Value###16 09 2013 new variable assessment#:#rectangle#:#Rektangel assessment#:#rectangle_click_br_corner#:#Klik venligst på det nederste højre hjørne af det ønskede område. assessment#:#rectangle_click_tl_corner#:#Klik venligst på det øverste venstre hjørne af det ønskede område. -assessment#:#redirectAfterSave#:#The maximum working time has been reached and your last question has been saved automatically. In a few seconds you will be redirected...###15 09 2008 new variable +assessment#:#redirectAfterSave#:#Den maksimale arbejdstid er nået. Om få sekunder vil du blive omdirigeret... assessment#:#redirect_after_finishing_rule#:#Redirect###27 01 2015 new variable assessment#:#redirect_after_finishing_tst#:#Redirect after finishing the test###16 09 2013 new variable assessment#:#redirect_after_finishing_tst_desc#:#After completing the test, each participant is automatically redirected to a specific webpage of your choosing. This will only happen if participants do not have direct access to their test results. When entering the address of an external webpage, use the complete URL (including ‘https://’). When redirecting to an Object in ILIAS, use the permalink that can be found in the footer of the Object in question.###27 01 2015 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Søg roller assessment#:#search_term#:#Søge kriterier assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Vælg hul assessment#:#select_max_one_item#:#Vælg venligst kun en ting assessment#:#select_one_user#:#Vælg mindst en bruger assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Vis overblik for de markerede besvarelser assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Vis de markerede besvarelser -assessment#:#shuffle_answers#:#Bland svar assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Tekst @@ -1393,15 +1364,15 @@ assessment#:#tst_answer_fixation_on_instant_feedback#:#Lock Answers with the Pre assessment#:#tst_answer_fixation_on_instant_feedback_desc#:#After the feedback for a question is shown participant answers are locked, participants cannot change these answers any longer.###10 11 2018 new variable assessment#:#tst_answer_fixation_on_instantfb_or_followupqst#:#Lock Answers with the Presentation of Feedback or Follow-Up Questions###10 11 2018 new variable assessment#:#tst_answer_fixation_on_instantfb_or_followupqst_desc#:#Participant Answers for a question will be locked either with the presentation of the questions's feedback or when the follow-up question is shown.###10 11 2018 new variable -assessment#:#tst_answer_status_answered#:#Answered###fau: testNav -assessment#:#tst_answer_status_editing#:# (editing ... )###fau: testNav -assessment#:#tst_answer_status_not_answered#:#Not answered###fau: testNav +assessment#:#tst_answer_status_answered#:#Besvaret###fau: testNav +assessment#:#tst_answer_status_editing#:# (i redigering...)###fau: testNav +assessment#:#tst_answer_status_not_answered#:#Ikke besvaret###fau: testNav assessment#:#tst_answered_questions#:#Besvarede spørgsmål assessment#:#tst_answered_questions_of_total#:#%s of %s###07 02 2020 new variable assessment#:#tst_answered_questions_test#:#Spørgsmål besvaret i denne test assessment#:#tst_attached_xls_file#:#You find the test result for this participant in the attached Excel file.###27 01 2015 new variable assessment#:#tst_attempt#:#Attempt###30 08 2015 new variable -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#Totalt antal gange, du må tage denne test: %s. assessment#:#tst_attempt_started#:#Test startet assessment#:#tst_back_to_pass_details#:#Back to Pass Details###26 09 2014 new variable assessment#:#tst_back_to_question_list#:#Back to Question List###26 09 2014 new variable @@ -1452,7 +1423,7 @@ assessment#:#tst_derive_new_pools#:#Derive New Question Pools###25 10 2016 new v assessment#:#tst_dont_show_msg_again_in_current_session#:#Don't show this message again in my current session.###10 11 2018 new variable assessment#:#tst_edit_competence_assign#:#Edit Assignment Properties###30 08 2015 new variable assessment#:#tst_edit_scoring#:#Edit Scoring###28 08 2012 new variable -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#Vis 'Liste over spørgsmål' assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#Sluttidspunkt assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1477,14 +1448,14 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#Indtast venligst adgangskoden for at starte testen. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable -assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#Test adgangskode +assessment#:#tst_exam_password_invalid_message#:#Den angivne adgangskode er ikke gyldig! +assessment#:#tst_exam_password_label#:#Adgangskode assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable +assessment#:#tst_exam_use_previous_answers#:#Brug tidligere svar assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#The working time of the participant has been increased by %s minutes.###16 09 2013 new variable assessment#:#tst_extratime_info#:#If you want to add the working time multiple times for the same participant, please insert the total amount of time you want to add.###14 05 2014 new variable @@ -1504,15 +1475,15 @@ assessment#:#tst_final_information#:#Finishing the Test: Information Before Subm assessment#:#tst_finish_confirm_button#:#Ja, jeg vil afslutte testen assessment#:#tst_finish_confirm_cancel_button#:#Nej, gå tilbage til sidste svar assessment#:#tst_finish_confirmation_question#:#You are going to finish this test and reach the maximum number of allowed test passes. You won't be able to enter this test again to change your answers. Do you really want to finish the test?###01 Mar 2006 new variable -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Du er ved at afslutte denne test og nå det maksimale antal tilladte testforsøg. Du vil ikke kunne deltage i denne test igen for at ændre dine svar. Vil du virkelig afslutte testen? assessment#:#tst_finished#:#Afsluttet assessment#:#tst_form_dynamic_question_set_config#:#Continues Question Selection###16 09 2013 new variable assessment#:#tst_gap_analysis#:#Gap Analysis###26 09 2014 new variable assessment#:#tst_general_properties#:#Generelle egenskaber assessment#:#tst_header_participant#:#Result:###16 09 2013 new variable -assessment#:#tst_header_participant_no_answer#:#Question - not answered###26 08 2024 new variable +assessment#:#tst_header_participant_no_answer#:#Spørgsmål - ikke besvaret assessment#:#tst_header_solution#:#Correct solution:###16 09 2013 new variable -assessment#:#tst_hide_info_tab#:#Hide Info Tab###26 08 2024 new variable +assessment#:#tst_hide_info_tab#:#Skjul fanen Info assessment#:#tst_hide_info_tab_desc#:#Hides the tab ‘Info’ of the test.###26 08 2024 new variable assessment#:#tst_hide_pagecontents#:#Hide page content###26 08 2024 new variable assessment#:#tst_hide_pagecontents_desc#:#ILIAS content placed before and after the actual question text via the "Edit Page" button will not be displayed in the result views and print output.###26 08 2024 new variable @@ -1588,10 +1559,10 @@ assessment#:#tst_introduction_desc#:#Shows an introductory message on the tab 'I assessment#:#tst_introduction_text#:#Introductory Message###27 01 2015 new variable assessment#:#tst_invited_nobody#:#No users, groups or roles have been added as fixed test participants###12 11 2006 new variable assessment#:#tst_invited_selected_users#:#The selected users have been added as fixed test participants###12 11 2006 new variable -assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable +assessment#:#tst_launcher_button_label_passes_limit_reached#:#Du har nået grænsen for mulige testpasseringer assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_launcher_status_message_password#:#Du vil blive bedt om adgangskoden, når du starter testen. assessment#:#tst_level#:#Competence Level###26 09 2014 new variable assessment#:#tst_limit_nr_of_tries#:#Maximum Number of Test Passes###07 11 2014 new variable assessment#:#tst_link_only_unassigned#:#You have selected at least one question that is already linked to a question pool. Only unassigned questions can be added to a question pool.###14 09 2011 new variable @@ -1696,7 +1667,7 @@ assessment#:#tst_objective_progress_header#:#Learning Objective Progress###25 10 assessment#:#tst_objectives_progress_header#:#Learning Objectives Progress###25 10 2016 new variable assessment#:#tst_old_style_rnd_quest_set_broken#:#This random test is in a irreparable state, because one or more connected question pools have been deleted. Therefor participants cannot take the test any longer.###30 08 2015 new variable assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Question related to allready passed learning objectives are optional.

    You want to navigate to a question, that relates to an allready passed learning objective.
    You can choose:

    I you proceed, you can work on these questions. Your answers from previous attempts were not adopted, since new random questions were selected for this attempt. With working on this questions you can also degrade your learning objective result.

    If you decide to not work on these questions, you can go back. In this case these questions won't be considered in the evaluation.###30 08 2015 new variable -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#Tiden til at tage denne test er udløbet. assessment#:#tst_participant#:#Deltager assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s###26 09 2014 new variable assessment#:#tst_participant_status#:#Participant Status###28 08 2012 new variable @@ -1726,7 +1697,7 @@ assessment#:#tst_pass_waiting_info#:#With this option additional passes can not assessment#:#tst_pass_waiting_time#:#Waiting Time###25 10 2016 new variable assessment#:#tst_passed#:#Passed###07 02 2020 new variable assessment#:#tst_passes#:#Testforsøg -assessment#:#tst_password#:#Test password +assessment#:#tst_password#:#Test adgangskode assessment#:#tst_password_details#:#Hvis du indtaster et test password skal alle brugere der vil tilgå testen indtaste dette ved start af testen. assessment#:#tst_password_enter#:#Enter Password###27 01 2015 new variable assessment#:#tst_password_entered_wrong_password#:#You cannot start the test because you entered the wrong test password! @@ -1842,7 +1813,7 @@ assessment#:#tst_results_overview#:#Overblik over testresultater assessment#:#tst_results_print_best_solution#:#Best Solution in Test Results###18 01 2012 new variable assessment#:#tst_results_print_best_solution_info#:#If activated and accessible by the participant, the best solution appears in the test result summary.###18 01 2012 new variable assessment#:#tst_resume_test#:#Genoptag testen -assessment#:#tst_revert_changes#:#Undo Editing###fau: testNav +assessment#:#tst_revert_changes#:#Fortryd redigering###fau: testNav assessment#:#tst_rnd_quest_cfg_tab_general#:#General Config###16 09 2013 new variable assessment#:#tst_rnd_quest_cfg_tab_pool#:#Source Question Pools###16 09 2013 new variable assessment#:#tst_rnd_quest_set_cfg_general_form#:#Random Question Selection Config###16 09 2013 new variable @@ -1952,7 +1923,7 @@ assessment#:#tst_text_count_system#:#Scoringssystem assessment#:#tst_threshold#:#Thresholds###26 09 2014 new variable assessment#:#tst_time_already_spent#:#Tid allerede brugt på arbejde assessment#:#tst_time_already_spent_left#:#Du har %s tilbage. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#Du har %s minutter til at besvare alle spørgsmål. assessment#:#tst_title_output#:#Test Title Output###29 11 2006 new variable assessment#:#tst_title_output_full#:#Vis testens titel og mulige point assessment#:#tst_title_output_hide_points#:#Vis kun testens titel @@ -3413,7 +3384,7 @@ cmxv#:#cmxv_create_info#:#Select a completed xAPI/cmi5 object to generate a cert cntr#:#cntr_add_new_item#:#Tilføj indhold cntr#:#cntr_adopt_content#:#Kopier indhold fra andet kursus cntr#:#cntr_container_only_on_their_own#:#Categories, courses, groups, folders or study programmes can only be copied as single objects. Please select one item only. -cntr#:#cntr_copy_crs_grp#:#My Courses and Groups###30 08 2015 new variable +cntr#:#cntr_copy_crs_grp#:#Mine kurser og grupper cntr#:#cntr_copy_repo_tree#:#Repository Tree###30 08 2015 new variable cntr#:#cntr_hide_title_and_icon#:#Skjul titel og ikon cntr#:#cntr_manage#:#Ret @@ -4660,7 +4631,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#Favoritter common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4671,10 +4642,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#Trævisning +common#:#mm_repo_tree_view_act#:#Aktiver trævisning +common#:#mm_repo_tree_view_deact#:#Deaktiver trævisning +common#:#mm_repository#:#Arkiv common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Du har ikke rettigheder til at indsætte følgende common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Du har ikke rettigheder til at ændre rettighedsindstillinger common#:#msg_no_perm_read#:#Du har ikke rettigheder til adgang af objekterne -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'. +common#:#msg_no_perm_read_item#:#You have no permission to access the object. common#:#msg_no_perm_read_lm#:#du har ingen rettigheder læse dette læringsmodul. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Du har ikke skriverettigheder @@ -5057,8 +5028,8 @@ common#:#obj_rcat#:#ECS Category ###28 08 2012 new variable common#:#obj_rcrs#:#Kursuslink common#:#obj_recf#:#Gendannede objekter common#:#obj_recf_desc#:#Indeholder gendannede objekter fra systemcheck. -common#:#obj_rep#:#Repository###07 02 2020 new variable -common#:#obj_reps#:#Repository###16 09 2013 new variable +common#:#obj_rep#:#Arkiv +common#:#obj_reps#:#Arkiv common#:#obj_reps_desc#:#General settings for the Repository###16 09 2013 new variable common#:#obj_rfil#:#ECS File###28 08 2012 new variable common#:#obj_rglo#:#ECS Glossary###28 08 2012 new variable @@ -5247,12 +5218,12 @@ common#:#parameter#:#Parameter common#:#parse#:#Parse###21 Apr 2005 new variable common#:#participate#:#Subscribe###07 02 2020 new variable common#:#passed#:#Bestået -common#:#passwd#:#Password +common#:#passwd#:#Adgangskode common#:#passwd_generation#:#Password generering common#:#passwd_invalid#:#Det nye password er ugyldigt! Kun gyldige karakterer er gyldige (minimum 6 karaktere): A-Z a-z 0-9 _.-+*@!$%~ common#:#passwd_not_match#:#Dine indtastninger for et nyt password matcher ikke. Venligst indtast påny. common#:#passwd_wrong#:#Det password du har indtastet er forkert! -common#:#password#:#Password +common#:#password#:#Adgangskode common#:#password_allow_chars#:#Tilladte karakterer: %s common#:#password_assistance_info#:#Hvis passwordhjælp er aktiveret vil et link med teksten Glemt password blive vist på loginbilledet til ILIAS. Brugere kan bruge dette link til at angive et nyt password til deres brugerkonto uden hjælp fra systemadministrator. common#:#password_change_on_first_login_demand#:#Du skal vælge et nyt password før du kan begynde at anvende ILIAS. @@ -5792,7 +5763,7 @@ common#:#trash#:#Slettede ting/skrald common#:#tree#:#Træ common#:#tree_frame#:#Oversigstræ common#:#treeview#:#Træoversigt -common#:#tst#:#Test +common#:#tst#:#Prøve common#:#tst_add#:#Lav test common#:#tst_edit_questions#:#Ret spørgsmål common#:#tst_history_read#:#View History###26 08 2024 new variable @@ -7708,7 +7679,7 @@ crs#:#crs_members_map#:#Kort over kursister crs#:#crs_members_print_title#:#Kursusdeltagere crs#:#crs_min_one_admin#:#There has to be at least one administrator assigned to this course.###12 08 2009 new variable crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable +crs#:#crs_my_courses_groups_enabled#:#Mine kurser og grupper crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable crs#:#crs_new_status#:#Din nye status er: crs#:#crs_new_subscription#:#Ny tilmelding "%s" @@ -8090,15 +8061,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#Favoritter dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#Mine kurser og grupper dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#Favoritter dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8110,7 +8081,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#Mine kurser og grupper dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Luk tekst +qsts#:#cloze_textgapcase_insensitive#:#Ingen forskel på store og små bogstaver +qsts#:#cloze_textgapcase_sensitive#:#Forskel på store og små bogstaver +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein afstand på %s +qsts#:#confirm_delete_questions#:#Er du sikker på du vil slette følgende spørgsmål? Hvis du sletter låste spørgsmål vil resultater af alle test der bruger et låst spørgsmål også blive slettet. +qsts#:#create_question#:#Create Question###16 09 2013 new variable +qsts#:#gap#:#Hul +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###11 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Spørgsmålsliste +qsts#:#questions#:#Spørgsmål +qsts#:#range_lower_limit#:#Lower limit +qsts#:#range_upper_limit#:#Upper limit +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Vælg hul +qsts#:#shuffle_answers#:#Bland svar +qsts#:#suggested_learning_content#:#Opret løsningsforslag rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -15080,11 +15080,11 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable -rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable +rep#:#rep_fav_intro1#:#Du har endnu ikke valgt nogen favoritter. For at gøre dette skal du gennemføre to trin: +rep#:#rep_fav_intro2#:#Klik på '%s' og vælg et læringsobjekt fra de tilgængelige muligheder, f.eks. et læringsmodul eller et forum. +rep#:#rep_fav_intro3#:#Hvis du finder noget, der interesserer dig, kan du nemt tilføje det til dine favoritter. For det ønskede element skal du vælge "Føj til favoritter" i menuen Handlinger. +rep#:#rep_favourites#:#Favoritter +rep#:#rep_favourites_info#:#Brugere kan markere enkelte repository-elementer som favoritter. En "Favoritter"-liste kan aktiveres for dashboardet og hovedmenuen. rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Velkommen til oversigten! rep#:#rep_intro1#:#I dette område kan du oprette læring og arbejdsresurser til alle brugere. Alle resurser er organiseret i kategorier. Kategorier kan afspejle strukturen af din organisation (f.eks. afdelinger), et hieraki af discipliner eller klasser i en skole. @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Spørgsmåls blok survey#:#questionblock_inserted#:#Blok indsat survey#:#questionblocks#:#Spørgsmåls blok survey#:#questionblocks_inserted#:#Spørgsmålsblokke indsat -survey#:#questions#:#Spørgsmål survey#:#questions_inserted#:#Spørgsmål indsat! survey#:#questions_removed#:#Spørgsmål og/eller spørgsmålsblok fjernet! survey#:#questiontype#:#Spørgsmåls type @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Spørgsmål survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_de.lang b/lang/ilias_de.lang index 476a103a5fe0..7699c2077b8b 100644 --- a/lang/ilias_de.lang +++ b/lang/ilias_de.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#TinyMCE-Editor für WYSIWYG-Bearbeitung aktivieren assessment#:#activate_logging#:#Protokollieren des Test und Assessments aktivieren assessment#:#activate_manual_scoring#:#Bewertung aktivieren assessment#:#activate_manual_scoring_desc#:#Aktiviert die Bewertung für alle Fragentypen -assessment#:#addSuggestedSolution#:#Inhalte zur Wiederholung assessment#:#add_answers#:#Antworten hinzufügen assessment#:#add_circle#:#Kreis hinzufügen assessment#:#add_gap#:#Lückentext hinzufügen @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Sie haben Punkte für Ihre Lö assessment#:#answer_is_right#:#Ihre Lösung ist korrekt. assessment#:#answer_is_wrong#:#Ihre Lösung ist falsch. assessment#:#answer_of#:#Antwort von -assessment#:#answer_options#:#Antwort-Optionen: assessment#:#answer_question#:#Frage beantworten assessment#:#answer_text#:#Antwort-Text assessment#:#answer_types#:#Antwort-Editor @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Bestehen durch Abgabe assessment#:#ass_completion_by_submission_info#:#Falls aktiviert, führt die Abgabe einer Lösungsdatei zur Vergabe der Maximalpunktzahl für diese Frage. Die Bewertung kann jederzeit manuell angepasst werden. Das Ändern dieser Einstellung hat keine nachträglichen Auswirkungen auf bereits eingereichte Lösungen. assessment#:#ass_create_export_file_with_results#:#inkl. Teilnehmerergebnisse assessment#:#ass_create_export_test_archive#:#als Archivdatei -assessment#:#ass_create_question#:#Frage erstellen assessment#:#ass_imap_hint#:#Hinweis (angezeigt als Tooltipp) assessment#:#ass_imap_map_file_not_readable#:#Die hochgeladene Imagemap kann nicht gelesen werden. assessment#:#ass_imap_no_map_found#:#In der hochgeladenen Imagemap konnte keine unterstützte Form gefunden werden. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Vorangestellte oder nachfolgende Leerzeich assessment#:#cloze_fixed_textlength#:#Länge des Textfeldes assessment#:#cloze_fixed_textlength_description#:#Wenn Sie hier einen Wert eintragen, werden Textlücken, welche keinen eigenen Wert für eine maximale Länge definieren, sowie numerische Lücken mit dieser Länge erzeugt, so dass es nicht möglich ist eine größere Anzahl an Zeichen einzugeben. Für numerische Lücken ist darüber hinaus zu beachten, dass das Dezimaltrennzeichen dabei mit gezählt wird. assessment#:#cloze_gap_size_info#:#Ist ein Wert größer 0 eingetragen, wird diese Lücke mit der hier angegebenen Länge erzeugt. Ist kein Wert angegeben, wird diese Lücke mit der global angegebenen Textfeldlänge erzeugt. -assessment#:#cloze_text#:#Lückentextfrage -assessment#:#cloze_textgap_case_insensitive#:#Zwischen Groß- und Kleinschreibung wird nicht unterschieden -assessment#:#cloze_textgap_case_sensitive#:#Groß- und Kleinschreibung beachten -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein-Abstand von %s assessment#:#code#:#Code assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Verknüpfung @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Erlaubt ist die Verwendung von bereits definierte assessment#:#fq_no_restriction_info#:#Sowohl Dezimalzahlen als auch Brüche werden als Eingabe akzeptiert. assessment#:#fq_precision_info#:#Geben Sie hier die Anzahl der gewünschten Nachkommastellen an. assessment#:#fq_question_desc#:#Sie definieren Variablen durch die Angabe von $v1, $v2 ... $vn, Ergebnisfelder mit $r1, $r2 .... $rn an den gewünschten Positionen im Text. Klicken Sie dann auf die Schaltfläche „Frage analysieren“, um Bearbeitungsformulare für alle Variablen und Ergebnisse zu erzeugen. -assessment#:#gap#:#Lücke assessment#:#gap_combination#:#Lückentext-Kombination -assessment#:#gaps#:#Lücken assessment#:#glossary_term#:#Glossarbegriff assessment#:#goto_first_question#:#Zur ersten Frage assessment#:#grading_mark_msg#:#Sie haben die Note "[mark]" erzielt. @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Die Frage beinhaltet bereits Bilder. Der assessment#:#info_text_upload#:#Wählen Sie eine Textdatei (UTF-8) mit Antworten zum Hochladen aus. assessment#:#insert_after#:#Einfügen hinter assessment#:#insert_before#:#Einfügen vor -assessment#:#insert_gap#:#Lücke einfügen assessment#:#interaction_type#:#Interaktion assessment#:#internal_links#:#Interne Verweise assessment#:#intprecision#:#Teilbar durch @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Teilnehmer hat falsches Testpas assessment#:#longmenu#:#Longmenu assessment#:#longmenu_answeroptions_differ#:#Diese Frage funktioniert nicht richtig, denn sie hat nicht die gleiche Anzahl Lücken im Text wie in den Antwortoptionen. assessment#:#longmenu_text#:#„Long Menu“-Text -assessment#:#mainbar_button_label_questionlist#:#Fragenliste assessment#:#maintenance#:#Wartung assessment#:#manscoring#:#Bewertung assessment#:#manscoring_done#:#Bereits bewertete Teilnehmer @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Sie haben die maximale Anzahl von Tes assessment#:#maximum_points#:#Maximal erreichbare Punktezahl assessment#:#maxsize#:#Maximale Dateigröße assessment#:#maxsize_info#:#Geben Sie die maximale Größe in Bytes an, die eine hochgeladene Datei haben darf. Wenn Sie das Feld leer lassen, wird die Einstellung des zugrunde liegenden Systems verwendet. -assessment#:#min_auto_complete#:#Autovervollständigung assessment#:#min_ip_label#:#Kleinste IP mit Zugriff assessment#:#min_percentage_ne_0#:#Das Notenschema muss mindestens eine Stufe mit einem minimalen Prozentsatz von 0 Prozent enthalten. assessment#:#misc#:#Verschiedene Optionen @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#Nacheinander assessment#:#mode_question#:#Nach Frage assessment#:#mode_user#:#Nach Teilnehmer assessment#:#msg_circle_added#:#Kreis hinzugefügt -assessment#:#msg_no_questions_selected#:#Keine Fragen ausgewählt. assessment#:#msg_number_of_terms_too_low#:#Die Anzahl der Terme muss größer oder gleich der Anzahl der Definitionen sein. assessment#:#msg_poly_added#:#Polygon hinzugefügt assessment#:#msg_questions_moved#:#Fragen verschoben @@ -984,7 +971,6 @@ assessment#:#order#:#Sortierung assessment#:#ordering_answer_sequence_info#:#Die hier definierte Reihenfolge der Antworten wird als korrekte Lösungsreihenfolge verwendet. assessment#:#ordertext#:#Anzuordnender Text assessment#:#ordertext_info#:#Bitte geben Sie den Text in der Reihenfolge ein, in der er horizontal angeordnet werden soll. Die einzelnen Bestandteile werden durch Leerzeichen getrennt. Wenn Sie eine abweichende Trennung benötigen, verwenden Sie bitte den Trenner %s anstelle der Leerzeichen. -assessment#:#out_of_range#:#Ausserhalb des Bereichs assessment#:#output#:#Ausgabe assessment#:#output_mode#:#Ausgabemodus assessment#:#parseQuestion#:#Frage analysieren @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Hinzufügen assessment#:#qpl_bulk_save_overwrite#:#Überschreiben assessment#:#qpl_bulkedit_success#:#Änderungen gespeichert. assessment#:#qpl_cancel_skill_assigns_update#:#Abbrechen -assessment#:#qpl_confirm_delete_questions#:#Sind Sie sicher, dass Sie die folgenden Fragen entfernen wollen? assessment#:#qpl_copy_insert_clipboard#:#Die ausgewählten Fragen wurden in die Zwischenablage kopiert assessment#:#qpl_copy_select_none#:#Bitte wählen Sie mindestens eine Frage aus, um diese in die Zwischenablage zu kopieren! assessment#:#qpl_delete_rbac_error#:#Sie haben keine Berechtigung, diese Frage zu entfernen! @@ -1106,12 +1091,11 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetenz assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Summe aller Kompetenzpunkte je Kompetenz assessment#:#qpl_question_is_in_use#:#Die Frage, die Sie jetzt bearbeiten möchten, existiert bereits in %s Test(s). Wenn Sie diese Frage jetzt verändern, so hat das KEINE Auswirkungen auf bereits in Tests eingebundene Fragen, da das System automatisch eine Kopie der Frage anlegt, wenn diese in einen Test eingebunden wird! assessment#:#qpl_questions_deleted#:#Fragen gelöscht -assessment#:#qpl_reset_preview#:#Vorschau zurücksetzen assessment#:#qpl_save_skill_assigns_update#:#Kompetenzzuweisung speichern assessment#:#qpl_settings_availability#:#Verfügbarkeit -assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Vorhandene Taxonomien können zum Filtern der Fragen genutzt werden. -assessment#:#qpl_settings_general_form_property_nav_taxonomy#:#Taxonomie als Navigationsbaum -assessment#:#qpl_settings_general_form_property_nav_taxonomy_description#:#Ist eine Taxonomie ausgewählt, wird diese nicht als Filter sondern als Navigationsbaum angezeigt. +assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Taxonomien können als Filter im Reiter „Fragen“ verwendet werden. +assessment#:#qpl_settings_general_form_property_nav_taxonomy#:#Taxonomie als Baumansicht +assessment#:#qpl_settings_general_form_property_nav_taxonomy_description#:#Die ausgewählte Taxonomie wird im Reiter „Fragen“ in einer Baumansicht angezeigt. Sie erscheint nicht mehr im Filter. assessment#:#qpl_settings_general_form_property_opt_notax_selected#:#Keine Taxonomie als Navigationsbaum verwenden assessment#:#qpl_settings_general_form_property_show_taxonomies#:#Taxonomien assessment#:#qpl_settings_subtab_general#:#Allgemeine Einstellungen @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Noch übrige Zeichen: assessment#:#qst_essay_wordcounter_enabled#:#Wörter zählen assessment#:#qst_essay_wordcounter_enabled_info#:#Die eingegebenen Wörter werden gezählt. Die Anzahl der Wörter wird den Teilnehmern unterhalb des Texteingabefeldes angezeigt. assessment#:#qst_essay_written_words#:#Anzahl der eingegebenen Wörter: -assessment#:#qst_lifecycle#:#Lebenszyklus -assessment#:#qst_lifecycle_draft#:#Entwurf -assessment#:#qst_lifecycle_filter_all#:#Alle Lebenszyklen -assessment#:#qst_lifecycle_final#:#Endgültig -assessment#:#qst_lifecycle_outdated#:#Veraltet -assessment#:#qst_lifecycle_rejected#:#Abgelehnt -assessment#:#qst_lifecycle_review#:#Überarbeitung notwendig -assessment#:#qst_lifecycle_sharable#:#Verteilbar assessment#:#qst_nested_nested_answers_off#:#Ohne Einrückung assessment#:#qst_nested_nested_answers_on#:#Mit Einrückung assessment#:#qst_nr_of_tries#:#Anzahl der Versuche @@ -1168,17 +1144,14 @@ assessment#:#question_type#:#Fragetyp assessment#:#questionlist_cannot_be_altered#:#Die Fragenliste kann nicht verändert werden da der Test Teilnehmerdatensätze enthält. assessment#:#questionpool_not_entered#:#Bitte geben Sie einen Namen für den Fragenpool an! assessment#:#questionpool_not_selected#:#Bitte wählen Sie einen Fragenpool aus! -assessment#:#questions#:#Fragen assessment#:#questions_from#:#Fragen aus assessment#:#questions_per_page_view#:#Seitenansicht assessment#:#random_accept_sample#:#Zusammenstellung akzeptieren assessment#:#random_another_sample#:#Neue Zusammenstellung assessment#:#random_selection#:#Zufällige Auswahl assessment#:#range#:#Bereich -assessment#:#range_lower_limit#:#Untere Schranke assessment#:#range_max#:#Bereich (Maximum) assessment#:#range_min#:#Bereich (Minimum) -assessment#:#range_upper_limit#:#Obere Schranke assessment#:#rated_sign#:#Vorzeichen assessment#:#rated_unit#:#Einheit assessment#:#rated_value#:#Wert @@ -1254,7 +1227,6 @@ assessment#:#search_roles#:#nach Rollen assessment#:#search_term#:#Suchbegriff assessment#:#select_at_least_one_feedback_type_and_trigger#:#Bitte mindestens eine Art der Rückmeldung und einen Auslöser auswählen. assessment#:#select_at_least_one_lock_answer_type#:#Bitte mindestens eine Art Antworten festzuschreiben auswählen. -assessment#:#select_gap#:#Auswahl-Lücke assessment#:#select_max_one_item#:#Bitte wählen Sie nur ein Objekt aus! assessment#:#select_one_user#:#Bitte wählen Sie mindestens einen Benutzer aus! assessment#:#select_question#:#Frage auswählen @@ -1281,7 +1253,6 @@ assessment#:#show_old_introduction#:#Alten Einleitungstext anzeigen assessment#:#show_pass_overview#:#Ergebnisübersicht (bewerteter Testdurchlauf) assessment#:#show_results#:#Testergebnisse anzeigen assessment#:#show_user_answers#:#Antworten (bewerteter Testdurchlauf) -assessment#:#shuffle_answers#:#Antworten mischen assessment#:#skip_question#:#Nicht antworten und weiter assessment#:#solution#:#Lösungen assessment#:#solutionText#:#Text @@ -2652,6 +2623,7 @@ book#:#book_pool_added#:#Ein Buchungspool wurde angelegt. book#:#book_pool_selection#:#Auswahl Buchungspool book#:#book_post_booking_file#:#Datei book#:#book_post_booking_information#:#Informationen zur Buchung +book#:#book_post_booking_information_for#:#Informationen zur Buchung von "%s" book#:#book_post_booking_text#:#Text book#:#book_post_booking_text_info#:#Die Platzhalter können genutzt werden, um Buchungsdetails zum Infotext hinzuzufügen.
    Der Platzhalter [OBJECT] wird durch das jeweilige Angebot ersetzt.
    Der Platzhalter [PERIOD] wird durch den gewählten Buchungszeitraum ersetzt. book#:#book_pref_book_cron#:#Buchung mit Präferenzen @@ -3479,7 +3451,7 @@ cntr#:#cntr_switch_to_new_editor_message#:#Dies ist der Standard-Seiteneditor. W cntr#:#cntr_switched_editor#:#Auf neue Darstellung umgestellt cntr#:#cntr_tax_none_available#:#Es gibt keine verfügbaren Taxonomien. cntr#:#cntr_tax_settings_info#:#Taxonomien in Kategorien klassifizieren und filtern die in der Kategorie enthaltenen Objekte. Nach dem Hinzufügen von Taxonomien können über die Reiter „Metadaten“ und die Unterreiter „Taxonomiezuordnung“ der jeweiligen Objekte Klassifizierungen vorgenommen werden. Taxonomien können zusätzlich im Seitenblock des Reiters „Inhalt“ der Kategorie angezeigt werden, um ein direktes Filtern der zugeordneten Objekte zu ermöglichen. -cntr#:#cntr_taxonomy_definitions#:#Taxonomie-Definition +cntr#:#cntr_taxonomy_definitions#:#Taxonomien cntr#:#cntr_taxonomy_show_sideblock#:#Taxonomie im Seitenblock darstellen cntr#:#cntr_taxonomy_sideblock_settings#:#Präsentationseinstellungen cntr#:#cntr_text_media_editor#:#Seite bearbeiten @@ -4391,7 +4363,7 @@ common#:#il_grp_admin#:#Gruppenadministration common#:#il_grp_member#:#Gruppenmitglied common#:#il_grp_status_closed#:#Geschlossene Gruppe common#:#il_grp_status_open#:#Offene Gruppe -common#:#il_iass_member#:#Teilnehmer +common#:#il_iass_member#:#Bewertete Person common#:#il_lso_admin#:#Lernsequenzadministration common#:#il_lso_member#:#Lernsequenzmitglied common#:#il_lti_instructor#:#LTI Instructor @@ -4821,7 +4793,7 @@ common#:#msg_no_perm_paste#:#Ihnen fehlt die Berechtigung, um die folgenden Obje common#:#msg_no_perm_paste_object_in_folder#:#Ihnen fehlt die Berechtigung, um das Objekt %s in den Ordner %s einzufügen. common#:#msg_no_perm_perm#:#Ihnen fehlt die Berechtigung, um auf die Rechteeinstellungen zuzugreifen. common#:#msg_no_perm_read#:#Ihnen fehlt die Berechtigung, um auf dieses Objekt zuzugreifen. -common#:#msg_no_perm_read_item#:#Sie haben keine Berechtigung, auf das Objekt „%s“ zuzugreifen. +common#:#msg_no_perm_read_item#:#Sie haben keine Berechtigung, auf das Objekt zuzugreifen. common#:#msg_no_perm_read_lm#:#Ihnen fehlt die Berechtigung, um diese Lernmodul anzuzeigen. common#:#msg_no_perm_view_roles_of_user#:#Sie haben keine Berechtigung, auf die Rollenzuweisung des Kontos zuzugreifen common#:#msg_no_perm_write#:#Sie besitzen keine Rechte, um Einstellungen zu ändern! @@ -5107,6 +5079,8 @@ common#:#obj_ps_desc#:#Globale Einstellungen für Datenschutz und Sicherheit common#:#obj_qpl#:#Fragenpool für Tests common#:#obj_qpl_duplicate#:#Fragenpool für Tests kopieren common#:#obj_qpl_select#:#-- Bitte wählen Sie einen Fragenpool für Tests aus -- +common#:#obj_qsts#:#Fragen +common#:#obj_qsts_desc#:#Globale Einstellungen für Fragen common#:#obj_rcat#:#ECS-Kategorie common#:#obj_rcrs#:#ECS-Kurs common#:#obj_recf#:#Wiederhergestellte Objekte @@ -5160,7 +5134,7 @@ common#:#obj_tala_desc#:#Gesprächsvorlagen common#:#obj_tals#:#Team Gesprächserie common#:#obj_talt#:#Gesprächsvorlage common#:#obj_task#:#To-Do -common#:#obj_tax#:#Taxonomie +common#:#obj_tax#:#Taxonomien innerhalb dieses Objekts common#:#obj_taxf#:#Taxonomienordner common#:#obj_tool_setting_calendar#:#Kalender-Block common#:#obj_tool_setting_calendar_active#:#Kalender @@ -5381,6 +5355,7 @@ common#:#preconditions_optional_hint#:#Bitte erfüllen Sie mindestens %s common#:#predefined_template#:#Vordefinierte Rollenvorlage common#:#preferences#:#Benutzerdefinierte Einstellungen common#:#presentation_table_more#:#Mehr anzeigen +common#:#presenter#:#Präsentiert von common#:#preview#:#Vorschau common#:#preview_create#:#Vorschau erstellen common#:#preview_delete#:#Vorschau löschen @@ -5705,6 +5680,7 @@ common#:#show_content#:#Inhalt anzeigen common#:#show_details#:#Details anzeigen common#:#show_filter#:#Filter anzeigen common#:#show_hidden_sections#:#Weitere Informationen anzeigen » +common#:#show_less#:#Weniger zeigen common#:#show_list#:#Auflistung anzeigen common#:#show_members#:#Mitglieder anzeigen common#:#show_more#:#Mehr zeigen @@ -7673,20 +7649,20 @@ crs#:#crs_loc_passes_info#:#Maximalanzahl Testdurchläufe: crs#:#crs_loc_passes_left#:#Verbleibende Anzahl von Testdurchläufen crs#:#crs_loc_passes_reached#:#Keine weiteren Testdurchläufe möglich crs#:#crs_loc_perc#:#Benötigte Prozentzahl an Punkten -crs#:#crs_loc_progress_do_qualifying#:#Bitte führen Sie den Abschlusstest durch, um das Lernziel abzuschließen. -crs#:#crs_loc_progress_do_qualifying_again#:#Bitte bearbeiten Sie das Lernziel erneut. +crs#:#crs_loc_progress_do_qualifying#:#Führen Sie den Abschlusstest durch, um das Erreichen des Lernziels zu überprüfen. +crs#:#crs_loc_progress_do_qualifying_again#:#Bitte bearbeiten Sie die Materialien zum Lernziel erneut. crs#:#crs_loc_progress_no_result_do_initial#:#Bearbeiten Sie den Einstiegstest -crs#:#crs_loc_progress_no_result_no_initial#:#Bearbeiten Sie die folgenden Materialien und danach den Abschlusstest. +crs#:#crs_loc_progress_no_result_no_initial#:#Bearbeiten Sie die folgenden Materialien und absolvieren danach den Abschlusstest. crs#:#crs_loc_progress_objective_complete#:#Sie haben das Lernziel erreicht. crs#:#crs_loc_progress_result_itest#:#Ergebnis Einstiegstest crs#:#crs_loc_progress_result_qtest#:#Ergebnis -crs#:#crs_loc_qst_resume_tst_itest#:#Einstiegstests zu verschiedenen Lernzielen dürfen nicht parallel gestartet werden. Sie haben schon einen Einstiegstest zu einem Lernziel gestartet. Entweder setzen Sie diesen alten Test fort oder Sie starten einen neuen Test. -crs#:#crs_loc_qst_resume_tst_qtest#:#Qualifizierende Tests zu verschiedenen Lernzielen dürfen nicht parallel gestartet werden. Sie haben schon einen Qualifizierenden Test zu einem Lernziel gestartet. Entweder setzen Sie diesen alten Test fort oder Sie starten einen neuen Test. +crs#:#crs_loc_qst_resume_tst_itest#:#Einstiegstests zu verschiedenen Lernzielen dürfen nicht parallel gestartet werden. Sie haben schon einen Einstiegstest zu einem Lernziel gestartet. Entweder setzen Sie diesen Test fort oder starten einen neuen Test. +crs#:#crs_loc_qst_resume_tst_qtest#:#Qualifizierende Tests zu verschiedenen Lernzielen dürfen nicht parallel gestartet werden. Sie haben schon einen Qualifizierenden Test zu einem Lernziel gestartet. Entweder setzen Sie diesen Test fort oder starten einen neuen Test. crs#:#crs_loc_qtest_info#:#Abschlusstest -crs#:#crs_loc_qtst_for_objective#:#Qualifizierender Test "%1$s" +crs#:#crs_loc_qtst_for_objective#:#Qualifizierender Test „%1$s“ crs#:#crs_loc_rand_assign_qpl#:#Zuordnung aus Fragenpool crs#:#crs_loc_rand_qpl#:#Verfügbare Fragenpools -crs#:#crs_loc_settings_err_qstart#:#Die Option "Abschlusstest als Startobjekt" wurde deaktiviert, da sie nur für Kurse ohne Einstiegstest verwendet werden kann. +crs#:#crs_loc_settings_err_qstart#:#Die Option „Abschlusstest als Startobjekt“ wurde deaktiviert, da sie nur für Kurse ohne Einstiegstest verwendet werden kann. crs#:#crs_loc_settings_it_start_object#:#Einstiegstest ist Startobjekt crs#:#crs_loc_settings_it_type#:#Einstiegstest crs#:#crs_loc_settings_itest_tbl#:#Einstellungen für Einstiegstest @@ -7707,21 +7683,21 @@ crs#:#crs_loc_settings_tbl_its_q_all#:#Qualifizierender Einstiegstest über alle crs#:#crs_loc_settings_tbl_qt#:#Abschlusstests pro Lernziel crs#:#crs_loc_settings_tbl_qts_all#:#Abschlusstest über alle Lernziele crs#:#crs_loc_settings_type_it_none#:#Kein Einstiegstest -crs#:#crs_loc_settings_type_it_none_info#:#Kein Einstiegstest +crs#:#crs_loc_settings_type_it_none_info#:#Die am Kurs teilnehmenden Personen arbeiten sich selbstgesteuert durch das Kursangebot, um die Lernziele zu erreichen. Sie können den Abschlusstest ablegen, um festzustellen, ob sie die Lernziele bereits erreicht haben oder ob zusätzliches Lernen und Training erforderlich ist. crs#:#crs_loc_settings_type_it_placement_all#:#Diagnostischer Einstiegstest über alle Lernziele -crs#:#crs_loc_settings_type_it_placement_all_info#:#Diagnostischer Einstiegstest über alle Lernziele +crs#:#crs_loc_settings_type_it_placement_all_info#:#Es muss zunächst ein erster Test absolviert werden, der Fragen zu allen Lernzielen enthält. Auf der Grundlage der individuellen Ergebnisse wird unterstützendes Lernmaterial empfohlen. Auch Lernziele, die in diesem Test bereits bestanden wurden, werden im Abschlusstest erneut überprüft. crs#:#crs_loc_settings_type_it_placement_sel#:#Diagnostischer Einstiegstest pro Lernziel -crs#:#crs_loc_settings_type_it_placement_sel_info#:#Diagnostischer Einstiegstest pro Lernziel +crs#:#crs_loc_settings_type_it_placement_sel_info#:#Für jedes Lernziel muss ein separater Einstiegstest absolviert werden. Dieser enthält nur Fragen zu dem jeweiligen Lernziel. Auf der Grundlage der individuellen Ergebnisse wird unterstützendes Lernmaterial empfohlen. Auch Lernziele, die in den Einstiegstests bestanden wurden, werden im Abschlusstest erneut überprüft. crs#:#crs_loc_settings_type_it_qualifying_all#:#Qualifizierender Einstiegstest über alle Lernziele -crs#:#crs_loc_settings_type_it_qualifying_all_info#:#Qualifizierender Einstiegstest über alle Lernziele +crs#:#crs_loc_settings_type_it_qualifying_all_info#:#Der Eingangstest bewertet, ob ein Lernziel bereits erreicht wird. Der Test enthält Fragen zu allen Lernzielen. Wurden Lernziele im Einstiegstest bereits erreicht, werden sie nicht mehr im Abschlusstest überprüft. crs#:#crs_loc_settings_type_it_qualifying_sel#:#Qualifizierender Einstiegstest pro Lernziel -crs#:#crs_loc_settings_type_it_qualifying_sel_info#:#Qualifizierender Einstiegstest pro Lernziel +crs#:#crs_loc_settings_type_it_qualifying_sel_info#:#Für jedes Lernziel bewertet ein separater Einstiegstest, ob ein Lernziel bereits erreicht wird. Die jeweiligen Tests enthalten nur Fragen zum jeweiligen Lernziel und prüfen, ob das jeweilige Lernziel bereits erreicht wird oder nicht. Wurde ein Lernziel im zugehörigen Einstiegstest bereits erreicht, wird es nicht mehr im Abschlusstest überprüft. crs#:#crs_loc_settings_type_q_all#:#Abschlusstest über alle Lernziele -crs#:#crs_loc_settings_type_q_all_info#:#Abschlusstest über alle Lernziele +crs#:#crs_loc_settings_type_q_all_info#:#Das Erreichen aller Lernziele wird in einem einzigen Abschlusstest überprüft. crs#:#crs_loc_settings_type_q_selected#:#Abschlusstest pro Lernziel -crs#:#crs_loc_settings_type_q_selected_info#:#Abschlusstest pro Lernziel +crs#:#crs_loc_settings_type_q_selected_info#:#Für jedes Lernziel ist ein separater Abschlusstest zu absolvieren, um das Erreichen des jeweiligen Lernziels zu bestätigen. crs#:#crs_loc_subtab_creation#:#Erstellen -crs#:#crs_loc_suggested#:#Bearbeiten Sie bitte die aufgeführten Materialien, um das Lernziel zu erreichen. +crs#:#crs_loc_suggested#:#Bearbeiten Sie die nachfolgend aufgeführten Materialien. Führen Sie am Ende den Abschlusstest durch, um das Erreichen des Lernziels zu überprüfen. crs#:#crs_loc_tab_itest#:#Einstiegstest crs#:#crs_loc_tab_itests#:#Einstiegstests crs#:#crs_loc_tab_materials#:#Materialien @@ -9096,12 +9072,12 @@ ecs#:#ecs_cms_id#:#Root-ID im Campus-Management-System ecs#:#ecs_cms_tree_deleted#:#Die Zuweisungen zum Campus-Management-Baum wurden gelöscht ecs#:#ecs_cms_tree_synchronize#:#Synchronisieren ecs#:#ecs_cms_tree_synchronized#:#Der Baum wurde synchronisiert. -ecs#:#ecs_communities#:#Teilnehmer +ecs#:#ecs_communities#:#Partizipanten ecs#:#ecs_confirm_delete_tree#:#Wollen Sie wirklich alle Zuweisungen zu diesem CMS-Baum löschen? ecs#:#ecs_connection_settings#:#Verbindungsdaten ecs#:#ecs_consent_modal_btn_accept#:#Zustimmen und fortfahren ecs#:#ecs_consent_modal_title#:#Einwilligung zur Datenübertragung -ecs#:#ecs_consent_reset_confirm_title#:#Benutzerzustimmung für diesen Teilnehmer zurücksetzen +ecs#:#ecs_consent_reset_confirm_title#:#Benutzerzustimmung für diesen Partizipanten zurücksetzen ecs#:#ecs_cron_task_scheduler#:#ECS-Aufgaben ausführen ecs#:#ecs_cron_task_scheduler_info#:#Wenn aktiviert, werden ECS-Aufgaben regelmäßig ausgeführt. Dies ist nur möglich, wenn ein ECS-Server unter „Administration » ILIAS erweitern » ECS“ aktiviert ist. ecs#:#ecs_crs_alloc#:#Kurszuordnungen @@ -9152,7 +9128,7 @@ ecs#:#ecs_field_cycle#:#Zyklus ecs#:#ecs_field_day#:#Tag ecs#:#ecs_field_end#:#Endtermin ecs#:#ecs_field_lecturer#:#Leitung -ecs#:#ecs_field_part_id#:#Teilnehmer-ID +ecs#:#ecs_field_part_id#:#Partizipanten-ID ecs#:#ecs_field_room#:#Raum ecs#:#ecs_field_semester_hours#:#Semesterwochenstunden ecs#:#ecs_field_start#:#Starttermin @@ -9186,11 +9162,11 @@ ecs#:#ecs_import_id#:#Import-ID ecs#:#ecs_import_id_info#:#Bitte geben Sie die ID der Kategorie ein, in der neue ECS-Objekte angelegt werden sollen. ecs#:#ecs_import_types#:#Importierbare Objekttypen ecs#:#ecs_import_user_credentials_by_auth_mode#:#Konfiguration der Authentifikations-Methoden zur Übertragung via ECS -ecs#:#ecs_import_user_credentials_by_auth_mode_info#:#Aktivieren Sie diese Option um es Account der Authentifizierungsmethode "Default" zu erlauben, über den ECS auf Ressourcen des Teilnehmers zugreifen zu können. +ecs#:#ecs_import_user_credentials_by_auth_mode_info#:#ILIAS-Konten, die die Standard-Authentifizierungsmethode verwenden, können über den ECS auf Ressourcen des Partizipanten zugreifen. ecs#:#ecs_imported_content#:#Importierte Materialien ecs#:#ecs_imported_from#:#Importiert von ecs#:#ecs_institution#:#Institution -ecs#:#ecs_invalid_import_type_cms#:#Sie können den Import-Typ "Campus-Management" nur für maximal einen Teilnehmer auswählen. +ecs#:#ecs_invalid_import_type_cms#:#Sie können den Import-Typ „Campus-Management“ nur für maximal einen Partizipanten auswählen. ecs#:#ecs_key_password#:#Schlüsselpasswort ecs#:#ecs_lastname#:#Nachname ecs#:#ecs_lm_export#:#Lernmodulfreigaben @@ -9205,7 +9181,7 @@ ecs#:#ecs_mapping_exp_tbl#:#Zuordnung der Erweiterten Metadaten zu ECS-Daten ecs#:#ecs_mapping_rcrs#:#Zuordnung für ECS-Kurse ecs#:#ecs_mapping_tbl#:#Zuordnung von ECS-Daten zu Erweiterten Metadaten ecs#:#ecs_mappings#:#Zuordnung von ECS-Daten -ecs#:#ecs_member_auth_type#:#Authentifizierungsmodus der Teilnehmer +ecs#:#ecs_member_auth_type#:#Authentifizierungsmodus der Partizipanten ecs#:#ecs_meta_data#:#Metadaten ecs#:#ecs_new_approval_subject#:#Ein neuer Kurs wurde freigegeben ecs#:#ecs_new_category_mapping#:#Neue Regel für die Zuordnung von importierten ECS-Kursen zu Kategorien @@ -9227,8 +9203,8 @@ ecs#:#ecs_not_published#:#Es wurden keine Freigaben ausgewählt. ecs#:#ecs_notifications#:#Benachrichtigungen ecs#:#ecs_outgoing_user_credentials#:#Benutzerattribut ecs#:#ecs_outgoing_user_credentials_info#:#Bitte geben Sie an, welches Benutzerattribut zur Übertragung verwendet werden soll. Mögliche Werte [Login], [EXTERNAL_ACCOUNT]. Sie können das angegebene Attribut durch voranstellen oder anhängen von beliebigen Strings verändern. Bespiel: [LOGIN]@example.com -ecs#:#ecs_part_settings#:#Einstellungen für Teilnehmer: -ecs#:#ecs_participants#:#Teilnehmer +ecs#:#ecs_part_settings#:#Einstellungen für Partizipanten: +ecs#:#ecs_participants#:#Partizipanten ecs#:#ecs_participants_infos#:#Weitere Informationen ecs#:#ecs_polling#:#Frequenz der Abfragen ecs#:#ecs_polling_info#:#Bitte legen Sie eine Frequenz für Anfragen an den ECS-Server fest. @@ -9241,7 +9217,7 @@ ecs#:#ecs_published_for#:#Freigegeben für: ecs#:#ecs_rcat_created_body_a#:#Eine neue ECS-Kategorie wurde angelegt: ecs#:#ecs_rcrs_created_body_a#:#Ein neuer ECS-Kurs wurde angelegt: ecs#:#ecs_read_remote_links#:#Kursinformationen aktualisieren -ecs#:#ecs_refresh_participants#:#ECS-Teilnehmer aktualisieren +ecs#:#ecs_refresh_participants#:#ECS-Partizipanten aktualisieren ecs#:#ecs_released#:#Freigegebene Kurse ecs#:#ecs_released_content#:#Freigegebener E-Content ecs#:#ecs_remote_imported#:#Die Informationen über Kursänderungen wurden neu eingelesen. @@ -9279,7 +9255,7 @@ ecs#:#ecs_tst_export#:#Testfreigaben ecs#:#ecs_tst_export_disabled#:#Nicht freigeben ecs#:#ecs_tst_export_enabled#:#Freigeben ecs#:#ecs_tst_export_obj_settings#:#Einstellungen für Testfreigaben -ecs#:#ecs_unique_id#:#Teilnehmer-ID +ecs#:#ecs_unique_id#:#Partizipanten-ID ecs#:#ecs_user_rcp#:#Benachrichtigungen über ECS-Benutzer ecs#:#ecs_user_rcp_info#:#Geben Sie hier kommagetrennt einen oder mehrere Anmeldenamen ein, die über neue ECS-Konten per Mail benachrichtigt werden sollen. ecs#:#ecs_wiki_export#:#Wikifreigaben @@ -9435,7 +9411,7 @@ exc#:#exc_fixed_date_individual_info#:#Es gibt keinen gemeinsamen Abgabetermin. exc#:#exc_fixed_date_info#:#Alle Teilnehmenden erhalten zunächst das gleiche feste Abgabedatum. exc#:#exc_fullscreen#:#Vollbild exc#:#exc_future#:#Kommende -exc#:#exc_given_feedback#:#Gegebene Feedbacks +exc#:#exc_given_feedback#:#Gegebenes Feedback exc#:#exc_global_feedback_file#:#Musterlösung exc#:#exc_global_feedback_file_after_date#:#Nach festem Datum exc#:#exc_global_feedback_file_cron#:#Benachrichtigung bei Verfügbarkeit @@ -9504,9 +9480,9 @@ exc#:#exc_msg_new_feedback_file_uploaded2#:#Eine neue Feedback-Datei wurde für exc#:#exc_msg_new_feedback_text_uploaded#:#Es wurde ein neuer Kommentar zur Übung „%s“ hinzugefügt. exc#:#exc_msg_new_feedback_text_uploaded2#:#die folgende Einreichung von Ihnen wurde kommentiert. exc#:#exc_msg_new_message_from_pf_giver#:#Es wurde eine neue Mitteilung zur Übung „%s“ hinzugefügt. -exc#:#exc_msg_new_message_from_pf_giver2#:#Ein Peer-Feedback-Geber hat eine neue Mitteilung für Sie eingestellt: +exc#:#exc_msg_new_message_from_pf_giver2#:#Eine Person, die Ihnen Feedback gegeben hat, hat folgende Mitteilung an Sie: exc#:#exc_msg_new_message_from_pf_recipient#:#Es wurde eine neue Mitteilung zur Übung „%s“ hinzugefügt. -exc#:#exc_msg_new_message_from_pf_recipient2#:#Ein Peer-Feedback-Nehmer hat eine neue Mitteilung für Sie eingestellt: +exc#:#exc_msg_new_message_from_pf_recipient2#:#Eine Person, die von Ihnen Feedback erhalten hat, hat folgende Mitteilung an Sie: exc#:#exc_msg_participants_removed#:#Die Personen wurden aus der Übung entfernt. exc#:#exc_msg_public_submission#:#Alle Lösungsabgaben werden nach dem Abgabetermin veröffentlicht. exc#:#exc_msg_saved_grades#:#Die Änderungen wurden gespeichert. @@ -9574,11 +9550,11 @@ exc#:#exc_peer_review_file#:#Datei-Upload exc#:#exc_peer_review_file_info#:#Ermöglicht Peers eine Datei je Review hochzuladen exc#:#exc_peer_review_give#:#Feedback geben exc#:#exc_peer_review_given#:#Gegebenes Feedback zeigen -exc#:#exc_peer_review_giver#:#Feedback-Geber -exc#:#exc_peer_review_invalid_giver_ids#:#Feedback-Geber, die an der Übung nicht teilnehmen oder nichts abgegeben haben -exc#:#exc_peer_review_invalid_peer_ids#:#Feedback-Nehmer, die an der Übung nicht teilnehmen oder nichts abgegeben haben +exc#:#exc_peer_review_giver#:#Feedback von +exc#:#exc_peer_review_invalid_giver_ids#:#Personen, die Feedback geben sollten, aber nicht an der Übung teilgenommen oder kein Feedback abgegeben haben +exc#:#exc_peer_review_invalid_peer_ids#:#Personen, denen ein Feedback gegeben werden sollte, die aber nicht an der Übung teilgenommen haben oder denen kein Feedback gegeben wurde exc#:#exc_peer_review_min_chars#:#Mindestanzahl Zeichen -exc#:#exc_peer_review_min_chars_info#:#Die nötige Anzahl Zeichen für ein gültiges Feedback. +exc#:#exc_peer_review_min_chars_info#:#Die nötige Anzahl Zeichen für ein gültiges Feedback exc#:#exc_peer_review_min_chars_tgl#:#Mindestlänge exc#:#exc_peer_review_min_number#:#Geforderte Anzahl von Feedbacks exc#:#exc_peer_review_min_number_info#:#Anzahl von Einreichungen, zu denen man Feedback geben muss. Sollte die Anzahl der geforderten Rückmeldungen die Anzahl der tatsächlichen Einreichungen übersteigen, wird die geforderte Anzahl automatisch auf die Anzahl der tatsächlichen Einreichungen reduziert. @@ -9587,13 +9563,13 @@ exc#:#exc_peer_review_missing_info_deadline#:#Um das erhaltene Feedback zu sehen exc#:#exc_peer_review_missing_users#:#Benutzer mit einer Abgabe, die nicht Teil des Peer-Feedbacks sind exc#:#exc_peer_review_no_peers#:#Es konnten keine Peers gefunden werden. exc#:#exc_peer_review_no_peers_reviewed_yet#:#Es wurden bisher noch keine Bewertungen vorgenommen. -exc#:#exc_peer_review_not_returned_users#:#Benutzer ohne Abgabe, die nicht Teil des Peer-Feedbacks sind +exc#:#exc_peer_review_not_returned_users#:#Personen ohne Abgabe, die nicht Teil des Peer-Feedbacks sind exc#:#exc_peer_review_overview#:#Peer-Gruppen anzeigen -exc#:#exc_peer_review_overview_invalid_users#:#Ungültige Benutzer +exc#:#exc_peer_review_overview_invalid_users#:#Andere Personen exc#:#exc_peer_review_personal#:#Personalisiertes Peer-Feedback exc#:#exc_peer_review_personal_info#:#Peers werden mit vollem Namen gezeigt exc#:#exc_peer_review_rating#:#5-Sterne-Bewertung -exc#:#exc_peer_review_recipient#:#Feedback-Nehmer +exc#:#exc_peer_review_recipient#:#Feedback an exc#:#exc_peer_review_reset#:#Peer-Feedback löschen und zurücksetzen exc#:#exc_peer_review_reset_done#:#Sämtliche Peer-Feedback-Daten wurde für die Übungseinheit gelöscht. exc#:#exc_peer_review_reset_sure#:#Wollen Sie wirklich das komplette Peer-Feedback für die Übungseinheit „%s“ löschen? @@ -9625,7 +9601,7 @@ exc#:#exc_random_assignment_info#:#Wenn Sie die Übung starten, wird Ihnen eine exc#:#exc_random_selection#:#Zufällige Auswahl exc#:#exc_random_selection_info#:#Jeder Person wird eine zufällige Auswahl an verpflichtenden Übungseinheiten zugeordnet. exc#:#exc_random_selection_not_changeable_info#:#Diese Option kann nicht aktiviert werden. -exc#:#exc_received_feedback#:#Erhaltene Feedbacks +exc#:#exc_received_feedback#:#Erhaltenes Feedback exc#:#exc_rel_last_submission#:#Letztmöglicher Abgabetermin exc#:#exc_rel_last_submission_info#:#Wird dieses Datum gesetzt, so müssen alle Abgaben vor diesem Datum getätigt werden. exc#:#exc_rel_start_latest_lead_text#:#spätestens am %s @@ -9888,7 +9864,7 @@ file#:#copyright_custom#:#Benutzerdefiniert file#:#copyright_custom_info#:#Lizenz auswählen, welche auf alle entpackten Dateien dieses Archivs angewandt wird. file#:#copyright_inherited#:#Vererbt file#:#copyright_inherited_info#:#Lizenz des Zip-Archivs auf seine entpackten Dateien anwenden.
    Lizenz des Zip-Archivs: %s. -file#:#could_not_create_file_objs#:#Beim Erstellen der Dateiobjekte ist ein Fehler aufgetreten, wenden Sie sich an die Administrierenden der Plattform. +file#:#could_not_create_file_objs#:#Beim Erstellen der Dateiobjekte ist ein Fehler aufgetreten. Bitte wenden Sie sich an die technische Betreuung dieser Installation. file#:#de_activate_icon#:#(De-)Aktivieren file#:#download_ascii_filename#:#Nur ASCII-Zeichen im Download file#:#download_ascii_filename_info#:#Die Namen heruntergeladener Dateien enthalten nur ASCII-Zeichen und können so auf allen Systemen problemlos genutzt werden. Andere Zeichen werden durch Unterstriche ersetzt. Auf Installationen, die Dateinamen mit nicht-lateinischen Schriftzeichen nutzen, muss diese Option deaktiviert werden. @@ -10328,6 +10304,7 @@ glo#:#glo_really_remove_from_collection#:#Sind Sie sich sicher, dass Sie das fol glo#:#glo_reference#:#Link glo#:#glo_reference_terms#:#Begriffe verlinken glo#:#glo_referenced_term#:#Verlinkte Begriffe +glo#:#glo_remove_glossary#:##Sind Sie sich sicher, dass Sie das folgende Glossar aus der Liste der automatisch verlinkten Glossare entfernen wollen? glo#:#glo_removed_from_collection_info#:#Das Glossar wurde aus dem Sammelglossar entfernt. glo#:#glo_reset_all_boxes#:#Alle Fächer zurücksetzen glo#:#glo_save_and_continue#:#Speichern und weiter @@ -10672,8 +10649,8 @@ iass#:#grading#:#Bewertung iass#:#grading_info#:#Bewertungsinformationen iass#:#grading_record#:#Bewertungszusammenfassung iass#:#iass_add#:#Individuelle Bewertung anlegen -iass#:#iass_add_user_failure#:#Einer oder mehrere Benutzer konnten nicht hinzugefügt werden. -iass#:#iass_add_user_success#:#Benutzer als Teilnehmer hinzugefügt. +iass#:#iass_add_user_failure#:#Eine oder mehrere Personen konnten nicht hinzugefügt werden. +iass#:#iass_add_user_success#:#Die Person wurde hinzugefügt. iass#:#iass_added#:#Individuelle Bewertung hinzugefügt iass#:#iass_amend_saved#:#Geänderte Prüfungsdaten wurden gespeichert. iass#:#iass_assessment_not_completed#:#Noch nicht abgeschlossen @@ -10691,13 +10668,14 @@ iass#:#iass_edit#:#Einstellungen iass#:#iass_edit_info#:#Einstellungen Kontakt iass#:#iass_edit_record#:#Prüfungsdaten iass#:#iass_event_time#:#Zeitpunkt der Prüfung -iass#:#iass_event_time_place_required#:#Pflichtangabe Zeitpunkt und Ort +iass#:#iass_event_time_place_required#:#Pflichtangabe „Zeitpunkt“ und „Ort“ iass#:#iass_event_time_place_required_info#:#Zeitpunkt und Ort der Prüfung müssen eingetragen werden. -iass#:#iass_file#:#Datei -iass#:#iass_file_dropzone#:#Ziehen Sie ihre Datei hierhin +iass#:#iass_file#:#Prüfungsblatt +iass#:#iass_file_dropzone#:#Ziehen Sie die Datei hierhin. iass#:#iass_file_required#:#Pflichtangabe Prüfungsblatt iass#:#iass_file_required_info#:#Ein Prüfungsblatt muss hochgeladen werden. -iass#:#iass_file_visible_examinee#:#Datei für Teilnehmer sichtbar +iass#:#iass_file_visible_examinee#:#Prüfungsblatt für bewertete Person sichtbar +iass#:#iass_file_visible_examinee_info#:#Nach abgeschlossener Bewertung kann das Prüfungsblatt von der bewerteten Person eingesehen werden. Dazu muss die Funktion „Ergebnis zugänglich machen“ aktiviert sein. iass#:#iass_filter_all#:#Alle iass#:#iass_filter_failed#:#Nur nicht bestandene iass#:#iass_filter_finalized#:#Nur bestandene @@ -10705,28 +10683,28 @@ iass#:#iass_filter_not_finalized#:#Nur nicht abgeschlossene iass#:#iass_filter_not_started#:#Nur nicht bewertete iass#:#iass_finalize#:#Abschließen iass#:#iass_finalize_info#:#Die Individuelle Bewertung wird abgeschlossen. -iass#:#iass_finalize_user_qst#:#Soll die Bewertung des Teilnehmers wirklich final abgeschlossen werden? Änderungen an der Bewertung sind hinterher nicht mehr möglich. +iass#:#iass_finalize_user_qst#:#Soll diese Bewertung wirklich abgeschlossen werden? iass#:#iass_further_field_headline#:#Detaillierte Informationen iass#:#iass_graded_by#:#Bewertet von iass#:#iass_info_emails_expl#:#Sie können mehrere Adressen mit einem Komma getrennt angeben. iass#:#iass_internal_note#:#Interne Anmerkungen zur Prüfung -iass#:#iass_internal_note_info#:#Dieser Text ist nur für Personen sichtbar, die Prüfungsdaten einsehen können. Teilnehmerinnen und Teilnehmer sehen die interne Anmerkung zur Prüfung nicht. +iass#:#iass_internal_note_info#:#Dieser Text ist nur für Personen sichtbar, die Prüfungsdaten einsehen können. Bewertete Personen sehen die interne Anmerkung zur Prüfung nicht. iass#:#iass_location#:#Ort iass#:#iass_mails#:#E-Mail iass#:#iass_may_not_finalize#:#Prüfung kann noch nicht abschließend bewertet werden. Bitte geben Sie eine Bewertung ab. iass#:#iass_membership_finalized#:#Bewertung abgeschlossen. -iass#:#iass_membership_saved#:#Bewertung wurde gespeichert aber noch nicht final abgeschlossen. +iass#:#iass_membership_saved#:#Bewertung wurde gespeichert, aber noch nicht final abgeschlossen. iass#:#iass_mess_notification_completed#:#Sie haben die Prüfung „%s“ bestanden. Beachten Sie bitte auch die folgende Notiz zur Prüfung. iass#:#iass_mess_notification_failed#:#Sie haben die Prüfung „%s“ leider nicht bestanden. Beachten Sie bitte auch die folgende Notiz zur Prüfung. -iass#:#iass_notify#:#Ergebnis dem Teilnehmer zugänglich machen -iass#:#iass_notify_explanation#:#Der Teilnehmer wird nach Abschluss der Bewertung per E-Mail benachrichtigt und kann die Prüfungsnotiz auf dem Reiter „Info“ einsehen. +iass#:#iass_notify#:#Ergebnis zugänglich machen +iass#:#iass_notify_explanation#:#Die bewertete Person wird nach Abschluss der Bewertung per E-Mail benachrichtigt und kann die Prüfungsnotiz auf dem Reiter „Info“ und in der E-Mail einsehen. iass#:#iass_phone#:#Telefon iass#:#iass_place#:#Ort der Prüfung iass#:#iass_record#:#Prüfungsnotiz -iass#:#iass_record_info#:#Die Prüfungsnotiz kann nach finaler Bewertung vom Teilnehmer eingesehen werden. Ist unten die Benachrichtigung aktiviert, erhält der Teilnehmer die Prüfungsnotiz auch per E-Mail. +iass#:#iass_record_info#:#Nach abgeschlossener Bewertung kann die Prüfungsnotiz von der bewerteten Person eingesehen werden. Dazu muss die Funktion „Ergebnis zugänglich machen“ aktiviert sein. iass#:#iass_record_template#:#Vorlage Prüfungsnotiz -iass#:#iass_record_template_explanation#:#Hier eingegebener Text dient als Vorlage für die Prüfungsnotiz und wird für jeden neuen Teilnehmer verwendet. -iass#:#iass_remove_user_qst#:#Soll der Teilnehmer wirklich entfernt werden? +iass#:#iass_record_template_explanation#:#Dieser Text dient als Vorlage für die Prüfungsnotiz und wird für jede neue Bewertung angezeigt. +iass#:#iass_remove_user_qst#:#Soll die Person wirklich aus der Individuellen Bewertung ausgetragen werden? iass#:#iass_responsibility#:#Zuständigkeit iass#:#iass_save_amend#:#Geänderte Prüfungsdaten speichern iass#:#iass_settings_availability#:#Verfügbarkeit @@ -10743,14 +10721,14 @@ iass#:#iass_status_pending#:#Noch nicht bewertet iass#:#iass_subj_notification_completed#:#%s: Individuelle Bewertung wurde erfolgreich abgeschlossen. iass#:#iass_subj_notification_failed#:#%s: Individuelle Bewertung wurde nicht erfolgreich abgeschlossen. iass#:#iass_upload_file#:#Prüfungsblatt -iass#:#iass_user_removed#:#Benutzer wurde erfolgreich entfernt. +iass#:#iass_user_removed#:#Person wurde erfolgreich ausgetragen. iass#:#iass_usr_amend#:#Prüfungsdaten nachträglich ändern -iass#:#iass_usr_download_attachment#:#Datei herunterladen +iass#:#iass_usr_download_attachment#:#Prüfungsblatt herunterladen iass#:#iass_usr_edit#:#Prüfungsdaten bearbeiten -iass#:#iass_usr_remove#:#Entfernen +iass#:#iass_usr_remove#:#Austragen iass#:#iass_usr_view#:#Prüfungsdaten -iass#:#il_iass_members#:#Teilnehmer -iass#:#lp_inactive#:#Beachten Sie: die Lernfortschrittsbestimmung für dieses Objekt ist deaktiviert. Daher können Teilnahmen nicht finalisiert werden. +iass#:#il_iass_members#:#Bewertungen +iass#:#lp_inactive#:#Beachten Sie: die Bestimmung des Lernfortschritts ist für dieses Objekt deaktiviert. Daher können Teilnahmen nicht finalisiert werden. iass#:#save_amend#:#Geänderte Prüfungsdaten speichern impr#:#impr_page_type_impr#:#Impressum init#:#init_error_authentication_fail#:#Authentifizierung fehlgeschlagen. @@ -11149,28 +11127,21 @@ lng#:#lng_disable_language_detection#:#Automatische Spracherkennung deaktivieren lng#:#lng_download_deprecated#:#Veraltete Einträge herunterladen lng#:#lng_enable_language_detection#:#Automatische Spracherkennung aktivieren lng#:#lng_switch_language_detection#:#Automatische Spracherkennung umschalten -log#:#log_browser#:#Browser Konsolen-Log -log#:#log_browser_users#:#Aktivierte Benutzer für Browser-Log -log#:#log_cache_#:#Caching -log#:#log_cache_info#:#Erst wenn eine Nachricht den eingestellten Caching-Level erreicht oder überschreitet, werden innerhalb des aktuellen Server-Requests alle Nachrichten protokolliert, deren Level mindestens dem Log-Level entspricht. -log#:#log_cache_level#:#Caching-Level log#:#log_component_btn_reset#:#Einstellungen zurücksetzen log#:#log_component_col_component#:#Komponente log#:#log_component_col_level#:#Log-Level -log#:#log_component_root_desc#:#Log-Level für Nachrichten, die keiner Komponente zugeordnet sind. +log#:#log_component_unknown#:#Unbekannt (%s) log#:#log_components#:#Komponenten -log#:#log_general_settings#:#Einstellungen zur Protokollierung log#:#log_level_alert#:#ALERT log#:#log_level_critical#:#CRITICAL log#:#log_level_debug#:#DEBUG +log#:#log_level_default#:#Standard (%s) log#:#log_level_emergency#:#EMERGENCY log#:#log_level_error#:#ERROR log#:#log_level_info#:#INFO log#:#log_level_notice#:#NOTICE log#:#log_level_off#:#Deaktiviert log#:#log_level_warning#:#WARNING -log#:#log_log_level#:#Log-Level -log#:#log_memory#:#Logge Speicherbedarf logging#:#error_settings_saved#:#Einstellungen gespeichert logging#:#frm_clear_older_then#:#Dateien löschen die älter sind als logging#:#frm_clear_older_then_info#:#Bitte geben Sie den Zeitraum in Tagen ein. @@ -13269,7 +13240,7 @@ obj#:#obj_deactivate_multilang#:#Mehrsprachigkeit deaktivieren obj#:#obj_deactivate_multilang_conf#:#Wollen Sie die Unterstützung für mehrsprachige Inhalte wirklich deaktivieren? Nur die Inhalte der Standardsprache werden verfügbar bleiben. obj#:#obj_fallback_lang#:#Standardsprache obj#:#obj_features#:#Zusätzliche Funktionen -obj#:#obj_import_file_error#:#Die Datei konnte nicht importiert werden. Bitte stellen Sie sicher, dass es sich um eine ILIAS-Exportdatei (XML-Export) des gleichen Objekttyps handelt und der Dateiname unverändert ist. Fehlermeldung: +obj#:#obj_import_file_error#:#Die Datei konnte nicht importiert werden. Bitte stellen Sie sicher, dass es sich um eine ILIAS-Exportdatei (XML-Export) des gleichen Objekttyps handelt und der Dateiname unverändert ist. obj#:#obj_insert_into_clipboard#:#In Zwischenablage übernehmen obj#:#obj_inserted_clipboard#:#Die Objekte wurden in die Zwischenablage übernommen. obj#:#obj_master_lang#:#Basissprache @@ -14132,6 +14103,114 @@ qpl#:#qpl_page_type_qfbg#:#Generelles Feedback qpl#:#qpl_page_type_qfbs#:#Spezielles Feedback qpl#:#qpl_page_type_qht#:#Hinweis qpl#:#qpl_page_type_qpl#:#Fragenseite +qsts#:#above_range#:#Oberhalb des Bereichs +qsts#:#add_gap_combination#:#Lückentext-Kombination hinzufügen +qsts#:#answer_form#:#Antwortformular +qsts#:#answer_options#:#Antwort-Optionen +qsts#:#answer_options_awarding_points#:#Punktevergebende Antwort-Optionen +qsts#:#answer_options_must_be_unique#:#Antwort-Optionen müssen einzigartig sein. +qsts#:#async_view#:#Asynchrone Ansicht +qsts#:#at_least_one_gap_positiv_points#:#Mindestens eine Lücke muss Punkte geben. +qsts#:#available_points#:#Maximal erreichbare Punkte +qsts#:#awarded_points#:#Erhaltene Punkte +qsts#:#basic_answer_form_properties#:#Grundlegende Eigenschaften des Antwortformulars +qsts#:#below_range#:#Unterhalb des Bereichs +qsts#:#best_response#:#Beste Antwort +qsts#:#best_response_given#:#Dies ist die bestmögliche Antwort. +qsts#:#between#:#Zwischen %s und %s +qsts#:#broken_answer_form#:#Ungültiges Antwortformular +qsts#:#byline_create_mode_full#:#Der Seiteneditor wird verwendet. Der Fragentext kann Formatierungen und mehrere Antwortformulare enthalten. +qsts#:#byline_create_mode_simple#:#Es wird nur ein Textfeld zur Eingabe des Fragentexts angezeigt. Der Fragetext kann keine Formatierungen enthalten und nur ein Antwortformular kann erstellt werden. Beim Abschluss des Erstellprozesses wird ein Knopf angeboten, der es erlaubt beim Speichern gleich die nächste Frage zu erstellen. +qsts#:#cloze#:#Lückentext +qsts#:#cloze_enable_gap_combinations#:#Enable Gap Combination +qsts#:#cloze_text#:#Lückentextfrage +qsts#:#cloze_textgap_case_insensitive#:#Zwischen Groß- und Kleinschreibung wird nicht unterschieden +qsts#:#cloze_textgap_case_sensitive#:#Groß- und Kleinschreibung beachten +qsts#:#cloze_textgap_levenshtein_of#:#Levenshtein-Abstand von %s +qsts#:#combination_needs_more_than_one#:#Eine Kombination von Lücken muss mehr als eine Lücke enthalten. +qsts#:#confirm_delete_feedback#:#Soll diese Rückmeldung wirklich gelöscht werden? +qsts#:#confirm_delete_questions#:#Sind Sie sicher, dass Sie die folgenden Fragen entfernen wollen? +qsts#:#confirm_remove_gaps#:#Es wurden Lücken aus dem Lückentext entfernt. Sollen diese nun definitiv entfernt und alle dazugehörigen Informationen gelöscht werden. +qsts#:#cont_ed_insert_answf#:#Antwortformular einfügen +qsts#:#contained_answer_form_types#:#Enthaltene Antwortformulartypen +qsts#:#contains_answer_form_types#:#Enthält Antwortformulartypen +qsts#:#create_answer_form#:#Antwortformular erstellen +qsts#:#create_feedback#:#Rückmeldung erstellen +qsts#:#create_mode_full#:#Vollständig +qsts#:#create_mode_simple#:#Einfach +qsts#:#create_question#:#Frage erstellen +qsts#:#default_user_settings#:#Standard Einstellungen +qsts#:#default_view#:#Standard Ansicht +qsts#:#delete_combination#:#Delete Combination of Gaps +qsts#:#delete_responses#:#Antworten löschen +qsts#:#disable_marking_allowing_partial_points#:#Bewertung deaktivieren +qsts#:#disable_suggested_learning_content#:#Inhalte zur Wiederholung deaktivieren +qsts#:#disable_text_feedback#:#Rückmeldungen deaktivieren +qsts#:#edit_answer_options#:#Antwort-Optionen bearbeiten +qsts#:#edit_available_points#:#Verfügbare Punkte bearbeiten +qsts#:#edit_basic_answer_form_properties#:#Grundlegende Eigenschaften des Antwortformulars bearbeiten +qsts#:#edit_basic_question_properties#:#Grundeinstellungen der Frage bearbeiten +qsts#:#edit_feedback#:#eedback bearbeiten +qsts#:#edit_gaps#:#Lücken bearbeiten +qsts#:#edit_generic_feedback#:#Rückmeldung basierend auf den erreichten Punkten +qsts#:#edit_points#:#Punkte bearbeiten +qsts#:#edit_suggested_learning_content#:#Inhalt zur Wiederholung bearbeiten +qsts#:#enable_marking_allowing_partial_points#:#Bewertung aktivieren +qsts#:#enable_suggested_learning_content#:#Inhalte zur Wiederholung +qsts#:#enable_text_feedback#:#Rückmeldungen aktivieren +qsts#:#equal#:#Gleich %s +qsts#:#gap#:#Lücke +qsts#:#gap_combination_already_exists#:#Diese Kombination von Lücken existiert bereits. +qsts#:#gap_combinations#:#Lückentext-Kombinationen +qsts#:#gap_type#:#Art der Lücke +qsts#:#gaps#:#Lücken +qsts#:#insert_gap#:#Lücke einfügen +qsts#:#insert_legacy_texts#:#Texte aus Altdaten importieren +qsts#:#insert_legacy_texts_info#:#Es gibt Texte, die aus einer älteren Version importiert wurden. Diese Texte können nicht direkt bearbeitet werden, sie können jedoch in das Formulare importiert werden. Dabei gehen alle Formatierungen verloren. +qsts#:#legacy_text_cannot_be_edited#:#Der Text stammt aus einer überführten Frage und kann nicht geändert werden. +qsts#:#long_menu_gap#:#Longmenu +qsts#:#max_characters#:#Maximale Zeichenanzahl +qsts#:#min_auto_complete#:#Autovervollständigung +qsts#:#msg_no_questions_selected#:#Keine Fragen ausgewählt. +qsts#:#no_best_response_available#:#Keine beste Antwort definiert +qsts#:#no_gaps#:#Der eingegebene Text enthält keine Lücken. +qsts#:#no_response#:#Keine Antwort +qsts#:#no_response_given#:#Keine Antwort +qsts#:#other_response#:#Nicht die Beste Antwort +qsts#:#other_response_given#:#Dies ist nicht die bestmögliche Antwort. +qsts#:#out_of_range#:#Ausserhalb des Bereichs +qsts#:#qst_lifecycle#:#Lebenszyklus +qsts#:#qst_lifecycle_draft#:#Entwurf +qsts#:#qst_lifecycle_filter_all#:#Alle Lebenszyklen +qsts#:#qst_lifecycle_final#:#Endgültig +qsts#:#qst_lifecycle_outdated#:#Veraltet +qsts#:#qst_lifecycle_rejected#:#Abgelehnt +qsts#:#qst_lifecycle_review#:#Überarbeitung notwendig +qsts#:#qst_lifecycle_sharable#:#Verteilbar +qsts#:#qst_remarks#:#Bemerkungen +qsts#:#question_create_mode#:#Art der Fragenerstellung +qsts#:#question_text#:#Fragentext +qsts#:#questionlist#:#Fragenliste +qsts#:#questions#:#Fragen +qsts#:#range_lower_limit#:#Untere Schranke +qsts#:#range_upper_limit#:#Obere Schranke +qsts#:#reset_preview#:#Vorschau zurücksetzen +qsts#:#save_and_new#:#Speichern und weitere Frage erstellen +qsts#:#score_all#:#Alle Antworten bewerten +qsts#:#score_distinct#:#Gleiche Antworten nur einmal bewerten +qsts#:#scoring_of_identical_responses#:#Bewertung gleicher Antworten +qsts#:#select_answer_form_type#:#Art des Antwortformulars auswählen +qsts#:#select_gap#:#Auswahl-Lücke +qsts#:#select_gaps_for_combination#:#Lücken zur Kombination auswählen +qsts#:#set_gap_types#:#Typen für die Lücken auswählen +qsts#:#shuffle_answers#:#Antworten mischen +qsts#:#specific_feedback#:#Rückmeldung basierend auf der gewählten Antwortoption +qsts#:#step_size#:#Präzision +qsts#:#suggested_learning_content#:#Inhalte zur Wiederholung +qsts#:#text_matching_method#:#Textvergleichsmethode +qsts#:#upload_answer_options#:#Antwort-Optionen hochladen +qsts#:#upload_answer_options_info#:#Es kann eine Text-Datei hochgeladen werden, die eine Liste von Antwort-Optionen enthält. Die Datei muss eine Liste von Antwort-Optionen enthalten, wobei jede Antwort-Option auf einer neuen Zeile stehen muss. Die Antwort-Optionen werden zur bereits bestehenden Liste hinzugefügt. +qsts#:#upper_limit_bigger_than_lower#:#Die obere Schranke muss sowohl grösser sein als die untere als auch als die Präzision. rating#:#rat_not_rated_yet#:#Noch nicht bewertet rating#:#rat_nr_ratings#:#%s Bewertungen rating#:#rat_one_rating#:#Eine Bewertung @@ -14396,15 +14475,15 @@ rbac#:#feed_delete#:#Webfeed löschen rbac#:#feed_edit_permission#:#Rechteeinstellungen ändern rbac#:#feed_read#:#Inhalt des Webfeeds lesen rbac#:#feed_write#:#Einstellungen des Webfeeds bearbeiten -rbac#:#file_content#:#Inhalt anzeigen rbac#:#file_copy#:#Datei kopieren rbac#:#file_delete#:#Datei verschieben oder löschen rbac#:#file_edit_file#:#Bearbeitung in einem externen Editor erlauben, sofern vorhanden rbac#:#file_edit_learning_progress#:#Lernfortschrittseinstellungen können bearbeitet werden. rbac#:#file_edit_permission#:#Rechteeinstellungen ändern +rbac#:#file_file_view_content#:#Inhalt der Datei wird im Browser angezeigt (wenn WOPI aktiv ist). +rbac#:#file_file_view_content_short#:#Inhalt anzeigen rbac#:#file_read#:#Datei herunterladen rbac#:#file_read_learning_progress#:#Lernfortschritt von anderen einsehen -rbac#:#file_view_content#:#Inhalt der Datei wird im Browser angezeigt (wenn WOPI aktiv ist). rbac#:#file_visible#:#Datei ist sichtbar. rbac#:#file_write#:#Einstellungen der Datei bearbeiten und neue Version hochladen rbac#:#files_visible#:#Dateien sichtbar @@ -14489,7 +14568,7 @@ rbac#:#iass_amend_grading#:#Finalisierte Bewertung der Individuellen Bewertung rbac#:#iass_copy#:#Individuelle Bewertung kopieren rbac#:#iass_delete#:#Individuelle Bewertung löschen rbac#:#iass_edit_learning_progress#:#Lernfortschritt in Individuellen Bewertung bearbeiten -rbac#:#iass_edit_members#:#Teilnehmer einer Individuellen Bewertung bearbeiten +rbac#:#iass_edit_members#:#Personen der Individuellen Bewertung hinzufügen und bewerten rbac#:#iass_edit_permission#:#Rechteeinstellungen ändern rbac#:#iass_read#:#Lesezugriff auf Individuelle Bewertung rbac#:#iass_read_learning_progress#:#Lernfortschritt in Individuellen Bewertung einsehen @@ -15635,7 +15714,7 @@ search#:#lucene_tbl_create_ini#:#Konfigurationsdatei für Java-Server erstellen search#:#search_add_members_from_container_crs#:#Benutzer aus aktuellem Kurs hinzufügen search#:#search_add_members_from_container_grp#:#Benutzer aus aktueller Gruppe hinzufügen search#:#search_any#:#-- Beliebig -- -search#:#search_area#:#Suchbereich +search#:#search_area_filter#:#Suchbereich search#:#search_area_info#:#Bitte wählen Sie einen Bereich aus, innerhalb dem die Suche starten soll. search#:#search_auto_complete_length#:#Anzahl der Einträge in Auto-Complete-Liste search#:#search_auto_complete_length_info#:#Wählen Sie „0“, um keine Auto-Complete-Liste anzubieten. @@ -15680,6 +15759,7 @@ search#:#search_minimum_info#:#Die Suchbegriffe müssen mindestens %s Zeichen la search#:#search_minimum_three#:#Die Suchbegriffe müssen mindestens 3 Zeichen lang sein. search#:#search_newer_than#:#Objekte erstellt vor dem... search#:#search_no_connection_lucene#:#Es kann keine Verbindung zum Lucene-Server hergestellt werden. +search#:#search_no_further_match#:#Ihre Suche ergab keine weiteren Treffer. search#:#search_no_match#:#Ihre Suche ergab keine Treffer. search#:#search_no_match_hint#:#Es wurden keine Treffer für Ihre Suchanfrage nach %s gefunden.
    Vorschläge:

    • Vergewissern Sie sich, dass alle Wörter richtig geschrieben sind.
    • Probieren Sie andere Suchbegriffe.
    • Probieren Sie allgemeinere Suchbegriffe.
    • Probieren Sie weniger Suchbegriffe. search#:#search_no_selection#:#Sie haben keine Auswahl getroffen. @@ -15702,6 +15782,8 @@ search#:#search_sort_generic_desc#:#%s, abst. search#:#search_sort_relevance#:#Nach Relevanz search#:#search_sort_title_asc#:#Alphabetisch: A-Z search#:#search_sort_title_desc#:#Alphabetisch: Z-A +search#:#search_tab_content#:#Inhalt +search#:#search_tab_user#:#Personen search#:#search_term_combination#:#Kombination search#:#search_title_description#:#Titel / Beschreibung search#:#search_tst_svy#:#Tests/Umfragen @@ -15762,8 +15844,8 @@ sess#:#sess_msg_applicants_assigned#:#Person wurde für den Sitzungstermin angem sess#:#sess_msg_applicants_removed#:#Antrag abgelehnt und aus der Liste entfernt. sess#:#sess_new#:#Neue Sitzung anlegen sess#:#sess_new_registrations#:#Teilnahmeanträge -sess#:#sess_notification_option#:#Option -sess#:#sess_notification_option_inherit#:#Vom übergeordneten Objekt erben +sess#:#sess_notification_option#:#Benachrichtigte Personen +sess#:#sess_notification_option_inherit#:#Wie in Kurs oder Gruppe sess#:#sess_notification_option_inherit_info#:#Es werden die gleichen Personen benachrichtigt wie im übergeordneten Objekt. sess#:#sess_notification_option_manual#:#Manuell setzen sess#:#sess_notification_option_manual_info#:#Es muss manuell festgelegt werden, wer die Benachrichtigung empfangen soll. @@ -16783,7 +16865,6 @@ survey#:#questionblock#:#Fragenblock survey#:#questionblock_inserted#:#Fragenblock eingefügt survey#:#questionblocks#:#Fragenblöcke survey#:#questionblocks_inserted#:#Fragenblöcke eingefügt -survey#:#questions#:#Fragen survey#:#questions_inserted#:#Frage(n) hinzugefügt. survey#:#questions_removed#:#Fragen und/oder Fragenblock entfernt! survey#:#questiontype#:#Fragetyp @@ -17084,6 +17165,7 @@ survey#:#svy_please_select_unused_codes#:#Bitte wählen Sie zumindest einen unge survey#:#svy_print_hide_labels#:#Labels ausblenden survey#:#svy_print_show_labels#:#Labels anzeigen survey#:#svy_privacy_info#:#Persönliche Daten +survey#:#svy_questions#:#Fragen survey#:#svy_rater#:#Feedback-Geber survey#:#svy_rater_see_app_info#:#Den Feedback-Gebern werden die Namen der Feedback-Nehmern angezeigt, damit die Fragen personenbezogen beantwortet werden können. survey#:#svy_reminder_mail_template#:#Mail-Vorlage @@ -17261,7 +17343,7 @@ tax#:#tax_add_taxonomy#:#Taxonomie hinzufügen tax#:#tax_added#:#Die Taxonomie wurde erstellt. tax#:#tax_admin_settings_repository#:#Magazin-Taxonomien tax#:#tax_alphabetical#:#Alphabetisch -tax#:#tax_assigned_items#:#Zugewiesene Einträge +tax#:#tax_assigned_items#:#Zugeordnete Fragen tax#:#tax_confirm_deletion#:#Wollen Sie wirklich die gesamte Taxonomie mit allen Beziehungen löschen? tax#:#tax_create_node#:#Knoten anlegen tax#:#tax_item_sorting#:#Sortierung der zugewiesenen Einträge unterstützen @@ -17275,9 +17357,9 @@ tax#:#tax_order#:#Reihenfolge tax#:#tax_order_nr#:#Ordnungsnummer tax#:#tax_please_select_target#:#Bitte wählen Sie ein Ziel aus! tax#:#tax_target_within_nodes#:#Das Ziel darf kein Unterknoten des ausgewählten Elements sein. -tax#:#tax_tax_assignment#:#Taxonomiezuordnung +tax#:#tax_tax_assignment#:#Zuordnung zu Taxonomien tax#:#tax_tax_deleted#:#Die Taxonomie wurde gelöscht. -tax#:#tax_tax_settings#:#Taxonomieeinstellungen +tax#:#tax_tax_settings#:#Taxonomien darstellen tax#:#tax_taxonomy#:#Taxonomie tbl#:#tbl_export_csv#:#.CSV-Export tbl#:#tbl_export_excel#:#Excel-Export @@ -17335,7 +17417,7 @@ trac#:#trac_assigned#:#Ausgewählt trac#:#trac_average#:#Durchschnitt trac#:#trac_begin_at#:#Startdatum trac#:#trac_closed_expire#:#Timeout -trac#:#trac_closed_login#:#Anonym zu Login +trac#:#trac_closed_login#:#Statusänderung - Anonym zu angemeldet trac#:#trac_closed_manual#:#Logout trac#:#trac_closed_misc#:#Sonstige trac#:#trac_collection_assign#:#Für Lernfortschritts-Bestimmung auswählen diff --git a/lang/ilias_el.lang b/lang/ilias_el.lang index 0983be59ab38..b5cc049cdc19 100644 --- a/lang/ilias_el.lang +++ b/lang/ilias_el.lang @@ -423,7 +423,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Ενεργοποίηση καταγραφής διαγωνίσματος & αξιολόγησης assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###30 04 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Προσθήκη κειμένου κενών @@ -448,7 +447,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Παίρνετε βαθμού assessment#:#answer_is_right#:#Η λύση σας είναι σωστή assessment#:#answer_is_wrong#:#Η λύση σας είναι λάθος assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Κείμενο απάντησης assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -502,7 +500,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -572,10 +569,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length assessment#:#cloze_fixed_textlength_description#:#Εαν εισάγετε τιμή μεγαλύτερη του 0, όλα τα κείμενα και οι αριθμητικές τιμές θα δημιουργηθούν μέ αυτόν ώς μέγιστο αριθμό επιτρεπόμενο χαρακτήρων assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Κείμενο με κενά -assessment#:#cloze_textgap_case_insensitive#:#Χωρίς ταίριασμα πεζών-κεφαλαίων -assessment#:#cloze_textgap_case_sensitive#:#Με ταίριασμα πεζών-κεφαλαίων -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein απόσταση του %s assessment#:#code#:#Κώδικας assessment#:#codebase#:#Κωδικοσελίδα assessment#:#concatenation#:#Συγχώνευση @@ -758,9 +751,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Κενό assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Όρος γλωσσαρίου assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -778,7 +769,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Εισαγωγή μετά assessment#:#insert_before#:#Εισαγωγή πριν -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Εσωτερικοί σύνδεσμοι assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -890,7 +880,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Συντήρηση assessment#:#manscoring#:#Χειροκίνητη Βαθμολόγηση assessment#:#manscoring_done#:#Scored Participants###30 04 2009 new variable @@ -917,7 +906,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Φθάσατε το μέγιστο α assessment#:#maximum_points#:#Μέγιστη δυνατή βαθμολογία assessment#:#maxsize#:#Maximum file upload size ###30 04 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###30 04 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Πρέπει να ορίσετε ένα ελάχιστο ποσοστό 0%! Το βαθμολογικό σχήμα δεν αποθηκεύθηκε. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -926,7 +914,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -985,7 +972,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###30 04 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###30 04 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output assessment#:#output_mode#:#Κατάσταση εξόδου assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1054,7 +1040,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Είστε σίγουροι ότι θέλετε να διαγράψετε τις ακόλουθες ερωτήσεις; Αν διαγράψετε κλειδωμένες ερωτήσεις τα αποτελέσματα των τεστ που περιέχουν μια κλειδωμένη ερώτηση θα διαγραφούν. assessment#:#qpl_copy_insert_clipboard#:#Οι επιλεγμένες ερωτήσεις αντιγράφηκαν στο πρόχειρο assessment#:#qpl_copy_select_none#:#Παρακαλώ επιλέξτε τουλάχιστο μια ερώτηση για αντιγραφή στο πρόχειρο assessment#:#qpl_delete_rbac_error#:#Δεν έχετε δικαίωμα να διαγράψετε την ερώτηση! @@ -1107,7 +1092,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Η ερώτηση που πρόκειται να επεξεργαστείτε βρίσκεται στα τεστ %s. Αν αλλάξετε την ερώτηση, δεν θ' αλλάξει μέσα στα τεστ, επειδή το σύστημα δημιουργεί αντίγραφα της ερώτησης όταν την εισάγετε σ' ένα τεστ! assessment#:#qpl_questions_deleted#:#Οι ερωτήσεις διαγράφηκαν. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1137,14 +1121,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1168,17 +1144,14 @@ assessment#:#question_title#:#Τίτλος ερώτησης assessment#:#question_type#:#Τύπος ερώτησης assessment#:#questionpool_not_entered#:#Παρακαλώ εισάγετε ένα όνομα για την πηγή ερωτήσεων! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#ερωτήσεις από assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Αποδοχή δείγματος assessment#:#random_another_sample#:#Λήψη άλλου δείγματος assessment#:#random_selection#:#Τυχαία επιλογή assessment#:#range#:#Εύρος -assessment#:#range_lower_limit#:#Κάτω όριο assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Άνω όριο assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1254,7 +1227,6 @@ assessment#:#search_roles#:#Αναζήτηση Ρόλων assessment#:#search_term#:#Αναζήτηση Όρου assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Επιλογή κενού assessment#:#select_max_one_item#:#Παρακαλώ επιλέξτε μόνο ένα αντικείμενο assessment#:#select_one_user#:#Παρακαλώ επιλέξτε τουλάχιστο ένα χρήστη assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1281,7 +1253,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Εμφάνιση γενικής εικόνας αποτελεσμάτων του Χρήστη assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Εμφάνιση απαντήσεων του Χρήστη -assessment#:#shuffle_answers#:#Ανακάτεμα απαντήσεων assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###30 04 2009 new variable @@ -4764,7 +4735,7 @@ common#:#msg_no_perm_paste#:#Δεν έχετε άδεια να επικολλή common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###30 04 2009 new variable common#:#msg_no_perm_perm#:#Δεν έχετε άδεια να επεξεργαστείτε τις ρυθμίσεις άδειας common#:#msg_no_perm_read#:#Δεν έχετε άδεια πρόσβασης σε αυτό το αντικείμενο. -common#:#msg_no_perm_read_item#:#Δεν έχετε δικαίωμα να προσπελάσετε το αντικείμενο '%s'. +common#:#msg_no_perm_read_item#:#Δεν έχετε δικαίωμα να προσπελάσετε το αντικείμενο. common#:#msg_no_perm_read_lm#:#Δεν έχετε άδεια να διαβάσετε αυτή την εκπαιδευτική μονάδα. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Δεν έχετε άδεια για να γράψετε @@ -13972,6 +13943,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Κείμενο με κενά +qsts#:#cloze_textgapcase_insensitive#:#Χωρίς ταίριασμα πεζών-κεφαλαίων +qsts#:#cloze_textgapcase_sensitive#:#Με ταίριασμα πεζών-κεφαλαίων +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein απόσταση του %s +qsts#:#confirm_delete_questions#:#Είστε σίγουροι ότι θέλετε να διαγράψετε τις ακόλουθες ερωτήσεις; Αν διαγράψετε κλειδωμένες ερωτήσεις τα αποτελέσματα των τεστ που περιέχουν μια κλειδωμένη ερώτηση θα διαγραφούν. +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Κενό +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Κάτω όριο +qsts#:#range_upper_limit#:#Άνω όριο +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Επιλογή κενού +qsts#:#shuffle_answers#:#Ανακάτεμα απαντήσεων +qsts#:#suggested_learning_content#:#Add suggested solution###30 04 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16621,7 +16621,6 @@ survey#:#questionblock#:#Μπλοκ ερώτησης survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Μπλοκ ερωτήσεων survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Ερωτήσεις survey#:#questions_inserted#:#Εισαχθείσες ερωτήσεις! survey#:#questions_removed#:#Οι ερωτήσεις και/η τα μπλοκ ερωτήσεων διαγράφηκαν! survey#:#questiontype#:#Τύπος ερώτησης @@ -16922,6 +16921,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Ερωτήσεις survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_en.lang b/lang/ilias_en.lang index 512dd28c41af..af564a65d48b 100644 --- a/lang/ilias_en.lang +++ b/lang/ilias_en.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE Editor for WYSIWYG Editing assessment#:#activate_logging#:#Activate Test and Assessment Logging assessment#:#activate_manual_scoring#:#Enable Scoring assessment#:#activate_manual_scoring_desc#:#Enables Scoring for all question types. -assessment#:#addSuggestedSolution#:#Add Content for Recapitulation assessment#:#add_answers#:#Add answers assessment#:#add_circle#:#Add circle area assessment#:#add_gap#:#Add Gap Text @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Your solution is correct assessment#:#answer_is_wrong#:#Your solution is wrong assessment#:#answer_of#:#Answer of -assessment#:#answer_options#:#Answer Options: assessment#:#answer_question#:#Answer Question assessment#:#answer_text#:#Answer Text assessment#:#answer_types#:#Editor for Answers @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions. assessment#:#ass_create_export_file_with_results#:#incl. Participant Results assessment#:#ass_create_export_test_archive#:#as Archive File -assessment#:#ass_create_question#:#Create Question assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read. assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length assessment#:#cloze_fixed_textlength_description#:#If you enter a value, all text gap fields, not providing an own maximum character limitation, as well as all numeric gap fields will be created with a fixed length of this value, so entering more than the allowed characters is not possible. Note, that for numeric gaps the decimal separator is counted as a regular character. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value, the gap text field will be created with the value of the global fixed length. -assessment#:#cloze_text#:#Cloze Text -assessment#:#cloze_textgap_case_insensitive#:#Case Insensitive -assessment#:#cloze_textgap_case_sensitive#:#Case Sensitive -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein Distance of %s assessment#:#code#:#Code assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Concatenation @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input. assessment#:#fq_precision_info#:#Enter the number of desired decimal places. assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button ‘Parse Question’ to create editing forms for variables and results. -assessment#:#gap#:#Gap assessment#:#gap_combination#:#Gap Combination -assessment#:#gaps#:#Gaps assessment#:#glossary_term#:#Glossary Term assessment#:#goto_first_question#:#Show First Question assessment#:#grading_mark_msg#:#Your grade is: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer text (UTF-8) file to upload. assessment#:#insert_after#:#Insert After assessment#:#insert_before#:#Insert Before -assessment#:#insert_gap#:#Insert Gap assessment#:#interaction_type#:#Interaction Type assessment#:#internal_links#:#Internal Links assessment#:#intprecision#:#Divisible By @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options. assessment#:#longmenu_text#:#Long Menu Text -assessment#:#mainbar_button_label_questionlist#:#Question List assessment#:#maintenance#:#Maintenance assessment#:#manscoring#:#Scoring assessment#:#manscoring_done#:#Scored Participants @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#You have already taken this test the assessment#:#maximum_points#:#Maximum Available Points assessment#:#maxsize#:#Maximum file upload size assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead. -assessment#:#min_auto_complete#:#Autocomplete assessment#:#min_ip_label#:#Lowest IP With Access assessment#:#min_percentage_ne_0#:#One of your grade categories needs to start at the ‘Minimum Score Required (in %)’ level of 0% Your grading system hasn’t been saved. assessment#:#misc#:#Misc Options @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One assessment#:#mode_question#:#Question oriented assessment#:#mode_user#:#Participant oriented assessment#:#msg_circle_added#:#Circle added -assessment#:#msg_no_questions_selected#:#No questions were selected. assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions. assessment#:#msg_poly_added#:#Polygon added assessment#:#msg_questions_moved#:#Question(s) moved @@ -984,7 +971,6 @@ assessment#:#order#:#Order assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence. assessment#:#ordertext#:#Ordering Text assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units. -assessment#:#out_of_range#:#Out of range assessment#:#output#:#Output assessment#:#output_mode#:#Output Mode assessment#:#parseQuestion#:#Parse Question @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add assessment#:#qpl_bulk_save_overwrite#:#Overwrite assessment#:#qpl_bulkedit_success#:#Modifications saved. assessment#:#qpl_cancel_skill_assigns_update#:#Cancel -assessment#:#qpl_confirm_delete_questions#:#Are you sure you want to remove the following questions? assessment#:#qpl_copy_insert_clipboard#:#Selected question(s) successfully copied to clipboard. assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard assessment#:#qpl_delete_rbac_error#:#You have no rights to remove this question! @@ -1106,14 +1091,13 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence assessment#:#qpl_question_is_in_use#:#The question you are about to edit exists in %s test(s). If you change this question, you will NOT change the question(s) in the test(s), because the system creates a copy of a question when it is inserted in a test! assessment#:#qpl_questions_deleted#:#Question(s) removed. -assessment#:#qpl_reset_preview#:#Reset Preview assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments assessment#:#qpl_settings_availability#:#Availability -assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Existing taxonomies in this pool are offered for question filtering. -assessment#:#qpl_settings_general_form_property_nav_taxonomy#:#Taxonomy Filter as Navigation Tree -assessment#:#qpl_settings_general_form_property_nav_taxonomy_description#:#When a taxonomy is selected, it well be presented as navigation tree instead of a table filter item. +assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Taxonomies can be used as filters in the ‘Questions’ tab. +assessment#:#qpl_settings_general_form_property_nav_taxonomy#:#Taxonomy as Tree View +assessment#:#qpl_settings_general_form_property_nav_taxonomy_description#:#The selected taxonomy is displayed in a tree view in the „Questions” tab. It will not appear in the filter anymore. assessment#:#qpl_settings_general_form_property_opt_notax_selected#:#Use No Navigation Tree Filter -assessment#:#qpl_settings_general_form_property_show_taxonomies#:#Show Taxonomies +assessment#:#qpl_settings_general_form_property_show_taxonomies#:#Taxonomies assessment#:#qpl_settings_subtab_general#:#General Settings assessment#:#qpl_settings_subtab_taxonomies#:#Taxonomies assessment#:#qpl_skill_point_eval_by_quest_result#:#Evaluation of Competence Points by Question Result @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters: assessment#:#qst_essay_wordcounter_enabled#:#Count Words assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field. assessment#:#qst_essay_written_words#:#Number of entered words: -assessment#:#qst_lifecycle#:#Lifecycle -assessment#:#qst_lifecycle_draft#:#Draft -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles -assessment#:#qst_lifecycle_final#:#Final -assessment#:#qst_lifecycle_outdated#:#Outdated -assessment#:#qst_lifecycle_rejected#:#Rejected -assessment#:#qst_lifecycle_review#:#To be Reviewed -assessment#:#qst_lifecycle_sharable#:#Shareable assessment#:#qst_nested_nested_answers_off#:#No indents, just order assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers assessment#:#qst_nr_of_tries#:#Number of Tries @@ -1168,17 +1144,14 @@ assessment#:#question_type#:#Question Type assessment#:#questionlist_cannot_be_altered#:#The questionlist cannot be altered as the test already contains participant data sets. assessment#:#questionpool_not_entered#:#Please enter a name for a question pool! assessment#:#questionpool_not_selected#:#Please select a question pool! -assessment#:#questions#:#Questions assessment#:#questions_from#:#questions from assessment#:#questions_per_page_view#:#Page View assessment#:#random_accept_sample#:#Accept Sample assessment#:#random_another_sample#:#Get another Sample assessment#:#random_selection#:#Random Selection assessment#:#range#:#Range -assessment#:#range_lower_limit#:#Lower Bound assessment#:#range_max#:#Range (Maximum) assessment#:#range_min#:#Range (Minimum) -assessment#:#range_upper_limit#:#Upper Bound assessment#:#rated_sign#:#Sign assessment#:#rated_unit#:#Unit assessment#:#rated_value#:#Value @@ -1254,7 +1227,6 @@ assessment#:#search_roles#:#Search Roles assessment#:#search_term#:#Search Term assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger. assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock. -assessment#:#select_gap#:#Select Gap assessment#:#select_max_one_item#:#Please select one item only assessment#:#select_one_user#:#Please select at least one user. assessment#:#select_question#:#Select a Question @@ -1281,7 +1253,6 @@ assessment#:#show_old_introduction#:#Show old introduction assessment#:#show_pass_overview#:#Show Marked Pass Overview assessment#:#show_results#:#Show Results assessment#:#show_user_answers#:#Show User’s Marked Answers -assessment#:#shuffle_answers#:#Shuffle Answers assessment#:#skip_question#:#Do not Answer and Next assessment#:#solution#:#Solution assessment#:#solutionText#:#Text @@ -1938,7 +1909,7 @@ assessment#:#tst_tab_results_objective_oriented#:#Test Results by Learning Objec assessment#:#tst_tab_results_pass_oriented#:#Test Results by Attempts assessment#:#tst_tbl_col_answered_questions#:#Answered Questions assessment#:#tst_tbl_col_final_mark#:#Mark -assessment#:#tst_tbl_col_finished_passes#:#Finished Passes +assessment#:#tst_tbl_col_finished_passes#:#Finished Attempts assessment#:#tst_tbl_col_finished_passes_num_of#:#%s of %s assessment#:#tst_tbl_col_last_scored_access#:#Last Scored Access assessment#:#tst_tbl_col_pass_finished#:#Pass Finished @@ -2506,7 +2477,7 @@ blog#:#blog_no_keywords#:#No keywords have been entered yet. blog#:#blog_notification_activated#:#Notifications Activated blog#:#blog_notification_deactivated#:#Notifications Deactivated blog#:#blog_notification_toggle_off#:#Deactivate Notifications -blog#:#blog_notification_toggle_on#:#Activate Notification +blog#:#blog_notification_toggle_on#:#Activate Notifications blog#:#blog_number_users_notes_or_comments#:#Number of users who have attached notes or comments to this post blog#:#blog_posting#:#Blog Post blog#:#blog_posting_deleted#:#Post successfully deleted. @@ -2653,6 +2624,7 @@ book#:#book_pool_added#:#Booking pool successfully created. book#:#book_pool_selection#:#Booking Pool Selection book#:#book_post_booking_file#:#File book#:#book_post_booking_information#:#Booking Information +book#:#book_post_booking_information_for#:#Booking Information for "%s" book#:#book_post_booking_text#:#Text book#:#book_post_booking_text_info#:#Use placeholders to include booking-specific information.
    [OBJECT] will be replaced by the respective Bookable Item.
    [PERIOD] will be replaced by the respective schedule. book#:#book_pref_book_cron#:#Booking with Preferences @@ -3480,7 +3452,7 @@ cntr#:#cntr_switch_to_new_editor_message#:#This is the supported standard editor cntr#:#cntr_switched_editor#:#Switched to new content. cntr#:#cntr_tax_none_available#:#There are no taxonomies available. cntr#:#cntr_tax_settings_info#:#Taxonomies in categories classify and filter the objects contained in the category. After adding taxonomies, classifications can be made via the "Metadata" tabs and the "Taxonomy Assignment" sub-tabs of the respective objects. Taxonomies can additionally be displayed in the side block of the category's "Contents" tab to enable direct filtering of the assigned objects. -cntr#:#cntr_taxonomy_definitions#:#Taxonomy Definition +cntr#:#cntr_taxonomy_definitions#:#Taxonomies cntr#:#cntr_taxonomy_show_sideblock#:#Present in Side Panel cntr#:#cntr_taxonomy_sideblock_settings#:#Presentation Settings cntr#:#cntr_text_media_editor#:#Edit Page @@ -3646,7 +3618,7 @@ common#:#auth_soap_namespace#:#Namespace common#:#auth_soap_namespace_desc#:#As defined in WSDL. Must be specified, if .NET SOAP style is used. common#:#auth_soap_port_desc#:#E.g. 8080 if the full SOAP server URI is http://auth.yourserver.com:8080/dir/server.php common#:#auth_soap_server_desc#:#E.g. auth.yourserver.com if the full SOAP server URI is http://auth.yourserver.com:8080/dir/server.php -common#:#auth_soap_settings_saved#:#SOAP authentication settings saved +common#:#auth_soap_settings_saved#:#SOAP authentication settings saved. common#:#auth_soap_uri_desc#:#Local URI, e.g. dir/server.php if the full SOAP server URI is http://auth.yourserver.com:8080/dir/server.php common#:#auth_soap_use_dotnet#:#Use .NET SOAP Style common#:#auth_soap_use_https#:#Use HTTPS @@ -3950,7 +3922,7 @@ common#:#default_skin_style#:#Default Skin / Style common#:#default_style#:#Default Style common#:#defaults#:#Defaults common#:#delete#:#Delete -common#:#delete_existing_file#:#Delete Existing File +common#:#delete_existing_file#:#Delete existing file common#:#delete_inactivated_user_accounts#:#Delete inactivated user accounts common#:#delete_inactivated_user_accounts_desc#:#If enabled, user accounts will be deleted %s days after their inactivation. common#:#delete_inactivated_user_accounts_include_roles#:#Considered roles @@ -4231,8 +4203,8 @@ common#:#forums_anonymized#:#Forum anonymized common#:#forums_anonymous#:#anonym common#:#forums_articles#:#Posts common#:#forums_closed#:#closed -common#:#forums_disable_forum_notification#:#Disable Notification for this Forum -common#:#forums_enable_forum_notification#:#Enable Notification for this Forum +common#:#forums_disable_forum_notification#:#Disable Notifications for This Forum +common#:#forums_enable_forum_notification#:#Enable Notifications for This Forum common#:#forums_forum_notification_enabled#:#You will be notified about new posts in this forum. common#:#forums_last_post#:#Latest Post common#:#forums_last_posting_asc#:#Last Post Ascending @@ -4822,7 +4794,7 @@ common#:#msg_no_perm_paste#:#You have no permission to paste the following objec common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s. common#:#msg_no_perm_perm#:#You have no permission to change permission settings. common#:#msg_no_perm_read#:#You have no permission to access this item. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s’. +common#:#msg_no_perm_read_item#:#You have no permission to access the object. common#:#msg_no_perm_read_lm#:#You have no permission to read this learning module. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user common#:#msg_no_perm_write#:#You have no permission to edit settings. @@ -5109,6 +5081,8 @@ common#:#obj_ps_desc#:#Configure global privacy and security settings here. common#:#obj_qpl#:#Question Pool for Tests common#:#obj_qpl_duplicate#:#Copy Question Pool for Tests common#:#obj_qpl_select#:#-- Please select one question pool for tests -- +common#:#obj_qsts#:#Questions +common#:#obj_qsts_desc#:#Global Settings For Questions common#:#obj_rcat#:#ECS Category common#:#obj_rcrs#:#ECS Course common#:#obj_recf#:#Restored Objects @@ -5161,7 +5135,7 @@ common#:#obj_tala_desc#:#Talk Templates common#:#obj_tals#:#Employee Talk Series common#:#obj_talt#:#Talk Template common#:#obj_task#:#Task -common#:#obj_tax#:#Taxonomy +common#:#obj_tax#:#Taxonomies within this object common#:#obj_taxf#:#Taxonomies common#:#obj_tool_setting_calendar#:#Calendar Block common#:#obj_tool_setting_calendar_active#:#Calendar @@ -5382,6 +5356,7 @@ common#:#preconditions_optional_hint#:#You have to fulfill %s of the foll common#:#predefined_template#:#Predefined role template common#:#preferences#:#Preferences common#:#presentation_table_more#:#Show More +common#:#presenter#:#Presenter common#:#preview#:#Preview common#:#preview_create#:#Create Preview common#:#preview_delete#:#Delete Preview @@ -5706,6 +5681,7 @@ common#:#show_content#:#Show Content common#:#show_details#:#Show Details common#:#show_filter#:#Show Filter common#:#show_hidden_sections#:#Show More Information » +common#:#show_less#:#Show less common#:#show_list#:#Show List common#:#show_members#:#Display Members common#:#show_more#:#Show More @@ -7722,7 +7698,7 @@ crs#:#crs_loc_settings_type_q_all_info#:#Mastery of all learning objectives is e crs#:#crs_loc_settings_type_q_selected#:#Separate Final Test for Each Objective crs#:#crs_loc_settings_type_q_selected_info#:#Participants are presented with a separate mastery test for each learning objective. crs#:#crs_loc_subtab_creation#:#Create -crs#:#crs_loc_suggested#:#Please work through the following learning materials. +crs#:#crs_loc_suggested#:#Please work through the listed materials and then take the final test to pass the learning objective. crs#:#crs_loc_tab_itest#:#Initial Test crs#:#crs_loc_tab_itests#:#Initial Tests crs#:#crs_loc_tab_materials#:#Material @@ -7902,7 +7878,7 @@ crs#:#crs_select_archive_language#:#Please select a language for the archive crs#:#crs_select_one_archive#:#Please select one archive crs#:#crs_select_starter#:#Select Start Object crs#:#crs_settings#:#Course Settings -crs#:#crs_settings_saved#:#Settings saved +crs#:#crs_settings_saved#:#Settings saved. crs#:#crs_shorten_breadcrumb#:#Breadcrumb crs#:#crs_show_all_obj#:#Expand All crs#:#crs_show_member_export#:#Participants List @@ -8085,7 +8061,7 @@ crs#:#event_title#:#Title crs#:#event_tutor_data#:#Presentation by crs#:#event_unregister#:#Unregister crs#:#event_unregistered#:#You have been unregistered. -crs#:#event_updated#:#Settings saved +crs#:#event_updated#:#Settings saved. crs#:#event_user_selection#:#Selection of Users crs#:#event_user_selection_include_filter#:#Include "%1$s" crs#:#event_user_selection_include_requests#:#Include all users on list "Join Requests" @@ -9862,7 +9838,7 @@ file#:#copyright_custom#:#Custom file#:#copyright_custom_info#:#Choose a custom copyright which will be applied to all unzipped files of this archive. file#:#copyright_inherited#:#Inherited file#:#copyright_inherited_info#:#Apply the copyright of the zip archive to its unzipped files.
    Copyright of zip archive: %s. -file#:#could_not_create_file_objs#:#An error occurred while creating your file objects. Please contact the administrators of this platform. +file#:#could_not_create_file_objs#:#An error occurred while creating your file objects. Please contact this installation's technical support. file#:#de_activate_icon#:#Activate / Deactivate file#:#download_ascii_filename#:#Allow Only ASCII Characters in Downloaded Filenames file#:#download_ascii_filename_info#:#Downloaded files should only have ASCII-characters in their filename. Deactivate to use all characters. @@ -10302,6 +10278,7 @@ glo#:#glo_really_remove_from_collection#:#Are you sure you want to remove the fo glo#:#glo_reference#:#Reference glo#:#glo_reference_terms#:#Reference Terms glo#:#glo_referenced_term#:#Referenced Term +glo#:#glo_remove_glossary#:##Are you sure you want to remove the following glossary from the list of auto-linked glossaries? glo#:#glo_removed_from_collection_info#:#The glossary has been removed from the collection glossary. glo#:#glo_reset_all_boxes#:#Reset All Boxes glo#:#glo_save_and_continue#:#Save and Continue @@ -10672,6 +10649,7 @@ iass#:#iass_file_dropzone#:#you can drop your files here iass#:#iass_file_required#:#Record file required iass#:#iass_file_required_info#:#A record file has to be uploaded to each participant record. iass#:#iass_file_visible_examinee#:#File visible for participant +iass#:#iass_file_visible_examinee_info#:#Once the individual assessment has been completed, the person assessed can view the record file. To do so, the ‘Make Result Available to Participant’ function must be enabled. iass#:#iass_filter_all#:#All iass#:#iass_filter_failed#:#Failed only iass#:#iass_filter_finalized#:#Completed only @@ -10692,7 +10670,7 @@ iass#:#iass_membership_finalized#:#Record finalised iass#:#iass_membership_saved#:#Record saved, not yet finalised iass#:#iass_mess_notification_completed#:#You passed the assessment %s. Please check the following grading record for details: iass#:#iass_mess_notification_failed#:#You failed the assessment %s. Please check the following grading record for details: -iass#:#iass_notify#:#Make Result available to Participant +iass#:#iass_notify#:#Make Result Available to Participant iass#:#iass_notify_explanation#:#The participant will be notified via e-mail after finalisation and will get access to her or his record on the Info screen. iass#:#iass_phone#:#Phone iass#:#iass_place#:#Place of assessment @@ -11121,29 +11099,22 @@ lng#:#lng_disable_language_detection#:#Disable Language Detection lng#:#lng_download_deprecated#:#Download Deprecated List lng#:#lng_enable_language_detection#:#Enable Language Detection lng#:#lng_switch_language_detection#:#Switch Language Detection -log#:#log_browser#:#Browser Console Log -log#:#log_browser_users#:#Usernames Using Console Log -log#:#log_cache_#:#Caching -log#:#log_cache_info#:#Only if a message reaches or surpasses the caching level, all messages which have at least the log level will be added to the log for the current request. -log#:#log_cache_level#:#Caching-Level log#:#log_component_btn_reset#:#Reset Settings log#:#log_component_col_component#:#Component log#:#log_component_col_level#:#Log-Level -log#:#log_component_root_desc#:#Leg-Level for message which are not assigned to any component. +log#:#log_component_unknown#:#Unknown (%s) log#:#log_components#:#Components -log#:#log_general_settings#:#Logging Settings log#:#log_level_alert#:#ALERT log#:#log_level_critical#:#CRITICAL log#:#log_level_debug#:#DEBUG +log#:#log_level_default#:#Default (%s) log#:#log_level_emergency#:#EMERGENCY log#:#log_level_error#:#ERROR log#:#log_level_info#:#INFO log#:#log_level_notice#:#NOTICE log#:#log_level_off#:#Disabled log#:#log_level_warning#:#WARNING -log#:#log_log_level#:#Log Level -log#:#log_memory#:#Log Memory Usage -logging#:#error_settings_saved#:#Settings saved +logging#:#error_settings_saved#:#Settings saved. logging#:#frm_clear_older_then#:#Deletes files older then logging#:#frm_clear_older_then_info#:#Please enter duration in days. logging#:#log_error_file_cleanup_info#:#Deletes old or orphand files of error log. @@ -11973,10 +11944,8 @@ mem#:#mem_settings_tab_settings#:#General Settings mem#:#mmbr_gallery_user_actions#:#Member Gallery Actions membership#:#mem_error_preconditions#:#A registration is not possible, since minimum one setting prevents this. membership#:#mem_force_notification#:#Notification per Mail -membership#:#mem_force_notification_mode_all#:#Notification activated for all members (changeable) membership#:#mem_force_notification_mode_all_sub_blocked#:#Members can deactivate notifications membership#:#mem_force_notification_mode_blocked#:#Members will be notified automatically -membership#:#mem_force_notification_mode_custom#:#Custom membership#:#mem_force_notification_mode_self#:#Members have to manually activate notification mep#:#mep_all#:#All mep#:#mep_all_mobs#:#All Media Objects @@ -14103,6 +14072,114 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback qpl#:#qpl_page_type_qfbs#:#Special Feedback qpl#:#qpl_page_type_qht#:#Hint qpl#:#qpl_page_type_qpl#:#Question Page +qsts#:#above_range#:#Above Range +qsts#:#add_gap_combination#:#Add Combination of Gaps +qsts#:#answer_form#:#Answer Form +qsts#:#answer_options#:#Answer Options +qsts#:#answer_options_awarding_points#:#Answer Options Awarding Points +qsts#:#answer_options_must_be_unique#:#All answer options must be unique. +qsts#:#async_view#:#Asynchronous View +qsts#:#at_least_one_gap_positiv_points#:#At least one gap needs to award points. +qsts#:#available_points#:#Available Points +qsts#:#awarded_points#:#Awarded Points +qsts#:#basic_answer_form_properties#:#Basic Answer Form Properties +qsts#:#below_range#:#Below Range +qsts#:#best_response#:#Best Response +qsts#:#best_response_given#:#You have provided the best possible response. +qsts#:#between#:#Between %s and %s +qsts#:#broken_answer_form#:#Broken Answer Form +qsts#:#byline_create_mode_full#:#The page editor is used. The question text can contain rich content and multiple answer forms. +qsts#:#byline_create_mode_simple#:#Only a simple text input is shown to enter the question text. The question text cannot be formatted and only one answer form can be created. At the end of the creation process a button is shown to directly create an additional question after saving. +qsts#:#cloze#:#Cloze +qsts#:#cloze_enable_gap_combinations#:#Lückenkombinationen aktivieren +qsts#:#cloze_text#:#Cloze Text +qsts#:#cloze_textgap_case_insensitive#:#Case Insensitive +qsts#:#cloze_textgap_case_sensitive#:#Case Sensitive +qsts#:#cloze_textgap_levenshtein_of#:#Levenshtein Distance of %s +qsts#:#combination_needs_more_than_one#:#A combination of gaps needs to contain more than one gap. +qsts#:#confirm_delete_feedback#:#Do you really want to delete this feedback. +qsts#:#confirm_delete_questions#:#Are you sure you want to remove the following questions? +qsts#:#confirm_remove_gaps#:#You have removed gaps from the cloze text. Do you really want to delete them and all associated information? +qsts#:#cont_ed_insert_answf#:#Insert Answer Form +qsts#:#contained_answer_form_types#:#Contained Answer Form Types +qsts#:#contains_answer_form_types#:#Contains Answer Form Types +qsts#:#create_answer_form#:#Create Answer Form +qsts#:#create_feedback#:#Create Feedback +qsts#:#create_mode_full#:#Full +qsts#:#create_mode_simple#:#Simple +qsts#:#create_question#:#Create Question +qsts#:#default_user_settings#:#Default Settings +qsts#:#default_view#:#Default View +qsts#:#delete_combination#:#Delete Combination of Gaps +qsts#:#delete_responses#:#Delete Responses +qsts#:#disable_marking_allowing_partial_points#:#Disable Marking +qsts#:#disable_suggested_learning_content#:#Disable Suggested Learning Content +qsts#:#disable_text_feedback#:#Disable Feedback +qsts#:#edit_answer_options#:#Edit Answer Options +qsts#:#edit_available_points#:#Edit Available Points +qsts#:#edit_basic_answer_form_properties#:#Edit Basic Answer Form Properties +qsts#:#edit_basic_question_properties#:#Edit Basic Question Properties +qsts#:#edit_feedback#:#Edit Feedback +qsts#:#edit_gaps#:#Edit Gaps +qsts#:#edit_generic_feedback#:#Feedback Based On Reached Points +qsts#:#edit_points#:#Edit Points +qsts#:#edit_suggested_learning_content#:#Edit Suggested Learning Content +qsts#:#enable_marking_allowing_partial_points#:#Enable Marking +qsts#:#enable_suggested_learning_content#:#Enable Suggested Learning Content +qsts#:#enable_text_feedback#:#Enable Feedback +qsts#:#equal#:#Equal to %s +qsts#:#gap#:#Gap +qsts#:#gap_combination_already_exists#:#This combination of gaps already exists. +qsts#:#gap_combinations#:#Combinations of Gaps +qsts#:#gap_type#:#Type of Gap +qsts#:#gaps#:#Gaps +qsts#:#insert_gap#:#Insert Gap +qsts#:#insert_legacy_texts#:#Import Legacy Texts +qsts#:#insert_legacy_texts_info#:#Some texts have been migrated from a previous version. They cannot be edited directed, but you can import them into the form. All formatting will be lost. +qsts#:#legacy_text_cannot_be_edited#:#This text was migrated from the previous question implementation and cannot be edited. +qsts#:#long_menu_gap#:#Longmenu +qsts#:#max_characters#:#Character Limit +qsts#:#min_auto_complete#:#Autocomplete +qsts#:#msg_no_questions_selected#:#No questions were selected. +qsts#:#no_best_response_available#:#The Best Response is not Defined +qsts#:#no_gaps#:#The provided text does not contain any gaps. +qsts#:#no_response#:#No Response +qsts#:#no_response_given#:#No Response Given +qsts#:#other_response#:#Not the Best Response +qsts#:#other_response_given#:#There are better responses. +qsts#:#out_of_range#:#Out of range +qsts#:#qst_lifecycle#:#Lifecycle +qsts#:#qst_lifecycle_draft#:#Draft +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles +qsts#:#qst_lifecycle_final#:#Final +qsts#:#qst_lifecycle_outdated#:#Outdated +qsts#:#qst_lifecycle_rejected#:#Rejected +qsts#:#qst_lifecycle_review#:#To be Reviewed +qsts#:#qst_lifecycle_sharable#:#Shareable +qsts#:#qst_remarks#:#Remarks +qsts#:#question_create_mode#:#Question Create Mode +qsts#:#question_text#:#Question Text +qsts#:#questionlist#:#Question List +qsts#:#questions#:#Questions +qsts#:#range_lower_limit#:#Lower Bound +qsts#:#range_upper_limit#:#Upper Bound +qsts#:#reset_preview#:#Reset Preview +qsts#:#save_and_new#:#Save and New +qsts#:#score_all#:#All Responses are Scored +qsts#:#score_distinct#:#Identical Responses are Only Scored Once +qsts#:#scoring_of_identical_responses#:#Scoring of Identical Responses +qsts#:#select_answer_form_type#:#Select Type of Answer Form +qsts#:#select_gap#:#Select Gap +qsts#:#select_gaps_for_combination#:#Select Gap for Combination +qsts#:#set_gap_types#:#Set Types for Gaps +qsts#:#shuffle_answers#:#Shuffle Answers +qsts#:#specific_feedback#:#Feedback Based On Answer Options +qsts#:#step_size#:#Step Size +qsts#:#suggested_learning_content#:#Suggested Content +qsts#:#text_matching_method#:#Text Matching Method +qsts#:#upload_answer_options#:#Upload Answer Options +qsts#:#upload_answer_options_info#:#You can upload a file containing a list of answer options that will be added to the list. Each answer option needs to be on a new line. +qsts#:#upper_limit_bigger_than_lower#:#The upper bound must be bigger than the lower bound and the step size. rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -14367,15 +14444,15 @@ rbac#:#feed_delete#:#User can move or delete web feed rbac#:#feed_edit_permission#:#User can change permission settings rbac#:#feed_read#:#User can read content of web feed rbac#:#feed_write#:#User can edit web feed settings -rbac#:#file_content#:#Show Content rbac#:#file_copy#:#User can copy file rbac#:#file_delete#:#User can move or delete file rbac#:#file_edit_file#:#Allow to edit the file in an external editor, if available rbac#:#file_edit_learning_progress#:#User can edit learning progress settings rbac#:#file_edit_permission#:#User can change permission settings +rbac#:#file_file_view_content#:#File content presented in browser (if WOPI is active) +rbac#:#file_file_view_content_short#:#Show Content rbac#:#file_read#:#User can download file rbac#:#file_read_learning_progress#:#User can view learning progress of other users -rbac#:#file_view_content#:#File content presented in browser (if WOPI is active) rbac#:#file_visible#:#File is visible rbac#:#file_write#:#User can edit file settings and upload new version of file rbac#:#files_visible#:#Files Visible @@ -15209,11 +15286,11 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export rep#:#rep_export_limitation_unlimited#:#Unlimited Export rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead. -rep#:#rep_fav_intro1#:#You have not yet selected any favourites. To do this, you must take two steps: -rep#:#rep_fav_intro2#:#Click on '%s' and select a learning object from the available offer, e.g. a learning module or a forum. -rep#:#rep_fav_intro3#:#When you have found something that interests you, you can easily add it to your favourites. Select the desired item in the Actions menu and choose "Add to favourites". +rep#:#rep_fav_intro1#:#You have not yet selected any favourites. To do so, there are two steps you need to take: +rep#:#rep_fav_intro2#:#Click on '%s' and select a learning object from those available, for example a learning module or a forum. +rep#:#rep_fav_intro3#:#When you have found something that interests you, you can easily add it to your favourites. Select the desired item in the Actions menu and select "Add to favourites". rep#:#rep_favourites#:#Favourites -rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings. +rep#:#rep_favourites_info#:#Users can mark individual repository items as favourites. A 'Favourites' list can be activated for the dashboard and the main menu. rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value. rep#:#rep_intro#:#Welcome to the Repository! rep#:#rep_intro1#:#In this area you can create learning and working resources for all users. All resources are organised in categories. Categories can reflect the structure of your organisation (e.g. departments), a hierarchy of disciplines, or classes of a school. @@ -15606,7 +15683,7 @@ search#:#lucene_tbl_create_ini#:#Create Java-Server Ini-File search#:#search_add_members_from_container_crs#:#Add Users From Current Course search#:#search_add_members_from_container_grp#:#Add Users From Current Group search#:#search_any#:#-- Any -- -search#:#search_area#:#Search Area +search#:#search_area_filter#:#Scope search#:#search_area_info#:#Please select an area where the search should start. search#:#search_auto_complete_length#:#Number of Auto-Complete List Entries search#:#search_auto_complete_length_info#:#Choose ‘0‘ to switch off the auto-complete list. @@ -15651,6 +15728,7 @@ search#:#search_minimum_info#:#Your search must be at least %s characters long search#:#search_minimum_three#:#Your search must be at least three characters long. search#:#search_newer_than#:#Objects newer than search#:#search_no_connection_lucene#:#Cannot connect to Lucene server. +search#:#search_no_further_match#:#No further matches found. search#:#search_no_match#:#Your search did not match any results. search#:#search_no_match_hint#:#Your search for %s did not match any documents.

    Suggestions:
    • Make sure all words are spelled correctly.
    • Try different keywords.
    • Try more general keywords.
    • Try fewer keywords. search#:#search_no_selection#:#You made no selection. @@ -15673,6 +15751,8 @@ search#:#search_sort_generic_desc#:#%s, desc. search#:#search_sort_relevance#:#By Relevance search#:#search_sort_title_asc#:#Alphabetically: A-Z search#:#search_sort_title_desc#:#Alphabetically: Z-A +search#:#search_tab_content#:#Content +search#:#search_tab_user#:#Users search#:#search_term_combination#:#Combination search#:#search_title_description#:#Title / Description search#:#search_tst_svy#:#Tests/Surveys @@ -16752,7 +16832,6 @@ survey#:#questionblock#:#Question Block survey#:#questionblock_inserted#:#Question block inserted. survey#:#questionblocks#:#Question Blocks survey#:#questionblocks_inserted#:#Question blocks inserted. -survey#:#questions#:#Questions survey#:#questions_inserted#:#Question(s) added. survey#:#questions_removed#:#Question and/or question block removal successful. survey#:#questiontype#:#Question Type @@ -17035,6 +17114,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels survey#:#svy_print_show_labels#:#Show labels survey#:#svy_privacy_info#:#Privacy +survey#:#svy_questions#:#Questions survey#:#svy_rater#:#Rater survey#:#svy_rater_see_app_info#:#Raters are shown the names of their appraisees so that they can meaningfully respond to the questions concerning those individuals. survey#:#svy_reminder_mail_template#:#Mail Template @@ -17210,7 +17290,7 @@ tax#:#tax_add_taxonomy#:#Add Taxonomy tax#:#tax_added#:#Taxonomy has been created. tax#:#tax_admin_settings_repository#:#Repository Taxonomies tax#:#tax_alphabetical#:#Alphabetical -tax#:#tax_assigned_items#:#Assigned Items +tax#:#tax_assigned_items#:#Assigned Questions tax#:#tax_confirm_deletion#:#Do you really want to delete the whole taxonomy and all its relations? tax#:#tax_create_node#:#Create Node tax#:#tax_item_sorting#:#Support Sorting of Assigned Items @@ -17224,9 +17304,9 @@ tax#:#tax_order#:#Order tax#:#tax_order_nr#:#Order Nr tax#:#tax_please_select_target#:#Please select the target. tax#:#tax_target_within_nodes#:#The target must not be a sub-node of the selected items. -tax#:#tax_tax_assignment#:#Taxonomy Assignment +tax#:#tax_tax_assignment#:#Assignment to Taxonomies tax#:#tax_tax_deleted#:#The taxonomy has been deleted. -tax#:#tax_tax_settings#:#Taxonomy Settings +tax#:#tax_tax_settings#:#Display Taxonomies tax#:#tax_taxonomy#:#Taxonomy tbl#:#tbl_export_csv#:#Export CSV tbl#:#tbl_export_excel#:#Export Excel @@ -17284,7 +17364,7 @@ trac#:#trac_assigned#:#Assigned trac#:#trac_average#:#Average trac#:#trac_begin_at#:#Start date trac#:#trac_closed_expire#:#Timeout -trac#:#trac_closed_login#:#Anonymous To Login +trac#:#trac_closed_login#:#Change of status - anonymous to logged-in trac#:#trac_closed_manual#:#Logout trac#:#trac_closed_misc#:#Misc. trac#:#trac_collection_assign#:#Select for Learning Progress Determination @@ -17472,10 +17552,10 @@ trac#:#trac_session_statistics_mode_today#:#Today trac#:#trac_session_statistics_mode_week#:#Week trac#:#trac_session_statistics_mode_year#:#Year trac#:#trac_session_statistics_no_data#:#No data for this statistics could be found. -trac#:#trac_sessions_closed#:#Leavings -trac#:#trac_sessions_opened#:#Admissions +trac#:#trac_sessions_closed#:#Exits +trac#:#trac_sessions_opened#:#Entrances trac#:#trac_settings#:#Settings -trac#:#trac_settings_saved#:#Settings saved +trac#:#trac_settings_saved#:#Settings saved. trac#:#trac_short_system_load#:#Short term trac#:#trac_show_graph#:#Show Graph trac#:#trac_show_progress_block#:#Show Personal Progress Chart in ‘Content’-Tab @@ -17498,7 +17578,7 @@ trac#:#trac_title#:#Title trac#:#trac_title_description#:#Title / Description trac#:#trac_total_online#:#Total Time Online trac#:#trac_trash#:#Moved to Trash -trac#:#trac_update_edit_user#:#Settings saved +trac#:#trac_update_edit_user#:#Settings saved. trac#:#trac_updated_status#:#Saved learning progress status. trac#:#trac_user_data#:#User Data trac#:#trac_valid_request#:#Max. Time Between Requests diff --git a/lang/ilias_es.lang b/lang/ilias_es.lang index 52c4dd49cd9a..03f606066d03 100644 --- a/lang/ilias_es.lang +++ b/lang/ilias_es.lang @@ -425,7 +425,6 @@ adve#:#adve_use_tiny_mce#:#Activar el editor TinyMCE para edición WYSIWYG assessment#:#activate_logging#:#Activar el registro de pruebas y evaluaciones assessment#:#activate_manual_scoring#:#Activar puntuación manual assessment#:#activate_manual_scoring_desc#:#Habilita la puntuación manual para todos los tipos de preguntas. -assessment#:#addSuggestedSolution#:#Agregar contenido para recapitulación assessment#:#add_answers#:#Agregar respuestas assessment#:#add_circle#:#Agregar área circular assessment#:#add_gap#:#Agregar texto de hueco @@ -450,7 +449,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Has obtenido puntos por tu sol assessment#:#answer_is_right#:#Tu solución es correcta assessment#:#answer_is_wrong#:#Tu solución es incorrecta assessment#:#answer_of#:#Respuesta de -assessment#:#answer_options#:#Opciones de respuesta: assessment#:#answer_question#:#Responder pregunta assessment#:#answer_text#:#Texto de la respuesta assessment#:#answer_types#:#Editor de respuestas @@ -504,7 +502,6 @@ assessment#:#ass_completion_by_submission#:#Completado por envío assessment#:#ass_completion_by_submission_info#:#Si está habilitado, la entrega de al menos un archivo provoca la finalización de esta pregunta otorgando la puntuación máxima para esta pregunta. La puntuación puede modificarse manualmente más tarde. Cambiar esta configuración no afecta a las soluciones ya enviadas. assessment#:#ass_create_export_file_with_results#:#incl. Resultados de participantes assessment#:#ass_create_export_test_archive#:#como archivo comprimido -assessment#:#ass_create_question#:#Crear pregunta assessment#:#ass_imap_hint#:#Sugerencia que se mostrará como información sobre herramientas assessment#:#ass_imap_map_file_not_readable#:#No se pudo leer el mapa de imagen subido. assessment#:#ass_imap_no_map_found#:#No se pudo encontrar ningún formulario en el mapa de imagen subido. @@ -574,10 +571,6 @@ assessment#:#cloze_answer_text_info#:#Los espacios que precedan o sigan al texto assessment#:#cloze_fixed_textlength#:#Longitud del campo de texto assessment#:#cloze_fixed_textlength_description#:#Si introduce un valor, todos los campos de hueco de texto que no proporcionen una limitación propia de caracteres, así como todos los campos de hueco numéricos, se crearán con una longitud fija de este valor, por lo que no será posible introducir más caracteres de los permitidos. Tenga en cuenta que para los huecos numéricos el separador decimal se cuenta como un carácter normal. assessment#:#cloze_gap_size_info#:#Si introduce un valor mayor que 0, este campo de texto del hueco se creará con la longitud fija de ese valor. Si no introduce un valor, el campo de texto del hueco se creará con el valor de la longitud fija global. -assessment#:#cloze_text#:#Texto Cloze -assessment#:#cloze_textgap_case_insensitive#:#Sin distinción de mayúsculas/minúsculas -assessment#:#cloze_textgap_case_sensitive#:#Con distinción de mayúsculas/minúsculas -assessment#:#cloze_textgap_levenshtein_of#:#Distancia de Levenshtein de %s assessment#:#code#:#Código assessment#:#codebase#:#Base de código assessment#:#concatenation#:#Concatenación @@ -761,9 +754,7 @@ assessment#:#fq_formula_desc#:#Puede introducir variables predefinidas ($v1 a $v assessment#:#fq_no_restriction_info#:#Se aceptan tanto decimales como fracciones. assessment#:#fq_precision_info#:#Introduzca el número de decimales deseados. assessment#:#fq_question_desc#:#Puede definir variables insertando $v1, $v2 ... $vn, resultados insertando $r1, $r2 ... $rn en la posición deseada del texto de la pregunta. Haga clic en el botón ‘Analizar pregunta’ para crear formularios de edición para variables y resultados. -assessment#:#gap#:#Hueco assessment#:#gap_combination#:#Combinación de huecos -assessment#:#gaps#:#Huecos assessment#:#glossary_term#:#Término del glosario assessment#:#goto_first_question#:#Mostrar la primera pregunta assessment#:#grading_mark_msg#:#Su calificación es: "[mark]" @@ -781,7 +772,6 @@ assessment#:#info_answer_type_change#:#La pregunta ya contiene imágenes. No pue assessment#:#info_text_upload#:#Seleccione un archivo de texto de respuesta (UTF-8) para subir. assessment#:#insert_after#:#Insertar después assessment#:#insert_before#:#Insertar antes -assessment#:#insert_gap#:#Insertar hueco assessment#:#interaction_type#:#Tipo de interacción assessment#:#internal_links#:#Enlaces internos assessment#:#intprecision#:#Divisible por @@ -893,7 +883,6 @@ assessment#:#logs_wrong_test_password_provided#:#El participante introdujo una c assessment#:#longmenu#:#Menú largo assessment#:#longmenu_answeroptions_differ#:#Esta pregunta no funciona correctamente, ya que no hay la misma cantidad de huecos en el texto que en las opciones de corrección. assessment#:#longmenu_text#:#Texto del menú largo -assessment#:#mainbar_button_label_questionlist#:#Lista de preguntas assessment#:#maintenance#:#Mantenimiento assessment#:#manscoring#:#Calificación manual assessment#:#manscoring_done#:#Participantes calificados @@ -920,7 +909,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Ha alcanzado el número máximo de in assessment#:#maximum_points#:#Puntos máximos disponibles assessment#:#maxsize#:#Tamaño máximo de archivo subido assessment#:#maxsize_info#:#Introduzca el tamaño máximo en bytes que se permitirá para las cargas de archivos. Si deja este campo vacío, se elegirá en su lugar el tamaño máximo de esta instalación. -assessment#:#min_auto_complete#:#Autocompletar assessment#:#min_ip_label#:#IP más baja con acceso assessment#:#min_percentage_ne_0#:#Una de sus categorías de calificación debe comenzar en el nivel ‘Puntuación mínima requerida (en %)’ de 0%. Su sistema de calificaciones no se ha guardado. assessment#:#misc#:#Opciones varias @@ -929,7 +917,6 @@ assessment#:#mode_onebyone#:#One by One assessment#:#mode_question#:#Question oriented assessment#:#mode_user#:#Participant oriented assessment#:#msg_circle_added#:#Círculo añadido -assessment#:#msg_no_questions_selected#:#No se seleccionaron preguntas. assessment#:#msg_number_of_terms_too_low#:#El número de términos debe ser mayor o igual que el número de definiciones. assessment#:#msg_poly_added#:#Polígono añadido assessment#:#msg_questions_moved#:#Pregunta(s) movida(s) @@ -988,7 +975,6 @@ assessment#:#order#:#Orden assessment#:#ordering_answer_sequence_info#:#La secuencia de respuestas que defina aquí se considerará la secuencia de solución correcta. assessment#:#ordertext#:#Texto para ordenar assessment#:#ordertext_info#:#Por favor, introduzca el texto que debe ordenarse horizontalmente. El texto para ordenar será separado por los espacios en blanco del texto. Si necesita una separación diferente, puede usar el separador %s para separar sus unidades de texto. -assessment#:#out_of_range#:#Fuera de rango assessment#:#output#:#Salida assessment#:#output_mode#:#Modo de salida assessment#:#parseQuestion#:#Analizar pregunta @@ -1057,7 +1043,6 @@ assessment#:#qpl_bulk_save_add#:#Agregar assessment#:#qpl_bulk_save_overwrite#:#Sobrescribir assessment#:#qpl_bulkedit_success#:#Modificaciones guardadas. assessment#:#qpl_cancel_skill_assigns_update#:#Cancelar -assessment#:#qpl_confirm_delete_questions#:#¿Está seguro de que desea eliminar las siguientes preguntas? assessment#:#qpl_copy_insert_clipboard#:#La(s) pregunta(s) seleccionada(s) se han copiado al portapapeles assessment#:#qpl_copy_select_none#:#Por favor seleccione al menos una pregunta para copiarla al portapapeles assessment#:#qpl_delete_rbac_error#:#¡No tiene permisos para eliminar esta pregunta! @@ -1110,7 +1095,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competencia assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Suma total de puntos de competencia por competencia assessment#:#qpl_question_is_in_use#:#La pregunta que está a punto de editar existe en %s prueba(s). Si cambia esta pregunta, NO cambiará la(s) pregunta(s) en la(s) prueba(s), ¡porque el sistema crea una copia de una pregunta cuando se inserta en una prueba! assessment#:#qpl_questions_deleted#:#Pregunta(s) eliminada(s). -assessment#:#qpl_reset_preview#:#Restablecer vista previa assessment#:#qpl_save_skill_assigns_update#:#Guardar asignaciones de competencias assessment#:#qpl_settings_availability#:#Disponibilidad assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Las taxonomías existentes en este banco de preguntas se ofrecen para filtrar preguntas. @@ -1140,14 +1124,6 @@ assessment#:#qst_essay_chars_remaining#:#Caracteres restantes: assessment#:#qst_essay_wordcounter_enabled#:#Contar palabras assessment#:#qst_essay_wordcounter_enabled_info#:#Se cuentan las palabras introducidas. El número de palabras escritas se muestra a los participantes debajo del campo de entrada de texto. assessment#:#qst_essay_written_words#:#Número de palabras introducidas: -assessment#:#qst_lifecycle#:#Ciclo de vida -assessment#:#qst_lifecycle_draft#:#Borrador -assessment#:#qst_lifecycle_filter_all#:#Todos los ciclos de vida -assessment#:#qst_lifecycle_final#:#Final -assessment#:#qst_lifecycle_outdated#:#Obsoleto -assessment#:#qst_lifecycle_rejected#:#Rechazado -assessment#:#qst_lifecycle_review#:#Por revisar -assessment#:#qst_lifecycle_sharable#:#Compartible assessment#:#qst_nested_nested_answers_off#:#Sin sangrías, solo orden assessment#:#qst_nested_nested_answers_on#:#Usar sangrías en las respuestas assessment#:#qst_nr_of_tries#:#Número de intentos @@ -1172,17 +1148,14 @@ assessment#:#question_type#:#Tipo de pregunta assessment#:#questionlist_cannot_be_altered#:#La lista de preguntas no puede modificarse porque la prueba ya contiene conjuntos de datos de participantes. assessment#:#questionpool_not_entered#:#¡Por favor ingrese un nombre para el banco de preguntas! assessment#:#questionpool_not_selected#:#¡Por favor seleccione un banco de preguntas! -assessment#:#questions#:#Preguntas assessment#:#questions_from#:#preguntas de assessment#:#questions_per_page_view#:#Vista de página assessment#:#random_accept_sample#:#Aceptar muestra assessment#:#random_another_sample#:#Obtener otra muestra assessment#:#random_selection#:#Selección aleatoria assessment#:#range#:#Rango -assessment#:#range_lower_limit#:#Límite inferior assessment#:#range_max#:#Rango (máximo) assessment#:#range_min#:#Rango (mínimo) -assessment#:#range_upper_limit#:#Límite superior assessment#:#rated_sign#:#Signo assessment#:#rated_unit#:#Unidad assessment#:#rated_value#:#Valor @@ -1258,7 +1231,6 @@ assessment#:#search_roles#:#Buscar Roles assessment#:#search_term#:#Término de búsqueda assessment#:#select_at_least_one_feedback_type_and_trigger#:#Por favor, seleccione al menos un tipo de feedback y un desencadenador. assessment#:#select_at_least_one_lock_answer_type#:#Por favor, seleccione al menos un tipo de bloqueo de respuesta. -assessment#:#select_gap#:#Seleccionar hueco assessment#:#select_max_one_item#:#Por favor, seleccione solo un elemento assessment#:#select_one_user#:#Por favor, seleccione al menos un usuario. assessment#:#select_question#:#Seleccionar una pregunta @@ -1285,7 +1257,6 @@ assessment#:#show_old_introduction#:#Mostrar introducción antigua assessment#:#show_pass_overview#:#Mostrar resumen de pases marcados assessment#:#show_results#:#Mostrar resultados assessment#:#show_user_answers#:#Mostrar respuestas marcadas del usuario -assessment#:#shuffle_answers#:#Barajar respuestas assessment#:#skip_question#:#No responder y pasar a la siguiente assessment#:#solution#:#Solución assessment#:#solutionText#:#Texto @@ -1484,12 +1455,12 @@ assessment#:#tst_exam_modal_message_conditions#:#Por favor, confirme las condici assessment#:#tst_exam_modal_message_conditions_and_password#:#Por favor, confirme las condiciones e introduzca la contraseña para iniciar la prueba. assessment#:#tst_exam_modal_message_password#:#Por favor, introduzca la contraseña para iniciar la prueba. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#No puede iniciar esta prueba, ya que no está asignado como participante. -assessment#:#tst_exam_password#:#Contraseña del examen +assessment#:#tst_exam_password#:#Contraseña de la prueba assessment#:#tst_exam_password_invalid_message#:#¡La contraseña proporcionada no es válida! assessment#:#tst_exam_password_label#:#Contraseña assessment#:#tst_exam_required_fields_not_filled_message#:#¡Debe completar todos los campos obligatorios! assessment#:#tst_exam_start#:#Iniciar prueba -assessment#:#tst_exam_use_previous_answers#:#Respuestas anteriores +assessment#:#tst_exam_use_previous_answers#:#Usar respuestas anteriores assessment#:#tst_exam_use_previous_answers_label#:#Si está habilitado, las respuestas de pruebas anteriores se rellenarán automáticamente. assessment#:#tst_extratime_added#:#El tiempo de trabajo del participante se ha incrementado en %s minutos. assessment#:#tst_extratime_info#:#Si desea añadir tiempo de trabajo varias veces para el mismo participante, por favor ingrese la cantidad total de tiempo que desea añadir. @@ -1509,7 +1480,13 @@ assessment#:#tst_final_information#:#Finalizar la prueba assessment#:#tst_finish_confirm_button#:#Sí, quiero finalizar la prueba assessment#:#tst_finish_confirm_cancel_button#:#No, volver a la pregunta anterior assessment#:#tst_finish_confirmation_question#:#Va a finalizar esta prueba. No podrá volver a acceder a este intento de prueba para cambiar sus respuestas. ¿Realmente desea finalizar la prueba? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Va a finalizar esta prueba y alcanzará el número máximo de intentos permitidos. No podrá volver a entrar en esta prueba para cambiar sus respuestas. ¿Realmente desea finalizar la prueba? +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Va a finalizar esta prueba y alcanzará el número máximo de intentos permitidos. No podrá volver a acceder a esta prueba para cambiar sus respuestas. ¿Realmente desea finalizarla? +assessment#:#tst_finish_notification#:#Notificación +assessment#:#tst_finish_notification_advanced#:#Enviar resultado completo de la prueba +assessment#:#tst_finish_notification_content_type#:#Contenido del correo electrónico +assessment#:#tst_finish_notification_desc#:#Envía un correo electrónico al propietario de la prueba por cada usuario que haya completado la prueba. +assessment#:#tst_finish_notification_no#:#Sin correo electrónico +assessment#:#tst_finish_notification_simple#:#Enviar nombre de usuario y fecha de finalización assessment#:#tst_finished#:#Finalizado assessment#:#tst_form_dynamic_question_set_config#:#Continuar selección de preguntas assessment#:#tst_gap_analysis#:#Análisis de brechas @@ -1594,9 +1571,9 @@ assessment#:#tst_introduction_text#:#Mensaje introductorio assessment#:#tst_invited_nobody#:#No se han añadido usuarios, grupos ni roles como participantes fijos del test assessment#:#tst_invited_selected_users#:#Los usuarios seleccionados se han añadido como participantes fijos del test assessment#:#tst_launcher_button_label_passes_limit_reached#:#Has alcanzado el límite de intentos posibles del test -assessment#:#tst_launcher_status_message_conditions#:#Se te pedirá que aceptes las condiciones del examen cuando inicies el test. -assessment#:#tst_launcher_status_message_conditions_and_password#:#Se te pedirá la contraseña y que aceptes las condiciones del examen cuando inicies el test. -assessment#:#tst_launcher_status_message_password#:#Se te pedirá la contraseña cuando inicies el test. +assessment#:#tst_launcher_status_message_conditions#:#Se le pedirá que acepte las condiciones del examen cuando inicie la prueba. +assessment#:#tst_launcher_status_message_conditions_and_password#:#Se le pedirá la contraseña y que acepte las condiciones del examen cuando inicie la prueba. +assessment#:#tst_launcher_status_message_password#:#Se le pedirá la contraseña cuando inicie la prueba. assessment#:#tst_level#:#Nivel de competencia assessment#:#tst_limit_nr_of_tries#:#Limitar el número de intentos del test assessment#:#tst_link_only_unassigned#:#Has seleccionado al menos una pregunta que ya está vinculada a un banco de preguntas. Solo se pueden añadir preguntas no asignadas a un banco de preguntas. @@ -4774,7 +4751,7 @@ common#:#msg_no_perm_paste#:#No tiene permiso para pegar los siguientes objeto(s common#:#msg_no_perm_paste_object_in_folder#:#No tiene permiso para pegar el objeto %s en la carpeta %s. common#:#msg_no_perm_perm#:#No tiene permiso para cambiar los ajustes de permisos. common#:#msg_no_perm_read#:#No tiene permiso para acceder a este elemento. -common#:#msg_no_perm_read_item#:#No tiene permiso para acceder al elemento '%s'. +common#:#msg_no_perm_read_item#:#No tiene permiso para acceder al elemento. common#:#msg_no_perm_read_lm#:#No tiene permiso para leer este módulo de aprendizaje. common#:#msg_no_perm_view_roles_of_user#:#No tiene permiso para ver la asignación de roles de este usuario common#:#msg_no_perm_write#:#No tiene permiso para editar los ajustes. @@ -5805,15 +5782,15 @@ common#:#trash#:#Papelera common#:#tree#:#Árbol common#:#tree_frame#:#Marco del árbol common#:#treeview#:#Mostrar barra lateral -common#:#tst#:#Test -common#:#tst_add#:#Añadir test +common#:#tst#:#Prueba +common#:#tst_add#:#Añadir prueba common#:#tst_edit_questions#:#Editar preguntas common#:#tst_history_read#:#Ver historial -common#:#tst_new#:#Nuevo test -common#:#tst_results#:#Resultados del examen +common#:#tst_new#:#Nueva prueba +common#:#tst_results#:#Resultados de la prueba common#:#tst_run#:#Ejecución -common#:#tst_user_not_invited#:#No está autorizado para realizar este examen. -common#:#tst_warning_test_not_complete#:#¡El examen no está completo! +common#:#tst_user_not_invited#:#No está autorizado para realizar esta prueba. +common#:#tst_warning_test_not_complete#:#¡La prueba no está completa! common#:#tutors#:#Tutores common#:#txt_registered#:#Se ha registrado correctamente en ILIAS. Por favor, haga clic en el botón de abajo para iniciar sesión con su cuenta de usuario. common#:#txt_registered_passw_gen#:#Se ha registrado correctamente en ILIAS. En breve recibirá un correo electrónico con su contraseña generada. @@ -14036,6 +14013,35 @@ qpl#:#qpl_page_type_qfbg#:#Feedback general qpl#:#qpl_page_type_qfbs#:#Feedback especial qpl#:#qpl_page_type_qht#:#Sugerencia qpl#:#qpl_page_type_qpl#:#Página de pregunta +qsts#:#answer_options#:#Opciones de respuesta +qsts#:#cloze_text#:#Texto Cloze +qsts#:#cloze_textgapcase_insensitive#:#Sin distinción de mayúsculas/minúsculas +qsts#:#cloze_textgapcase_sensitive#:#Con distinción de mayúsculas/minúsculas +qsts#:#cloze_textgaplevenshtein_of#:#Distancia de Levenshtein de %s +qsts#:#confirm_delete_questions#:#¿Está seguro de que desea eliminar las siguientes preguntas? +qsts#:#create_question#:#Crear pregunta +qsts#:#gap#:#Hueco +qsts#:#gaps#:#Huecos +qsts#:#insert_gap#:#Insertar hueco +qsts#:#min_auto_complete#:#Autocompletar +qsts#:#msg_no_questions_selected#:#No se seleccionaron preguntas. +qsts#:#out_of_range#:#Fuera de rango +qsts#:#qst_lifecycle#:#Ciclo de vida +qsts#:#qst_lifecycle_draft#:#Borrador +qsts#:#qst_lifecycle_filter_all#:#Todos los ciclos de vida +qsts#:#qst_lifecycle_final#:#Final +qsts#:#qst_lifecycle_outdated#:#Obsoleto +qsts#:#qst_lifecycle_rejected#:#Rechazado +qsts#:#qst_lifecycle_review#:#Por revisar +qsts#:#qst_lifecycle_sharable#:#Compartible +qsts#:#questionlist#:#Lista de preguntas +qsts#:#questions#:#Preguntas +qsts#:#range_lower_limit#:#Límite inferior +qsts#:#range_upper_limit#:#Límite superior +qsts#:#reset_preview#:#Restablecer vista previa +qsts#:#select_gap#:#Seleccionar hueco +qsts#:#shuffle_answers#:#Barajar respuestas +qsts#:#suggested_learning_content#:#Agregar contenido para recapitulación rating#:#rat_not_rated_yet#:#Aún sin calificar rating#:#rat_nr_ratings#:#%s Calificaciones rating#:#rat_one_rating#:#Una calificación @@ -15146,8 +15152,8 @@ rep#:#rep_export_limitation_limited#:#Limitar exportación rep#:#rep_export_limitation_unlimited#:#Exportación ilimitada rep#:#rep_failure_trashed_trash#:#Ha seleccionado objetos que no pueden restaurarse a su ubicación original porque sus objetos superiores fueron eliminados. Por favor, desmarque el objeto correspondiente en la tabla o seleccione Restaurar en una ubicación nueva en su lugar. rep#:#rep_fav_intro1#:#Aún no ha seleccionado ningún favorito. Para ello, debe seguir dos pasos: -rep#:#rep_fav_intro2#:#Haga clic en '%s' y seleccione un objeto de aprendizaje de la oferta disponible, por ejemplo, un módulo de aprendizaje o un foro. -rep#:#rep_fav_intro3#:#Cuando haya encontrado algo que le interese, puede añadirlo fácilmente a sus favoritos. Seleccione el elemento deseado en el menú Acciones y elija "Añadir a favoritos". +rep#:#rep_fav_intro2#:#Haga clic en '%s' y seleccione un objeto de aprendizaje entre las opciones disponibles, por ejemplo, un módulo de aprendizaje o un foro. +rep#:#rep_fav_intro3#:#Cuando encuentre algo que le interese, puede añadirlo fácilmente a sus favoritos. En el menú Acciones del elemento deseado, seleccione «Añadir a favoritos». rep#:#rep_favourites#:#Favoritos rep#:#rep_favourites_info#:#Los usuarios pueden marcar elementos individuales del repositorio como favoritos. Las listas de favoritos se pueden activar y configurar en los ajustes del tablero y del menú. rep#:#rep_input_not_empty#:#Este campo no puede estar vacío, por favor proporcione un valor. @@ -16691,7 +16697,6 @@ survey#:#questionblock#:#Bloque de preguntas survey#:#questionblock_inserted#:#Bloque de preguntas insertado. survey#:#questionblocks#:#Bloques de preguntas survey#:#questionblocks_inserted#:#Bloques de preguntas insertados. -survey#:#questions#:#Preguntas survey#:#questions_inserted#:#Pregunta(s) añadida(s). survey#:#questions_removed#:#La eliminación de preguntas y/o bloques de preguntas se ha realizado con éxito. survey#:#questiontype#:#Tipo de pregunta @@ -16992,6 +16997,7 @@ survey#:#svy_please_select_unused_codes#:#Por favor, seleccione al menos un cód survey#:#svy_print_hide_labels#:#Ocultar etiquetas survey#:#svy_print_show_labels#:#Mostrar etiquetas survey#:#svy_privacy_info#:#Privacidad +survey#:#svy_questions#:#Preguntas survey#:#svy_rater#:#Evaluador survey#:#svy_rater_see_app_info#:#A los evaluadores se les muestran los nombres de sus evaluados para que puedan responder de forma significativa a las preguntas relativas a esas personas. survey#:#svy_reminder_mail_template#:#Plantilla de correo diff --git a/lang/ilias_et.lang b/lang/ilias_et.lang index c7ab92d89998..321fec20c4c7 100644 --- a/lang/ilias_et.lang +++ b/lang/ilias_et.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Võimalda TinyMCE WYSIWYG toimetamiseks assessment#:#activate_logging#:#aktiveeri testi ja hindamise logimine assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Lisa soovituslik lahendus assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Lisa ringiala assessment#:#add_gap#:#Lisa lünka tekst @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Said vastuse eest punkti(d), k assessment#:#answer_is_right#:#Lahendus on õige assessment#:#answer_is_wrong#:#Lahendus on vale assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Vastustekst assessment#:#answer_types#:#Vastusetüübid @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Tööd saadetud assessment#:#ass_completion_by_submission_info#:#Võimaldamise korral loetakse antud küsimus vastatuks vähemalt ühe faili esitamisel ja selle eest saab maksimaalse punktisumma. Punktisummat saab hiljem käsitsi muuta. Antud seade vahetamine ei muuda olemasolevaid ehk juba ära saadetud vastuseid. assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File -assessment#:#ass_create_question#:#Create Question assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Tekstivälja pikkus assessment#:#cloze_fixed_textlength_description#:#Kui sisestad nullist suurema väärtuse, luuakse kõik teksti- ja numbriväljad selles väärtuses fikseeritud pikkuses. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length. -assessment#:#cloze_text#:#Lünktekst -assessment#:#cloze_textgap_case_insensitive#:#Mittetundlik variant -assessment#:#cloze_textgap_case_sensitive#:#Tundlik variant -assessment#:#cloze_textgap_levenshtein_of#:#Levenšteini kaugus of %s assessment#:#code#:#Kood assessment#:#codebase#:#Koodibaas assessment#:#concatenation#:#Jätkamine @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input. assessment#:#fq_precision_info#:#Enter the number of desired decimal places. assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results. -assessment#:#gap#:#Lünk assessment#:#gap_combination#:#Gap Combination -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Sõnastiku mõiste assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Küsimus juba sisaldab pilte. Te ei saa m assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Sisesta pärast assessment#:#insert_before#:#Sisesta enne -assessment#:#insert_gap#:#Insert Gap assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Sisemised lingid assessment#:#intprecision#:#Divisible By @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Säilitamine assessment#:#manscoring#:#Käsitsi punktihaldus assessment#:#manscoring_done#:#Hinnatud osalejad @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Lubatud soorituste arv on täis. Test assessment#:#maximum_points#:#Maksimaalsed võimalikud punktid assessment#:#maxsize#:#Üleslaetava faili maksimaalne suurus assessment#:#maxsize_info#:#Sisesta üleslaetavate failide lubatud maksimumsuurus baitides. Kui jätad selle välja tühjaks, valib see installatsioon lubatud maksimumsuruse ise. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Sa pead määrama miinimumtasemeks 0 protsenti! Hindeskeemi ei salvestatud. assessment#:#misc#:#Misc Options @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Ringiala lisatud -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Mõistete arv peab olema võrdne (või suurem) definitsioonide arvuga. assessment#:#msg_poly_added#:#Hulknurk lisatud assessment#:#msg_questions_moved#:#Küsimus(ed) on ümber tõstetud @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Vastuste järjestust siin arvestatakse kui õige vastuse järjestust. assessment#:#ordertext#:#Teksti järjestamine assessment#:#ordertext_info#:#Palun sisesta tekst, mis peaks olema järjestatud horisontaalselt. Järjestatav tekst eraldatakse tekstis olevate valgete tühikutega. Kui vajad muud eraldajat, võid kasutada eraldajat %s oma tekstiosade eraldamiseks. -assessment#:#out_of_range#:#Out of range assessment#:#output#:#Väljund assessment#:#output_mode#:#Väljundi olek assessment#:#parseQuestion#:#Parse Question @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Kas oled kindel, et soovid järgmise(d) küsimuse(d) kustutada? Kui sa kustutad lukustatud küsimused, kustutatakse ka kõiki lukustatud küsimusi sisaldavad testitulemused. assessment#:#qpl_copy_insert_clipboard#:#Valitud küsimus(ed) on puhvrisse salvestatud. assessment#:#qpl_copy_select_none#:#Palun märgista puhvrisse kopeerimiseks vähemalt üks küsimus assessment#:#qpl_delete_rbac_error#:#Sul ei ole piisavalt õigusi selle küsimuse kustutamiseks! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Küsimus, mida muuta soovid, on käigus juba %s testis. Kui muudad seda küsimust, ei muuda sa seda küsimust testi(de)s, sest süsteem loob testidesse sisestamiseks küsimusest koopia! assessment#:#qpl_questions_deleted#:#Küsimus(ed) on kustutatud. -assessment#:#qpl_reset_preview#:#Reset Preview assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Katsetuste arv @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Küsimuse pealkiri assessment#:#question_type#:#Küsimuse liik assessment#:#questionpool_not_entered#:#Palun sisesta küsimustevaramu nimi! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#küsimust assessment#:#questions_per_page_view#:#Lehe vaade assessment#:#random_accept_sample#:#Kinnita küsimused assessment#:#random_another_sample#:#Küsi uusi küsimusi assessment#:#random_selection#:#Juhuvalik assessment#:#range#:#Vahemik -assessment#:#range_lower_limit#:#Alumine piir assessment#:#range_max#:#Range (Maximum) assessment#:#range_min#:#Range (Minimum) -assessment#:#range_upper_limit#:#Ülemine piir assessment#:#rated_sign#:#Sign assessment#:#rated_unit#:#Unit assessment#:#rated_value#:#Value @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Otsi rolle assessment#:#search_term#:#Otsingusõna assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Vali lünk assessment#:#select_max_one_item#:#Palun vali ainult üks element. assessment#:#select_one_user#:#Palun vali vähemalt üks kasutaja. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Näita märgistatud soorituse ülevaadet assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Näita kasutaja märgitud vastuseid -assessment#:#shuffle_answers#:#Sega vastuseid assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Tekst @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#You have no permission to paste the following objec common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s. common#:#msg_no_perm_perm#:#You have no permission to edit permission settings common#:#msg_no_perm_read#:#Sul ei ole piisavalt õigusi sellesse üksusesse sisenemiseks. -common#:#msg_no_perm_read_item#:#Puuduvad juurdepääsuõigused '%s'. +common#:#msg_no_perm_read_item#:#Puuduvad juurdepääsuõigused. common#:#msg_no_perm_read_lm#:#Puuduvad õigused vaadata seda õppemoodulit! common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Sul puudub õigus kirjutada @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Lünktekst +qsts#:#cloze_textgapcase_insensitive#:#Mittetundlik variant +qsts#:#cloze_textgapcase_sensitive#:#Tundlik variant +qsts#:#cloze_textgaplevenshtein_of#:#Levenšteini kaugus of %s +qsts#:#confirm_delete_questions#:#Kas oled kindel, et soovid järgmise(d) küsimuse(d) kustutada? Kui sa kustutad lukustatud küsimused, kustutatakse ka kõiki lukustatud küsimusi sisaldavad testitulemused. +qsts#:#create_question#:#Create Question +qsts#:#gap#:#Lünk +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Alumine piir +qsts#:#range_upper_limit#:#Ülemine piir +qsts#:#reset_preview#:#Reset Preview +qsts#:#select_gap#:#Vali lünk +qsts#:#shuffle_answers#:#Sega vastuseid +qsts#:#suggested_learning_content#:#Lisa soovituslik lahendus rating#:#rat_not_rated_yet#:#Pole veel hääletatud rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#Üks hääletus @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Küsimusteplokk survey#:#questionblock_inserted#:#Küsimusteplokk on sisestatud survey#:#questionblocks#:#Küsimusteplokid survey#:#questionblocks_inserted#:#Küsimusteplokid on sisestatud -survey#:#questions#:#Küsimused survey#:#questions_inserted#:#Küsimus(ed) on sisestatud! survey#:#questions_removed#:#Küsimus(ed) ja/või küsimusteplok(id) on eemaldatud! survey#:#questiontype#:#Küsimuse tüüp @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Küsimused survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_fa.lang b/lang/ilias_fa.lang index 6dd4ffa6a623..c30f399ae428 100644 --- a/lang/ilias_fa.lang +++ b/lang/ilias_fa.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#فعال کردن ثبت وقایع تست و ارزیابی assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#اضافه کردن راه حل پیشنهادی assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area assessment#:#add_gap#:#Add Gap Text @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Your solution is correct assessment#:#answer_is_wrong#:#Your solution is wrong assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#متن جواب assessment#:#answer_types#:#انواع جواب @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#کامل شده با ارسال assessment#:#ass_completion_by_submission_info#:#اگر فعال شود، ارسال حداقل یک فایل باعث کامل شدن سوال شده و نمره دهی هم انجام می شود. assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#طول فیلد متن assessment#:#cloze_fixed_textlength_description#:#اگر مقداری بیشتر از 0 وارد کنید، همه فیلدهای متن با این اندازه ساخته خواهند شد. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#متن -assessment#:#cloze_textgap_case_insensitive#:#غیر حساس به کوچک و بزرگی حروف -assessment#:#cloze_textgap_case_sensitive#:#حساس به کوچک و بزرگی حروف -assessment#:#cloze_textgap_levenshtein_of#:#فاصله Levenshtein %s assessment#:#code#:#کد assessment#:#codebase#:#پایگاه کد assessment#:#concatenation#:#Concatenation @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Gap assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#اصطلاح لغتنامه assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Insert After assessment#:#insert_before#:#Insert Before -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Internal Links assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#نگهداری assessment#:#manscoring#:#امتیازدهی دستی assessment#:#manscoring_done#:#شرکت کنندگان دارای نمره @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#You have reached the maximum number o assessment#:#maximum_points#:#حداکثر امتیازات موجود assessment#:#maxsize#:#حداکثر اندازه فایل برای آپلود assessment#:#maxsize_info#:#مقدار به بایت -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#You must define a minimum percentage of 0 percent! The mark schema wasn't saved. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions. assessment#:#msg_poly_added#:#Polygon added assessment#:#msg_questions_moved#:#Question(s) moved @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#دنباله جوابی که اینجا مشخص می کنید به عنوان دنباله جواب در نظر گرفته خواهد شد. assessment#:#ordertext#:#متن مرتب سازی assessment#:#ordertext_info#:#لطفا متنی را که باید بصورت افقی مرتب شود را وارد کنید. متنها با فاصله از هم جدا می شوند. می توانید از %s هم برای جدا کردن واحدهای متن استفاده کنید. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output assessment#:#output_mode#:#حالت خروجی assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Are you sure you want to delete the following question(s)? assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard assessment#:#qpl_delete_rbac_error#:#You have no rights to delete this question! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#The question you are about to edit exists in %s test(s). If you change this question, you will NOT change the question(s) in the test(s), because the system creates a copy of a question when it is inserted in a test! assessment#:#qpl_questions_deleted#:#Question(s) deleted. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#عنوان سوال assessment#:#question_type#:#نوع سوال assessment#:#questionpool_not_entered#:#Please enter a name for a question pool! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#questions from assessment#:#questions_per_page_view#:#نمای صفحه assessment#:#random_accept_sample#:#Accept Sample assessment#:#random_another_sample#:#Get another Sample assessment#:#random_selection#:#Random Selection assessment#:#range#:#محدوده -assessment#:#range_lower_limit#:#حد پایین assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#حد بالا assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Search Roles assessment#:#search_term#:#Search Term assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Select Gap assessment#:#select_max_one_item#:#Please select one item only assessment#:#select_one_user#:#لطفا حداقل یک کاربر انتخاب کنید. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#نمایش مرور کلی دوره انتخاب شده assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#نمایش پاسخهای کاربر انتخاب شده -assessment#:#shuffle_answers#:#قاطی کردن جوابها assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#متن @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#You have no permission to paste the following objec common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s. common#:#msg_no_perm_perm#:#You have no permission to edit permission settings common#:#msg_no_perm_read#:#You have no permission to access this item. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'. +common#:#msg_no_perm_read_item#:#You have no permission to access item. common#:#msg_no_perm_read_lm#:#You have no permission to read this learning module. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#You have no permission to write @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#متن +qsts#:#cloze_textgapcase_insensitive#:#غیر حساس به کوچک و بزرگی حروف +qsts#:#cloze_textgapcase_sensitive#:#حساس به کوچک و بزرگی حروف +qsts#:#cloze_textgaplevenshtein_of#:#فاصله Levenshtein %s +qsts#:#confirm_delete_questions#:#Are you sure you want to delete the following question(s)? +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Gap +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#حد پایین +qsts#:#range_upper_limit#:#حد بالا +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Select Gap +qsts#:#shuffle_answers#:#قاطی کردن جوابها +qsts#:#suggested_learning_content#:#اضافه کردن راه حل پیشنهادی rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -16621,7 +16621,6 @@ survey#:#questionblock#:#Question Block survey#:#questionblock_inserted#:#Question Block inserted survey#:#questionblocks#:#بلوکهای سوال survey#:#questionblocks_inserted#:#Question Blocks inserted -survey#:#questions#:#سوالها survey#:#questions_inserted#:#Question(s) inserted! survey#:#questions_removed#:#Question(s) and/or question block(s) removed! survey#:#questiontype#:#Question Type @@ -16922,6 +16921,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#سوالها survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_fr.lang b/lang/ilias_fr.lang index 2ebad3a3957f..1f81e868191c 100644 --- a/lang/ilias_fr.lang +++ b/lang/ilias_fr.lang @@ -407,7 +407,6 @@ adve#:#adve_use_tiny_mce#:#Activez TinyMCE pour une Edition WYSIWYG assessment#:#activate_logging#:#Activer le Suivi des Tests et Evaluations assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Ajouter solution suggérée assessment#:#add_answers#:#Add Antworten assessment#:#add_circle#:#Ajouter Zone Circulaire assessment#:#add_gap#:#Ajouter une nouvelle valeur @@ -432,7 +431,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Vous obtenez des points pour v assessment#:#answer_is_right#:#Votre réponse est correcte assessment#:#answer_is_wrong#:#Votre réponse est incorrecte assessment#:#answer_of#:#Answer of -assessment#:#answer_options#:#Options de réponse: assessment#:#answer_question#:#Répondez à la question assessment#:#answer_text#:#Texte de Réponse assessment#:#answer_types#:#Types de réponse @@ -486,7 +484,6 @@ assessment#:#ass_completion_by_submission#:#Validation Automatique assessment#:#ass_completion_by_submission_info#:#Le dépôt d'un fichier permet de valider cette question en attribuant le score maximum. Le score peut toutefois être modifié ultérieurement. Modifier cette option n'affecte pas les réponses déjà fournies. assessment#:#ass_create_export_file_with_results#:#Créer un fichier d’exportation de tests (y compris les résultats des participants) assessment#:#ass_create_export_test_archive#:#Créer Archive du Test -assessment#:#ass_create_question#:#Créer Question assessment#:#ass_imap_hint#:#Indice à montrer comme info-bulle assessment#:#ass_imap_map_file_not_readable#:#L’image de carte chargée n’a pas pu être lue. assessment#:#ass_imap_no_map_found#:#N’a pas pu trouver de forme dans la carte d’image chargée. @@ -556,10 +553,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Longueur du Champ Texte assessment#:#cloze_fixed_textlength_description#:#Si une valeur supérieure à zéro est saisie , tous les champs de texte seront créés avec cette valeur comme longueur de champ. assessment#:#cloze_gap_size_info#:#Si vous entrez une valeur supérieure à 0, ce champ de texte d'écart sera créé avec la longueur fixe de cette valeur. Si vous n'entrez pas de valeur, le champ de texte d'écart sera créé avec la valeur de la longueur fixe globale. -assessment#:#cloze_text#:#Texte à trous -assessment#:#cloze_textgap_case_insensitive#:#Ne pas distinguer majuscules et minuscules -assessment#:#cloze_textgap_case_sensitive#:#Distinguer majuscules et minuscules -assessment#:#cloze_textgap_levenshtein_of#:#Distance Levenshtein de %s assessment#:#code#:#Code assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Concaténation @@ -742,9 +735,7 @@ assessment#:#fq_formula_desc#:#Vous pouvez entrer des variables prédéfinies ($ assessment#:#fq_no_restriction_info#:#Les décimales et les fractions sont des entrées acceptées. assessment#:#fq_precision_info#:#Entrez le nombre de décimales souhaitées. assessment#:#fq_question_desc#:#Vous pouvez définir des variables en insérant $v1, $v2 ... $vn, des résultats en insérant $r1, $r2 .... $rn aux positions souhaitées dans le texte de la question. Cliquer sur le bouton "Traiter la Question" pour créer le formulaire d'édition des variables et réponses. -assessment#:#gap#:#Trou assessment#:#gap_combination#:#Association de Gap -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Terme de glossaire assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Votre résultat est: "[mark]" @@ -762,7 +753,6 @@ assessment#:#info_answer_type_change#:#La question contient déjà des images. assessment#:#info_text_upload#:#Choisissez un fichier de réponses à télécharger assessment#:#insert_after#:#Ajouter après assessment#:#insert_before#:#Ajouter avant -assessment#:#insert_gap#:#Insérer Ecart assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Liens internes assessment#:#intprecision#:#Divisible Par @@ -874,7 +864,6 @@ assessment#:#logs_wrong_test_password_provided#:#Le Participant a entré un mot assessment#:#longmenu#:#Longmenu assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options. assessment#:#longmenu_text#:#Texte de menu long -assessment#:#mainbar_button_label_questionlist#:#Questionlist###31 10 2023 new variable assessment#:#maintenance#:#Maintenance assessment#:#manscoring#:#Notation Manuelle assessment#:#manscoring_done#:#Participants notés @@ -901,7 +890,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Vous avez atteint le nombre de tentat assessment#:#maximum_points#:#Nombre Maximum de Points assessment#:#maxsize#:#Taille maximale du fichier à télécharger assessment#:#maxsize_info#:#Saisir la taille maximale en bytes autorisée pour le téléversement. Si cette zone de saisie reste vide, le maximum par défaut sera proposé. -assessment#:#min_auto_complete#:#Saisie automatique assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Vous devez définir un pourcentage minimal de 0 %. L'échelle d'évaluation n'a pas été enregistrée. assessment#:#misc#:#Options Mixtes @@ -910,7 +898,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Cercle ajouté -assessment#:#msg_no_questions_selected#:#No questions were selected.###31 10 2023 new variable assessment#:#msg_number_of_terms_too_low#:#Le nombre de termes doit être supérieur ou équal au nombre de définitions. assessment#:#msg_poly_added#:#Polygone ajouté assessment#:#msg_questions_moved#:#Question(s) déplacée(s) @@ -969,7 +956,6 @@ assessment#:#order#:#Order assessment#:#ordering_answer_sequence_info#:#La séquence de réponse définie, ici, sera prise comme séquence correcte de la solution. assessment#:#ordertext#:#Texte à ordonner assessment#:#ordertext_info#:#Veuillez saisir le texte devant être ordonné horizontalement. Le texte à ordonner devra être séparé par des caractères blancs dans le texte. Vous pouvez aussi utiliser le séparateur %s pour séparer vos groupes de texte. -assessment#:#out_of_range#:#Hors de portée assessment#:#output#:#Restitution assessment#:#output_mode#:#Mode de Restitution assessment#:#parseQuestion#:#Traiter la Question @@ -1038,7 +1024,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Annuler -assessment#:#qpl_confirm_delete_questions#:#Etes-vous sûr(e) de vouloir supprimer la(les) question(s) suivante(s) ? Si vous détruisez des questions verrouillées, les résultats de tous les tests contenant une question verrouillée seront détruits également. assessment#:#qpl_copy_insert_clipboard#:#La ou les questions sélectionnés sont copiées dans le presse-papier assessment#:#qpl_copy_select_none#:#Cocher au moins une question à copier dans le presse-papier assessment#:#qpl_delete_rbac_error#:#Vous n'avez pas le droit de supprimer cette question! @@ -1091,7 +1076,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Compétence assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Somme totale de points de compétence par compétence assessment#:#qpl_question_is_in_use#:#La question que vous êtes sur le point de modifier existe dans %s test(s). Si vous changez cette question, vous ne la changerez pas dans ce(s) test(s), car le système crée une copie de la question quand elle est ajoutée dans un test. assessment#:#qpl_questions_deleted#:#Question(s) détruite(s). -assessment#:#qpl_reset_preview#:#Réinitialiser l'aperàçu assessment#:#qpl_save_skill_assigns_update#:#Sauvegarder les tâches de compétence assessment#:#qpl_settings_availability#:#Availability###31 10 2023 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Lorsque activé, les taxinomies créées sont utilisées pour le filtrage. @@ -1121,14 +1105,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters: assessment#:#qst_essay_wordcounter_enabled#:#Count Words assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field. assessment#:#qst_essay_written_words#:#Number of entered words: -assessment#:#qst_lifecycle#:#Lifecycle -assessment#:#qst_lifecycle_draft#:#Draft -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles -assessment#:#qst_lifecycle_final#:#Final -assessment#:#qst_lifecycle_outdated#:#Outdated -assessment#:#qst_lifecycle_rejected#:#Rejected -assessment#:#qst_lifecycle_review#:#To be Reviewed -assessment#:#qst_lifecycle_sharable#:#Sharable assessment#:#qst_nested_nested_answers_off#:#No indents, just order assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers assessment#:#qst_nr_of_tries#:#Nombre de tentatives @@ -1152,17 +1128,14 @@ assessment#:#question_title#:#Titre de la Question assessment#:#question_type#:#Type de Question assessment#:#questionpool_not_entered#:#Veuillez saisir un nom pour un groupe de questions. assessment#:#questionpool_not_selected#:#Please select a question pool! -assessment#:#questions#:#Questions###31 10 2023 new variable assessment#:#questions_from#:#questions de assessment#:#questions_per_page_view#:#Vue par Page assessment#:#random_accept_sample#:#Accepter échantillon assessment#:#random_another_sample#:#Obtenir un autre échantillon assessment#:#random_selection#:#Tirage Aléatoire assessment#:#range#:#Etendue -assessment#:#range_lower_limit#:#Limite Inférieure assessment#:#range_max#:#Intervalle (Maximum) assessment#:#range_min#:#Intervalle (Minimum) -assessment#:#range_upper_limit#:#Limite Supérieure assessment#:#rated_sign#:#Signe assessment#:#rated_unit#:#Unité assessment#:#rated_value#:#Valeur @@ -1238,7 +1211,6 @@ assessment#:#search_roles#:#Recherche des rôles assessment#:#search_term#:#Rechercher des termes assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Selectionner trou assessment#:#select_max_one_item#:#Veuillez ne saisir qu'un objet assessment#:#select_one_user#:#Veuillez sélectionner au moins un utilisateur assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1265,7 +1237,6 @@ assessment#:#show_old_introduction#:#Afficher l'ancienne introduction assessment#:#show_pass_overview#:#Afficher les Résultats assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Afficher les Réponses de l'Utilisateur -assessment#:#shuffle_answers#:#Mélanger les Réponses assessment#:#skip_question#:#Ne pas répondre et passer assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Texte @@ -1379,14 +1350,14 @@ assessment#:#tst_answer_fixation_on_instant_feedback_desc#:#After the feedback f assessment#:#tst_answer_fixation_on_instantfb_or_followupqst#:#Lock Answers with the Presentation of Feedback or Follow-Up Questions assessment#:#tst_answer_fixation_on_instantfb_or_followupqst_desc#:#Participant Answers for a question will be locked either with the presentation of the questions's feedback or when the follow-up question is shown. assessment#:#tst_answer_status_answered#:#Répondues -assessment#:#tst_answer_status_editing#:# (editing ... ) +assessment#:#tst_answer_status_editing#:# (En cours...) assessment#:#tst_answer_status_not_answered#:#Pas répondues assessment#:#tst_answered_questions#:#Réponses assessment#:#tst_answered_questions_of_total#:#%s of %s assessment#:#tst_answered_questions_test#:#Questions avec réponse du test assessment#:#tst_attached_xls_file#:#Vous trouverez le résultat du test pour ce participant dans le fichier Excel ci-joint. assessment#:#tst_attempt#:#Tentative -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###31 10 2023 new variable +assessment#:#tst_attempt_limit_message#:#Nombre total de tentatives autorisées pour ce test : %s. assessment#:#tst_attempt_started#:#Commencé assessment#:#tst_back_to_pass_details#:#Retour aux détails d’essai assessment#:#tst_back_to_question_list#:#Retour à la liste de questions @@ -1437,7 +1408,7 @@ assessment#:#tst_derive_new_pools#:#Obtenir de nouveaux pools de questions assessment#:#tst_dont_show_msg_again_in_current_session#:#Don't show this message again in my current session. assessment#:#tst_edit_competence_assign#:#Éditer les propriétés de la tâche assessment#:#tst_edit_scoring#:#Notation Manuelle -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###31 10 2023 new variable +assessment#:#tst_enable_questionlist#:#Afficher la Liste des questions assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###31 10 2023 new variable assessment#:#tst_ending_time#:#Heure de Fin assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date. @@ -1464,11 +1435,11 @@ assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions t assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###31 10 2023 new variable assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###31 10 2023 new variable assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###31 10 2023 new variable -assessment#:#tst_exam_password#:#Test Password###31 10 2023 new variable -assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###31 10 2023 new variable +assessment#:#tst_exam_password#:#Mot de passe de test +assessment#:#tst_exam_password_invalid_message#:#Le mot de passe que vous avez saisi n'est pas valide. Veuillez réessayer et, si nécessaire, contacter la personne responsable de ce test. assessment#:#tst_exam_password_label#:#Password###31 10 2023 new variable assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###31 10 2023 new variable -assessment#:#tst_exam_start#:#Start Test###31 10 2023 new variable +assessment#:#tst_exam_start#:#Démarrer le test assessment#:#tst_exam_use_previous_answers#:#Previous Answers###31 10 2023 new variable assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###31 10 2023 new variable assessment#:#tst_extratime_added#:#Le temps passé par le participant a été augmenté de %s minutes. @@ -1489,13 +1460,13 @@ assessment#:#tst_final_information#:#Informations avant la Fin du Test assessment#:#tst_finish_confirm_button#:#Oui, je souhaite terminer le test assessment#:#tst_finish_confirm_cancel_button#:#Non, revenir à la question précédente assessment#:#tst_finish_confirmation_question#:#Vous allez terminer ce test et atteindre le nombre maximum de tests autorisés validés. Vous ne pourrez plus refaire ce test une nouvelle fois pour modifier vos réponses. Voulez-vous vraiment terminer ce test ? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###31 10 2023 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Vous allez terminer ce test et atteindre le nombre maximal de tentatives autorisées. Vous ne pourrez plus accéder à ce test pour modifier vos réponses. Voulez-vous vraiment terminer le test ? assessment#:#tst_finished#:#Terminé assessment#:#tst_form_dynamic_question_set_config#:#Sélection des Questions assessment#:#tst_gap_analysis#:#Analyse d’écart assessment#:#tst_general_properties#:#Paramètres Généraux assessment#:#tst_header_participant#:#Résultat : -assessment#:#tst_header_participant_no_answer#:#Question - not answered###26 08 2024 new variable +assessment#:#tst_header_participant_no_answer#:#Question – sans réponse assessment#:#tst_header_solution#:#Solution correcte : assessment#:#tst_hide_info_tab#:#Hide Info Tab###31 10 2023 new variable assessment#:#tst_hide_info_tab_desc#:#Hides the tab ‘Info’ of the test.###31 10 2023 new variable @@ -1573,10 +1544,10 @@ assessment#:#tst_introduction_desc#:#Affiche un message d'introduction sur l'ong assessment#:#tst_introduction_text#:#Message d’introduction assessment#:#tst_invited_nobody#:#Aucun utilisateur, groupe ou rôle ajouté au test comme participant désigné assessment#:#tst_invited_selected_users#:#Les utilisateurs sélectionnés ont été ajoutés au test comme participants désignés -assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###31 10 2023 new variable +assessment#:#tst_launcher_button_label_passes_limit_reached#:#Vous avez passé ce test le nombre maximal de fois autorisé. assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###31 10 2023 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###31 10 2023 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###31 10 2023 new variable +assessment#:#tst_launcher_status_message_password#:#Le mot de passe vous sera demandé au début du test. assessment#:#tst_level#:#Niveau de compétence assessment#:#tst_limit_nr_of_tries#:#Nombre maximal d'Essais assessment#:#tst_link_only_unassigned#:#Vous avez sélectionné au moins une question qui est déjà liée à une Banque de Questions.
    Seule les questions non assignées peuvent être ajoutées dans une Banque de Questions. @@ -1681,7 +1652,7 @@ assessment#:#tst_objective_progress_header#:#Progression d'Objectif d'Apprentiss assessment#:#tst_objectives_progress_header#:#Progression d'Objectif d'Apprentissage assessment#:#tst_old_style_rnd_quest_set_broken#:#Ce test aléatoire se trouve dans un état irréparable car un ou plusieurs pools de questions connectés ont été supprimés. Par conséquent, les participants ne peuvent plus passer le test. assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Question related to allready passed learning objectives are optional.

    You want to navigate to a question, that relates to an allready passed learning objective.
    You can choose:

    I you proceed, you can work on these questions. Your answers from previous attempts were not adopted, since new random questions were selected for this attempt. With working on this questions you can also degrade your learning objective result.

    If you decide to not work on these questions, you can go back. In this case these questions won't be considered in the evaluation. -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###31 10 2023 new variable +assessment#:#tst_out_of_time_message#:#Le temps imparti pour passer ce test est écoulé. assessment#:#tst_participant#:#Participant assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s assessment#:#tst_participant_status#:#Type de Participant @@ -1920,7 +1891,7 @@ assessment#:#tst_tab_results_objective_oriented#:#Résultats par Objectifs d'app assessment#:#tst_tab_results_pass_oriented#:#Résultats par tentatives assessment#:#tst_tbl_col_answered_questions#:#Answered Questions assessment#:#tst_tbl_col_final_mark#:#Mark -assessment#:#tst_tbl_col_finished_passes#:#Finished Passes +assessment#:#tst_tbl_col_finished_passes#:#Tentatives achevées assessment#:#tst_tbl_col_finished_passes_num_of#:#%s of %s assessment#:#tst_tbl_col_last_scored_access#:#Last Scored Access assessment#:#tst_tbl_col_pass_finished#:#Pass Finished @@ -1937,7 +1908,7 @@ assessment#:#tst_text_count_system#:#Système de Notation assessment#:#tst_threshold#:#Thresholds assessment#:#tst_time_already_spent#:#Temps déjà passé assessment#:#tst_time_already_spent_left#:#Il vous reste %s. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###31 10 2023 new variable +assessment#:#tst_time_limit_message#:#Vous disposerez de %s minutes pour répondre à toutes les questions. assessment#:#tst_title_output#:#Présentation des Titres de Questions assessment#:#tst_title_output_full#:#Afficher le titre des questions et les points à obtenir assessment#:#tst_title_output_hide_points#:#Afficher seulement le titre des questions @@ -4656,9 +4627,9 @@ common#:#mm_personal_and_shared_r#:#Ressources personnelles et partagées common#:#mm_personal_workspace#:#Espace personnel common#:#mm_portfolio#:#Portfolio common#:#mm_private_chats#:#Private Chats###31 10 2023 new variable -common#:#mm_repo_tree_view#:#Tree View -common#:#mm_repo_tree_view_act#:#Activate Tree -common#:#mm_repo_tree_view_deact#:#Deactivate Tree +common#:#mm_repo_tree_view#:#Vue arborescente +common#:#mm_repo_tree_view_act#:#Activer la vue arborescente +common#:#mm_repo_tree_view_deact#:#Désactiver la vue arborescente common#:#mm_repository#:#Catalogue common#:#mm_skills#:#Compétences common#:#mm_staff_list#:#Collaborateurs @@ -4748,7 +4719,7 @@ common#:#msg_no_perm_paste#:#Vous n'avez pas la permission de coller les objets common#:#msg_no_perm_paste_object_in_folder#:#Vous n'avez pas le droit de coller l'objet %s dans le dossier %s. common#:#msg_no_perm_perm#:#Vous n'avez pas le droit de modifier les permissions common#:#msg_no_perm_read#:#Vous n'avez pas la permission d'accéder à cet objet. -common#:#msg_no_perm_read_item#:#Vous n'avez pas la permission d'accéder à l'objet '%s'. +common#:#msg_no_perm_read_item#:#Vous n'avez pas la permission d'accéder à l'objet. common#:#msg_no_perm_read_lm#:#Vous n'avez pas la permission de lire ce module. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Vous n'avez pas de permission en écrire @@ -5755,7 +5726,7 @@ common#:#toggle_off#:#OFF common#:#toggle_on#:#ON common#:#tomorrow#:#Demain common#:#toolbar_more_actions#:#More Actions###31 10 2023 new variable -common#:#tools#:#Tools +common#:#tools#:#Outils common#:#top_of_page#:#Haut de page common#:#tos_accept_usr_agreement#:#Accept Terms of Service?###31 10 2023 new variable common#:#tos_accept_usr_agreement_intro#:#There are new terms of service. You need to accept them before proceeding with the use of ILIAS. Read the following document carefully and give your consent or dissent at the bottom of the page.###31 10 2023 new variable @@ -7693,7 +7664,7 @@ crs#:#crs_members_map#:#Carte des Membres du Cours crs#:#crs_members_print_title#:#Membres du cours crs#:#crs_min_one_admin#:#Il existe au moins un administrateur assigné à ce cours. crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups +crs#:#crs_my_courses_groups_enabled#:#Mes cours et groupes crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible. crs#:#crs_new_status#:#Votre nouveau statut est : crs#:#crs_new_subscription#:#Nouvel abonnement au cours "%s" @@ -8075,10 +8046,10 @@ dash#:#dash_dashboard#:#Tableau de bord dash#:#dash_default_presentation#:#Default Presentation dash#:#dash_default_sortation#:#Default Sortation dash#:#dash_enable_cal#:#Calendar -dash#:#dash_enable_favourites#:#Favourites +dash#:#dash_enable_favourites#:#Favoris dash#:#dash_enable_learning_sequences#:#Learning Sequences###31 10 2023 new variable dash#:#dash_enable_mail#:#Mail -dash#:#dash_enable_memberships#:#My Courses and Groups +dash#:#dash_enable_memberships#:#Mes cours et mes groupes dash#:#dash_enable_news#:#News dash#:#dash_enable_recommended_content#:#Recommended Content###31 10 2023 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###31 10 2023 new variable @@ -8112,8 +8083,8 @@ dash#:#dash_sort_options#:#Postition of new Objects###29 10 2025 new variable dash#:#dash_sortation#:#Sortation dash#:#dash_study_programmes#:#My Study Programmes###31 10 2023 new variable dash#:#dash_tile#:#Tile -dash#:#dash_view_courses_groups#:#Section ‘My Courses and Groups’ -dash#:#dash_view_favourites#:#Section ‘Favourites’ +dash#:#dash_view_courses_groups#:#Rubrique « Mes cours et mes groupes » +dash#:#dash_view_favourites#:#Rubrique « Favoris » dash#:#favourites_disabled_info#:#Add to favorites is deactivated. You may change this inside the repository settings. dash#:#memberships_disabled_info#:#Subscriptions are deactivated. You may change this inside the course settings. dash#:#topitem_block#:#Block###31 10 2023 new variable @@ -13956,6 +13927,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback qpl#:#qpl_page_type_qfbs#:#Special Feedback qpl#:#qpl_page_type_qht#:#Hint qpl#:#qpl_page_type_qpl#:#Question Page +qsts#:#answer_options#:#Options de réponse +qsts#:#cloze_text#:#Texte à trous +qsts#:#cloze_textgapcase_insensitive#:#Ne pas distinguer majuscules et minuscules +qsts#:#cloze_textgapcase_sensitive#:#Distinguer majuscules et minuscules +qsts#:#cloze_textgaplevenshtein_of#:#Distance Levenshtein de %s +qsts#:#confirm_delete_questions#:#Etes-vous sûr(e) de vouloir supprimer la(les) question(s) suivante(s) ? Si vous détruisez des questions verrouillées, les résultats de tous les tests contenant une question verrouillée seront détruits également. +qsts#:#create_question#:#Créer Question +qsts#:#gap#:#Trou +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insérer Ecart +qsts#:#min_auto_complete#:#Saisie automatique +qsts#:#msg_no_questions_selected#:#No questions were selected.###31 10 2023 new variable +qsts#:#out_of_range#:#Hors de portée +qsts#:#qst_lifecycle#:#Lifecycle +qsts#:#qst_lifecycle_draft#:#Draft +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles +qsts#:#qst_lifecycle_final#:#Final +qsts#:#qst_lifecycle_outdated#:#Outdated +qsts#:#qst_lifecycle_rejected#:#Rejected +qsts#:#qst_lifecycle_review#:#To be Reviewed +qsts#:#qst_lifecycle_sharable#:#Sharable +qsts#:#questionlist#:#Liste de questions +qsts#:#questions#:#Questions +qsts#:#range_lower_limit#:#Limite Inférieure +qsts#:#range_upper_limit#:#Limite Supérieure +qsts#:#reset_preview#:#Réinitialiser l'aperàçu +qsts#:#select_gap#:#Selectionner trou +qsts#:#shuffle_answers#:#Mélanger les Réponses +qsts#:#suggested_learning_content#:#Ajouter solution suggérée rating#:#rat_not_rated_yet#:#Pas Encore Noté rating#:#rat_nr_ratings#:#%s Notations rating#:#rat_one_rating#:#Une Notation @@ -15068,7 +15068,7 @@ rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored t rep#:#rep_fav_intro1#:#Vous n'avez pas encore sélectionné de favori. Pour le faire, suivez ces deux étapes : rep#:#rep_fav_intro2#:#Cliquez sur '%s' et repérez le sujet qui vous intéresse dans l'offre disponible, par exemple un module ou un forum. rep#:#rep_fav_intro3#:#
    Cliquez sur le sujet souhaité, puis sur le menu Actions et choisissez l'option "Ajouter aux favoris". -rep#:#rep_favourites#:#Favourites +rep#:#rep_favourites#:#Favoris rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings. rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Bienvenue dans le Catalogue ILIAS ! @@ -16605,7 +16605,6 @@ survey#:#questionblock#:#Bloc de Questions survey#:#questionblock_inserted#:#Bloc de question ajouté survey#:#questionblocks#:#Blocs de Questions survey#:#questionblocks_inserted#:#Bloc de questions ajouté -survey#:#questions#:#Questions survey#:#questions_inserted#:#Question(s) ajoutée(s) survey#:#questions_removed#:#Question(s) et/ou bloc(s) de questions supprimé(es) ! survey#:#questiontype#:#Type de Question @@ -16906,6 +16905,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Masquer les vignettes survey#:#svy_print_show_labels#:#Montrer les vignettes survey#:#svy_privacy_info#:#Privacy###31 10 2023 new variable +survey#:#svy_questions#:#Questions survey#:#svy_rater#:#Rater###31 10 2023 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###31 10 2023 new variable survey#:#svy_reminder_mail_template#:#Modèle d’e-mail diff --git a/lang/ilias_hr.lang b/lang/ilias_hr.lang index 77f56a71ffb7..eec324369aa9 100644 --- a/lang/ilias_hr.lang +++ b/lang/ilias_hr.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#Aktivirajte protokoliranje testa i procjene assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Sadržaji za ponavljanje assessment#:#add_answers#:#Dodaj odgovore assessment#:#add_circle#:#Dodaj krug assessment#:#add_gap#:#Dodaj tekst za praznine @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Dobili ste bodove za svoje rje assessment#:#answer_is_right#:#Vaše rješenje je ispravno. assessment#:#answer_is_wrong#:#Vaše rješenje je pogrešno. assessment#:#answer_of#:#Answer of###04 06 2021 new variable -assessment#:#answer_options#:#Opcija odgovora: assessment#:#answer_question#:#Odgovori na pitanje assessment#:#answer_text#:#Tekst odgovora assessment#:#answer_types#:#Urednik odgovora @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Polaganje dostavom assessment#:#ass_completion_by_submission_info#:#Ako je to aktivirano, dostava datoteke s rješenjem dovodi do dodjele maksimalnog broja bodova za ovo pitanje. Procjena se u svakom trenutku može prilagoditi ručno. Promjena ove postavke nema nikakvih naknadnih učinaka na već dostavljena rješenja. assessment#:#ass_create_export_file_with_results#:#Izradi datoteku za izvoz (uklj. rezultate sudionika) assessment#:#ass_create_export_test_archive#:#Izradi datoteku arhive za test -assessment#:#ass_create_question#:#Izradi pitanje assessment#:#ass_imap_hint#:#Napomena (prikazuje kao tooltip) assessment#:#ass_imap_map_file_not_readable#:#Učitani se Imagemap ne može pročitati. assessment#:#ass_imap_no_map_found#:#U učitanom Imapemap-u nije pronađen nijedan oblik koji se podržava. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Duljina tekstualnog polja assessment#:#cloze_fixed_textlength_description#:#Ako ovdje unesete vrijednost, generiraju se praznine u tekstu koje ne definiraju vlastitu vrijednost za maksimalnu duljinu kao i numeričke praznine te duljine, tako da nije moguće upisati veći broj znakova od dopuštenog. Kod numeričkih praznina također treba voditi računa da se decimalni separator također računa kao znak. assessment#:#cloze_gap_size_info#:#Ako je upisana vrijednost veća od 0, to se tekstualno polje s prazninom generira s ovdje navedenom duljinom. Ako nije upisana vrijednost, to se tekstualno polje s prazninom generira s globalno određenom duljinom polja za tekst. -assessment#:#cloze_text#:#Pitanje s prazninom u tekstu -assessment#:#cloze_textgap_case_insensitive#:#Neosjetljivo na velika i mala slova -assessment#:#cloze_textgap_case_sensitive#:#Osjetljivo na velika i mala slova -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein razmak od%s assessment#:#code#:#Kod assessment#:#codebase#:#Kodna osnova assessment#:#concatenation#:#Povezivanje @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Možete unijeti unaprijed definirane varijable ($ assessment#:#fq_no_restriction_info#:#Kao unos prihvaćeni su kako decimale tako i razlomci. assessment#:#fq_precision_info#:#Unesite broj željenih decimalnih mjesta. assessment#:#fq_question_desc#:#Varijable možete definirati tako da umetnete $v1, $v2 ... $ VN, a rezultate da umetnete $r1, $r2 .... $rn na željeno mjesto u tekstu pitanja. Kliknite na uklopnu površinu „Analiziraj Pitanje” kako bi se generirali obrasci za obradu varijabli i rezultata. -assessment#:#gap#:#Praznina assessment#:#gap_combination#:#Kombinacija praznina -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Pojam iz pojmovnika assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Vaša ocjena je. "[ocjena]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Pitanje već sadrži slike. Ne možete pr assessment#:#info_text_upload#:#Odaberite datoteku s tekstom odgovora (UTF-8) kako biste je učitali. assessment#:#insert_after#:#Umetni iza assessment#:#insert_before#:#Umetni ispred -assessment#:#insert_gap#:#Umetni prazninu assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Unutarnje poveznice assessment#:#intprecision#:#Djeljivo s @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Sudionik je unio pogrešnu lozi assessment#:#longmenu#:#Dugi izbornik assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Tekst dugog izbornika -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Održavanje assessment#:#manscoring#:#Ručno bodovanje assessment#:#manscoring_done#:#Sudionici koji su već bodovani @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Dosegli ste maksimalan broj prolaza z assessment#:#maximum_points#:#Maksimalno raspoloživi broj bodova assessment#:#maxsize#:#Maksimalna veličina datoteke za učitavanje assessment#:#maxsize_info#:#Navedite u bajtovima maksimalnu veličinu koju bi smjela imati datoteka namijenjena za učitavanje. Ako ovo polje ostavite prazno, koristit će se umjesto toga maksimalna veličina osnovnog sustava. -assessment#:#min_auto_complete#:#Automatsko dopunjavanje assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Morate odrediti minimalni postotak od 0 posto! Shema ocjena nije spremljena. assessment#:#misc#:#Razne opcije @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Dodan je krug -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Broj pojmova mora biti veći ili jednak broju definicija. assessment#:#msg_poly_added#:#Dodan je poligon assessment#:#msg_questions_moved#:#Pitanje(a) je(su) pomaknuto(a) @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Slijed odgovora koji ovdje definirate uzet će se kao ispravan redoslijed rješenja. assessment#:#ordertext#:#Tekst za raspoređivanje assessment#:#ordertext_info#:#Unesite tekst koji treba rasporediti vodoravno. Tekst koji treba rasporediti bit će odvojen razmaknicama u tekstu. Ako trebate drugačiji odvajanje, za razdvajanje tekstualnih jedinica umjesto razmaknica možete koristiti separator%s. -assessment#:#out_of_range#:#Izvan raspona assessment#:#output#:#Izdavanje assessment#:#output_mode#:#Način izdavanja assessment#:#parseQuestion#:#Analiziraj pitanje @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Otkaži -assessment#:#qpl_confirm_delete_questions#:#Jeste li sigurni da želite ukloniti sljedeća pitanja? assessment#:#qpl_copy_insert_clipboard#:#Odabrano(a) pitanje(a) se kopiraju u međuspremnik assessment#:#qpl_copy_select_none#:#Molimo odaberite najmanje jedno pitanje za kopiranje u međuspremnik! assessment#:#qpl_delete_rbac_error#:#Nemate prava za uklanjanje ovog pitanja! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetencija assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Ukupan broj kompetencijskih bodova po kompetenciji assessment#:#qpl_question_is_in_use#:#Pitanje koje želite urediti postoji već u u %s testova. Ako promijenite ovo pitanje, to NEĆE imati nikakav utjecaj na pitanja koja su već sadržana u testovima, jer sustav automatski izrađuje kopiju pitanja kada se umetne u test! assessment#:#qpl_questions_deleted#:#Pitanje(a) izbrisano(a). -assessment#:#qpl_reset_preview#:#Resetiraj pregled assessment#:#qpl_save_skill_assigns_update#:#Spremi dodjelu kompetencija assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Postojeće taksonomije u ovom bazenu mogu se koristiti za filtriranje pitanja. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###04 06 2021 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###04 06 2021 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###04 06 2021 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###04 06 2021 new variable -assessment#:#qst_lifecycle#:#Lifecycle###04 06 2021 new variable -assessment#:#qst_lifecycle_draft#:#Draft###04 06 2021 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###04 06 2021 new variable -assessment#:#qst_lifecycle_final#:#Final###04 06 2021 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###04 06 2021 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###04 06 2021 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###04 06 2021 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###04 06 2021 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Broj pokušaja @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Naziv pitanja assessment#:#question_type#:#Tip pitanja assessment#:#questionpool_not_entered#:#Unesite naziv za bazen pitanja! assessment#:#questionpool_not_selected#:#Please select a question pool!###04 06 2021 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#Pitanja iz assessment#:#questions_per_page_view#:#Prikaz stranice assessment#:#random_accept_sample#:#Prihvati uzorak assessment#:#random_another_sample#:#Uzmite drugi uzorak assessment#:#random_selection#:#Slučajni odabir assessment#:#range#:#Raspon -assessment#:#range_lower_limit#:#Donja granica assessment#:#range_max#:#Raspon (maksimalni) assessment#:#range_min#:#Raspon (minimalni) -assessment#:#range_upper_limit#:#Gornja granica assessment#:#rated_sign#:#Predznak assessment#:#rated_unit#:#Jedinica assessment#:#rated_value#:#Vrijednost @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Pretraži po ulogama assessment#:#search_term#:#Pojam za pretraživanje assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Odaberi prazninu assessment#:#select_max_one_item#:#Molimo odaberite samo jedan objekt assessment#:#select_one_user#:#Molimo odaberite najmanje jednog korisnika. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Prikaži pregled rezultata ocijenjenog prolaza testa assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Pokaži ocijenjene odgovore korisnika -assessment#:#shuffle_answers#:#Pomiješaj odgovore assessment#:#skip_question#:#Nemoj odgovoriti i dalje assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Tekst @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nemate dopuštenje za umetanje sljedećih objekata: common#:#msg_no_perm_paste_object_in_folder#:#Nemate dopuštenje za umetanje objekta %s u mapu %s. common#:#msg_no_perm_perm#:#Nemate dopuštenje za pristup postavkama prava common#:#msg_no_perm_read#:#Nemate dozvolu za pristup ovom objektu. -common#:#msg_no_perm_read_item#:#Nemate dozvolu za pristup objektu '%s'. +common#:#msg_no_perm_read_item#:#Nemate dozvolu za pristup objektu. common#:#msg_no_perm_read_lm#:#Nemate dopuštenje za čitanje ovog modula za učenje. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nemate dopuštenje za pisanje @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###04 06 2021 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###04 06 2021 new variable qpl#:#qpl_page_type_qht#:#Hint###04 06 2021 new variable qpl#:#qpl_page_type_qpl#:#Question Page###04 06 2021 new variable +qsts#:#answer_options#:#Opcija odgovora +qsts#:#cloze_text#:#Pitanje s prazninom u tekstu +qsts#:#cloze_textgapcase_insensitive#:#Neosjetljivo na velika i mala slova +qsts#:#cloze_textgapcase_sensitive#:#Osjetljivo na velika i mala slova +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein razmak od%s +qsts#:#confirm_delete_questions#:#Jeste li sigurni da želite ukloniti sljedeća pitanja? +qsts#:#create_question#:#Izradi pitanje +qsts#:#gap#:#Praznina +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Umetni prazninu +qsts#:#min_auto_complete#:#Automatsko dopunjavanje +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Izvan raspona +qsts#:#qst_lifecycle#:#Lifecycle###04 06 2021 new variable +qsts#:#qst_lifecycle_draft#:#Draft###04 06 2021 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###04 06 2021 new variable +qsts#:#qst_lifecycle_final#:#Final###04 06 2021 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###04 06 2021 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###04 06 2021 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###04 06 2021 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###04 06 2021 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Donja granica +qsts#:#range_upper_limit#:#Gornja granica +qsts#:#reset_preview#:#Resetiraj pregled +qsts#:#select_gap#:#Odaberi prazninu +qsts#:#shuffle_answers#:#Pomiješaj odgovore +qsts#:#suggested_learning_content#:#Sadržaji za ponavljanje rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok pitanja survey#:#questionblock_inserted#:#Blok pitanja je umetnut survey#:#questionblocks#:#Blokovi pitanja survey#:#questionblocks_inserted#:#Blokovi pitanja su umetnuti -survey#:#questions#:#Pitanja survey#:#questions_inserted#:#Pitanje(a) je(su) umetnuto(a)! survey#:#questions_removed#:#Pitanje(a) i/ili blok(ovi) pitanja je(su) uklonjeno(i)! survey#:#questiontype#:#Tip pitanja @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Sakrij oznake survey#:#svy_print_show_labels#:#Pokaži oznake survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Pitanja survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Predložak pošte diff --git a/lang/ilias_hu.lang b/lang/ilias_hu.lang index f1271ccc3d4a..29a1f5f9451b 100644 --- a/lang/ilias_hu.lang +++ b/lang/ilias_hu.lang @@ -20,7 +20,7 @@ * @module language file Hungarian * @modulegroup language * @author Kiss-Kálmán Dániel -* @version 7.x 2021-01-02 +* @version 11.x 2026-06-01 */ // The language file starts beyond the HTML-comment below. DO NOT modify this line! // To edit your language file with a spreadsheet (i.e. Excel or StarCalc) remove all lines @@ -31,28 +31,28 @@ acc#:#acc_add_document_btn_label#:#Dokumentum hozzáadása acc#:#acc_crit_type_usr_language#:#A profil nyelve -acc#:#acc_criterion_assignment_must_be_unique_insert#:#Ezt a feltételt nem csatolhatja ehhez az értékhez. Már létezik egy ugyanilyen kritérium. -acc#:#acc_criterion_assignment_must_be_unique_update#:#Nem változtathatja meg a kritériumot kívánt módon. Már létezik egy ugyanilyen kritérium. -acc#:#acc_ctrl_cpt_txt#:#Hozzáférés-vezérlés koncepciója +acc#:#acc_criterion_assignment_must_be_unique_insert#:#Ezt a nyelv már megjelenítési feltétele egy másik Hozzáférhetőségi dokumentumnak, nem állíthatja be ehhez is. +acc#:#acc_criterion_assignment_must_be_unique_update#:#Ezt a nyelv már megjelenítési feltétele egy másik Hozzáférhetőségi dokumentumnak, nem állíthatja be ehhez is. +acc#:#acc_ctrl_cpt_txt#:#Hozzáférhetőségi dokumentumok acc#:#acc_deleted_documents_p#:#A dokumentumokat sikeresen törölte. acc#:#acc_deleted_documents_s#:#A dokumentumot sikeresen törölte. -acc#:#acc_doc_crit_attached#:#A feltételt sikeresen hozzárendelte. -acc#:#acc_doc_crit_changed#:#A feltételt sikeresen módosította. -acc#:#acc_doc_crit_detached#:#A feltételt sikeresen eltávolította. +acc#:#acc_doc_crit_attached#:#A Hozzáférhetőségi dokumentum megjelenítési feltételét sikeresen hozzárendelte. +acc#:#acc_doc_crit_changed#:#A Hozzáférhetőségi dokumentum megjelenítési feltételét sikeresen módosította. +acc#:#acc_doc_crit_detached#:#A Hozzáférhetőségi dokumentum megjelenítési feltételét sikeresen eltávolította. acc#:#acc_doc_delete#:#Dokumentum törlése -acc#:#acc_doc_detach_crit_confirm_title#:#Feltétel eltávolítása -acc#:#acc_doc_sure_detach_crit#:#Biztos, hogy eltávolítja ezt a feltételt? +acc#:#acc_doc_detach_crit_confirm_title#:#Nyelvi feltétel eltávolítása +acc#:#acc_doc_sure_detach_crit#:#Biztos, hogy eltávolítja ezt a nyelvi feltételt? acc#:#acc_document#:#Dokumentum -acc#:#acc_form_attach_criterion_head#:#Feltétel hozzárendelése +acc#:#acc_form_attach_criterion_head#:#Nyelvi feltétel hozzárendelése a Hozzáférhetőségi dokumentum megjelenítési feltételéhez acc#:#acc_form_criterion#:#Feltétel acc#:#acc_form_document#:#Dokumentum -acc#:#acc_form_document_content_changed#:#Az ILIAS megtisztította a feltöltött fájl tartalmát. Kérjük, ellenőrizze a végeredményt és szükség esetén töltsön fel új fájlt. -acc#:#acc_form_document_info#:#Válasszon egy fájlt a helyi fájlrendszerből. Feltölthet egy egyszerű szöveges fájlt vagy egy egyszerű HTML-fájlt. A HTML fájlok tisztításra kerülnek, csak a törzselem tartalmát használjuk. +acc#:#acc_form_document_content_changed#:#Az ILIAS eltávolított a feltöltött fájl <head> tartalmát. Kérjük, ellenőrizze a végeredményt és szükség esetén töltsön fel új fájlt. +acc#:#acc_form_document_info#:#Válasszon egy fájlt a saját gépéről. Feltölthet egy egyszerű szöveges fájlt vagy egy egyszerű HTML-fájlt. A HTML fájl <head> tartalmát eltávolítjuk, csak a törzselem tartalmát használjuk. acc#:#acc_form_document_new#:#Tartalom módosítása -acc#:#acc_form_document_new_info#:#Válasszon egy fájlt a helyi fájlrendszerből. Feltölthet egy egyszerű szöveges fájlt vagy egy egyszerű HTML-fájlt. A HTML fájlok tisztításra kerülnek, csak a törzselem tartalmát használjuk. A már létező tartalmat lecseréljük. +acc#:#acc_form_document_new_info#:#Válasszon egy fájlt a saját gépéről, amit a Hozzáférhetőségi Dokumentum új tartalmának szeretne. Feltölthet egy egyszerű szöveges fájlt vagy egy egyszerű HTML-fájlt. A HTML fájl <head> tartalmát eltávolítjuk, csak a törzselem tartalmát használjuk. A már létező tartalmat lecseréljük. acc#:#acc_form_document_title#:#Cím acc#:#acc_form_document_title_info#:#Adja meg a dokumentum címét. -acc#:#acc_form_edit_criterion_head#:#Feltétel hozzárendelése módosítása +acc#:#acc_form_edit_criterion_head#:#Nyelvi feltétel módosítása acc#:#acc_form_edit_doc_head#:#Dokumentum módosítása acc#:#acc_form_new_doc_head#:#Dokumentum létrehozása acc#:#acc_forward_mail#:#Továbbítás @@ -62,37 +62,37 @@ acc#:#acc_saved_sorting#:#A rendezést sikeresen mentette. acc#:#acc_sure_delete_documents_p#:#Biztos, hogy törli a kiválasztott dokumentumokat? acc#:#acc_sure_delete_documents_s#:#Biztos, hogy törli a kiválasztott dokumentumot? acc#:#acc_tbl_docs_action_add_criterion#:#Feltétel hozzáadása -acc#:#acc_tbl_docs_cell_not_criterion#:#Egy feltétel sincs hozzárendelve +acc#:#acc_tbl_docs_cell_not_criterion#:#Egy nyelvi feltétel sincs hozzárendelve acc#:#acc_tbl_docs_head_created#:#Létrehozása dátuma -acc#:#acc_tbl_docs_head_criteria#:#Feltételek +acc#:#acc_tbl_docs_head_criteria#:#Feltétel acc#:#acc_tbl_docs_head_last_change#:#Utolsó módosítás acc#:#acc_tbl_docs_head_sorting#:#Rendezés acc#:#acc_tbl_docs_head_title#:#Cím acc#:#acc_tbl_docs_title#:#Dokumentumok acc#:#acc_tree_off#:#Tartalomfa kikapcsolása acc#:#acc_tree_on#:#Tartalomfa bekapcsolása -adm#:#adm_acc_ctrl_cpt_desc#:#Ha be van kapcsolva, a Hozzáférés-vezérlés koncepciója link jelenik meg a lálécben. -adm#:#adm_acc_ctrl_cpt_enable#:#Hozzáférésvezérlés-koncepció bekapcsolása -adm#:#adm_accessibility_contacts#:#A kapcsolat hozzáférési pontja -adm#:#adm_accessibility_contacts_info#:#Kapcsolatok a hozzáférési problémák jelentéséhez, láblécben lévő link. Felhasználónevek vesszővel elválasztott felsorolása. -adm#:#adm_awrn_support_contacts_info#:#Az összes technikai segítségnyújtót felsoroljuk. Ezek az 'Általános beállítások' » 'Elérhetőségek' » 'Technikai segítségnyújtók' részben található felhasználók. +adm#:#adm_acc_ctrl_cpt_desc#:#A Hozzáférhetőségi Dokumentum linkje jelenik meg a láblécben. +adm#:#adm_acc_ctrl_cpt_enable#:#A Hozzáférhetőségi Dokumentum linkje a láblécben +adm#:#adm_accessibility_contacts#:#Elérthetőségek hozzáférési problémák esetén +adm#:#adm_accessibility_contacts_info#:#Kapcsolatok a hozzáférési problémák jelentéséhez. Láblécben lévő link, felhasználónevek vesszővel elválasztott felsorolása. +adm#:#adm_awrn_support_contacts_info#:#Az összes technikai segítségnyújtót felsoroljuk. Ezek az ‘Általános beállítások’ » ‘Elérhetőségek’ » ‘Technikai segítségnyújtók’ részben található felhasználók. adm#:#adm_support_contacts#:#Technikai segítségnyújtók -adm#:#adm_support_contacts_info#:#A támogatási kapcsolatok - ami vesszővel elválasztott felhasználói fiókok felsorolása - a 'Ki van online?'-eszköz láblécébe kerülnek (ha az be van kapcsolva). -administration#:#adm_achievements#:#Kitüntetések -administration#:#adm_adm_role_protect#:#Rendszergazdai szerep védelme -administration#:#adm_adm_role_protect_info#:#Ha be van kapcsolva, csak a rendszergazda rendelhet felhasználókat a rendszergazda szerephez, illetve csak ő vonhatja vissza azt. -administration#:#adm_auth_login#:#Authentication Login###29 07 2022 new variable -administration#:#adm_auth_reg#:#Authentication Registration###29 07 2022 new variable +adm#:#adm_support_contacts_info#:#A támogatói kapcsolatok - ami vesszővel elválasztott felhasználónevek felsorolása - a ‘Ki van online?’-eszköz láblécébe kerülnek (ha az be van kapcsolva). +administration#:#adm_achievements#:#Eredmények +administration#:#adm_adm_role_protect#:#Rendszergazdai szerepkör védelme +administration#:#adm_adm_role_protect_info#:#Csak a rendszergazda rendelhet hozzá felhasználókat a rendszergazda szerepkörhöz, illetve csak ő távolíthatja el onnan őket. +administration#:#adm_auth_login#:#Hitelesítés bejelentkezés +administration#:#adm_auth_reg#:#Hitelesítés regisztráció administration#:#adm_communication#:#Kommunikáció administration#:#adm_extending_ilias#:#ILIAS kiterjesztése administration#:#adm_external_setting_edit#:#Beállítások módosítása administration#:#adm_hide#:#Beállítások elrejtése az űrlapon -administration#:#adm_hide_tabs#:#Fülek elrejtése +administration#:#adm_hide_tabs#:#Lapok elrejtése administration#:#adm_https#:#HTTPS administration#:#adm_imprint#:#Impresszum administration#:#adm_imprint_inactive#:#Az impresszum inaktív, a felhasználók nem érhetik el. administration#:#adm_layout_and_navigation#:#Kinézet és navigáció -administration#:#adm_legal_regulations#:#Legal Regulations###26 08 2024 new variable +administration#:#adm_legal_regulations#:#Jogi előírások administration#:#adm_locale#:#Helyi administration#:#adm_locale_info#:#A helyi beállítások befolyásolják például a listák sorba rendezését. Például hu_HU.UTF-8 vagy de_DE. A többszörös helyi beállítások vesszővel választhatók el. Az első érvényest használjuk. administration#:#adm_maintenance#:#Rendszerbeállítások és karbantartás @@ -105,15 +105,15 @@ administration#:#adm_predefined_settings#:#Előre definiált beállítások administration#:#adm_pub_section_domain_filter#:#Domain szűrő administration#:#adm_pub_section_domain_filter_info#:#A domain szűrők engedélyezik az anonymous hozzáférést. Adjon meg egy vagy több domaint, melyekről engedélyezett az anonymous hozzáférés. administration#:#adm_rep_shorten_description#:#Leírások hosszának korlátja -administration#:#adm_rep_shorten_description_info#:#Ha be van kapcsolva, az objektumok felsorolásánál a leírások maximum ennyi karakterben jelennek meg. +administration#:#adm_rep_shorten_description_info#:#Az objektumok felsorolásánál a leírások maximum ennyi karakterben jelennek meg. administration#:#adm_rep_shorten_description_length#:#Karakterek maximális száma -administration#:#adm_rep_tree_all_types#:#Összes forrástípus -administration#:#adm_rep_tree_all_types_info#:#Az összes forrástípust felsoroljuk a fában. -administration#:#adm_rep_tree_limit_grp_crs#:#Korlátozott faszerkezet-tartalom megjelenítése kurzusokban és csoportokban. -administration#:#adm_rep_tree_limit_grp_crs_info#:#Ezt igényli és automatikusa bekapcsolja a 'Faszerkezet szinkronizálása' opciót +administration#:#adm_rep_tree_all_types#:#Összes objektumtípus +administration#:#adm_rep_tree_all_types_info#:#Az összes objektumtípust felsoroljuk a fában. +administration#:#adm_rep_tree_limit_grp_crs#:#Megjelenítés csak kurzusokban és csoportokban. +administration#:#adm_rep_tree_limit_grp_crs_info#:#A fa nézet a kurzusok és a csoportok összes objektumát megjeleníti, azokon kívül pedig csak a tárolóobjektumokat. administration#:#adm_rep_tree_only_cntr#:#Csak tárolók -administration#:#adm_rep_tree_only_cntr_info#:#Csak kategóriákat, kurzusokat és csoportokat sorolunk fel -administration#:#adm_rep_tree_presentation#:#Tartalomtár megjelenítése +administration#:#adm_rep_tree_only_cntr_info#:#Csak képzési programokat, kategóriákat, kurzusokat és csoportokat jelenítünk meg +administration#:#adm_rep_tree_presentation#:#Tartalomtár fa nézete administration#:#adm_repository_and_objects#:#Tartalomtár és objektumok administration#:#adm_search_and_find#:#Keresés és találat administration#:#adm_show_comments_tagging_in_lists#:#Jegyzetek, megjegyzések és címkék számának megjelenítése az objektumlistákban @@ -127,14 +127,14 @@ administration#:#adm_user_starting_point_inherit_info#:#A rendszergazda összes administration#:#adm_user_starting_point_invalid_info#:#Ez a funkció jelenleg nem aktív. administration#:#adm_user_starting_point_object#:#Tartalomtárbeli objektum administration#:#adm_user_starting_point_personal#:#Személyes beállítás -administration#:#adm_user_starting_point_personal_info#:#Ha be van kapcsolva, a felhasználók kiválaszthatják kezdőlapjukat. -administration#:#adm_user_starting_point_ref_id#:#ref_id -administration#:#adm_user_starting_point_ref_id_info#:#Nyissa meg az objektumot, amit Személyes kezdőpontnak szeretne beállítani, majd másolja böngészője címsorában lévő 'ref_id' számértékét a szövegmezőbe. +administration#:#adm_user_starting_point_personal_info#:#A felhasználók kiválaszthatják kezdőlapjukat. +administration#:#adm_user_starting_point_ref_id#:#Referencia-ID +administration#:#adm_user_starting_point_ref_id_info#:#Nyissa meg az objektumot, amit Személyes kezdőpontjának szeretne beállítani, majd másolja böngészője címsorában lévő ‘ref_id’ számértékét a szövegmezőbe. administration#:#adm_value#:#Előre definiált érték -administration#:#allow_change_loginname#:#Felhasználónevek módosításának engedélyezése a 'Felhasználói adatok és profil' » 'Személyes adatok' részében +administration#:#allow_change_loginname#:#Felhasználónevek módosításának engedélyezése a ‘Felhasználói adatok és profil’ » ‘Személyes adatok’ részében administration#:#analysis_options#:#Elemzési beállítások administration#:#analyze_data#:#Adatintegritás vizsgálata és javítása -administration#:#analyzing_tree_structure#:#Fastruktúra elemzése... +administration#:#analyzing_tree_structure#:#Fastruktúra elemzése… administration#:#apache_auth_authenticate_on_login_page#:#Apache-azonosítás próbálása a bejelentkező lapra belépéskor. administration#:#apache_auth_domains#:#Engedélyezett átirányítási tartományok administration#:#apache_auth_domains_description#:#Adjon meg soronként egy domaint az átirányítás engedélyezéséhez erre a címre.
    Ha az ILIAS-t több mint egy domain eléri, adja meg az összes engedélyezendő célt.
    Például: az example.com lehetővé teszi az átirányítást a http://example.com és a http://www.example.com címre, valamint minden lapra, amely azokon helyezkedik el. @@ -151,7 +151,7 @@ administration#:#apache_auth_username_direct_mapping#:#Egyenes összerendelés administration#:#apache_auth_username_direct_mapping_fieldname#:#Mező összerendeléshez administration#:#apache_auth_username_extended_mapping#:#Kiterjesztett összerendelés administration#:#apache_autocreate#:#ILIAS-fiók generálásának engedélyezése -administration#:#apache_default_role#:#Alapértelmezett felhasználói szerep +administration#:#apache_default_role#:#Alapértelmezett felhasználói szerepkör administration#:#apache_enable_auth#:#Apache azonosítási támogatás engedélyezése administration#:#apache_enable_ldap#:#LDAP felhasználói hozzárendelés engedélyezése administration#:#apache_enable_local#:#Helyi felhasználói hozzárendelés engedélyezése @@ -163,29 +163,29 @@ administration#:#auth_auth_mode_determination#:#Azonosítási mód meghatározá administration#:#auth_automatic#:#Rögzített sorrend administration#:#auth_by_user#:#A felhasználó által administration#:#auth_kind_determination#:#Meghatározásfajta -administration#:#auth_mode_default_change_info#:#Changing the default authentication method affects all user accounts configured to use the default authentication method. If the selected default method (e.g., Shibboleth, SAML, SOAP, ...) does not support or is not configured to allow fallback to local ILIAS authentication, affected users may no longer be able to log in. To avoid this, please ensure that local fallback authentication is activated in the configuration of the selected method, or that the authentication method stored for affected user accounts is manually changed.###29 10 2025 new variable +administration#:#auth_mode_default_change_info#:#Az alapértelmezett hitelesítési mód módosítása az alapértelmezett hitelesítési módot használó összes felhasználói fiókot érinti. Ha a kiválasztott alapértelmezett módot (pl. Shibboleth, SAML, SOAP) nem támogatja, vagy az nincs konfigurálva a helyi ILIAS-hitelesítésre való tartalék használatára, az érintett felhasználók a továbbiakban nem biztos, hogy bejelentkezhetnek. Ennek elkerülése érdekében győződjön meg arról, hogy a helyi tartalék hitelesítés aktiválva van a kiválasztott módszer konfigurációjában, vagy hogy az érintett felhasználói fiókokhoz tárolt hitelesítési módszert manuálisan módosítják. administration#:#auth_mode_determination_info#:#Jelölje be, ha a felhasználóknak ki kell választaniuk az azonosítási módot a bejelentkező képernyőn, vagy ha bejelentkezési módok rögzített sorrendjével kerül kezelésre. administration#:#clean#:#Rendbetétel administration#:#clean_desc#:#Érvénytelen hivatkozások és faszerkezet-bejegyzések eltávolítása. Hézagok inicializálása a faszerkezetben. -administration#:#cleaning#:#Tisztítás... -administration#:#cleaning_final#:#Végső tisztítás... +administration#:#cleaning#:#Tisztítás… +administration#:#cleaning_final#:#Végső tisztítás… administration#:#course_export#:#Látható a kurzusokban administration#:#done#:#Kész administration#:#dump_tree#:#Faszerkezet kiírása administration#:#dump_tree_desc#:#A faszerkezet átvizsgálása és a facsomópontok nyomtatása az elemzés adataival. -administration#:#dumping_tree#:#Faszerkezet kiírása... +administration#:#dumping_tree#:#Faszerkezet kiírása… administration#:#found#:#találat. administration#:#found_none#:#nincs találat. administration#:#git_hash_short#:#Változtatás Hash (rövid): %s -administration#:#git_last_commit#:#Utolsó változtatás: %s +administration#:#git_last_commit#:#Utolsó módosítás: %s administration#:#git_revision#:#Szám: %s administration#:#group_export#:#Látható a csoportokban administration#:#history_loginname#:#Felhasználónév-előzmények -administration#:#initializing_gaps#:#Hézagok inicializálása a fában... +administration#:#initializing_gaps#:#Hézagok inicializálása a fában… administration#:#language_all_modules#:#Összes modul administration#:#language_change_settings#:#Nyelvi beállítások változtatása administration#:#language_clear_local_changes#:#Helyi változatok törlése az adatbázisban -administration#:#language_clear_local_changes_info#:#A nyelv összes bejegyzését a lang/ilias_%s.lang fájlban megadott alapértelmezett értékre állítjuk. Minden egyéb változtatás törlünk. +administration#:#language_clear_local_changes_info#:#A nyelv összes bejegyzését a lang/customizing/ilias_%s.lang fájlban megadott alapértelmezett értékre állítjuk. Minden egyéb változtatás törlünk. administration#:#language_cleared_local#:#A helyi változatok törlődtek az adatbázisból. administration#:#language_compare#:#Összehasonlítás administration#:#language_default_entries#:#(alapértelmezett bejegyzések) @@ -197,9 +197,9 @@ administration#:#language_error_local_missed#:#Az egyéni nyelvi fájl nem léte administration#:#language_error_read_local#:#Az egyéni nyelvi fájl nem létezik vagy nem olvasható! administration#:#language_error_write_global#:#A standard nyelvi fájl nem írható! administration#:#language_export_file#:#Nyelvi fájl exportja -administration#:#language_file_imported#:#A nyelvi fájlt (%s) importáltuk. +administration#:#language_file_imported#:#A nyelvi fájlt (%s) sikeresen importálta. administration#:#language_file_scope#:#Nyelvi fájl hatóköre -administration#:#language_former_file_description#:#A helyi módosításainak a legutóbbi frissítés módosításaival való összehasonlításhoz másolja a korábban installált ILIAS-verzió nyelvi fájlját a fentebb említett mappába. A következő frissítés előtt ezt megteheti a Karbantartás fül alatt a 'Standard nyelvi fájlok biztonsági mentése' beállítással. +administration#:#language_former_file_description#:#A helyi módosításainak a legutóbbi frissítés módosításaival való összehasonlításhoz másolja a korábban installált ILIAS-verzió nyelvi fájlját a fentebb említett mappába. A következő frissítés előtt ezt megteheti a Karbantartás lapon a ‘Standard nyelvi fájlok biztonsági mentése’ beállítással. administration#:#language_former_file_equal#:#%s fájl azonos a jelenlegi nyelvi fájllal. administration#:#language_former_file_missing#:#%s fájl hiányzik. administration#:#language_import_file#:#Nyelvi fájl importálása @@ -208,14 +208,14 @@ administration#:#language_load_local_changes_info#:#A lang/customizing/ilias_%s. administration#:#language_loaded_local#:#Az egyéni nyelvi fájlt sikeresen betöltötte az adatbázisba. administration#:#language_local_file_deleted#:#Az egyéni nyelvi fájlt sikeresen törölte. administration#:#language_maintain#:#Karbantartás -administration#:#language_maintain_local_changes#:#Helyi módosítások karbantartás +administration#:#language_maintain_local_changes#:#Helyi módosítások karbantartása administration#:#language_maintenance#:#Nyelv karbantartása administration#:#language_merge_local_changes#:#Helyi változatok összefésülése a standard nyelvi fájllal -administration#:#language_merge_local_changes_info#:#A összes helyi és egyéb változat összeolvasztása a lang/ilias_%s.lang standard nyelvi fájlba betűrendben. A webszerver futtatójának írási jog szükséges a fájlhoz. +administration#:#language_merge_local_changes_info#:#A összes helyi és egyéb változat összeolvasztása a lang/customizing/ilias_%s.lang standard nyelvi fájlba betűrendben. A webszerver futtatójának írási jog szükséges a fájlhoz. administration#:#language_merged_global#:#A helyi változatokat összefésülte a standard nyelvi fájllal administration#:#language_mode_existing#:#Létező bejegyzések administration#:#language_mode_existing_delete#:#Létező bejegyzések törlése -administration#:#language_mode_existing_delete_info#:#Importálás előtt az összes bejegyzés törlése az adatbázisból.
    FIGYELEM: Az importálandó nyelvi fájlnak teljesnek kell lennie, különben nem minden nyelvi változó jelenik meg hibátlanul. Amennyiben ez bekövetkezik, kapcsolja be a 'Karbantartás'-t és válassza a 'Helyi változatok törlése az adatbázisban' opciók. +administration#:#language_mode_existing_delete_info#:#Importálás előtt az összes bejegyzés törlése az adatbázisból.
    FIGYELEM: Az importálandó nyelvi fájlnak teljesnek kell lennie, különben nem minden nyelvi változó jelenik meg hibátlanul. Amennyiben ez bekövetkezik, kapcsolja be a ‘Karbantartás’-t és válassza a ‘Helyi változatok törlése az adatbázisban’ opciók. administration#:#language_mode_existing_keepall#:#Az összes már létező bejegyzés megtartása administration#:#language_mode_existing_keepall_info#:#Csak az új, adatbázisban még nem létező bejegyzések importálása. administration#:#language_mode_existing_keepnew#:#Az összes helyi változat megtartása @@ -225,15 +225,15 @@ administration#:#language_mode_existing_replace_info#:#Új bejegyzések importá administration#:#language_note_translation#:#Az oldalfordító az egyes nyelvekhez külön-külön kapcsolható be. A felhasználónak olvasási és írási jogosultsággal is rendelkeznie kell az egyes nyelvi fájlokhoz. administration#:#language_process_maintenance#:#Karbantartás futtatása administration#:#language_remove_local_file#:#Egyéni nyelvi fájl törlése -administration#:#language_remove_local_file_info#:#A lang/customizing/ilias_%s.lang.local fájl törlése és a nyelv 'Helyi nyelvi fájllal telepítve' cseréje 'Telepítve' állapotra. Az adatbázisban nem történik változtatás. +administration#:#language_remove_local_file_info#:#A lang/customizing/ilias_%s.lang.local fájl törlése és a nyelv ‘Helyi nyelvi fájllal telepítve’ cseréje ‘Telepítve’ állapotra. Az adatbázisban nem történik változtatás. administration#:#language_save_dist#:#A standard nyelvi fájl biztonsági mentése administration#:#language_save_dist_failed#:#A standard nyelvi fájl biztonsági mentése nem sikerült (írási hiba). administration#:#language_save_dist_info#:#Az ILIAS adatmappájában lévő standard ILIAS nyelvi fájlról biztonsági másolat készül. Ez segítségére lehet ILIAS frissítés után a saját módosítások és a frissített nyelvi változók közötti ütközések keresésékor. administration#:#language_save_local_changes#:#Az összes változtatást egyéni nyelvi fájlba mentése -administration#:#language_save_local_changes_info#:#Az összes helyileg hozzáadott vagy adatbázisban megváltoztatott bejegyzés mentése a lang/customizing/ilias_%s.lang.local fájlban, és a nyelv átállítása 'Helyi nyelvi fájllal telepítve' állapotúra. A webszerver futtatójának írási jog szükséges a mappába. Figyeljen arra, hogy a telepítés összes kliense ezt a fájlt használja. +administration#:#language_save_local_changes_info#:#Az összes helyileg hozzáadott vagy adatbázisban megváltoztatott bejegyzés mentése a lang/customizing/ilias_%s.lang.local fájlban, és a nyelv átállítása ‘Helyi nyelvi fájllal telepítve’ állapotúra. A webszerver futtatójának írási jog szükséges a mappába. Figyeljen arra, hogy a telepítés összes kliense ezt a fájlt használja. administration#:#language_saved_dist#:#Sikeresen létrehozta a standard nyelvi fájl biztonsági mentését. administration#:#language_scope_added#:#Csak helyi felvétel -administration#:#language_scope_added_info#:#Az összes, az adatbázisba helyiként hozzáadott bejegyzés exportálása. A fejlesztés alatt lévő változatok biztonsági mentésére lehet felhasználni a 'Karbantartás' fülön történő helyi változatok törlése előtt. +administration#:#language_scope_added_info#:#Az összes, az adatbázisba helyiként hozzáadott bejegyzés exportálása. A fejlesztés alatt lévő változatok biztonsági mentésére lehet felhasználni a ‘Karbantartás’ lapon történő helyi változatok törlése előtt. administration#:#language_scope_commented#:#Csak a nyelvi fájlban megjegyzésekkel ellátott bejegyzések megjelenítése administration#:#language_scope_conflicts#:#Helyi és módosított változások administration#:#language_scope_dbremarks#:#Csak az adatbázisban megjegyzésekkel ellátott bejegyzések megjelenítése @@ -246,32 +246,32 @@ administration#:#language_scope_local_info#:#Az összes helyiként hozzáadott v administration#:#language_scope_merged#:#A helyi változatokat összefésülte a standard nyelvi fájllal administration#:#language_scope_merged_info#:#Standard ILIAS nyelvi fájl exportálása az összes helyi változattal együtt, modulonként és azonosítónként rendezve. Ez az ILIAS ILIAS git repository-ban lévő standard nyelvi fájl frissítésére használható. administration#:#language_scope_unchanged#:#Csak a nem változtatott bejegyzések -administration#:#language_scope_unchanged_info#:#Az összes alapértelmezett, adatbázisban meg nem változtatott bejegyzés exportálása. Ez a 'Csak a helyi változatok' ellentéte. A kettő együtt az adatbázisban jelenleg lévő összes nyelvi bejegyzés biztonsági mentése. +administration#:#language_scope_unchanged_info#:#Az összes alapértelmezett, adatbázisban meg nem változtatott bejegyzés exportálása. Ez a ‘Csak a helyi változatok’ ellentéte. A kettő együtt az adatbázisban jelenleg lévő összes nyelvi bejegyzés biztonsági mentése. administration#:#language_settings#:#Nyelvi beállítások administration#:#language_statistics#:#Statisztika -administration#:#language_translation#:#Page translation###29 10 2025 new variable +administration#:#language_translation#:#Oldalfordító administration#:#language_translation_enabled#:#Oldalfordító -administration#:#language_variables_saved#:#The changes to the language variables were saved successfully.###29 07 2022 new variable +administration#:#language_variables_saved#:#A nyelvi változók módosítását sikeresen mentette. administration#:#log_scan#:#Vizsgálati eredmények naplózása -administration#:#log_scan_desc#:#Vizsgálati eredmények mentése a kliens adatmappa 'scanlog.log' fájljába. +administration#:#log_scan_desc#:#Vizsgálati eredmények mentése a kliens adatmappa ‘scanlog.log’ fájljába. administration#:#loginname_change_blocking_time#:#Blokkolási idő a felhasználónevek cseréjéhez -administration#:#loginname_change_blocking_time_info#:#Adjon meg időtartamot napban, ameddig a felhasználók nem változtathatják meg felhasználónevüket. Ha 0-t ad meg, a felhasználók bármikor megváltoztathatják felhasználónevüket. +administration#:#loginname_change_blocking_time_info#:#Adjon meg a napok számát, ameddig a felhasználók nem változtathatják meg felhasználónevüket. Ha 0-t ad meg, a felhasználók bármikor megváltoztathatják felhasználónevüket. administration#:#loginname_change_blocking_time_invalidity_info#:#Számértéket adjon meg! -administration#:#loginname_history_info#:#Ha be van kapcsolva, a felhasználónevek cseréje bejegyzésre kerül az adatbázisba. Az előzmények a 'loginname_history' táblában érhetők el. -administration#:#nothing_to_purge#:#Nincs mit tisztítani... -administration#:#nothing_to_remove#:#Nincs mit eltávolítani... -administration#:#nothing_to_restore#:#Nincs mit helyreállítani... +administration#:#loginname_history_info#:#A felhasználónevek módosításait tároljuk az adatbázisban. Az előzmények a ‘loginname_history’ táblában érhetők el. +administration#:#nothing_to_purge#:#Nincs mit tisztítani… +administration#:#nothing_to_remove#:#Nincs mit eltávolítani… +administration#:#nothing_to_restore#:#Nincs mit helyreállítani… administration#:#obj_blga#:#Blog administration#:#obj_blga_desc#:#Blog globális beállításai administration#:#obj_chta_desc#:#Csevegés rendszerbeállításainak kezelése administration#:#obj_excs#:#Beadandó feladat administration#:#obj_excs_desc#:#Beadandó feladat globális beállításai -administration#:#obj_gsfo#:#Footer###29 10 2025 new variable -administration#:#obj_gsfo_desc#:#Administrate Footer Layout and Content###29 10 2025 new variable -administration#:#obj_impr#:#Legal Notice###26 08 2024 new variable -administration#:#obj_impr_desc#:#Deployment of Legal Notice###26 08 2024 new variable +administration#:#obj_gsfo#:#Lábléc +administration#:#obj_gsfo_desc#:#Lábléc és tartalma rendszerbeállításai +administration#:#obj_impr#:#Jogi nyilatkozat +administration#:#obj_impr_desc#:#Jogi nyilatkozat kezelése administration#:#obj_mds#:#Metaadatok -administration#:#obj_mds_desc#:#Metaadat és fejlettebb metaadat beállítások konfigurálása +administration#:#obj_mds_desc#:#Metaadat és egyéni metaadat beállítások konfigurálása administration#:#obj_otpl#:#Didaktikai sablonok administration#:#obj_otpl_desc#:#Sablon új objektum létrehozásához administration#:#obj_prfa#:#Portfólió @@ -281,7 +281,7 @@ administration#:#obj_taxs_desc#:#Taxonómia globális beállításai administration#:#org_op_edit_user_accounts#:#Felhasználói fiókok módosítása administration#:#output_options#:#Kimeneti lehetőségek administration#:#path_to_mkisofs#:#Elérési út a mkisofs-hoz -administration#:#prg_export#:#Visible in Study Programmes###26 08 2024 new variable +administration#:#prg_export#:#Látható a Képzési programokban administration#:#purge_age_limit#:#Életkorlát administration#:#purge_age_limit_desc#:#Ha ez a mező értéket tartalmaz, csak azok az objektumokat távolítjuk el véglegesen, amelyeket a megadott napok számánál régebben töröltek. administration#:#purge_count_limit#:#Számkorlát @@ -292,35 +292,39 @@ administration#:#purge_trash#:#A törölt objektumok végleges eltávolítása administration#:#purge_trash_desc#:#Az összes objektum végleges eltávolítása a lomtárból. administration#:#purge_type_limit#:#Típuskorlát administration#:#purge_type_limit_desc#:#Ha ez a mező értéket tartalmaz, csak a megadott objektumtípusok lesznek végleg eltávolítva. -administration#:#purging#:#Végleges eltávolítás... -administration#:#purging_missing_objs#:#Elveszett objektumok végleges eltávolítása... -administration#:#purging_trash#:#Lomtár ürítése... -administration#:#purging_unbound_objs#:#Kapcsolódás nélküli objektumok végleges eltávolítása... -administration#:#removing_invalid_childs#:#Érvénytelen keresőfa-bejegyzések eltávolítása... +administration#:#purging#:#Végleges eltávolítás… +administration#:#purging_missing_objs#:#Elveszett objektumok végleges eltávolítása… +administration#:#purging_trash#:#Lomtár ürítése… +administration#:#purging_unbound_objs#:#Kapcsolódás nélküli objektumok végleges eltávolítása… +administration#:#removing_invalid_childs#:#Érvénytelen keresőfa-bejegyzések eltávolítása… administration#:#removing_invalid_refs#:#Érvénytelen hivatkozások eltávolítása -administration#:#removing_invalid_rolfs#:#Érvénytelen szerepmappák eltávolítása... +administration#:#removing_invalid_rolfs#:#Érvénytelen szerepkörmappák eltávolítása… administration#:#repair_options#:#Javítási beállítások administration#:#restore_missing#:#Elveszett objektumok visszaállítása administration#:#restore_missing_desc#:#Elveszett és kapcsolódás nélküli objektumok visszaállítása a helyreállító mappába. administration#:#restore_trash#:#Törölt objektumok visszaállítása administration#:#restore_trash_desc#:#A lomtárban levő összes objektum visszaállítása a helyreállító mappába. -administration#:#restoring#:#Helyreállítás... -administration#:#restoring_missing_objs#:#Elveszett objektumok visszaállítása... -administration#:#restoring_trash#:#Törölt objektumok visszaállítása... -administration#:#restoring_unbound_objs#:#Kapcsolódás nélküli objektumok és alobjektumok visszaállítása... -administration#:#reuse_of_loginnames_contained_in_history#:#Felhasználónevek újra felhasználhatóak -administration#:#reuse_of_loginnames_contained_in_history_info#:#Ha be van kapcsolva, a felhasználó újra használtatja a korábbi felhasználóneveket (még abban az esetben is, ha a felhasználónév törölt felhasználóhoz tartozik). +administration#:#restoring#:#Helyreállítás… +administration#:#restoring_missing_objs#:#Elveszett objektumok visszaállítása… +administration#:#restoring_trash#:#Törölt objektumok visszaállítása… +administration#:#restoring_unbound_objs#:#Kapcsolódás nélküli objektumok és alobjektumok visszaállítása… +administration#:#reuse_of_loginnames_contained_in_history#:#Felhasználónevek újra felhasználhatók +administration#:#reuse_of_loginnames_contained_in_history_info#:#A felhasználó újra használtatja a korábbi felhasználóneveket (még abban az esetben is, ha a felhasználónév törölt felhasználóhoz tartozik). +administration#:#rpc_pdf_configuration#:#PDF-generálás +administration#:#rpc_pdf_font#:#Betűtípusok +administration#:#rpc_pdf_font_info#:#További betűtípusok PDF fájlok létrehozásához. A ‘Helvetica’ és az ‘unifont’ betűtípusoktól eltérőket telepíteni kell az ILIAS szerverre. +administration#:#rpc_pdf_generation#:#Betűtípusok PDF létrehozásához administration#:#scan#:#Vizsgálat administration#:#scan_desc#:#Rendszer átvizsgálása korrupt/érvénytelen/elveszett/kapcsolódás nélküli objektumok után. administration#:#scan_details#:#Vizsgálat részletei administration#:#scan_modes#:#Használt vizsgálati módok -administration#:#scanning_system#:#Rendszer átvizsgálása... -administration#:#searching_deleted_objs#:#Törölt objektumok keresése... -administration#:#searching_invalid_childs#:#Érvénytelen fabejegyzések keresése... -administration#:#searching_invalid_refs#:#Érvénytelen hivatkozások keresése... -administration#:#searching_invalid_rolfs#:#Érvénytelen szerepmappák keresése... -administration#:#searching_missing_objs#:#Elveszett objektumok keresése... -administration#:#searching_unbound_objs#:#Kapcsolódás nélküli objektumok keresése... +administration#:#scanning_system#:#Rendszer átvizsgálása… +administration#:#searching_deleted_objs#:#Törölt objektumok keresése… +administration#:#searching_invalid_childs#:#Érvénytelen fabejegyzések keresése… +administration#:#searching_invalid_refs#:#Érvénytelen hivatkozások keresése… +administration#:#searching_invalid_rolfs#:#Érvénytelen szerepkörmappák keresése… +administration#:#searching_missing_objs#:#Elveszett objektumok keresése… +administration#:#searching_unbound_objs#:#Kapcsolódás nélküli objektumok keresése… administration#:#skipped#:#kihagyva administration#:#start_scan#:#Indítás! administration#:#svn_path#:#Útvonal: %s @@ -328,7 +332,7 @@ administration#:#svn_revision_current#:#Jelenlegi revízió: %s administration#:#svn_revision_last_change#:#Utoljára módosított revízió: %s administration#:#svn_root#:#Gyökér: %s administration#:#system_check_no_owner#:#Tulajdonos nélküli objektumok -administration#:#system_folder_info#:#Please choose an item from the administration main menu.###29 10 2025 new variable +administration#:#system_folder_info#:#Válasszon egy elemet a Rendszerbeállítások » Főmenü részben. administration#:#systemcheck#:#Rendszerellenőrzés administration#:#tree_corrupt#:#A faszerkezet megsérült! A részletekért nézze meg a vizsgálati naplót. administration#:#user_criteria#:#Egyedi felhasználói kritérium @@ -338,72 +342,72 @@ administration#:#vc_information#:#SVN verzió megjelenítése administration#:#vc_information_not_determined#:#ILIAS nem tudja megállapítani az verzióinformációt. administration#:#view_last_log#:#Utolsó átvizsgálás napló megtekintése administration#:#view_log#:#Részletek megtekintése -adn#:#action_confirm_delete#:#Delete Notifications###26 08 2024 new variable -adn#:#action_confirm_delete_msg#:#Would you like to delete the following notification(s)?###26 08 2024 new variable -adn#:#administrative_notification#:#Administrative Notifications -adn#:#administrative_notification_description#:#Provide system-wide notifications in topbar of ILIAS -adn#:#btn_cancel#:#Cancel -adn#:#btn_delete#:#Delete -adn#:#btn_delete_confirm#:#Would you like to delete this Notification? -adn#:#btn_duplicate#:#Duplicate###26 08 2024 new variable -adn#:#btn_edit#:#Edit -adn#:#btn_reset#:#Reset -adn#:#btn_reset_confirm#:#Would you like to reset this Notification for all Users? -adn#:#common_actions#:#Actions -adn#:#common_add_msg#:#Add Notification -adn#:#main#:#Notifications -adn#:#msg_body#:#Body -adn#:#msg_body_info#:#Body of the Notification -adn#:#msg_dismissable#:#Dismissable -adn#:#msg_dismissable_info#:#Notifications can be closed by the user. The user won't see this notification again. -adn#:#msg_display_date_end#:#Displayed Until -adn#:#msg_display_date_start#:#Displayed From -adn#:#msg_error_false_date_configuration#:#Can't create a notification with this configuration of dates. The event must be within the display time.###29 07 2022 new variable -adn#:#msg_event_date_end#:#Event Ends -adn#:#msg_event_date_start#:#Event Starts -adn#:#msg_form_title#:#Notification -adn#:#msg_has_language_limitation#:#Limited to selected languages###26 08 2024 new variable -adn#:#msg_has_language_limitation_info#:#Only selected languages will see the notification.###26 08 2024 new variable -adn#:#msg_languages#:#Languages###26 08 2024 new variable -adn#:#msg_limit_to_roles#:#Role-sensitive Presentation -adn#:#msg_limit_to_roles_info#:#Only the selected roles will see the notification. -adn#:#msg_limited_to_role_ids#:#Roles -adn#:#msg_permanent#:#Display -adn#:#msg_permanent_info#:#Display Notifications permanently or temporarily -adn#:#msg_permanent_no#:#Show Temporarily -adn#:#msg_permanent_yes#:#Show Permanently -adn#:#msg_presentation#:#Presentation###26 08 2024 new variable -adn#:#msg_show_to_all_languages#:#Show to all languages###26 08 2024 new variable -adn#:#msg_show_to_all_roles#:#Show to all roles###26 08 2024 new variable -adn#:#msg_show_to_all_roles_info#:#All users even when not logged-in will see notification.###26 08 2024 new variable -adn#:#msg_success_created#:#Notification created -adn#:#msg_success_deleted#:#Notification sucessfully deleted -adn#:#msg_success_duplicated#:#Notification sucessfully duplicated###26 08 2024 new variable -adn#:#msg_success_reset#:#Notification reset -adn#:#msg_success_updated#:#Notification updated###29 07 2022 new variable -adn#:#msg_table_title#:#Notifications -adn#:#msg_title#:#Headline -adn#:#msg_title_info#:#Short Headline of the Notification -adn#:#msg_type#:#Importance -adn#:#msg_type_0#:#Notice###29 07 2022 new variable -adn#:#msg_type_1#:#Notice -adn#:#msg_type_2#:#Important -adn#:#msg_type_3#:#Breaking News -adn#:#msg_type_during_event#:#During Event -adn#:#msg_type_info#:#the importance has an influence on the color representation of the notification +adn#:#action_confirm_delete#:#Értesítések törlése +adn#:#action_confirm_delete_msg#:#Biztos, hohgy törli a következő értesítés(eke)t? +adn#:#administrative_notification#:#Rendszerértesítések +adn#:#administrative_notification_description#:#Rendszerértesítések megjelenítésének lehetősége az ILIAS felső sávjában +adn#:#btn_cancel#:#Mégsem +adn#:#btn_delete#:#Törlés +adn#:#btn_delete_confirm#:#Biztos, hogy törli ezt az értesítést? +adn#:#btn_duplicate#:#Duplikálás +adn#:#btn_edit#:#Módosítás +adn#:#btn_reset#:#Reszetelés +adn#:#btn_reset_confirm#:#Biztos, hogy alapértékre álítja ezt az értesítést az összes felhasználónál? +adn#:#common_actions#:#Műveletek +adn#:#common_add_msg#:#Értesítés létrehozása +adn#:#main#:#Értesítések +adn#:#msg_body#:#Szöveg +adn#:#msg_body_info#:#Az értesítés szövege. +adn#:#msg_dismissable#:#Levehető +adn#:#msg_dismissable_info#:#A felhasználók az értesítést bezárhassák-e. Bezárás után az értesítés többet nem jelenik meg. +adn#:#msg_display_date_end#:#Megjelenés eddig +adn#:#msg_display_date_start#:#Megjelenés ekkortól +adn#:#msg_error_false_date_configuration#:#Az értesítés nem hozható létre ezekkel a időpontokkal. Az eseménynek a megjelenítési idő között kell lennie. +adn#:#msg_event_date_end#:#Esemény vége +adn#:#msg_event_date_start#:#Esemény eleje +adn#:#msg_form_title#:#Értesítés +adn#:#msg_has_language_limitation#:#Korlátozás a telpeített nyelvekre +adn#:#msg_has_language_limitation_info#:#Csak a kijelölt nyelveken jelennek meg az értesítések +adn#:#msg_languages#:#Nyelvek +adn#:#msg_limit_to_roles#:#Szerepkörfüggő megjelenítés +adn#:#msg_limit_to_roles_info#:#Csak a kijelölt szerepkörök tagjainak jelenik meg az értesítés. +adn#:#msg_limited_to_role_ids#:#Szerepkörök +adn#:#msg_permanent#:#Megjelenítés +adn#:#msg_permanent_info#:#Megadható, hogy az értesítés állandó vagy ideiglenes legyen-e. +adn#:#msg_permanent_no#:#Ideiglenesen +adn#:#msg_permanent_yes#:#Állandóan +adn#:#msg_presentation#:#Megjelenítés +adn#:#msg_show_to_all_languages#:#Megjelenítés az összes nyelven +adn#:#msg_show_to_all_roles#:#Megjelenítés az összes szerepkörnek +adn#:#msg_show_to_all_roles_info#:#Mindenki, még a be nem jelentkezett felhasználók is látni fogják ezt az értesítést. +adn#:#msg_success_created#:#Az értesítést sikeresen létrehozta +adn#:#msg_success_deleted#:#Az értesítést sikeresen törölte +adn#:#msg_success_duplicated#:#Az értesítést sikeresen duplikálta +adn#:#msg_success_reset#:#Az értesítést sikeresen alapértékre állította +adn#:#msg_success_updated#:#Az értesítést sikeresen módosította +adn#:#msg_table_title#:#Értesítések +adn#:#msg_title#:#Tárgy +adn#:#msg_title_info#:#Az értesítés rövid tárgya. +adn#:#msg_type#:#Fontosság +adn#:#msg_type_0#:#Értesítés +adn#:#msg_type_1#:#Értesítés +adn#:#msg_type_2#:#Fontos +adn#:#msg_type_3#:#Friss hírek +adn#:#msg_type_during_event#:#Esemény közben +adn#:#msg_type_info#:#A fontosság az értesítés színét határozza meg. adve#:#advanced_editing_excass_settings#:#Beadandó szöveges feladatok adve#:#advanced_editing_tst_editing#:#Lapszerkesztő használata a további kérdéstartalom szerkesztéséhez adve#:#advanced_editing_tst_editing_desc#:#Kapcsolja be az ILIAS-lapszerkesztőt a visszajelzések és a súgószövegek szerkesztéséhez. adve#:#adve_activation#:#Aktiválás adve#:#adve_auto_url_linking#:#URL Auto-linkelés -adve#:#adve_auto_url_linking_info#:#Megpróbáljuk megtalálni a szövegben lévő az URL-eket ('http://..') és automatikusa linkké alakítjuk. -adve#:#adve_autosave#:#Automatic Saving Intervall -adve#:#adve_autosave_info#:#Auto-save for text content. With shorter intervals, the server load increases and the performance of the system decreases. -adve#:#adve_autosave_info_min_10#:#Please choose a value of minimal 10 seconds if you activated this feature.###29 07 2022 new variable +adve#:#adve_auto_url_linking_info#:#Megpróbáljuk megtalálni a szövegben lévő az URL-eket (http://…) és automatikusa linkké alakítjuk. +adve#:#adve_autosave#:#Automatikus mentési időköz +adve#:#adve_autosave_info#:#Szöveges tartalom mentésének gyakorsága. A rövidebb időköz növeli a szerver terhelését. +adve#:#adve_autosave_info_min_10#:#Kérem, legalább 10 mp-es értéket állítson be. adve#:#adve_blocking_mode#:#Szerkesztés zárolása adve#:#adve_excass_settings#:#Beadandó feladatok adve#:#adve_grp_copa#:#Tartalomlapok -adve#:#adve_grp_frm#:#Forums###29 07 2022 new variable +adve#:#adve_grp_frm#:#Fórumok adve#:#adve_grp_glo#:#Fogalomtárak adve#:#adve_grp_lm#:#ILIAS-tananyagok adve#:#adve_grp_rep#:#Tartalomtároló-lapok @@ -418,10 +422,10 @@ adve#:#adve_rte_settings#:#TinyMCE szerkesztő adve#:#adve_text_content_features#:#Szövegtartalom menü adve#:#adve_use_physical#:#b/i/u használata str/emp/imp helyett adve#:#adve_use_physical_info#:#Ez a beállítás lecseréli a félkövér, dőlt, aláhúzott (strong, emphatic, important) szemantikus stílusosztályokhoz tartozó gombokat b (bold), i (italic), u (underline) fizikai attribútumok gombjaira. Ne feledje, hogy ez inkonzisztenciát okozhat, ha a stílusszerkesztőt használ és más fizikai attribútumokat rendelt a strong/emphatic/important stílusosztályokhoz. -adve#:#adve_use_tiny_mce#:#TinyMCE engedélyezése WYSIWYG szerkesztéshez -assessment#:#activate_logging#:#Teszt és értékelés naplózásának bekapcsolása -assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable -assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable +adve#:#adve_use_tiny_mce#:#TinyMCE szerkesztő engedélyezése WYSIWYG szerkesztéshez +assessment#:#activate_logging#:#Teszt és értékelés naplózása +assessment#:#activate_manual_scoring#:#Manuális pontozás bekapcsolása +assessment#:#activate_manual_scoring_desc#:#Maunális pontozás bekapcsolása az összes kérdéstípushoz assessment#:#addSuggestedSolution#:#Ismétlő összefoglaláshoz tartalom hozzáadása assessment#:#add_answers#:#Válasz hozzáadása assessment#:#add_circle#:#Kör alakú terület hozzáadása @@ -429,16 +433,16 @@ assessment#:#add_gap#:#Kiegészítendő szöveg hozzáadása assessment#:#add_imagemap#:#Képtérkép importálása assessment#:#add_poly#:#Sokszög alakú terület hozzáadása assessment#:#add_rect#:#Téglalap alakú terület hozzáadása -assessment#:#add_users#:#Add Users###28 10 2024 new variable +assessment#:#add_users#:#Felhasználók hozzáadása assessment#:#additional_rating_info#:#Figyeljen arra, hogy az itt megadott érték százalékot jelentenek, és összegük 100 kell, hogy legyen. assessment#:#advanced_rating#:#Fejlett értékelés assessment#:#advanced_rating_info#:#A fejlett értékelés csak akkor elérhető, ha a végeredményhez hozzá van rendelve egy mértékegység. További értékelési beállítások az érintett mértékegység mentése után jelennek meg. assessment#:#all_available_question_pools#:#Összes elérhető kérdésgyűjtemény -assessment#:#all_participants#:#Összes résztvevő +assessment#:#all_participants#:#Összes kitöltő assessment#:#allow_images#:#Képsegítség válaszokhoz assessment#:#allowedextensions#:#Engedélyezett fájlkiterjesztések assessment#:#allowedextensions_info#:#Sorolja fel vesszővel tagolva az engedélyezett fájlkiterjesztéseket, amennyiben korlátozni szeretné a feltölthető fájltípusokat (például: doc, xls, odt). -assessment#:#already_added_extra_time#:#already added: %s min###28 10 2024 new variable +assessment#:#already_added_extra_time#:#már hozzáadott %s percet assessment#:#analyze_errortext#:#Szöveg elemzése assessment#:#answer#:#Válasz assessment#:#answer_characters#:# az engedélyezett karakterek száma, a válasz karaktereinek száma: @@ -447,7 +451,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Szerzett pontot a megoldásár assessment#:#answer_is_right#:#A megoldása helyes assessment#:#answer_is_wrong#:#A megoldása rossz assessment#:#answer_of#:#Válasz -assessment#:#answer_options#:#Válaszlehetőségek: assessment#:#answer_question#:#Kérdés megválaszolása assessment#:#answer_text#:#Válaszszöveg assessment#:#answer_types#:#Válaszokhoz szerkesztő @@ -468,7 +471,7 @@ assessment#:#assFlashQuestion#:#Flash-kérdés assessment#:#assFormulaQuestion#:#Képletkérdés assessment#:#assImagemapQuestion#:#Aktív terület/képtérképes kérdés assessment#:#assKprimChoice#:#Többválaszos kérdés (Kprim válaszok) -assessment#:#assLongMenu#:#'Étlap'-kérdés +assessment#:#assLongMenu#:#‘Étlap’-kérdés assessment#:#assMatchingQuestion#:#Párosító kérdés assessment#:#assMultipleChoice#:#Többválaszos kérdés (jelölőnégyzetes) assessment#:#assNumeric#:#Számszerű kérdés @@ -483,31 +486,30 @@ assessment#:#ass_cloze_fb_mode_gap_answ#:#Válaszfüggő visszajelzés assessment#:#ass_cloze_fb_mode_gap_answ_info#:#Minden szöveghelyhez és eltérő válaszhoz más-más visszajelzés állítható be. assessment#:#ass_cloze_fb_mode_gap_qst#:#Visszajelzés résenként assessment#:#ass_cloze_fb_mode_gap_qst_info#:#Minden szöveghelyhez egy egyszerű visszajelzés állítható be. -assessment#:#ass_cloze_gap_fb_gap_label#:#'%s' szöveghely: %s -assessment#:#ass_cloze_gap_fb_num_empty_label#:#'%s' szöveghely - Nincs bemenet -assessment#:#ass_cloze_gap_fb_num_rangehit_label#:#'%s' szöveghely - Tartománytalálat -assessment#:#ass_cloze_gap_fb_num_toohigh_label#:#'%s' szöveghely - Túl magas érték -assessment#:#ass_cloze_gap_fb_num_toolow_label#:#'%s' szöveghely - Túl alacsony érték -assessment#:#ass_cloze_gap_fb_num_valuehit_label#:#'%s' szöveghely - Értéktalálat -assessment#:#ass_cloze_gap_fb_sel_empty_label#:#'%s' szöveghely - Nincs választás -assessment#:#ass_cloze_gap_fb_sel_opt_label#:#'%s' szöveghely - Lehetőség kiválasztása: %s -assessment#:#ass_cloze_gap_fb_txt_empty_label#:#'%s' szöveghely - Nincs bemenet -assessment#:#ass_cloze_gap_fb_txt_match_label#:#'%s' szöveghely - Adott válasz: %s -assessment#:#ass_cloze_gap_fb_txt_nomatch_label#:#'%s' szöveghely - Hibás válasz +assessment#:#ass_cloze_gap_fb_gap_label#:#‘%s’ szöveghely: %s +assessment#:#ass_cloze_gap_fb_num_empty_label#:#‘%s’ szöveghely - Nincs bemenet +assessment#:#ass_cloze_gap_fb_num_rangehit_label#:#‘%s’ szöveghely - Tartománytalálat +assessment#:#ass_cloze_gap_fb_num_toohigh_label#:#‘%s’ szöveghely - Túl magas érték +assessment#:#ass_cloze_gap_fb_num_toolow_label#:#‘%s’ szöveghely - Túl alacsony érték +assessment#:#ass_cloze_gap_fb_num_valuehit_label#:#‘%s’ szöveghely - Értéktalálat +assessment#:#ass_cloze_gap_fb_sel_empty_label#:#‘%s’ szöveghely - Nincs választás +assessment#:#ass_cloze_gap_fb_sel_opt_label#:#‘%s’ szöveghely - Lehetőség kiválasztása: %s +assessment#:#ass_cloze_gap_fb_txt_empty_label#:#‘%s’ szöveghely - Nincs bemenet +assessment#:#ass_cloze_gap_fb_txt_match_label#:#‘%s’ szöveghely - Adott válasz: %s +assessment#:#ass_cloze_gap_fb_txt_nomatch_label#:#‘%s’ szöveghely - Hibás válasz assessment#:#ass_commented_questions_only#:#Csak azok a kérdések, melyekhez hozzászóltak assessment#:#ass_comments#:#Hozzászólások -assessment#:#ass_competence_respect_level_ordering#:#Figyeljen arra, hogy a kompetencia-küszöbértékeket az elérhető szintek alapján növekvő sorrendben szükséges megadni. +assessment#:#ass_competence_respect_level_ordering#:#Figyeljen arra, hogy a kompetencia-küszöbértékeket az elérhető kompetenciaszintek alapján növekvő sorrendben szükséges megadni. assessment#:#ass_completion_by_submission#:#Befejezve elküldéssel -assessment#:#ass_completion_by_submission_info#:#Ha be van kapcsolva, legalább egy fájl elküldése ennek a kérdésnek a teljesítését jelenti a maximális pontszám megszerzésével. A pont a későbbiekben manuálisan módosítható. Ennek a beállításnak a bekapcsolása nincs hatással a már beküldött megoldásokra. -assessment#:#ass_create_export_file_with_results#:#Export fájl létrehozása (résztvevők eredményeivel) +assessment#:#ass_completion_by_submission_info#:#Legalább egy fájl elküldése ennek a kérdésnek a teljesítését jelenti a maximális pontszám megszerzésével. A pont a későbbiekben manuálisan módosítható. Ennek a beállításnak a bekapcsolása nincs hatással a már beküldött megoldásokra. +assessment#:#ass_create_export_file_with_results#:#Export fájl létrehozása (kitöltők eredményeivel) assessment#:#ass_create_export_test_archive#:#Tesztarchívum fájl létrehozása -assessment#:#ass_create_question#:#Kérdés létrehozása assessment#:#ass_imap_hint#:#Tippek buboréksúgóként jelenjenek meg assessment#:#ass_imap_map_file_not_readable#:#A feltöltött képtérkép nem olvasható. assessment#:#ass_imap_no_map_found#:#Egy űrlap sem található a feltöltött képtérképben. assessment#:#ass_lac_expression#:#Kifejezés assessment#:#ass_lac_show_legend_btn#:#Jelmagyarázat megjelenítése -assessment#:#ass_lac_unable_to_parse_condition#:#'%s' feltétel nem validálható. +assessment#:#ass_lac_unable_to_parse_condition#:#‘%s’ feltétel nem validálható. assessment#:#ass_lac_validation_error#:#Hiba a feltételes kifejezés(ek) validálása során! assessment#:#ass_location#:#Helyszín assessment#:#ass_mc_sel_lim_exhausted_hint#:#Ne jelöljön ki %s válasznál többet %s válaszlehetőségből! @@ -531,25 +533,25 @@ assessment#:#assessment_pool_selection#:#Gyűjtemény kiválasztása assessment#:#assessment_scoring_adjust#:#Utólagos korrekció engedélyezése assessment#:#assessment_scoring_adjust_desc#:#Az utólagos korrekció engedélyezése a kérdések módosítását teszi lehetővé a tesztben. assessment#:#autocomplete_error#:#Az automatikus kiegészítés értéke túl nagy szám. Mivel válaszai rövidebbek, azok sosem fognak megjelenni. -assessment#:#autoparticipants_subtab#:#Résztvevők +assessment#:#autoparticipants_subtab#:#Kitöltők assessment#:#autosave#:#Automatikus mentés assessment#:#autosave_failed#:#Az automatikus mentés sikertelen volt! -assessment#:#autosave_info#:#A válaszokat meghatározott időközönként automatikusan mentjük, az adatvesztés elkerülése érdekében. +assessment#:#autosave_info#:#Az ILIAS automatikusan elmenti a felhasználók válaszait a legutóbb megnyitott kérdésre. Mivel ezek az automatikusan mentett válaszok nem minősülnek a felhasználó által adott válaszoknak, ezért ezeket az ILIAS nem veszi figyelembe az automatizált értékelés során. Az automatikusan mentett válaszokat mindig manuálisan kell kiértékelni, azok nem jelennek meg az adott felhasználó eredménynézetében sem. A válaszok automatikus mentése csak vészhelyzetekre szolgál, ilyen lehet például a böngészőablak véletlen bezárása. assessment#:#autosave_ival#:#Időköz -assessment#:#autosave_success#:#Az automatikus mentés sikeres... -assessment#:#autosavecontent#:#Autosave Content###29 07 2022 new variable +assessment#:#autosave_success#:#Az automatikus mentés sikeres… +assessment#:#autosavecontent#:#Tartalom automatikus mentése assessment#:#average_reached_points#:#Elért pontok átlaga assessment#:#back_to_objective_container#:#Ugrás a kurzushoz -assessment#:#backtocallingpage#:#Back to the question page###29 07 2022 new variable -assessment#:#backtocallingpool#:#Back to the question pool###29 07 2022 new variable +assessment#:#backtocallingpage#:#Vissza a kérdésoldalra +assessment#:#backtocallingpool#:#Vissza a kérdésgyűjteményhez assessment#:#backtocallingtest#:#Vissza a teszthez assessment#:#baseunit#:#Alapmértékegység -assessment#:#broken_test#:#Broken Test###29 10 2025 new variable -assessment#:#bulkedit_author#:#Set Author###28 10 2024 new variable -assessment#:#bulkedit_lifecycle#:#Set Lifecycle###28 10 2024 new variable -assessment#:#bulkedit_taxonomies#:#Set Taxonomies###28 10 2024 new variable +assessment#:#broken_test#:#Törött teszt +assessment#:#bulkedit_author#:#Szerző beállítása +assessment#:#bulkedit_lifecycle#:#Életcilklus beállítása +assessment#:#bulkedit_taxonomies#:#Taxonómiák beállítása assessment#:#cancel_test#:#Teszt felfüggesztése -assessment#:#cannot_edit_marks#:#Felhasználók már töltik a tesztet. Az érdemjegyeket csak akkor változtathatja meg, ha a Jelentés a ponteredményekről engedélyezett, és a jelentési dátum még nem érkezett el. +assessment#:#cannot_edit_marks#:#Néhány felhasználók már kitöltötte a tesztet. Az érdemjegyeket csak akkor módosíthatja, ha a ‘Hozzáférés a teszteredményekhez’ dátum be van állítva és az jövőbeni. assessment#:#cannot_edit_test#:#Nincs megfelelő jogosultsága a teszt módosításához. assessment#:#cannot_execute_test#:#Nincs megfelelő jogosultsága a teszt futtatásához. assessment#:#cannot_export_archive#:#Export archívum fájl nem hozható létre. @@ -564,17 +566,13 @@ assessment#:#checkbox_unchecked#:#Nem kiválasztott assessment#:#circle#:#Kör assessment#:#circle_click_center#:#Kattintson a kívánt terület középpontjába. assessment#:#circle_click_circle#:#Kattintson a kívánt terület körvonalának egy pontjára. -assessment#:#client_ip_range#:#Client IP Range###28 10 2024 new variable +assessment#:#client_ip_range#:#Kliens IP-tartománya assessment#:#clientip#:#Kliens-IP -assessment#:#close_text_hint#:#Új kitöltendő hely létrehozásához vigye a kurzort a kívánt helyre, majd használja a 'Szöveghely' legördülőt. A megfelelő szerkesztési szakaszok megjelennek alatta. A kitöltendő helyeket szerkesztheti úgy is, hogy kitöltendő részen belül a kitöltendő szövegre kattint. -assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer text will be deleted when the form is saved.###26 08 2024 new variable +assessment#:#close_text_hint#:#Új kitöltendő hely létrehozásához vigye a kurzort a kívánt helyre, majd használja a ‘Szöveghely’ legördülőt. A megfelelő szerkesztési szakaszok megjelennek alatta. A kitöltendő helyeket szerkesztheti úgy is, hogy kitöltendő részen belül a kitöltendő szövegre kattint. +assessment#:#cloze_answer_text_info#:#A válaszszöveg előtti és utáni szóközök mentéskor törlődnek. assessment#:#cloze_fixed_textlength#:#Szövegmező hossza assessment#:#cloze_fixed_textlength_description#:#Ha megad egy értéket, akkor az összes szöveg- és szám mező evvel a rögzített hosszal kerül létrehozásra, így nincs lehetőség a több karakter bevitelére. Szövegmezőknek lehet saját korlátjuk a karakterszámra. Számmezők esetén a tizedesvessző is egy karakternek számít. assessment#:#cloze_gap_size_info#:#Ha 0-nál nagyobb értéked ad meg, ilyen hosszúságú lesz a szövegmező. Amennyiben nem ad meg értéket, a globális hossz lesz ez az érték. -assessment#:#cloze_text#:#Kiegészítendő szöveg -assessment#:#cloze_textgap_case_insensitive#:#Kis-/nagybetűre nem érzékeny -assessment#:#cloze_textgap_case_sensitive#:#Kis-/nagybetűre érzékeny -assessment#:#cloze_textgap_levenshtein_of#:#'%s' Levenshtein-távolsága assessment#:#code#:#Kód assessment#:#codebase#:#Kódbázis assessment#:#concatenation#:#Szavak összekapcsolása @@ -585,33 +583,33 @@ assessment#:#coordinates#:#Koordináták assessment#:#copy_and_link_to_questionpool#:#Hozzáadás kérdésgyűjteményhez assessment#:#copy_no_questions_selected#:#Válasszon ki legalább egy kérdést a másoláshoz! assessment#:#copy_questions_success#:#A kérdés(eke)t másolta. -assessment#:#correct_answers#:#Helyes válaszok +assessment#:#correct_answers#:#Helyes válaszok: assessment#:#counter#:#Számláló assessment#:#create_gaps#:#Kitöltendő helyek létrehozása és frissítése assessment#:#create_new#:#új létrehozása -assessment#:#created#:#Created###28 10 2024 new variable +assessment#:#created#:#Létrehozta assessment#:#customstyle#:#Egyéni stílus -assessment#:#dashboard_tab#:#Műszerfal +assessment#:#dashboard_tab#:#Kitöltők assessment#:#definition#:#Definíció assessment#:#definition_image#:#Definíciókép assessment#:#definition_text#:#Definíciószöveg assessment#:#definitions#:#Definíciók assessment#:#deleteSuggestedSolution#:#Ezen tartalom eltávolítása -assessment#:#delete_all_user_data_confirmation#:#Biztos, hogy eltávolítja ebben a tesztben minden felhasználó tesztadatát? +assessment#:#delete_all_user_data_confirmation#:#Biztos, hogy eltávolítja ebben a teszt összes kitöltőjének tesztadatát? assessment#:#delete_image_header#:#Kép eltávolítása assessment#:#delete_image_question#:#Biztos, hogy eltávolítja a képet? -assessment#:#delete_mark_confirmation#:#Are you sure you want to delete the following mark?###29 10 2025 new variable -assessment#:#delete_participants_no_valid_participants_selected#:#Test results already exist for the selected participant(s). They therefore cannot be removed.###29 10 2025 new variable -assessment#:#delete_result_no_valid_participants_selected#:#There are no test results for the selected participants, so they cannot be removed.###29 10 2025 new variable -assessment#:#delete_selected_user_data_confirmation#:#Biztos, hogy eltávolítja a kiválasztott felhasználók tesztadatait? +assessment#:#delete_mark_confirmation#:#ABiztos, hogy eltávolítja a jegyet? +assessment#:#delete_participants_no_valid_participants_selected#:#A kiválasztott kitöltőkhöz már léteznek eredmények, ezért ezek nem távolíthatók el. +assessment#:#delete_result_no_valid_participants_selected#:#A kiválasztott kitöltőkhöz még léteznek eredmények, ezért ezek nem távolíthatók el. +assessment#:#delete_selected_user_data_confirmation#:#Biztos, hogy eltávolítja a kiválasztott felhasználó tesztadatait? assessment#:#delete_user_data#:#A kiválasztott felhasználók tesztadatinak eltávolítása assessment#:#description_maxchars#:#Ha üres, ennek a szöveges válasznak a maximális karakterszáma nincs korlátozva. -assessment#:#detail_ending_time_reached#:#A tesztre előírt idő lejárt. A teszt nem elérhető % óta -assessment#:#detail_max_processing_time_reached#:#Lejárt a teszt kitöltési ideje. -assessment#:#detail_starting_time_not_reached#:#Még nem érkezett el a tesztkitöltés kezdő időpontja. A teszt %s időponttól lesz elérhető. +assessment#:#detail_ending_time_reached#:#A teszt befejezesére rendelkezésre álló idő lejárt. A teszt nem elérhető % óta +assessment#:#detail_max_processing_time_reached#:#A tesztet nem folytathaja, mert elérte a maximálisan engedélyezett kitöltési időt. +assessment#:#detail_starting_time_not_reached#:#Még nem indíthatja el a tesztet. A teszt kezdő időpontja: %s assessment#:#detailed_evaluation#:#Részletes értékelés assessment#:#detailed_evaluation_for#:#Részletes értékelés - %s -assessment#:#detailed_evaluation_missing_active_id#:#Részletes értékelést kell kérni a kiválasztott résztvevőhöz! +assessment#:#detailed_evaluation_missing_active_id#:#Részletes értékelést kell kérni a kiválasztott kitöltőhöz! assessment#:#detailed_evaluation_show#:#Részletes értékelés megjelenítése assessment#:#detailed_output_printview#:#Részletes eredmény kérdés-nyomtatási képekkel assessment#:#detailed_output_solutions#:#Részletes eredmény kérdésmegoldásokkal @@ -619,33 +617,33 @@ assessment#:#direct_feedback#:#Válasz ellenőrzése assessment#:#discard_answer#:#Válasz törlése assessment#:#discard_answer_confirmation#:#Válaszát végérvényesen törölni készül. Bármikor új választ adhat a kérdésre, de a jelenlegi választ végérvényesen töröli.

    Biztos, hogy törli válaszát? assessment#:#dont_use_questionpool#:#Ne illessze be a kérdéseket kérdésgyűjteménybe (csak ebben a tesztben elérhetők). -assessment#:#download_all_files#:#Download All Files###28 10 2024 new variable +assessment#:#download_all_files#:#Összes fájl letöltése assessment#:#duplicate#:#Másodpéldány létrehozása assessment#:#duplicate_matching_values_selected#:#Többszörösen illeszkedő értékeket választott ki. assessment#:#duplicate_order_values_entered#:#Többszörös sorrendi értékeket adott meg. assessment#:#edit_answer#:#Válasz módosítása -assessment#:#edit_concluding_remarks#:#Edit Concluding Remarks###26 08 2024 new variable -assessment#:#edit_introduction#:#Edit Introduction###26 08 2024 new variable +assessment#:#edit_concluding_remarks#:#Záró megjegyzések szerkesztése +assessment#:#edit_introduction#:#Útmutató szerkesztése assessment#:#edit_question#:#Kérdés módosítása -assessment#:#edit_score#:#Edit Score###29 10 2025 new variable +assessment#:#edit_score#:#Pontszám módosítása assessment#:#edit_test_questions#:#Listanézet assessment#:#element_height#:#Minimum magasság assessment#:#element_height_info#:#Ez a minimális magasság pixelben a kifejezés és definíció/kép elemek számára a tesztkimenethez. assessment#:#enable_examview#:#Adott válaszok áttekintése -assessment#:#enable_examview_desc#:#A résztvevők beadás előtt áttekinthetik az összes kérdést és a kérdésekre adott válaszaikat. +assessment#:#enable_examview_desc#:#A teszt befejezésére kattinta a kitöltőknek megjelenik az összes kérdés és a kérdésekre adott válaszaik. Innen még vissza tudnak menni, hogy módosítsák válaszaikat, amíg azokat nem zárolták. assessment#:#end_tag#:#Zárócímke assessment#:#enlarge#:#növelés -assessment#:#enter_anonymous_code#:#Adja meg az anonymous felhasználó belépési kódját +assessment#:#enter_anonymous_code#:#A teszt folytatásához adja meg a hozzáférési kódot: assessment#:#enter_enough_positive_points#:#A maximálisan elérhető pontszámnak magasabbnak kell lennie 0-nál. Megfelelő, nem negatív pontszámokat adjon válaszaihoz. assessment#:#enter_enough_positive_points_checked#:#A pontozáshoz legalább egy választ meg kell adnia. Kérjük, adjon meg egy pozitív számot a válasz megjelöléséhez. assessment#:#enter_valid_values#:#Érvényes számot adj meg! Karakterek hibásan lesznek értékelve! assessment#:#errFormulaQuestion#:#A képlet-kérdés hibás információt tartalmaz! assessment#:#errRecursionInResult#:#A képlet végtelen rekurziót tartalmaz. assessment#:#err_category_in_use#:#Legalább egy kategória nem törölhető. A kategória egy vagy több mértékegysége még használatban van. -assessment#:#err_divider_too_big#:#The divider of one of the variables in this question is too big.###29 07 2022 new variable -assessment#:#err_division#:#The value you chose would make it impossible to generate a valid value for the variable.###29 07 2022 new variable +assessment#:#err_divider_too_big#:#Ebben a kérdésben az egyik változó osztója túl nagy. +assessment#:#err_division#:#Ennek az értéknek a maximumnál kisebbnek kell lennie. assessment#:#err_duplicate_results#:#Többször használtál egy végeredményt. Ez tesztkérdésben nem megengedett -assessment#:#err_no_formula#:#Képletet írj +assessment#:#err_no_formula#:#Képletet írjon assessment#:#err_no_numeric_value#:#Számértéket adjon meg! assessment#:#err_range#:#A maximum értéknek nagyobbnak kell lennie, mint a minimum érték assessment#:#err_rating_advanced_not_allowed#:#Más értékelés, mint az egyszerű jelenleg nem használható, mivel több azonos alapmértékegységű végeredményt adott meg. @@ -654,7 +652,7 @@ assessment#:#err_unit_in_variables#:#A mértékegység nem törölhető. Jelenle assessment#:#err_unit_is_baseunit#:#A mértékegység nem törölhető. Jelenleg egy másik mértékegység alapmértékegysége. assessment#:#err_wrong_categoryname#:#A kategória már létezik. assessment#:#err_wrong_rating_advanced#:#Fejlett értékelés esetén a számok összege 100% kell, hogy legyen. -assessment#:#error_creating_certificate_zip_empty#:#No data for export.###26 08 2024 new variable +assessment#:#error_creating_certificate_zip_empty#:#Nincs exportálható adat. assessment#:#error_importing_question#:#Hiba lépett fel a kérdés(ek) kijelölt fájlból való importálásakor. assessment#:#error_open_image_file#:#Hiba történt egy képfájl megnyitásakor. assessment#:#error_random_question_generation#:#Végzetes hiba történt tesztjéhez a kérdések véletlenszerű generálása közben. Vegye fel a kapcsolatot a rendszergazdával a következő információkkal: A rendszer nem tudott aktív ID-t létrehozni %s user_ID-hez és %s test_ID-hez. @@ -675,34 +673,34 @@ assessment#:#eval_all_users#:#Összes felhasználó eredménye assessment#:#eval_legend_link#:#Az oszlopok fejlécszimbólumainak jelentése alább található. assessment#:#evaluated_users#:#Értékelt felhasználók assessment#:#exam_id#:#Tesztkitöltés-azonosító: -assessment#:#exam_id_label#:#Exam Id###29 07 2022 new variable -assessment#:#exam_id_of_attempt#:#ID of Attempt###28 10 2024 new variable +assessment#:#exam_id_label#:#Teszt-azonosító +assessment#:#exam_id_of_attempt#:#Kitöltés-ID-je assessment#:#examid_in_test_pass#:#Tesztkitöltés-azonosító megjelenítése assessment#:#examid_in_test_pass_desc#:#Minden tesztkitöltésnek új, egyedi azonosítója van, ami megjelenik a tesztben. -assessment#:#examid_in_test_res#:#ILIAS-vizsgaazonosító +assessment#:#examid_in_test_res#:#ILIAS-vizsgaazonosító megjelenítése assessment#:#examid_in_test_res_desc#:#Az ILIAS-vizsgaazonosító a teszteredményeknél jelenik meg. -assessment#:#exp_all_test_runs#:#All test attempts###26 08 2024 new variable -assessment#:#exp_eval_data#:#Kiértékelési adatok exportja, mint -assessment#:#exp_grammar_as#:#as###26 08 2024 new variable -assessment#:#exp_scored_test_attempt#:#Scored Test Attempt###28 10 2024 new variable -assessment#:#exp_type_certificate#:#Igazolás (PDF) +assessment#:#exp_all_test_runs#:#Az összes tesztkitöltés +assessment#:#exp_eval_data#:#Adatok exportálása +assessment#:#exp_grammar_as#:#mint +assessment#:#exp_scored_test_attempt#:#Pontozott tesztkitöltés +assessment#:#exp_type_certificate#:#Tanúsítvány (PDF) assessment#:#exp_type_excel#:#Microsoft Excel (XLS) assessment#:#expected_result_type#:#Elvárt eredménytípus -assessment#:#export_cert_failed_for_users_p#:#No certificate file could be generated and added for the following %s accounts: %s. Please contact an administrator to check the log file.###26 08 2024 new variable -assessment#:#export_cert_failed_for_users_s#:#No certificate file could be generated and added to the archive for the following account: %s. Please contact an administrator to check the log file.###26 08 2024 new variable -assessment#:#export_cert_ignored_for_users_p#:#The following %s accounts did not achieve a certificate, or the certificate service is not enabled/activate: %s###26 08 2024 new variable -assessment#:#export_cert_ignored_for_users_s#:#The following account did not achieve a certificate, or the certificate service is not enabled/activate: %s###26 08 2024 new variable -assessment#:#export_cert_no_users#:#A certificate archive cannot be created due to missing test participants.###26 08 2024 new variable +assessment#:#export_cert_failed_for_users_p#:#Nem sikerült tanúsítványfájlt létrehozni és hozzáadni a következő %s fiókhoz: %s. Kérem, keresse az üzemeltetőt, hogy tekintse meg a naplófájlt. +assessment#:#export_cert_failed_for_users_s#:#Nem sikerült tanúsítványfájlt létrehozni és hozzáadni a következő fiókhoz: %s. Kérem, keresse az üzemeltetőt, hogy tekintse meg a naplófájlt. +assessment#:#export_cert_ignored_for_users_p#:#A következő %s fiók nem szerzett tanúsítványt, vagy a tanúsítványszolgáltatás nincs bekapcsolva: %s +assessment#:#export_cert_ignored_for_users_s#:#A következő fiók nem szerzett tanúsítványt, vagy a tanúsítványszolgáltatás nincs bekapcsolva: %s +assessment#:#export_cert_no_users#:#Hiányzó kitöltők miatt nem lehet tanúsítványarchívumot létrehozni assessment#:#export_essay_qst_with_html#:#Esszé kérdések exportálása HTML kódként -assessment#:#export_essay_qst_with_html_desc#:#Ha be van kapcsolva, lehetővé válik esszékérdések exportálása HTML segítségével Excelbe. -assessment#:#export_legacy_logs#:#Legacy Log-Daten exportieren###26 08 2024 new variable -assessment#:#extra_time_byline#:#Put in extra time in minutes. Already entered extra time is added up.###28 10 2024 new variable -assessment#:#extra_time_for_all_participants#:#You are adding some extra time to all participants.###28 10 2024 new variable -assessment#:#extra_time_for_selected_participants#:#You are adding extra time to the selected participants.###28 10 2024 new variable -assessment#:#extra_time_for_selected_participants_different#:#You have selected participants with different additional times.###28 10 2024 new variable -assessment#:#extra_time_for_single_participant#:#Your are adding extra time to the following participant:###28 10 2024 new variable -assessment#:#extratime#:#Extra-idő -assessment#:#extratime_added#:#The extra time has been added to the selected participants.###28 10 2024 new variable +assessment#:#export_essay_qst_with_html_desc#:#Lehetővé válik esszékérdések exportálása HTML segítségével Excelbe. +assessment#:#export_legacy_logs#:#Joginapló adatok exportálása +assessment#:#extra_time_byline#:#Adja meg az extra időt percben. A már megadott extra időt megnöveli. +assessment#:#extra_time_for_all_participants#:#Extra időt állított be az összes kitöltőnek. +assessment#:#extra_time_for_selected_participants#:#Extra időt állított be a kiválasztott kitöltőknek. +assessment#:#extra_time_for_selected_participants_different#:#A kiválasztott felhasználóknak eltérő extra idő van beállítva. +assessment#:#extra_time_for_single_participant#:#Extra időt állított be az alábbi kitöltőknek: +assessment#:#extratime#:#Extra idő +assessment#:#extratime_added#:#Az extra időt sikeresen hozzáadta a kiválasztott kitöltőkhöz. assessment#:#factor#:#Szorzó assessment#:#failed_official#:#nem teljesítette assessment#:#failed_short#:#sikertelen @@ -713,7 +711,7 @@ assessment#:#feedback_checked#:#Válaszfüggő visszajelzések megjelenítése a assessment#:#feedback_complete_solution#:#Hibátlan megoldás assessment#:#feedback_correct_kprim#:#Válaszfüggő visszajelzések megjelenítése az összes helyesen megválaszolt kérdéshez (helyes válasznak az minősül, mely pozitív lehetőséget választottak). assessment#:#feedback_correct_sc_mc#:#Válaszfüggő visszajelzések megjelenítése az összes helyesen megválaszolt kérdéshez (helyes válasznak az minősül, mely pozitív pontot ér). -assessment#:#feedback_generic#:#Általános megoldás-visszajelzés +assessment#:#feedback_generic#:#Hibátlan/hibás megoldás visszajelzése assessment#:#feedback_incomplete_solution#:#Legalább egy válasz nem helyes assessment#:#feedback_setting#:#Válaszfüggő visszajelzések módja. assessment#:#fileDownload#:#Fájlletöltés @@ -730,73 +728,70 @@ assessment#:#finalized_evaluation#:#A pontozás befejezve assessment#:#finalized_on#:#Befejezve assessment#:#finish_all_user_passes#:#Összes tesztkitöltés befejezettre állítása assessment#:#finish_pass_for_all_users#:#Biztos, hogy az összes felhasználó kitöltését befejezettre állítja? -assessment#:#finish_pass_for_multiple_users_in_processing_time#:#You cannot finish the passes of all users together, because for at least one user the processing time is not over yet.###26 08 2024 new variable -assessment#:#finish_pass_for_user_confirmation#:#Biztos, hogy befejezi '%s' tesztkitöltését? -assessment#:#finish_pass_for_user_in_processing_time#:#WARNING: the processing time for this user is not over yet! You should only end the test run if there is a compelling reason (e.g. exclusion from the test).###26 08 2024 new variable +assessment#:#finish_pass_for_multiple_users_in_processing_time#:#Nem állíthatja befejezettre a kiválasztott felhasználók tesztkitöltést, mert legalább egy kitöltési időkorlátja még nem járt le. +assessment#:#finish_pass_for_user_confirmation#:#Biztos, hogy befejezettre állítja ‘%s’ tesztkitöltését? +assessment#:#finish_pass_for_user_in_processing_time#:#FIGYELMEZTETÉS: a felhasználó ideje még nem járt le! Csak nyomós ok esetén fejezze be a tesztkitöltést (például kizárás a tesztből). assessment#:#finish_test#:#Teszt befejezése -assessment#:#finish_test_all#:#Are you sure you want to finish the test attempts for all users?###28 10 2024 new variable -assessment#:#finish_test_more_than_one_selected#:#Only a single participant may be selected to finish the pass if the test allows only one pass.###29 10 2025 new variable -assessment#:#finish_test_multiple#:#Are you sure you want to finish the test attempts for the following participants?###28 10 2024 new variable -assessment#:#finish_test_no_valid_participants_selected#:#There are no active test runs for the selected participants, so they cannot be completed.###29 10 2025 new variable -assessment#:#finish_test_single#:#Are you sure you want to finish the test attempt for the participant "%s"?###28 10 2024 new variable +assessment#:#finish_test_all#:#Biztos, hogy befejezettre állítja az összes felhasználó tesztkitöltését? +assessment#:#finish_test_more_than_one_selected#:#Ha csak egy kitöltés engedélyezett, akkor csak az egyszeres kitöltőknél állítható befejezettre a tesz. +assessment#:#finish_test_multiple#:#Biztos, hogy befejezettre állítja a kiválasztott felhasználók tesztkitöltését? +assessment#:#finish_test_no_valid_participants_selected#:#Egy aktív tesztkitöltése sincs a kiválasztott felhasználóknak, így nincs mit befejezni. +assessment#:#finish_test_single#:#Biztos, hogy befejezettre állítja ‘%s’ felhasználók tesztkitöltését? assessment#:#finish_unfinished_passes#:#Összes befejezetlen tesztkitöltés befejezettre állítása assessment#:#finish_unfinished_passes_desc#:#Ez az ütemezett feladat az összes záró időponttal vagy időtartamkorláttal rendelkező kitöltést befejezettre állítja. -assessment#:#finished_by_administrator#:#Finished by Administrator###28 10 2024 new variable -assessment#:#finished_by_cronjob#:#Finished by Cronjob###28 10 2024 new variable -assessment#:#finished_by_duration#:#Finished by time limit###28 10 2024 new variable -assessment#:#finished_by_participant#:#Finished by Participant###28 10 2024 new variable -assessment#:#finished_by_unknown#:#Finished by Unknown###28 10 2024 new variable -assessment#:#fixed_participants_hint#:#Ez a teszt csak a kézzel hozzárendelt, alább felsorolt résztvevők számára érhető el. Kikapcsolhatja ezt a korlátozást úgy, hogy a tesztbeállításokban lévő 'Kézzel beállított résztvevők' jelölőnégyzetből kiveszi a pipát. -assessment#:#fixedparticipants_subtab#:#Manuálisan kiválasztott résztvevők +assessment#:#finished_by_administrator#:#Befejezettre állította az Adminisztrátor +assessment#:#finished_by_cronjob#:#Befejezettre állította az Ütemezett feladat +assessment#:#finished_by_duration#:#Befejezettre állította az határidő +assessment#:#finished_by_participant#:#Befejezettre állította a kitöltő +assessment#:#finished_by_unknown#:#Befejezettre állította: ismeretlen +assessment#:#fixed_participants_hint#:#Ez a teszt csak a kézzel hozzárendelt, alább felsorolt kitöltők számára érhető el. Kikapcsolhatja ezt a korlátozást úgy, hogy a tesztbeállításokban lévő ‘Kézzel beállított kitöltők’ jelölőnégyzetből kiveszi a pipát. +assessment#:#fixedparticipants_subtab#:#Manuálisan kiválasztott kitöltők assessment#:#flashfile#:#Flash fájl assessment#:#for#:#ehhez assessment#:#forcejs#:#JavaScript output kikényszerítése tesztkérdésekhez assessment#:#form_msg_area_missing_points#:#Adjon meg pontot minden területhez. assessment#:#formula#:#Képlet -assessment#:#fq_formula_desc#:#Beírhat megadott változókat ($v1, $v2, ..., $vn), megadott eredményeket (például $r1), zárójeleket, matematikai műveleti jeleket + (összeadás), - (kivonás), * (szorzás), / (osztás), ^ (n-edik hatvány), 'pi' és 'e' konstansokat, továbbá 'sin', 'sinh', 'arcsin', 'asin', 'arcsinh', 'asinh', 'cos', 'cosh', 'arccos', 'acos', 'arccosh', 'acosh', 'tan', 'tanh', 'arctan', 'atan', 'arctanh', 'atanh', 'sqrt', 'abs', 'ln' és 'log' függvényeket. +assessment#:#fq_formula_desc#:#Beírhat megadott változókat ($v1, $v2, …, $vn), megadott eredményeket (például $r1), zárójeleket, matematikai műveleti jeleket + (összeadás), - (kivonás), * (szorzás), / (osztás), ^ (n-edik hatvány), ‘pi’ és ‘e’ konstansokat, továbbá ‘sin’, ‘sinh’, ‘arcsin’, ‘asin’, ‘arcsinh’, ‘asinh’, ‘cos’, ‘cosh’, ‘arccos’, ‘acos’, ‘arccosh’, ‘acosh’, ‘tan’, ‘tanh’, ‘arctan’, ‘atan’, ‘arctanh’, ‘atanh’, ‘sqrt’, ‘abs’, ‘ln’ és ‘log’ függvényeket. assessment#:#fq_no_restriction_info#:#Tizedestört és tört egyaránt megadható. assessment#:#fq_precision_info#:#Adja meg a tizedeshelyek számát. -assessment#:#fq_question_desc#:#Definiálhat változókat $v1, $v2 ... $vn beírásával, végeredményeket $r1, $r2 .... $rn beírásával a kérdés szövegének tetszőleges helyén. Kattints a 'Kérdés elemzése' gombra, hogy a változók és a végeredmények szerkeszthető űrlapja megjelenjen. -assessment#:#gap#:#Kitöltendő hely +assessment#:#fq_question_desc#:#fq_question_desc#:#Definiálhat változókat $v1, $v2 … $vn beírásával, végeredményeket $r1, $r2 …. $rn beírásával a kérdés szövegének tetszőleges helyén. Kattintson a ‘Kérdés elemzése’ gombra, hogy a változók és a végeredmények szerkeszthető űrlapja megjelenjen. assessment#:#gap_combination#:#Kitöltéskombináció -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Fogalomtár fogalma -assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable +assessment#:#goto_first_question#:#Az első kérdés megjelenítése assessment#:#grading_mark_msg#:#Érdemjegye: "[mark]" assessment#:#grading_status_failed_msg#:#Sajnáljuk, nem teljesítette a tesztet. assessment#:#grading_status_passed_msg#:#Gratulálunk, sikeresen teljesítette a tesztet. -assessment#:#hide_best_solution#:#Hide best solution###28 10 2024 new variable +assessment#:#hide_best_solution#:#A legjobb megoldás elrejtése assessment#:#identical_scoring#:#Megegyezők pontozása assessment#:#identical_scoring_desc#:#A kitöltendő helyek megegyező megoldásai pontozva legyenek-e meg akkor is, ha ugyanazon megoldást kétszer vagy többször adott meg. Ha nincs pipa, csak a megoldás első előfordulása kerül pontozásra. assessment#:#imagemap#:#Képtérkép -assessment#:#imap_line_color#:#Képtérkép vonalszíne +assessment#:#imap_line_color#:#Képtérkép vonal színe assessment#:#import_question#:#Kérdés(ek) importálása -assessment#:#in_range#:#Within range###26 08 2024 new variable -assessment#:#in_trash#:#In Trash###26 08 2024 new variable +assessment#:#in_range#:#Terjedelmen belül +assessment#:#in_trash#:#Lomtárba assessment#:#info_answer_type_change#:#A kérdés képet tartalmaz. Nem változtathatja a válasz típusát többsorosra. assessment#:#info_text_upload#:#Válasszon egy UTF-8 kódolású válaszfájlt a feltöltéshez assessment#:#insert_after#:#Beszúrás utána assessment#:#insert_before#:#Beszúrás elé -assessment#:#insert_gap#:#Kitöltendő hely beszúrása -assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable +assessment#:#interaction_type#:#Interakcó típusa assessment#:#internal_links#:#Belső linkek assessment#:#intprecision#:#Osztható a következővel -assessment#:#intprecision_info#:# Az 'Osztható a következővel' csak akkor van hatással a változók létrehozására, ha a Pontosság értéke 0. Ebben az esetben az 'Osztható a következővel'-nek olyan egész számot adj meg, amivel oszthatónak kell lennie az létrehozott változónak. 10 esetén olyan egészeket generálódnak, melyek 10-el oszthatóak. 5 esetén olyan egészek jönnek létre, melyek 5-el oszthatóak, stb.. Amennyiben a Pontosság értéke 0, az 'Osztható a következővel'-t kötelezőt megadni, értéke pozitív egész kell, hogy legyen. Egészek esetén az alapértelmezett érték 1. -assessment#:#invalid_ip#:#Invalid IP###26 08 2024 new variable -assessment#:#ip_range_byline#:#Only IP addresses within the defined range can start the test. You can either use IPv4 OR IPv6 addresses.###28 10 2024 new variable -assessment#:#ip_range_for_all_participants#:#You are changing the IP Range of all participants###28 10 2024 new variable -assessment#:#ip_range_for_selected_participants#:#You are changing the IP Range of the following participant.###28 10 2024 new variable -assessment#:#ip_range_for_single_participant#:#You are changing the IP Range of the selected participants.###28 10 2024 new variable -assessment#:#ip_range_info#:#Only clients with an IP in the provided range will be able to access the test.###26 08 2024 new variable -assessment#:#ip_range_label#:#IP Range###26 08 2024 new variable -assessment#:#ip_range_updated#:#The IP-Range has been update for the selected participants.###28 10 2024 new variable +assessment#:#intprecision_info#:# Az ‘Osztható a következővel’ csak akkor van hatással a változók létrehozására, ha a Pontosság értéke 0. Ebben az esetben az ‘Osztható a következővel’-nek olyan egész számot adj meg, amivel oszthatónak kell lennie az létrehozott változónak. 10 esetén olyan egészeket generálódnak, melyek 10-el oszthatók. 5 esetén olyan egészek jönnek létre, melyek 5-el oszthatók, stb.. Amennyiben a Pontosság értéke 0, az ‘Osztható a következővel’-t kötelezőt megadni, értéke pozitív egész kell, hogy legyen. Egészek esetén az alapértelmezett érték 1. +assessment#:#invalid_ip#:#Érvénytelen IP +assessment#:#ip_range_byline#:#Csak a meghatározott IP-tartományba eső IP-címek indíthatják el a tesztet. IPv4 VAGY IPv6 címek is használhatók. +assessment#:#ip_range_for_all_participants#:#Megváltoztatja az IP-tartományt az összes kitöltőnél. +assessment#:#ip_range_for_selected_participants#:#Megváltoztatja az IP-tartományt a következő kitöltőknél. +assessment#:#ip_range_for_single_participant#:#Megváltoztatja az IP-tartományt a kiválasztott kitöltőnél. +assessment#:#ip_range_info#:#Csak a megadott tartományba eső IP-címmel rendelkezőknek van hozzáférésük a teszthez. +assessment#:#ip_range_label#:#IP-tartomány +assessment#:#ip_range_updated#:#Az IP-tartomány módosult a kiválasztott kitöltőnél. assessment#:#kiosk#:#Vizsganézet -assessment#:#kiosk_description#:#A vizsganézet esetén a teszt úgynevezett kioszk-módban fut. Ilyenkor nem látszódik a böngésző cím- és állapotsora, továbbá azok az elemek sem, amelyek nem részei a tesztnek. Ez megakadályozva a felhasználót új weboldal megnyitásában.
    Hogy a teszt kitöltése alatt hatékonyan megakadályozhassuk a résztvevőknek másik weboldal megnyitását, megfelelő böngészőkörnyezet telepítése szükséges (például Safe Exam Browser). +assessment#:#kiosk_description#:#A vizsganézet esetén a teszt úgynevezett kioszk-módban fut. Ilyenkor nem látszódik a böngésző cím- és állapotsora, továbbá azok az elemek sem, amelyek nem részei a tesztnek. Ez megakadályozva a felhasználót új weboldal megnyitásában.
    Hogy a teszt kitöltése alatt hatékonyan megakadályozhassuk a kitöltőknek másik weboldal megnyitását, megfelelő böngészőkörnyezet telepítése szükséges (például Safe Exam Browser). assessment#:#kiosk_options#:#Vizsganézet beállításai -assessment#:#kiosk_options_desc#:#Az információ a képernyő tetején jelenik meg. -assessment#:#kiosk_show_participant#:#Résztvevő nevének megjelenítése +assessment#:#kiosk_options_desc#:#Az információ a képernyő fejlécén jelenik meg. +assessment#:#kiosk_show_participant#:#Kitöltő nevének megjelenítése assessment#:#kiosk_show_title#:#Tesztcím megjelenítése -assessment#:#kprim_answers_info#:#Egyválaszos kérdés (rádiógombos) 'négy helyes/helytelen döntés' fajtája ('K' vagy 'Kprim'-ként is ismert). Eredménye négy válasz/döntés vagy befejezetlen állapot lehet. A hibátlan eredmény mind a négy kérdésre adott választól/döntéstől függ. Maximális pontszám csak akkor adható, ha mind négy válasz/döntés hibátlan. +assessment#:#kprim_answers_info#:#Egyválaszos kérdés (rádiógombos) ‘négy helyes/helytelen döntés’ fajtája (‘K’ vagy ‘Kprim’-ként is ismert). Eredménye négy válasz/döntés vagy befejezetlen állapot lehet. A hibátlan eredmény mind a négy kérdésre adott választól/döntéstől függ. Maximális pontszám csak akkor adható, ha mind négy válasz/döntés hibátlan. assessment#:#kprim_instruction_text#:#Minden állításnál döntse el: [%s] vagy [%s] assessment#:#lacex_assClozeTest_NumberOfResultExpression_d#:#A negyedik válaszlehetőség egy választásos szöveghely és a második lehetőséget választották válaszul assessment#:#lacex_assClozeTest_NumberOfResultExpression_e#:#R[4] = +2+ @@ -837,71 +832,70 @@ assessment#:#lacex_assSingleChoice_NumberOfResultExpression_e#:#R = +2+ assessment#:#lacex_assTextSubset_StringResultExpression_d#:#A második válaszlehetőségre a „nátrium-klorid” választ adták assessment#:#lacex_assTextSubset_StringResultExpression_e#:#R[2] = ~nátrium-klorid~ assessment#:#lacex_example_header#:#Példák -assessment#:#list_of_participants#:#Participants###28 10 2024 new variable +assessment#:#list_of_participants#:#Kitöltők assessment#:#locked#:#Zárolva -assessment#:#log_deletion_not_allowed#:#You don't have the necessary permissions to delete log entries.###26 08 2024 new variable -assessment#:#log_entry_type#:#Log Entry Type###26 08 2024 new variable -assessment#:#log_ip#:#Log IP###26 08 2024 new variable -assessment#:#log_ip_info#:#The IP of Participants is Logged for each interaction with a test. Disabling it does not delete existing IP records.###26 08 2024 new variable -assessment#:#log_participant_data_delete_warning#:#This test contains log data for participant interactions that will be deleted when changing the test to a test without names.###26 08 2024 new variable +assessment#:#log_deletion_not_allowed#:#Nincs jogosultsága törölni a naplóbejegyzéseket. +assessment#:#log_entry_type#:#Naplóbejegyzés típusa +assessment#:#log_ip#:#IP naplózása +assessment#:#log_ip_info#:#A kitöltők minden tesztinterakciójával naplózzuk a kitöltő IP-címét. Kikapcsolása nem törli a már meglévő rekordokat. +assessment#:#log_participant_data_delete_warning#:#Ez a teszt naplóadatokat tartalmaz a kitöltők interakcióiról, amelyek törlődnek, ha a tesztet nevek nélküli tesztre módosítja. assessment#:#log_text#:#Naplóüzenet assessment#:#log_user_solution_willingly_deleted#:#A felhasználó törölte a választ. -assessment#:#logging_settings#:#Bejelentkezés -assessment#:#logs_answer_deleted#:#Answer deleted###26 08 2024 new variable -assessment#:#logs_answer_submitted#:#Answer Submitted###26 08 2024 new variable -assessment#:#logs_deleted#:#A kiválasztott tesztekhez tartozó naplófájladatokat sikeresen törölte. -assessment#:#logs_error_on_participant_interaction#:#Error on Participant Interaction###26 08 2024 new variable -assessment#:#logs_error_on_question_administration_interaction#:#Error on Question Administration Interaction###26 08 2024 new variable -assessment#:#logs_error_on_scoring_interaction#:#Error on Scoring Interaction###26 08 2024 new variable -assessment#:#logs_error_on_test_administration_interaction#:#Error on Test Administration Interaction###26 08 2024 new variable -assessment#:#logs_error_on_undefined_interaction#:#Error on Undefined Interaction###26 08 2024 new variable -assessment#:#logs_extra_time_added#:#Extra Time Added###26 08 2024 new variable -assessment#:#logs_main_settings_modified#:#Main Settings Modified###26 08 2024 new variable -assessment#:#logs_mark_schema_modified#:#Mark Schema Modified###26 08 2024 new variable -assessment#:#logs_mark_schema_reset#:#Mark Schema Reset###26 08 2024 new variable -assessment#:#logs_new_test_created#:#New Test Created###26 08 2024 new variable -assessment#:#logs_output#:#Naplófájladatok kimenete -assessment#:#logs_participant_data_removed#:#Participant Data Removed###26 08 2024 new variable -assessment#:#logs_pi#:#Participant Interaction###26 08 2024 new variable -assessment#:#logs_qai#:#Question Administration Interaction###26 08 2024 new variable -assessment#:#logs_question_added#:#Question Added###26 08 2024 new variable -assessment#:#logs_question_graded#:#Question Graded###26 08 2024 new variable -assessment#:#logs_question_grading_reset#:#Grading Reset###26 08 2024 new variable -assessment#:#logs_question_modified#:#Question Modified###26 08 2024 new variable -assessment#:#logs_question_modified_in_corrections#:#Question Modified in Corrections###26 08 2024 new variable -assessment#:#logs_question_moved#:#Question Moved###26 08 2024 new variable -assessment#:#logs_question_removed#:#Question Removed###26 08 2024 new variable -assessment#:#logs_question_removed_in_corrections#:#Question Removed in Corrections###26 08 2024 new variable -assessment#:#logs_question_selection_criteria_modified#:#Question Selection Criteria Modified###26 08 2024 new variable -assessment#:#logs_question_shown#:#Question Shown###26 08 2024 new variable -assessment#:#logs_question_skipped#:#Question Skipped###26 08 2024 new variable -assessment#:#logs_question_synchronisation_reset#:#Question Synchronisation Reset###26 08 2024 new variable -assessment#:#logs_questions_synchronised#:#Questions Synchonised###26 08 2024 new variable -assessment#:#logs_scoring_settings_modified#:#Scoring Settings Modified###26 08 2024 new variable -assessment#:#logs_si#:#Scoring Interaction###26 08 2024 new variable -assessment#:#logs_tai#:#Test Administration Interaction###26 08 2024 new variable -assessment#:#logs_te#:#Error###26 08 2024 new variable -assessment#:#logs_test_deleted#:#Test Deleted###26 08 2024 new variable -assessment#:#logs_test_run_finished#:#Test Run Finished###26 08 2024 new variable -assessment#:#logs_test_run_of_participant_closed#:#Run of Participant Closed###26 08 2024 new variable -assessment#:#logs_test_run_started#:#Test Run Started###26 08 2024 new variable -assessment#:#logs_wrong_test_password_provided#:#A résztvevő rossz jelszót adott meg. +assessment#:#logging_settings#:#Naplózás +assessment#:#logs_answer_deleted#:#Választ töröltek +assessment#:#logs_answer_submitted#:#Választ beküldtek +assessment#:#logs_deleted#:#A kiválasztott naplóadatokat sikeresen törölte. +assessment#:#logs_error_on_participant_interaction#:#Hiba a kitöltő interakciójában +assessment#:#logs_error_on_question_administration_interaction#:#Hiba kérdés adminisztrációs interakciójában +assessment#:#logs_error_on_scoring_interaction#:#Hiba az interakció pontozásakor +assessment#:#logs_error_on_test_administration_interaction#:#Hiba a teszt adminisztrációs interakciójában +assessment#:#logs_error_on_undefined_interaction#:#Hiba a nem definált interakción. +assessment#:#logs_extra_time_added#:#Extra idő hozzáadva +assessment#:#logs_main_settings_modified#:#Alapbeállítások módosítva +assessment#:#logs_mark_schema_modified#:#Értékelési séma módosítva +assessment#:#logs_mark_schema_reset#:#Értékelési séma alapértelmezettre állítva +assessment#:#logs_new_test_created#:#Új teszt jött létre +assessment#:#logs_output#:#Napló adat kimenet +assessment#:#logs_participant_data_removed#:#Kitöltő adatai törölve +assessment#:#logs_pi#:#Kitöltő interakció +assessment#:#logs_qai#:#Kérdés adminisztrációs interakció +assessment#:#logs_question_added#:#Kérdés hozzáadva +assessment#:#logs_question_graded#:#Kérdés értékelték +assessment#:#logs_question_grading_reset#:#Kérdés alapértelmezettre állították +assessment#:#logs_question_modified#:#Kérdés módosították +assessment#:#logs_question_modified_in_corrections#:#A kérdést a javításokban módosították +assessment#:#logs_question_moved#:#Kérdés áthelyezték +assessment#:#logs_question_removed#:#Kérdés törölték +assessment#:#logs_question_removed_in_corrections#:#A kérdést eltávolították a javításokból. +assessment#:#logs_question_selection_criteria_modified#:#Kérdés kiválasztási feltételét módosították +assessment#:#logs_question_shown#:#Kérdés megjelenítve +assessment#:#logs_question_skipped#:#Kérdést kihagyták +assessment#:#logs_question_synchronisation_reset#:#Kérdések szinkonizálását alaértelmezettre állították +assessment#:#logs_questions_synchronised#:#Kérdéseket szinkronizálták +assessment#:#logs_scoring_settings_modified#:#Pontozási beállításokat módosították +assessment#:#logs_si#:#Pontozás interakció +assessment#:#logs_tai#:#Teszt adminisztrációs interakció +assessment#:#logs_te#:#Hiba +assessment#:#logs_test_deleted#:#Tesztet törölték +assessment#:#logs_test_run_finished#:#Teszt futását befejezték +assessment#:#logs_test_run_of_participant_closed#:#Kitöltő futását lezárták +assessment#:#logs_test_run_started#:#Teszt futása elindult +assessment#:#logs_wrong_test_password_provided#:#Kitöltő hibás jelszót adott meg. assessment#:#longmenu#:#Étlap -assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable -assessment#:#longmenu_text#:#'Étlap'-szöveg -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable +assessment#:#longmenu_answeroptions_differ#:#Ez a kérdés jelenleg nem teljes, mert a szövegben lévő rések száma nem egyezik a javítási lehetőségek számával. +assessment#:#longmenu_text#:#‘Étlap’-szöveg assessment#:#maintenance#:#Karbantartás assessment#:#manscoring#:#Manuális pontozás -assessment#:#manscoring_done#:#Pontozott résztvevők +assessment#:#manscoring_done#:#Pontozott kitöltők assessment#:#manscoring_hint#:#Van legalább egy olyan kérdés, amely manuálisan pontozható. Kérjük, megfelelő időpontot adjon a teszteredmények eléréséhez annak érdekében, hogy a felhasználók a manuális pontozás előtt ne tekinthessék meg teszteredményüket. -assessment#:#manscoring_none#:#Nem pontozott résztvevők -assessment#:#manscoring_not_allowed#:#A manuális pontozás nem volt bekapcsolva erre a kérdéstípusra. Nincs engedélyezve az Ön számára ennek a fülnek a használata. +assessment#:#manscoring_none#:#Nem pontozott kitöltők +assessment#:#manscoring_not_allowed#:#A manuális pontozás nem volt bekapcsolva erre a kérdéstípusra. Nincs engedélyezve az Ön számára ennek a lapnak a használata. assessment#:#manscoring_questions_not_found#:#Ez a tesztteljesítés nem tartalmaz olyan kérdéstípusokat, amelyeket manuálisan lehet pontozni. assessment#:#manscoring_results_pass#:#Manuálisan pontozandó kérdések a(z) %s sorszámhoz -assessment#:#manual_editing#:#Kézi módosítás -assessment#:#manual_entry#:#Manual Entry###28 10 2024 new variable +assessment#:#manual_editing#:#Manuális módosítás +assessment#:#manual_entry#:#Manuális bejegyzés assessment#:#mark_schema#:#Értékelés -assessment#:#mark_schema_invalid#:#A jelölésséma nem érvényesít. Megfelelő sémát hozzon létre! +assessment#:#mark_schema_invalid#:#Az értékelésséma nem teljes, kérem, ellenőrizze a minálisan elérendő értéket. assessment#:#matches#:#összeillők assessment#:#matching_pairs#:#Összeillő párok assessment#:#matching_shuffle_definitions#:#Csak definíciók @@ -910,36 +904,34 @@ assessment#:#matching_shuffle_terms_definitions#:#Mindkettő (szakkifejezések assessment#:#matching_type#:#Párosító kérdés altípusa assessment#:#material#:#Segítség assessment#:#material_file#:#Fájl -assessment#:#max_ip_label#:#Highest IP With Access###26 08 2024 new variable +assessment#:#max_ip_label#:#Legmagasabb IP-jű hozzáférés assessment#:#maxchars#:#Karakterek maximális száma -assessment#:#maximum_nr_of_tries_reached#:#Elfogyott az összes próbálkozási lehetősége ebben a tesztben. A teszt nem nyitható meg. +assessment#:#maximum_nr_of_tries_reached#:#Elfogyott az összes teszkitöltési lehetősége ebben a tesztben. A teszt nem nyitható meg. assessment#:#maximum_points#:#Maximálisan elérhető pont assessment#:#maxsize#:#Feltölthető maximális fájlméret assessment#:#maxsize_info#:#Adja meg bájtban a feltölthető fájlméretet. Ha üresen hagyja ezt a mezőt, a rendszerben beállított maximális méret kerül használatra. -assessment#:#min_auto_complete#:#Automatikus kiegészítés -assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable -assessment#:#min_percentage_ne_0#:#Meg kell határoznia a 0 százalék minimális pontértékét. Az érdemjegyképzést nem mentettük. +assessment#:#min_ip_label#:#Legalacsonyabb IP-jű hozzáférés +assessment#:#min_percentage_ne_0#:#Az egyik kategóriának 0 százalékkal kell kezdődnie. Az értékeléssémát nem mentettük. assessment#:#misc#:#Egyéb beállítások -assessment#:#mode_allatonce#:#All###29 10 2025 new variable -assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable -assessment#:#mode_question#:#Question oriented###29 10 2025 new variable -assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable +assessment#:#mode_allatonce#:#Összes +assessment#:#mode_onebyone#:#Egyesével +assessment#:#mode_question#:#Kérdésorientáltan +assessment#:#mode_user#:#Résztvevő-orientáltan assessment#:#msg_circle_added#:#Kör hozzáadva -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#A kifejezések száma nagyobb vagy egyenlő legyen, mint a definíciók száma. assessment#:#msg_poly_added#:#Sokszög hozzáadva assessment#:#msg_questions_moved#:#Kérdés(ek) áthelyezve. assessment#:#msg_rect_added#:#Téglalap hozzáadva -assessment#:#msg_score_settings_modified_and_recalc#:#Your changes were saved and the results recalculated correspondingly.###26 08 2024 new variable -assessment#:#msg_score_settings_not_modified#:#Your changes were not saved.###26 08 2024 new variable +assessment#:#msg_score_settings_modified_and_recalc#:#A módosításait sikeresen mentette, az eredményeket ennek megfelelően újraszámoltuk. +assessment#:#msg_score_settings_not_modified#:#Módosításait nem mentette. assessment#:#msg_selected_for_move#:#Kérdés(ek) kiválasztva áthelyezéshez. assessment#:#new_category#:#Új mértékegység-kategória assessment#:#new_unit#:#Új mértékegység assessment#:#next_question#:#Következő -assessment#:#next_question_rows#:#Kérdések %d - %d (összesen: %d) >> -assessment#:#no_manual_feedback_export_info#:#Manual feedbacks will not be exported.###26 08 2024 new variable -assessment#:#no_passed_after_failed#:#Failing marks cannot have a higher minimum level than any passing mark.###29 10 2025 new variable -assessment#:#no_passed_mark#:#A sikeres vizsgához meg kell jelölni legalább egy érdemjegyet. Az érdemjegyképzést nem mentettük. +assessment#:#next_question_rows#:#Kérdések %d - %d (összesen: %d) → +assessment#:#no_manual_feedback_export_info#:#A manuális visszajelzéseket nem exportáljuk. +assessment#:#no_passed_after_failed#:#A nem teljesítésnek nem lehet magasabb a minimális szintje, mint a teljesítésnek. +assessment#:#no_passed_mark#:#Legalább egy értékelésnek sikeres teljesítésnek kell lennie. Az értékeléssémát nem mentettük. assessment#:#no_question_selected_for_move#:#Legalább egy kérdést jelöljön ki az áthelyezéshez! assessment#:#no_questions_available#:#Nincsenek elérhető kérdések. assessment#:#no_result_type#:#Nincs korlátozás @@ -947,23 +939,23 @@ assessment#:#no_selection#:#--- Nincs kiválasztva --- assessment#:#no_selection_for_move#:#Nincs kiválasztva kérdés a mozgatáshoz assessment#:#no_target_selected_for_move#:#Ki kell választania egy célpozíciót! assessment#:#no_user_or_group_selected#:#Jelöljön ki egy beállítást, amelyet keres (felhasználók/csoportok)! -assessment#:#no_valid_participant_selection#:#No valid Participants selected.###28 10 2024 new variable +assessment#:#no_valid_participant_selection#:#Egy érvényes kitöltőt sem választott ki. assessment#:#not_evaluated_users#:#Még nem értékelt felhasználók -assessment#:#not_started#:#Not started yet###28 10 2024 new variable -assessment#:#not_yet_accessed#:#Még nem volt belépés +assessment#:#not_started#:#Még nem indult el +assessment#:#not_yet_accessed#:#Még senki sem lépett be assessment#:#nr_of_correct_answers#:#Elvárt válaszok száma assessment#:#number_of_answers#:#Válaszok száma assessment#:#numeric_gap#:#Számszerű hely -assessment#:#old_mark_default_not_applied#:#The marks from your personal settings could not be applied as they use an old format. All other settings have been updated.###29 10 2025 new variable +assessment#:#old_mark_default_not_applied#:#A személyes beállításaiban szereplő jegyek nem használhatók, mert a formátumuk régi. Az összes többi beállítást frissítettük. assessment#:#option_label#:#Választható címkék assessment#:#option_label_adequate#:#adekvát assessment#:#option_label_adequate_or_not#:#adekvát / nem adekvát assessment#:#option_label_applicable#:#alkalmazható assessment#:#option_label_applicable_or_not#:#alkalmazható / nem alkalmazható assessment#:#option_label_custom#:#Felhasználó által definiált címkék -assessment#:#option_label_custom_false#:#'HAMIS'-ra címke -assessment#:#option_label_custom_true#:#'IGAZ'-ra címre -assessment#:#option_label_info#:#A résztvevők döntésüknél választható címkeként látják az itt megadott megnevezéseket. +assessment#:#option_label_custom_false#:#‘HAMIS’-ra címke +assessment#:#option_label_custom_true#:#‘IGAZ’-ra címre +assessment#:#option_label_info#:#A kitöltők döntésüknél választható címkeként látják az itt megadott megnevezéseket. assessment#:#option_label_minus#:#- assessment#:#option_label_not_adequate#:#nem adekvát assessment#:#option_label_not_applicable#:#nem alkalmazható @@ -980,19 +972,18 @@ assessment#:#oq_btn_use_order_pictures#:#Rendezze a képeket assessment#:#oq_btn_use_order_terms#:#Rendezze a kifejezéseket assessment#:#oq_header_ordering_elements#:#Elemek rendezése assessment#:#or#:#vagy -assessment#:#order#:#Order###26 08 2024 new variable +assessment#:#order#:#Sorrend assessment#:#ordering_answer_sequence_info#:#Az itt megadott válaszsorozat a helyes megoldások sorozataként kerül felhasználásra. assessment#:#ordertext#:#Sorrendbe rakó szöveg assessment#:#ordertext_info#:#Adja meg a vízszintesen sorba rakandó szöveget. A rendezendő szövegegységek nem látható (fehér) karakterekkel lesznek elválasztva. Ha más elválasztójelre van szüksége, használhatja a %s elválasztójelet szövegegységeinek elkülönítésére. -assessment#:#out_of_range#:#Tartományon kívül esik assessment#:#output#:#Kimenet (output) assessment#:#output_mode#:#Kimeneti mód assessment#:#parseQuestion#:#Kérdés elemzése -assessment#:#part_received_a_of_b_points#:#A résztvevő elért %s pontot a lehetséges %s pontból -assessment#:#participants#:#Résztvevők -assessment#:#participants_invitation#:#Kézzel kiválasztott résztvevők -assessment#:#participants_invitation_description#:#Ez a teszt csak a 'Műszerfal' fülön kézzel hozzáadott felhasználók számára érhető el. -assessment#:#participants_results_subtab#:#Összes résztvevő +assessment#:#part_received_a_of_b_points#:#A kitöltő elért %s pontot a lehetséges %s pontból +assessment#:#participants#:#Kitöltők +assessment#:#participants_invitation#:#Kitöltők manuális kiválasztása +assessment#:#participants_invitation_description#:#Ez a teszt csak a ‘Kitöltők’ lapon manuálisan hozzáadott felhasználók számára érhető el. +assessment#:#participants_results_subtab#:#Összes kitöltő assessment#:#pass#:#Sorszám assessment#:#pass_finished#:#%s tesztkitöltés assessment#:#passed_official#:#sikeresen teljesítette @@ -1001,36 +992,36 @@ assessment#:#passed_short#:#sikeres assessment#:#passed_status#:#Teljesítési állapot assessment#:#passes_finished#:#%s tesztkitöltés assessment#:#percentage#:#Százalék -assessment#:#percentage_points_achieved#:#Reached Points###28 10 2024 new variable +assessment#:#percentage_points_achieved#:#Elért pontszám assessment#:#percentile#:#Százalékpont -assessment#:#personal_settings_apply#:#Apply Settings Template###29 10 2025 new variable -assessment#:#personal_settings_apply_changed_confirmation#:#The current test settings will be overwritten with the settings from the selected template. This also overwrites the Selection of Test Questions. The process cannot be undone!###29 10 2025 new variable -assessment#:#personal_settings_apply_confirmation#:#The current test settings will be overwritten with the settings from the selected template. This process cannot be undone!###29 10 2025 new variable -assessment#:#personal_settings_apply_description#:#This template overrides all settings of test '%s'.###29 10 2025 new variable -assessment#:#personal_settings_apply_not_possible#:#ILIAS could not apply the selected template to this test! Maybe this test already contains participant data sets.###29 10 2025 new variable -assessment#:#personal_settings_apply_success#:#Personal Test Settings have been applied successfully.###29 10 2025 new variable -assessment#:#personal_settings_author#:#Created by###29 10 2025 new variable -assessment#:#personal_settings_create#:#Add New Setting Template###29 10 2025 new variable -assessment#:#personal_settings_delete_confirmation#:#The selected template(s) will be permanently deleted. This cannot be undone.###29 10 2025 new variable -assessment#:#personal_settings_delete_success#:#The selected template(s) have been deleted.###29 10 2025 new variable -assessment#:#personal_settings_description#:#Template Description###29 10 2025 new variable -assessment#:#personal_settings_explanation#:#ILIAS will store the settings of the current test in a template. This template can be used to transfer the settings to another test.###29 10 2025 new variable -assessment#:#personal_settings_export#:#Export Settings Template###29 10 2025 new variable -assessment#:#personal_settings_import#:#Import Setting Templates###29 10 2025 new variable -assessment#:#personal_settings_import_success#:#The template was imported successfully.###29 10 2025 new variable -assessment#:#personal_settings_invalid_selection#:#Please select one template.###29 10 2025 new variable -assessment#:#personal_settings_name#:#Template Title###29 10 2025 new variable -assessment#:#personal_settings_required_author#:#Please enter an author for your template.###29 10 2025 new variable -assessment#:#personal_settings_required_title#:#Please enter a title for your template.###29 10 2025 new variable -assessment#:#personal_settings_save#:#Save New Setting Template###29 10 2025 new variable -assessment#:#personal_settings_show#:#Show Template Details###29 10 2025 new variable -assessment#:#personal_settings_templates_available#:#Personal Test Settings Templates###29 10 2025 new variable -assessment#:#personal_settings_timestamp#:#Creation Date###29 10 2025 new variable +assessment#:#personal_settings_apply#:#Beállítássablon alkalmazása +assessment#:#personal_settings_apply_changed_confirmation#:#A jelenlegi tesztbeállításokat a kiválasztott sablon felülírja, a tesztkédések kiválasztátást is. Ez a folyamat nem vonható vissza! +assessment#:#personal_settings_apply_confirmation#:#A jelenlegi tesztbeállításokat a kiválasztott sablon felülírja. Ez a folyamat nem vonható vissza! +assessment#:#personal_settings_apply_description#:#‘%s’ teszt összes beállítását felülírja ez a sablon. +assessment#:#personal_settings_apply_not_possible#:#Az ILIAS nem tudta alkalmazni a kiválasztott sablont erre a tesztre! Lehetséges, hogy a tesztnek már vannak kitöltői. +assessment#:#personal_settings_apply_success#:#A személyes tesztbeállításokat sikeresen alkalmazta. +assessment#:#personal_settings_author#:#Létrehozta +assessment#:#personal_settings_create#:#Új beállítássablon létrehozása +assessment#:#personal_settings_delete_confirmation#:#A kiválasztott sablon(oka)t véglegesen törli. Ez nem visszavonható. +assessment#:#personal_settings_delete_success#:#A kiválasztott sablon(oka)t sikeresen törölte. +assessment#:#personal_settings_description#:#Sablon leírása +assessment#:#personal_settings_explanation#:#A teszt beállításait sablonként menti, aminek a használatával a beállításokat másik tesztbe viheti át. +assessment#:#personal_settings_export#:#Beállítássablon exportálása +assessment#:#personal_settings_import#:#Beállítássablon importálása +assessment#:#personal_settings_import_success#:#A sablont sikeresen importálta. +assessment#:#personal_settings_invalid_selection#:#Válasszon egy sablont +assessment#:#personal_settings_name#:#Sablon címe +assessment#:#personal_settings_required_author#:#Adja meg a sablon szerzőjét +assessment#:#personal_settings_required_title#:#Adjon címet a sablonjának +assessment#:#personal_settings_save#:#Új beállítássablon mentése +assessment#:#personal_settings_show#:#Sablon részleteinek megjelenítése +assessment#:#personal_settings_templates_available#:#Személyes tesztbeállítás-sablon +assessment#:#personal_settings_timestamp#:#Létrehozás dátuma assessment#:#picture#:#Kép assessment#:#point#:#pont assessment#:#points#:#pont assessment#:#points_checked#:#Pont (bejelölve) -assessment#:#points_non_numeric_or_negative_msg#:#Inputs for points only accept positive numeric values.###26 08 2024 new variable +assessment#:#points_non_numeric_or_negative_msg#:#A pontok csak pozitív számok lehetnek. assessment#:#points_short#:#pont assessment#:#points_unchecked#:#Pont (bejelölés nélkül) assessment#:#points_wrong#:#Helytelen kiválasztások @@ -1045,15 +1036,14 @@ assessment#:#postponed#:#Későbbre halasztott assessment#:#precision#:#Pontosság (tizedesjegyek száma) assessment#:#previous_question#:#Előző assessment#:#previous_question_rows#:#<< Kérdések %d - %d (összesen: %d) -assessment#:#print_answers#:#Print Answers###28 10 2024 new variable +assessment#:#print_answers#:#Válaszok nyomtatása assessment#:#qpl_assessment_no_assessment_of_questions#:#Nincs a kiválasztott kérdéshez elérhető értékelés. A kérdést még nem használták a tesztben. assessment#:#qpl_assessment_total_of_answers#:#Válaszok összszáma assessment#:#qpl_assessment_total_of_right_answers#:#Hibátlan válaszok összszázaléka (maximum pontok százaléka) -assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable -assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable -assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable +assessment#:#qpl_bulk_save_add#:#Hozzáadás +assessment#:#qpl_bulk_save_overwrite#:#Felülírás +assessment#:#qpl_bulkedit_success#:#A módosításokat sikeresen mentette. assessment#:#qpl_cancel_skill_assigns_update#:#Mégsem -assessment#:#qpl_confirm_delete_questions#:#Biztos, hogy eltávolítja az alábbi kérdés(eke)t? assessment#:#qpl_copy_insert_clipboard#:#A kijelölt kérdés(ek)et a vágólapra helyezte. assessment#:#qpl_copy_select_none#:#Jelöljön ki legalább egy kérdést a másoláshoz! assessment#:#qpl_delete_rbac_error#:#Nincs joga a kérdés(ek) eltávolításához. @@ -1092,13 +1082,13 @@ assessment#:#qpl_numeric_upper_needs_valid_upper_alert#:#A felső korlátnak az assessment#:#qpl_paste_error#:#Legalább egy kérdés beillesztése sikertelen a kérdésgyűjteménybe. Ennek egyik lehetséges oka, hogy ugyanabba a kérdésgyűjteménybe próbálta mozgatni. assessment#:#qpl_paste_no_objects#:#Nincsenek kérdések a vágólapon. Másoljon vagy mozgasson egy kérdést a vágólapra! assessment#:#qpl_paste_success#:#A kérdés(ek)et sikeresen beillesztette a kérdésgyűjteménybe. -assessment#:#qpl_qst_edit_form_taxonomy#:#'%s' taxonómia +assessment#:#qpl_qst_edit_form_taxonomy#:#‘%s’ taxonómia assessment#:#qpl_qst_edit_form_taxonomy_section#:#Taxonómiák assessment#:#qpl_qst_inp_matching_mode#:#Egyezés módja assessment#:#qpl_qst_inp_matching_mode_all_on_all#:#Egy vagy több kifejezés egy vagy több definícióval egyezik meg (n:n) assessment#:#qpl_qst_inp_matching_mode_one_on_one#:#Egy kifejezés egy definícióval egyezik meg (1:1) assessment#:#qpl_qst_skl_assign_properties_modified#:#Az összerendelés tulajdonságait sikeresen módosította. -assessment#:#qpl_qst_skl_assign_synced_to_orig#:#A kompetencia-összerendeléseket szinkronizáltuk az eredeti kérdésekkel. +assessment#:#qpl_qst_skl_assign_synced_to_orig#:#A kompetencia-összerendeléseket sikeresen szinkronizálta az eredeti kérdésekkel. assessment#:#qpl_qst_skl_assigns_updated#:#A kompetencia összerendeléseit sikeresen módosította. assessment#:#qpl_qst_skl_selection_for_question_header#:#Kérdéshez rendelt kompetenciák: %s assessment#:#qpl_qst_skl_usg_numq_col#:#Kérdésgyűjteményben lévő, erre a kompetenciára vonatkozó kérdések száma @@ -1106,10 +1096,9 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetencia assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Kompetencia-pontszámok összege kérdésenként assessment#:#qpl_question_is_in_use#:#A módosítandó kérdés %s tesztben szerepel. Ha megváltoztatja a kérdést, az a teszt(ek)ben nem fog módosulni, mert a rendszer másolatot hoz létre a kérdésekről, mielőtt beilleszti azokat a teszt(ek)be. assessment#:#qpl_questions_deleted#:#Kérdés(eke)et sikeresen eltávolított. -assessment#:#qpl_reset_preview#:#Előnézet alaphelyzetbe állítása assessment#:#qpl_save_skill_assigns_update#:#Kompetencia-összerendelése mentése -assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable -assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#A már létező taxonómiák a kérdések szűrésére használhatóak ebben a gyűjteményben. +assessment#:#qpl_settings_availability#:#Elérhetőség +assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#A már létező taxonómiák a kérdések szűrésére használhatók ebben a gyűjteményben. assessment#:#qpl_settings_general_form_property_nav_taxonomy#:#Taxonómia szűrő, mint navigációs fa assessment#:#qpl_settings_general_form_property_nav_taxonomy_description#:#Mikor egy taxonómia kiválasztása kerül, asztali szűrő helyett navigáció faként jelenik meg. assessment#:#qpl_settings_general_form_property_opt_notax_selected#:#Ne használjon navigációs fa szűrőt @@ -1120,64 +1109,54 @@ assessment#:#qpl_skill_point_eval_by_quest_result#:#Kompetencia-pontszámok kié assessment#:#qpl_skill_point_eval_by_solution_compare#:#Kompetencia-pontszámok kiértékelése megoldás-összehasonlítás alapján assessment#:#qpl_skill_point_eval_mode_quest_result#:#Kérdéseredmény assessment#:#qpl_skill_point_eval_mode_solution_compare#:#Megoldás-összehasonlítás -assessment#:#qpl_skl_all_questions#:#All questions###29 10 2025 new variable -assessment#:#qpl_skl_assigned_questions#:#Questions with assignment###29 10 2025 new variable -assessment#:#qpl_skl_assignment_for_question#:#Competence assignments for question „%s“###29 10 2025 new variable +assessment#:#qpl_skl_all_questions#:#Összes kérdés +assessment#:#qpl_skl_assigned_questions#:#Kérdések hozzárendeléssel +assessment#:#qpl_skl_assignment_for_question#:#Kompetenciahozzárendelések ‘%s’ kérdéshez assessment#:#qpl_skl_sub_tab_quest_assign#:#Kérdés/kompetencia összerendelés assessment#:#qpl_skl_sub_tab_usages#:#Összerendelés gyakorisága -assessment#:#qpl_skl_unassigned_questions#:#Questions without assignment###29 10 2025 new variable -assessment#:#qpl_skl_view_control_mode_aria:#:#View control mode###29 10 2025 new variable +assessment#:#qpl_skl_unassigned_questions#:#Hozzárendelés nélküli kérdések +assessment#:#qpl_skl_view_control_mode_aria:#:#Ellenőrzési mód nézete assessment#:#qpl_sync_quest_skl_assigns_confirmation#:#A kérdést egy másik objektumból illesztették be. Frissítsük a kérdés eredetijét a jelenlegi kompetencia-összerendelések beállítása alapján? assessment#:#qpl_tab_competences#:#Kompetenciák -assessment#:#qpl_taxonomy_tab_info_message#:#Taxonomies in question pools can be used to filter the questions. After activating the function in the "Settings" tab, they are displayed in the filter in the "Questions" tab.###26 08 2024 new variable -assessment#:#qst_error_text_too_long#:#One or more text elements marked as erroneous are too long. The maximum size for a text element marked as erroneous is 150 characters:###26 08 2024 new variable +assessment#:#qpl_taxonomy_tab_info_message#:#A kérdések szűrésére használhatók a kérdésgyűjteményben található taxonómiák. Miután bekapcsolta ezt a funkciót a ‘Beállítások’ lapon, szűrésre használhatja a ‘Kérdések’ lapon. +assessment#:#qst_error_text_too_long#:#Néhány szövegelem hibásnak van megjelölve a hossza miatt. A karakterek megengedett maximális száma 150: assessment#:#qst_essay_allready_written_words#:#Beírt szavak száma: assessment#:#qst_essay_chars_remaining#:#Fennmaradó karakterek száma: assessment#:#qst_essay_wordcounter_enabled#:#Szavak számolása assessment#:#qst_essay_wordcounter_enabled_info#:#A beírt szavak számát számoljuk és megjelenítjük a felhasználóknak a bevitelő mező alatt . assessment#:#qst_essay_written_words#:#Szavak megadott száma: -assessment#:#qst_lifecycle#:#Életciklus -assessment#:#qst_lifecycle_draft#:#Piszkozat -assessment#:#qst_lifecycle_filter_all#:#Összes életciklus -assessment#:#qst_lifecycle_final#:#Végső -assessment#:#qst_lifecycle_outdated#:#Elavult -assessment#:#qst_lifecycle_rejected#:#Elutasított -assessment#:#qst_lifecycle_review#:#Átnézendő -assessment#:#qst_lifecycle_sharable#:#Megosztható -assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable -assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable +assessment#:#qst_nested_nested_answers_off#:#Nincsnek behúzások, csak rendezés +assessment#:#qst_nested_nested_answers_on#:#Behúzások használata a válaszokban assessment#:#qst_nr_of_tries#:#Próbálkozások száma assessment#:#qst_preview_reset_msg#:#Előnézet alaphelyzetbe állítása megtörtént. -assessment#:#qst_use_nested_answers#:#Nested answers###29 07 2022 new variable +assessment#:#qst_use_nested_answers#:#Beágyazott válaszok assessment#:#que_contains_unused_var#:#A kérdés olyan változót tartalmaz, mely egyik végeredmény-képletben sem szerepel! assessment#:#question_browse_area_info#:#Válasszon egy objektumot, melyből kérdéseket kíván importálni. -assessment#:#question_complete_title#:#Complete###26 08 2024 new variable +assessment#:#question_complete_title#:#Sikeresen teljesítve assessment#:#question_cumulated_statistics#:#Halmozott kérdésstatisztika assessment#:#question_id#:#Kérdésazonosító assessment#:#question_id_short#:#Azonosító assessment#:#question_instances_title#:#Ezt a kérdést az alábbi tesztek használják -assessment#:#question_is_part_of_running_test#:#Question is part of a running test and may not be edited.###29 07 2022 new variable +assessment#:#question_is_part_of_running_test#:#A kérdés egy futó teszt része, így nem módosítható. assessment#:#question_marking#:#Kérdések megjelölése -assessment#:#question_marking_description#:#A résztvevők lehetőséget kapnak, hogy megjelölhessék a tesztkérdéseket. A jelölések a 'Kérdéslistában' láthatóak. +assessment#:#question_marking_description#:#A kitöltők lehetőséget kapnak, hogy megjelölhessék a tesztkérdéseket. A jelölések a ‘Kérdéslistában’ láthatók. assessment#:#question_not_answered#:#Nem válaszolt a kérdésre assessment#:#question_saved_for_upload#:#A kérdést automatikusan mentettük, hogy lefoglalja a feltöltött fájl számára szükséges területet a tárhelyen. Ha nem fejezi be az űrlap kitöltést, és a kérdést sem szeretné megtartani, akkor a kérdést a kérdésgyűjteményből kell törölnie. -assessment#:#question_summary#:#Irányítópult -assessment#:#question_summary_btn#:#Irányítópult +assessment#:#question_summary#:#Teszkitöltések áttekintése +assessment#:#question_summary_btn#:#Teszkitöltések áttekintése assessment#:#question_title#:#Kérdéscím assessment#:#question_type#:#Kérdéstípus +assessment#:#questionlist_cannot_be_altered#:#A kérdéslista nem módosítható, mert már vannak kitöltések. assessment#:#questionpool_not_entered#:#Adjon nevet a kérdésgyűjteménynek. assessment#:#questionpool_not_selected#:#Kérem, válasszon ki egy kérdésgyűjteményt. -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#kérdések innen: assessment#:#questions_per_page_view#:#Lapnézet assessment#:#random_accept_sample#:#Minta elfogadása assessment#:#random_another_sample#:#Másik minta kérése assessment#:#random_selection#:#Véletlen-kiválasztás assessment#:#range#:#Terület -assessment#:#range_lower_limit#:#Alsó határ assessment#:#range_max#:#Tartomány (Maximum) assessment#:#range_min#:#Tartomány (Minimum) -assessment#:#range_upper_limit#:#Felső határ assessment#:#rated_sign#:#Jel assessment#:#rated_unit#:#Mértékegység assessment#:#rated_value#:#Érték @@ -1189,23 +1168,23 @@ assessment#:#rating_value#:#Érték értékelése assessment#:#rectangle#:#Téglalap assessment#:#rectangle_click_br_corner#:#Kattintson a kívánt terület jobb alsó sarkán. assessment#:#rectangle_click_tl_corner#:#Kattintson a kívánt terület bal felső sarkán. -assessment#:#redirectAfterSave#:#Elérte a maximális munkaidőt, az Ön utolsó kérdését automatikusan mentettük. Hamarosan átirányítjuk... +assessment#:#redirectAfterSave#:#Elérte a maximális munkaidőt, az Ön utolsó kérdését automatikusan mentettük. Hamarosan átirányítjuk… assessment#:#redirect_after_finishing_rule#:#Átirányítás assessment#:#redirect_after_finishing_tst#:#Átirányítás -assessment#:#redirect_after_finishing_tst_desc#:#A teszt befejezése után az összes résztvevő automatikus átirányítása a megadott oldalra, amennyiben nincs hozzáférése a teszteredményéhez. -assessment#:#redirect_always#:#mindig a megadott URL-re -assessment#:#redirect_always_to_logout#:#Always to the logout screen###29 10 2025 new variable -assessment#:#redirect_in_kiosk_mode#:#csak akkor, ha a vizsganézet be van kapcsolva -assessment#:#redirect_url_invalid#:#Please enter a valid url of the target webpage.###29 10 2025 new variable -assessment#:#redirect_url_required_for_rule#:#The url of the webpage is required when "%s" is selected.###29 10 2025 new variable +assessment#:#redirect_after_finishing_tst_desc#:#A teszt befejezése után az összes kitöltő automatikus átirányítása a megadott oldalra, amennyiben nincs hozzáférése a teszteredményéhez. Külső weboldal megadásakor használjon teljes URL-t (beleértve a ‘https://’-t is). ILIAS-objektumra irányításhoz használja annak láblécében levő állandó linket. +assessment#:#redirect_always#:#Mindig a megadott URL-re +assessment#:#redirect_always_to_logout#:#Mindig a kijelentkezési képpernyőre +assessment#:#redirect_in_kiosk_mode#:#Amikor a ‘Vizsganézet’ be van kapcsolva, a meghatározott weboldalra +assessment#:#redirect_url_invalid#:#A cél weboldal valós URL-jét írja ide. +assessment#:#redirect_url_required_for_rule#:#Amikor "%s" van kiválasztva, a weboldal URL-je kötelező. assessment#:#redirection_url#:#URL assessment#:#region#:#Régió -assessment#:#remaining_duration#:#Remaining Duration###28 10 2024 new variable +assessment#:#remaining_duration#:#Fennmaradó idő assessment#:#remove_gap#:#Kitöltendő hely eltávolítása -assessment#:#remove_participants#:#Meghatározottként eltávolítás +assessment#:#remove_participants#:#Kitöltő(k) eltávolítása assessment#:#remove_question#:#Eltávolítás -assessment#:#remove_selected_participants_confirmation#:#Are you sure you want to remove the selected participants from the test?###28 10 2024 new variable -assessment#:#remove_selected_templates_confirmation#:#Are you sure you want to permanently remove the selected personal test settings templates?###29 10 2025 new variable +assessment#:#remove_selected_participants_confirmation#:#Biztos, hogy eltávolítja a következő résztvevőket a tesztből? +assessment#:#remove_selected_templates_confirmation#:#Biztos, hogy véglegesen eltávolítja a kiválasztott személyes tesztbeállítás-sablont? assessment#:#remove_solution#:#Ismétlő összefoglaló tartalmának eltávolítása assessment#:#res_contains_undef_res#:#Egy végeredmény-képlet nem definiált végeredményt tartalmaz! assessment#:#res_contains_undef_var#:#Egy végeredmény-képlet nem definiált változót tartalmaz! @@ -1220,19 +1199,19 @@ assessment#:#result_dec_info#:#Elfogadható eredmény például a 2,3 és a 2.3 assessment#:#result_frac#:#Tört assessment#:#result_frac_info#:#Elfogadható eredmény például az 1/3 és a 2/6 assessment#:#result_type_selection#:#Eredmény-típus választása -assessment#:#result_unit_info#:#Figyeljen arra, hogy a kiválasztott mértékegységnek aktívak kell lenni a 'Rendelkezésre álló mértékegységek'-ben. +assessment#:#result_unit_info#:#Figyeljen arra, hogy a kiválasztott mértékegységnek aktívak kell lenni a ‘Rendelkezésre álló mértékegységek’-ben. assessment#:#result_units#:#Elérhető mértékegységek assessment#:#result_units_info#:#A megjelölt mértékegységeket a válasz részeként ajánljuk fel a hallgatónak, amiből egyet kell választania. assessment#:#result_x#:#%s eredmény assessment#:#results#:#Eredmények assessment#:#results_tab#:#Eredmények -assessment#:#resulttable_all#:#All###26 08 2024 new variable -assessment#:#resulttable_correct#:#Correct###26 08 2024 new variable -assessment#:#resulttable_incorrect#:#Incorrect/Incomplete###26 08 2024 new variable -assessment#:#resulttable_vc_sort_iooa#:#in order of appearance###26 08 2024 new variable -assessment#:#resulttable_vc_sort_posscore#:#highest possible score first###26 08 2024 new variable +assessment#:#resulttable_all#:#Összes +assessment#:#resulttable_correct#:#Helyes +assessment#:#resulttable_incorrect#:#Helytelen/Nem teljes +assessment#:#resulttable_vc_sort_iooa#:#megjelenési sorrendben +assessment#:#resulttable_vc_sort_posscore#:#a lehető legmagasabb pontszám legelől assessment#:#review_view#:#Áttekintés -assessment#:#running#:#Running###28 10 2024 new variable +assessment#:#running#:#Fut assessment#:#saveOrder#:#Sorrend mentése assessment#:#saveOrderAndObligations#:#Sorrend és kötelezőség mentése assessment#:#save_and_next#:#Mentés és folytatás @@ -1241,94 +1220,92 @@ assessment#:#save_on_navigation_confirmation#:#Módosításait automatikusan men assessment#:#save_on_navigation_forced_feedback_hint#:#Mielőtt visszajelzést kap válaszára. assessment#:#save_on_navigation_locked_confirmation#:#Módosított válaszait automatikusan mentjük és zároljuk navigáláskor. assessment#:#saved_adjustment#:#Változások mentése sikerült. -assessment#:#score_anon#:#Score anonymously###29 10 2025 new variable +assessment#:#score_anon#:#Pontozás névtelenül assessment#:#score_partsol_enabled#:#Részmegoldások pontozásának bekapcsolása assessment#:#score_partsol_enabled_info#:#A felhasználóknak általában az összes kérdést hibátlanul meg kell válaszolniuk a beállított pont eléréséhez. Evvel a lehetőséggel a beállított pont felét megszerezhetik legalább három hibátlan döntés esetén. -assessment#:#scored_by#:#Scored BY###29 10 2025 new variable +assessment#:#scored_by#:#Pontozta: assessment#:#scored_pass#:#Sikeres kitöltés assessment#:#scoring#:#Pontozás és eredmények assessment#:#scoringadjust#:#Utólagos módosítás assessment#:#search_groups#:#Talált csoportok -assessment#:#search_roles#:#Talált szerepek +assessment#:#search_roles#:#Talált szerepkörök assessment#:#search_term#:#Fogalom keresése -assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable -assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Szöveghely választása +assessment#:#select_at_least_one_feedback_type_and_trigger#:#Kérjük, válasszon legalább egy visszajelzéstípust és egy triggert. +assessment#:#select_at_least_one_lock_answer_type#:#Legalább egy válaszzárolási típust válasszon. assessment#:#select_max_one_item#:#Csak egy elemet válasszon! -assessment#:#select_one_user#:#Válasszon ki legalább egy felhasználót! -assessment#:#select_question#:#Select a Question###28 10 2024 new variable +assessment#:#select_one_user#:#Válasszon legalább egy felhasználót! +assessment#:#select_question#:#Válasszon egy kérdést assessment#:#select_target_position_for_move_question#:#Válasszon célhelyet a kérdés(ek) áthelyezéséhez és nyomja meg az egyik beszúrás gombot. assessment#:#select_unit#:#--- Válasszon mértékegységet --- assessment#:#selected_category#:#Kiválasztott kategória: %s assessment#:#selection#:#Válasszon assessment#:#set_edit_mode#:#Szerkesztői mód beállítása assessment#:#set_filter#:#Szűrő beállítása -assessment#:#set_manscoring_done#:#'Pontozott résztvevő'-ként megjelölés -assessment#:#set_manscoring_open#:#Remove 'scoring complete' flag###29 10 2025 new variable +assessment#:#set_manscoring_done#:#‘Pontozott kitöltő’-ként megjelölés +assessment#:#set_manscoring_open#:#‘Pontozás kész’ jelölés eltávolítása assessment#:#set_manual_feedback#:#Manuális visszajelzés assessment#:#shape#:#Alakzat assessment#:#showSuggestedSolution#:#Típus assessment#:#show_all_test_properties_on_info_page#:#Az összes teszttulajdonság megjelenítése -assessment#:#show_all_test_properties_on_info_page_byline#:#Az összes teszttulajdonság felsorolása jelenik meg először a felhasználónak, mint például információ a pontozásról, vagy az eredmények megjelenítéséről. +assessment#:#show_all_test_properties_on_info_page_byline#:#Az ‘Információ’ lapon az összes pontozással és riportálással kapcsolatos teszttulajdonságot megjelenítjük. assessment#:#show_answer_overview#:#Válaszok áttekintésének megjelenítése -assessment#:#show_best_solution#:#Show best solution###28 10 2024 new variable +assessment#:#show_best_solution#:#Legjobb megoldás megjelenítése assessment#:#show_detailed_results#:#Figyelembe vett tesztkitöltés részletes áttekintése assessment#:#show_examview_html#:#Képernyőn -assessment#:#show_hide_best_solution#:#Show or hide best solution###28 10 2024 new variable -assessment#:#show_old_concluding_remarks#:#Show old conlcuding remarks###26 08 2024 new variable -assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new variable +assessment#:#show_hide_best_solution#:#Legjobb eredmény megjelenítése / elrejtése +assessment#:#show_old_concluding_remarks#:#A régi záró megjegyzések megjelenítése +assessment#:#show_old_introduction#:#A régi utasítás megjelenítése assessment#:#show_pass_overview#:#Figyelembe vett tesztkitöltés áttekintése -assessment#:#show_results#:#Show Results###28 10 2024 new variable +assessment#:#show_results#:#Eredmények megjelentése assessment#:#show_user_answers#:#Figyelembe vett tesztkitöltés válaszainak megjelenítése -assessment#:#shuffle_answers#:#Kevert válaszok assessment#:#skip_question#:#Válaszadás kihagyása és következő -assessment#:#solution#:#Solution###28 10 2024 new variable +assessment#:#solution#:#Megoldás assessment#:#solutionText#:#Szöveg assessment#:#solution_contain_keywords#:#A pontozás a következő kulcsszavak előfordulása alapján történik: assessment#:#solution_hint#:#Ismétlő összefoglaláshoz rendelt tartalom -assessment#:#solutions#:#Solutions###28 10 2024 new variable +assessment#:#solutions#:#Megoldások assessment#:#start_tag#:#Kezdő címke assessment#:#statistical_data#:#Statisztikai adatok assessment#:#statistics#:#Statisztika -assessment#:#status_of_attempt#:#Status of Attempt###28 10 2024 new variable +assessment#:#status_of_attempt#:#A kitöltés állapota assessment#:#submit_and_check#:#Mentés és válasz ellenőrzése assessment#:#submit_answer#:#Válasz mentése assessment#:#suggest_range#:#Ajánlott tartomány assessment#:#suggestedSolutionType#:#Hivatkozás a következőre assessment#:#suggested_solution#:#Ismétlő összefoglaló tartalma assessment#:#suggested_solution_added_successfully#:#Sikeresen beállított tartalmat ismétlő összefoglaláshoz. -assessment#:#sync_question_to_pool#:#Synchronize Question###26 08 2024 new variable -assessment#:#ta_resulttable_vc_mode_aria#:#switch question mode###26 08 2024 new variable -assessment#:#tab_nest_answers#:#Nesting###29 07 2022 new variable -assessment#:#tax_filter#:#Taxonomy###26 08 2024 new variable -assessment#:#tax_filter_notax#:#Questions without assigned Taxonomy###26 08 2024 new variable -assessment#:#taxonomy_node_title#:#Taxonomy Node Title###28 10 2024 new variable -assessment#:#taxonomy_title#:#Taxonomy Title###28 10 2024 new variable +assessment#:#sync_question_to_pool#:#Kérdés szinkronizálása +assessment#:#ta_resulttable_vc_mode_aria#:#váltás kérdés módra +assessment#:#tab_nest_answers#:#Behúzás +assessment#:#tax_filter#:#Taxonomia +assessment#:#tax_filter_notax#:#Taxonómia nélküli kérdések +assessment#:#taxonomy_node_title#:#Taxonómia csomópont címe +assessment#:#taxonomy_title#:#Taxonómia címe assessment#:#term#:#Fogalom assessment#:#term_image#:#Kifejezéskép assessment#:#term_text#:#Kifejezésszöveg assessment#:#terms#:#Fogalmak -assessment#:#test_attempts_finished#:#The test pass has been finished for the selected participants.###28 10 2024 new variable +assessment#:#test_attempts_finished#:#A tesztkitöltés befejeződött a kiválasztott kitöltők számára. assessment#:#test_confirm_template_reset#:#Biztos, hogy nem szeretné használni továbbiakban a sablont? assessment#:#test_delete_page#:#Kérdések törlése assessment#:#test_edit_settings#:#Beállítások módosítása assessment#:#test_enable_archiving#:#Archiválás engedélyezése assessment#:#test_has_datasets_warning_page_view#:#A teszt már tartalmaz adatokat. Nem szerkesztheti a kérdéseket, amíg el nem távolítja azokat. -assessment#:#test_has_datasets_warning_page_view_link#:#Résztvevők módosítása +assessment#:#test_has_datasets_warning_page_view_link#:#Kitöltők módosítása assessment#:#test_is_offline#:#Nem kezdheti el a tesztet, mert az offline (nem aktív). assessment#:#test_jump_to#:#Ugrás kérdésre assessment#:#test_move_page#:#Kérdések áthelyezése assessment#:#test_next_question#:#Következő kérdés assessment#:#test_prev_question#:#Előző kérdés -assessment#:#test_question_set_type#:#Selection of Test Questions###29 07 2022 new variable -assessment#:#test_question_set_type_fixed#:#Use of a fixed set of questions###29 07 2022 new variable -assessment#:#test_question_set_type_fixed_info#:#All testees see the same questions.
    You can create questions directly in the test as well as reuse questions from a Question Pool. If you create new questions you can decide to save them in a Question Pool.###29 07 2022 new variable -assessment#:#test_question_set_type_random#:#Use of a random set of questions###29 07 2022 new variable -assessment#:#test_question_set_type_random_info#:#Every testee will see an individually generated set of questions. The questions are drawn from one or more Question Pools.###29 07 2022 new variable +assessment#:#test_question_set_type#:#Tesztkérdések kiválasztása +assessment#:#test_question_set_type_fixed#:#Rögzített kérdéssor használata +assessment#:#test_question_set_type_fixed_info#:#Az összes tesztkitöltő ugyanazokat a kérdéseket kapja.
    A kérdéseket létrehozhatja közvetlenül a tesztben, vagy újra használhatja őket kérdésgyűjteményből. Az újonan létrehozott kérdéseket kérdésgyújteménybe is mentheti. +assessment#:#test_question_set_type_random#:#Véletlenszerű kérdéssor használata +assessment#:#test_question_set_type_random_info#:#Minden tesztkitöltő egyéni kérdéssor kap. A kérdések egy vagy több kérdésgyűjteményből véletlen kiválasztással kerülnek ki. assessment#:#test_results#:#Teszteredmények összefoglalója assessment#:#test_scoring#:#Pontozási beállítások assessment#:#test_template_reset#:#A sablont sikeresen eltávolította. -assessment#:#test_title#:#Test Title###28 10 2024 new variable +assessment#:#test_title#:#Teszt címe assessment#:#test_using_template#:#A teszt ezt a sablont használja: %s. Ha nem szeretne sablont használni a teszthez, és már vannak beállításai, kattintson ide: %s. assessment#:#test_using_template_link#:#Ne használjon a továbbiakban sablont assessment#:#text_correct#:#Helyes szöveg @@ -1350,31 +1327,31 @@ assessment#:#too_many_targets_selected_for_move#:#Egy célpozíciót válasszon assessment#:#toplist_by_score#:#Toplista pontozás alapján assessment#:#toplist_by_time#:#Toplista kidolgozási idő alapján assessment#:#toplist_col_achieved#:#Dátum -assessment#:#toplist_col_participant#:#Résztvevő +assessment#:#toplist_col_participant#:#Kitöltő assessment#:#toplist_col_percentage#:#Százalék assessment#:#toplist_col_rank#:#Helyezés assessment#:#toplist_col_score#:#Pont assessment#:#toplist_col_wtime#:#Kidolgozási idő -assessment#:#total_attempts#:#Total Attempts###28 10 2024 new variable -assessment#:#total_duration#:#Total Duration###28 10 2024 new variable -assessment#:#total_max_points_cannot_be_negative#:#The maximum amount of reachable points cannot be negative.###29 10 2025 new variable +assessment#:#total_attempts#:#Összes kitöltés +assessment#:#total_duration#:#Összes időtartam +assessment#:#total_max_points_cannot_be_negative#:#Az elérhető pontok maximális száma nem lehet negatív. assessment#:#true#:#Igaz -assessment#:#tst_access_code_created#:#Egyedi hozzáférési kódot állítottunk be az Ön számára, hogy bármikor elérhesse teszteredményeit, és hogy lehetősége legyen ennek a tesztnek a folytatására. Jegyezze fel ezt a kódot a teszt későbbi elérése érdekében. +assessment#:#tst_access_code_created#:#Egyedi hozzáférési kódot állítottunk be az Ön számára, hogy bármikor elérhesse teszteredményeit, és hogy lehetősége legyen ennek a tesztnek a folytatására. Jegyezze fel ezt a kódot, hogy később a teszt elérhesse, illetve folytathassa. assessment#:#tst_activate_skill_service#:#Kompetenciaszolgáltatás -assessment#:#tst_activate_skill_service_desc#:#Kérdések kompetenciákhoz rendelését és meghatározott kompetenciaszint eléréshez küszöbérték meghatározását teszi lehetővé. -assessment#:#tst_activation_limited_visibility_info#:#Before and after the period during which the test is available, the test's title will be displayed, but participants won’t be able to take the test. Access, including to tests already in progress, will be prevented once the period of availability has ended.###29 10 2025 new variable -assessment#:#tst_activation_online_info#:#Ha online, a résztvevők kitölthetik a tesztet. -assessment#:#tst_add_quest_cont_edit_mode#:#Visszajelzések és tippek szerkesztésének módja -assessment#:#tst_add_quest_cont_edit_mode_IPE#:#ILIAS-lapszerkesztő használata -assessment#:#tst_add_quest_cont_edit_mode_IPE_info#:#No formatting of text in question and answers. No use of LaTex either. But feedback and hints can be reused when question is embedded in ILIAS learning module.###29 07 2022 new variable -assessment#:#tst_add_quest_cont_edit_mode_RTE#:#Rich Text szerkesztő használata -assessment#:#tst_add_quest_cont_edit_mode_RTE_info#:#Allows text formatting of questions, answers, feedbacks and hints. But feedback and hints cannot be reused when question is embedded in ILIAS learning module.###29 07 2022 new variable -assessment#:#tst_add_quest_cont_edit_mode_plain#:#Use plain text###29 10 2025 new variable -assessment#:#tst_add_quest_cont_edit_mode_plain_info#:#No formatting of text in question, answers and feedback.###29 10 2025 new variable +assessment#:#tst_activate_skill_service_desc#:#A teszt elérhetősége előtt és után a teszt címe jelenik meg, a kitöltők a tesztet nem tudják kitölteni. A teszt elérhetőség után a tesztet már nem lehet kitölteni, illetve befejezni, akkor sem, a kiltöltés már folyamatban van. +assessment#:#tst_activation_limited_visibility_info#:#Az adott időszakon kívül csak a teszt címe látható. Ilyenkor a kitöltők nem tudják kitölteni a tesztet. +assessment#:#tst_activation_online_info#:#Ha online, a kitöltők kitölthetik a tesztet. +assessment#:#tst_add_quest_cont_edit_mode#:#Szerkesztő +assessment#:#tst_add_quest_cont_edit_mode_IPE#:#Egyszerű szöveg használata kérdések és válaszok, ILIAS-lapszerkesztő használata visszajelzések és tippek szerkesztéséhez. +assessment#:#tst_add_quest_cont_edit_mode_IPE_info#:#A kérdések és a válaszok nem formázható szövegek. LaTex sem használható. Viszont a visszajelzések és a tippek újra felhasználhatók, ha kérdés beágyazott az ILIAS-tananyagban. +assessment#:#tst_add_quest_cont_edit_mode_RTE#:#Rich-Text-Editor (TinyMCE) használata a kérdések és a válaszok, továbbá a visszajelzések és a segítségek szerkesztéséhez +assessment#:#tst_add_quest_cont_edit_mode_RTE_info#:#A kérdések, a válaszok, a visszajelzések és a tippek formázható szövegek. Viszont a visszajelzések és a tippek nem használhatók fel újra, ha kérdés beágyazott az ILIAS-tananyagban. +assessment#:#tst_add_quest_cont_edit_mode_plain#:#Egyszerű szöveg használata +assessment#:#tst_add_quest_cont_edit_mode_plain_info#:#A kérdések, a válaszok, a visszajelzések és a tippek nem formázható szövegek. assessment#:#tst_addit_passes_blocked_after_passed_msg#:#A tesztet sikeresen kitöltötte, több kitöltést nem indíthat el. assessment#:#tst_all_test_competences#:#Összes tesztkompetencia assessment#:#tst_all_user_data_deleted#:#Ennek a tesztnek minden felhasználói adatát sikeresen eltávolította. -assessment#:#tst_already_passed_cannot_retake#:#Test already passed. You cannot start the test again.###26 08 2024 new variable +assessment#:#tst_already_passed_cannot_retake#:#A tesztet már sikeresen teljesítette, nem indíthatja el újra. assessment#:#tst_already_submitted#:#A tesztet már befejezte és válaszait elküldte. assessment#:#tst_analysis#:#Analízis assessment#:#tst_anonymity#:#Adatvédelem @@ -1383,50 +1360,50 @@ assessment#:#tst_anonymity_no_anonymization#:#Eredmények nevekkel assessment#:#tst_answer_aggr_answer_header#:#Válasz assessment#:#tst_answer_aggr_frequency_header#:#Gyakoriság assessment#:#tst_answer_details#:#Válasz részletei -assessment#:#tst_answer_fixation#:#Lock Answers###29 10 2025 new variable -assessment#:#tst_answer_fixation_handling#:#Résztvevő válaszai +assessment#:#tst_answer_fixation#:#Válaszok zárolása +assessment#:#tst_answer_fixation_handling#:#Válaszok véglegesítése assessment#:#tst_answer_fixation_none#:#A válaszokat nem véglegesítjük a tesztkitöltés alatt -assessment#:#tst_answer_fixation_none_desc#:#A résztvevők a válaszaikat a teszt befejezésig bármikor módosíthatják. +assessment#:#tst_answer_fixation_none_desc#:#A kitöltők a válaszaikat a teszt befejezésig bármikor módosíthatják. assessment#:#tst_answer_fixation_on_followup_question#:#A válaszok véglegesítése a következő kérdés megjelenésekor -assessment#:#tst_answer_fixation_on_followup_question_desc#:#A résztvevő a válaszát a következő kérdés megjelenése utána már nem módosíthatja. +assessment#:#tst_answer_fixation_on_followup_question_desc#:#A kitöltő a válaszát a következő kérdés megjelenése utána már nem módosíthatja. assessment#:#tst_answer_fixation_on_instant_feedback#:#A válaszok véglegesítése a visszajelzés megjelenésekor -assessment#:#tst_answer_fixation_on_instant_feedback_desc#:#A résztvevő a válaszát a visszajelzés utána már nem módosíthatja. +assessment#:#tst_answer_fixation_on_instant_feedback_desc#:#A kitöltő a válaszát a visszajelzés utána már nem módosíthatja. assessment#:#tst_answer_fixation_on_instantfb_or_followupqst#:#A válaszok véglegesítése a visszajelzés vagy a következő kérdés megjelenésekor -assessment#:#tst_answer_fixation_on_instantfb_or_followupqst_desc#:#A résztvevő a válaszát a visszajelzés, illetve a következő kérdés megjelenése után már módosíthatja. +assessment#:#tst_answer_fixation_on_instantfb_or_followupqst_desc#:#A kitöltő a válaszát a visszajelzés, illetve a következő kérdés megjelenése után már módosíthatja. assessment#:#tst_answer_status_answered#:#Megválaszolt assessment#:#tst_answer_status_editing#:# (módosítás alatt) assessment#:#tst_answer_status_not_answered#:#Meg nem válaszolt assessment#:#tst_answered_questions#:#Megválaszolt kérdések assessment#:#tst_answered_questions_of_total#:#%s / %s assessment#:#tst_answered_questions_test#:#Ebben a tesztben megválaszolt kérdések -assessment#:#tst_attached_xls_file#:#A csatolt Excel fájlban találja a résztvevő teszteredményét. -assessment#:#tst_attempt#:#Próbálkozás -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable -assessment#:#tst_attempt_started#:#Teszt megkezdve +assessment#:#tst_attached_xls_file#:#A csatolt Excel fájlban találja a kitöltő teszteredményét. +assessment#:#tst_attempt#:#Testkitöltés +assessment#:#tst_attempt_limit_message#:#A maximálisan engedélyezett teszkitöltések száma: %s. +assessment#:#tst_attempt_started#:#A kitöltés elkezdődött assessment#:#tst_back_to_pass_details#:#Vissza a kitöltés részleteihez assessment#:#tst_back_to_question_list#:#Vissza kérdéslistához assessment#:#tst_back_to_top#:#Vissza a tetejére assessment#:#tst_back_to_virtual_pass#:#Vissza a kérdésáttekintéshez assessment#:#tst_best_solution_is#:#A legjobb megoldás -assessment#:#tst_block_passes_after_passed#:#További kitöltések tiltás sikeres kitöltés után -assessment#:#tst_block_passes_after_passed_info#:#A résztvevő sikeres kitöltés után már nem töltheti ki többször a tesztet. +assessment#:#tst_block_passes_after_passed#:#További teszkitöltések tiltás sikeres kitöltés után +assessment#:#tst_block_passes_after_passed_info#:#A kitöltő sikeres kitöltés után már nem töltheti ki többször a tesztet. assessment#:#tst_browse_for_qpl_questions#:#Hozzáadás kérdésgyűjteményből assessment#:#tst_browse_for_tst_questions#:#Hozzáadás másik tesztből assessment#:#tst_btn_hide_best_solutions#:#Legjobb megoldások elrejtése assessment#:#tst_btn_rebuild_random_question_stage#:#Kérdések szinkronizálása gyűjteményekből -assessment#:#tst_btn_reset_pool_sync#:#Edit/Cancel Synchronisation###29 07 2022 new variable +assessment#:#tst_btn_reset_pool_sync#:#Szinkronizáció módosítása/megszakítása assessment#:#tst_btn_show_best_solutions#:#Legjobb megoldások megjelenítése assessment#:#tst_cannot_online_due_to_switched_quest_set_type_setting#:#A teszt nem állítható online-ra, mert a teszt-mód beállítása megváltozott. A kérdésbeállításnak megfelelő teszt-módot szükséges beállítani, mielőtt a teszt ismét online-ra állítható. assessment#:#tst_change_dyn_test_question_selection#:#Kérdéskiválasztás módosítása assessment#:#tst_change_points_for_question#:#Válaszért járó pontszám assessment#:#tst_change_quest_set_type_from_old_to_new_with_conflict#:#Hamarosan megváltoztatja a teszt módját: %s -> %s, annak ellenére, hogy ehhez teszt módhoz a kérdése/kérdésgyűjtemények beállítása már megtörtént.
    A jelenlegi beállítások elvesznek. -assessment#:#tst_change_workingtime#:#Extra-idő adása a résztvevőknek +assessment#:#tst_change_workingtime#:#Extra-idő adása a kitöltőknek assessment#:#tst_comp_eval_mode#:#Értékelte assessment#:#tst_comp_points#:#Kompetencia-pontszámok assessment#:#tst_competence#:#Kompetencia -assessment#:#tst_competence_tree#:#Competence tree###29 10 2025 new variable -assessment#:#tst_conditions_checkbox_enabled#:#Exam Conditions###26 08 2024 new variable -assessment#:#tst_conditions_checkbox_enabled_desc#:#Participants must select a checkbox to start the test. Please use the introductory message to present the exam to the participants.###26 08 2024 new variable +assessment#:#tst_competence_tree#:#Kompetenciafa +assessment#:#tst_conditions_checkbox_enabled#:#Vizsgafeltételek +assessment#:#tst_conditions_checkbox_enabled_desc#:#A kitöltőknek ki kell pipálniuk egy jelölőnégyzetet. Kérem, használja az ‘Útmutató szerkesztése’ allapot a vizsga bemutatására. assessment#:#tst_confirm_submit_answers#:#Ellenőrizze megoldását! Az elküldés gomb megnyomása után már nem fogja tudni visszavonni válaszait. assessment#:#tst_conflicting_setting#:#Ez a beállítás ütközik egy másikkal. assessment#:#tst_copy#:#Teszt másolása @@ -1435,8 +1412,8 @@ assessment#:#tst_corr_answ_stat_tbl_header_answer#:#Válasz assessment#:#tst_corr_answ_stat_tbl_header_frequency#:#Gyakoriság assessment#:#tst_corrections_answers_tbl#:#Statisztikák assessment#:#tst_corrections_answers_tbl_subindex#:#%s statisztikái -assessment#:#tst_corrections_incompatible_question_set_type#:#Corrections are only possible if the test uses a fixed set of questions.###29 07 2022 new variable -assessment#:#tst_corrections_manscore_reset_warning#:#%s manuális pontozás található '%s (ID: %s)' kérdéshez, ezek mind elvesznek a kérdés mentésekor. +assessment#:#tst_corrections_incompatible_question_set_type#:#Javítás csak rögzített kérdések esetén lehetséges. +assessment#:#tst_corrections_manscore_reset_warning#:#%s manuális pontozás található ‘%s (ID: %s)’ kérdéshez, ezek mind elvesznek a kérdés mentésekor. assessment#:#tst_corrections_qst_form#:#Pontok javítása assessment#:#tst_corrections_tab_question#:#Kérdés assessment#:#tst_corrections_tab_solution#:#Megoldás @@ -1444,89 +1421,90 @@ assessment#:#tst_corrections_tab_statistics#:#Statisztikák assessment#:#tst_count_correct_solutions#:#Csak a teljesen hibátlan megoldások érnek pontot assessment#:#tst_count_correct_solutions_desc#:#A tökéletes, teljesen hibátlan megoldás maximális pontszámot, minden egyéb 0 pontot ér. Ez azokra a kérdésekre is érvényes, melyeknél részmegoldásért is járna pont. assessment#:#tst_count_partial_solutions#:#Nem teljes vagy részben hibás megoldások is érnek pontot -assessment#:#tst_count_partial_solutions_desc#:#A részmegoldásért jár pont. A helyes részmegoldások pontszámai összeadódnak: a résztvevők pontot kapnak a nem teljes vagy részben hibás megoldásokért ezeknél a kérdéseknél. -assessment#:#tst_current_run_no_longer_valid#:#Your current test run is no longer valid.
    It was probably completed already or finished by a tutor.###26 08 2024 new variable +assessment#:#tst_count_partial_solutions_desc#:#A részmegoldásért jár pont. A helyes részmegoldások pontszámai összeadódnak: a kitöltők pontot kapnak a nem teljes vagy részben hibás megoldásokért ezeknél a kérdéseknél. +assessment#:#tst_current_run_no_longer_valid#:#A jelenlegi teszkitöltése nem érvényes.
    Vélhetően már befejezték vagy a tutor lezárta. assessment#:#tst_delete_missing_mark#:#Válasszon legalább egy érdemjegyet az eltávolításhoz! assessment#:#tst_derive_new_pool#:#Új kérdésgyűjtemény származtatása assessment#:#tst_derive_new_pools#:#Új kérdésgyűjtemények származtatása assessment#:#tst_dont_show_msg_again_in_current_session#:#Ez az üzenet többször ne jelenjen meg a munkamenet alatt. assessment#:#tst_edit_competence_assign#:#Összerendelési tulajdonságok módosítása assessment#:#tst_edit_scoring#:#Pontozás módosítása -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable -assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#‘Kérdések listája’ megjelenítése +assessment#:#tst_enable_questionlist_description#:#A kitöltők bekapcsolhatják a tesztkérdések felsorolását az aktuális kérdés bal oldalán. assessment#:#tst_ending_time#:#Záró időpont -assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable -assessment#:#tst_ending_time_desc#:#Az az időpont, amikor az ILIAS lezárja a tesztet, a résztvevők választ adni utána már nem tudnak. +assessment#:#tst_ending_time_before_starting_time#:#A tesztet lezáró, a kezdődátumnál későbbi dátum. +assessment#:#tst_ending_time_desc#:#Az az időpont, ami utána kitöltők már nem tudnak választ adni. Fontos: Ne használja ezt a lehetőséget vizsgánál, helyett inkább korlátozza a kitöltési időt. Csak ez utóbbi esetben fejeződik be a teszt a szerveroldalon, illetve ekkor mentjük automatikusan az utolsó beírt választ. assessment#:#tst_enter_questionpool#:#Adja meg annak a kérdéssornak a nevét, amelybe menteni szeretné az új kérdést. assessment#:#tst_eval_question_points#:#Eredményes teljesítéshez kérdéseredmények %s assessment#:#tst_eval_results_by_pass#:#%s. tesztkitöltés kérdésre adott válaszai assessment#:#tst_eval_results_by_pass_lo#:#%s tesztkitöltés válaszainak felsorolása assessment#:#tst_eval_results_lo#:#Válaszok felsorolása assessment#:#tst_eval_show_answer#:#Válasz megjelenítése -assessment#:#tst_eval_total_finished#:#Összes befejezett teszt (azon résztvevők, aki az összes tesztkitöltési lehetőségük elhasználták) +assessment#:#tst_eval_total_finished#:#Összes befejezett teszt (azon kitöltők, aki az összes tesztkitöltési lehetőségük elhasználták) assessment#:#tst_eval_total_finished_average_time#:#Teszt átlagos kitöltési ideje assessment#:#tst_eval_total_passed#:#Összes sikeres teszt assessment#:#tst_eval_total_passed_average_points#:#Sikeres tesztek átlagpontszámai assessment#:#tst_eval_total_passed_average_time#:#Sikeres tesztek átlagos kitöltési ideje -assessment#:#tst_eval_total_persons#:#A tesztet elkezdő összes résztvevő száma -assessment#:#tst_exam_access_code#:#Access Code###26 08 2024 new variable -assessment#:#tst_exam_access_code_label#:#Enter access code to continue your already started test.###26 08 2024 new variable -assessment#:#tst_exam_conditions#:#Exam Conditions###26 08 2024 new variable -assessment#:#tst_exam_conditions_label#:#Check to accept the conditions.###26 08 2024 new variable -assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the exam conditions!###26 08 2024 new variable -assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable -assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable -assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable -assessment#:#tst_extratime_added#:#A résztvevő munkaideje megnövelve %s perccel. -assessment#:#tst_extratime_info#:#Amennyiben többször szeretne extra-időt adni ugyanannak a résztvevőnek az idejéhez, az összesített extra-időt adja meg. +assessment#:#tst_eval_total_persons#:#A tesztet elkezdő összes kitöltő száma +assessment#:#tst_exam_access_code#:#Hozzáférési kód +assessment#:#tst_exam_access_code_invalid_message#:#A megadott kód érvénytelen. +assessment#:#tst_exam_access_code_label#:#Adja meg a hozzáférési kódot a már megkezdett tesztkitöltés folytatásához vagy hagyja üresen teljesen új kitöltés indításhoz. +assessment#:#tst_exam_conditions#:#Vizsgafeltételek +assessment#:#tst_exam_conditions_label#:#Jelölje be a feltételek elfogadásához. +assessment#:#tst_exam_conditions_not_checked_message#:#El kell fogadni a vizsgfeltételeket! +assessment#:#tst_exam_ending_time_message#:#A teszt nem indítható %s után. +assessment#:#tst_exam_modal_message_conditions#:#A teszt indításához, kérem, fogadja el a vizsgafeltéleket. +assessment#:#tst_exam_modal_message_conditions_and_password#:#A teszt indításához, kérem, adja meg a jelszót és erősítse meg a vizsgafeltéleket. +assessment#:#tst_exam_modal_message_password#:#A teszt indításához, kérem, adja meg a jelszót. +assessment#:#tst_exam_not_assigned_participant_disclaimer#:#Nem kezdheti meg a teszt kitöltését, mert annak nem kitöltője. +assessment#:#tst_exam_password#:#Tesztjelszó! +assessment#:#tst_exam_password_invalid_message#:#A megadott jelszó nem érvényes! +assessment#:#tst_exam_password_label#:#Jelszó +assessment#:#tst_exam_required_fields_not_filled_message#:#Az összes köteletző mezőt ki kell töltenie! +assessment#:#tst_exam_start#:#Teszt indítása +assessment#:#tst_exam_use_previous_answers#:#Korábbi válaszok +assessment#:#tst_exam_use_previous_answers_label#:#Korábbi tesztkitöltésében megadott válaszai betöltődnek. +assessment#:#tst_extratime_added#:#A kitöltő munkaideje megnövelve %s perccel. +assessment#:#tst_extratime_info#:#Amennyiben többször szeretne extra-időt adni ugyanannak a kitöltőnek az idejéhez, az összesített extra-időt adja meg. assessment#:#tst_extratime_notavailable#:#Extra-időt csak egy kitöltött és elért maximális kitöltési idővel rendelkező teszthez lehet adni. assessment#:#tst_failed#:#Nem sikerült -assessment#:#tst_failed_imp_qst_skl_assign#:#A kérdéseket nem sikerült a következő kompetenciákhoz rendelni. Az érintett kompetenciák nem azonosíthatóak be ebben az ILIAS telepítésben. +assessment#:#tst_failed_imp_qst_skl_assign#:#A kérdéseket nem sikerült a következő kompetenciákhoz rendelni. Az érintett kompetenciák nem azonosíthatók be ebben az ILIAS telepítésben. assessment#:#tst_failed_imp_skl_thresholds#:#A következő kompetenciák határértékeinek importálása meghiúsult, mert az érintett kompetenciák eltérő szinteket tartalmaznak ebben az ILIAS telepítésben. assessment#:#tst_feedback#:#Visszajelzés -assessment#:#tst_feedback_is_given_inline#:#The feedback will be displayed along with your answer.###26 08 2024 new variable -assessment#:#tst_feedback_not_available_for_answer#:#There is no feedback available for your answer.###26 08 2024 new variable +assessment#:#tst_feedback_is_given_inline#:#A visszajelzés a válaszával együtt jelenik meg. +assessment#:#tst_feedback_not_available_for_answer#:#Válaszához nincs visszajelzés. assessment#:#tst_filter_lifecycle_enabled#:#Szűrés életciklus alapján assessment#:#tst_filter_question_type#:#Kérdéstípus assessment#:#tst_filter_question_type_enabled#:#Szűrés kérdéstípus alapján assessment#:#tst_filter_tax_node#:#Taxonómia csomópont assessment#:#tst_filter_taxonomy#:#Taxonómia assessment#:#tst_final_information#:#Teszt befejezése -assessment#:#tst_finish_confirm_button#:#Igen, be szeretném fejezni a tesztet. +assessment#:#tst_finish_confirm_button#:#Igen, befejezem a tesztet. assessment#:#tst_finish_confirm_cancel_button#:#Nem, menjen vissza az előző kérdéshez. -assessment#:#tst_finish_confirmation_question#:#Ha befejezi ezt a tesztet, eléri az engedélyezett tesztkitöltések maximális számát. Nem fog tudni visszatérni a tesztbe, hogy megváltoztassa válaszait. Biztos, hogy be szeretné fejezni a tesztet? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question#:#Most befejezheti a tesztkitöltést. Ezután már nem lesz lehetősége, hogy ezen a kitöltésen módosítson. Biztos, hogy befejezi ezt a tesztkitöltést? +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Most befejezheti a tesztet, amivel eléri az engedélyezett kitöltések számát. Ezután már nem lesz lehetősége, hogy a válaszait módosítsa. Biztos, hogy befejezi a tesztet? assessment#:#tst_finished#:#Befejezve assessment#:#tst_form_dynamic_question_set_config#:#Folyamatos kérdéskiválasztás assessment#:#tst_gap_analysis#:#Gap analízis (rés elemzés) assessment#:#tst_general_properties#:#Általános beállítások -assessment#:#tst_header_participant#:#Az Ön válasza: -assessment#:#tst_header_participant_no_answer#:#Question - not answered###26 08 2024 new variable +assessment#:#tst_header_participant#:#A kérdés és az Ön válasza: +assessment#:#tst_header_participant_no_answer#:#Kérdés - meg nem válaszolt assessment#:#tst_header_solution#:#Legjobb megoldás: -assessment#:#tst_hide_info_tab#:#Hide Info Tab###26 08 2024 new variable -assessment#:#tst_hide_info_tab_desc#:#Hides the tab ‘Info’ of the test.###26 08 2024 new variable -assessment#:#tst_hide_pagecontents#:#Hide page content###26 08 2024 new variable -assessment#:#tst_hide_pagecontents_desc#:#ILIAS content placed before and after the actual question text via the "Edit Page" button will not be displayed in the result views and print output.###26 08 2024 new variable +assessment#:#tst_hide_info_tab#:#Az ‘Információ’ lap elrejtése +assessment#:#tst_hide_info_tab_desc#:#A teszt ‘Információ’ lapja nem látható +assessment#:#tst_hide_pagecontents#:#Oldaltartalom elrejtése +assessment#:#tst_hide_pagecontents_desc#:#Az ‘Oldal szerkesztése’ gombbal a tényleges kérdésszöveg előtt és után elhelyezett LIAS-tartalom nem jelenik meg a eredménynézetekben és a nyomtatási kimenetben. assessment#:#tst_highscore_achieved_ts#:#Időpont assessment#:#tst_highscore_achieved_ts_description#:#A rangsorban a teszt időpontját tartalmazó oszlopot megjelenik. -assessment#:#tst_highscore_all_tables#:#Résztvevő saját helyezése és legkiemelkedőbb helyezések -assessment#:#tst_highscore_all_tables_description#:#A résztvevők információt kapnak a legkiemelkedőbb helyezésekről és a saját helyezéséről +assessment#:#tst_highscore_all_tables#:#Kitöltő saját helyezése és legkiemelkedőbb helyezések +assessment#:#tst_highscore_all_tables_description#:#A kitöltők információt kapnak a legkiemelkedőbb helyezésekről és a saját helyezéséről assessment#:#tst_highscore_anon#:#Nevek nélkül -assessment#:#tst_highscore_anon_description#:#A rangsor résztvevőket azok nevei nélkül sorolja fel. Névtelen tesztkitöltés esetén is ez történik. -assessment#:#tst_highscore_description#:#A résztvevők az 'Eredmények' fül 'Rangsor megjelenítése' alfül alatt jelennek meg. Rákattintva a résztvevők tesztben nyújtott teljesítményei láthatóak. Eléréséhez a 'Hozzáférés a teszteredményekhez' funkciót engedélyezni kell. +assessment#:#tst_highscore_anon_description#:#A rangsor kitöltőket azok nevei nélkül sorolja fel. Névtelen tesztkitöltés esetén is ez történik. +assessment#:#tst_highscore_description#:#A kitöltők az ‘Eredmények’ lap ‘Rangsor megjelenítése’ allap alatt jelennek meg. Rákattintva a kitöltők tesztben nyújtott teljesítményei láthatók. Eléréséhez a ‘Hozzáférés a teszteredményekhez’ funkciót engedélyezni kell. assessment#:#tst_highscore_enabled#:#Rangsor assessment#:#tst_highscore_mode#:#Mód -assessment#:#tst_highscore_own_table#:#Résztvevő saját helyezése -assessment#:#tst_highscore_own_table_description#:#A résztvevők láthatják saját helyezésüket. +assessment#:#tst_highscore_own_table#:#Kitöltő saját helyezése +assessment#:#tst_highscore_own_table_description#:#A kitöltők láthatják saját helyezésüket. assessment#:#tst_highscore_percentage#:#Százalék assessment#:#tst_highscore_percentage_description#:#A rangsorban a teszt százalékát tartalmazó oszlopot megjelenik. assessment#:#tst_highscore_score#:#Pontszám @@ -1534,7 +1512,7 @@ assessment#:#tst_highscore_score_description#:#A rangsorban a pontszámot tartal assessment#:#tst_highscore_top_num#:#Legkiemelkedőbb helyezések hossza assessment#:#tst_highscore_top_num_description#:#Hány helyezés legyen a legkiemelkedőbb helyezések felsorolásában. assessment#:#tst_highscore_top_table#:#Legkiemelkedőbb helyezések -assessment#:#tst_highscore_top_table_description#:#A résztvevők láthatják a legkiemelkedőbb helyezéseket. +assessment#:#tst_highscore_top_table_description#:#A kitöltők láthatják a legkiemelkedőbb helyezéseket. assessment#:#tst_highscore_wtime#:#Tesztkitöltés ideje assessment#:#tst_highscore_wtime_description#:#A rangsorban a tesztkitöltés idejét tartalmazó oszlopot megjelenik. assessment#:#tst_imap_qst_mode#:#Mód @@ -1543,7 +1521,7 @@ assessment#:#tst_imap_qst_mode_sc#:#Egyválaszos kérdés (rádiógombos) assessment#:#tst_import_non_ilias_zip#:#Hiba: A feltöltött importfájl neve megfelelő formátumú. assessment#:#tst_import_verify_found_questions#:#Az ILIAS az alábbi kérdéseket találta a teszt importfájlban. Válassza ki azokat a kérdéseket, amelyeket be szeretne importálni ebbe a tesztbe. assessment#:#tst_inp_all_quest_points_equal_per_pool#:#Csak olyan kérdésgyűjtemények használata, melyben a kérdések pontszám megegyezik. -assessment#:#tst_inp_all_quest_points_equal_per_pool_desc#:#Ha be van kapcsolva, csak azonos pontozású kérdéseket tartalmazó gyűjtemények használhatóak. Az ilyen tesztben az összes résztvevő felhasználó maximálisan elérhető pontszáma így azonos lesz, és az elért eredmények ezáltal jobban összehasonlíthatóak lesznek. Célszerű ezt a lehetőséget választani. +assessment#:#tst_inp_all_quest_points_equal_per_pool_desc#:#Csak azonos pontozású kérdéseket tartalmazó gyűjtemények használhatók. Az ilyen tesztben az összes kitöltő felhasználó maximálisan elérhető pontszáma így azonos lesz, és az elért eredmények ezáltal jobban összehasonlíthatók lesznek. Célszerű ezt a lehetőséget választani. assessment#:#tst_inp_dyn_quest_set_quest_ordering_by_date_desc#:#A kérdések megjelenítésének sorrendje azok utolsó módosítási idején alapszik. assessment#:#tst_inp_dyn_quest_set_quest_ordering_by_tax_desc#:#A kérdések megjelenítésének sorrendje azok taxonómiához rendeltségén alapszik. assessment#:#tst_inp_no_available_tax_hint#:#Nincs elérhető taxonómia a kiválasztott kérdésgyűjteményhez @@ -1553,7 +1531,7 @@ assessment#:#tst_inp_quest_amount_cfg_mode_test#:#Kérdésmennyiség meghatároz assessment#:#tst_inp_quest_amount_per_source_pool#:#Kérdésmennyiség assessment#:#tst_inp_quest_amount_per_test#:#Kérdések szám az egész tesztre nézve assessment#:#tst_inp_source_pool_filter_tax#:#Taxonómia szűrő -assessment#:#tst_inp_source_pool_filter_tax_x#:#'%s' taxonómia használata szűrőként +assessment#:#tst_inp_source_pool_filter_tax_x#:#‘%s’ taxonómia használata szűrőként assessment#:#tst_inp_source_pool_label#:#Kérdésgyűjtemény assessment#:#tst_inp_source_pool_no_tax_filter#:#Nem taxonómia alapú szűrő használata assessment#:#tst_input_dyn_quest_set_answer_status_filter_enabled#:#Válasz állapota alapján szűrő biztosítása @@ -1564,70 +1542,70 @@ assessment#:#tst_input_dynamic_question_set_question_ordering_by_date#:#Kérdés assessment#:#tst_input_dynamic_question_set_question_ordering_by_tax#:#Kérdések rendezése taxonómia alapján assessment#:#tst_input_dynamic_question_set_source_questionpool#:#Forrás kérdésgyűjtemény assessment#:#tst_input_dynamic_question_set_taxonomie_filter_enabled#:#Taxonómia alapján szűrő biztosítása -assessment#:#tst_insert_in_test#:#Insert in Test###28 10 2024 new variable +assessment#:#tst_insert_in_test#:#Beillesztés a tesztbe assessment#:#tst_insert_missing_question#:#Válasszon legalább egy kérdést a tesztbe beillesztéshez! assessment#:#tst_insert_questions#:#Biztos, hogy beilleszti az alábbi kérdés(eke)t a tesztbe? assessment#:#tst_instant_feedback#:#Azonnali visszajelzés -assessment#:#tst_instant_feedback_answer_generic#:#Visszajelzés teljesen hibátlan válasz esetén -assessment#:#tst_instant_feedback_answer_generic_desc#:#Amennyiben a válasz tökéletes, az 'Ellenőrzés' gombra kattintáskor visszajelzést jelenít meg. Amennyiben a válasz nem teljesen hibátlan, másfajta visszajelzés jelenik meg. Mindkét típust az adott kérdés 'Tanulói visszajelzés' fülénél kell meghatározni. +assessment#:#tst_instant_feedback_answer_generic#:#Helyes/Nem helyes válaszra visszajelzés +assessment#:#tst_instant_feedback_answer_generic_desc#:#Amennyiben a válasz tökéletes, az ‘Ellenőrzés’ gombra kattintáskor a helyes megoldás jelenik meg. Amennyiben a válasz nem teljesen hibátlan, a ‘Legalább egy válasz nem helyes’ visszajelzés jelenik meg. Mindkét típust az adott kérdés ‘Visszajelzés’ lapjánál kell meghatározni. assessment#:#tst_instant_feedback_answer_specific#:#Válaszlehetőségenkénti visszajelzés -assessment#:#tst_instant_feedback_answer_specific_desc#:#Az Ellenőrzés gombra kattintva előre meghatározott visszajelzés jelenik meg a felhasználó által kiválasztott akármelyik válaszadási lehetőségre. A kérdéssel együtt kell elkészíteni az összes válaszhoz tartozó a visszajelzést. Nem minden kérdéstípus esetén lehetséges válaszfüggő visszajelzés. -assessment#:#tst_instant_feedback_contents#:#Belefoglalt tartalmak -assessment#:#tst_instant_feedback_desc#:#Amikor a kérdéseket visszajelzéssel állítják be, az a résztvevőknek a teszt kitöltése alatt jelenik meg. +assessment#:#tst_instant_feedback_answer_specific_desc#:#Az ‘Ellenőrzés’ gombra kattintva előre meghatározott visszajelzés jelenik meg a felhasználó által kiválasztott válaszadási lehetőségre. A kérdéssel együtt kell elkészíteni az összes válaszhoz tartozó a visszajelzést. Nem minden kérdéstípus esetén lehetséges válaszfüggő visszajelzés. +assessment#:#tst_instant_feedback_contents#:#Visszajelzés típusai +assessment#:#tst_instant_feedback_desc#:#Amikor a kérdéseket visszajelzéssel állítják be, az a kitöltőknek a teszt kitöltése alatt jelenik meg. assessment#:#tst_instant_feedback_results#:#Elért pontszámok -assessment#:#tst_instant_feedback_results_desc#:#Az Ellenőrzés gombra kattintva megjelenítik az erre a kérdésre adott válaszra kapott pontszám. +assessment#:#tst_instant_feedback_results_desc#:#Az ‘Ellenőrzés’ gombra kattintva megjelenik, mennyi pontot kapna erre válaszra. assessment#:#tst_instant_feedback_solution#:#Legjobb lehetséges válasz megjelenítése -assessment#:#tst_instant_feedback_solution_desc#:#Az Ellenőrzés gombra kattintva megjelenítik erre a kérdésre adható legjobb válasz. +assessment#:#tst_instant_feedback_solution_desc#:#Az ‘Ellenőrzés’ gombra kattintva megjelenítik erre a kérdésre adható legjobb válasz. assessment#:#tst_instant_feedback_trigger#:#Mi váltsa ki a visszajelzést -assessment#:#tst_instant_feedback_trigger_forced#:#A visszajelzést a kérdés megválaszolása váltja ki -assessment#:#tst_instant_feedback_trigger_forced_desc#:#A visszajelzés akkor jelenik meg, amikor a résztvevő megválaszol egy kérdést. -assessment#:#tst_instant_feedback_trigger_manual#:#A résztvevők a visszajelzést manuálisan idézik elő -assessment#:#tst_instant_feedback_trigger_manual_desc#:#A visszajelzés elérhető, de csak akkor jelenik meg, amikor a résztvevő azt manuális előidézi. +assessment#:#tst_instant_feedback_trigger_forced#:#Automatikus visszajelzés +assessment#:#tst_instant_feedback_trigger_forced_desc#:#A visszajelzés automatikusan, válaszadáskor jelenik meg. +assessment#:#tst_instant_feedback_trigger_manual#:#Manuális visszajelzés +assessment#:#tst_instant_feedback_trigger_manual_desc#:#A visszajelzés az ‘Ellenőrzés’ gombra kattintva jelenik meg. assessment#:#tst_introduction#:#Bevezető üzenet assessment#:#tst_introduction_desc#:#Bevezető üzenet megjelenítése a teszt információs oldalán. Ez a szöveg már elérhető a teszt megkezdése előtt. assessment#:#tst_introduction_text#:#Bevezető üzenet -assessment#:#tst_invited_nobody#:#Nincs állandó tesztrésztvevőnek hozzáadott felhasználó, csoport vagy szerep. -assessment#:#tst_invited_selected_users#:#A kiválasztott felhasználókat állandó tesztrésztvevőkként sikeresen felvette. -assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable -assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_invited_nobody#:#Nincs állandó kitöltőnek hozzáadott felhasználó, csoport vagy szerepkör. +assessment#:#tst_invited_selected_users#:#A kiválasztott felhasználókat állandó kitöltőként sikeresen felvette. +assessment#:#tst_launcher_button_label_passes_limit_reached#:#Sajnálom, elhasználta az összes tesztkitöltési lehetőségét! +assessment#:#tst_launcher_status_message_conditions#:#A teszt indításához a vizsgafeltéleket el kell fogadnia. +assessment#:#tst_launcher_status_message_conditions_and_password#:#A teszt indításához a jelszót meg kell adnia és a vizsgafeltéleket el kell fogadnia. +assessment#:#tst_launcher_status_message_password#:#A teszt indításához a jelszót meg kell adnia. assessment#:#tst_level#:#Kompetenciaszint assessment#:#tst_limit_nr_of_tries#:#Tesztkitöltések számának korlátja assessment#:#tst_link_only_unassigned#:#Legalább egy kérdésgyűjteménybe linkelt kérdést választott ki. Csak máshová nem rendelt kérdéseket vehet fel kérdésgyűjteménybe. assessment#:#tst_list_answer_details#:#Mutassa az alábbi listában assessment#:#tst_list_of_answers#:#Válaszok listája assessment#:#tst_list_of_answers_show#:#A pontozott válaszok áttekintése -assessment#:#tst_list_of_questions_end#:#Azelőtt jelenjen meg, mielőtt a résztvevő befejezi a tesztet +assessment#:#tst_list_of_questions_end#:#Azelőtt jelenjen meg, mielőtt a kitöltő befejezi a tesztet assessment#:#tst_list_of_questions_start#:#Azelőtt jelenjen meg, mielőtt az első kérdés megjelenik assessment#:#tst_list_of_questions_with_description#:#Kérdésleírásokat is tartalmazza -assessment#:#tst_man_scoring_answered_hide#:#Hide answered questions###29 10 2025 new variable -assessment#:#tst_man_scoring_answered_only#:#Show only answered questions###29 10 2025 new variable -assessment#:#tst_man_scoring_by_part#:#Rendezés résztvevők szerint +assessment#:#tst_man_scoring_answered_hide#:#Megválaszolt kérdések elrejtése +assessment#:#tst_man_scoring_answered_only#:#Csak a megválaszolt kérdések megjelenítése +assessment#:#tst_man_scoring_by_part#:#Rendezés kitöltők szerint assessment#:#tst_man_scoring_by_qst#:#Rendezés válaszok szerint -assessment#:#tst_man_scoring_finalized#:#Show finalized gradings###29 10 2025 new variable -assessment#:#tst_man_scoring_finalized_hide#:#Hide finalized gradings###29 10 2025 new variable -assessment#:#tst_man_scoring_finalized_only#:#Show only finalized gradings###29 10 2025 new variable -assessment#:#tst_man_scoring_only_answered#:#Only answered###29 07 2022 new variable -assessment#:#tst_man_scoring_questionselection#:#Questions###29 10 2025 new variable -assessment#:#tst_man_scoring_userselection#:#Participants###29 10 2025 new variable +assessment#:#tst_man_scoring_finalized#:#Véglegesített értékelések megjelenítése +assessment#:#tst_man_scoring_finalized_hide#:#Véglegesített értékelések elrejtése +assessment#:#tst_man_scoring_finalized_only#:#Csak a véglegesített értékelések megjelenítése +assessment#:#tst_man_scoring_only_answered#:#Csak a megválaszoltak +assessment#:#tst_man_scoring_questionselection#:#Kérdések +assessment#:#tst_man_scoring_userselection#:#Résztvevők assessment#:#tst_manage_competence_assigns#:#Kompetencia-összerendelések kezelése -assessment#:#tst_manage_competence_select_skills#:#Select Competences###29 10 2025 new variable +assessment#:#tst_manage_competence_select_skills#:#Kompetenciák kiválasztása assessment#:#tst_manscoring_input_max_points_for_question#:#Válaszért adható maximális pontszám -assessment#:#tst_manscoring_input_of_max#:#of###29 10 2025 new variable +assessment#:#tst_manscoring_input_of_max#:#/ assessment#:#tst_manscoring_input_question_and_user_solution#:#Kérdés és
    a felhasználó válasza assessment#:#tst_manscoring_maxpoints_exceeded_input_alert#:#Több, mint a maximum %s pont! -assessment#:#tst_manscoring_no_feedback#:#No written feedback has been given yet.###29 10 2025 new variable +assessment#:#tst_manscoring_no_feedback#:#Még senki sem írt visszajelzést. assessment#:#tst_manscoring_question_section_header#:#Kérdés: %s assessment#:#tst_manscoring_user_notification#:#Értesítés küldése assessment#:#tst_mark#:#Jegy assessment#:#tst_mark_create_new_mark_step#:#Új értékelésséma létrehozása assessment#:#tst_mark_minimum_level#:#Minimumszint (%-ban) -assessment#:#tst_mark_minimum_level_invalid#:#Minimum Level must be between 0 and 100.###26 08 2024 new variable +assessment#:#tst_mark_minimum_level_invalid#:#A minimumszint értéke 0 és 100 köze kell, hogy essen. assessment#:#tst_mark_official_form#:#Hivatalos forma assessment#:#tst_mark_passed#:#Sikeres teljesítés-e -assessment#:#tst_mark_reset_to_simple_mark_schema#:#Egyszerű értékelésséma visszaállítása -assessment#:#tst_mark_reset_to_simple_mark_schema_confirmation#:#If you proceed the current mark schema set for this test will be replaced by a simple mark schema thus deleting all local changes.###26 08 2024 new variable +assessment#:#tst_mark_reset_to_simple_mark_schema#:#Egyszerű (Teljesített/Nem teljesítette) értékelésséma visszaállítása +assessment#:#tst_mark_reset_to_simple_mark_schema_confirmation#:#Ha továbblép, és az ehhez a teszthez beállított jelenlegi értékelési sémát lecseréli egy egyszerű értékelési sémára, akkor evvel törli az összes helyi módosítást is. assessment#:#tst_mark_short_form#:#Rövid forma assessment#:#tst_max_comp_points#:#Max. kompetencia-pontszámok assessment#:#tst_maximum_points#:#Maximális pontszám @@ -1668,7 +1646,7 @@ assessment#:#tst_nav_while_edit_modal_nosave_btn#:#Nincs mentés assessment#:#tst_nav_while_edit_modal_save_btn#:#Mentés assessment#:#tst_nav_while_edit_modal_text#:#Mi legyen az erre a kérdésre adott válaszaival? assessment#:#tst_no_evaluation_data#:#Nincsenek elérhető kiértékelhető adatok. -assessment#:#tst_no_marks_defined#:#Nincsenek érdemjegyek definiálva, adjon meg legalább egy egyszerű érdemjegyképzést. +assessment#:#tst_no_marks_defined#:#Nincsenek értékelések definiálva, adjon meg legalább egy egyszerű értékeléssémát. assessment#:#tst_no_question_selected_for_moving_to_qpl#:#Legalább egy kérdést válasszon, ami kérdésgyűjteményhez kíván adni! assessment#:#tst_no_question_selected_for_removal#:#Jelöljön ki legalább egy kérdést az eltávolításhoz! assessment#:#tst_no_scorable_qst_available#:#Nincs elérhető pontozandó kérdés @@ -1678,12 +1656,12 @@ assessment#:#tst_non_avail_pools_table#:#Nem elérhető kérdésgyűjtemények assessment#:#tst_non_available_pool_newly_derived#:#Az új kérdésgyűjtemény(eke)t sikeresen származtatta. assessment#:#tst_nonpool_questions_get_lost_warning#:#A jelenlegi teszt mód beállításai alapján olyan kérdések is szerepelnek, melyek egy kérdésgyűjteményhez sem tartoznak. Amennyiben ezt a módot megváltoztatja, ezek a kérdések végérvényesen elvesznek. assessment#:#tst_notification_explanation_admin#:#Ezt a levelet azért kapta, mert beállította, hogy kér értesítést. -assessment#:#tst_notify_manscoring_done_body_msg_reason#:#Ezt az értesítést azért kapta, mert résztvevő ebben a tesztben. -assessment#:#tst_notify_manscoring_done_body_msg_subject#:#'%s' teszthez manuális pontozás +assessment#:#tst_notify_manscoring_done_body_msg_reason#:#Ezt az értesítést azért kapta, mert kitöltő ebben a tesztben. +assessment#:#tst_notify_manscoring_done_body_msg_subject#:#‘%s’ teszthez manuális pontozás assessment#:#tst_notify_manscoring_done_body_msg_topic#:#ezúton tájékoztatjuk, hogy az alábbi teszthez a manuális pontozás közzétették: -assessment#:#tst_nr_of_passes#:#Tesztkitöltések száma -assessment#:#tst_nr_of_tries#:#Próbálkozások maximális száma -assessment#:#tst_nr_of_tries_desc#:#Egy résztvevő maximális kitöltéseinek száma. +assessment#:#tst_nr_of_passes#:#Teszkitöltések száma +assessment#:#tst_nr_of_tries#:#Teszkitöltés maximális száma +assessment#:#tst_nr_of_tries_desc#:#Egy kitöltő maximális teszkitöltéseinek száma. assessment#:#tst_num_all_questions#:#Összes kérdés száma assessment#:#tst_num_correct_answered_questions#:#Hibátlanul megválaszoltak assessment#:#tst_num_non_answered_questions_notseen#:#Még meg sem nyitottak @@ -1691,51 +1669,52 @@ assessment#:#tst_num_non_answered_questions_skipped#:#Kihagyottak assessment#:#tst_num_questions#:#Kérdések száma assessment#:#tst_num_selected_questions#:#Kiválasztott kérdések száma assessment#:#tst_num_wrong_answered_questions#:#Hibásan megválaszoltak -assessment#:#tst_objective_oriented_test_pass_without_questions#:#'%s' teszt induló kitöltése nem tartalmaz kérdését. +assessment#:#tst_objective_oriented_test_pass_without_questions#:#‘%s’ teszt induló kitöltése nem tartalmaz kérdését. assessment#:#tst_objective_progress_header#:#Tanulási célkitűzés folyamata assessment#:#tst_objectives_progress_header#:#Tanulási célkitűzések folyamata assessment#:#tst_old_style_rnd_quest_set_broken#:#Ez a véletlen teszt nem helyreállítható állapotban van, mert egy vagy több kérdésgyűjteményét törölték. Ezt a tesztet nem tölthetik ki többé. -assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#A már teljesített tanulási célokhoz tartozó kérdés megválaszolása nem kötelező.

    Olyan kérdésre navigál, melyet már teljesített tanulási célhoz tartozik.
    Választhat:

    Ha folytatja, tovább dolgozhat ezeken a kérdéseken. Válaszait korábbi próbálkozásaiból nem fogadjuk el, mert új véletlen kérdéseket választunk ehhez a próbálkozáshoz, így le is ronthatja tanulási céljának eredményét.

    Ha nem kíván tovább dolgozni a kérdéseken, menjen vissza. Ebben az esetben a kérdéseket nem vesszük figyelembe a kiértékelésnél. -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable -assessment#:#tst_participant#:#Résztvevő +assessment#:#tst_optional_questions_confirmation_fixed_test#:#A már teljesített tanulási célokhoz tartozó kérdésekre már megválaszolták a kérdéseket.

    A következő kérdések a már teljesített tanulási célokhoz vannak rendelve. A korábbi tesztkísérletekből származó válaszai átkerülnek a korábbiakra.

    Ha folytatja, módosíthatja a válaszait. Ez megváltoztathatja a kapcsolódó tanulási célokban elért eredményeit.

    Ha nem szeretné módosítani a válaszait, visszaléphet. +assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#A már teljesített tanulási célokhoz tartozó kérdések opcionálisak.

    A következő kérdések a már teljesített tanulási célokhoz vannak rendelve.

    Ha folytatja, átgondolhatja ezeket a kérdéseket. A kapcsolódó tanulási célokban elért eredményei megváltozhatnak.

    Ha visszalép, a kérdések nem fognak szerepet játszani a teszt értékelésében. +assessment#:#tst_out_of_time_message#:#Sajnálom, elhasználta a teszt kitöltésére engedélyezett időkeretet! +assessment#:#tst_participant#:#Kitöltő assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s -assessment#:#tst_participant_status#:#Résztvevő állapota +assessment#:#tst_participant_status#:#Kitöltő állapota assessment#:#tst_participating_users#:#Felhasználók assessment#:#tst_pass_best_pass#:#Legnagyobb elért pontszám számít -assessment#:#tst_pass_best_pass_desc#:#Amennyiben többször töltheti ki egy résztvevő a tesztet, a legjobb eredményét vesszük figyelembe. -assessment#:#tst_pass_deletion#:#Előző próbálkozások kezelése -assessment#:#tst_pass_deletion_allowed#:#Az előző próbálkozások törlése engedélyezett +assessment#:#tst_pass_best_pass_desc#:#Amennyiben többször töltheti ki egy kitöltő a tesztet, a legjobb eredményét vesszük figyelembe. +assessment#:#tst_pass_deletion#:#Korábbi teszkitöltések kezelése +assessment#:#tst_pass_deletion_allowed#:#A még nem pontozott teszkitöltések törölhetők. assessment#:#tst_pass_details#:#Részletes eredmények assessment#:#tst_pass_details_header_lo_initial#:#A Tanulási célkitűzések Belépő tesztjének eredményei
    %s - %s assessment#:#tst_pass_details_header_lo_qualifying#:#A Tanulási célkitűzések Záró tesztjének eredményei
    %s - %s -assessment#:#tst_pass_details_overview_table_title#:#%s. tesztkitöltés válaszainak részletes áttekintése -assessment#:#tst_pass_finished#:#Test attempt finished###26 08 2024 new variable -assessment#:#tst_pass_finished_on#:#Tesztkitöltés befejezésének időpontja -assessment#:#tst_pass_last_pass#:#Utolsó kitöltés pontszáma számít -assessment#:#tst_pass_last_pass_desc#:#Minden résztvevőnél a legutolsó tesztkitöltését vesszük figyelembe. +assessment#:#tst_pass_details_overview_table_title#:#%s. teszkitöltés válaszainak részletes áttekintése +assessment#:#tst_pass_finished#:#A teszkitöltés befejeződött +assessment#:#tst_pass_finished_on#:#A tesztkitöltés befejezésének időpontja +assessment#:#tst_pass_last_pass#:#Utolsó teszkitöltés pontszáma számít +assessment#:#tst_pass_last_pass_desc#:#Minden kitöltőnél a legutolsó teszkitöltését vesszük figyelembe. assessment#:#tst_pass_overview_for_participant#:#%s teszt-sorszámai -assessment#:#tst_pass_overview_header_lo_initial_all_objectives#:#'%s' kurzus Tanulási célkitűzéseinek
    Belépő tesztjének eredményei -assessment#:#tst_pass_overview_header_lo_initial_per_objective#:#'%s' kurzus Tanulási célkitűzésének
    Belépő tesztjének eredményei -assessment#:#tst_pass_overview_header_lo_qualifying_all_objectives#:#'%s' kurzus Tanulási célkitűzéseinek
    Záró tesztjének eredményei -assessment#:#tst_pass_overview_header_lo_qualifying_per_objective#:#'%s' kurzus Tanulási célkitűzésének
    Záró tesztjének eredményei -assessment#:#tst_pass_scoring#:#Több kitöltés esetén a pontszámítás -assessment#:#tst_pass_scoring_best#:#Best Test Attempt###26 08 2024 new variable -assessment#:#tst_pass_scoring_last#:#Last Test Attempt###26 08 2024 new variable -assessment#:#tst_pass_waiting_enabled#:#Várakozási idő kikényszerítése kitöltések között -assessment#:#tst_pass_waiting_info#:#Ha be van kapcsolva, további kitöltés nem indítható, amíg a megadott idő el nem telik az utolsó kitöltés befejezése óta. +assessment#:#tst_pass_overview_header_lo_initial_all_objectives#:#‘%s’ kurzus Tanulási célkitűzéseinek
    Belépő tesztjének eredményei +assessment#:#tst_pass_overview_header_lo_initial_per_objective#:#‘%s’ kurzus Tanulási célkitűzésének
    Belépő tesztjének eredményei +assessment#:#tst_pass_overview_header_lo_qualifying_all_objectives#:#‘%s’ kurzus Tanulási célkitűzéseinek
    Záró tesztjének eredményei +assessment#:#tst_pass_overview_header_lo_qualifying_per_objective#:#‘%s’ kurzus Tanulási célkitűzésének
    Záró tesztjének eredményei +assessment#:#tst_pass_scoring#:#Több teszkitöltés esetén a pontszámítás +assessment#:#tst_pass_scoring_best#:#Legjobb teszkitöltés +assessment#:#tst_pass_scoring_last#:#Utolsó teszkitöltés +assessment#:#tst_pass_waiting_enabled#:#Várakozási idő kikényszerítése teszkitöltések között +assessment#:#tst_pass_waiting_info#:#További teszkitöltés nem indítható, amíg a megadott idő el nem telik az utolsó teszkitöltés befejezése óta. assessment#:#tst_pass_waiting_time#:#Várakozási idő assessment#:#tst_passed#:#Sikeresen teljesítette -assessment#:#tst_passes#:#Tesztkitöltések +assessment#:#tst_passes#:#Teszkitöltések assessment#:#tst_password#:#Tesztjelszó -assessment#:#tst_password_details#:#Ha adott meg tesztjelszót, a tesztbe belépni szándékozóknak meg kell adniuk azt a teszt elkezdéséhez. +assessment#:#tst_password_details#:#Ha adott meg tesztjelszót, a teszt elkezdéséhez, illetve folytatásához azt meg kell adni. assessment#:#tst_password_enter#:#Adja meg jelszavát assessment#:#tst_password_entered_wrong_password#:#Nem kezdheti meg a tesztet, mert rossz jelszót adott meg. assessment#:#tst_password_form#:#Adja meg a tesztjelszót assessment#:#tst_password_introduction#:#Ez a teszt csak tesztjelszóval érhető el. Adja meg a teszthez tartozó jelszót a teszt elkezdéséhez! assessment#:#tst_percent_solved#:#Elért százalék -assessment#:#tst_player_answer_saved_and_locked#:#Answer is saved and locked and can no longer be changed###26 08 2024 new variable -assessment#:#tst_please_select_source_pool#:#Please select a question pool.###26 08 2024 new variable -assessment#:#tst_please_select_target_for_pool_derives#:#Válassza ki a cél tárolót. +assessment#:#tst_player_answer_saved_and_locked#:#Mentett és zárolt válasz nem módosítható +assessment#:#tst_please_select_source_pool#:#Válassza ki a kérdésgyűjteményt. +assessment#:#tst_please_select_target_for_pool_derives#:#Válassza ki a céltárolót. assessment#:#tst_position#:#%s / %s kérdés assessment#:#tst_position_without_total#:#%s. kérdés assessment#:#tst_postpone#:#Megválaszolatlan kérdések @@ -1748,15 +1727,15 @@ assessment#:#tst_presentation_settings_section#:#Megjelenítés assessment#:#tst_previous_access_code_not_available#:#Egy korábbi kód sem érhető el! assessment#:#tst_proceed#:#Folytatás assessment#:#tst_processing_time#:#Elhasználható idő korlátja -assessment#:#tst_processing_time_desc#:#A résztvevők csak meghatározott ideig dolgozhatnak a teszten. A visszaszámlálás akkor kezdődik, amikor a felhasználó először indítja a tesztet. A teszt felfüggesztése nem állítja meg az órát. Ha a lehetséges kitöltések száma korlátozott, megjelenik az extra idő biztosítása a kitöltőknek lehetőség a 'Műszerfal' fül alatt. +assessment#:#tst_processing_time_desc#:#E-vizsgákhoz/távvizsgákhoz hasznos beálltás. A kitöltők csak meghatározott ideig dolgozhatnak a teszten. A visszaszámlálás akkor kezdődik, amikor a felhasználó először indítja a tesztet. A teszt felfüggesztése nem állítja meg az órát. Ha a lehetséges kitöltések száma korlátozott, megjelenik az extra idő biztosítása a kitöltőknek lehetőség a ‘Résztvevők’ lapon. assessment#:#tst_processing_time_duration#:#Maximális feldolgozási idő -assessment#:#tst_processing_time_duration_desc#:#Meghatározza a teszt futtatásának maximális időhosszát +assessment#:#tst_processing_time_duration_desc#:#Meghatározza a teszt befejezésének maximális időhosszát assessment#:#tst_qbt_filter_question_title#:#Kérdés címe assessment#:#tst_qst_added_to_pool_p#:#A kérdéseket sikeresen hozzáadta a kiválasztott kérdésgyűjteményhez. assessment#:#tst_qst_added_to_pool_s#:#A kérdést sikeresen hozzáadta a kiválasztott kérdésgyűjteményhez. assessment#:#tst_qst_order#:#Sorrend -assessment#:#tst_qst_skl_cfg_in_pool_hint_dynquestset#:#A tesztek a kompetencia és kérdés összerendelése '%s' módon a megfelelő kérdésgyűjteményben történik:
    %s

    A küszöbértékek beállítása itt, a tesztben szükséges. -assessment#:#tst_qst_skl_cfg_in_pool_hint_rndquestset#:#A tesztek a kompetencia és kérdés összerendelése '%s' módon a megfelelő kérdésgyűjtemény(ek)ben történik:
    %s

    A küszöbértékek beállítása itt, a tesztben szükséges. +assessment#:#tst_qst_skl_cfg_in_pool_hint_dynquestset#:#A tesztek a kompetencia és kérdés összerendelése ‘%s’ módon a megfelelő kérdésgyűjteményben történik:
    %s

    A küszöbértékek beállítása itt, a tesztben szükséges. +assessment#:#tst_qst_skl_cfg_in_pool_hint_rndquestset#:#A tesztek a kompetencia és kérdés összerendelése ‘%s’ módon a megfelelő kérdésgyűjtemény(ek)ben történik:
    %s

    A küszöbértékek beállítása itt, a tesztben szükséges. assessment#:#tst_question#:#Kérdés assessment#:#tst_question_amount#:#Kérdésmennyiség assessment#:#tst_question_answer_status#:#Mely kérdések jelenjenek meg? @@ -1774,11 +1753,11 @@ assessment#:#tst_question_not_marked#:#Kérdés nincs megjelölve assessment#:#tst_question_offer#:#Elfogadja ezt a mintát vagy másikat szeretne? assessment#:#tst_question_set_type#:#Tesztkérdések kiválasztása assessment#:#tst_question_set_type_dynamic#:#Kérdésfolyam - egy kérdésgyűjtemény összes kérdése -assessment#:#tst_question_set_type_dynamic_desc#:#Minden résztvevő egy előre kiválasztott kérdésgyűjtemény kérdéseit kapja meg. A hibásan megválaszolt kérdések újra megjelennek. A már futó teszthez új kérdés adható, illetve a már hozzárendelt kérdések módosíthatóak. +assessment#:#tst_question_set_type_dynamic_desc#:#Minden kitöltő egy előre kiválasztott kérdésgyűjtemény kérdéseit kapja meg. A hibásan megválaszolt kérdések újra megjelennek. A már futó teszthez új kérdés adható, illetve a már hozzárendelt kérdések módosíthatók. assessment#:#tst_question_set_type_fixed#:#Előre meghatározott kérdések -assessment#:#tst_question_set_type_fixed_desc#:#Minden résztvevő ugyanazokat a kérdéseket kapja. +assessment#:#tst_question_set_type_fixed_desc#:#Minden kitöltő ugyanazokat a kérdéseket kapja. assessment#:#tst_question_set_type_random#:#Véletlenszerű kérdések -assessment#:#tst_question_set_type_random_desc#:#Minden résztvevő más-más kérdéseket kap. A kérdések véletlenszerűen kerülnek kiválasztásra egy vagy több kérdésgyűjteményekből. +assessment#:#tst_question_set_type_random_desc#:#Minden kitöltő más-más kérdéseket kap. A kérdések véletlenszerűen kerülnek kiválasztásra egy vagy több kérdésgyűjteményekből. assessment#:#tst_question_title#:#Kérdéscím assessment#:#tst_question_type#:#Kérdéstípus assessment#:#tst_questions_inserted#:#A kérdés(eke)t sikeresen beillesztette. @@ -1788,7 +1767,7 @@ assessment#:#tst_random_question_set_source_questionpool_summary_string#:#%s (Ú assessment#:#tst_random_select_questionpool#:#Válassza ki a kérdésgyűjteményt, hogy választhasson a kérdések közül assessment#:#tst_reached_points#:#Elért pontszám assessment#:#tst_reached_points_of_max#:#%s / %s -assessment#:#tst_remove_mark#:#Ennek a jelnek az eltávolítása +assessment#:#tst_remove_mark#:#Megjelölés eltávolítása assessment#:#tst_remove_question#:#Biztos, hogy eltávolítja az alábbi kérdéseket a tesztből? assessment#:#tst_remove_questions#:#Biztos, hogy eltávolítja az alábbi kérdéseket a tesztből? assessment#:#tst_remove_questions_and_results#:#Ezt a tesztet %s felhasználó már kitöltötte. A kérdések eltávolításával törli ezen felhasználók minden teszteredményét is. Biztos, hogy eltávolítja az alábbi kérdés(eke)t? @@ -1799,48 +1778,48 @@ assessment#:#tst_report_after_test#:#Teszteredményekről jelentés felajánlás assessment#:#tst_report_never#:#Egy teszteredmény sem érhető el assessment#:#tst_reporting_date#:#Dátum assessment#:#tst_res_jump_to_participant_btn#:#Ugrás -assessment#:#tst_res_jump_to_participant_hint_opt#:#Ugrás a résztvevőkhöz +assessment#:#tst_res_jump_to_participant_hint_opt#:#--Ugrás a kitöltőkhöz-- assessment#:#tst_res_lo_objectives_header#:#Releváns Tanulási célkitűzések -assessment#:#tst_res_lo_try_header#:#Próbálkozás -assessment#:#tst_res_lo_try_n#:#%s próbálkozás -assessment#:#tst_res_tab_msg_no_lp_access#:#You are currently not allowed to access your Learning Progress, as you are not allowed to see your test results.###29 10 2025 new variable -assessment#:#tst_res_tab_msg_res_after_date#:#Itt mutatjuk meg az eredményeket ekkortól: %s -assessment#:#tst_res_tab_msg_res_after_date_no_res#:#A teszt kitöltésekor itt mutatjuk meg az eredményeket ekkortól: %s -assessment#:#tst_res_tab_msg_res_after_finish_test#:#Itt mutatjuk meg az eredményeket a teszt befejezése után. -assessment#:#tst_res_tab_msg_res_after_taking_test#:#Itt mutatjuk meg az eredményeket a teszt megkezdése után. -assessment#:#tst_res_tab_msg_res_after_test_passed#:#Itt mutatjuk meg az eredményeket a teszt sikeres kitöltése után. -assessment#:#tst_reset_processing_time#:#A kitöltési idő visszaállítása minden tesztkitöltéshez -assessment#:#tst_reset_processing_time_desc#:#A kitöltési idő értéke visszaáll a megadott maximális kitöltési idő értékére. Ez a beállítás csak akkor működik, ha engedélyezett a többszörös tesztkitöltés. +assessment#:#tst_res_lo_try_header#:#Teszkitöltés +assessment#:#tst_res_lo_try_n#:#%s. teszkitöltés +assessment#:#tst_res_tab_msg_no_lp_access#:#Jelenleg nem érheti el a saját tanulási haladását, mert a teszt eredményeit nem láthajta. +assessment#:#tst_res_tab_msg_res_after_date#:#Itt mutatjuk meg az eredményeit ekkortól: %s +assessment#:#tst_res_tab_msg_res_after_date_no_res#:#A teszt kitöltésekor itt mutatjuk meg az eredményeit ekkortól: %s +assessment#:#tst_res_tab_msg_res_after_finish_test#:#Itt mutatjuk meg az eredményeit a teszt befejezése után. +assessment#:#tst_res_tab_msg_res_after_taking_test#:#Itt mutatjuk meg az eredményeit a teszt megkezdése után. +assessment#:#tst_res_tab_msg_res_after_test_passed#:#Itt mutatjuk meg az eredményeit a teszt sikeres kitöltése után. +assessment#:#tst_reset_processing_time#:#Az összes teszkitöltés időkorlátjának alapértékre állítása +assessment#:#tst_reset_processing_time_desc#:#A kitöltési időkorlát értéke visszaáll a megadott maximális értékre. Ez a beállítás csak akkor működik, ha a teszt többszörös kitölthető. assessment#:#tst_result#:#Teszteredmény -assessment#:#tst_result_pass#:#Tesztkitöltés végeredményei +assessment#:#tst_result_pass#:#Teszkitöltés végeredményei assessment#:#tst_result_user_name#:#%s eredményei: -assessment#:#tst_result_user_name_pass#:#%s. tesztkitöltés eredménye, %s +assessment#:#tst_result_user_name_pass#:#%s. teszkitöltés eredményei, %s assessment#:#tst_results#:#Teszteredmények assessment#:#tst_results_access_always#:#Azonnal -assessment#:#tst_results_access_always_desc#:#A résztvevők elérhetik eredményeiket az 'Eredmények' fül alatt a tesztkitöltésük ideje alatt, továbbá a teszt befejezése után átirányítjuk őket az 'Eredmények' fülre. -assessment#:#tst_results_access_date#:#Időpont -assessment#:#tst_results_access_date_desc#:#A résztvevők a megadott időpont után érhetik el eredményüket az 'Eredmények' fül alatt. +assessment#:#tst_results_access_always_desc#:#A kitöltők elérhetik eredményeiket az ‘Eredmények’ lapon a tesztkitöltésük ideje alatt, továbbá a teszt befejezése után átirányítjuk őket az ‘Eredmények’ lapra. +assessment#:#tst_results_access_date#:#Elérhető ettől (dátum) +assessment#:#tst_results_access_date_desc#:#A kitöltők a megadott időpont után érhetik el eredményüket az ‘Eredmények’ lapon. assessment#:#tst_results_access_enabled#:#Hozzáférés a teszteredményekhez -assessment#:#tst_results_access_enabled_desc#:#A résztvevők számára elérhetővé válik az 'Eredmények' fül. Ebben és a következő részekben határozhatja meg, hogy a jelentés mikortól legyen elérhető és milyen információkat tartalmazzon. -assessment#:#tst_results_access_finished#:#A tesztkitöltés befejezése után -assessment#:#tst_results_access_finished_desc#:#A végeredmény a teszt befejezése után rögtön megjelenik. A teszt befejezése után a résztvevők bármikor elérhetik eredményeiket az 'Eredmények' fül alatt. -assessment#:#tst_results_access_passed#:#A teszt sikeres kitöltése után -assessment#:#tst_results_access_passed_desc#:#A végeredmény a teszt sikeres kitöltése után jelenik meg. A teszt sikeres kitöltés után a résztvevők bármikor elérhetik eredményeiket az 'Eredmények' fül alatt. +assessment#:#tst_results_access_enabled_desc#:#A kitöltők számára elérhetővé válik az ‘Eredmények’ lap. Ebben és a következő részekben határozhatja meg, hogy a jelentés mikortól legyen elérhető és milyen információkat tartalmazzon. +assessment#:#tst_results_access_finished#:#A teszkitöltés befejezése után +assessment#:#tst_results_access_finished_desc#:#A végeredmény a teszkitöltés befejezése után azonnal megjelenik. A teszkitöltés befejezése után a kitöltők bármikor elérhetik eredményeiket az ‘Eredmények’ lapon. +assessment#:#tst_results_access_passed#:#A teszkitöltés sikeres kitöltése után +assessment#:#tst_results_access_passed_desc#:#A végeredmény a teszt sikeres kitöltése után jelenik meg. A teszt sikeres kitöltés után a kitöltők bármikor elérhetik eredményeiket az ‘Eredmények’ lapon. assessment#:#tst_results_access_setting#:#Időpont assessment#:#tst_results_aggregated#:#Összesített teszteredmény assessment#:#tst_results_back_introduction#:#Vissza a bevezető üzenethez assessment#:#tst_results_back_overview#:#Vissza az eredmények áttekintéséhez -assessment#:#tst_results_details_options#:#A teszteredményekben megjelenítendő további részletek -assessment#:#tst_results_gamification#:#Gamification###26 08 2024 new variable -assessment#:#tst_results_grading_opt_show_details#:#Show detailed test results###26 08 2024 new variable -assessment#:#tst_results_grading_opt_show_details_desc#:#In addition to the summary test result, a "Detailed Results" action is provided. The "Detailed test results" table shows the titles of the questions and the points achieved for each run. The content of the table can be further supplemented in the "Further options" section.###26 08 2024 new variable +assessment#:#tst_results_details_options#:#További lehetőségek +assessment#:#tst_results_gamification#:#Gamifikació +assessment#:#tst_results_grading_opt_show_details#:#Részletes teszteredmények megjelenítése +assessment#:#tst_results_grading_opt_show_details_desc#:#Az összefoglaló teszteredmény mellett egy ‘Részletes eredmények’ művelet megjelenik. A ‘Részletes teszteredmények’ táblázat a kérdések címét és az egyes kitöltéseken elért pontokat jeleníti meg. assessment#:#tst_results_grading_opt_show_mark#:#Érdemjegy megjelenítése -assessment#:#tst_results_grading_opt_show_mark_desc#:#Érdemjegyről az információt a teszteredmények összegzéséhez fűzzük hozzá. A résztvevők elérhetik eredményeiket az 'Eredmények' fül alatt. +assessment#:#tst_results_grading_opt_show_mark_desc#:#Érdemjegyről az információt a teszteredmények összegzéséhez fűzzük hozzá. A kitöltők elérhetik eredményeiket az ‘Eredmények’ lapon. assessment#:#tst_results_grading_opt_show_status#:#Sikeres/Sikertelen állapot megjelenítése -assessment#:#tst_results_grading_opt_show_status_desc#:#Sikeres/Sikertelen állapotról az információt a teszteredmények összegzéséhez fűzzük hozzá. A résztvevők elérhetik eredményeiket az 'Eredmények' fül alatt.
    +assessment#:#tst_results_grading_opt_show_status_desc#:#Sikeres/Sikertelen állapotról az információt a teszteredmények összegzéséhez fűzzük hozzá. A kitöltők elérhetik eredményeiket az ‘Eredmények’ lapon.
    assessment#:#tst_results_overview#:#Teszteredmények áttekintése assessment#:#tst_results_print_best_solution#:#Legjobb megoldás -assessment#:#tst_results_print_best_solution_info#:#Kérdésenként a lehetséges legjobb megoldás megjelenik. +assessment#:#tst_results_print_best_solution_info#:#Kérdésenként a lehetséges legjobb megoldás jelenik meg. assessment#:#tst_resume_test#:#Teszt folytatása assessment#:#tst_revert_changes#:#Módosítás visszavonása assessment#:#tst_rnd_quest_cfg_tab_general#:#Beállítások @@ -1856,47 +1835,47 @@ assessment#:#tst_save_thresholds#:#Küszöbértékek mentése assessment#:#tst_saved_manscoring_by_question_successfully#:#%s tesztkitöltésének %s kérdéséhez a manuális pontozás mentése sikerült. assessment#:#tst_saved_manscoring_successfully#:#%s. %s tesztkitöltéséhez a manuális pontozás mentése sikerült. assessment#:#tst_score_cut_question#:#Az összes kérdésnél a negatív pontszám 0-ra módosítása -assessment#:#tst_score_cut_question_desc#:#Előfordulhat, hogy egy résztvevők hibás válaszával negatív pontszámot kapna egy kérdésre. Evvel ezt elkerülheti, így minden egyes kérdésre a legkisebb elérhető pontszám 0 lesz. +assessment#:#tst_score_cut_question_desc#:#Előfordulhat, hogy egy kitöltő hibás válaszával negatív pontszámot kapna egy kérdésre. Evvel ezt elkerülheti, így minden egyes kérdésre a legkisebb elérhető pontszám 0 lesz. assessment#:#tst_score_cut_test#:#Negatív pontszámú végeredmény 0-ra módosítása -assessment#:#tst_score_cut_test_desc#:#Az összes kérdésre elért válasz pontszáma - melyek között lehet negatív is - összeadódik. A végeredmény, az összpontszám azonban nem lehet negatív, azt 0-ra módosítjuk. Ebben az esetben a negatív pontszámok nagy hangsúlyt kapnak. +assessment#:#tst_score_cut_test_desc#:#Az összes kérdésre elért válasz pontszáma - melyek között lehet negatív is - összeadódik. A végeredmény, az összpontszám azonban nem lehet negatív, azt 0-ra módosítjuk. Ebben az esetben a hibás, illetve a részben hibás válaszok negatív pontszámai nagy hangsúlyt kaphatnak a végős pontszámban, eredményben. assessment#:#tst_score_cutting#:#Negatív pontszámok -assessment#:#tst_search_users#:#Résztvevők keresése +assessment#:#tst_search_users#:#Kitöltők keresése assessment#:#tst_select_questionpool#:#Válasszon ki egy kérdésgyűjteményt a létrehozott kérdés mentéséhez! assessment#:#tst_selected_user_data_deleted#:#A kiválasztott felhasználó(k) tesztadatai sikeresen eltávolította. assessment#:#tst_sequence_properties#:#Teszt felügyelete: Felhasználók számára elérhető funkcionalitások assessment#:#tst_set_offline_due_to_switched_question_set_type_setting#:#A teszt offline lett, mert a teszt-mód beállítása megváltozott. Új teszt-módot szükséges beállítani a kérdésbeállításnak megfelelően, mielőtt a teszt ismét online-ra állítható. -assessment#:#tst_settings_conflict_postpone_and_lock#:#"Unanswered questions will be enqueued" cannot be used together with "Lock Answers After Moving to Next Question".###26 08 2024 new variable -assessment#:#tst_settings_conflict_shuffle_and_lock#:#"Shuffle Questions" cannot be used together with "Lock Answers After Moving to Next Question".###26 08 2024 new variable -assessment#:#tst_settings_form_reload_needed#:#The form needed to be reloaded to avoid data loss as the available settings have changed due to the removal of all results of participants.###29 10 2025 new variable -assessment#:#tst_settings_header_additional#:#Additional Features###26 08 2024 new variable +assessment#:#tst_settings_conflict_postpone_and_lock#:#A ‘Meg nem válaszolt kérdések sorba állítása’ nem használható együtt a ‘Válaszok véglegesítése a következő kérdés megjelenésekor’ lehetőséggel. +assessment#:#tst_settings_conflict_shuffle_and_lock#:#A ‘Kérdések keverése’ nem használható együtt a ‘Válaszok véglegesítése a következő kérdés megjelenésekor’ lehetőséggel. +assessment#:#tst_settings_form_reload_needed#:#Az adatvesztés elkerülése érdekében újra kellett tölteni az űrlapot, mivel az elérhető beállítások megváltoztak a résztvevők összes eredményének eltávolítása miatt. +assessment#:#tst_settings_header_additional#:#További jellemzők assessment#:#tst_settings_header_execution#:#Teszt kezelése: hozzáférés assessment#:#tst_settings_header_intro#:#A teszt megkezdése előtti információ assessment#:#tst_settings_header_test_run#:#Teszt kezelése: teszt futtatása -assessment#:#tst_settings_not_found#:#Missing Test Settings###29 10 2025 new variable -assessment#:#tst_settings_not_found_msg#:#Test Settings could not found. This may be due to a missing migration step. Please contact your system administrator.###29 10 2025 new variable +assessment#:#tst_settings_not_found#:#Hiányzó tesztbeállítások +assessment#:#tst_settings_not_found_msg#:#A teszbeállítások nem találhatók. Ennek oka vélhetően egy hiányzó migrációs lépés. Kérem, vegye fel a kapcsolatot az üzemeltetőkkel. assessment#:#tst_show_answer_sheet#:#Válaszok megjelenítése assessment#:#tst_show_cancel#:#Teszt felfüggesztése -assessment#:#tst_show_cancel_description#:#A résztvevő egy gomb megnyomásával felfüggeszthetik a teszt töltését, hogy később folytathassák azt. FIGYELEM: A teszt felfüggesztése nem állítja le az órát akkor sem, ha maximálisan elhasználható idő be lett állítva. +assessment#:#tst_show_cancel_description#:#A kitöltő egy gomb megnyomásával felfüggeszthetik a teszt töltését, hogy később folytathassák azt. FIGYELEM: A teszt felfüggesztése nem állítja le az órát akkor sem, ha maximálisan elhasználható idő be lett állítva. assessment#:#tst_show_comp_results#:#Kompetenciaeredmények assessment#:#tst_show_results#:#Teszteredmények assessment#:#tst_show_side_list#:#Kérdéslista megjelenítése assessment#:#tst_show_solution_answers_only#:#Eredmények nyomtatási előnézete (csak a válaszoké) -assessment#:#tst_show_solution_answers_only_desc#:#Ha be van kapcsolva, a 'Tartalom módosítása' fülön a kérdéshez beállított tartalom nem jelenik meg nyomtatásban. Papír spórolása esetén válassza ezt az opciót. -assessment#:#tst_show_solution_details_singlepage#:#Scored Answers on single pages###26 08 2024 new variable -assessment#:#tst_show_solution_details_singlepage_desc#:#Participants can access each question individually and see if their answers were correct and how many points they scored.###26 08 2024 new variable +assessment#:#tst_show_solution_answers_only_desc#:#A ‘Tartalom módosítása’ lapon a kérdéshez beállított tartalom nem jelenik meg nyomtatásban. Papír spórolása esetén válassza ezt az opciót. +assessment#:#tst_show_solution_details_singlepage#:#Pontozott válaszok egyetlen oldalon +assessment#:#tst_show_solution_details_singlepage_desc#:#A kitöltők minden kérdéshez külön-külön hozzáférhetnek, és megnézhetik, hogy helyesek voltak-e a válaszaik, illetve, hogy hány pontot szereztek. assessment#:#tst_show_solution_feedback#:#Válaszspecifikus visszajelzés megjelenítése a teszteredményekben -assessment#:#tst_show_solution_feedback_desc#:#Válaszfüggő visszajelzés jelenik meg a teszteredményeknél a kérdések mellett. Figyeljen arra, hogy ezen opció használatára akkor van lehetőség, ha bekapcsolta a 'Résztvevők pontozott válaszai'-t és a visszajelzés a kérdésekkel együtt készült az első helyen. +assessment#:#tst_show_solution_feedback_desc#:#Válaszfüggő visszajelzés jelenik meg a teszteredményeknél a kérdések mellett. Figyeljen arra, hogy ezen opció csak akkor működik, ha bekapcsolta a ‘Kitöltők pontozott válaszai’-t, illetve a ‘Pontozott válaszok egy oldalon’-t és a visszajelzés a kérdésekhez elkészült. assessment#:#tst_show_solution_printview#:#Válaszok listájának megjelenítése -assessment#:#tst_show_solution_printview_desc#:#Az összes kérdésből és az adott résztvevő válaszaiból egy áttekintés készül. Ez a felsorolás az 'Eredmények' fül 'Pontozott válaszok áttekintése' alfül alatt érhető el. +assessment#:#tst_show_solution_printview_desc#:#Az összes kérdésből és az adott kitöltő válaszaiból egy áttekintés készül. Ez a felsorolás az ‘Eredmények’ lap ‘Pontozott válaszok áttekintése’ allap alatt érhető el. assessment#:#tst_show_solution_signature#:#Aláírás-helyőrző megjelenítése -assessment#:#tst_show_solution_signature_desc#:#Az aláírás helye megjelenik nyomtatott verzióban. Ennek használatához ne felejtse bekapcsolni a 'Részletes teszteredmények táblázata' a funkciót. +assessment#:#tst_show_solution_signature_desc#:#Az aláírás helye megjelenik nyomtatott verzióban. Ennek használatához ne felejtse bekapcsolni a ‘Részletes teszteredmények táblázata’ a funkciót. assessment#:#tst_show_solution_suggested#:#Ismétlő összefoglaló tartalom megjelenítése -assessment#:#tst_show_solution_suggested_desc#:#Ha az első helyen a teszt kérdéseihez ismétlő összefoglaló tartalom van hozzárendelve, akkor ez megjelenik a 'Részletes teszteredmények táblázata' tartalmában. A résztvevők lehetőséget kapnak újratanulásra. Hogy hatásos legyen ez az opció, kapcsolja be a 'Hozzáférés a teszteredményekhez' fül alatt a 'Részletes teszteredmények táblázata' opciót. +assessment#:#tst_show_solution_suggested_desc#:#Ha az első helyen a teszt kérdéseihez ismétlő összefoglaló tartalom van hozzárendelve, akkor ez megjelenik a ‘Részletes teszteredmények táblázata’ tartalmában. A kitöltők lehetőséget kapnak újratanulásra. Hogy hatásos legyen ez az opció, kapcsolja be a ‘Hozzáférés a teszteredményekhez’ lapon a ‘Részletes teszteredmények táblázata’ opciót. assessment#:#tst_show_summary#:#Kérdéslista megjelenítése -assessment#:#tst_show_summary_description#:#A résztvevő számára megjelenik a 'Kérdéslista' gomb, amivel bekapcsolhatják az összes kérdés felsorolását. Ekkor a képernyőn az összesített állapot is megjelenik. +assessment#:#tst_show_summary_description#:#A kitöltő számára megjelenik a ‘Kérdéslista’ gomb, amivel bekapcsolhatják az összes kérdések felsorolását, ahol látszódik, melyikre adtak már választ. További beállítási lehetőséget alább talál. assessment#:#tst_show_toplist#:#Rangsor assessment#:#tst_shuffle_questions#:#Kérdések összekeverése -assessment#:#tst_shuffle_questions_description#:#Kérdéssorrend keverése minden tesztkitöltéshez. +assessment#:#tst_shuffle_questions_description#:#A kérdések sorrendje elterő lesz minden teszkitöltésnél. assessment#:#tst_signature#:#Aláírás assessment#:#tst_single_answer_details#:#Egyszeres válasz megjelenítése assessment#:#tst_skill_triggerings_num_req_answers#:#Kompetencia felméréséhez szükséges válaszok száma @@ -1913,7 +1892,7 @@ assessment#:#tst_start_dyn_test_with_cur_quest_sel#:#Teszt indítása a jelenleg assessment#:#tst_start_new_test_pass#:#Új tesztkitöltés elkezdése assessment#:#tst_start_test#:#Teszt indítása assessment#:#tst_starting_time#:#Kezdő időpont -assessment#:#tst_starting_time_desc#:#Az az időpont, ami után az 'Indítás' gomb megnyomásával a résztvevők megkezdhetik a válaszadást. +assessment#:#tst_starting_time_desc#:#Az az időpont, ami után az ‘Indítás’ gomb megnyomásával a kitöltők megkezdhetik a válaszadást. assessment#:#tst_stat_result_atimeofwork#:#Munkaidő átlaga assessment#:#tst_stat_result_firstvisit#:#Első látogatás assessment#:#tst_stat_result_lastvisit#:#Utolsó látogatás @@ -1923,28 +1902,28 @@ assessment#:#tst_stat_result_pworkedthrough#:#A teljes munka eddig elvégzett r assessment#:#tst_stat_result_qmax#:#Kérdések teljes számra assessment#:#tst_stat_result_qworkedthrough#:#Kérdések, amelyeken már keresztülhaladt assessment#:#tst_stat_result_rank_median#:#A mediánhoz rendelhető helyezés -assessment#:#tst_stat_result_rank_participant#:#A résztvevő helyezése +assessment#:#tst_stat_result_rank_participant#:#A kitöltő helyezése assessment#:#tst_stat_result_resultsmarks#:#Teszteredmények érdemjegyben kifejezve assessment#:#tst_stat_result_resultspoints#:#Teszteredmények pontban kifejezve -assessment#:#tst_stat_result_timeontask#:#Munkaidő -assessment#:#tst_stat_result_total_participants#:#Résztvevők teljes száma -assessment#:#tst_stat_result_total_timeontask#:#Total Time On Task (All Test Attempts)###28 10 2024 new variable +assessment#:#tst_stat_result_timeontask#:#Feladatra fordított idő +assessment#:#tst_stat_result_total_participants#:#Kitöltők teljes száma +assessment#:#tst_stat_result_total_timeontask#:#Feladatra fordított összidő (összes teszkitöltés) assessment#:#tst_submit_results#:#Igen, megerősítem elküldési szándékom. assessment#:#tst_tab_competences#:#Kompetenciák assessment#:#tst_tab_results_objective_oriented#:#Végeredmények tanulási célok szerint -assessment#:#tst_tab_results_pass_oriented#:#Végeredmények próbálkozások szerint +assessment#:#tst_tab_results_pass_oriented#:#Végeredmények teszkitöltések szerint assessment#:#tst_tbl_col_answered_questions#:#Megválaszolt kérdések assessment#:#tst_tbl_col_final_mark#:#Érdemjegy -assessment#:#tst_tbl_col_finished_passes#:#Finished Passes###26 08 2024 new variable -assessment#:#tst_tbl_col_finished_passes_num_of#:#%s of %s###26 08 2024 new variable -assessment#:#tst_tbl_col_last_scored_access#:#Last Scored Access###26 08 2024 new variable +assessment#:#tst_tbl_col_finished_passes#:#Befejezett teszkitöltések +assessment#:#tst_tbl_col_finished_passes_num_of#:#%s / %s +assessment#:#tst_tbl_col_last_scored_access#:#Utolsó pontozott hozzáférés assessment#:#tst_tbl_col_pass_finished#:#Befejezte a kitöltést assessment#:#tst_tbl_col_passed_status#:#Értékelés assessment#:#tst_tbl_col_percent_result#:#Elért százalék assessment#:#tst_tbl_col_reached_points#:#Elért pontszám assessment#:#tst_tbl_col_scored_pass#:#Elért pontszám -assessment#:#tst_tbl_col_started_passes#:#Started Passes###26 08 2024 new variable -assessment#:#tst_tbl_invited_users#:#Manuálisan kiválasztott résztvevők +assessment#:#tst_tbl_col_started_passes#:#Megkezdett teszkitöltések +assessment#:#tst_tbl_invited_users#:#Manuálisan kiválasztott kitöltők assessment#:#tst_tbl_participants#:#Résztevők assessment#:#tst_tbl_results_grades#:#Eredmények és érdemjegyek assessment#:#tst_test_result#:#Teszt végeredmények @@ -1952,25 +1931,25 @@ assessment#:#tst_text_count_system#:#Pontozási szisztéma assessment#:#tst_threshold#:#Küszöbértékek (itt: %) assessment#:#tst_time_already_spent#:#A tesztet elkezdte: %s. Maximális kitöltési idő: %s. assessment#:#tst_time_already_spent_left#:#Maradt: %s. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#%s perce lesz az összes kérdés megválaszolására. assessment#:#tst_title_output#:#Kérdéscím megjelenítése assessment#:#tst_title_output_full#:#Kérdéscímek és elérhető pontszámok assessment#:#tst_title_output_hide_points#:#Csak kérdéscímek -assessment#:#tst_title_output_info#:#Set which combination of question titles and/or points available should be visible to participants while they are taking the test and within the test attempt overview (see below).###29 10 2025 new variable +assessment#:#tst_title_output_info#:#Azt határozza meg, hogy a kérdéscímek és/vagy az elérhető pontszámok melyik kombinációja legyen látható a résztvevők számára a teszt kitöltése közben és a tesztkísérlet áttekintésében (lásd alább). assessment#:#tst_title_output_no_title#:#Sem a kérdéscímek, sem az elérhető pontszámok -assessment#:#tst_title_output_only_points#:#Only Available Points###26 08 2024 new variable +assessment#:#tst_title_output_only_points#:#Csak az elérhetőpontok assessment#:#tst_trigger_result_refreshing#:#A végeredményeket újra kell számolni. Ez egy ideig eltarthat. assessment#:#tst_type#:#Teszttípus assessment#:#tst_unchanged_answer_is_correct#:#A jelenlegi válasz helyes. assessment#:#tst_unchanged_order_is_correct#:#A jelenlegi sorrend helyes. assessment#:#tst_use_previous_answers#:#Korábbi válaszok használata -assessment#:#tst_use_previous_answers_description#:#A résztvevők számára korábbi tesztkitöltéseik válaszai megjelennek. Ezt a lehetőséget a résztvevők saját maguknak tudják bekapcsolni az 'Információ' fülön a kitöltés megkezdése előtt. -assessment#:#tst_user_finished_test#:#'%s' tesztet egy felhasználó befejezte +assessment#:#tst_use_previous_answers_description#:#A kitöltők számára korábbi teszkitöltéseinek válaszai megjelennek. Ezt a lehetőséget a kitöltők saját maguknak tudják bekapcsolni egy felugró ablakban a teszkitöltés indítása előtt. +assessment#:#tst_user_finished_test#:#‘%s’ tesztet egy felhasználó befejezte assessment#:#tst_view_competence_assign#:#Összerendelési tulajdonságok megtekintése assessment#:#tst_virtual_pass_header_lo_initial#:#A Tanulási célkitűzés Belépő tesztjének eredményei
    %s assessment#:#tst_virtual_pass_header_lo_qualifying#:#A Tanulási célkitűzés Záró tesztjének eredményei
    %s -assessment#:#tst_wf_info_answer_adopted_from_prev_pass#:#Válaszát egy korábbi próbálkozásból elfogadtuk. -assessment#:#tst_wf_info_answer_not_adopted#:#Korábbi próbálkozásaiból válaszát nem tudjuk elfogadni, így dolgoznia kell még a kérdés megválaszolásán, mert különben tanulási céljának eredményét le kell, hogy rontsuk. +assessment#:#tst_wf_info_answer_adopted_from_prev_pass#:#Válaszát egy korábbi teszkitöltéséből elfogadtuk. +assessment#:#tst_wf_info_answer_not_adopted#:#Korábbi teszkitöltéseiből válaszát nem tudjuk elfogadni, így dolgoznia kell még a kérdés megválaszolásán, mert különben tanulási céljának eredményét le kell, hogy rontsuk. assessment#:#tst_wf_info_optional_question#:#Ez a kérdés egy már korábban teljesített tanulási célhoz tartozik. assessment#:#tst_your_answer_was#:#Az Ön által adott válasz a következő volt assessment#:#tst_your_answers#:#Ezek az Ön által adott válaszok az alábbi kérdésekre. @@ -2006,30 +1985,30 @@ assessment#:#unit_placeholder#:#** Új mértékegység ** assessment#:#units#:#Mértékegységek assessment#:#unlimited#:#Korlátlan assessment#:#unlock#:#Zárolás feloldása -assessment#:#updated#:#Updated###28 10 2024 new variable +assessment#:#updated#:#Módosított assessment#:#uploaded_material#:#Feltöltött anyag assessment#:#use_previous_solution#:#Előző megoldás használata -assessment#:#use_previous_solution_advice#:#A jelenleg látszódó megoldás az Ön egy korábbi megoldása. A megoldás elfogadását meg kell erősítenie, ha azt módosítás nélkül szeretné használni. -assessment#:#user_has_finished_a_test#:#Egy résztvevő befejezte a tesztet. -assessment#:#user_ip_outside_range#:#You are not allowed to access the test from this IP.###26 08 2024 new variable +assessment#:#use_previous_solution_advice#:#A jelenleg látszódó megoldás egy korábbi teszkitöltése során adott válasza. Ha módosítás nélkül szeretné ezt a korábbi megoldását használni, erősítse azt meg a ‘Előző megoldás használata’ gombbal. +assessment#:#user_has_finished_a_test#:#Egy kitöltő befejezte a tesztet. +assessment#:#user_ip_outside_range#:#Erről az IP-címről nem érhető el a teszt. assessment#:#user_not_invited#:#Önnek nem kell elvégeznie ezt a tesztet. -assessment#:#usr_manscoring_complete#:#Marke as 'scored'###29 10 2025 new variable +assessment#:#usr_manscoring_complete#:#Megjelölés ‘pontozott’-ként assessment#:#value_between_x_and_y#:#Az értéknek %s és %s közöttinek kell lennie. assessment#:#values#:#Értékek -assessment#:#variable#:#Variable###26 08 2024 new variable +assessment#:#variable#:#Változó assessment#:#variable_x#:#%s változó assessment#:#variables#:#Változók assessment#:#wait_for_next_pass_hint_msg#:#További kitöltés lehetséges ekkor: %s -assessment#:#warning_question_not_complete#:#A kérdés nem teljes. +assessment#:#warning_question_not_complete#:#A kérdés hiányos. assessment#:#width#:#Szélesség -assessment#:#with_solution#:#Participants with solution###28 10 2024 new variable -assessment#:#with_solutions_participants#:#Választ adó résztvevők -assessment#:#without_solution#:#Participants without solution###28 10 2024 new variable -assessment#:#without_solutions_participants#:#Egy választ sem adó résztvevők +assessment#:#with_solution#:#Kitöltők megoldással +assessment#:#with_solutions_participants#:#Választ adó kitöltők +assessment#:#without_solution#:#Kitöltők megoldás nélkül +assessment#:#without_solutions_participants#:#Egy választ sem adó kitöltők assessment#:#worked_through#:#Dolgozott rajta assessment#:#working_time#:#Megoldási idő assessment#:#you_received_a_of_b_points#:#Ön %s pontot kapott a lehetséges %s pontból -assessment#:#your_results#:#Your Results###28 10 2024 new variable +assessment#:#your_results#:#Eredményeim auth#:#auth_account_code#:#Kód auth#:#auth_account_code_info#:#ILIAS-fiókja újraaktiválásához használhat ILIAS-fiókkódot. auth#:#auth_account_code_title#:#ILIAS-fiókkód @@ -2039,46 +2018,46 @@ auth#:#auth_account_migration_keep#:#Felhasználói fiókok migrálása auth#:#auth_account_migration_name#:#Migrálás auth#:#auth_account_migration_new#:#Új ILIAS-fiók létrehozása auth#:#auth_activation_code_success#:#Fiókját újra aktív, bejelentkezhet az ILIAS-ba. -auth#:#auth_allow_local_info#:#Ha be van kapcsolva, ILIAS adatbázisú helyi hitelesítés (helyi felhasználónév/jelszó párossal) még lehetséges azoknak az fiókoknak, melyek hitelesítési módja SAML. +auth#:#auth_allow_local_info#:#Az ILIAS adatbázisú helyi hitelesítés (helyi felhasználónév/jelszó párossal) még lehetséges azoknak az fiókoknak, melyek hitelesítési módja SAML. auth#:#auth_auth_settings#:#Beállítások -auth#:#auth_cron_destroy_expired_sessions#:#Deletion of Expired Sessions###26 08 2024 new variable -auth#:#auth_cron_destroy_expired_sessions_desc#:#This job deletes expires sessions.###26 08 2024 new variable +auth#:#auth_cron_destroy_expired_sessions#:#Lejárt munkamenetek törlése +auth#:#auth_cron_destroy_expired_sessions_desc#:#Ez az ütemezett feladat törli a lejárt munkameneteket. auth#:#auth_err_expired#:#Munkamenete inaktivitás miatt lejárt. -auth#:#auth_err_invalid_user_account#:#Hitelesítés belső hiba miatt sikertelen. +auth#:#auth_err_invalid_user_account#:#Sikertelen bejelentkezés. Kérjük, ellenőrizze, hogy helyesen adta-e meg felhasználónevét és jelszavát. Ha a probléma továbbra is fennáll, fiókja inaktív lehet, vagy lejárt. Ebben az esetben kérjük, vegye fel a kapcsolatot az ILIAS platform technikai támogatásával a képernyő alján található linken keresztül. auth#:#auth_err_ldap_exception#:#Hitelesítés belső (LDAP) hitelesítési hiba miatt sikertelen. auth#:#auth_info_add#:#Válassza ezt a lehetőséget, ha még nem regisztrált az ILIAS-ba. Új ILIAS-fiók jön létre. -auth#:#auth_info_migrate#:#Ha van már ILIAS-fiókja, adja meg felhasználónevét és jelszavát személyes adatai migrálásához (levelek, teszteredmények, ...). +auth#:#auth_info_migrate#:#Ha van már ILIAS-fiókja, adja meg felhasználónevét és jelszavát személyes adatai migrálásához (levelek, teszteredmények, …). auth#:#auth_ldap_server_ds#:#LDAP szerver auth#:#auth_login_editor#:#Bejelentkezési képernyő szerkesztő -auth#:#auth_odic_scope_info#:#In this mask, the standard claims are displayed as a suggestion for a profile data assignment based on the OpenID Connect scopes configured %s. You can adopt this suggestion as an effective profile data assignment by clicking on "%s" or make your own adjustments by changing the text fields.###28 10 2024 new variable -auth#:#auth_odic_scope_tab_info#:#In this mask you can assign OpenID Connect claims to ILIAS profile data. To do this, enter the scope from which the information should be taken over upon successful authentication in the corresponding text fields for the respective profile date. Activate the corresponding checkbox if the data should also be transferred to an existing ILIAS user account. You can view a list of standard claims %s.###28 10 2024 new variable -auth#:#auth_oidc#:#OpenID -auth#:#auth_oidc_configured_scopes#:#Pre-fill Scope-based Mapping###28 10 2024 new variable -auth#:#auth_oidc_discover_scopes#:#Perform Scope Auto Discovery###28 10 2024 new variable -auth#:#auth_oidc_discover_scopes_info#:#The automatic scope discovery was performed. Scopes are added to the field "Additional Scopes" in the form below. Please define your relevant scopes and save the form afterwards.###28 10 2024 new variable -auth#:#auth_oidc_failed#:#Login via OpenID Connect failed###26 08 2024 new variable -auth#:#auth_oidc_here#:#here###28 10 2024 new variable +auth#:#auth_odic_scope_info#:#Ebben a maszkban a szabványos jogcímek javaslatként jelennek meg a profiladatok hozzárendelésére a %s konfigurált OpenID Connect hatókörei alapján. Ezt a javaslatot hatékony profiladat-hozzárendelésként fogadhatja el, ha rákattint a ‘%s’ elemre, vagy módosíthatja a szövegmezőket. +auth#:#auth_odic_scope_tab_info#:#Ebben a maszkban OpenID Connect jogcímeket rendelhet az ILIAS profiladatokhoz. Ehhez adja meg az adott profil dátumának megfelelő szövegmezőkbe azt a hatókört, ahonnan az információkat át kell venni a sikeres hitelesítés után. Aktiválja a megfelelő jelölőnégyzetet, ha az adatokat egy meglévő ILIAS felhasználói fiókba is át kell vinni. Megtekintheti a %s szabványos követelések listáját. +auth#:#auth_oidc#:#OpenID-kapcsolat +auth#:#auth_oidc_configured_scopes#:#Hatókör alapú leképezés előkitöltése +auth#:#auth_oidc_discover_scopes#:#Automatikus hatókörfelderítés végrehajtása +auth#:#auth_oidc_discover_scopes_info#:#Megtörtént az automatikus hatókör felderítése. A hatókörök az alábbi űrlap ‘További hatókörök’ mezőjébe kerülnek. Kérjük, határozza meg a releváns hatóköröket, majd mentse el az űrlapot. +auth#:#auth_oidc_failed#:#Az OpenID-kapcsolaton keresztüli bejelenkezés sikertelen +auth#:#auth_oidc_here#:#itt auth#:#auth_oidc_login_element_info#:#Bejelentkezés az ILIAS-ba OpenID hitelesítéssel auth#:#auth_oidc_mapping_table#:#ILIAS felhasználói adatok és OpenID-attribútumok összerendelése auth#:#auth_oidc_profile#:#Profiladatok hozzárendelése auth#:#auth_oidc_role_info#:#OpenID csatlakozási attribútum::Érték (például: "szabályok::alkalmazottak"). -auth#:#auth_oidc_role_mapping_table#:#ILIAS-szerepek és OpenID-attribútumok összerendelése. -auth#:#auth_oidc_roles#:#Szerep hozzárendelése -auth#:#auth_oidc_saved_values#:#Effective Attribute Mapping###28 10 2024 new variable -auth#:#auth_oidc_scopes#:#Scopes###28 10 2024 new variable +auth#:#auth_oidc_role_mapping_table#:#ILIAS-szerepkörök és OpenID-attribútumok összerendelése. +auth#:#auth_oidc_roles#:#Szerepkör hozzárendelése +auth#:#auth_oidc_saved_values#:#Hatékony attribútumleképezés +auth#:#auth_oidc_scopes#:#Hatókörök auth#:#auth_oidc_settings#:#Szerver beállításai auth#:#auth_oidc_settings_activation#:#OpenID bekapcsolása auth#:#auth_oidc_settings_additional_scopes#:#További hatókörök -auth#:#auth_oidc_settings_additional_scopes_info#:#Standard scopes: address, email, phone, profile###28 10 2024 new variable +auth#:#auth_oidc_settings_additional_scopes_info#:#Standard hatókörök: cím, e-mail cím, telefonszám, profil auth#:#auth_oidc_settings_client_id#:#Kliens-ID auth#:#auth_oidc_settings_custom_session_duration#:#Munkamenet időtartama auth#:#auth_oidc_settings_custom_session_duration_option#:#Saját munkamenet időtartama auth#:#auth_oidc_settings_custom_session_duration_type#:#A munkamenet időtartamának beállításai -auth#:#auth_oidc_settings_default_role#:#Szerep hozzárendelése -auth#:#auth_oidc_settings_default_role_info#:#Kérem, válasszon ki egy globális szerepet az új ILIAS-fiókhoz -auth#:#auth_oidc_settings_default_scopes#:#Default Scope###28 10 2024 new variable -auth#:#auth_oidc_settings_discovery_error#:#Retrieving the Discovery URL failed with: %s###26 08 2024 new variable -auth#:#auth_oidc_settings_discovery_url#:#Discovery URL of the provider###26 08 2024 new variable +auth#:#auth_oidc_settings_default_role#:#Szerepkör hozzárendelése +auth#:#auth_oidc_settings_default_role_info#:#Kérem, válasszon ki egy globális szerepkört az új ILIAS-fiókhoz +auth#:#auth_oidc_settings_default_scopes#:#Alapértelmezett hatókör +auth#:#auth_oidc_settings_discovery_error#:#Felderítési URL lekérése sikertelen: %s +auth#:#auth_oidc_settings_discovery_url#:#A szolgáltató Felderítési URL-je auth#:#auth_oidc_settings_img#:#Kép auth#:#auth_oidc_settings_img_file_info#:#Töltsön fel egy képet, ami a bejelentkezési oldalon fog megjelenni. A szöveget automatikusan hozzáfűzzük a bejelentkezési szkripthez. auth#:#auth_oidc_settings_invalid_scopes#:#Az következő értékek nem valós hatókörök: %s @@ -2093,26 +2072,26 @@ auth#:#auth_oidc_settings_logout_scope_global#:#Globális kijelentkezés auth#:#auth_oidc_settings_logout_scope_global_info#:#Ebben az esetben az OpenID-munkamenet és az ILIAS-munkamenet lezárul. auth#:#auth_oidc_settings_logout_scope_local#:#Kijelentkezés csak az ILIAS-ból auth#:#auth_oidc_settings_logout_scope_local_info#:#Ebben az esetben csak az ILIAS munkamenet zárul le. -auth#:#auth_oidc_settings_provider#:#Szolgáltató-Url +auth#:#auth_oidc_settings_provider#:#Szolgáltató-URL auth#:#auth_oidc_settings_secret#:#Klienskulcs auth#:#auth_oidc_settings_section_user_sync#:#Felhasználói szinkronizálási beállítások auth#:#auth_oidc_settings_session_duration#:#Időtartam auth#:#auth_oidc_settings_title#:#OpenID hitelesítés beállításai auth#:#auth_oidc_settings_txt#:#Szöveg -auth#:#auth_oidc_settings_txt_val_info#:#Írjon be egy szöveget, ami a bejelentkezési oldalon fog megjelenni. A szöveget automatikusan hozzáfűzzük a bejelentkezési szkripthez. +auth#:#auth_oidc_settings_txt_val_info#:#Írja be a bejelentkezési oldalon megjelenítendő szöveget. A szöveget automatikusan hozzáfűzzük az OpenID bejelentkezési szkripthez. auth#:#auth_oidc_settings_user_attr#:#Felhasználónév attribútumneve auth#:#auth_oidc_settings_user_sync#:#Automatikus szinkronizálás -auth#:#auth_oidc_settings_user_sync_info#:#Ha be van kapcsolva, azoknak a felhasználóknak, akik sikeresen hitelesítették magukat az OpenID-szerveren, létrehozzuk egy ILIAS-fiókot, ha az még nem létezik. -auth#:#auth_oidc_settings_validate_scope_custom#:#Use custom OpenID Connect Discovery url###26 08 2024 new variable -auth#:#auth_oidc_settings_validate_scope_default#:#Use :Provider-URL:/.well-known/openid-configuration###26 08 2024 new variable -auth#:#auth_oidc_settings_validate_scope_none#:#Do not validate Scopes on saving###26 08 2024 new variable -auth#:#auth_oidc_settings_validate_scopes#:#Validate Scopes upon saving###26 08 2024 new variable +auth#:#auth_oidc_settings_user_sync_info#:#Azoknak a felhasználóknak, akik sikeresen hitelesítették magukat az OpenID-szerveren, létrehozunk egy ILIAS-fiókot, ha az még nem létezik. +auth#:#auth_oidc_settings_validate_scope_custom#:#Egyéni OpenID Csatlakozási Discovery url használata +auth#:#auth_oidc_settings_validate_scope_default#:#Use [PROVIDER_URL]/.well-known/openid-configuration +auth#:#auth_oidc_settings_validate_scope_none#:#Do not validate Scopes on saving +auth#:#auth_oidc_settings_validate_scopes#:#Validate Scopes upon saving auth#:#auth_oidc_update_field_info#:#Automatikus frissítés auth#:#auth_oidc_update_role_info#:#Csak az első bejelentkezéskor (automatikus szinkronizálás) alkalmazzuk auth#:#auth_oidconnect#:#OpenID auth#:#auth_page_type_auth#:#Bejelentkezési oldal -auth#:#auth_required_password#:#Please enter a password.###29 10 2025 new variable -auth#:#auth_required_username#:#Please enter a username.###29 10 2025 new variable +auth#:#auth_required_password#:#Adjon meg egy jelszót +auth#:#auth_required_username#:#Adjon meg egy felhasználónevet auth#:#auth_saml_add_idp_btn#:#Új azonosításszolgáltató hozzáadása auth#:#auth_saml_add_idp_md_error#:#A megadott érték nem valós XML dokumentum. Ellenőrizze, hogy valós XML valós azonosítószolgálgatót tartalmazzon. auth#:#auth_saml_add_idp_md_info#:#Adja meg az azonosítószolgáltató metaadatát XML formátumban. @@ -2121,21 +2100,22 @@ auth#:#auth_saml_configure#:#SAML hitelesítés konfigurálása auth#:#auth_saml_configure_idp#:#SAML IDP konfigurálása: %s auth#:#auth_saml_deleted_idp#:#Az azonosításszolgáltatót sikeresen törölte. auth#:#auth_saml_enable#:#SAML támogatása bekapcsolása -auth#:#auth_saml_err_sqlite_driver#:#The SAML authentication requires the SQLite driver for PHP. Please install the SQLite package and try again.###29 07 2022 new variable +auth#:#auth_saml_err_sqlite_driver#:#Az SAML hitelesítéshez szükséges az PHP-SQLite. Telepítse az SQLite csomagot, majd próbálja újra. auth#:#auth_saml_idp#:#IDP +auth#:#auth_saml_idp_deactivated_auth_failed#:#A hitelesítés sikertelen, az azonosítószolgáltatót deaktivált. auth#:#auth_saml_idp_selection_table_desc#:#Válassza ki azt az azonosítószolgáltatót, amellyel be kíván jelentkezni. auth#:#auth_saml_idp_selection_table_title#:#Azonosításszolgáltató kiválasztása auth#:#auth_saml_idp_settings#:#IDP beállítások auth#:#auth_saml_idps#:#SAML IDP lista -auth#:#auth_saml_idps_info#:#Ellenőrizze és módosítsa a SimpleSAMLphp konfigurációt itt '%s' és itt '%s' (külső adatmappa). Ne felejtse el privát kulcsának és tanúsítványának útvonalát hozzáadni az authsources.php fájlban. További információkért elolvashatja a leírást: %s.
    Szövetségi Metaadat URL: %s +auth#:#auth_saml_idps_info#:#Ellenőrizze és módosítsa a SimpleSAMLphp konfigurációt itt ‘%s’ és itt ‘%s’ (külső adatmappa). Ne felejtse el privát kulcsának és tanúsítványának útvonalát hozzáadni az authsources.php fájlban. További információkért elolvashatja a leírást: %s.
    Szövetségi Metaadat URL: %s auth#:#auth_saml_login_form#:#Gomb a bejelentkezési oldalon auth#:#auth_saml_login_form_info#:#Ha be van kapcsolva és van legalább egy aktív IDP, egy gomb jelenik meg a bejelentkezési oldalon. Egy kattintás erre gombra egy SAML kérést inicializál. auth#:#auth_saml_migration#:#Felhasználói fiókok migrálása: auth#:#auth_saml_migration_info#:#Ennek az opciónak a bekapcsolásával az új felhasználók lehetőséget kapnak, hogy a már létező ILIAS-fiókjukat SAML hitelesítéssé migrálhassák. -auth#:#auth_saml_role_select#:#Szerep: +auth#:#auth_saml_role_select#:#Szerepkör: auth#:#auth_saml_sure_delete_idp#:#Biztos, hogy törli a kiválasztott azonosításszolgáltatót? A művelet nem vonható vissza. Az érintett ILIAS-fiókokat átállítjuk alapértelmezett hitelesítési módra. auth#:#auth_saml_sync#:#Felhasználók szinkronizációja -auth#:#auth_saml_sync_info#:#Ha be van kapcsolva, sikeres hitelesítés után automatikusan létrehozzuk az új ILIAS-fiókot, illetve módosítjuk a már meglévőt a felhasználói profil leképezési szabályainak alapján. +auth#:#auth_saml_sync_info#:#Sikeres hitelesítés után automatikusan létrehozzuk az új ILIAS-fiókot, illetve módosítjuk a már meglévőt a felhasználói profil leképezési szabályainak alapján. auth#:#auth_saml_uid_claim#:#Felhasználói fiók egyezéséhez egyedi attribútum auth#:#auth_saml_uid_claim_info#:#Ez meghatározza azt az ILIAS attribútumot, ami eldönti, hogy egy beérkező hitelesítési kérés megegyezik-e már létező ILIAS-fiókkal. auth#:#auth_saml_unknow_idp#:#Ilyen azonosításszolgáltatót nem létezik. @@ -2144,56 +2124,56 @@ auth#:#auth_saml_user_mapping#:#Felhasználói profil leképezése auth#:#auth_saml_username_claim#:#Felhasználónév attribútuma auth#:#auth_saml_username_claim_info#:#Ez meghatározza azt az ILIAS attribútumot, ami alapján generáljuk az ILIAS-ban megjelenő a felhasználónevet. auth#:#auth_sync#:#Felhasználó szinkronizációja -auth#:#destination_after_logout#:#Destination After Logout###28 10 2024 new variable -auth#:#destination_external_ressource#:#Show External Ressource###28 10 2024 new variable -auth#:#destination_external_ressource_url#:#External URL###28 10 2024 new variable -auth#:#destination_internal_ressource#:#Show Internal Ressource###28 10 2024 new variable -auth#:#destination_internal_ressource_ref_id#:#Internal Reference Id###28 10 2024 new variable -auth#:#destination_login_screen#:#Show Login Screen###28 10 2024 new variable -auth#:#destination_login_screen_info#:#Make sure that, for example, an SSO is not addressed that leads to immediate login.###28 10 2024 new variable -auth#:#destination_logout_screen#:#Show Logout Screen###28 10 2024 new variable -auth#:#err_auth_ldap_failed#:#Authentication failed. Please contact your ILIAS administrator.###29 07 2022 new variable +auth#:#destination_after_logout#:#Kijelentkezés utáni cél +auth#:#destination_external_ressource#:#Külső erőforrás megjelenítése +auth#:#destination_external_ressource_url#:#Külső URL +auth#:#destination_internal_ressource#:#Belső erőforrás megjelenítése +auth#:#destination_internal_ressource_ref_id#:#Belsőhivatkozás-azonosító (ref_id) +auth#:#destination_login_screen#:#Bejelentkezési képernyő megjelenítése +auth#:#destination_login_screen_info#:#Ellenőrizze, hogy például egy SSO nem jelentkezteti rögtön vissza. +auth#:#destination_logout_screen#:#Kijelentkezési képernyő megjelenítése +auth#:#err_auth_ldap_failed#:#A hitelesítés sikertelen. Kérem, keresse az ILIAS-üzemeltetőt. auth#:#err_auth_saml_failed#:#Hitelesítés sikertelen. Vegye fel a kapcsolatot a rendszergazdával. auth#:#err_auth_saml_no_ilias_user#:#Hitelesítés sikertelen. Vegye fel a kapcsolatot a rendszergazdával. -auth#:#language_does_not_exist#:#The selected language does not exist.###26 08 2024 new variable -auth#:#login_page#:#Language of Login-Page###26 08 2024 new variable -auth#:#login_pages#:#Login-Pages###26 08 2024 new variable -auth#:#logout_behaviour#:#Logout Behaviour###28 10 2024 new variable -auth#:#logout_behaviour_invalid_ref_id#:#Please make sure the internal resource id exists and is not in trash###28 10 2024 new variable -auth#:#logout_behaviour_invalid_url#:#The external ressource given is not a valid URL.###28 10 2024 new variable -auth#:#logout_behaviour_ref_id_no_access#:#Please make sure the "Anonymous" user has access to the defined ressource.###28 10 2024 new variable -auth#:#logout_behaviour_ref_id_valid_status_changed#:#The configured internal resource is no longer valid. If the resource has been deleted or access for the "Anonymous" user has been restricted, please configure a new valid internal resource. Without a valid configuration, the user will be redirected to the logout screen by default.###28 10 2024 new variable -auth#:#logout_behaviour_settings#:#Logout Behaviour Settings###28 10 2024 new variable -auth#:#logout_editor#:#Design Logout-Page###26 08 2024 new variable -auth#:#logout_page#:#Language of Logout-Page###26 08 2024 new variable -auth#:#logout_pages#:#Logout-Pages###26 08 2024 new variable +auth#:#language_does_not_exist#:#A kiválasztott nyelv nem létezik. +auth#:#login_page#:#Bejelentkezési oldal nyelve. +auth#:#login_pages#:#Bejelentkezési oldalak +auth#:#logout_behaviour#:#Kijelentkezési viselkedés +auth#:#logout_behaviour_invalid_ref_id#:#Győződjön meg arról, hogy a belső erőforrás_id (ref_id) létezik és nincs a lomtárban +auth#:#logout_behaviour_invalid_url#:#A megadott külső erőforrás nem érvényes URL. +auth#:#logout_behaviour_ref_id_no_access#:#Ellenőrizzem hogy az ‘Anonymous’ felhasználó hozzáfér a megadott erőforráshoz. +auth#:#logout_behaviour_ref_id_valid_status_changed#:#A megadott erőforrás már nem érvényes. Amennyiben az erőforrást törölték vagy az ‘Anonymous’ hozzáférését megvonták, adjon meg egy új, érvényes belső erőforrást. Érvényes beállítás hiányában, a felhasználót a kijelentkezési képernőre irányítjuk. +auth#:#logout_behaviour_settings#:#Kijelentkezési viselkedés beállításai +auth#:#logout_editor#:#Kijelentkezési oldal szerkesztése +auth#:#logout_page#:#Kijelentkezési oldal nyelve +auth#:#logout_pages#:#Kijelentkezési oldalak auth#:#lti_consumer_inactive#:#LTI-eszközfogyasztó ki van kapcsolva. -auth#:#page_design_activate#:#Activate Page Design###26 08 2024 new variable -auth#:#page_design_deactivate#:#Deactivate Page Design###26 08 2024 new variable +auth#:#page_design_activate#:#Bekapcsolás +auth#:#page_design_deactivate#:#Kikapcsolás auth#:#saml_tab_head_idp#:#IDP awrn#:#awareness_now_online#:#Jelenleg online awrn#:#awareness_settings#:#Beállítások awrn#:#awrn_caching_period#:#Gyorsítótárazási időköz awrn#:#awrn_caching_period_info#:#Ennyi időnként frissül a felső sávban a felhasználók száma, illetve új felhasználó érzékelése. -awrn#:#awrn_enable#:#'Ki van online?'-eszköz engedélyezése -awrn#:#awrn_filter#:#User Filter###29 07 2022 new variable -awrn#:#awrn_hide_from_awareness#:#Rejtsen el engem a 'Ki van online?'-eszközben -awrn#:#awrn_hide_from_awareness_info#:#A 'Ki van online?'-eszköz a felső sávban található és felhasználókat jelenít meg (például kurzusai tagjait). +awrn#:#awrn_enable#:#‘Ki van online?’-eszköz engedélyezése +awrn#:#awrn_filter#:#Felhasználószűrő +awrn#:#awrn_hide_from_awareness#:#Rejtsen el engem a ‘Ki van online?’-eszközben +awrn#:#awrn_hide_from_awareness_info#:#A ‘Ki van online?’ eszköz a felső sávban található és felhasználókat jelenít meg (például kurzusai tagjait). awrn#:#awrn_inactive#:#Nincs felsorolva awrn#:#awrn_incl_offline#:#Online és offline awrn#:#awrn_max_inactivity#:#Maximális tétlenségi időszak awrn#:#awrn_max_inactivity_info#:#Ennyi idő után tekintjük offline állapotúnak a felhasználót. Ha nem állít be értéket, a munkamenet idejét használjuk. awrn#:#awrn_max_nr_entries#:#Elemek maximális száma -awrn#:#awrn_max_nr_entries_info#:#Maximum ennyi elem legyen a 'Ki van online?' felsorolásban. Ennek a beállításnak elhanyagolható hatása amikor az eszköz a felső sávban megjelenik. +awrn#:#awrn_max_nr_entries_info#:#Maximum ennyi elem legyen a ‘Ki van online?’ felsorolásban. Ennek a beállításnak elhanyagolható hatása amikor az eszköz a felső sávban megjelenik. awrn#:#awrn_minutes#:#perc awrn#:#awrn_online#:#Online awrn#:#awrn_online_only#:#Csak online awrn#:#awrn_seconds#:#másodperc awrn#:#awrn_use_osd#:#Online felhasználók felugróban -awrn#:#awrn_use_osd_info#:#'Ki van online' felsorolásában új felhasználók felugróban jelenjenek meg. -awrn#:#awrn_user_show#:#ILIAS-fiókom megjelenítése a 'Ki van online?' eszközben -awrn#:#awrn_user_show_default#:#Default Value for the Visibility in "Who-Is-Online?"###29 10 2025 new variable -awrn#:#awrn_user_show_default_info#:#Defines the default value for the visibility of the status of a user in "Who-Is-Online?".###29 10 2025 new variable +awrn#:#awrn_use_osd_info#:#‘Ki van online’ felsorolásában új felhasználók felugróban jelenjenek meg. +awrn#:#awrn_user_show#:#ILIAS-fiókom megjelenítése a ‘Ki van online?’ eszközben +awrn#:#awrn_user_show_default#:#‘Ki van online?’ láthatóságának alapértelmezett értéke +awrn#:#awrn_user_show_default_info#:#Meghatározza a felhasználó állapotának láthatóságának alapértelmezett értékét a ‘Ki van online?’ eszközben. awrn#:#user_awrn_default#:#Alapértelmezett awrn#:#user_awrn_hide#:#Állapotom elrejtése awrn#:#user_awrn_show#:#Állapotom megjelenítése @@ -2209,39 +2189,39 @@ background_tasks#:#ui_msg_no_files_found#:#Egy fájlt sem találtunk. A letölt background_tasks#:#ui_msg_num_files#:#%s fájlt találtunk a letöltéshez, biztos, hogy folytatja? background_tasks#:#ui_msg_sum_file_sizes#:#A letöltés mérete a zip készítése előtt %s. Biztos, hogy folytatja? background_tasks#:#waiting#:#Várakozó -badge#:#awarded_by#:#Awarded by###26 08 2024 new variable +badge#:#awarded_by#:#Odaítélte badge#:#badge_activity_badges#:#Aktivitás érdemérmek badge#:#badge_add_template#:#Sablon létrehozása badge#:#badge_add_to_profile#:#Hozzáadás a Profilhoz -badge#:#badge_assignment_deletion_confirmation#:#Biztos, hogy visszavonja az alábbi érdemérmet a következőktől: '%s'? +badge#:#badge_assignment_deletion_confirmation#:#Biztos, hogy visszavonja az alábbi érdemérmet a következőktől: ‘%s’? badge#:#badge_award_badge#:#Érdemérem odaítélése -badge#:#badge_award_revoke#:#Award/Revoke Badge###29 10 2025 new variable +badge#:#badge_award_revoke#:#Érdemérem odaítélése/visszavonása badge#:#badge_badge#:#Érdemérem badge#:#badge_course_lp#:#Kurzushaladás badge#:#badge_course_lp_invalid#:#Az alábbi objektumok tanulási haladásának módja nem támogatott: %s. -badge#:#badge_create#:#Create Badge###26 08 2024 new variable -badge#:#badge_create_image_processing_failed#:#The badge could not be created, an error occurred while processing the image.###26 08 2024 new variable +badge#:#badge_create#:#Érdemérem létrehozása +badge#:#badge_create_image_processing_failed#:#Az érdemérmet nem sikerült létrehozni, hiba történt a kép feldolgozása közben. badge#:#badge_criteria#:#Kritérium badge#:#badge_crs_merit#:#Érdem -badge#:#badge_deletion#:#Badge successfully deleted.###28 10 2024 new variable -badge#:#badge_deletion_confirmation#:#Biztos, hogy törli az alábbi érdemérmeket azok összes hozzárendeléseivel? +badge#:#badge_deletion#:#Az érdemérmet sikeresen törölte. +badge#:#badge_deletion_confirmation#:#Biztos, hogy törli az alábbi érdemérmeket? Evvel törlöd a felhasználók által megszerzett vagy nekik odaítélt érdemérmeket is. badge#:#badge_image_from_template#:#Sablon használata badge#:#badge_image_from_upload#:#Kép feltöltése badge#:#badge_image_template_form#:#Képsablon badge#:#badge_image_templates#:#Képsablonok badge#:#badge_in_profile#:#Profilban badge#:#badge_issued_on#:#Kiállítás dátuma -badge#:#badge_lhist_badge_completed#:#$3$ érdemérem elnyerve. -badge#:#badge_lhist_badge_completed_in#:#$3$ érdemérem elnyerve $1$ alatt. +badge#:#badge_lhist_badge_completed#:#$3$ érdemérmet elnyerte. +badge#:#badge_lhist_badge_completed_in#:#$3$ érdemérmet elnyerte $1$ alatt. badge#:#badge_manual#:#Manuális odaítélés badge#:#badge_new_badges#:#%1 új érdemérme van. badge#:#badge_no_valid_types_for_obj#:#Nem hozhat létre új érdemérmet, mert egy aktív érdemérem-típus sem érhető el. Keresse a rendszergazdát. badge#:#badge_notification_badges#:#Új érdemérem badge#:#badge_notification_badges_goto#:#Érdemérmeimhez badge#:#badge_notification_body#:#ezúton értesítjük, hogy új érdemérmet kapott. -badge#:#badge_notification_osd#:#Új érdemérmeket kapott: [BADGE_LIST] +badge#:#badge_notification_osd#:#Új érdemérmet kapott: [BADGE_LIST] badge#:#badge_notification_parent_goto#:#Tartalomtárhoz -badge#:#badge_notification_reason#:#Ezt az üzenetet azért kapta, mert érdemérmet adhat profiljához. +badge#:#badge_notification_reason#:#Profilodhoz új vagy meglévő érdemérmeket a ‘Teljesítmények’ / ‘Érdemérmek’ menüpontban (lásd a fenti link) adhatsz. badge#:#badge_notification_subject#:#Érdemérmet kapott badge#:#badge_object_badges#:#Érdemérem-objektumok badge#:#badge_personal_badges#:#Érdemérmeim @@ -2249,51 +2229,51 @@ badge#:#badge_profile_less#:#Kevesebb megjelenítése badge#:#badge_profile_more#:#Összes megjelenítése badge#:#badge_remove_badge#:#Érdemérem visszavonása badge#:#badge_remove_from_profile#:#Eltávolítás a Profilból -badge#:#badge_select_one#:#You have to select at least one badge###28 10 2024 new variable +badge#:#badge_select_one#:#Legalább egy érdemérmet ki kell választania badge#:#badge_service_activate#:#Szolgáltatás bekapcsolása -badge#:#badge_service_activate_info#:#A szolgáltatás bekapcsolása érdemérmek elérhetővé tétéléhez +badge#:#badge_service_activate_info#:#A szolgáltatás bekapcsolása érdemérmek elérhetővé tételéhez badge#:#badge_settings#:#Érdemérem beállításai -badge#:#badge_sort_active_badges_first#:#Active Badges First###29 10 2025 new variable -badge#:#badge_sort_active_badges_last#:#Active Badges Last###29 10 2025 new variable -badge#:#badge_sort_activity_badges_first#:#Activity Badges First###29 10 2025 new variable -badge#:#badge_sort_activity_badges_last#:#Activity Badges Last###29 10 2025 new variable -badge#:#badge_sort_added_to_profile_last#:#Added To Profile First###29 10 2025 new variable -badge#:#badge_sort_excluded_from_profile_first#:#Excluded From Profile First###29 10 2025 new variable -badge#:#badge_sort_manual_awarding_first#:#Badges mit manueller Vergabe zuerst###29 10 2025 new variable -badge#:#badge_sort_manual_awarding_last#:#Badges mit manueller Vergabe zuletzt###29 10 2025 new variable -badge#:#badge_subtype_auto#:#automatikus -badge#:#badge_subtype_manual#:#manuális +badge#:#badge_sort_active_badges_first#:#Aktív érdemérmék előre +badge#:#badge_sort_active_badges_last#:#Aktív érdemérmék hátra +badge#:#badge_sort_activity_badges_first#:#Aktivitás érdemérmék előre +badge#:#badge_sort_activity_badges_last#:#Aktivitás érdemérmék hátra +badge#:#badge_sort_added_to_profile_last#:#A profilhoz hozzárendeltek előre +badge#:#badge_sort_excluded_from_profile_first#:#A profilból kizátrak előre +badge#:#badge_sort_manual_awarding_first#:#Manuális hozzárendelésű érdemérmék előre +badge#:#badge_sort_manual_awarding_last#:#Manuális hozzárendelésű érdemérmék hátra +badge#:#badge_subtype_auto#:#Automatikus +badge#:#badge_subtype_manual#:#Manuális badge#:#badge_template_deletion_confirmation#:#Biztos, hogy törli a következő képsablont? -badge#:#badge_template_types#:#Valid típusok +badge#:#badge_template_types#:#Érdemérem-típus kiosztása badge#:#badge_template_types_all#:#Összes badge#:#badge_template_types_specific#:#Specifikus badge#:#badge_types#:#Típusok -badge#:#badge_update_image_processing_failed#:#The badge could not be updated, an error occurred while processing the image.###26 08 2024 new variable -badge#:#badge_uploaded_image_file_not_found#:#No uploaded image for the badge could be found.###26 08 2024 new variable +badge#:#badge_update_image_processing_failed#:#Az érdemérmet nem sikerült módosítani, hiba történt a kép feldolgozása közben. +badge#:#badge_uploaded_image_file_not_found#:#Nem található az érdeméremhez feltöltött kép. badge#:#badge_user_profile#:#Felhasználói profil badge#:#badge_valid#:#Érvényes eddig -badge#:#criteria#:#Criteria###26 08 2024 new variable -badge#:#endless#:#Always###26 08 2024 new variable -badge#:#issued_on#:#Issued on###26 08 2024 new variable -badge#:#position_updated#:#Profil assignment updated.###26 08 2024 new variable -badge#:#sort_by_date_asc#:#Sort by Date Ascending###26 08 2024 new variable -badge#:#sort_by_date_desc#:#Sort by Date Descending###26 08 2024 new variable -badge#:#sort_by_title_asc#:#Sort by Title Ascending###26 08 2024 new variable -badge#:#sort_by_title_desc#:#Sort by Title Descending###26 08 2024 new variable -badge#:#table_view#:#Table View###26 08 2024 new variable -badge#:#tile_view#:#Tile View###26 08 2024 new variable -badge#:#valid_until#:#Valid until###26 08 2024 new variable -benchmark#:#adm_activate_db_benchmark#:#Activate Benchmarking###29 10 2025 new variable -benchmark#:#adm_activate_db_benchmark_desc#:#Benchmarking will be automatically disabled after one request.###29 10 2025 new variable -benchmark#:#adm_db_bench_by_first_table#:#Aggregated by First Table in SQL###29 10 2025 new variable -benchmark#:#adm_db_bench_chronological#:#Chronological###29 10 2025 new variable -benchmark#:#adm_db_bench_slowest_first#:#Slowest First###29 10 2025 new variable -benchmark#:#adm_db_bench_sorted_by_sql#:#Sorted by SQL###29 10 2025 new variable -benchmark#:#adm_db_benchmark#:#DB Benchmark###29 10 2025 new variable -benchmark#:#adm_db_benchmark_user#:#User Account Name###29 10 2025 new variable -benchmark#:#adm_db_benchmark_user_desc#:#Measurements will be made for this user only. The username entered should not belong to the user initiating the benchmarking.###29 10 2025 new variable -benchmark#:#adm_sql#:#SQL###29 10 2025 new variable -benchmark#:#adm_time#:#Time###29 10 2025 new variable +badge#:#criteria#:#Feltétel +badge#:#endless#:#Örökké +badge#:#issued_on#:#Kiállítás időpontja +badge#:#position_updated#:#A profil összerendelését sikeresen módosította. +badge#:#sort_by_date_asc#:#Dátum ↑ +badge#:#sort_by_date_desc#:#Dátum ↓ +badge#:#sort_by_title_asc#:#Cím A→Z +badge#:#sort_by_title_desc#:#Cím Z→A +badge#:#table_view#:#Táblázatos nézet +badge#:#tile_view#:#Csempe nézet +badge#:#valid_until#:#Érvényes eddig +benchmark#:#adm_activate_db_benchmark#:#Teljesítménymérés bekapcsolása +benchmark#:#adm_activate_db_benchmark_desc#:#A teljesítménymérést automatikusan leállítjuk egy kérelem után. +benchmark#:#adm_db_bench_by_first_table#:#Első SQL tábla alapján összesítve +benchmark#:#adm_db_bench_chronological#:#Időrendi +benchmark#:#adm_db_bench_slowest_first#:#Leglassabbak előre +benchmark#:#adm_db_bench_sorted_by_sql#:#Rendezés SQL szerint +benchmark#:#adm_db_benchmark#:#Adatbázis teljesítménymérés +benchmark#:#adm_db_benchmark_user#:#Felhasználónév +benchmark#:#adm_db_benchmark_user_desc#:#Csak ehhez a felhasználóhoz készítünk méréseket. A megadott felhasználónév nem tartozhat a teljesítménymérést kezdeményező felhasználóhoz. +benchmark#:#adm_sql#:#SQL +benchmark#:#adm_time#:#Idő bgtask#:#bgtask_blocked#:#Egyidejű letöltés bgtask#:#bgtask_blocked_cancel_new#:#Új letöltés megszakítása bgtask#:#bgtask_blocked_cancel_old#:#Meglévő letöltés megszakítása @@ -2305,10 +2285,10 @@ bgtask#:#bgtask_download_too_large#:#A letöltés átlépi a korlátot (%s). bgtask#:#bgtask_empty_folder#:#A jelenlegi kiválasztása nem tartalmaz letölthető objektumokat. bgtask#:#bgtask_failure#:#Hiba bgtask#:#bgtask_processing#:#Letöltés létrehozása -bgtask#:#bgtask_setting#:#«Letöltés háttérben» bekapcsolása +bgtask#:#bgtask_setting#:#‘Letöltés háttérben’ bekapcsolása bgtask#:#bgtask_setting_info#:#A ZIP fájl létrehozása aszinkron módon történik, bármikor megszakítható. bgtask#:#bgtask_setting_limit#:#Globális korlát -bgtask#:#bgtask_setting_limit_info#:#Letöltés csak akkor lehetséges, ha a fájlok összmérete ezen érték alatt van. +bgtask#:#bgtask_setting_limit_info#:#Letöltés csak akkor lehetséges, ha a fájlok összmérete ezen érték alatt van MB-ban. bgtask#:#bgtask_setting_threshold_count#:#Minimális szám bgtask#:#bgtask_setting_threshold_count_info#:#Ha a fájlok száma meghaladja ezt az értéket, a letöltés aszinkron lesz. bgtask#:#bgtask_setting_threshold_size#:#Minimális méret @@ -2359,7 +2339,7 @@ bibl#:#bibtex#:#Bibtex bibl#:#changes_saved#:#A módosításokat sikeresen mentette. bibl#:#custom#:#Egyéni bibl#:#detail_view#:#Részletes nézet -bibl#:#detailed_information#:#Detailed Information###28 10 2024 new variable +bibl#:#detailed_information#:#Részletes információ bibl#:#download_original_file#:#Eredeti fájl letöltése bibl#:#field#:#Mező bibl#:#fields#:#Mezők @@ -2373,15 +2353,15 @@ bibl#:#filter_type_3#:#Többszörös szövegbemenet bibl#:#filter_type_info#:#Válasszon egy szűrőtípust a mezőhöz. bibl#:#identifier#:#Azonosító bibl#:#msg_confirm_delete_filter#:#Biztos, hogy törli az alábbi szűrőt? -bibl#:#msg_filter_info#:#Create a filter here that can be used in the "Contents" tab to limit the display of entries.###26 08 2024 new variable +bibl#:#msg_filter_info#:#Hozzon létre itt egy szűrőt, amellyel a ‘Tartalom’ lapon a bejegyzések megjelenítését korlátozhatja. bibl#:#news_title_created#:#Új bibliográfiai lista jött létre bibl#:#news_title_updated#:#Bibliográfiai lista frissült -bibl#:#not_yet_migrated#:#This Object has not et been migrated. Please contact the administrators of the platform.###29 07 2022 new variable +bibl#:#not_yet_migrated#:#Ezt az objektumot még nem migráltuk. Kérem, jelezze az Üzemeltetőknek. bibl#:#obj_bibl_duplicate#:#Bibliográfia duplikálása bibl#:#order#:#Sorrend bibl#:#override_entries#:#Bejegyzések felülbírálása -bibl#:#replace_bibliography_file#:#Replace Bibliography File###26 08 2024 new variable -bibl#:#replace_bibliography_file_info#:#The current bibliography file will be replaced by the new file. All existing entries from the current file will be deleted.###26 08 2024 new variable +bibl#:#replace_bibliography_file#:#Bibliográfiai fájl cseréje +bibl#:#replace_bibliography_file_info#:#A jelenlegi bibliográi fálj cseréje annak összes bejegyzését törli. bibl#:#ris#:#Ris bibl#:#ris_default_a2#:#Archívumban a helye bibl#:#ris_default_au#:#Szerző @@ -2407,12 +2387,12 @@ bibl#:#ris_default_u2#:#Felhasználó által meghatározott bibl#:#ris_default_ur#:#URL bibl#:#ris_default_vl#:#Kötet bibl#:#ris_default_y1#:#Év -bibl#:#sorting_1#:#By Title (Ascending)###28 10 2024 new variable -bibl#:#sorting_2#:#By Title (Descending)###28 10 2024 new variable -bibl#:#sorting_3#:#By Author (Ascending)###28 10 2024 new variable -bibl#:#sorting_4#:#By Author (Descending)###28 10 2024 new variable -bibl#:#sorting_5#:#By Year (Ascending)###28 10 2024 new variable -bibl#:#sorting_6#:#By Year (Descending)###28 10 2024 new variable +bibl#:#sorting_1#:#Cím szerint A→Z +bibl#:#sorting_2#:#Cím szerint Z→A +bibl#:#sorting_3#:#Szerző szerint A→Z +bibl#:#sorting_4#:#Szerző szerint Z→A +bibl#:#sorting_5#:#Év szerint ↑ +bibl#:#sorting_6#:#Év szerint ↓ bibl#:#standard#:#Standard bibl#:#translate#:#Fordítás bkm#:#bkm_fold_created#:#Sikeresen létrehozott egy könyvjelzőmappát. @@ -2427,8 +2407,8 @@ blog#:#blog_abstract_shorten_length#:#Maximális hossz blog#:#blog_add#:#Blog létrehozása blog#:#blog_add_contributor#:#Szerző hozzáadása blog#:#blog_add_posting#:#Bejegyzés létrehozása -blog#:#blog_admin_inactive_info#:#A blogfunkciót a munkaasztal rendszerbeállításaiban kapcsolhatja be. -blog#:#blog_admin_toggle_info#:#A blogfunkciót a munkaasztal rendszerbeállításaiban kapcsolhatja ki teljesen. +blog#:#blog_admin_inactive_info#:#A blogfunkciót a Rendszerbeállítások » Személyes munkaterület » Személyes erőforrások kezelése menüpont alatt kapcsolhatja be. +blog#:#blog_admin_toggle_info#:#A blogfunkciót a Rendszerbeállítások » Személyes munkaterület » Személyes erőforrások kezelése menüpont alatt kapcsolhatja ki teljesen. blog#:#blog_approve#:#Blogbejegyzés jóváhagyása blog#:#blog_author#:#Írta blog#:#blog_authors#:#Szerzők @@ -2439,10 +2419,10 @@ blog#:#blog_change_notification_body_new#:#az alábbi bloghozzászólás jött l blog#:#blog_change_notification_body_update#:#az alábbi bloghozzászólás frissült blog#:#blog_change_notification_link#:#URL blog#:#blog_change_notification_reason#:#Ezt a levelet azért kapta, mert fent említett blognál beállította, hogy kér értesítést. -blog#:#blog_change_notification_subject#:#'%s' blog frissült +blog#:#blog_change_notification_subject#:#‘%s’ blog frissült blog#:#blog_comments#:#Bejegyzések blog#:#blog_confirm_delete_contributors#:#Biztos, hogy törli a következő blogszerzőket? -blog#:#blog_contribute_other_roles#:#A 'Blogszerzők' szerepkör mellett a következő szerepek tagjai is hozhatnak létre új bejegyzéseket: %s. +blog#:#blog_contribute_other_roles#:#A ‘Blogszerzők’ szerepkör mellett a következő szerepkörök tagjai is hozhatnak létre új bejegyzéseket: %s. Az alábbi táblázatban nem szerepelnek, mert a megfelelő engedélyt egy átfogó objektumtól kapják. blog#:#blog_contributors#:#Blogközreműködők blog#:#blog_copy#:#Blog másolása blog#:#blog_download_submission#:#Benyújtás letöltése @@ -2456,39 +2436,39 @@ blog#:#blog_edit_date_info#:#A hozzászólás állapota nem függ ettől a dátu blog#:#blog_edit_keywords#:#Kulcsszavak módosítása blog#:#blog_edit_posting#:#Bejegyzés módosítása blog#:#blog_enable_approval#:#Bejegyzések jóváhagyása -blog#:#blog_enable_approval_info#:#A bejegyzések csak a blog egy 'Beállítások módosítása' jogosultsággal rendelkező felhasználójának jóváhagyása után kerülnek közzétételre. +blog#:#blog_enable_approval_info#:#A bejegyzések csak a blog egy ‘Beállítások módosítása’ jogosultsággal rendelkező felhasználójának jóváhagyása után kerülnek közzétételre. blog#:#blog_enable_keywords#:#Kulcsszavak -blog#:#blog_enable_keywords_info#:#A bejegyzésekhez kulcsszavak állíthatóak be, melyre kattintva az összes avval a kulcsszóval megjelölt bejegyzése megjelenik. +blog#:#blog_enable_keywords_info#:#A bejegyzésekhez kulcsszavak állíthatók be, melyre kattintva az összes avval a kulcsszóval megjelölt bejegyzése megjelenik. blog#:#blog_enable_nav_authors#:#Szerzők blog#:#blog_enable_nav_authors_info#:#A szerzők felsorolása, ahol a névre kattintva megjelenik az adott szerző összes bejegyzése. blog#:#blog_enable_notes#:#Nyilvános megjegyzések blog#:#blog_enable_rss#:#RSS bekapcsolása blog#:#blog_enable_rss_info#:#Az RSS csatorna nyilvános, és független a blogmegosztástól vagy felhasználói jogoktól. -blog#:#blog_est_reading_time#:#Estimated Reading Time###29 07 2022 new variable -blog#:#blog_est_reading_time_info#:#For Blogs in the repository reading time can be determined and displayed.###29 07 2022 new variable -blog#:#blog_exercise_info#:#Ez a blog a(z) '%s' értékelés része, amely a(z) '%s' beadandó feladathoz tartozik. +blog#:#blog_est_reading_time#:#Becsült olvasási idő +blog#:#blog_est_reading_time_info#:#Blogoknál az olvasási időt meghatározhatjuk és megjeleníthetjük. +blog#:#blog_exercise_info#:#Ez a blog a(z) ‘%s’ értékelés része, amely a(z) ‘%s’ beadandó feladathoz tartozik. blog#:#blog_exercise_submitted_info#:#Utolsó beadásának időpontja: %s. Ellenőrizze az exportfájlt: %s blog#:#blog_finalize_blog#:#Blog véglegesítése és elküldése blog#:#blog_finalized#:#A blogot elküldte. blog#:#blog_import#:#Blog importálása -blog#:#blog_incl_comments#:#including comments +blog#:#blog_incl_comments#:#hozzászólásokkal együtt blog#:#blog_keyword#:#Kulcsszó blog#:#blog_keyword_enter#:#Írjon be egy kulcsszót, majd nyomjon Enter-t. blog#:#blog_keywords#:#Kulcsszavak blog#:#blog_latest_posting#:#Utolsó bejegyzés -blog#:#blog_link#:#Link###29 07 2022 new variable +blog#:#blog_link#:#Link blog#:#blog_list_more#:#Bővebben blog#:#blog_list_num_postings#:#Bejegyzések száma blog#:#blog_list_num_postings_info#:#Ez a beállítás csak akkor használható, ha nincs konkrét hónap kiválasztva. blog#:#blog_nav_mode#:#Bejegyzések blog#:#blog_nav_mode_month_list#:#Hónapok listájának megjelenítése -blog#:#blog_nav_mode_month_list_info#:#Összes hónap felsorolása bejegyzéseikkel együtt a 'Bejegyzések' blokkban. +blog#:#blog_nav_mode_month_list_info#:#Összes hónap felsorolása bejegyzéseikkel együtt a ‘Bejegyzések’ blokkban. blog#:#blog_nav_mode_month_list_num_month#:#Felsorolt hónapok száma blog#:#blog_nav_mode_month_list_num_month_info#:#A korlát feletti hónapokat nem soroljuk fel és az azokhoz kapcsolódó bejegyzéseket nem lehet elérni. blog#:#blog_nav_mode_month_list_num_month_with_post#:#Hónapok száma blog#:#blog_nav_mode_month_list_num_month_with_post_info#:#A navigációs blokkban ezek a hónap jelennek meg a bejegyzéseikkel együtt. blog#:#blog_nav_mode_month_single#:#Kiválasztott hónap megjelenítése -blog#:#blog_nav_mode_month_single_info#:#Csak a kiválasztott hónap összes bejegyzése kerül felsorolásra a 'Bejegyzések' blokkban. A kívánt hónap legördülőből választható. +blog#:#blog_nav_mode_month_single_info#:#Csak a kiválasztott hónap összes bejegyzése kerül felsorolásra a ‘Bejegyzések’ blokkban. A kívánt hónap legördülőből választható. blog#:#blog_nav_sortorder#:#Blokkok rendezése blog#:#blog_navigation#:#Bejegyzések blog#:#blog_needs_approval#:#A blogbejegyzést még senki sem hagyta jóvá @@ -2508,7 +2488,7 @@ blog#:#blog_posting_deleted#:#A bejegyzést sikeresen törölte. blog#:#blog_posting_deletion_confirmation#:#Biztos, hogy törli az alábbi bejegyzéseket? blog#:#blog_posting_edit_approval_info#:#A hozzászólást a közzététel előtt egy tutornak jóvá kell hagynia. blog#:#blog_posting_not_found#:#Ez a blogbejegyzés nem elérhető. -blog#:#blog_postings#:#Postings###29 07 2022 new variable +blog#:#blog_postings#:#Bejegyzések blog#:#blog_presentation_frame#:#Blogmegjelenítés blog#:#blog_presentation_overview#:#Kezdeti áttekintés blog#:#blog_preview#:#Előnézet @@ -2516,53 +2496,60 @@ blog#:#blog_profile_picture#:#Profilkép megjelenítése blog#:#blog_profile_picture_repository_info#:#A szerzők profilképe megjelenik a bejegyzések oldalain, de az áttekintő oldalakon nem. blog#:#blog_properties#:#Blog tulajdonságai blog#:#blog_rename_posting#:#Bejegyzés átnevezése -blog#:#blog_selected_pages#:#Selected Postings###29 07 2022 new variable +blog#:#blog_selected_pages#:#Kijelölt bejegyzések blog#:#blog_settings#:#Blog beállításainak kezelése blog#:#blog_settings_navigation#:#Navigáció oszlop blog#:#blog_show_latest#:#Utolsó bejegyzés/piszkozat megjelenítése -blog#:#blog_show_print_view#:#Show Print View###29 07 2022 new variable -blog#:#blog_side_blocks#:#Side Blocks###28 10 2024 new variable -blog#:#blog_starting_page#:#Starting Page###26 08 2024 new variable -blog#:#blog_task_publishing_draft_title#:#'%s' bejegyzéspiszkozat közzététele +blog#:#blog_show_print_view#:#Nyomtatási nézet megjelenítése +blog#:#blog_side_blocks#:#Oldalsó blokkok +blog#:#blog_starting_page#:#Kezdőoldal +blog#:#blog_task_publishing_draft_title#:#‘%s’ bejegyzéspiszkozat közzététele blog#:#blog_toggle_draft#:#Közzététel visszavonása blog#:#blog_toggle_draft_admin#:#Blog hozzászólások tiltása blog#:#blog_toggle_final#:#Bejegyzés közzététele -blog#:#blog_whole_blog#:#Whole Blog###29 07 2022 new variable +blog#:#blog_whole_blog#:#Teljes blog book#:#X_reservations_of#:#%s foglalás / book#:#book_add#:#Foglalásgyűjtemény létrehozása book#:#book_add_object#:#Objektum létrehozása +book#:#book_add_participant#:#Résztvevő hozzáadása book#:#book_add_schedule#:#Időterv létrehozása book#:#book_additional_info_file#:#További leírás book#:#book_all#:#Összes megjelenítése +book#:#book_all_day#:#All-Day###07 07 2026 new variable book#:#book_all_pools_need_schedules#:#A beállításokat nem mentettük. Az összes hozzárendelt gyűjteménynek kell, hogy legyen legalább egy időterve. book#:#book_all_users#:#Összes résztvevő book#:#book_assign#:#Lefoglalás book#:#book_assign_object#:#Foglalható objektum lefoglalása book#:#book_assign_participant#:#Résztvevőnek lefoglalás +book#:#book_assign_participants#:#Book for other Participant(s)###07 07 2026 new variable book#:#book_back_to_list#:#Vissza a listához book#:#book_bobj#:#Foglalható objektumok book#:#book_book#:#Lefoglalom -book#:#book_book_available#:#Book Available Dates###26 08 2024 new variable -book#:#book_book_recurrence#:#Book multiple dates###26 08 2024 new variable +book#:#book_book_available#:#Elérhető dátumok +book#:#book_book_recurrence#:#Ismétlődő dátumok book#:#book_booked_in#:#Lefoglalt -book#:#book_booking#:#Booking###26 08 2024 new variable +book#:#book_booking#:#Foglalás book#:#book_booking_information#:#Információ -book#:#book_booking_objects#:#Booking Objects###29 07 2022 new variable +book#:#book_booking_objects#:#Foglalható objektumok book#:#book_booking_reminders#:#Jövőbeni foglalások book#:#book_bulk_confirmation#:#Kérem, ellenőrizze, hogy az összes érték helyesen jelenik-e meg. book#:#book_bulk_creation#:#Üres létrehozása book#:#book_bulk_data#:#Objektum adata book#:#book_cal_entry#:#Ennek a foglalása: book#:#book_confirm_booking#:#Foglalás megerősítése -book#:#book_confirm_booking_for_users#:#Are you sure you want to book this item for the following user(s)?###29 10 2025 new variable +book#:#book_confirm_booking_for_users#:#Biztos, hogy lefoglalja ezt az objektumot az alábbi felhaszáló(k)nak? book#:#book_confirm_booking_no_schedule#:#Biztos, hogy lefoglalja az alábbi objektumot? book#:#book_confirm_booking_schedule_number_of_objects#:#Foglalás visszaigazolása book#:#book_confirm_booking_schedule_number_of_objects_info#:#Adja meg a lefoglalandó objektumok számát. book#:#book_confirm_cancel#:#Biztos, hogy lemondja az alábbi foglalásokat? book#:#book_confirm_cancel_aggregation#:#Lemondandó foglalások száma +book#:#book_confirm_cancel_info#:#The selected bookings will be cancelled.###07 07 2026 new variable book#:#book_confirm_delete#:#Biztos, hogy törli az alábbi tételeket? +book#:#book_confirm_remove_participant#:#Are you sure you want to remove the following Participant(s)? This will delete all related Bookings.###07 07 2026 new variable book#:#book_copy#:#Foglalásgyűjtemény másolása -book#:#book_create_objects#:#Create Items###26 08 2024 new variable +book#:#book_create_objects#:#Objektumok létrehozása +book#:#book_date_from#:#From date###07 07 2026 new variable +book#:#book_date_to#:#To date###07 07 2026 new variable book#:#book_deadline#:#Határidő book#:#book_deadline_hours#:#X órával a foglalási időszak előttig book#:#book_deadline_info#:#Minimális idő a foglalás és a foglalt időszakok között @@ -2570,51 +2557,72 @@ book#:#book_deadline_options#:#Foglalási határidő book#:#book_deadline_slot_end#:#Foglalási időszak végéig book#:#book_deadline_slot_start#:#Foglalási időszak elejéig book#:#book_deassign#:#Foglalás megszüntetése +book#:#book_delete_object#:#Delete###07 07 2026 new variable +book#:#book_deleted_booking#:#Deleted Booking(s)###07 07 2026 new variable +book#:#book_deleted_object#:#Deleted Bookable Item###07 07 2026 new variable book#:#book_download_info#:#További leírás letöltése book#:#book_edit#:#Foglalásgyűjtemény módosítása book#:#book_edit_object#:#Objektum módosítása book#:#book_edit_schedule#:#Időterv módosítása +book#:#book_filter_end_date#:#End Date###07 07 2026 new variable +book#:#book_filter_objects#:#Bookable Items###07 07 2026 new variable book#:#book_filter_past_reservations#:#Múltbéli foglalások megjelenítése +book#:#book_filter_period#:#Period###07 07 2026 new variable +book#:#book_filter_start_date#:#Start Date###07 07 2026 new variable book#:#book_fromto#:#Dátumtartomány book#:#book_hours#:#Óra book#:#book_is_used#:#Használja -book#:#book_limit_objects_available#:#Nem rendelhet hozzá %s résztvevőt ('%s'), mert csak %s elem érhető el. -book#:#book_list#:#List###26 08 2024 new variable +book#:#book_limit_objects_available#:#Nem rendelhet hozzá %s résztvevőt (‘%s’), mert csak %s elem érhető el. +book#:#book_list#:#Felsorolás book#:#book_log#:#Foglalások -book#:#book_mail_permanent_link#:#Link to Booking Pool###26 08 2024 new variable -book#:#book_mail_to_booker#:#Mail to User###26 08 2024 new variable -book#:#book_message#:#Message###26 08 2024 new variable -book#:#book_message_info#:#You may enter a message for the booking organiser here.###26 08 2024 new variable -book#:#book_messages#:#Messages###26 08 2024 new variable -book#:#book_messages_info#:#Allow users to add a message when booking an item.###26 08 2024 new variable -book#:#book_missing_availability#:#It was not possible to book all items on all dates.###26 08 2024 new variable -book#:#book_missing_items#:#$1 missing item(s).###26 08 2024 new variable +book#:#book_mail_permanent_link#:#Link a foglalásgyűjteményhez +book#:#book_mail_to_booker#:#Levél a felhasználónak +book#:#book_message#:#Üzenet +book#:#book_message_info#:#Itt írhat üzenetet a foglalás szervezőjének. +book#:#book_messages#:#Üzenetek +book#:#book_messages_info#:#A felhasználók üzenetet írhatnak a foglaláskor. +book#:#book_missing_availability#:#Nem lehetséges az összes időpont összes elemét lefoglalni. +book#:#book_missing_items#:#$1 elem hiányzik. +book#:#book_modal_booking_confirmation#:#Booking Confirmation###07 07 2026 new variable +book#:#book_modal_enter_quantity_intro#:#Please enter the number of items that you would like to book.###07 07 2026 new variable +book#:#book_modal_recurrence#:#Recurrence###07 07 2026 new variable +book#:#book_modal_recurrence_multiple#:#Book multiple dates###07 07 2026 new variable +book#:#book_modal_recurrence_single#:#Book only this date###07 07 2026 new variable +book#:#book_modal_skipped_unknown_item#:#Unknown or invalid selection (%s).###07 07 2026 new variable +book#:#book_modal_warning_skipped_selections#:#Some selected items or periods are not available for booking and are excluded from this confirmation.###07 07 2026 new variable book#:#book_new#:#Új foglalásgyűjtemény book#:#book_no_bookings_for_you#:#Nem foglaltunk le semmi az Ön számára. book#:#book_no_objects#:#Nincs hozzárendelés +book#:#book_no_objects_available#:#None of the selected items are currently available for booking.###07 07 2026 new variable book#:#book_no_of_objects#:#Objektumok száma -book#:#book_no_pools_selected#:#No booking pools have been assigned to this course. Booking pools can be assigned via the course's 'Resources' tab.###29 10 2025 new variable +book#:#book_no_pools_selected#:#Ehhez a kurzushoz nincsenek hozzárendelve foglalási csoportok. A foglalási csoportokat a kurzus ‘Erőforrások’ lapján tud hozzárendelni. book#:#book_no_preferences_for_you#:#Egy előzetes választását sem tároltunk el. -book#:#book_no_recurrence#:#Book only this date###26 08 2024 new variable +book#:#book_no_recurrence#:#Foglalás csak erre a dátumra book#:#book_not#:#Nem +book#:#book_not_cancelled#:#Not cancelled###07 07 2026 new variable book#:#book_not_enough_preferences#:#Az előzetes választása túl kevés, azokat nem mentettük. book#:#book_notification#:#Foglalási értesítők küldése -book#:#book_notification_cron_not_active#:#Note: The necessary cron job, 'Send Reservation Notifications', is currently not active.###26 08 2024 new variable +book#:#book_notification_cron_not_active#:#Megjegyzés: A ‘Foglalási értesítők küldése’ ütemezett feladat nem aktív. book#:#book_notification_info#:#A következő napon a foglalások listáját elküldjük a felhasználóknak (saját foglalásaikat) és az üzemeltetőknek (ha be van kapcsolva). book#:#book_nr_of_preferences#:#Választási lehetőségek száma book#:#book_nr_of_preferences_info#:#A felhasználók által előzetes választható elemek száma. -book#:#book_nr_preferences#:#Prefences###29 07 2022 new variable -book#:#book_obj_select#:#Select###26 08 2024 new variable +book#:#book_nr_preferences#:#Prefenciák +book#:#book_obj_select#:#Kiválasztás book#:#book_object_added#:#Sikeresen létrehozott egy foglalástípust. book#:#book_object_deleted#:#A foglalható objektumot sikeresen törölte. -book#:#book_object_selection#:#Item Selection###26 08 2024 new variable +book#:#book_object_selection#:#Objektumválasztás +book#:#book_object_title_or_description#:#Title/Description###07 07 2026 new variable book#:#book_object_updated#:#A foglalható objektumot sikeresen frissítette. book#:#book_objects_available#:#%s elérhető objektum book#:#book_open#:#Foglalásgyűjtemény megnyitása -book#:#book_overall_limit#:#Foglalások maximális száma +book#:#book_overall_limit#:#Felhasználonkénti összes foglalás maximális száma book#:#book_overall_limit_warning#:#Foglalásai elérték a maximális megengedett számot. -book#:#book_participant_already_assigned#:#A résztvevőt már korábban hozzárendelték. +book#:#book_overall_limit_would_be_exceeded#:#Invalid selection. The overall limit would be exceeded.###07 07 2026 new variable +book#:#book_participant#:#Participant###07 07 2026 new variable +book#:#book_participant_already_assigned#:#Egy vagy több résztvevőt már korábban hozzárendeltek. book#:#book_participant_assigned#:#A résztvevő(k)nek sikeresen lefoglalta. +book#:#book_participant_removed#:#The participants and all related bookings have been removed successfully.###07 07 2026 new variable +book#:#book_past_bookings#:#Past bookings###07 07 2026 new variable book#:#book_period#:#Időszak book#:#book_pool_added#:#Sikeresen létrehozott egy foglalásgyűjteményt. book#:#book_pool_selection#:#Foglalásgyűjtemény kiválasztása @@ -2625,46 +2633,50 @@ book#:#book_post_booking_text_info#:#Használhatja a foglalások adatainak hely book#:#book_pref_book_cron#:#Foglalás előzetes választási lehetőségekkel book#:#book_pref_book_cron_info#:#Automatikus foglalások az előzetes választások alapján a határidő után book#:#book_pref_deadline#:#Határidő -book#:#book_pref_deadline_info#:#Preferences can be given up to this point.###29 07 2022 new variable +book#:#book_pref_deadline_info#:#A preferenciák idáig adhatók. book#:#book_pref_overview#:#Áttekintés book#:#book_preference_info#:#Kérem, válasszon %1 lehetőséget %2-ig. A foglalásokat automatikusan megtesszük a határidő után az összes felhasználó előzetes választása alapján. book#:#book_preferences#:#Előzetes választások book#:#book_preferences_saved#:#Az előzetes választásait sikeresen mentette. +book#:#book_present_bookings#:#Present bookings###07 07 2026 new variable book#:#book_public_log#:#A foglalások nyilvánosak book#:#book_public_log_info#:#Az olvasási jogosultsággal rendelkezők a többi felhasználó foglalását is megtekinthetik. -book#:#book_recurrence#:#Recurrence###26 08 2024 new variable -book#:#book_refresh#:#Refresh###26 08 2024 new variable +book#:#book_recurrence#:#Ismétlődés +book#:#book_refresh#:#Frissítése book#:#book_rem_intro#:#A jövőbeni foglalások áttekintése: book#:#book_rem_reason#:#Ezt az e-mail azért küldtük, mert Ön értesítéseket kér az érintett foglalásokról. -book#:#book_reminder_day#:#A foglalás előtt +book#:#book_reminder_day#:#Emlékeztető küldése book#:#book_reminder_day_info#:#A felhasználóknak saját foglalásuk, a vezetőknek az összes foglalás megküldése. -book#:#book_reminder_days#:#nappal +book#:#book_reminder_days#:#nappal a foglalás előtt book#:#book_reminder_setting#:#Emlékeztető -book#:#book_rerun_assignments#:#Run Allocation Process###26 08 2024 new variable -book#:#book_rerun_confirmation#:#Attention. The process of allocating bookings according to preferences has already taken place. You may restart the process if any errors have occurred, e.g. no bookings have been saved. To prevent multiple allocations, please delete all existing bookings before restarting the process.###26 08 2024 new variable +book#:#book_remove_participants#:#Remove Participant(s)###07 07 2026 new variable +book#:#book_rerun_assignments#:#Hozzárendelési folyamat futtatása +book#:#book_rerun_confirmation#:#Figyelem. A preferencián keresztüli hozzárendelések már lefutottak. A folyamatot újraindíthatja, ha bármilyen hiba történt, például nem sikerült menteni az összes hozzárendelést. A többszöri hozzárendelés elkerülése érdekében törölje az összes foglalást a folyamat újraindítása előtt. book#:#book_reservation_available#:#%s elérhető +book#:#book_reservation_cancelled#:#Reservation(s) cancelled.###07 07 2026 new variable book#:#book_reservation_confirmed#:#Foglalását megerősítette. book#:#book_reservation_failed#:#Foglalása sikertelen. book#:#book_reservation_failed_overbooked#:#Foglalás sikertelen, mert az objektum már nem elérhető. book#:#book_reservation_filter_period#:#Foglalási lista időköze book#:#book_reservation_filter_period_info#:#Az alapértelmezett időszakszűrő értéke napokban a mai dátumtól számítva. book#:#book_reservation_fix_info#:#A foglalás csak adott időpontokra lehetséges. -book#:#book_reservation_overview#:#Foglalások áttekintése +book#:#book_reservation_overview#:#Foglalás áttekintése book#:#book_reservation_status_5#:#Törölve book#:#book_reservation_title#:#Foglalás ehhez: book#:#book_reservations_list#:#Foglalások book#:#book_schedule#:#Időterv book#:#book_schedule_added#:#Sikeresen létrehozta a foglalás időtervét. +book#:#book_schedule_all_day#:#All-Day Schedule###07 07 2026 new variable book#:#book_schedule_days#:#Hétköznap book#:#book_schedule_days_info#:#Érvényes foglalási idők az egyes napokra (ÓÓ:PP-ÓÓ:PP) book#:#book_schedule_deleted#:#A foglalási időtervet sikeresen törölte. book#:#book_schedule_slot#:#Időtartam -book#:#book_schedule_type#:#Típus +book#:#book_schedule_type#:##Foglalási mód book#:#book_schedule_type_fixed#:#Ismétlődő, rögzített időterv book#:#book_schedule_type_fixed_info#:#Termek, kivetítők, stb. foglalásánál használható. book#:#book_schedule_type_none#:#Nincs időterv book#:#book_schedule_type_none_direct#:#Nincs ismétlődés, közvetlen a foglalás -book#:#book_schedule_type_none_direct_info#:#Előadástéma, feladatkiosztás, stb. választásához használható. A résztvevők közvetlenül foglalhatnak elemeket. +book#:#book_schedule_type_none_direct_info#:#Előadástéma, feladatkiosztás, stb. választásához használható. A résztvevők közvetlenül foglalhatnak elemeket. Minden elemet résztvevőnként csak egyszer lehet lefoglalni. book#:#book_schedule_type_none_info#:#Szemináriumi dolgozatokhoz, beszámolókhoz és hasonlókhoz használható book#:#book_schedule_type_none_preference#:#Nincs ismétlődés, az előzetes választásokat használjuk book#:#book_schedule_type_none_preference_info#:#Előadástéma, feladatkiosztás, stb. választásához használható. A résztvevők előzetesen választhatnak, majd a tényleges foglalások az előzetes választások határideje után történik meg. @@ -2674,33 +2686,46 @@ book#:#book_schedules#:#Időtervek book#:#book_select_pool#:#Válasszon gyűjteményt book#:#book_set_cancel#:#Foglalás törlése book#:#book_set_delete#:#Törlése -book#:#book_show_message#:#Show Message###26 08 2024 new variable -book#:#book_title_description_nr#:#Title; Description; Number of Units###26 08 2024 new variable -book#:#book_title_description_nr_info#:#Enter title, description and number of units separated by semicolon or TAB character (if importing from spreadsheet software). Use one line per item.###26 08 2024 new variable +book#:#book_show_message#:#Üzenet megjelenítése +book#:#book_show_past_bookings#:#Show past bookings###07 07 2026 new variable +book#:#book_some_reservations_unavailable#:#Some of the selected items could not be booked because they are no longer available.###07 07 2026 new variable +book#:#book_table#:#Table###07 07 2026 new variable +book#:#book_table_col_availability#:#Availability###07 07 2026 new variable +book#:#book_table_col_datetime#:#Date/Time###07 07 2026 new variable +book#:#book_title_description_nr#:#Cím; Leírás; Objektumok száma +book#:#book_title_description_nr_info#:#Adja meg a címet, a leírást és az objektumok számát pontosvesszővel vagy TAB karakterrel elválasztva (ha táblázatkezelőből importálja). Minden objektum új sorba kerüljön. book#:#book_too_many_preferences#:#Az előzetes választása túl sok, azokat nem mentettük. +book#:#book_total_individual_bookings_limit#:#Az egyes résztvevők által/az egyes résztvevők számára az összes foglalás számának korlátozása. Mindegyik elem továbbra is csak egyszer foglalható résztvevőnként. book#:#book_type_warning#:#Jelenleg nem érhető el foglalható objektum. A foglalásgyűjtemény használatához foglalható objektumot is létre kell hoznia. -book#:#book_week#:#Week###26 08 2024 new variable +book#:#book_view#:#View###07 07 2026 new variable +book#:#book_week#:#hét +book#:#book_week_no_objects_selected#:#Select at least one Bookable Item at the ‘Item Selection’ section on the right and click the ‘Refresh’ button.###07 07 2026 new variable book#:#book_your_bookings#:#Foglalásaim book#:#book_your_preferences#:#Előzetes választásaim book#:#book_your_reservations#:#Foglalásaim book#:#booking_multiple_succesfully#:#A foglalásokat sikeresen létrehozta. book#:#booking_nr_of_items#:#Darabszám +book#:#booking_process_error#:#There was an error while processing your booking(s). Please try again.###07 07 2026 new variable +book#:#bookings_log#:#Bookings###07 07 2026 new variable +book#:#delete_bookable_item#:#Delete Bookable Item###07 07 2026 new variable +book#:#no_valid_selection#:#No valid selection###07 07 2026 new variable book#:#obj_book_duplicate#:#Foglalásgyűjtemény másolása book#:#participants#:#Résztvevők book#:#reservation_deleted#:#A foglalást sikeresen törölte +book#:#schedule_type#:#Schedule Type###07 07 2026 new variable buddysystem#:#buddy_allow_to_contact_me#:#Ismerősnek jelölhetnek -buddysystem#:#buddy_allow_to_contact_me_default_info#:#Defines if users can send each other requests for getting into contact by default.###29 10 2025 new variable -buddysystem#:#buddy_allow_to_contact_me_info#:#Ha be van kapcsolva, a többi felhasználó kérést küldhet felém, hogy ismerősnek kíván megjelölni. +buddysystem#:#buddy_allow_to_contact_me_default_info#:#Meghatározza, hogy a felhasználók alapértelmezés szerint küldhetnek-e egymásnak kapcsolatfelvételi kéréseket. +buddysystem#:#buddy_allow_to_contact_me_info#:#A többi felhasználó kérést küldhet felém, hogy ismerősnek kíván megjelölni. buddysystem#:#buddy_bs_act_btn_txt_ignored_request_to_linked#:#Jelölés elfogadása buddysystem#:#buddy_bs_act_btn_txt_ignored_request_to_unlinked#:#Jelölés visszavonása buddysystem#:#buddy_bs_act_btn_txt_linked_to_unlinked#:#Jelölés visszavonása buddysystem#:#buddy_bs_act_btn_txt_requested_to_ignored_request#:#Jelölés elutasítása buddysystem#:#buddy_bs_act_btn_txt_requested_to_linked#:#Jelölés elfogadása buddysystem#:#buddy_bs_act_btn_txt_requested_to_unlinked#:#Jelölés visszavonása -buddysystem#:#buddy_bs_action_already_ignored#:#Ezt a műveletet nem lehet végrehajtani. '%s' felhasználót már elutasította. -buddysystem#:#buddy_bs_action_already_linked#:#Ezt a műveletet nem lehet végrehajtani. '%s' felhasználótól már elfogadta a jelölést. -buddysystem#:#buddy_bs_action_already_requested#:#Ezt a műveletet nem lehet végrehajtani. '%s' felhasználónak már küldött jelölést. -buddysystem#:#buddy_bs_action_already_unlinked#:#Ezt a műveletet nem lehet végrehajtani. '%s' felhasználótól már visszavonta a jelölést. +buddysystem#:#buddy_bs_action_already_ignored#:#Ezt a műveletet nem lehet végrehajtani. ‘%s’ felhasználót már elutasította. +buddysystem#:#buddy_bs_action_already_linked#:#Ezt a műveletet nem lehet végrehajtani. ‘%s’ felhasználótól már elfogadta a jelölést. +buddysystem#:#buddy_bs_action_already_requested#:#Ezt a műveletet nem lehet végrehajtani. ‘%s’ felhasználónak már küldött jelölést. +buddysystem#:#buddy_bs_action_already_unlinked#:#Ezt a műveletet nem lehet végrehajtani. ‘%s’ felhasználótól már visszavonta a jelölést. buddysystem#:#buddy_bs_action_not_possible#:#Ezt a műveletet nem lehet végrehajtani buddysystem#:#buddy_bs_btn_txt_ignored_request_a#:#Elutasított buddysystem#:#buddy_bs_btn_txt_ignored_request_p#:#Elutasított @@ -2714,59 +2739,60 @@ buddysystem#:#buddy_bs_state_ignored_request_p#:#Ismerősnek jelölés elutasít buddysystem#:#buddy_bs_state_ignoredrequest#:#Ismerősnek jelölés elutasítva buddysystem#:#buddy_bs_state_linked#:#Ismerős buddysystem#:#buddy_bs_state_linked_a#:#Ismerős -buddysystem#:#buddy_bs_state_linked_p#:#Linked###29 07 2022 new variable +buddysystem#:#buddy_bs_state_linked_p#:#Összekötve buddysystem#:#buddy_bs_state_requested#:#Ismerősnek jelölés elküldve buddysystem#:#buddy_bs_state_requested_a#:#Ismerősnek jelölés elküldve -buddysystem#:#buddy_bs_state_requested_filter_a#:#Waiting for Reaction###29 07 2022 new variable -buddysystem#:#buddy_bs_state_requested_filter_p#:#Action Required###29 07 2022 new variable +buddysystem#:#buddy_bs_state_requested_filter_a#:#Várakozás a válaszra +buddysystem#:#buddy_bs_state_requested_filter_p#:#Művelet szükséges buddysystem#:#buddy_bs_state_requested_p#:#Ismerősnek jelölés elküldve -buddysystem#:#buddy_bs_state_unlinked#:#Unlinked###29 07 2022 new variable +buddysystem#:#buddy_bs_state_unlinked#:#Nincs összekötve buddysystem#:#buddy_bs_state_unlinked_a#:#Ismeretlen -buddysystem#:#buddy_bs_state_unlinked_p#:#Unlinked###29 07 2022 new variable -buddysystem#:#buddy_enable#:#'Kapcsolatok' aktiválása -buddysystem#:#buddy_enable_info#:#Ha be van kapcsolva, felhasználók kérések küldésével/elfogadásával ismerősnek jelölhetik meg egymást. Az összes felhasználó egyéni beállításában engedélyezheti/tilthatja, hogy őt ismerősnek jelöljék. +buddysystem#:#buddy_bs_state_unlinked_p#:#Nincs összekötve +buddysystem#:#buddy_confirm_unlink#:#Biztos, hogy bontja a kapcsolatot ezzel az ismerőssel? +buddysystem#:#buddy_enable#:#‘Kapcsolatok’ aktiválása +buddysystem#:#buddy_enable_info#:#Felhasználók kérések küldésével/elfogadásával ismerősnek jelölhetik meg egymást. Az összes felhasználó egyéni beállításában engedélyezheti/tilthatja, hogy őt ismerősnek jelöljék. buddysystem#:#buddy_handle_contact_request#:#Kapcsolat kérése buddysystem#:#buddy_noti_cr_profile_not_published#:#A profil nincs közzétéve. buddysystem#:#buddy_notification_contact_request#:#Ismerősnek jelölés -buddysystem#:#buddy_notification_contact_request_ignore#:#Ignore Request###26 08 2024 new variable +buddysystem#:#buddy_notification_contact_request_ignore#:#Ismerősnek jelölés elutasítása buddysystem#:#buddy_notification_contact_request_ignore_osd#:#Ismerősnek jelölés elutasítása -buddysystem#:#buddy_notification_contact_request_link#:#Approve Request###26 08 2024 new variable +buddysystem#:#buddy_notification_contact_request_link#:#Ismerősnek jelölés elfogadása buddysystem#:#buddy_notification_contact_request_link_osd#:#Ismerősnek jelölés elfogadása -buddysystem#:#buddy_notification_contact_request_long#:#[SALUTATION][BR][BR]'[REQUESTING_USER]' ismerősnek jelölt.[BR][BR]Személyes profilja: [PERSONAL_PROFILE_LINK][BR][BR][APPROVE_REQUEST_TXT] [APPROVE_REQUEST][BR][IGNORE_REQUEST_TXT] [IGNORE_REQUEST] -buddysystem#:#buddy_notification_contact_request_short#:#'[REQUESTING_USER]' ismerősnek jelölt meg.[BR][BR][APPROVE_REQUEST][BR][IGNORE_REQUEST] +buddysystem#:#buddy_notification_contact_request_long#:#[SALUTATION][BR][BR]‘[REQUESTING_USER]’ ismerősnek jelölt.[BR][BR]Személyes profilja: [PERSONAL_PROFILE_LINK][BR][BR][APPROVE_REQUEST_TXT] [APPROVE_REQUEST][BR][IGNORE_REQUEST_TXT] [IGNORE_REQUEST] +buddysystem#:#buddy_notification_contact_request_short#:#‘[REQUESTING_USER]’ ismerősnek jelölt.[BR][BR][APPROVE_REQUEST][BR][IGNORE_REQUEST] buddysystem#:#buddy_relation_requested#:#A felhasználónak sikeresen elküldte a kérést. buddysystem#:#buddy_request_approved#:#Sikeresen elfogadta a jelölést. buddysystem#:#buddy_request_ignored#:#Figyelmen kívül hagyta a felhasználót. buddysystem#:#buddy_tbl_filter_state#:#Állapot -buddysystem#:#buddy_tbl_state_actions_col_label#:#State / Action###26 08 2024 new variable +buddysystem#:#buddy_tbl_state_actions_col_label#:#Állapot / Művelet buddysystem#:#buddy_tbl_title_relations#:#Kapcsolat a többi felhasználóval buddysystem#:#buddy_use_osd#:#Ismerősnek jelölések felugró ablakban buddysystem#:#buddy_use_osd_info#:#Felugró ablakban jelzi a rendszer, hogy valaki a ismerősei közé szeretné felvenni. buddysystem#:#buddy_view_gallery#:#Képtár buddysystem#:#buddy_view_table#:#Felsorolás cat#:#cat_copy#:#Kategória másolása -cat#:#cat_hide_tax_in_side_block#:#Don't Present in Side Panel###26 08 2024 new variable +cat#:#cat_hide_tax_in_side_block#:#Ne jelenjen meg az oldalpanelen cat#:#cat_import#:#Kategória importja cat#:#cat_more_translations#:#További fordítások -cat#:#cat_show_tax_in_side_block#:#Present in Side Panel###26 08 2024 new variable -cert#:#cert_currently_no_certs#:#Még egy igazolást sem sikerült kiérdemelnie. +cat#:#cat_show_tax_in_side_block#:#Megjelenjen az oldalpanelen +cert#:#cert_currently_no_certs#:#Még egy tanúsítványt sem szerzett cert#:#cert_description_label#:#Leírás cert#:#cert_download_label#:#Letöltés -cert#:#cert_error_no_access#:#Önnek nincs hozzáférése ehhez az igazoláshoz. +cert#:#cert_error_no_access#:#Önnek nincs hozzáférése ehhez a tanúsítványhoz. cert#:#cert_issued_on_label#:#Megszerezve ekkor cert#:#cert_object_label#:#Objektum -cert#:#cert_sortable_by_issue_date_asc#:#Dátum (növekvő) -cert#:#cert_sortable_by_issue_date_desc#:#Dátum (csökkenő) -cert#:#cert_sortable_by_title_asc#:#Cím (növekvő) -cert#:#cert_sortable_by_title_desc#:#Cím (csökkenő) +cert#:#cert_sortable_by_issue_date_asc#:#Dátum ↑ +cert#:#cert_sortable_by_issue_date_desc#:#Dátum ↓ +cert#:#cert_sortable_by_title_asc#:#Cím A→Z +cert#:#cert_sortable_by_title_desc#:#Cím Z→A cert#:#certificate_achievement#:#%1$s megszerezve. -cert#:#certificate_achievement_sub_obj#:#%1$s számára igazolás +cert#:#certificate_achievement_sub_obj#:#%1$s számára tanúsítvány cert#:#certificate_no_object_title#:#Az objektum címe nem érhető el -cert#:#certificate_same_not_saved#:#Nem jött létre új igazolássablon, mert az értékek nem módosultak. -cert#:#error_creating_certificate_pdf#:#Az igazolást nem sikerült létrehozni. Kérem, keresse a szerver üzemeltetőjét. -cert#:#user_certificates#:#Igazolások -certificate#:#cert_cron_task_desc#:#Ez a feladat felelős a felhasználók tanulási eredményeire épülő igazolások előállításáért. -certificate#:#cert_cron_task_title#:#Igazolások +cert#:#certificate_same_not_saved#:#Nem jött létre új tanúsítványsablon, mert az értékek nem módosultak. +cert#:#error_creating_certificate_pdf#:#A tanúsítványt nem sikerült létrehozni. Kérem, keresse a szerver üzemeltetőjét. +cert#:#user_certificates#:#Tanúsítványok +certificate#:#cert_cron_task_desc#:#Ez a feladat felelős a felhasználók tanulási eredményeire épülő tanúsítványok előállításáért. +certificate#:#cert_cron_task_title#:#Tanúsítványok certificate#:#cert_form_sec_add_features#:#További jellemzők certificate#:#cert_form_sec_availability#:#Elérhetőség certificate#:#cert_form_sec_layout#:#Elrendezés és szöveg @@ -2775,30 +2801,30 @@ certificate#:#certificate_a4_landscape#:#A4 fekvő (210 mm x 297 mm) certificate#:#certificate_a5#:#A5 (210 mm x 148 mm) certificate#:#certificate_a5_landscape#:#A5 fekvő (148 mm x 210 mm) certificate#:#certificate_background_image#:#Háttérkép -certificate#:#certificate_card_thumbnail_image#:#Kártyaminiatűrök -certificate#:#certificate_change_active_status#:#Az igazolás állapota megváltozott -certificate#:#certificate_confirm_deletion_text#:#Valóban törli az igazolást és annak minden kapcsolódó adatát? -certificate#:#certificate_custom#:#Egyéni... -certificate#:#certificate_edit#:#Igazolássablon létrehozása/módosítása -certificate#:#certificate_error_import#:#Hiba fordult elő egy igazolás importálásakor. +certificate#:#certificate_card_tile_image#:#Indexkép +certificate#:#certificate_change_active_status#:#A tanúsítvány ‘Aktív’ állapota megváltozott +certificate#:#certificate_confirm_deletion_text#:#Biztos, hogy törli a tanúsítványsablon minden adatát? +certificate#:#certificate_custom#:#Egyéni… +certificate#:#certificate_edit#:#Tanúsítványsablon létrehozása/módosítása +certificate#:#certificate_error_import#:#Hiba egy tanúsítvány importálásakor. certificate#:#certificate_error_upload_bgimage#:#Hiba fordult elő a háttérkép feltöltése közben. certificate#:#certificate_export#:#Exportálás -certificate#:#certificate_failed#:#sikertelen -certificate#:#certificate_file_basename#:#Igazolás -certificate#:#certificate_id#:#Certificate ID###26 08 2024 new variable -certificate#:#certificate_issue_date#:#Issue Date###26 08 2024 new variable -certificate#:#certificate_learning_progress_must_be_active#:#Csak tanulási haladású objektumok választhatóak ki. A tanulási haladás ki van kapcsolva a következő objektumoknál: %s +certificate#:#certificate_failed#:#Sikertelen +certificate#:#certificate_file_basename#:#Tanúsítvány +certificate#:#certificate_id#:#TanúsítványID +certificate#:#certificate_issue_date#:#Kibocsátás dátuma +certificate#:#certificate_learning_progress_must_be_active#:#Csak tanulási haladású objektumok választhatók ki. A tanulási haladás ki van kapcsolva a következő objektumoknál: %s certificate#:#certificate_letter#:#Levél (11 inch x 8,5 inch) certificate#:#certificate_letter_landscape#:#Levél fektetve (8,5 inch x 11 inch) certificate#:#certificate_margin_body#:#Szövegmargó -certificate#:#certificate_not_well_formed#:#Az igazolásszöveg rosszul formázott. Érvényes XHTML-t adjon meg az igazolásszövegnek! +certificate#:#certificate_not_well_formed#:#A tanúsítványszöveg rosszul formázott. Érvényes XHTML-t adjon meg a tanúsítványszövegnek! certificate#:#certificate_page_format#:#Lapformátum -certificate#:#certificate_page_format_info#:#Új igazolások alapértelmezett lapformátuma. +certificate#:#certificate_page_format_info#:#Új tanúsítványok alapértelmezett lapformátuma. certificate#:#certificate_pageheight#:#Lapmagasság certificate#:#certificate_pagewidth#:#Lapszélesség certificate#:#certificate_passed#:#sikeresen teljesítette certificate#:#certificate_ph_birthday#:#Felhasználó születésnapja -certificate#:#certificate_ph_cert_id#:#Unique Certificate ID###26 08 2024 new variable +certificate#:#certificate_ph_cert_id#:#Egyedi tanúsítvány-ID certificate#:#certificate_ph_city#:#Felhasználó címe - város certificate#:#certificate_ph_country#:#Felhasználó címe - ország certificate#:#certificate_ph_date#:#Aktuális dátum @@ -2818,7 +2844,7 @@ certificate#:#certificate_ph_mark#:#Felhasználók értékelése certificate#:#certificate_ph_marklong#:#Felhasználó érdemjegye (hivatalos változat) certificate#:#certificate_ph_markshort#:#Felhasználó érdemjegye (rövid változat) certificate#:#certificate_ph_matriculation#:#Felhasználó törzskönyvi száma -certificate#:#certificate_ph_no_sco#:#Ha vannak kiválasztott teljes tanulási haladás állapotot meghatározó tételek, a tételek címei és pontjai megjeleníthetők az igazolásban. +certificate#:#certificate_ph_no_sco#:#Ha vannak kiválasztott teljes tanulási haladás állapotot meghatározó tételek, a tételek címei és pontjai megjeleníthetők a tanúsítványban. certificate#:#certificate_ph_salutation#:#Megszólítás certificate#:#certificate_ph_sco_points_max#:#helyőrző
    ponthoz
    max. certificate#:#certificate_ph_sco_points_raw#:#helyőrző
    ponthoz @@ -2831,21 +2857,21 @@ certificate#:#certificate_ph_scos#:#Az alábbi tételeket választotta ki a telj certificate#:#certificate_ph_street#:#Felhasználó címe - utca certificate#:#certificate_ph_testtitle#:#Teszt címe certificate#:#certificate_ph_title#:#Név előtag -certificate#:#certificate_ph_title_sco#:#cím -certificate#:#certificate_ph_zipcode#:#Felhasználó címe - irányítószám +certificate#:#certificate_ph_title_sco#:#Cím +certificate#:#certificate_ph_zipcode#:#Felhasználó címe - irányítószám / postafiók certificate#:#certificate_points_notavailable#:#Ez az érték nem számítható certificate#:#certificate_preview#:#Előnézet -certificate#:#certificate_settings#:#Igazolás beállításai -certificate#:#certificate_short_name#:#Igazolásfájl rövid címe -certificate#:#certificate_short_name_description#:#Adja meg az igazolás rövid nevét! A rövid név az igazolásnév része lesz: ÉÉHHNN_[surname]_[SHORT_TITLE]_certificate.pdf -certificate#:#certificate_text#:#Igazolásszöveg -certificate#:#certificate_text_info#:#Please enter the certificate text. If the WYSIWYG editor is disabled in the ILIAS administration, you can still use valid XHTML to format the text.###26 08 2024 new variable +certificate#:#certificate_settings#:#Tanúsítvány beállításai +certificate#:#certificate_short_name#:#Tanúsítványfájl rövid címe +certificate#:#certificate_short_name_description#:#Adja meg a tanúsítvány rövid nevét! A rövid név a tanúsítványnév része lesz: ÉÉHHNN_[surname]_[SHORT_TITLE]_certificate.pdf +certificate#:#certificate_text#:#Tanúsítványszöveg +certificate#:#certificate_text_info#:#Kérem, adja meg a tanúsítvány szövegét. Amennyiben a WYSIWYG szerkesztő ki van kapcsolva a Rendszerbeállításokban, használjon érvényes XHTML formátumú szöveget. certificate#:#certificate_unit_description#:#Adja meg értékként a mérték egységeit [cm|mm|in|pt|pc|px|em], például 10 mm vagy 3 in! -certificate#:#certificate_usage#:#Az igazoláskezelés csak akkor érhető el, ha fut az ILIAS Java-szerver. A Java-szerver konfigurálása a Rendszerbeállítások » Általános beállítások » Szerver menü Java-szerver almenüjében érhető el. +certificate#:#certificate_usage#:#Felhívjuk figyelmét, hogy tanúsítványok használata és létrehozása csak akkor lehetséges, ha az ILIAS Java szervert használja. A Java szerver konfigurálása a hálózati gazdagép és port megadásával történik az ILIAS telepítőjében, és többek között a PDF fájlok létrehozásához szükséges. certificate#:#certificate_var_max_points#:#46 certificate#:#certificate_var_result_mark_long#:#Jó certificate#:#certificate_var_result_mark_short#:#Jó -certificate#:#certificate_var_result_passed#:#sikeresen teljesítette +certificate#:#certificate_var_result_passed#:#Sikeresen teljesítette certificate#:#certificate_var_result_percent#:#83% certificate#:#certificate_var_result_points#:#38 certificate#:#certificate_var_user_birthday#:#1977-05-08 @@ -2863,61 +2889,65 @@ certificate#:#certificate_var_user_street#:#Fő utca 100. certificate#:#certificate_var_user_title#:#Dr. certificate#:#certificate_var_user_zipcode#:#1234 certificate#:#cmix_cert_ph_object_description#:#Leírás -certificate#:#cmix_cert_ph_object_title#:#Az xAPI/cmi5 objektum címe -certificate#:#cmix_cert_ph_reached_score#:#Elért pontok százalékos értéke -certificate#:#default_background_info#:#Az igazolásokhoz alapértelmezetten ez a háttérkép kerül kiválasztásra. Ha másikra van szüksége, az igazolásszerkesztőbe kell feltöltenie. -certificate#:#download_certificate#:#Igazolás letöltése -certificate#:#learning_progress_deactivated#:#A tanulási haladás ki van kapcsolva ennél az objektumnál. Az igazolássablon módosításához és a felhasználók igazolásának legeneráláshoz be kell kapcsolni. -certificate#:#lti_cert_ph_mastery_score#:#Mastery pont százalékos értéke +certificate#:#cmix_cert_ph_object_title#:#Az xAPI/cmi5-objektum címe +certificate#:#cmix_cert_ph_reached_score#:#Elért pontszám százalékos értéke +certificate#:#default_background_info#:#A tanúsítványokhoz alapértelmezetten ez a háttérkép kerül kiválasztásra. Ha másikra van szüksége, a tanúsítványszerkesztőbe kell feltöltenie. +certificate#:#download_certificate#:#Tanúsítvány letöltése +certificate#:#learning_progress_deactivated#:#A tanulási haladás ki van kapcsolva ennél az objektumnál. A tanúsítványsablon módosításához és a felhasználók tanúsítványának legeneráláshoz be kell kapcsolni. +certificate#:#lti_cert_ph_mastery_score#:#Az elért pontszám százalékos értéke certificate#:#lti_cert_ph_object_description#:#Leírás certificate#:#lti_cert_ph_object_title#:#Az LTI-fogyasztó objektum címe certificate#:#lti_cert_ph_reached_score#:#Elért pontok százalékos értéke -certificate#:#persistent_certificate_mode#:#Igazolások előállítása +certificate#:#persistent_certificate_mode#:#Tanúsítványok előállítása certificate#:#persistent_certificate_mode_cron#:#Ütemezett feladat certificate#:#persistent_certificate_mode_cron_info#:#Ez a lehetőség magas felhasználói igénybevétel esetén ajánlott. certificate#:#persistent_certificate_mode_instant#:#Azonnali -certificate#:#persistent_certificate_mode_instant_info#:#Ez a lehetőség közepes, illetve alacsony felhasználói igénybevétel esetén ajánlott. Amennyiben az igazolások azonnali előállítása túl sok időt vesz igénybe, célszerű ütemezett feladatra váltani. +certificate#:#persistent_certificate_mode_instant_info#:#Ez a lehetőség közepes, illetve alacsony felhasználói igénybevétel esetén ajánlott. Amennyiben a tanúsítványok azonnali előállítása túl sok időt vesz igénybe, célszerű ütemezett feladatra váltani. chatroom#:#allow_anonymous#:#Anonymous bejelentkezés engedélyezett chatroom#:#allow_custom_usernames#:#Egyéni felhasználónevek megengedettek -chatroom#:#anonymous_hint#:#Bizonyosodjon meg arról, hogy a megfelelő jogosultságokat állította be a 'Jogosultságok' fülön az anonymous felhasználók számára ehhez a Tartalomtárbeli objektumokhoz. +chatroom#:#allow_custom_usernames_info#:#Allow users to enter their own unique session name to use within the chat room. If this option is not selected, users are automatically identified using their usernames (login) when in the chat room.###07 07 2026 new variable +chatroom#:#anonymous_hint#:#Bizonyosodjon meg arról, hogy a megfelelő jogosultságokat állította be a ‘Jogosultságok’ lapon az anonymous felhasználók számára ehhez a Tartalomtárbeli objektumokhoz. chatroom#:#auto_scroll#:#Görgetés az aljára chatroom#:#autogen_usernames#:#Automatikusan generált felhasználónevek -chatroom#:#autogen_usernames_info#:#Az anonymous felhasználói fiókokhoz rendelt automatikusan generált felhasználónév minta. A '#' lecserélődik majd egy számmal. +chatroom#:#autogen_usernames_info#:#Az anonymous felhasználói fiókokhoz rendelt automatikusan generált felhasználónév minta. A ‘#’ lecserélődik majd egy számmal. chatroom#:#ban_question#:#Biztos, hogy kitiltja a felhasználót ebből a szobából? chatroom#:#ban_table_title#:#Kitiltott felhasználók chatroom#:#banned#:#Kitiltották ebből a csevegőszobából chatroom#:#bans#:#Kizártak chatroom#:#chat_address#:#Címzés chatroom#:#chat_anonymous_not_allowed#:#A csevegés használatához jelentkezzen be. -chatroom#:#chat_auth_token_info#:#Kérem, egyedi sztringeket hozzon létre. Ezeket a sztringeket az ILIAS hitelesítési célokra használja, amikor kéréseket küld a chatszervernek. A megfelelő gombra kattintva automatikusan létrehozhatja ezeket a sztringeket. Kérem, figyeljen arra, hogy a chatszerver több ILIAS klienssel képes kommunikálni, ezért az összes kliens id-nek egyedinek kell lennie. +chatroom#:#chat_auth_token_info#:#Kérem, egyedi sztringeket hozzon létre. Ezeket a sztringeket az ILIAS hitelesítési célokra használja, amikor kéréseket küld a chatszervernek. A megfelelő gombra kattintva automatikusan létrehozhatja ezeket a sztringeket. Kérem, figyeljen arra, hogy a chatszerver több ILIAS klienssel képes kommunikálni, ezért az összes kliensnévnek egyedinek kell lennie. chatroom#:#chat_ban#:#Kizárás -chatroom#:#chat_broadcast_typing#:#Broadcast Typing###29 07 2022 new variable -chatroom#:#chat_broadcast_typing_default_info#:#If enabled, typing will be broadcasted to other participants of a conversation or chat room by default.###29 10 2025 new variable -chatroom#:#chat_broadcast_typing_info#:#If enabled, your typing will be broadcasted to other participants of a conversation or chat room.###29 07 2022 new variable +chatroom#:#chat_broadcast_typing#:#Gépelés műsorszórása +chatroom#:#chat_broadcast_typing_default_info#:#Ha be van kapcsolva, alapértelmezetten a gépelést továbbítjuk a beszélgetés vagy a csevegőszoba többi résztvevőjének. +chatroom#:#chat_broadcast_typing_info#:#A gépelési folyamat megjelenítése a beszélgetés, illetve a csevegőszoba résztvevőnél. chatroom#:#chat_connection_disconnected#:#--- #username# elhagyta a csevegőszobát --- chatroom#:#chat_connection_established#:#+++ #username# belépett a csevegőszobába +++ chatroom#:#chat_deletion_disabled#:#Kikapcsolva chatroom#:#chat_deletion_interval#:#Időköz -chatroom#:#chat_deletion_interval_info#:#Ha be van kapcsolva, a Képernyőcsevegések és a Tartalomtárban lévő beszélgetéseket a megadott küszöbérték elérés után töröljük. +chatroom#:#chat_deletion_interval_info#:#A Képernyőcsevegések és a Tartalomtárban lévő beszélgetéseket a megadott küszöbérték elérés után töröljük. chatroom#:#chat_deletion_interval_run_at#:#Idő chatroom#:#chat_deletion_interval_run_at_info#:#Adja meg az időpontot (ÓÓ:PP formátumban), amikor a szerver az üzenettörlési folyamatot végrehajthatja. chatroom#:#chat_deletion_interval_unit#:#Mértékegység chatroom#:#chat_deletion_interval_value#:#Érték -chatroom#:#chat_deletion_ival_max_val#:#A kiválasztott '%s' mértékegység legnagyobb értéke: +chatroom#:#chat_deletion_ival_max_val#:#A kiválasztott ‘%s’ mértékegység legnagyobb értéke: chatroom#:#chat_deletion_section_head#:#Régi üzenetek törlése -chatroom#:#chat_enable_history#:#Enable History###29 07 2022 new variable -chatroom#:#chat_enable_history_info#:#Everybody can read and export past public chat messages in the tab „History“. Messages from within private rooms are only accessible by invited users.###29 07 2022 new variable +chatroom#:#chat_enable_history#:#Előzmények bekapcsolása +chatroom#:#chat_enable_history_info#:#Az ‘Előzmények’ lapon bárki elolvashatja és exportálhatja a korábbi csevegéseket. chatroom#:#chat_error_log_info#:#Kérem, adja meg a chatszerver hibanapló-fájljának abszolút útvonalát (pl.: /var/www/ilias/data/chat_error.log). Amennyiben üresen hagyja, a naplófájl a chatszerver mappájába kerül. -chatroom#:#chat_functions#:#Chat Functions###26 08 2024 new variable +chatroom#:#chat_functions#:#Chat-funktiók chatroom#:#chat_https_cert_info#:#Kérem, adja meg az SSL tanúsítványfájl abszolút útvonalát (pl.: /etc/ssl/certs/server.pem). chatroom#:#chat_https_dhparam_info#:#Kérem, adja meg a fájl abszolút útvonalát (pl: /etc/ssl/private/dhparam.pem), amit a Diffie-Hellman paraméterek átadására használunk (például így generálták: openssl dhparam -out /etc/ssl/private/dhparam.pem 2048 ). chatroom#:#chat_https_key_info#:#Kérem, adja meg a privátkulcs-fájl abszolút útvonalát (pl: /etc/ssl/private/server.key). -chatroom#:#chat_invitation#:#'[INVITER_NAME]' meghívja Ön '[ROOM_NAME]' csevegőszobába -chatroom#:#chat_invitation_long#:#[SALUTATION] Meghívtak ebbe a csevegőszobába: Csevegőszoba neve: [ROOM_NAME] A meghívó: [INVITER_NAME] URL: [LINK] Ha csatlakozni szeretne a csevegőszobához, kattintson a megadott URL-re! -chatroom#:#chat_invitation_nc_inv_x#:#You have %s chat invitations.###29 07 2022 new variable -chatroom#:#chat_invitation_nc_no_inv#:#You have no chat invitations.###29 07 2022 new variable -chatroom#:#chat_invitation_short#:#A csevegőszobába belépéshez kattints a linkre. -chatroom#:#chat_invitations#:#Chat invitations###29 07 2022 new variable +chatroom#:#chat_invitation#:#‘[INVITER_NAME]’ meghívja Ön ‘[ROOM_NAME]’ csevegőszobába +chatroom#:#chat_invitation_long#:#[SALUTATION][BR][BR]Meghívtak ebbe a csevegőszobába:[BR]Csevegőszoba neve: [ROOM_NAME][BR]A meghívó: [INVITER_NAME][BR]URL: [LINK][BR]Ha csatlakozni szeretne a csevegőszobához, kattintson a megadott URL-re! +chatroom#:#chat_invitation_modal_headline#:#Meghívás csevegőszobába +chatroom#:#chat_invitation_modal_section#:#Felhasználó meghívása +chatroom#:#chat_invitation_nc_inv_x#:#%s meghívás van. +chatroom#:#chat_invitation_nc_no_inv#:#Egy meghívása sincs. +chatroom#:#chat_invitation_short#:#A csevegőszobába belépéshez kattintson a linkre. +chatroom#:#chat_invitation_username_input_label#:#Felhasználónév: +chatroom#:#chat_invitations#:#Meghívások chatroom#:#chat_invite#:#Meghívás chatroom#:#chat_join#:#Csatlakozás chatroom#:#chat_kick#:#Kirúgás @@ -2927,14 +2957,14 @@ chatroom#:#chat_mainroom#:#Főszoba chatroom#:#chat_message#:#Üzenet chatroom#:#chat_message_display#:#Lehetőségek chatroom#:#chat_message_options#:#Megjelenítés -chatroom#:#chat_no_use_typing_broadcast#:#Typing will not be broadcasted###29 07 2022 new variable +chatroom#:#chat_no_use_typing_broadcast#:#A gépelést nem broadcastoljuk. chatroom#:#chat_not_use_osc#:#Képernyőbeszélgetések használatának kikapcsolása chatroom#:#chat_osc_accept_msg#:#Képernyőbeszélgetések bekapcsolása -chatroom#:#chat_osc_accept_msg_default_info#:#If enabled, users are by default allowed to send each other messages using the on-screen chat system.###29 10 2025 new variable -chatroom#:#chat_osc_accept_msg_info#:#Ha be van kapcsolva, mások beszélgetést kezdeményezhetnek Önnel. -chatroom#:#chat_osc_accept_msg_info_slate#:#To have private conversations, you must enable your setting "Allow On-Screen Chat Conversations".###26 08 2024 new variable -chatroom#:#chat_osc_accept_msg_info_slate_link_txt#:#Visibility (in Profile and Privacy)###26 08 2024 new variable -chatroom#:#chat_osc_accept_no_conv_info_slate#:#There are currently no minimzed conversations.###26 08 2024 new variable +chatroom#:#chat_osc_accept_msg_default_info#:#Ha be van kapcsolva van, a felhasználók alapértelmezés szerint üzeneteket küldhetnek egymásnak a képernyőn megjelenő csevegőrendszeren keresztül. +chatroom#:#chat_osc_accept_msg_info#:#Mások beszélgetést kezdeményezhetnek Önnel. +chatroom#:#chat_osc_accept_msg_info_slate#:#A privát beszélgetésekhez kapcsolja be a beállításokban a "Képernyőbeszélgetések bekapcsolása" lehetőséget. +chatroom#:#chat_osc_accept_msg_info_slate_link_txt#:#Láthatóság (a Profilban és az Adatvédelemben) +chatroom#:#chat_osc_accept_no_conv_info_slate#:#Nincsenek kis méretűre állított beszélgetések. chatroom#:#chat_osc_accepts_messages_no#:#Nem fogad üzeneteket chatroom#:#chat_osc_accepts_messages_yes#:#Fogad üzeneteket chatroom#:#chat_osc_add_user#:#További felhasználók hozzáadása @@ -2943,14 +2973,14 @@ chatroom#:#chat_osc_doesnt_accept_msg#:#Beszélgetés nem lehetséges chatroom#:#chat_osc_head_grp_x_persons#:#%s felhasználó chatroom#:#chat_osc_invite_to_conversation#:#Beszélgetéshez hozzáadás chatroom#:#chat_osc_leave_grp_conv#:#Kilépés a beszélgetésből -chatroom#:#chat_osc_minimize#:#Minimize###26 08 2024 new variable +chatroom#:#chat_osc_minimize#:#Kis méret chatroom#:#chat_osc_nc_conv_x_p#:#%s rejtett beszélgetése van. chatroom#:#chat_osc_nc_conv_x_s#:#Egy rejtett beszélgetése van. chatroom#:#chat_osc_nc_no_conv#:#Egy beszélgetés sem érhető el chatroom#:#chat_osc_nc_prop_time#:#Idő chatroom#:#chat_osc_no_conv#:#Jelenleg nem zajlik beszélgetés. chatroom#:#chat_osc_no_sub_directory#:#Almappa -chatroom#:#chat_osc_no_sub_directory_info#:#Ha a Chatszerver egy almappán keresztül érhető el, mint például 'http(s)://[IP/Domain]/[SUB_DIRECTORY]', akkor itt adja meg az almappát, az előbbi példából a [SUB_DIRECTORY] részt. A legtöbb esetben nincs almappa, azaz ez a rész üresen hagyható. +chatroom#:#chat_osc_no_sub_directory_info#:#Ha a Chatszerver egy almappán keresztül érhető el, mint például ‘http(s)://[IP/Domain]/[SUB_DIRECTORY]’, akkor itt adja meg az almappát, az előbbi példából a [SUB_DIRECTORY] részt. A legtöbb esetben nincs almappa, azaz ez a rész üresen hagyható. chatroom#:#chat_osc_no_usr_found#:#Nincs a keresési feltételnek megfelelő felhasználó. chatroom#:#chat_osc_search_modal_info#:#Itt keresheti meg a beszélgetéshez hozzáadni kívánt felhasználókat. Ha a keresési ablakot egy csoportos csevegésből nyitották meg, az új felhasználót ahhoz a csoportos csevegéshez adjuk hozzá. Ha keresést egy 1:1 csevegésből indította, egy új csevegőcsoport-ablakot fogunk nyitni. chatroom#:#chat_osc_self_rej_msgs#:#Jelenleg nem vehet részt ebben a beszélgetésben, mert beállításaiban kikapcsolta, hogy üzeneteket küldhessenek Önnek. @@ -2960,20 +2990,21 @@ chatroom#:#chat_osc_subs_rej_msgs#:#Ez a beszélgetés jelenleg nem folytatható chatroom#:#chat_osc_subs_rej_msgs_p#:#Beszélgetésnek alábbi chat-partnerei nem kívánnak több üzenetet kapni: %s chatroom#:#chat_osc_sure_to_leave_grp_conv#:#Biztos, hogy kilép a csoportbeszélgetésből? chatroom#:#chat_osc_user#:#Felhasználó -chatroom#:#chat_osc_user_left_grp_conv#:#'%s' kilépett a csoportbeszélgetésből. -chatroom#:#chat_osc_write_a_msg#:#Éppen üzenetet ír ... +chatroom#:#chat_osc_user_left_grp_conv#:#‘%s’ kilépett a csoportbeszélgetésből. +chatroom#:#chat_osc_write_a_msg#:#Éppen üzenetet ír … chatroom#:#chat_select_room#:#Csevegőszoba kiválasztása chatroom#:#chat_settings#:#Csevegésbeállítások -chatroom#:#chat_settings_functions_header#:#Chat Room Functions###29 07 2022 new variable -chatroom#:#chat_show_auto_messages#:#Show Status Messages###29 07 2022 new variable +chatroom#:#chat_settings_functions_header#:#Csevegőszoba beállításai +chatroom#:#chat_show_auto_messages#:#Üzenetállapotok megjelenítése chatroom#:#chat_to_mainroom#:#A főszobába -chatroom#:#chat_use_osc#:#Képernyőbeszélgetések használata###XXX -chatroom#:#chat_use_typing_broadcast#:#Typing will be broadcasted###29 07 2022 new variable +chatroom#:#chat_use_osc#:#Képernyőbeszélgetések használata +chatroom#:#chat_use_typing_broadcast#:#A gépelés broadcastoljuk chatroom#:#chat_user_action_invite_osd#:#Meghívás képernyőbeszélgetésbe -chatroom#:#chat_user_action_invite_public_room#:#Meghívás nyilvános chatszobába -chatroom#:#chat_user_x_is_typing#:#User %s is typing ...###29 07 2022 new variable -chatroom#:#chat_users_are_typing#:#Multiple users are typing ...###29 07 2022 new variable +chatroom#:#chat_user_action_invite_public_room#:#Meghívás nyilvános csevegőszobába +chatroom#:#chat_user_x_is_typing#:#%s ír… +chatroom#:#chat_users_are_typing#:#Több felhasználó ír… chatroom#:#chat_whisper#:#Suttogás +chatroom#:#chatroom_anonymous_default#:#Anonymous ####07 07 2026 new variable chatroom#:#chatroom_auth#:#Hitelesítés chatroom#:#chatroom_auth_btn_txt#:#Kulcsok generálása chatroom#:#chatroom_auth_key#:#Hitelesítés-kulcs @@ -2981,14 +3012,14 @@ chatroom#:#chatroom_auth_secret#:#Hitelesítés-titok chatroom#:#chatroom_client_name#:#Név chatroom#:#chatroom_client_name_info#:#Kérem, adjon meg egy nevet ehhez az ILIAS-klienshez. A megadott névnek ezen az ILIAS telepítésen egyedinek kell lennie. Kezdeti értéke az ILIAS-kliens azonosítója. Módosítás után a chatszervert újra kell indítani. chatroom#:#chatroom_enable_osc#:#Képernyőbeszélgetések bekapcsolása -chatroom#:#chatroom_enable_osc_info#:#Ha be van kapcsolva, az összes felhasználó számára elérhetővé válik a képernyőbeszélgetés, de mindenki beállíthatja, hogy engedélyezi-e a többieknek, hogy beszélgethessenek vele. Beszélgetés a 'Ki van online'-eszközből indítható. +chatroom#:#chatroom_enable_osc_info#:#Az összes felhasználó számára elérhetővé válik a képernyőbeszélgetés, de mindenki beállíthatja, hogy engedélyezi-e a többieknek, hogy beszélgethessenek vele. Beszélgetés a ‘Ki van online’-eszközből indítható. chatroom#:#chatroom_log#:#Csevegőszerver napló chatroom#:#chatserver_address#:#Csevegőszerver IP címe/teljes neve chatroom#:#chatserver_port#:#Csevegőszerver portja -chatroom#:#chtr_activation_limited_visibility_info#:#Ha be van kapcsolva, a csevegés címe a láthatósági időszakon kívül is látszódik, még akkor is, ha csevegés nem érhető el. -chatroom#:#chtr_activation_online_info#:#A csevegés bekapcsolása, a résztvevők számára elérhetővé tétele. A nem online csevegést csak a 'Beállítások módosítása' jogosultsággal rendelkezők érhetik el. +chatroom#:#chtr_activation_limited_visibility_info#:#A csevegés címe a láthatósági időszakon kívül is látszódik, még akkor is, ha csevegés nem érhető el. +chatroom#:#chtr_activation_online_info#:#A csevegés bekapcsolása, a résztvevők számára elérhetővé tétele. A nem online csevegést csak a ‘Beállítások módosítása’ jogosultsággal rendelkezők érhetik el. chatroom#:#chtr_add#:#Csevegőszoba létrehozása -chatroom#:#chtr_ban_actor_tbl_head#:#Résztvevő +chatroom#:#chtr_ban_actor_tbl_head#:#zárolta chatroom#:#chtr_ban_ts_tbl_head#:#Időbélyeg chatroom#:#chtr_new#:#Új csevegőszoba chatroom#:#chtr_server_status#:#Szerverállapot @@ -3005,10 +3036,10 @@ chatroom#:#duration_to#:#Ide: chatroom#:#end_whisper#:#Mégsem chatroom#:#enter#:#Csevegőszobába belépés chatroom#:#error_log#:#Csevegőszerver hibanapló -chatroom#:#hint_display_past_msgs#:#A szobába belépéskor megjelenítendő korábbi üzenetek száma. A '0' érték kikapcsolja ezt a funkciót. +chatroom#:#hint_display_past_msgs#:#A szobába belépéskor megjelenítendő korábbi üzenetek száma. A ‘0’ érték kikapcsolja ezt a funkciót. chatroom#:#history_byday_title#:#Beszélgetés megjelenítése naponként chatroom#:#history_cleared#:#Az üzenettörténelmet törölte a moderátor. -chatroom#:#history_title_general#:#Beszélgetés a(z) '%s' csevegőszobában +chatroom#:#history_title_general#:#Beszélgetés a(z) ‘%s’ csevegőszobában chatroom#:#ilias_chatserver_connection#:#ILIAS kapcsolata a szerverhez chatroom#:#ilias_proxy_info#:#Ha a szerver az alapértelmezett IP címen és porton nem érhető el, lehetősége van az ILIAS számára a szerverhez kapcsolódásához egyéni URL-t beállítani. chatroom#:#invite_to_private_room#:#Jelenlegi szobába meghívás @@ -3018,31 +3049,31 @@ chatroom#:#kick_question#:#Biztos, hogy kirúgja a felhasználót ebből a szob chatroom#:#kicked#:#Kitiltották ebből a csevegőszobából chatroom#:#lost_connection#:#A csevegőszerverrel megszakadt a kapcsolat. chatroom#:#main#:#Főszoba -chatroom#:#messages#:#Messages###26 08 2024 new variable +chatroom#:#messages#:#Üzenetek chatroom#:#no_further_users#:#Nincs jelen más felhasználó chatroom#:#no_messages#:#Nincsenek mentett üzenetek a megadott időszakhoz. chatroom#:#no_username_given#:#Válasszon felhasználónevet chatroom#:#osc_browser_noti_no_permission_error#:#Kérem, távolítsa el ezt a domaint böngészője vagy operációs rendszere értesítési tiltólistájáról. Amíg ezt nem teszi meg, nem kap értesítéseket. chatroom#:#osc_browser_noti_no_support_error#:#A böngésző-értesítés nem támogatott a böngészőjében. Kérem, ellenőrizze, hogy HTTPS a kapcsolata és támogatott böngészők valamelyikét használja. -chatroom#:#osc_browser_noti_req_permission_error#:#A böngésző-értesítések nem kapcsolhatóak be, mert nem adott hozzáférést. Kérem, távolítsa el ezt a domaint böngészője vagy operációs rendszere értesítési tiltólistájáról. -chatroom#:#osc_enable_browser_notifications_info#:#Ha be van kapcsolva, értesítést kap a böngészőjében az új beszélgetésekről és üzenetekről amikor az ILIAS másik böngészőfülön vagy a háttérben van, illetve az előtérben %s percnyi tétlenségi idő után is. +chatroom#:#osc_browser_noti_req_permission_error#:#A böngésző-értesítések nem kapcsolhatók be, mert nem adott hozzáférést. Kérem, távolítsa el ezt a domaint böngészője vagy operációs rendszere értesítési tiltólistájáról. +chatroom#:#osc_enable_browser_notifications_info#:#Értesítést kap a böngészőjében az új beszélgetésekről és üzenetekről amikor az ILIAS másik böngészőlapon vagy a háttérben van, illetve az előtérben %s percnyi tétlenségi idő után is. chatroom#:#osc_enable_browser_notifications_label#:#Böngésző-értesítések chatroom#:#osc_noti_title#:#Új üzenet chatroom#:#period#:#Időszak chatroom#:#permissions#:#Jogosultságok -chatroom#:#preferred_chatname#:#Preferred Name###29 07 2022 new variable +chatroom#:#preferred_chatname#:#Preferált név chatroom#:#public_chat_created#:#A nyilvános csevegést sikeresen létrehozta a Tartalomtárban. -chatroom#:#scope#:#Szoba/privát szoba +chatroom#:#scope#:#Szoba chatroom#:#select_custom_username#:#Egyéni felhasználónév kiválasztása -chatroom#:#server_further_information#:#További információkat a szerver-konfigurációról a readme file-ban talál. -chatroom#:#server_readme_file_btn_label#:#Readme File###29 10 2025 new variable +chatroom#:#server_further_information#:#További információkat a szerver-konfigurációról a Readme fájlban talál. +chatroom#:#server_readme_file_btn_label#:#Readme fájl chatroom#:#session#:#Munkamenet chatroom#:#settings_general#:#Általános chatroom#:#settings_title#:#Beállítások -chatroom#:#start_private_chat#:#Start Private Chat###28 10 2024 new variable +chatroom#:#start_private_chat#:#Privát csevegés indítása chatroom#:#unable_to_connect#:#A csevegőszerverhez kapcsolódás nem lehetséges. chatroom#:#unban#:#Kitiltás feloldása -chatroom#:#user_banned#:#The user #user# has been banned.###28 10 2024 new variable +chatroom#:#user_banned#:# #user# felhasználót kitiltotta chatroom#:#user_in_ilias#:#Felhasználó keresése és meghívása az ILIAS-ból chatroom#:#user_in_room#:#Felhasználó meghívása ebből a csevegőszobából chatroom#:#user_invited#:#A felhasználót meghívta. @@ -3050,14 +3081,14 @@ chatroom#:#user_invited_self#:##user# meghívta Önt a(z) #room# c chatroom#:#user_kicked#:#A(z) #user# felhasználót kirúgta. chatroom#:#users#:#Felhasználók chatroom#:#welcome_to_chat#:#Üdvözöljük a csevegőszobában -chatroom#:#write_message#:#New Message###26 08 2024 new variable +chatroom#:#write_message#:#Új üzenet chatroom_adm#:#chat_cannot_connect_to_server#:#Az ILIAS nem tud socket kapcsolatot felépíteni a csevegőszerverhez. chatroom_adm#:#chat_enabled#:#Csevegés engedélyezése chatroom_adm#:#chatserver_settings_title#:#Csevegőszerver beállításai chatroom_adm#:#client_settings#:#Általános beállítások chatroom_adm#:#general_settings_title#:#Általános csevegésbeállítások chatroom_adm#:#https#:#HTTPS -chatroom_adm#:#osc_adm_browser_noti_info#:#Ha be van kapcsolva, a felhasználók maguk eldönthetik, hogy kérnek-e értesítést böngészőjükben az új beszélgetésekről és üzenetekről. Az értesítések aktiválódnak amikor az ILIAS másik böngészőfülön vagy a háttérben van, illetve az előtérben egy bizonyos tételenségi idő után is. +chatroom_adm#:#osc_adm_browser_noti_info#:#A felhasználók maguk eldönthetik, hogy kérnek-e értesítést böngészőjükben az új beszélgetésekről és üzenetekről. Az értesítések aktiválódnak amikor az ILIAS másik böngészőlapon vagy a háttérben van, illetve az előtérben egy bizonyos tételenségi idő után is. chatroom_adm#:#osc_adm_browser_noti_label#:#Böngésző-értesítések chatroom_adm#:#osc_adm_conv_idle_state_threshold_info#:#Az értesítés számának csökkentése egy minimális időköz megadásával, mely időzíti a bejövő üzenetek böngésző-értesítéseit. chatroom_adm#:#osc_adm_conv_idle_state_threshold_label#:#Böngész-értesítési időköz @@ -3073,32 +3104,32 @@ classification#:#clsfct_block_title#:#Címkefelhő classification#:#clsfct_content_no_match#:#Nincs találat classification#:#clsfct_content_title#:#Címke alapján szűrt tartalom classification#:#clsfct_selected_objects#:#Kiválasztott objektumok -cmix#:#achieved_info#:#Successfully bring about or reach a desired objective, level, or result by effort, skill, or courage. -cmix#:#achieved_label#:#Statements with the verb 'achieved' +cmix#:#achieved_info#:#Erőfeszítéssel, ügyességgel vagy bátorsággal sikeresen elérni vagy elérni a kívánt célt, szintet, vagy eredményt. +cmix#:#achieved_label#:#Nyilatkozatok az ‘elért’ állapottal cmix#:#activity_id#:#Aktivitás-ID cmix#:#activity_id_info#:#Ezt az ID-t elsősorban az LRS-ből származó adatok megjelenítésére használjuk. Ezt az ID-t az erőforrás-szolgáltatótól kapja meg. -cmix#:#answered_info#:#Indicates the actor replied to a question, where the object is generally an activity representing the question. The text of the answer will often be included in the response inside result. -cmix#:#answered_label#:#Statements with the verb 'answered' -cmix#:#btn_change_registration#:#Submit +cmix#:#answered_info#:#A kérdésre válaszolt szereplőt jelöli, ahol a tárgy általában a kérdést reprezentáló tevékenység. A válasz szövege gyakran szerepel a válaszon belüli eredményben. +cmix#:#answered_label#:#Nyilatkozatok az ‘megválaszolt’ állapottal +cmix#:#btn_change_registration#:#Mehet cmix#:#btn_create_lrs_type#:#LRS-típus hozzáadása -cmix#:#btn_create_registration#:#Submit -cmix#:#change_registration#:#E-Mail address for Registration -cmix#:#cmix_add#:#xAPI/cmi5 objektum hozzáadása +cmix#:#btn_create_registration#:#Mehet +cmix#:#change_registration#:#E-mail cím a regisztrációhoz +cmix#:#cmix_add#:#xAPI/cmi5-objektum hozzáadása cmix#:#cmix_add_cmi5_lm#:#cmi5-tananyag -cmix#:#cmix_add_cmi5_lm_info#:#This option should be used when the content is a cmi5 compliant learning module. Related features like suitable reportings are available without further configurations. +cmix#:#cmix_add_cmi5_lm_info#:#Ezt a lehetőséget akkor kell használni, ha a tartalom egy cmi5-kompatibilis tanulási modul. A kapcsolódó szolgáltatások, mint például a megfelelő jelentések, további konfiguráció nélkül is elérhetők. cmix#:#cmix_add_lrs_type#:#LRS-típus cmix#:#cmix_add_source#:#Forrás -cmix#:#cmix_add_source_external_app#:#Resource not launched by ILIAS -cmix#:#cmix_add_source_external_app_info#:#Use this option for separately launched resources as e.g. apps or simulations. Users must agree to the fetching of data. -cmix#:#cmix_add_source_local_dir#:#Local Directory -cmix#:#cmix_add_source_local_dir_info#:#Use this option for content packages on your local device. -cmix#:#cmix_add_source_upload_dir#:#Upload Directory -cmix#:#cmix_add_source_upload_dir_info#:#Use this option for content packages already uploaded into the ILIAS upload directory which is also used for SCORM and HTML packages. -cmix#:#cmix_add_source_upload_select#:#--- Please select --- -cmix#:#cmix_add_source_url#:#Resource URL -cmix#:#cmix_add_source_url_info#:#Use this option for an external resource. -cmix#:#cmix_add_xapi_standard_object#:#xAPI Standard Object -cmix#:#cmix_add_xapi_standard_object_info#:#Use this option to have a generic content module offering all features like different reportings. This option comes with the greatest possible flexibility but requires a more complex configuration. +cmix#:#cmix_add_source_external_app#:#Az erőforrást nem az ILIAS indítja +cmix#:#cmix_add_source_external_app_info#:#Használja ezt a lehetőséget a külön elindított erőforrásokhoz, mint például alkalmazások vagy szimulációk. A felhasználóknak el kell fogadniuk az adatok lekérését. +cmix#:#cmix_add_source_local_dir#:#Helyi mappa +cmix#:#cmix_add_source_local_dir_info#:#Használja ezt a lehetőséget a helyi eszközön lévő tartalomcsomagokhoz. +cmix#:#cmix_add_source_upload_dir#:#Feltöltési mappa +cmix#:#cmix_add_source_upload_dir_info#:#Használja ezt az opciót az ILIAS feltöltési mappába már feltöltött tartalomcsomagokhoz, amelyet a SCORM- és HTML-csomagok is használnak. +cmix#:#cmix_add_source_upload_select#:#--- Válasszon --- +cmix#:#cmix_add_source_url#:#Erőforrás URL +cmix#:#cmix_add_source_url_info#:#Használja ezt a lehetőséget külső erőforráshoz. +cmix#:#cmix_add_xapi_standard_object#:#xAPI Standard Objektum +cmix#:#cmix_add_xapi_standard_object_info#:#Használja ezt a lehetőséget, ha egy általános tartalommodult szeretne kapni, amely minden funkciót, például különböző jelentéseket kínál. Ez az opció a lehető legnagyobb rugalmasságot biztosítja, de bonyolultabb konfigurációt igényel. cmix#:#cmix_adlnetgov_expapi_verbs_answered#:#Megválaszolt cmix#:#cmix_adlnetgov_expapi_verbs_asked#:#Megkérdezett cmix#:#cmix_adlnetgov_expapi_verbs_attempted#:#Megpróbált @@ -3125,104 +3156,104 @@ cmix#:#cmix_adlnetgov_expapi_verbs_suspended#:#Felfüggesztett cmix#:#cmix_adlnetgov_expapi_verbs_terminated#:#Lezárt cmix#:#cmix_adlnetgov_expapi_verbs_voided#:#Ürített cmix#:#cmix_all_verbs#:#Az összes ige -cmix#:#cmix_copy#:#Copy xAPI/cmi5 objektum -cmix#:#cmix_import#:#Import xAPI/cmi5 objektum -cmix#:#cmix_indication_to_user#:#Further Hints for this LRS -cmix#:#cmix_info_external_lrs_info#:#This Learning Record Store is an external LRS. An external LRS is characterized by insufficient influence on the LRS by the operator of the ILIAS-Installation. This is the case e.g. if there are no rights to delete data. -cmix#:#cmix_info_external_lrs_label#:#Additional Info about this LRS -cmix#:#cmix_info_privacy_section#:#Info about personal data -cmix#:#cmix_info_privacy_section_launch#:#Info about personal data transmitted at launch -cmix#:#cmix_lrs_type#:#Learning Record Store (LRS) -cmix#:#cmix_new#:#Új xAPI/cmi5 objektum -cmix#:#completed_info#:#Indicates the actor finished or concluded the activity normally. -cmix#:#completed_label#:#Statements with the verb 'completed' +cmix#:#cmix_copy#:#Copy xAPI/cmi5-objektum +cmix#:#cmix_import#:#Import xAPI/cmi5-objektum +cmix#:#cmix_indication_to_user#:#További tippek ehhez az LRS-hez +cmix#:#cmix_info_external_lrs_info#:#Ez a Tanulási Bejegyzések Tárolója (LRS) egy külső LRS. A külső LRS-t az jellemzi, hogy az ILIAS-telepítés üzemeltetője nem tud kellőképpen befolyást gyakorolni az LRS-re. Ilyen esetben például nincs jogosultsága adatok törléséhez. +cmix#:#cmix_info_external_lrs_label#:#További információ erről az LRS-ről +cmix#:#cmix_info_privacy_section#:#Információ a személyes adatokról +cmix#:#cmix_info_privacy_section_launch#:#A személyes adatokról az információ indításkor továbbítódik +cmix#:#cmix_lrs_type#:#Tanulási Bejegyzések Tárolója (LRS) +cmix#:#cmix_new#:#Új xAPI/cmi5-objektum +cmix#:#completed_info#:#Azt jelzi, hogy a művelet normálisan befejeztődött. +cmix#:#completed_label#:#Nyilatkozatok a ‘befejezte’ állapottal cmix#:#conf_availability#:#Elérhetőség cmix#:#conf_availability_0#:#Nem érhető el -cmix#:#conf_availability_0_info#:#Existing xAPI/cmi5 objects that use this LRS type can no longer be used.###28 10 2024 new variable +cmix#:#conf_availability_0_info#:#Az ezt az LRS-típust használó xAPI/cmi5 objektumok már nem használhatók. cmix#:#conf_availability_1#:#A már létezők engedélyezettek -cmix#:#conf_availability_1_info#:#This LRS type is not offered when creating new xAPI/cmi5 objects. Existing xAPI/cmi5 objects that use this type can continue to write or read data. Use this option to be able to delete data in the connected LRS at a later time.###28 10 2024 new variable +cmix#:#conf_availability_1_info#:#Ez az LRS-típust nem kínáljuk fel új xAPI/cmi5 objektumok létrehozásakor. Az ezt a típust használó, már meglévő xAPI/cmi5 objektumok folytathatják az adatok írását vagy olvasását. Használja ezt az opciót, ha később törölheti az adatokat a csatlakoztatott LRS-ből. cmix#:#conf_availability_2#:#Új létrehozható -cmix#:#conf_availability_2_info#:#This LRS type can be selected when creating xAPI/cmi5 objects.###28 10 2024 new variable +cmix#:#conf_availability_2_info#:#Ez az LRS típus választható xAPI/cmi5 objektumok létrehozásakor cmix#:#conf_bypass_proxy#:#Detection of Learning Progress -cmix#:#conf_bypass_proxy_disabled#:#xAPI-Proxy to get immediately data -cmix#:#conf_bypass_proxy_enabled#:#CronJob to check Learning Record Store -cmix#:#conf_bypass_proxy_info#:#In most cases it is recommended to use the xAPI-Proxy. Use the CronJob in case of Limitations regarding Resource or Server. -cmix#:#conf_cronjob_neccessary#:#CronJob necessary for Learning Progress -cmix#:#conf_cronjob_neccessary_info#:#By activating this option, xAPI-Objects using this LRS-típus could not use the xAPI-Proxy to get immediately data for Detection of Learning Progress. Use only the CronJob in case of limitations regarding resources or server. -cmix#:#conf_delete_data#:#Delete Data in LRS###28 10 2024 new variable -cmix#:#conf_delete_data_info#:#Deletion is currently only possible with the Learning Record Store (LRS) LearningLocker. Only use the options for deleting the user identification if the data has been pseudonymized in the LRS.###28 10 2024 new variable -cmix#:#conf_delete_data_opt0#:#Never###28 10 2024 new variable -cmix#:#conf_delete_data_opt1#:#Never - but if users are deleted and if xAPI/cmi objects are moved to the trash or deleted, data will no longer be assignable for ILIAS by deleting the - user identification###28 10 2024 new variable -cmix#:#conf_delete_data_opt11#:#When users are deleted and when xAPI/cmi objects are moved to the trash or deleted###28 10 2024 new variable -cmix#:#conf_delete_data_opt12#:#Additionally when users are removed from courses or groups###28 10 2024 new variable -cmix#:#conf_delete_data_opt2#:#Never - but additionally when users are removed from courses or groups, data will no longer be assignable for ILIAS by deleting the user identification###28 10 2024 new variable +cmix#:#conf_bypass_proxy_disabled#:#xAPI-Proxy az azonnali adat érdekében +cmix#:#conf_bypass_proxy_enabled#:#Ütemezett feladat a tanulás bejegyzések tárolójának ellenőrzéséhez +cmix#:#conf_bypass_proxy_info#:#A legtöbb esetben az xAPI-Proxy használata javasolt. Használjon Ütemezett feladatot erőforrás vagy szerver korlátozottságakor. +cmix#:#conf_cronjob_neccessary#:#Ütemezett feladat szükséges a Tanulási haadáshoz +cmix#:#conf_cronjob_neccessary_info#:#Ennek az opciónak a bekapcsolásával az ezt az LRS-típust használó xAPI-objektumok nem tudják használni az xAPI-proxyt, hogy azonnali adatokat kapjon a tanulási haladás észleléséhez. Csak az ütemezett feladatot használja, ha az erőforrásokkal vagy a szerverrel kapcsolatos korlátozások vannak életben. +cmix#:#conf_delete_data#:#Adat törlése LRS-ben +cmix#:#conf_delete_data_info#:#A törlés jelenleg csak a Learning Record Store (LRS) LearningLocker segítségével lehetséges. Csak akkor használja a felhasználói azonosítás törlésének lehetőségeit, ha az adatot pszeudoanonimizálta az LRS-ben. +cmix#:#conf_delete_data_opt0#:#Soha +cmix#:#conf_delete_data_opt1#:#Soha - de ha a felhasználókat törlik, és ha az xAPI/cmi objektumokat a kukába helyezik vagy törlik, akkor az adatok a továbbiakban nem lesznek hozzárendelhetők az ILIAS-hoz a felhasználói azonosító törlésével +cmix#:#conf_delete_data_opt11#:#Amikor a felhasználókat törlik, és amikor az xAPI/cmi objektumokat a kukába helyezik vagy törlik +cmix#:#conf_delete_data_opt12#:#Továbbá, amikor a felhasználókat eltávolítják a kurzusokból vagy csoportokból +cmix#:#conf_delete_data_opt2#:#Soha - de emellett, ha a felhasználókat eltávolítják a kurzusokból vagy csoportokból, az adatok többé nem rendelhetők hozzá az ILIAS-hoz a felhasználói azonosító törlésével cmix#:#conf_description#:#Leírás cmix#:#conf_external_lrs#:#Külső LRS cmix#:#conf_keep_lp#:#A tanulási folyamat megtartása -cmix#:#conf_keep_lp_info#:#Az ILIAS tanulási folyamatának 'Teljesítve' állapotát befagyasztjuk. +cmix#:#conf_keep_lp_info#:#Az ILIAS tanulási folyamatának ‘Teljesítve’ állapotát befagyasztjuk. cmix#:#conf_launch_mode#:#Indítási mód cmix#:#conf_launch_mode_browse#:#Böngészés -cmix#:#conf_launch_mode_browse_info#:#This option should provide a user experience that allows the user to "look around" without judgement.###26 08 2024 new variable +cmix#:#conf_launch_mode_browse_info#:#Ennek az opciónak olyan felhasználói élményt kell biztosítania, amely lehetővé teszi a felhasználó számára, hogy ítélkezés nélkül ‘körülnézzen’. cmix#:#conf_launch_mode_normal#:#Normál -cmix#:#conf_launch_mode_normal_info#:#Data related to the learning progress should be recorded.###26 08 2024 new variable +cmix#:#conf_launch_mode_normal_info#:#A tanulási előrehaladással kapcsolatos adatok rögzítése. cmix#:#conf_launch_mode_review#:#Felülvizsgálat -cmix#:#conf_launch_mode_review_info#:#This option should provide a user experience that allows the user to "revisit / review" already completed material.###26 08 2024 new variable +cmix#:#conf_launch_mode_review_info#:#Ennek az opciónak olyan felhasználói élményt kell biztosítania, amely lehetővé teszi a felhasználó számára, hogy ‘újra megtekintés/felülviszgálat” lehetőséget a már teljesített tananyagon. cmix#:#conf_lrs_endpoint#:#Zárópont cmix#:#conf_lrs_key#:#Kulcs / Bejelentkezés cmix#:#conf_lrs_secret#:#Titok / Jelszó -cmix#:#conf_new_window#:#New Window###29 07 2022 new variable -cmix#:#conf_new_window_info#:#The content is opened in a new window. When leaving the content this window gets closed.###29 07 2022 new variable +cmix#:#conf_new_window#:#Új ablak +cmix#:#conf_new_window_info#:#A tartalom új ablakban nyílik meg. A tartalom elhagyásakor ez az ablak bezárul. cmix#:#conf_own_window#:#Egy ablak cmix#:#conf_own_window_info#:#A tartalom ugyanabban az ablakban nyílik meg, lecserélve az ILIAS képernyőjét. A tartalom elhagyásakor a felhasználó visszatér az ILIAS-ba. cmix#:#conf_privacy_comment_default#:#Jelzés a felhasználó felé -cmix#:#conf_privacy_ident#:#User identification###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_ext_account#:#External User ID combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_ext_account_info#:#This is identical to each call, but may allow a direct conclusion about the user.###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_login#:#ILIAS Login combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_login_info#:#Sends the login name. This is identical to each call, but may allow a direct conclusion about the ILIAS user.###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_random#:#Random ID combined with a unique ILIAS platform ID formatted as an E-Mail address###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_random_info#:#For each ILIAS object and ILIAS user a random ID is generated which remains identical for each call. Conclusions about a user are very limited because it is practically impossible to create user profiles across objects.###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_sha256#:#Hash combined with a unique ILIAS platform id formatted as an E-Mail address###28 10 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_sha256_info#:#This is identical to each call, but does not permit any direct conclusions about the ILIAS user.###28 10 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_sha256url#:#Hash combined with the ILIAS Domain formatted as an E-Mail address###28 10 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_sha256url_info#:#This is identical to each call, with with a maximum of 80 characters significantly shorter than the variant with the ILIAS platform ID and allows only very limited conclusions about the ILIAS user.###28 10 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_user_id#:#ILIAS user id combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -cmix#:#conf_privacy_ident_il_uuid_user_id_info#:#Sends the internal numeric user id. This is identical to each call, but may allow conclusions about the ILIAS user.###26 08 2024 new variable -cmix#:#conf_privacy_ident_info#:#Standard is frequently the E-Mail address. The unique ILIAS platform id is:###26 08 2024 new variable -cmix#:#conf_privacy_ident_real_email#:#E-Mail Address###26 08 2024 new variable -cmix#:#conf_privacy_ident_real_email_info#:#Sends E-Mail Address of user as identification (Warning: an E-Mail Address might be used by multiple users!)###26 08 2024 new variable -cmix#:#conf_privacy_name#:#User name###26 08 2024 new variable -cmix#:#conf_privacy_name_firstname#:#First name###26 08 2024 new variable -cmix#:#conf_privacy_name_firstname_info#:#Sends the first name of the user name from ILIAS###26 08 2024 new variable -cmix#:#conf_privacy_name_fullname#:#Entire name###26 08 2024 new variable -cmix#:#conf_privacy_name_fullname_info#:#Sends title, first name and last name###26 08 2024 new variable -cmix#:#conf_privacy_name_info#:#Sending an user name is usually not required.###26 08 2024 new variable -cmix#:#conf_privacy_name_lastname#:#Title and last name###26 08 2024 new variable -cmix#:#conf_privacy_name_lastname_info#:#Sends Mister or Ms/Mrs. (unless otherwise specified) and the last name###26 08 2024 new variable -cmix#:#conf_privacy_name_none#:#No one###26 08 2024 new variable -cmix#:#conf_privacy_name_none_info#:#Sends '-' instead of a name###26 08 2024 new variable +cmix#:#conf_privacy_ident#:#Felhasználó azonosítása +cmix#:#conf_privacy_ident_il_uuid_ext_account#:#A külső user_id és az egyedi ILIAS platform_id e-mail cím formátumban. +cmix#:#conf_privacy_ident_il_uuid_ext_account_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged a felhasználóra. +cmix#:#conf_privacy_ident_il_uuid_login#:#Az ILIAS felhasználónév és ha szükséges az egyedi ILIAS platform_id e-mail címként. +cmix#:#conf_privacy_ident_il_uuid_login_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged az ILIAS felhasználóra. +cmix#:#conf_privacy_ident_il_uuid_random#:#Véletlen ID és az egyedi ILIAS platform_id e-mail cím formátumban. +cmix#:#conf_privacy_ident_il_uuid_random_info#:#Az összes ILIAS objektum és az összes ILIAS felhasználó számára egy véletlen azonosítót generálunk minden híváskor, így a felhasználóval kapcsolatos következtetések nagyon korlátozottak lesznek, mert gyakorlatilag lehetetlen objektumokra hivatkozó felhasználói profilokat létrehozni. +cmix#:#conf_privacy_ident_il_uuid_sha256#:#Hash és az egyedi ILIAS platform_id e-mail cím formátumban. +cmix#:#conf_privacy_ident_il_uuid_sha256_info#:#Ez azonosítja az összes hívást, de nem lehet belőle következtetni felhasználóra. +cmix#:#conf_privacy_ident_il_uuid_sha256url#:#Hash és az egyedi ILIAS domainnel e-mail cím formátumban. +cmix#:#conf_privacy_ident_il_uuid_sha256url_info#:#Ez azonosítja az összes hívást, legfeljebb 80 karakterrel lényegesen rövidebb, mint az ILIAS platformazonosítójú változat, és csak nagyon korlátozott következtetéseket tesz lehetővé a felhasználóról. +cmix#:#conf_privacy_ident_il_uuid_user_id#:#Az ILIAS user_id és az egyedi ILIAS platform_id e-mail cím formátumban. +cmix#:#conf_privacy_ident_il_uuid_user_id_info#:#Ez azonosítja az összes hívást, de nem enged következtetni az ILIAS felhasználóra. +cmix#:#conf_privacy_ident_info#:#A leggyakrabban használat az e-mail cím. Az egyedi ILIAS platform_id: +cmix#:#conf_privacy_ident_real_email#:#E-mail cím +cmix#:#conf_privacy_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelem: egy e-mail címet több felhasználó is használhat!) +cmix#:#conf_privacy_name#:#Felhasználó neve +cmix#:#conf_privacy_name_firstname#:#Utónév +cmix#:#conf_privacy_name_firstname_info#:#A felhasználó utónevét küldjük +cmix#:#conf_privacy_name_fullname#:#Teljes név +cmix#:#conf_privacy_name_fullname_info#:#A titulust, a családi és az utónevet is küldjük +cmix#:#conf_privacy_name_info#:#A felhasználó névének küldése általában nem szükséges. +cmix#:#conf_privacy_name_lastname#:#Titulus és családnév +cmix#:#conf_privacy_name_lastname_info#:#Asszony vagy Úr megszólítást (eltérő rendelkezés hiányában) és a családnevet küldjük +cmix#:#conf_privacy_name_none#:#Semmi +cmix#:#conf_privacy_name_none_info#:#‘-’-et küldjük a név helyett cmix#:#conf_privacy_setting_conf#:#Beállítási lehetőségek cmix#:#conf_privacy_setting_default#:#Alapértelmezett beállítások, módosíthatók az objektumoknál cmix#:#conf_privacy_setting_force#:#Az objektumok beállításai nem módosíthatók cmix#:#conf_privacy_setting_info#:#Konfigurációs beállítások az adatvédelmi beállításokhoz cmix#:#conf_remarks#:#Belső észrevételek cmix#:#conf_title#:#Cím -cmix#:#conf_use_proxy#:#xAPI-Proxy###28 10 2024 new variable -cmix#:#conf_use_proxy_info#:#The xAPI proxy provides real-time data to determine learning progress in ILIAS. The proxy reduces personal data in accordance with the selected data protection options. If the xAPI proxy is deactivated, the learning content writes the learning progress directly to the LRS. This data must then also be retrieved directly from the LRS. The cron job "xAPI/cmi5 get results" is required to determine the learning progress. The xAPI proxy is mandatory for cmi5 objects and is activated automatically.###28 10 2024 new variable -cmix#:#conf_use_proxy_info_cmi5#:#The xAPI proxy provides real-time data to determine learning progress in ILIAS. The proxy reduces personal data in accordance with the selected data protection options. The xAPI proxy is mandatory for cmi5 objects.###28 10 2024 new variable -cmix#:#conf_use_proxy_info_xapi#:#The xAPI proxy provides real-time data to determine learning progress in ILIAS. The proxy reduces personal data in accordance with the selected data protection options. If the xAPI proxy is deactivated, the learning content writes the learning progress directly to the LRS. This data must then also be retrieved directly from the LRS. The cron job "xAPI/cmi5 get results" is required to determine the learning progress.###28 10 2024 new variable +cmix#:#conf_use_proxy#:#xAPI-proxy +cmix#:#conf_use_proxy_info#:#Az xAPI-proxy valós idejű adatokat biztosít az ILIAS tanulási folyamatának meghatározásához. A proxy a kiválasztott adatvédelmi beállításoknak megfelelően csökkenti a személyes adatokat. Ha az xAPI-proxyt kikapcsolja, a tanulási tartalom közvetlenül az LRS-be írja a tanulási folyamatot. Ezután ezeket az adatokat is közvetlenül az LRS-ből kell lekérni. Az ‘xAPI/cmi5 eredményei’ ütemezett folyamat szükséges a tanulási folyamat meghatározásához. Az xAPI-proxy szükséges a cmi5 objekumokhoz, és automatikusan be legyen kapcsolva. +cmix#:#conf_use_proxy_info_cmi5#:#Az xAPI-proxy valós idejű adatokat biztosít az ILIAS tanulási folyamatának meghatározásához. A proxy a kiválasztott adatvédelmi beállításoknak megfelelően csökkenti a személyes adatokat. Az xAPI-proxy kötelező a cmi5 objektumoknál. +cmix#:#conf_use_proxy_info_xapi#:#Az xAPI-proxy valós idejű adatokat biztosít az ILIAS tanulási folyamatának meghatározásához. A proxy a kiválasztott adatvédelmi beállításoknak megfelelően csökkenti a személyes adatokat. Ha az xAPI-proxyt kikapcsolja, a tanulási tartalom közvetlenül az LRS-be írja a tanulási folyamatot. Ezután ezeket az adatokat is közvetlenül az LRS-ből kell lekérni. Az ‘xAPI/cmi5 eredményei’ ütemezett folyamat szükséges a tanulási folyamat meghatározásához. cmix#:#conf_user_ident#:#Felhasználó azonosítása -cmix#:#conf_user_ident_il_uuid_ext_account#:#A külső user id és az egyedi ILIAS platform id e-mail cím formátumban. +cmix#:#conf_user_ident_il_uuid_ext_account#:#Külső user_id kombinálva az egyedi ILIAS-telepítés azonosítóval e-mail formátumban cmix#:#conf_user_ident_il_uuid_ext_account_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged a felhasználóra. -cmix#:#conf_user_ident_il_uuid_login#:#Az ILIAS felhasználónév és az egyedi ILIAS platform id e-mail cím formátumban. +cmix#:#conf_user_ident_il_uuid_login#:#Az ILIAS felhasználónév és ha szükséges az egyedi ILIAS platform_id e-mail címként. cmix#:#conf_user_ident_il_uuid_login_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged az ILIAS felhasználóra. -cmix#:#conf_user_ident_il_uuid_random#:#Véletlen id és az egyedi ILIAS platform id e-mail cím formátumban. +cmix#:#conf_user_ident_il_uuid_random#:#Véletlen id és az egyedi ILIAS platform_id e-mail cím formátumban. cmix#:#conf_user_ident_il_uuid_random_info#:#Az összes ILIAS objektum és az összes ILIAS felhasználó számára egy véletlen azonosítót generálunk minden híváskor, így a felhasználóval kapcsolatos következtetések nagyon korlátozottak lesznek, mert gyakorlatilag lehetetlen objektumokra hivatkozó felhasználói profilokat létrehozni. -cmix#:#conf_user_ident_il_uuid_user_id#:#Az ILIAS user id és az egyedi ILIAS platform id e-mail cím formátumban. +cmix#:#conf_user_ident_il_uuid_user_id#:#Az ILIAS user_id és az egyedi ILIAS platform_id e-mail cím formátumban. cmix#:#conf_user_ident_il_uuid_user_id_info#:#Ez azonosítja az összes hívást, de nem enged következtetni az ILIAS felhasználóra. -cmix#:#conf_user_ident_info#:#A leggyakrabban használat az e-mail cím. Az egyedi ILIAS platform id: -cmix#:#conf_user_ident_real_email#:#E-mail cím -cmix#:#conf_user_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelem: egy e-mail címet több felhasználó is használhat!) +cmix#:#conf_user_ident_info#:#A standard gyakran az e-mail cím. Az egyedi ILIAS platformazonosítója: +cmix#:#conf_user_ident_real_email#:#E-mail címek +cmix#:#conf_user_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelmezetés: egy e-mail címet több felhasználó is használhat!) cmix#:#conf_user_name#:#Felhasználó neve cmix#:#conf_user_name_firstname#:#Utónév cmix#:#conf_user_name_firstname_info#:#A felhasználó utónevét küldjük @@ -3232,35 +3263,35 @@ cmix#:#conf_user_name_info#:#A felhasználó névének küldése általában nem cmix#:#conf_user_name_lastname#:#Titulus és családnév cmix#:#conf_user_name_lastname_info#:#Asszony vagy Úr megszólítást (eltérő rendelkezés hiányában) és a családnevet küldjük cmix#:#conf_user_name_none#:#Semmi -cmix#:#conf_user_name_none_info#:#'-'-et küldjük a név helyett -cmix#:#conf_user_registered_mail#:#Registered E-Mail-Address +cmix#:#conf_user_name_none_info#:#‘-’ a név helyett +cmix#:#conf_user_registered_mail#:#Regisztrált e-mail cím cmix#:#content_privacy_ident#:#A felhasználó azonosítása az erőforráshoz cmix#:#content_privacy_name#:#A felhasználó neve az erőforráshoz cmix#:#create_lrs_type_form#:#Új LRS-típus -cmix#:#create_registration#:#Register your E-Mail address -cmix#:#cron_xapi_del#:#Delete xAPI/cmi5 data in the Learning Record Store###29 10 2025 new variable -cmix#:#cron_xapi_del_desc#:#Data is deleted according to the settings of the xAPI/cmi5 objects.###29 10 2025 new variable -cmix#:#cron_xapi_results_evaluation#:#Fetch xAPI/cmi5 Results -cmix#:#cron_xapi_results_evaluation_desc#:#Requests all xAPI results from learning record stores for objects not supporting the ILIAS xAPI proxy. +cmix#:#create_registration#:#E-mail cím regisztrálása +cmix#:#cron_xapi_del#:#xAPI/cmi5 adat törlése az LRS-ben +cmix#:#cron_xapi_del_desc#:#Az xAPI/cmi5 objektum beállításainak megfelelően töröltük az adatot. +cmix#:#cron_xapi_results_evaluation#:#xAPI/cmi5 eredmények használata +cmix#:#cron_xapi_results_evaluation_desc#:#Az összes xAPI eredmény lekérése az ILIAS xAPI proxyt nem támogató objektumok esetén. cmix#:#description_info#:#A leírás a cím alatt jelenik meg. cmix#:#download_certificate#:#Tanúsítvány letöltése -cmix#:#duration_info#:#The duration can be entered e.g. for answering a task. The duration is set to the default value 0 seconds (PT00.000S) by this option. -cmix#:#duration_label#:#Duration +cmix#:#duration_info#:#Az időtartam beírható például feladat megválaszolásához. Ezzel az opcióval az időtartam az alapértelmezett értéke 0 másodperc (PT00.000S). +cmix#:#duration_label#:#Időtartam cmix#:#edit_lrs_type_form#:#LRS-típus -cmix#:#failed_info#:#Indicates the actor did not successfully pass an activity to a level of predetermined satisfaction. -cmix#:#failed_label#:#Statements with the verb 'failed' -cmix#:#fetch_xapi_statements#:#Fetch results from Learning Record Store +cmix#:#failed_info#:#Azt jelzi, hogy a színész nem teljesített sikeresen egy tevékenységet az előre meghatározott elégedettség szintjére. +cmix#:#failed_label#:#Nyilatkozatok a ‘nem teljesítette’ állapottal +cmix#:#fetch_xapi_statements#:#Eredmények használata az LRS-ből cmix#:#field_user_ident#:#E-mail cím -cmix#:#field_user_ident_info#:#Enter the e-mail address used in the external application to identify you. +cmix#:#field_user_ident_info#:#Adja meg az e-mail címét a külső applikációban történő azonosításához. cmix#:#form_change_registration#:#Registration cmix#:#form_create_registration#:#Regisztráció -cmix#:#hide_data_info#:#With this option which is only available for the ILIAS LRS proxy certain data is stored in statements with unrecognizable values in the Learning Record Store. -cmix#:#hide_data_label#:#Blacken data +cmix#:#hide_data_info#:#Ezzel az opcióval, amely csak az ILIAS LRS proxy számára érhető el, bizonyos adatok felismerhetetlen értékű kimutatásokban kerülnek tárolásra a LRS-ben. +cmix#:#hide_data_label#:#Blokkolt adat cmix#:#highscore_achieved_ts#:#Dátum cmix#:#highscore_achieved_ts_description#:#A dátumot tartalmazó oszlop legyen benne a rangsorban. cmix#:#highscore_all_tables#:#A résztvevő saját helyezése és a rangsor cmix#:#highscore_all_tables_description#:#A résztvevők információt kapnak a rangsorról és a benne elfogalt helyükről. -cmix#:#highscore_description#:#A többi felhasználó neve jelenjen meg, ha az 'A többi felhasználó tanulási tapasztalatának megtekintése' jogosultság be van állítva. +cmix#:#highscore_description#:#A többi felhasználó neve jelenjen meg, ha az ‘A többi felhasználó tanulási tapasztalatának megtekintése’ jogosultság be van állítva. cmix#:#highscore_enabled#:#Rangsor cmix#:#highscore_mode#:#Mód cmix#:#highscore_own_table#:#Résztvevő saját helyezése @@ -3276,40 +3307,40 @@ cmix#:#highscore_top_table#:#Rangsor cmix#:#highscore_top_table_description#:#A résztvevők a rangsorban elfoglalt helyükkel jelennek meg a táblázatban. cmix#:#highscore_wtime#:#Időtartam cmix#:#highscore_wtime_description#:#Az időtartamot tartalmazó oszolop legyen benne a rangsorban. -cmix#:#info_availability#:#Itt állítható a az LRS-típus elérhetősége a Tartalomtárban. Az összes típus a törlés helyett lehet 'A már létezők engedélyezettek'. +cmix#:#info_availability#:#Itt állítható a az LRS-típus elérhetősége a Tartalomtárban. Az összes típus a törlés helyett lehet ‘A már létezők engedélyezettek’. cmix#:#info_description#:#Ez a leírás jelenik meg új objektumok típusának kiválasztásakor. cmix#:#info_external_lrs#:#A tipp jelenik meg a felhasználónak, amikor egy külső LRS-vel foglalkozik. A külső LRS-t az ILIAS-telepítés üzemeltetője által az LRS-re gyakorolt nem megfelelő befolyása jellemzi. Ez az eset áll fenn, ha nincs törlés joga. -cmix#:#info_lrs_endpoint#:#A zárópont URL-je '/' nélkül a végén +cmix#:#info_lrs_endpoint#:#A zárópont URL-je ‘/’ nélkül a végén cmix#:#info_lrs_key#:#Kulcs vagy bejelentkezés a hozzáféréshez, például 12345 cmix#:#info_lrs_secret#:#Megosztott titok / Jelszó, például titok cmix#:#info_privacy_comment_default#:#Kérjük, illesszen be szükség szerint további adatbiztonsági jelzést ezen LRS használatakor. cmix#:#info_remarks#:#Itt írhatja le észrevételeit erről az LRS típusról. cmix#:#info_title#:#Ez a cím jelenik meg új objektumok típusának kiválasztásakor. -cmix#:#initialized_info#:#Indicates the activity provider has determined that the actor successfully started an activity. -cmix#:#initialized_label#:#Statements with the verb 'initialized' +cmix#:#initialized_info#:#Azt jelzi, hogy a tevékenység szolgáltatója megállapította, hogy a szereplő sikeresen megkezdte a tevékenységet. +cmix#:#initialized_label#:#Nyilatkozatok az ‘initializált’ állapottal cmix#:#launch_options#:#Indítási lehetőségek cmix#:#launch_url#:#Az erőforrás URL-je cmix#:#launch_url_info#:#Írja ide az internet címet http:// vagy https:// az elején . Az adatbiztonsági lehetőségek a távoli erőforrásokra is relevánsak. cmix#:#log_options#:#Az átvitt adatok megjelenítési lehetőségei cmix#:#lrs_authentication#:#Hitelesítés -cmix#:#no_substatements_info#:#With this option - which is only available for the ILIAS LRS proxy - the storage of subordinate statements can be suppressed. This can for example affect the answering of single tasks in a test. The content is informed that the statements would have been saved. -cmix#:#no_substatements_label#:#Do not store substatements +cmix#:#no_substatements_info#:#Ezzel az opcióval - amely csak az ILIAS LRS proxyhoz érhető el - az alárendelt utasítások tárolása letiltható. Ez befolyásolhatja például a tesztben szereplő egyes feladatok megválaszolását. A tartalom tájékoztatást kap arról, hogy a nyilatkozatok mentésre kerültek volna. +cmix#:#no_substatements_label#:#Résznyilatkozatok letiltása cmix#:#online_info#:#Ez az objektumot láthatóvá és felhasználhatóvá teszi a felhasználók számára. -cmix#:#only_moveon_info#:#With this option, which is only available for the ILIAS LRS proxy, only statements with defined verbs are stored in the Learning Record Store (WhiteList). The content is informed that the statements would have been saved. This usually ensures the expiration date but should be discussed with the content provider. -cmix#:#only_moveon_label#:#Save learning success data only -cmix#:#passed_info#:#Indicates the actor successfully passed an activity to a level of predetermined satisfaction. -cmix#:#passed_label#:#Statements with the verb 'passed' +cmix#:#only_moveon_info#:#Ezzel az opcióval, amely csak az ILIAS LRS proxyhoz érhető el, csak a meghatározott igéket tartalmazó utasítások kerülnek tárolásra a tanulási rekordtárban (fehérlista). A tartalom tájékoztatást kap arról, hogy a nyilatkozatok mentésre kerültek volna. Ez általában biztosítja a lejárati dátumot, de meg kell beszélni a tartalomszolgáltatóval. +cmix#:#only_moveon_label#:#Csak a kiválasztott igéket tartalmazó állítások mentése +cmix#:#passed_info#:#Azt jelzi, hogy a művelet sikeresen teljesített egy tevékenységet az előre meghatározott elégedettség szintjére. +cmix#:#passed_label#:#Nyilatkozatok a ‘sikeresen teljesítette’ állapottal cmix#:#privacy_options#:#Adatbiztonsági beállítások -cmix#:#progressed_info#:#Indicates a value of how much of an actor has advanced or moved through an activity. -cmix#:#progressed_label#:#Statements with the verb 'progressed' -cmix#:#registration_saved_successfully#:#Registration saved successfully -cmix#:#satisfied_info#:#Indicates that the authority or activity provider determined the actor has fulfilled the criteria of the object or activity. -cmix#:#satisfied_label#:#Statements with the verb 'satisfied' +cmix#:#progressed_info#:#Azt az értéket jelzi, hogy egy művelet mennyit lépett előre vagy haladt egy tevékenységben. +cmix#:#progressed_label#:#Nyilatkozatok a ‘progressed’ állapottal +cmix#:#registration_saved_successfully#:#A regisztrációt sikeresen elmentette +cmix#:#satisfied_info#:#Azt jelzi, hogy a hatóság vagy tevékenység szolgáltatója megállapította, hogy a szereplő teljesítette az objektum vagy tevékenység kritériumait. +cmix#:#satisfied_label#:#Nyilatkozatok az ‘elégedett’ állapottal cmix#:#sect_learning_progress_options#:#Tanulási haladás lehetőségei cmix#:#show_debug#:#Tanulási tapasztalat megjelenítése -cmix#:#show_debug_info#:#A többi felhasználó tanulási tapasztalata megjelenik, ha az 'A többi felhasználó tanulási tapasztalatának megtekintése' jogosultság be van állítva. +cmix#:#show_debug_info#:#A többi felhasználó tanulási tapasztalata megjelenik, ha az ‘A többi felhasználó tanulási tapasztalatának megtekintése’ jogosultság be van állítva. cmix#:#tab_export#:#Export -cmix#:#tab_info#:#Info +cmix#:#tab_info#:#Infornáció cmix#:#tab_lrs_types#:#LRS-típus cmix#:#tab_scoring#:#Rangsor cmix#:#tab_settings#:#Beállítások @@ -3323,13 +3354,13 @@ cmix#:#tbl_statements_actor#:#Felhasználó cmix#:#tbl_statements_date#:#Dátum cmix#:#tbl_statements_object#:#Objektum cmix#:#tbl_statements_verb#:#Ige -cmix#:#terminated_info#:#Indicates that the actor successfully ended an activity. -cmix#:#terminated_label#:#Statements with the verb 'terminated' -cmix#:#timestamp_info#:#The timestamp marks the time of an action indicated by the statement. The timestamp is set to the default value 01.01.1970 (1970-01-01T00:00:00.000Z) by this option. Please note that a Learning Record Store may automatically set a value for the stored date, which can be almost identical to the timestamp. -cmix#:#timestamp_label#:#Timestamp +cmix#:#terminated_info#:#Azt jelzi, hogy a művelet sikeresen befejezte a tevékenységet. +cmix#:#terminated_label#:#Nyilatkozatok a ‘megszűnt’ állapottal +cmix#:#timestamp_info#:#Az időbélyeg az utasítás által jelzett művelet időpontját jelöli. Az időbélyeg alapértelmezett értéke 01.01.1970 (1970-01-01T00:00:00.000Z). Kérjük, vegye figyelembe, hogy a LRS automatikusan beállíthat egy értéket a tárolt dátumhoz, amely szinte azonos lehet az időbélyeggel. +cmix#:#timestamp_label#:#Időbélyeg cmix#:#title_info#:#Adja meg az objektum címét. -cmix#:#type_cmi5#:#cmi5 Learning Module###29 07 2022 new variable -cmix#:#type_generic#:#xAPI Standard Object###29 07 2022 new variable +cmix#:#type_cmi5#:#cmi5-tananyag +cmix#:#type_generic#:#xAPI Standard Objektum cmix#:#use_fetch#:#Fetch-URL-en keresztüli hitelesítés cmix#:#use_fetch_info#:#Mindaddig, amíg az erőforrás támogatja ezt a beállítást, célszerű használnia ezt az lehetőséget az adatbiztonság fokozására. cmix#:#xapi_statements_fetched_successfully#:#Results from Learning Record Store were fetched successfully @@ -3339,17 +3370,17 @@ cmps#:#cmps_activate#:#Aktiválás cmps#:#cmps_active#:#Aktív cmps#:#cmps_add_new_rank#:#Pozíció az Új objektum létrehozása listában cmps#:#cmps_available#:#Elérhető -cmps#:#cmps_available_version#:#Available Version###29 07 2022 new variable +cmps#:#cmps_available_version#:#Elérhető verzió cmps#:#cmps_basic_files#:#Alapfájlok cmps#:#cmps_class_file#:#Osztályfájl cmps#:#cmps_component#:#Komponens cmps#:#cmps_configure#:#Konfigurálás -cmps#:#cmps_current_db_version#:#Current DB-Version###29 07 2022 new variable +cmps#:#cmps_current_db_version#:#Jelenlegi adatbázis-verzió cmps#:#cmps_current_version#:#Jelenlegi verzió cmps#:#cmps_database#:#Adatbázis cmps#:#cmps_db_update#:#Adatbázis-frissítési szkript cmps#:#cmps_deactivate#:#Deaktiválás -cmps#:#cmps_detailed_information#:#Detailed Informationen###29 07 2022 new variable +cmps#:#cmps_detailed_information#:#Részletes információ cmps#:#cmps_dir#:#Mappa cmps#:#cmps_enable_creation#:#Létrehozás engedélyezése cmps#:#cmps_file_version#:#Frissítési fájlverzió @@ -3359,8 +3390,8 @@ cmps#:#cmps_ilias_max_version#:#Maximum ILIAS-verzió cmps#:#cmps_ilias_min_version#:#Minimum ILIAS-verzió cmps#:#cmps_inactive#:#Inaktív cmps#:#cmps_install#:#Telepítés -cmps#:#cmps_is_active#:#Activated###29 07 2022 new variable -cmps#:#cmps_is_installed#:#Installed###29 07 2022 new variable +cmps#:#cmps_is_active#:#Aktivált +cmps#:#cmps_is_installed#:#Telepített cmps#:#cmps_lang_files#:#Nyelvi fájlok cmps#:#cmps_lang_prefix#:#Nyelvi változó előtag cmps#:#cmps_languages#:#Nyelvek @@ -3369,7 +3400,7 @@ cmps#:#cmps_missing#:#Hiányzik cmps#:#cmps_module#:#Modul cmps#:#cmps_must_installed#:#A komponenst telepíteni kell. cmps#:#cmps_name#:#Név -cmps#:#cmps_needs_matching_ilias_version#:#This plugin does not work with your current ILIAS version.###29 07 2022 new variable +cmps#:#cmps_needs_matching_ilias_version#:#Ez a bővítmény nem működik ezen az ILIAS verzión. cmps#:#cmps_needs_newer_ilias_version#:#Ez a bővítményverzió csak újabb ILIAS-verziókon fut. Frissítse az ILIAS-t! cmps#:#cmps_needs_newer_plugin_version#:#Ehhez az ILIAS-verzióhoz újabb bővítményverzió szükséges. Frissítse a bővítményt! cmps#:#cmps_needs_update#:#Frissítés szükséges. @@ -3380,39 +3411,39 @@ cmps#:#cmps_plugin#:#Bővítmény cmps#:#cmps_plugin_activated#:#A bővítményt bekapcsolta. cmps#:#cmps_plugin_db_prefixes#:#Adatbázistábla előtag cmps#:#cmps_plugin_deactivated#:#A bővítményt kikapcsolta. -cmps#:#cmps_plugin_deinstalled#:#The plugin has been uninstalled###29 07 2022 new variable +cmps#:#cmps_plugin_deinstalled#:#A bővítményt eltávolította. cmps#:#cmps_plugin_file#:#Bővítmény fájl cmps#:#cmps_plugin_lang_prefixes#:#Bővítmény nyelvi előtagok cmps#:#cmps_plugin_slot#:#Bővítmény csatlakozás -cmps#:#cmps_plugin_uninstalled#:#Az összes nyelvi- és adatbázis-bejegyzést sikeresen eltávolította, és a bővítményt inaktiválta. Most már biztonságosan letávolíthatja a bővítmény - 'Customizing' mappa alatt található - fájljait/mappáit. -cmps#:#cmps_plugin_updated#:#The plugin has been updated###29 07 2022 new variable +cmps#:#cmps_plugin_uninstalled#:#Az összes nyelvi- és adatbázis-bejegyzést sikeresen eltávolította, és a bővítményt inaktiválta. Most már biztonságosan letávolíthatja a bővítmény - ‘Customizing’ mappa alatt található - fájljait/mappáit. +cmps#:#cmps_plugin_updated#:#A bővítményt frissítette cmps#:#cmps_plugins#:#Bővítmények cmps#:#cmps_refresh#:#Frissítés -cmps#:#cmps_refresh_lng#:#Refresh language###29 07 2022 new variable +cmps#:#cmps_refresh_lng#:#Nyelv frissítés cmps#:#cmps_rep_object#:#Tartalomtárban lévő objektumtípus -cmps#:#cmps_repository_object_types#:#Tartalomtár-objektum típusok +cmps#:#cmps_repository_object_types#:#ILIAS-objektum típusok cmps#:#cmps_responsible#:#Felelős -cmps#:#cmps_responsible_mail#:#Mail (Responsible)###29 07 2022 new variable +cmps#:#cmps_responsible_mail#:#E-mail cím (Felelős) cmps#:#cmps_save_options#:#Mentés cmps#:#cmps_service#:#Szolgáltatás cmps#:#cmps_show_details#:#Részletek megjelenítése cmps#:#cmps_slots#:#Foglalatok cmps#:#cmps_status#:#Állapot -cmps#:#cmps_supports_cli_setup#:#Supports CLI-Setup###29 07 2022 new variable -cmps#:#cmps_supports_export#:#Supports export###29 07 2022 new variable -cmps#:#cmps_supports_learning_progress#:#Supports learning progress###29 07 2022 new variable +cmps#:#cmps_supports_cli_setup#:#Parancssori telepítés támogatása +cmps#:#cmps_supports_export#:#Exportálás támogatása +cmps#:#cmps_supports_learning_progress#:#Tanulási haladás támogatása cmps#:#cmps_uninstall#:#Eltávolítás -cmps#:#cmps_uninstall_confirm#:#Biztos, hogy eltávolítja a következő '%s' bővítményt annak összes adatbázis-bejegyzésével együtt? -cmps#:#cmps_uninstall_inactive_confirm#:#'%1$s' bővítmény jelenleg nem aktiválható ('%2$s'), így nem távolítható el teljesen, néhány adata a rendszerben marad. Biztos, hogy folytatja a részleges eltávolítást? +cmps#:#cmps_uninstall_confirm#:#Biztos, hogy eltávolítja a következő ‘%s’ bővítményt annak összes adatbázis-bejegyzésével együtt? +cmps#:#cmps_uninstall_inactive_confirm#:#‘%1$s’ bővítmény jelenleg nem aktiválható (‘%2$s’), így nem távolítható el teljesen, néhány adata a rendszerben marad. Biztos, hogy folytatja a részleges eltávolítást? cmps#:#cmps_update#:#Frissítés cmps#:#cmps_version#:#Verzió cmps#:#database_is_uptodate#:#Az adatbázis naprakész. cmps#:#no_changes#:#Nincsenek változások -cmxv#:#cmxv_create#:#Create Certificate for xAPI/cmi5 Objektum -cmxv#:#cmxv_create_info#:#Select a completed xAPI/cmi5 objektum to generate a certificate for it +cmxv#:#cmxv_create#:#Tanúsítvány létrehozása a xAPI/cmi5-objektumhoz +cmxv#:#cmxv_create_info#:#Válassza ki a teljesített xAPI/cmi5-objektumot, melyhez tanúsítványt kíván generálni cntr#:#cntr_add_new_item#:#Új objektum létrehozása cntr#:#cntr_adopt_content#:#Tartalom örökítése -cntr#:#cntr_container_only_on_their_own#:#Egyszerű objektumonként csak kategóriák, kurzusok, csoportok, mappák, illetve képzési programok másolhatóak. Csak egy elemet válasszon. +cntr#:#cntr_container_only_on_their_own#:#Egyszerű objektumonként csak kategóriák, kurzusok, csoportok, mappák, tanulási sorok, illetve képzési programok másolhatók. Csak egy elemet válasszon. cntr#:#cntr_copy_crs_grp#:#Kurzusaim és csoportjaim cntr#:#cntr_copy_repo_tree#:#Tartalomtár cntr#:#cntr_hide_title_and_icon#:#Cím és ikon elrejtése @@ -3423,11 +3454,11 @@ cntr#:#cntr_switch_to_new_editor_cmd#:#Új tartalom kapcsolása ehhez a laphoz. cntr#:#cntr_switch_to_new_editor_message#:#Ez a támogatott szabványos szerkesztő. A régi szerkesztő tartalma nem hozható át. Lentebb vegyen fel új laptartalmat. Ha az alábbi linkre kattint, az új tartalom kerül használatra. cntr#:#cntr_switched_editor#:#Új tartalomhoz kapcsolva. cntr#:#cntr_tax_none_available#:#Nincsenek elérhető taxonómiák. -cntr#:#cntr_tax_settings_info#:#Taxonomies in categories classify and filter the objects contained in the category. After adding taxonomies, classifications can be made via the "Metadata" tabs and the "Taxonomy Assignment" sub-tabs of the respective objects. Taxonomies can additionally be displayed in the side block of the category's "Contents" tab to enable direct filtering of the assigned objects.###26 08 2024 new variable +cntr#:#cntr_tax_settings_info#:#A kategóriákban lévő taxonómiák osztályozzák és szűrik a kategóriában lévő objektumokat. A taxonómiák hozzáadása után a besorolásokat a megfelelő objektumok ‘Metaadatok’ és ‘Taxonómia hozzárendelése’ allapjain lehet elvégezni. A taxonómiák emellett a kategória ‘Tartalom’ lapjának oldalsó blokkjában is megjeleníthetők, így lehetővé válik a hozzárendelt objektumok közvetlen szűrése is. cntr#:#cntr_taxonomy_definitions#:#Taxonómia meghatározása cntr#:#cntr_taxonomy_show_sideblock#:#Taxonómiát mutassa az oldalblokkban cntr#:#cntr_taxonomy_sideblock_settings#:#Megjelenítési beállítások -cntr#:#cntr_text_media_editor#:#Oldal testreszabása +cntr#:#cntr_text_media_editor#:#Lap szerkesztése cntr#:#cntr_view_by_type#:#Típus szerint csoportosított nézet cntr#:#cntr_view_info_by_type#:#Az objektumokat típusuk alapján csoportosítva jelenítjük meg. cntr#:#cntr_view_info_sessions#:#Először az eseményeket azok objektumaival, alatta pedig a további kurzustartalmakat jelenítjük meg. @@ -3448,10 +3479,10 @@ cntr#:#sorting_new_items_position#:#Új objektumok pozíciója cntr#:#tab_back_to_repository#:#Vissza a Tartalomtárhoz common#:#HH#:#ÓÓ:PP common#:#absolute_path#:#Abszolút elérési út -common#:#accept_usr_agreement_btn#:#Accept +common#:#accept_usr_agreement_btn#:#Elfogadás common#:#access#:#Hozzáférés -common#:#accessFree#:#'Érvényes eddig' dátum eltávolítása -common#:#accessRestrict#:#'Érvényes eddig' dátum beállítása +common#:#accessFree#:#‘Érvényes eddig’ dátum eltávolítása +common#:#accessRestrict#:#‘Érvényes eddig’ dátum beállítása common#:#access_expired#:#lejárt common#:#access_free_granted#:#A kiválasztott felhasználó(k)nak korlátlan hozzáférés beállítása common#:#access_from#:#Hozzáférés (honnan) @@ -3461,15 +3492,15 @@ common#:#access_scope#:#Hozzáférés common#:#access_unlimited#:#korlátlan common#:#access_until#:#Érvényes eddig common#:#access_users#:#Bejelentkezett felhasználók -common#:#accesscount_registered_users#:#Ennyi ILIAS-felhasználó tekintette meg -common#:#accessibility_control_concept#:#Hozzáférés-vezérlés koncepciója +common#:#accesscount_registered_users#:#Olvasta … (különböző ILIAS-felhasználók száma) +common#:#accessibility_control_concept#:#Hozzáférhetőség common#:#account#:#Fiókom -common#:#account_expires_body#:#Hozzáférése korlátozott, lejárati dátuma: +common#:#account_expires_body#:#%s helyen % ILIAS-fiókja hozzáférése korlátozott, lejárati dátuma: %s. Lejárt után ILIAS-fiókjával nem tud bejelentkezni. Személyes dokumentumait, tanúsítványait még időben töltse le. common#:#account_expires_subject#:#Hozzáférése hamarosan lejár common#:#action#:#Művelet common#:#action_aborted#:#Művelet megszakítva. common#:#actions#:#Műveletek -common#:#actions_for#:#Actions for %s###29 07 2022 new variable +common#:#actions_for#:#%s művelete common#:#activate#:#Aktiválás common#:#activate_https#:#HTTPS-t az ILIAS kezeli
    (bejelentkezés) common#:#activate_tracking#:#Aktiválás @@ -3479,12 +3510,12 @@ common#:#add#:#Hozzáadás common#:#add_condition#:#Feltétel hozzáadása common#:#add_entry#:#Bejegyzés létrehozása/módosítása common#:#add_member#:#Tag hozzáadása -common#:#add_member_role#:#Tagszerep hozzáadása +common#:#add_member_role#:#Tagszerepkör hozzáadása common#:#add_new_user_defined_field#:#Új felhasználói mező létrehozása common#:#add_note#:#Jegyzet hozzáadása common#:#add_parameter#:#Új paraméter common#:#add_remove_edit_entries_of_main_menu#:#A Főmenü elemeinek hozzáadása, eltávolítása, illetve módosítása -common#:#add_role#:#Szerep hozzáadása +common#:#add_role#:#Szerepkör hozzáadása common#:#add_translation#:#Fordítás hozzáadása common#:#add_user#:#Helyi felhasználó létrehozása common#:#add_user_defined_field#:#Új mező létrehozása @@ -3493,7 +3524,7 @@ common#:#additional_info#:#További információk common#:#address#:#Cím common#:#admin_force_noti#:#Az értesítés aktív common#:#administrate_users#:#Helyi ILIAS-fiókok kezelése -common#:#administrate_users_headline#:#Local ILIAS Accounts of this Category###26 08 2024 new variable +common#:#administrate_users_headline#:#A kategória helyi ILIAS-fiókokjai common#:#administration#:#Rendszerbeállítások common#:#administrator#:#Vezető common#:#adopt#:#Felvesz @@ -3508,12 +3539,12 @@ common#:#adve_assessment_settings#:#Teszt- és kiértékelés common#:#adve_frm_post_settings#:#Fórumhozzászólások common#:#adve_general_settings#:#Általános beállítások common#:#adve_survey_settings#:#Kérdőív -common#:#agree_date#:#Elfogadva +common#:#agree_date#:#Elfogadva ekkor: common#:#all#:#Összes -common#:#all_global_roles#:#Globális szerepek -common#:#all_local_roles#:#Helyi szerepek (összes) +common#:#all_global_roles#:#Globális szerepkörök +common#:#all_local_roles#:#Helyi szerepkörök (összes) common#:#all_objects#:#Összes objektum -common#:#all_roles#:#Összes szerep +common#:#all_roles#:#Összes szerepkör common#:#all_topics#:#Összes téma common#:#all_users#:#Összes felhasználó common#:#allow_assign_users#:#A helyi rendszergazdák felhasználókat adhatnak ehhez a csoporthoz. @@ -3542,19 +3573,19 @@ common#:#assf_allowed_questiontypes#:#Elérhető kérdéstípusok common#:#assf_allowed_questiontypes_desc#:#A bejelölt kérdéstípusok lesznek elérhetők az ILIAS-ban. Ha egy bizonyos kérdéstípust nem szeretne engedélyezni ezen a kliensen, akkor távolítsa el a megfelelő jelölőnégyzet pipáját. common#:#assf_questiontypes#:#Kérdésbeállítások common#:#assign#:#Hozzárendelés -common#:#assign_global_role#:#Globális szerephez hozzárendelés -common#:#assign_local_role#:#Helyi szerephez hozzárendelés +common#:#assign_global_role#:#Hozzárendelés globális szerepkörhöz +common#:#assign_local_role#:#Hozzárendelés helyi szerepkörhöz common#:#assigned_members#:#Hozzárendelt tagok -common#:#assigned_roles#:#Hozzárendelt szerepek +common#:#assigned_roles#:#Hozzárendelt szerepkörök common#:#associated_user#:#tag felhasználó common#:#astounded#:#Meghökken common#:#at_least_one_style#:#Legalább egy stílusnak aktívnak kell maradnia. common#:#attachment#:#Melléklet common#:#attachments#:#Mellékletek common#:#attempts#:#Próbálkozások -common#:#auth_active_roles#:#Globális szerepek elérhetők a regisztrációs űrlapon +common#:#auth_active_roles#:#Globális szerepkörök elérhetők a regisztrációs űrlapon common#:#auth_allow_local#:#Helyi hitelesítés engedélyezése -common#:#auth_configure#:#konfigurálás... +common#:#auth_configure#:#konfigurálás… common#:#auth_create_users#:#Nemlétező felhasználók automatikus létrehozása common#:#auth_default#:#Alapértelmezett beállítás common#:#auth_default_mode_changed_to#:#Az alapértelmezett hitelesítési mód a következőre változott: @@ -3562,15 +3593,15 @@ common#:#auth_ecs#:#ECS common#:#auth_ldap#:#LDAP common#:#auth_ldap_enable#:#LDAP-támogatás engedélyezése common#:#auth_ldap_migration#:#Felhasználói fiók migrációja -common#:#auth_ldap_migration_info#:#Kapcsolja be a beállítást, hogy az új felhasználók átalakíthassák a már meglévő ILIAS-fiókjukat LDAP-hitelesítésre. +common#:#auth_ldap_migration_info#:#Lehetővé teszi az új felhasználóknak, hogy átalakíthassák a már meglévő ILIAS-fiókjukat LDAP-hitelesítésűre. common#:#auth_local#:#ILIAS-adatbázis common#:#auth_login_instructions#:#A bejelentkező képernyőn megjelenítendő utasítások common#:#auth_mode#:#Hitelesítési mód common#:#auth_mode_not_changed#:#(Semmi nem változott) -common#:#auth_mode_roles_changed#:#Megváltozott a hitelesítési mód ehhez a szerephez. -common#:#auth_new_account_mail_desc#:#Új felhasználónak levél küldése, ha a felhasználó automatikusan jött létre. Jelszó csak akkor generálódik, ha a 'helyi hitelesítés engedélyezve' is aktív. +common#:#auth_mode_roles_changed#:#Megváltozott a hitelesítési mód ehhez a szerepkörhöz. +common#:#auth_new_account_mail_desc#:#Új felhasználónak levél küldése, ha a felhasználó automatikusan jött létre. Jelszó csak akkor generálódik, ha a ‘helyi hitelesítés engedélyezve’ is aktív. common#:#auth_per_default#:#Alapértelmezettként -common#:#auth_remark_non_local_auth#:#Ha az ILIAS-adatbázistól eltérő hitelesítési módot választ, nem változtathatja meg a továbbiakban felhasználónevét és jelszavát. +common#:#auth_remark_non_local_auth#:#‘ILIAS-hitelesítés’-től (ami az ILIAS adatbázist használja) eltérő mód választása avval jár, hogy a felhasználók nem tudják módosítani felhasználónevüket, illetve jelszavukat a regisztráció után. common#:#auth_role_auth_mode#:#Hitelesítési mód common#:#auth_saml#:#SAML common#:#auth_script#:#Egyéni @@ -3578,7 +3609,7 @@ common#:#auth_select#:#Hitelesítési mód kiválasztása common#:#auth_selection#:#Bejelentkezés common#:#auth_settings#:#Hitelesítési beállítások common#:#auth_shib#:#Shibboleth -common#:#auth_shib_instructions#:#Ajánlott a README elolvasása a Shibboleth-támogatás konfigurálásához. +common#:#auth_shib_instructions#:#Olvassa el a README-t a Shibboleth-támogatás konfigurálásához. common#:#auth_shib_not_configured#:#Shibboleth még nincs konfigurálva. common#:#auth_shibboleth#:#Shibboleth common#:#auth_soap#:#SOAP @@ -3594,8 +3625,8 @@ common#:#auth_soap_settings_saved#:#SOAP hitelesítési beállítások mentése common#:#auth_soap_uri_desc#:#Helyi URI, például dir/server.php, ha a teljes SOAP szerver URI http://auth.yourserver.com:8080/dir/server.php common#:#auth_soap_use_dotnet#:#.NET SOAP stílus használata common#:#auth_soap_use_https#:#Használjon HTTPS-t -common#:#auth_soap_user_default_role_desc#:#Ezt a szerepet rendeljük hozzá az automatikusan létrejött SOAP felhasználókhoz. -common#:#auth_user_default_role#:#Alapértelmezett szerep +common#:#auth_soap_user_default_role_desc#:#Ezt a szerepkört rendeljük hozzá az automatikusan létrejött SOAP felhasználókhoz. +common#:#auth_user_default_role#:#Alapértelmezett szerepkör common#:#authenticate_ilias#:#ILIAS natív bejelentkezés common#:#authentication_settings#:#Hitelesítés common#:#author#:#Szerző @@ -3605,17 +3636,17 @@ common#:#autocomplete_more#:#továbbiak common#:#available#:#Elérhető common#:#awra#:#Ki van online? common#:#back#:#Vissza -common#:#back_to_course#:#Back to Course +common#:#back_to_course#:#Vissza a kurzushoz common#:#back_to_crs_content#:#Vissza a kurzustartalomhoz common#:#back_to_fold_content#:#Vissza a mappatartalomhoz common#:#back_to_grp_content#:#Vissza a csoporttartalomhoz common#:#backto_lua#:#Vissza a helyi ILIAS-fiókok kezeléséhez common#:#basedn#:#BaseDN
    Például ou=userek, dc=pelda, dc=hu common#:#basic_settings#:#Alapbeállítások -common#:#before#:#előtte -common#:#behind#:#Mögötte: +common#:#before#:#Előtte +common#:#behind#:#Mögötte common#:#bib_data#:#Bibliográfiai adatok -common#:#bibl_add#:#Add Bibliography###29 07 2022 new variable +common#:#bibl_add#:#Bibliográfia hozzáadása common#:#birthday#:#Születési idő common#:#bkm_import#:#Könyvjelzők importálása common#:#bkm_import_ok#:#%d könyvjelző és %d könyvjelzőmappa sikeresen importálva. @@ -3625,7 +3656,7 @@ common#:#bm#:#Könyvjelző common#:#bm_add_to_ilias#:#Hozzáadás ILIAS-könyvjelzőkhöz common#:#bmf#:#Könyvjelzőmappa common#:#bold#:#Félkövér -common#:#bold_action#:#Insert Bold - Click to insert bold text.###26 08 2024 new variable +common#:#bold_action#:#Félkövér beillesztése - Kattintson félkövér szöveg beillesztéséhez. common#:#bookings#:#Foglalások common#:#bookmark_added#:#Sikeresen létrehozott egy könyvjelzőt. common#:#bookmark_folder_new#:#Új könyvjelzőmappa @@ -3644,8 +3675,8 @@ common#:#btn_remove_system#:#Eltávolítás a rendszerből common#:#btn_undelete#:#Törlés visszavonása common#:#buddy_allow_to_contact_me_no#:#Ismerősnek jelöléseket nem fogad common#:#buddy_allow_to_contact_me_yes#:#Ismerősnek jelöléseket fogad -common#:#building_export_file#:#Exportfájl létrehozása... -common#:#bulletlist_action#:#Insert Bulletpoint-List - Click to insert a bulletpoint-list.###26 08 2024 new variable +common#:#building_export_file#:#Exportfájl létrehozása… +common#:#bulletlist_action#:#Listajeles felsorolás beillesztése - Kattintson listajeles felsorolás beillesztésehez. common#:#by#:#Létrehozta common#:#bytes#:#Bájt common#:#cal_from#:#Mettől: @@ -3668,41 +3699,41 @@ common#:#cat_wizard_page#:#Kategória másolása (2/2. lépés) common#:#categories#:#Kategóriák common#:#categories_imported#:#A kategória importja befejeződött. common#:#catr#:#Kategórialink -common#:#catr_add#:#Add Category Link###29 07 2022 new variable +common#:#catr_add#:#Kategórialink hozzáadása common#:#catr_edit_info#:#Válasszon egy kategóriát új link létrehozásához! common#:#catr_new#:#Kategórialink létrehozása -common#:#catr_settings#:#Category Link Settings###29 07 2022 new variable -common#:#certificate#:#Igazolás -common#:#certificate_file_already_exists_error#:#Az igazolásfájl már létezik a rendszerben. -common#:#certificate_file_input_output_error#:#Az igazolásfájl létezik a rendszerben, de nem törölhető. Keresse meg a hibával az üzemeltetőt. -common#:#certificate_file_not_found_error#:#Az igazolásfájl már nem található a rendszerben. -common#:#certificate_persistent_option#:#Megszerzett igazolások -common#:#certificate_selection#:#Igazolások forrása -common#:#certificate_workspace_option#:#Személyes erőforrások igazolásai -common#:#certificates#:#Certificates###29 07 2022 new variable +common#:#catr_settings#:#Kategórialink beállításai +common#:#certificate#:#Tanúsítvány +common#:#certificate_file_already_exists_error#:#A tanúsítványfájl már létezik a rendszerben. +common#:#certificate_file_input_output_error#:#A tanúsítványfájl létezik a rendszerben, de nem törölhető. Keresse meg a hibával az üzemeltetőt. +common#:#certificate_file_not_found_error#:#A tanúsítványfájl már nem található a rendszerben. +common#:#certificate_persistent_option#:#Megszerzett tanúsítványok +common#:#certificate_selection#:#Tanúsítványok forrása +common#:#certificate_workspace_option#:#Személyes erőforrások tanúsítványai +common#:#certificates#:#Tanúsítványok common#:#change#:#Változtatás common#:#change_assignment#:#Hozzárendelés változtatása common#:#change_header_title#:#Fejléccím módosítása common#:#change_owner#:#Tulajdonos cseréje common#:#change_sort_direction#:#Rendezési irány változtatása -common#:#changeable#:#Módosítható a 'Felhasználói adatok' alatt -common#:#changed_to#:#amire változtat +common#:#changeable#:#Módosítható a ‘Felhasználói adatok’ alatt +common#:#changed_to#:#módosult erre common#:#changing_loginname_not_possible_info#:#Ön legutóbb %s-kor cserélte a felhasználónevét. Legközelebb %s-kor cserélheti. common#:#chapter#:#Fejezet common#:#characters#:#karakter -common#:#chat_enter_public_room#:#Nyilvános csevegés -common#:#chat_enter_public_room_tooltip#:#Belépés nyilvános csevegésbe. +common#:#chat_enter_public_room#:#Nyilvános csevegőszoba +common#:#chat_enter_public_room_tooltip#:#Belépés nyilvános csevegőszobába common#:#chat_users_active#:#Aktív felhasználók common#:#check#:#Ellenőrzés common#:#check_all#:#Összes kijelölése common#:#check_langfile#:#Ellenőrizze nyelvi fájlját! common#:#check_languages#:#Összes nyelv ellenőrzése common#:#check_link#:#ILIAS-tananyagban lévő weblinkek ellenőrzése -common#:#check_link_desc#:#Ha be van kapcsolva, az ILIAS-tananyagokban lévő aktív külső linkeket ellenőrizzük. +common#:#check_link_desc#:#Az ILIAS-tananyagokban lévő aktív külső linkeket ellenőrizzük. common#:#check_user_accounts#:#ILIAS-fiókok ellenőrzése -common#:#check_user_accounts_desc#:#Ha be van kapcsolva, minden lejárt bejelentkezésű felhasználó e-mailben értesítést kap. Ezen kívül azokat a felhasználókat is töröljük, akik regisztrációjuk után nem erősítették meg ILIAS-fiókjuk használati szándékát. +common#:#check_user_accounts_desc#:#Az összes lejárt bejelentkezésű felhasználó e-mailben értesítést kap. Ezen kívül azokat a felhasználókat is töröljük, akik regisztrációjuk után nem erősítették meg ILIAS-fiókjuk használati szándékát. common#:#check_web_resources#:#Weblinkek ellenőrzése -common#:#check_web_resources_desc#:#Ha be van kapcsolva, az összes aktív weblinket ellenőrizzük. +common#:#check_web_resources_desc#:#Az összes aktív weblinket ellenőrizzük. common#:#checked#:#Bejelölve common#:#checked_files#:#Importálható fájlok common#:#chg_ilias_and_webfolder_password#:#Webmappa jelszavának cseréje @@ -3734,13 +3765,13 @@ common#:#clientlist_public_access#:#Nyilvános elérés common#:#clientlist_start_page#:#Kezdőoldal common#:#clipboard#:#Vágólap common#:#close#:#Bezárás -common#:#cmix#:#Object xAPI/cmi5###26 08 2024 new variable +common#:#cmix#:#xAPI/cmi5 objektum common#:#cnt_new#:#(%s új) common#:#collapse#:#Fa bezárása common#:#collapse_all#:#Összes bezárása common#:#collapse_content#:#Tartalom összecsukása common#:#collapsed#:#Összezárt -common#:#column_selection#:#Column Selection###28 10 2024 new variable +common#:#column_selection#:#Oszlop kijelölése common#:#columns#:#Oszlopok common#:#comma_separated#:#Vesszővel elválasztva common#:#comment#:#Megjegyzés @@ -3761,14 +3792,14 @@ common#:#condition_not_finished#:#Nem befejezett common#:#condition_passed#:#Sikeres common#:#condition_select_object#:#Válasszon egy objektumot! common#:#conditions_updated#:#A feltételeket sikeresen mentette. -common#:#configuration#:#Configuration###29 10 2025 new variable +common#:#configuration#:#Beállítások common#:#confirm#:#Megerősítés common#:#confirm_delete_parameter#:#Biztos, hogy törli a paramétereket? common#:#confirmation#:#Megerősítés common#:#conflict_handling#:#Konfliktuskezelés common#:#cont_iim_content_popups_info#:#A felugró ablak akkor jelenik meg, amikor a felhasználó a háttérkép interaktív részeire kattint. Ezen a képernyőn hozhatja létre az előugró ablakokat, tartalmukat a fő lap szerkesztésekor módosíthatja. common#:#cont_iim_create_info#:#Töltse fel a háttérképet az interaktív képhez. -common#:#cont_iim_overlay_info#:#A fedőkép változtatja (például kiemeli) a háttérkép egy részét amikor az egér föléje kerül. A képet feltöltés után a 'Triggerek' fülön választhatja ki. +common#:#cont_iim_overlay_info#:#A fedőkép változtatja (például kiemeli) a háttérkép egy részét amikor az egér föléje kerül. A képet feltöltés után a ‘Triggerek’ lapon választhatja ki. common#:#contact#:#Kapcsolat common#:#contact_data#:#Elérhetőségek common#:#contact_sysadmin#:#Kapcsolat @@ -3778,10 +3809,10 @@ common#:#content#:#Tartalom common#:#content_frame#:#Tartalomkeret common#:#content_styles#:#Tartalomstílusok common#:#context#:#Kontextus -common#:#continue#:#folytatás +common#:#continue#:#Folytatás common#:#continue_work#:#Folytatás common#:#contra#:#Negatívum -common#:#copa#:#Content Page###26 08 2024 new variable +common#:#copa#:#Tartalomlap common#:#copy#:#Másolás common#:#copyChapter#:#Másolás common#:#copyPage#:#Másolás @@ -3789,11 +3820,11 @@ common#:#copy_all#:#Összeset másol common#:#copy_n_of_suffix#:#- másolata (%1$s) common#:#copy_of#:#Másolandó: common#:#copy_of_suffix#:#- másolata -common#:#copy_perma_link#:#Copy link to clipboard###29 10 2025 new variable +common#:#copy_perma_link#:#Link másolása a vágólapra common#:#copy_selected_items#:#Másolás common#:#count#:#Darabszám -common#:#counter_novelty#:#News###26 08 2024 new variable -common#:#counter_status#:#Status###26 08 2024 new variable +common#:#counter_novelty#:#Hírek +common#:#counter_status#:#Állapot common#:#country#:#Ország common#:#country_free_text#:#Ország (szabadszöveges mező) common#:#country_selection#:#Ország (legördülő lista) @@ -3804,22 +3835,22 @@ common#:#create_date#:#Létrehozva common#:#create_export_file#:#Exportfájl létrehozása common#:#create_stylesheet#:#Stílus létrehozása common#:#created#:#Létrehozva -common#:#cron_forum_notification#:#Fórumértesítések küldése -common#:#cron_forum_notification_crob_desc#:#Ha be van kapcsolva, az összes olyan felhasználó, aki a fórumértesítéseket engedélyezte bizonyos fórumokról, illetve témákról, a több, egymástól független azonnali e-mail értesítések helyett napi összesítő e-mail értesítést kap az új és a módosított hozzászólásokról. -common#:#cron_forum_notification_disabled#:#Can't be disabled when the Cron Job is active.###26 08 2024 new variable +common#:#cron_forum_notification#:#Fórumértesítések küldése ütemezett feladattal +common#:#cron_forum_notification_crob_desc#:#Az összes olyan felhasználó, aki a fórumértesítéseket engedélyezte bizonyos fórumokról, illetve témákról, a több, egymástól független azonnali e-mail értesítések helyett napi összesítő e-mail értesítést kap az új és a módosított hozzászólásokról. +common#:#cron_forum_notification_disabled#:#Addig nem kapcsolható ki, amíg az ütemezett feladat aktív. common#:#cron_jobs#:#Ütemezett feladatok common#:#cron_lucene_index#:#Lucene keresési index aktualizálása -common#:#cron_lucene_index_info#:#Ha be van kapcsolva, a Lucene keresési indexet frissítjük. A Lucene szervert a Rendszerbeállítások » Keresés menüpont alatt tudja konfigurálni. +common#:#cron_lucene_index_info#:#A Lucene keresési indexet frissítjük. A Lucene szervert a Rendszerbeállítások » Keresés menüpont alatt tudja konfigurálni. common#:#cron_mail_notification#:#E-mail értesítések küldése common#:#cron_mail_notification_cron#:#szabályosan ütemezett feladatonként -common#:#cron_mail_notification_desc#:#Ha be van kapcsolva, minden felhasználónak külső e-mail értesítést küldünk az ILIAS-fiókjában lévő leveleiről. Az bekapcsolás előtt kapcsolja ki a 'Külső levelek küldésének globális megakadályozása' beállítást. +common#:#cron_mail_notification_desc#:#Minden felhasználónak külső e-mail értesítést küldünk az ILIAS-fiókjában lévő leveleiről. Az bekapcsolás előtt kapcsolja ki a ‘Külső levelek küldésének globális megakadályozása’ beállítást. common#:#cron_mail_notification_message#:#Emlékeztető levél küldése e-mail üzenetben -common#:#cron_mail_notification_message_info#:#Ha be van kapcsolva, a felhasználók külső e-mail címére küldjük el az értesítő üzeneteket. +common#:#cron_mail_notification_message_info#:#A felhasználók külső e-mail címére küldjük el az értesítő üzeneteket. common#:#cron_mail_notification_never#:#soha common#:#cron_users_without_login_del_create_date_thr#:#Küszöbérték common#:#cron_users_without_login_del_create_date_thr_info#:#A megadott dátum előtt létrehozott összes felhasználói fiókot megfontolás tárgyává tesszük. -common#:#cron_users_without_login_del_role_whitelist#:#Tartalmazza a szerepet -common#:#cron_users_without_login_del_role_whitelist_info#:#Csak azokat a felhasználókat töröljük, akik legalább az egyik szerephez hozzá vannak rendelve +common#:#cron_users_without_login_del_role_whitelist#:#Tartalmazza a szerepkört +common#:#cron_users_without_login_del_role_whitelist_info#:#A kiválasztott szerepkörökből legalább eggyel bíró, inaktív fiókokat töröljük. Ki nem választott szereppel rendelkező fiókok nem módosulnak. common#:#cronjob_last_start#:#Ütemezett feladat legutóbbi indulása common#:#cronjob_last_start_unknown#:#Nem megállapítható common#:#crs#:#Kurzus @@ -3827,7 +3858,7 @@ common#:#crs_activation_start_invalid#:#Nem érvényes a kezdő és a záró dá common#:#crs_add#:#Kurzus létrehozása common#:#crs_added#:#Sikeresen létrehozott egy kurzust common#:#crs_archives#:#Archívumok -common#:#crs_cancel_waiting_list#:#Biztos, hogy leveszi magát a(z) '%s' kurzus várólistájáról? +common#:#crs_cancel_waiting_list#:#Biztos, hogy leveszi magát a(z) ‘%s’ kurzus várólistájáról? common#:#crs_copy_threads_info#:#Döntse el, mely kurzusanyagok lesznek másolva, csatolva vagy kihagyva. common#:#crs_edit#:#Kurzus módosítása common#:#crs_list_reg#:#Regisztráció @@ -3841,7 +3872,7 @@ common#:#crs_member_not_passed#:#Nem teljesítette common#:#crs_member_passed#:#Sikeresen teljesítette common#:#crs_members_gallery#:#Kurzustagok képtára common#:#crs_new#:#Új kurzus -common#:#crs_removed_from_waiting_list#:#Lekerült a(z) '%s' kurzus várólistájáról. +common#:#crs_removed_from_waiting_list#:#Lekerült a(z) ‘%s’ kurzus várólistájáról. common#:#crs_status_blocked#:#[Hozzáférés megtagadva] common#:#crs_status_pending#:#[Regisztrációra vár] common#:#crs_subscribers_assigned#:#Új felhasználó(k) hozzárendelve. @@ -3849,17 +3880,17 @@ common#:#crs_title#:#Kurzuscím common#:#crs_unsubscribe#:#Lejelentkezés a kurzusról common#:#crs_wizard_page#:#Kurzus másolása (2/2. lépés) common#:#crsr#:#Kurzuslink -common#:#crsr_add#:#Add Course Link###29 07 2022 new variable +common#:#crsr_add#:#Kurzuslink hozzáadása common#:#crsr_edit_info#:#Válasszon egy kurzust a link létrehozásához. common#:#crsr_new#:#Kurzuslink létrehozása -common#:#crsr_settings#:#Course Link Settings###26 08 2024 new variable +common#:#crsr_settings#:#Kurzuslink beállításai common#:#csv_export#:#Exportálás vesszővel tagolt (.csv) fájlba common#:#current_ip#:#Jelenlegi IP: common#:#current_ip_alert#:#Figyelmeztetés: Ha rossz IP-t ad meg, a továbbiakban ezzel a profillal nem fog tudni kapcsolódni a rendszerhez. common#:#current_password#:#Jelenlegi jelszó -common#:#current_user_avatar#:#Your User Avatar###29 07 2022 new variable +common#:#current_user_avatar#:#Profilképem common#:#currently_used_disk_space#:#Jelenleg használt tárhely -common#:#customize_page#:#Customize Page###28 10 2024 new variable +common#:#customize_page#:#Lap személyre szabása common#:#cut#:#Kivágás common#:#cutPage#:#Kivágás common#:#daily#:#napi @@ -3867,13 +3898,13 @@ common#:#database#:#Adatbázis common#:#database_version#:#Jelenlegi adatbázis-verzió common#:#dataset#:#Elem common#:#date#:#Dátum -common#:#date_time#:#Date and Time###29 10 2025 new variable +common#:#date_time#:#Dátum és idő common#:#dateplaner#:#Naptár common#:#day#:#Nap common#:#days#:#Nap common#:#db_host#:#Adatbázis-kiszolgáló common#:#db_name#:#Adatbázisnév -common#:#db_need_update#:#Az adatbázis frissítésre szorul. +common#:#db_need_update#:#Az adatbázist frissíteni kell! common#:#db_pass#:#Adatbázis-jelszó common#:#db_type#:#Adatbázis-típus common#:#db_user#:#Adatbázis-felhasználó @@ -3887,8 +3918,8 @@ common#:#default_auth_mode#:#Alapértelmezett azonosítási módszer common#:#default_auth_mode_info#:#Válassza ki a bejelentkező képernyőn előre kiválasztott bejelentkezési módot. common#:#default_language#:#Alapértelmezett nyelv common#:#default_perm_settings#:#Alapértelmezett jogosultságok -common#:#default_role#:#Alapértelmezett szerep -common#:#default_roles#:#Alapértelmezett szerepek +common#:#default_role#:#Alapértelmezett szerepkör +common#:#default_roles#:#Alapértelmezett szerepkörök common#:#default_skin#:#Alapértelmezett skin common#:#default_skin_style#:#Alapértelmezett skin / stílus common#:#default_style#:#Alapértelmezett stílus @@ -3896,15 +3927,15 @@ common#:#defaults#:#Alapértelmezett értékek common#:#delete#:#Törlés common#:#delete_existing_file#:#Meglévő fájl törlése common#:#delete_inactivated_user_accounts#:#Inaktivált ILIAS-fiókok törlése -common#:#delete_inactivated_user_accounts_desc#:#Ha be van kapcsolva, az inaktiválásuk dátumától függően törlünk ILIAS-fiókokat. -common#:#delete_inactivated_user_accounts_include_roles#:#Figyelembe vett szerepek -common#:#delete_inactivated_user_accounts_include_roles_desc#:#Csak a megjelölt szerepekkel bíró fiókokat ellenőrizzük, és töröljük, ha meghaladták a meximális napszámot. +common#:#delete_inactivated_user_accounts_desc#:#Az inaktiválásuk dátumától függően törlünk ILIAS-fiókokat. +common#:#delete_inactivated_user_accounts_include_roles#:#Figyelembe vett szerepkörök +common#:#delete_inactivated_user_accounts_include_roles_desc#:#A kiválasztott szerepkörökből legalább eggyel bíró, inaktív fiókokat töröljük. Ki nem választott szereppel rendelkező fiókok nem módosulnak. common#:#delete_inactivated_user_accounts_period#:#Inaktiválás óta eltelt napok száma common#:#delete_inactivated_user_accounts_period_desc#:#A fiókokat akkor töröljük, ha ennyi nap már eltelt az inaktiválás óta. common#:#delete_inactive_user_accounts#:#Régóta be nem jelentkezett ILIAS-fiókok törlése -common#:#delete_inactive_user_accounts_desc#:#Ha be van kapcsolva, a legutóbbi bejelentkezési dátumától függően törlünk ILIAS-fiókokat. -common#:#delete_inactive_user_accounts_include_roles#:#Figyelembe vett szerepek -common#:#delete_inactive_user_accounts_include_roles_desc#:#Csak a megjelölt szerepekkel bíró fiókokat ellenőrizzük, és töröljük, ha meghaladták a maximális napszámot. +common#:#delete_inactive_user_accounts_desc#:#A legutóbbi bejelentkezési dátumától függően törlünk ILIAS-fiókokat. +common#:#delete_inactive_user_accounts_include_roles#:#Figyelembe vett szerepkörök +common#:#delete_inactive_user_accounts_include_roles_desc#:#A kiválasztott szerepkörökből legalább eggyel bíró, inaktív fiókokat töröljük. Ki nem választott szereppel rendelkező fiókok nem módosulnak. common#:#delete_inactive_user_accounts_period#:#A legutóbbi bejelentkezés óta eltelt idő common#:#delete_inactive_user_accounts_period_desc#:#A megadott napszám óta be nem jelentkezett összes ILIAS-fiókot töröljük. common#:#delete_parameter#:#Paraméter törlése @@ -3912,21 +3943,21 @@ common#:#delete_selected_items#:#Törlés common#:#deleted#:#Törölt common#:#deleted_user#:#Törölt felhasználó common#:#deleted_users#:#Törölt felhasználók -common#:#deletion_notification#:#ezúton értesítjük, hogy '%s' lemondta résztvételi szándékát '%s' eseményről. +common#:#deletion_notification#:#ezúton értesítjük, hogy ‘%s’ lemondta részvételi szándékát ‘%s’ eseményről. common#:#deliver#:#Küldés -common#:#deny_usr_agreement#:#Do not accept terms of service? -common#:#deny_usr_agreement_btn#:#Not Accept +common#:#deny_usr_agreement#:#Biztos, hogy nem fogadja el a Szolgáltatási feltételeket? +common#:#deny_usr_agreement_btn#:#Elutasítás common#:#department#:#Tagozat / Szak / Évfolyam common#:#desc#:#Leírás common#:#description#:#Leírás common#:#desired_password#:#Új jelszó common#:#details#:#Részletek -common#:#didactic_template#:#Didactic Template###29 07 2022 new variable +common#:#didactic_template#:#Didaktikai sablon common#:#disable#:#Tiltás common#:#disable_check#:#Tiltás ellenőrzése common#:#disable_ext_lang_maint#:#Haladó nyelvi karbantartó kikapcsolása common#:#disable_hide_user_toggle#:#A tagnak nem engedélyezett az értesítés letiltása -common#:#disabled#:#Tiltott +common#:#disabled#:#Ki van kapcsolva common#:#disclose#:#Felfedés common#:#dislike#:#Nem kedvel common#:#domain#:#Tartomány @@ -3937,24 +3968,24 @@ common#:#download_link#:#Letöltési link common#:#download_multiple_objects#:#Több objektum letöltése common#:#download_selected_items#:#Letöltés common#:#downloading_settings#:#Letöltési beállítások -common#:#dpro_accept_usr_agreement#:#Accept Declaration of Data Protection?###26 08 2024 new variable -common#:#dpro_accept_usr_agreement_intro#:#There is a new Declaration of Data Protection. You need to accept it before proceeding with the use of ILIAS. Read the following document carefully and give your consent or dissent at the bottom of the page.###26 08 2024 new variable -common#:#dpro_agreed_on#:#DoDP agreed to on###29 10 2025 new variable -common#:#dpro_force_accept_usr_agreement#:#You must accept the Declaration of Data Protection!###26 08 2024 new variable -common#:#dpro_no_agreement_description#:#There is currently no Declaration of Data Protection document available for this installation. Please contact the system administrator.###26 08 2024 new variable -common#:#dpro_refuse_acceptance#:#Refuse to Accept the Declaration of Data Protection###26 08 2024 new variable -common#:#dpro_usr_agreement#:#Declaration of Data Protection###26 08 2024 new variable -common#:#dpro_usr_agreement_footer_intro#:#You have declared your consent to this Declaration of Data Protection.###26 08 2024 new variable -common#:#dpro_withdraw_consent_description#:#Withdraw your consent to our Declaration of Data Protection here.###26 08 2024 new variable -common#:#dpro_withdraw_consent_description_external#:#Please return to your ILIAS installation and log in again to complete the process of withdrawing your consent to the Declaration of Data Protection.###26 08 2024 new variable -common#:#dpro_withdraw_consent_description_internal#:#Please log in again to complete the process of withdrawing your consent to the Declaration of Data Protection.###26 08 2024 new variable -common#:#dpro_withdraw_consent_header#:#Withdraw to Consent of Declaration of Data Protection###26 08 2024 new variable -common#:#dpro_withdraw_consent_info#:#Withdraw your consent to our Declaration of Data Protection.###26 08 2024 new variable -common#:#dpro_withdraw_consent_info_external#:#Please contact the administrator of your authentication system and inform them of your intention to withdraw your consent to the Declaration of Data Protection.###26 08 2024 new variable -common#:#drafts#:#Vázlatok +common#:#dpro_accept_usr_agreement#:#Elfogadja az Adatvédelmi Nyilatkozatot? +common#:#dpro_accept_usr_agreement_intro#:#Az Adatvédelmi Nyilatkozat módosult. El kell fogadnia az ILIAS további használata előtt. Olvassa el figyelmesen, és fogadja vagy utasítsa el az oldal alján lévő gomb használatával. +common#:#dpro_agreed_on#:#Elfogadva ekkor: +common#:#dpro_force_accept_usr_agreement#:#El kell fogadnia az Adatvédelmi Nyilatkozatot! +common#:#dpro_no_agreement_description#:#Jelenleg nem érhető el Adatvédelmi Nyilatkozat. Kérem, keresse az üzemeltetőt. +common#:#dpro_refuse_acceptance#:#Az Adatvédelmi Nyilatkozat elutasítása +common#:#dpro_usr_agreement#:#Adatvédelem +common#:#dpro_usr_agreement_footer_intro#:#Elfogadta az Adatvédelmi Nyilatkozatban foglaltakat +common#:#dpro_withdraw_consent_description#:#Vonja vissza itt az Adatvédelmi Nyilatkozatban foglaltak elfogadását +common#:#dpro_withdraw_consent_description_external#:#Kérem, térjen vissza az ILIAS-telepítésbe és jelentkezzen be újra, hogy befejezze az Adatvédelmi Nyilatkozat elfogadásának visszavonási folyamatát. +common#:#dpro_withdraw_consent_description_internal#:#Jelentkezzen be újra, hogy befejezze az Adatvédelmi Nyilatkozat elfogadásának visszavonási folyamatát. +common#:#dpro_withdraw_consent_header#:#Az Adatvédelmi Nyilatkozat elfogadásának visszavonása +common#:#dpro_withdraw_consent_info#:#Az Adatvédelmi Nyilatkozat elfogadásának visszavonása +common#:#dpro_withdraw_consent_info_external#:#Kérem, tájékoztassa a hitelesítő rendszer üzemeltetőjét az Adatvédelmi Nyilatkozat elfogadásának visszavonási szándékáról. +common#:#drafts#:#Piszkozatok common#:#drag_file_here#:#Ide fogd-és-vidd a fájlt common#:#drag_files_here#:#Ide fogd-és-vidd a fájlokat -common#:#drag_handle#:#Draggable element###29 10 2025 new variable +common#:#drag_handle#:#Mozgatható elem common#:#drop_files_on_repo_obj_info#:#Ide fogd-és-vidd a fájlokat a feltöltéshez common#:#edit#:#Módosítás common#:#edit_assignments#:#Feladatok módosítása @@ -3974,40 +4005,40 @@ common#:#email#:#E-mail cím common#:#email_not_valid#:#A megadott e-mail cím hibás. common#:#enable#:#Engedélyezés common#:#enable_anonymous_fora#:#Hozzászólás álnéven engedélyezve -common#:#enable_anonymous_fora_desc#:#Ha ez a beállítás le van tiltva, a 'Hozzászólás álnéven' nem lesz elérhető a továbbiakban a fórumokban. +common#:#enable_anonymous_fora_desc#:#Ha ez a beállítás le van tiltva, a ‘Hozzászólás álnéven’ nem lesz elérhető a továbbiakban a fórumokban. common#:#enable_calendar#:#Naptár engedélyezése -common#:#enable_comments_export#:#Enable Comments Export +common#:#enable_comments_export#:#Hozzászólások exportálása common#:#enable_course_group_notifications#:#Napi e-mail csoport- és kurzushírekhez -common#:#enable_course_group_notifications_desc#:#Ha be van kapcsolva, a tagok feliratkozhatnak napi összesítő hírekre. +common#:#enable_course_group_notifications_desc#:#A tagok feliratkozhatnak napi összesítő hírekre. common#:#enable_custom_icons#:#Ikonbeállítások engedélyezése -common#:#enable_custom_icons_info#:#Ikonok definiálásának engedélyezése egyszerű tárolóobjektumokhoz és tartalomlap objektumhoz. Ezen objektumok tulajdonságok része lehetőséget fog nyújtani képek feltöltéséhez. -common#:#enable_dnd_upload#:#'Fogd-és-vidd' feltöltés engedélyezése -common#:#enable_dnd_upload_info#:#Ha be van kapcsolva, fájlok 'fogd-és-vidd' módon feltölthetőek a számítógépről. +common#:#enable_custom_icons_info#:#Ikonok definiálásának engedélyezése egyszerű tárolóobjektumokhoz és tartalomlap objektumhoz. Ezen objektumok Beállítások lapján lehetőség nyílik ikonkép feltöltéséhez. +common#:#enable_dnd_upload#:#‘Fogd-és-vidd’ feltöltés engedélyezése +common#:#enable_dnd_upload_info#:#Fájlok ‘fogd-és-vidd’ módon feltölthetőek a számítógépről. common#:#enable_download_folder#:#Mappa letöltésének engedélyezése -common#:#enable_download_folder_info#:#A mappa 'Műveletek' legördülő menüjében a 'Letöltés' bekapcsolása. +common#:#enable_download_folder_info#:#A mappa ‘Műveletek’ legördülő menüjében a ‘Letöltés’ bekapcsolása. common#:#enable_export_scorm_desc#:#Személyes adat megjelenítése a protokolladatban (SCORM) common#:#enable_fora_statistics#:#Statisztika engedélyezése a fórumban common#:#enable_fora_statistics_desc#:#Ha nem engedélyezett, senki nem éri el a fórumstatisztikát. common#:#enable_hide_user_toggle#:#A tagnak nem engedélyezett az értesítés letiltása -common#:#enable_multi_download#:#«Több objektum letöltése» engedélyezése +common#:#enable_multi_download#:#‘Több objektum letöltése’ engedélyezése common#:#enable_multi_download_info#:#Több mappa/fájl zip-archívumként történő letöltésének engedélyezése. common#:#enable_password_assistance#:#Jelszósegédlet engedélyezése common#:#enable_preview#:#Előnézet engedélyezése common#:#enable_preview_info#:#Engedélyezi, hogy támogatott fájltípusoknak legyen előnézete. common#:#enable_repository_dnd_upload#:#Engedélyezés a Tartalomtárban -common#:#enable_repository_dnd_upload_info#:#Engedélyezi, hogy fájlok 'fogd-és-vidd' módon feltölthetőek legyenek a számítógépről közvetlenül a Tartalomtár objektumába. +common#:#enable_repository_dnd_upload_info#:#Engedélyezi, hogy fájlok ‘fogd-és-vidd’ módon feltölthetőek legyenek a számítógépről közvetlenül a Tartalomtár objektumába. common#:#enable_sahs_protocol_data#:#Protokolladatok bekapcsolása common#:#enable_sahs_protocol_data_desc#:#Protokolladatok megjelenítése (SCORM) -common#:#enable_search_engine#:#Nyilvános terület internetes keresőmotoroknak (például Google).
    Az Apache modul 'mod_rewrite' szükséges hozzá. Ügyeljen arra, hogy megfelelő jogosultságai legyenek a .htaccess konfigurációk használatához. +common#:#enable_search_engine#:#Nyilvános terület internetes keresőmotoroknak (például Google).
    Az Apache modul ‘mod_rewrite’ szükséges hozzá. Ügyeljen arra, hogy megfelelő jogosultságai legyenek a .htaccess konfigurációk használatához. common#:#enable_trash#:#Lomtár bekapcsolása -common#:#enable_trash_info#:#Ha be van kapcsolva, a törölt objektumok a lomtárba kerülnek, és később visszaállíthatóak. Ha nem engedélyezett, a törölt objektumok visszavonhatatlanul törlődnek a rendszerből. +common#:#enable_trash_info#:#A törölt objektumok a lomtárba kerülnek, és később visszaállíthatók. Ha nem engedélyezett, a törölt objektumok visszavonhatatlanul törlődnek a rendszerből. common#:#enable_webdav#:#WebDAV elérés engedélyezése -common#:#enable_webdav_info#:#A WebDAV klienseknek engedély a Tartalomtár webmappaként való eléréséhez. A felhasználók a webmappákat a 'megnyitás webmappaként' paranccsal nyithatják meg a Tartalomtárban, vagy a következő címen belépve egy WebDAV kliensben: %1$s +common#:#enable_webdav_info#:#A WebDAV klienseknek engedély a Tartalomtár webmappaként való eléréséhez. A felhasználók a webmappákat a ‘megnyitás webmappaként’ paranccsal nyithatják meg a Tartalomtárban, vagy a következő címen belépve egy WebDAV kliensben: %1$s common#:#enabled#:#Engedélyezve -common#:#enlarge#:#Enlarge###28 10 2024 new variable +common#:#enlarge#:#Nagyítás common#:#enter_in_mb_desc#:#Adjon meg egy értéket MB-ban. common#:#enter_new_name#:#Adjon meg egy nevet -common#:#entered_notification#:#'%s' csatlakozott '%s' eseményhez. +common#:#entered_notification#:#‘%s’ csatlakozott ‘%s’ eseményhez. common#:#entry_status#:#Bejegyzés állapota common#:#err_1_param#:#Csak 1 paramétert! common#:#err_2_param#:#Csak 2 paramétert! @@ -4017,19 +4048,19 @@ common#:#err_auth_mode_inactive#:#Az Ön hitelesítési módszere ki van kapcsol common#:#err_auth_soap_no_ilias_user#:#Bejelentkezés sikertelen. A SOAP-hitelesítés sikeres, de nincs megfelelő ILIAS-felhasználó. Vegye fel a kapcsolatot egy rendszergazdával! common#:#err_check_input#:#Beállítások nem menthetők. Ellenőrizze a bemeneti értékeket. common#:#err_count_param#:#Ok: hibás paraméterszám -common#:#err_disabled#:#Account creation via Shibboleth has been disabled. Please contact the system administrator for further information.###28 10 2024 new variable -common#:#err_double_entries#:#Reason: Duplicate Entries###26 08 2024 new variable +common#:#err_disabled#:#A Shibboleth keresztüli fióklétrehozás ki van kapcsolva. További információkért keresse a rendszer üzemeltetőjét. +common#:#err_double_entries#:#Ok: Duplikált bejegyzés common#:#err_in_line#:#Hiba a sorban. -common#:#err_inactive#:#Ez az ILIAS-fiók még nincs aktiválva. Vegye fel a kapcsolatot egy rendszergazdával! -common#:#err_inactive_login_attempts#:#Felhasználói fiókját túl sok sikertelen bejelentkezési kísérlet miatt letiltottuk. Kattintson a láblécben lévő 'Kapcsolat' lehetőségre, hogy az üzemeltetőt megkérje ILIAS-fiókjának újraaktiválására. +common#:#err_inactive#:#Ezt az ILIAS-fiókot még nem aktiválták. Vegye fel a kapcsolatot egy rendszergazdával! +common#:#err_inactive_login_attempts#:#Felhasználói fiókját túl sok sikertelen bejelentkezési kísérlet miatt letiltottuk. Kattintson a láblécben lévő ‘Kapcsolat’ lehetőségre, hogy az üzemeltetőt megkérje ILIAS-fiókjának újraaktiválására. common#:#err_invalid_port#:#Érvénytelen port! common#:#err_no_cookies#:#Engedélyezze böngészőjében a sütiket munkamenetéhez! common#:#err_no_langfile_found#:#Nem található nyelvi fájl. common#:#err_no_param#:#Nincs paraméter. common#:#err_over_3_param#:#Több, mint 3 paraméter szükséges. -common#:#err_role_not_assignable#:#A felhasználók nem rendelhetők hozzá ehhez a szerephez ezen a területen. +common#:#err_role_not_assignable#:#A felhasználók nem rendelhetők hozzá ehhez a szerepkörhöz ezen a területen. common#:#err_session_expired#:#Munkamenete lejárt. -common#:#err_valid_login_account_creation_disabled#:#Authentication succeeded, but the creation of new user accounts is currently disabled. Please contact your system administrator.###29 07 2022 new variable +common#:#err_valid_login_account_creation_disabled#:#A hitelesítés sikerült, de az új felhasználói fiók létrehozásának lehetősége ki van kapcsolva. Kérjük, keresse fel az üzemeltetőket. common#:#err_wrong_header#:#Ok: hibás fejléc. common#:#err_wrong_login#:#Hibás felhasználónév vagy jelszó. common#:#err_wrong_password#:#Hibás jelszó @@ -4038,7 +4069,7 @@ common#:#error_empty_file_or_folder#:#A fájl valójában mappa vagy a mérete 0 common#:#error_extraction_failed#:#Az archívum fájl (és mappa) kicsomagolása sikertelen. Valószínűleg nincs jogosultsága mappát vagy kategóriákat létrehozni az objektum alá. common#:#error_parser#:#Hiba történt a szintaktikai elemző indulásakor. common#:#error_upload_was_zero_bytes#:#A feltöltés sikertelen, mert a fájl valójában mappa, vagy mérete 0 byte, vagy mérete meghaladja a feltölthet maximumot, vagy átnevezték. -common#:#etal_talks#:#Talks +common#:#etal_talks#:#Megbeszélés common#:#event_ass_materials_prop#:#Esemény segédanyagai common#:#event_assign_files#:#Fájlhozzárendelés common#:#exc#:#Beadandó feladat @@ -4055,7 +4086,7 @@ common#:#exc_files#:#Fájlok common#:#exc_files_returned#:#Beküldött fájl(ok) common#:#exc_instruction#:#Feladatleírás common#:#exc_last_submission#:#Utolsó megoldás -common#:#exc_member_of_crs_grp#:#Member in Course/Group###26 08 2024 new variable +common#:#exc_member_of_crs_grp#:#Kurzus/Csoport tagja common#:#exc_members_already_assigned#:#Ezek a felhasználók már hozzá vannak rendelve ezen beadandó feladathoz. common#:#exc_members_assigned#:#Tagokat sikeresen hozzárendelte. common#:#exc_members_comments_saved#:#A kiválasztott felhasználók számára a beadandó feladathoz tartozó megjegyzést sikeresen mentette. @@ -4085,7 +4116,7 @@ common#:#export_format#:#Export formátum common#:#export_html#:#Exportálás HTML-fájlként common#:#ext_cat_settings#:#Fejlettebb kategória-beállítások módosítása common#:#ext_link#:#Link -common#:#extracting#:#Kicsomagolás... +common#:#extracting#:#Kicsomagolás… common#:#eyeclosed#:#Szem bezárása - Kattintson a bemenet tartalmának elrejtéséhez common#:#eyeopened#:#Szem megnyitása - Kattintson a bemenet tartalmának megjelenítéséhez common#:#failure_message#:#Hibaüzenet @@ -4107,26 +4138,26 @@ common#:#file_info#:#Fájlinformációk common#:#file_is_infected#:#A fájl vírussal fertőzött. common#:#file_no_valid_file_type#:#Ez a fájltípus nem engedélyezett. common#:#file_not_found#:#A fájl nem található -common#:#file_not_found_sec#:#This file cannot be found in ILIAS or has been blocked due to security reasons.###29 07 2022 new variable +common#:#file_not_found_sec#:#Ez a fájl nem található vagy biztonsági okok miatt letitottuk a hozzáférést. common#:#file_not_valid#:#A fájl nem érvényes. common#:#file_notice#:#Maximális feltölthető méret: -common#:#file_objects#:#File Objects -common#:#file_rollback#:#Ez legyen az aktuális verzió -common#:#file_rollback_done#:#%s. fájlverzió lett az aktuális. -common#:#file_rollback_select_exact_one#:#Csak egy verziót választhat, hogy az az aktuális legyen. +common#:#file_objects#:#Fájlobjektumok +common#:#file_rollback#:#Ezen verzió közzététele +common#:#file_rollback_done#:#%s. fájlverzió lett a közzétett. +common#:#file_rollback_select_exact_one#:#Csak egy verziót választhat, hogy az legyen közzétett. common#:#file_some_invalid_file_types_removed#:#Néhány fájltípus nem engedélyezett és ezért eltávolítottuk. common#:#file_suffix_repl#:#Fájlfeltöltés a kiterjesztés változtatásával -common#:#file_suffix_repl_info#:#Adjon meg fájlokat kiterjesztésükkel (vesszővel elválasztva), amelyeket, hogy ne legyenek futtatható fájlok, '.sec' kiterjesztésűre kell átnevezni a webhelyre feltöltéskor. A kiterjesztés változtatása alapértelmezetten az alábbi kiterjesztésekre történik meg: -common#:#file_system_clean_temp_dir_cron#:#Clean temp directory###29 07 2022 new variable -common#:#file_system_clean_temp_dir_cron_info#:#This job cleans the ILIAS temp-directory of files, which are older than 10 days. This counteracts the accumulation of unused files and therefore prevents an increased use of disk space by the temp directory.###29 07 2022 new variable +common#:#file_suffix_repl_info#:#Adjon meg fájlokat kiterjesztésükkel (vesszővel elválasztva), amelyeket, hogy ne legyenek futtatható fájlok, ‘.sec’ kiterjesztésűre kell átnevezni a webhelyre feltöltéskor. A kiterjesztés változtatása alapértelmezetten az alábbi kiterjesztésekre történik meg: +common#:#file_system_clean_temp_dir_cron#:#Ideiglenes könyvtár tisztítása +common#:#file_system_clean_temp_dir_cron_info#:#A 10 napnál régebbi ideiglenes fájlok törlése, ami megakadályozza a felesleges tárhely-foglalást. common#:#file_updated#:#A fájl módosult. common#:#file_upload_pending#:#Függőben levő fájl common#:#file_valid#:#A fájl érvényes. common#:#file_version#:#Verziókövetés elérhető. common#:#file_version_create#:#Első verzió -common#:#file_version_intermediate_version#:#Intermediate Version###26 08 2024 new variable +common#:#file_version_intermediate_version#:#Köztes verzió common#:#file_version_new_version#:#Új verzió -common#:#file_version_published_version#:#Published Version###26 08 2024 new variable +common#:#file_version_published_version#:#Közzétett verzió common#:#file_version_replace#:#Összes verziót lecserélte common#:#file_version_rollback#:#Visszaállította %s. verziót %s common#:#file_versions_deleted#:#A kiválasztott fájlverziókat sikeresen törölte. @@ -4165,7 +4196,7 @@ common#:#folders#:#Mappák common#:#follow_link_to_read_mails#:#kattintson az alábbi linkre a levelet olvasásához: common#:#forgot_password#:#Elfelejtette jelszavát? common#:#forgot_username#:#Elfelejtette felhasználónevét? -common#:#form_input_not_valid#:#Néhány adat hiányzik vagy nem megfelelő. Javítsa az űrlapadatokat! +common#:#form_input_not_valid#:#Néhány információ hiányzik vagy nem megfelelő. Javítsa az adatokat! common#:#forum#:#Fórum common#:#forum_direct_notification#:#Értesítés common#:#forum_notify_me#:#Értesítést kérek ehhez a hozzászólásra érkező válaszokról. Ebben a témában, illetve fórumban született bármely hozzászólásról értesítés a jobb felső sarokban lévő Műveletek menüben kapcsolható be. @@ -4174,20 +4205,20 @@ common#:#forums#:#Fórumok common#:#forums_anonymized#:#Anonimizált fórum common#:#forums_anonymous#:#anonym common#:#forums_articles#:#Hozzászólások -common#:#forums_closed#:#closed###26 08 2024 new variable +common#:#forums_closed#:#lezárt common#:#forums_disable_forum_notification#:#Értesítés lemondása ehhez a fórumhoz common#:#forums_enable_forum_notification#:#Értesítés kérése ehhez a fórumhoz common#:#forums_forum_notification_enabled#:#Értesítést fog kapni, ha új hozzászólás keletkezik ebben a fórumban. common#:#forums_last_post#:#Utolsó hozzászólás -common#:#forums_last_posting_asc#:#Last Post Ascending###26 08 2024 new variable -common#:#forums_last_posting_dsc#:#Last Post Descending###26 08 2024 new variable +common#:#forums_last_posting_asc#:#Utolsó bejegyzés ↑ +common#:#forums_last_posting_dsc#:#Utolsó bejegyzés ↓ common#:#forums_notification_settings#:#Fórumértesítések beállításai -common#:#forums_rating_asc#:#Rating Ascending###26 08 2024 new variable -common#:#forums_rating_dsc#:#Rating Descending###26 08 2024 new variable -common#:#forums_thread_sorting_asc#:#Thread Title A→Z###26 08 2024 new variable -common#:#forums_thread_sorting_dsc#:#Thread Title Z→A###26 08 2024 new variable +common#:#forums_rating_asc#:#Értékelés ↑ +common#:#forums_rating_dsc#:#Értékelés ↓ +common#:#forums_thread_sorting_asc#:#Téma címe A→Z +common#:#forums_thread_sorting_dsc#:#Téma címe Z→A common#:#forums_threads#:#Témák -common#:#forums_use_alias#:#Használhat álnevet a hozzászóláshoz. Ha üresen hagyja ezt a mezőt, a hozzászólás írója anonymous lesz. +common#:#forums_use_alias#:#Használhat álnevet a hozzászóláshoz. Ha üresen hagyja ezt a mezőt, a hozzászólás írója ‘%s’ lesz. common#:#forums_your_name#:#Az Ön neve common#:#frm#:#Fórum common#:#frm_add#:#Fórum létrehozása @@ -4196,7 +4227,7 @@ common#:#frm_edit#:#Fórum módosítása common#:#frm_import#:#Fórum importálása common#:#frm_latest_postings#:#Legújabb hozzászólások common#:#frm_new#:#Új fórum -common#:#frm_no_threads#:#There are no threads available at the moment.###26 08 2024 new variable +common#:#frm_no_threads#:#Jelenleg egy téma sem található common#:#from#:#Ettől common#:#fullname#:#Teljes név common#:#functions#:#Funkciók @@ -4207,22 +4238,22 @@ common#:#gender#:#Megszólítás common#:#gender_f#:#Nő common#:#gender_m#:#Férfi common#:#gender_n#:#Nincs megszólítás -common#:#general#:#General###26 08 2024 new variable +common#:#general#:#Általános common#:#general_settings#:#Általános beállítások common#:#generate#:#Generálás -common#:#ghostscript_not_configured#:#GhostScript nincs konfigurálva. Nyissa meg a Setup-ot a konfiguráláshoz. +common#:#ghostscript_not_configured#:#GhostScript nincs konfigurálva. Nyissa meg a Setup-ot a konfiguráláshoz. common#:#glo#:#Fogalomtár common#:#glo_add#:#Fogalomtár létrehozása common#:#glo_added#:#Sikeresen létrehozott egy fogalomtárat. common#:#glo_import#:#Fogalomtár importálása common#:#glo_mode#:#Mód common#:#glo_mode_desc#:#A virtuális fogalomtár úgy működik, mint a normál fogalomtár. A főbb különbség az, hogy a virtuális tartalmazza a Tartalomtárban vele azonos szinten, illetve a pozíciójától lejjebb elhelyezkedő fogalomtárak fogalmait is. -common#:#glo_mode_normal#:#normál +common#:#glo_mode_normal#:#Általános forgalomtár common#:#glo_new#:#Új fogalomtár common#:#global#:#Globális common#:#global_default#:#Globális alapértelmezett common#:#global_fixed#:#Globálisan meghatározott -common#:#global_role_assignment#:#Globális szerep-hozzárendelés +common#:#global_role_assignment#:#Globális szerepkör hozzárendelése common#:#global_settings#:#Globális beállítások common#:#global_user#:#Globális felhasználók common#:#glossaries#:#Fogalomtárak @@ -4243,15 +4274,15 @@ common#:#group_status#:#A csoportállapot common#:#groupings#:#Tagságkorlátozások common#:#groupings_assigned_obj_crs#:#Hozzárendelt kurzusok common#:#groupings_assigned_obj_grp#:#Hozzárendelt csoportok -common#:#groupings_source#:#Source###29 10 2025 new variable +common#:#groupings_source#:#Forrás common#:#groups#:#Csoportok common#:#grp#:#Csoport common#:#grp_add#:#Csoport létrehozása common#:#grp_added#:#Sikeresen létrehozott egy csoportot. common#:#grp_btn_unsubscribe#:#Kilépés a csoportból -common#:#grp_cancel_waiting_list#:#Biztos, hogy leveszi magát a(z) '%s' csoport várólistájáról? +common#:#grp_cancel_waiting_list#:#Biztos, hogy leveszi magát a(z) ‘%s’ csoport várólistájáról? common#:#grp_copy_threads_info#:#Döntse el, mely segédanyagok lesznek másolva, csatolva vagy kihagyva. -common#:#grp_deleted_export_files#:#Kiválasztott fájlokat sikeresen törölte. +common#:#grp_deleted_export_files#:#Kiválasztott fájl(oka)t sikeresen törölte. common#:#grp_dismiss_member#:#Biztos, hogy eltávolítja a csoportból alábbi tagokat? common#:#grp_dismiss_myself#:#Biztos, hogy leiratkozik a csoportból? common#:#grp_edit#:#Csoport módosítása @@ -4275,19 +4306,19 @@ common#:#grp_msg_membership_annulled#:#Tagságát töröltük. common#:#grp_new#:#Új csoport common#:#grp_registration#:#Csatlakozás csoporthoz common#:#grp_registration_completed#:#Csatlakozott a csoporthoz. -common#:#grp_removed_from_waiting_list#:#Lekerült a(z) '%s' csoport várólistájáról. +common#:#grp_removed_from_waiting_list#:#Lekerült a(z) ‘%s’ csoport várólistájáról. common#:#grp_select_one_file#:#Válasszon egy fájlt! common#:#grp_wizard_page#:#Csoport másolása (2/2. lépés) common#:#grpr#:#Csoportlink -common#:#grpr_add#:#Add Group Link###29 07 2022 new variable +common#:#grpr_add#:#Csoportlink hozzáadása common#:#grpr_edit#:#Csoportlink módosítása common#:#grpr_edit_info#:#Válasszon egy csoportot egy új link létrehozásához. common#:#grpr_new#:#Csoportlink létrehozása -common#:#grpr_settings#:#Group Link Settings###26 08 2024 new variable -common#:#header_action#:#Insert Heading - Click to insert a heading.###26 08 2024 new variable +common#:#grpr_settings#:#Csoportlink beállításai +common#:#header_action#:#Címsor beillesztése - Kattintson címsor beillesztéséhez. common#:#header_searchable#:#Kereshető common#:#header_title#:#Fejléccím -common#:#header_visible_registration#:#Látható a 'Regisztráció' alatt +common#:#header_visible_registration#:#Látható a ‘Regisztráció’ alatt common#:#header_zip#:#Több fájl feltöltése ZIP formátumban common#:#height#:#Magasság common#:#help#:#Súgó @@ -4319,9 +4350,9 @@ common#:#icon_settings#:#Egyéni ikonok common#:#id#:#azonosító (ID) common#:#identifier#:#azonosító common#:#if_no_title_then_filename#:#Hagyja üresen, ha címként a fájl nevét szeretné megjeleníteni. -common#:#ignore_on_conflict#:#Ellentmondás figyelmen kívül hagyása +common#:#ignore_on_conflict#:#A beszúrási/frissítési művelet szigorúan betartása common#:#ignore_required_fields#:#Kötelező mezők figyelmen kívül hagyása -common#:#ignore_required_fields_info#:#Ha be van kapcsolva, ezt a űrlapot az összes kötelező mező kitöltése nélkül elküldheti. A felhasználóknak a következő bejelentkezésükkor kell megadniuk a személyes adataikban hiányzó információkat. +common#:#ignore_required_fields_info#:#Ezt a űrlapot az összes kötelező mező kitöltése nélkül elküldheti. A felhasználóknak a következő bejelentkezésükkor kell megadniuk a személyes adataikban hiányzó információkat. common#:#il_astpl_loc_initial#:#Belépő teszt common#:#il_astpl_loc_qualified#:#Záró teszt common#:#il_blog_contributor#:#Blogszerző @@ -4336,30 +4367,30 @@ common#:#il_grp_admin#:#Csoportvezető common#:#il_grp_member#:#Csoporttag common#:#il_grp_status_closed#:#Zárt csoport common#:#il_grp_status_open#:#Nyílt csoport -common#:#il_iass_member#:#Participant###29 10 2025 new variable +common#:#il_iass_member#:#Résztvevő common#:#il_lso_admin#:#Tanulás sor vezetője common#:#il_lso_member#:#Tanulási sor tagja -common#:#il_lti_instructor#:#LTI Instructor###29 07 2022 new variable -common#:#il_lti_learner#:#LTI Learner###29 07 2022 new variable -common#:#il_lti_user#:#LTI User###29 10 2025 new variable +common#:#il_lti_instructor#:#LTI-Instruktor +common#:#il_lti_learner#:#LTI-Tanuló +common#:#il_lti_user#:#LTI-Felhasználó common#:#il_orgu_employee#:#Beosztott common#:#il_orgu_superior#:#Felettes common#:#ilias_version#:#ILIAS-verzió common#:#image#:#Kép common#:#import#:#Import -common#:#import_cat_localrol#:#Helyi szerep létrehozása minden új kategóriához +common#:#import_cat_localrol#:#Helyi szerepkör létrehozása minden új kategóriához common#:#import_cat_table#:#Az alábbi táblázat csak akkor nyújt érdemleges adatokat, ha a jelölőnégyzet be van jelölve. common#:#import_categories#:#Kategóriák importja common#:#import_failure_log#:#Hibanapló importálása common#:#import_file#:#Importfájl -common#:#import_file_not_valid_here#:#Az importfájl nem érvényes. +common#:#import_file_not_valid_here#:#Az importfájl érvénytelen, vagy a benne lévő objektumtípus nem importálható ide. common#:#import_finished#:#Importált üzenetek száma. common#:#import_lm#:#ILIAS-tananyag importja common#:#import_qpl#:#Tesztkérdésgyűjtemény importálása common#:#import_questions_into_qpl#:#Kérdés(ek) importálása kérdésgyűjteménybe common#:#import_sahs#:#SCORM-csomag importálása -common#:#import_sahs_info#:#To correct typos or images, use the option to replace individual files via the file directory. Upload a SCORM export from your authoring tool here and not an ILIAS export file. Make sure that your authoring tool has retained the IDs in the manifest file. Attention: Even popular authoring tools cannot do this. SCORM learning modules of certain authoring tools discard learner data obtained if you change the number of answer options of questions or insert new questions. Check in a test installation whether learning statuses that have already been achieved are possible when learning modules that have already been started are called up again.###26 08 2024 new variable -common#:#import_sahs_new#:#Import New Version of SCORM Package###26 08 2024 new variable +common#:#import_sahs_info#:#Az elírások vagy képek kijavításához használja az egyes fájlok cseréjét a fájlkönyvtáron keresztül. Töltsön fel ide egy SCORM-export fált, ami megőrizte az azonosítókat a manifest fájlban. Figyelem: Erre még a népszerű SCORM előállító alkalmazások sem mind képesek. Egyes szerzői eszközök SCORM tanulási moduljai eldobját a már meglévő tanulói adatokat, ha módosítja a kérdések válaszlehetőségeinek számát, vagy új kérdéseket szúr be. Egy teszttelepítés során ellenőrizze, hogy nem veszik-e el a már elért tanulási állapot, amikor a már elindított tananyagokat ismét megnyitja. +common#:#import_sahs_new#:#SCORM csomag új verziójának importálása common#:#import_svy#:#Kérdőív importálása common#:#import_tst#:#Teszt importálása common#:#import_users#:#Felhasználók importálása @@ -4379,14 +4410,14 @@ common#:#info_access_permissions#:#Elérési jogosultságok common#:#info_activate_sure#:#Biztos, hogy aktiválja az alábbi felhasználó(ka)t? common#:#info_assign_sure#:#Biztos, hogy hozzárendeli az alábbi felhasználó(ka)t? common#:#info_assigned#:#hozzárendelve -common#:#info_available_roles#:#Rendelkezésre álló szerepek +common#:#info_available_roles#:#Rendelkezésre álló szerepkörök common#:#info_change_user_view#:#Felhasználó cseréje common#:#info_deactivate_sure#:#Biztos, hogy nem hagyja jóvá, hogy az alábbi felhasználó(k) aktív felhasználó(k) legyenek? common#:#info_delete_sure#:#Biztos, hogy törli az alábbi elem(ek)et? common#:#info_delete_warning_no_trash#:#(FIGYELMEZTETÉS: A kiválasztott objektumok visszavonhatatlanul töröljük a rendszerből, így azokat később már nem lehet visszaállítani. common#:#info_deleted#:#Az objektumo(ka)t sikeresen törölte. -common#:#info_err_user_not_exist#:#Ezzel a felhasználónévvel vagy felhasználó-ID-vel nincs felhasználó. -common#:#info_from_role#:#Szereptagságon / tulajdonjogon keresztül biztosított +common#:#info_err_user_not_exist#:#Ezzel a felhasználónévvel vagy user_id-vel nincs felhasználó. +common#:#info_from_role#:#Szerepkörtagságon / tulajdonjogon keresztül biztosított common#:#info_is_member#:#A felhasználó tag common#:#info_is_not_member#:#A felhasználó nem tag common#:#info_message#:#Információs üzenet @@ -4394,11 +4425,11 @@ common#:#info_not_assigned#:#nincs összerendelve common#:#info_owner_of_object#:#Tulajdonos common#:#info_permission_origin#:#Származási helye common#:#info_permission_source#:#Innentől lép érvénybe* -common#:#info_remark_interrupted#:#A szerep itt helyivé válik. A szerep érvényben lévő alapértelmezett jogosultságait ezen a helyen definiálták. +common#:#info_remark_interrupted#:#A szerepkör itt helyivé válik. A szerepkör érvényben lévő alapértelmezett jogosultságait ezen a helyen definiálták. common#:#info_remove_sure#:#Biztos, hogy eltávolítja az alábbi elem(ek)et? common#:#info_short#:#Információ common#:#info_status_info#:#Felhasználó jogosultságai -common#:#info_view_of_user#:#Felhasználó +common#:#info_view_of_user#:#Felhasználói menü common#:#inform_user_mail#:#Felhasználó értesítése a módosításról common#:#inline_file_extensions#:#Böngészőben megjelenítendő fájlok common#:#inline_file_extensions_info#:#Az ezekkel a kiterjesztésekkel rendelkező fájlok böngészőablakban jelennek meg.
    Például: gif jpg mp3 pdf png
    Minden további fájlt letöltésre ajánlunk fel. @@ -4409,31 +4440,30 @@ common#:#inst_info#:#Telepítési információ common#:#inst_name#:#Telepítési név common#:#install#:#Telepítés common#:#install_local#:#Telepítés egyéni nyelvi fájllal -common#:#installation_status#:#Installation Status###29 07 2022 new variable +common#:#installation_status#:#Telepítési állapot common#:#installed#:#Telepítve common#:#installed_local#:#Egyéni nyelvi fájllal telepítve common#:#instant_messengers#:#Azonnali üzenetküldő alkalmazások common#:#institution#:#Intézmény -common#:#internal_local_roles_only#:#Helyi szerepek (csak automatikusan létrejöttek) -common#:#invalid_visible_required_options_selected#:#Minden kitöltendő mezőt láthatóvá kell tenni a 'Regisztráció' alatt is. +common#:#internal_local_roles_only#:#Helyi szerepkörök (csak automatikusan létrejöttek) +common#:#invalid_visible_required_options_selected#:#Minden kitöltendő mezőt láthatóvá kell tenni a ‘Regisztráció’ alatt is. common#:#invisible_block#:#Nem látható blokk common#:#invisible_block_mess#:#Nincs jogosultsága ennek a blokknak a megtekintésére. common#:#ip_address#:#IP-cím common#:#is_already_your#:#már az Ön -common#:#italic_action#:#Insert Italic - Click to insert italic text.###26 08 2024 new variable +common#:#italic_action#:#Dőlt beillesztése - Kattintson dőlt szöveg beillesztéséhez. common#:#item#:#Elem common#:#itgr_add#:#Objektumcsoport létrehozása common#:#itgr_new#:#Új objektumcsoport -common#:#java_server#:#Java-szerver common#:#java_server_host#:#Kiszolgáló -common#:#java_server_info#:#Ha be van kapcsolva, működik a keresés PDF, HTML-fájlokban és HTML-tananyagokban. +common#:#java_server_info#:#Keresés PDF-fájok, HTML-fájlok és HTML-tananyagok tartalmában is. common#:#java_server_port#:#Port common#:#java_server_readme#:#Setup információk common#:#join#:#Csatlakozás common#:#join_session#:#Feljelentkezés common#:#kb#:#kByte common#:#keywords#:#Kulcsszavak -common#:#label_search_options#:#Search Area###29 07 2022 new variable +common#:#label_search_options#:#Keresési terület common#:#lang_dateformat#:#Y-m-d common#:#lang_path#:#Nyelv elérési útja common#:#lang_refresh_confirm#:#Biztos, hogy frissíti az összes nyelvet? @@ -4458,7 +4488,7 @@ common#:#languages_already_installed#:#A kiválasztott nyelv(ek)et már korábba common#:#languages_already_uninstalled#:#A kiválasztott nyelv(ek)et sikeresen eltávolította. common#:#languages_updated#:#Az összes telepített nyelvet sikeresen frissítette. common#:#last_access#:#Utolsó hozzáférés -common#:#last_change#:#Utolsó változtatás +common#:#last_change#:#Utolsó módosítás common#:#last_edited_on#:#Utolsó módosítás: common#:#last_login#:#Utolsó bejelentkezés common#:#last_refresh#:#Utolsó frissítés @@ -4466,7 +4496,7 @@ common#:#last_reminder#:#Utolsó emlékeztető common#:#last_update#:#Módosítva common#:#last_visited#:#Utolsó megtekintéseim common#:#lastname#:#Utónév -common#:#latex_edit_info#:#You can enter LaTeX code in the delimiters [tex] and [/tex].###29 10 2025 new variable +common#:#latex_edit_info#:#LaTeX kódot [tex] és [/tex] közé tehet. common#:#laugh#:#Nevet common#:#launch#:#Indítás common#:#ldap#:#LDAP @@ -4483,10 +4513,10 @@ common#:#leave_waiting_list#:#Várólista elhagyása common#:#legend#:#Jelmagyarázat common#:#level#:#Szint common#:#link#:#Linkelés -common#:#link_action#:#Insert Link - Click to insert a link.###26 08 2024 new variable +common#:#link_action#:#Link beillesztése - Kattintson link beillesztéséhez common#:#link_all#:#Összeset linkel common#:#link_check#:#ILIAS-tananyagban lévő weblinkek ellenőrzése -common#:#link_check_message_b#:#Ha be van kapcsolva, levélben kap értesítést az érvénytelen linkekről. +common#:#link_check_message_b#:#Levélben kap értesítést az érvénytelen linkekről. common#:#link_check_message_disabled#:#Üzenetek tiltva common#:#link_check_message_enabled#:#Üzenetek engedélyezve common#:#link_check_subject#:#[ILIAS] Weblink-ellenőrzés @@ -4495,7 +4525,7 @@ common#:#link_selected_items#:#Linkelés common#:#links_add_param#:#Paraméter hozzáadása: common#:#links_dyn_parameter#:#Dinamikus paraméterek common#:#links_dynamic#:#Dinamikus weblink paraméterek -common#:#links_dynamic_info#:#Ha be van kapcsolva, dinamikus paraméterek fűzhetők a weblinkekhez.
    Például ILIAS felhasználói azonosító vagy felhasználónév. +common#:#links_dynamic_info#:#Dinamikus paraméterek fűzhetők a weblinkekhez.
    Például ILIAS felhasználói azonosító vagy felhasználónév. common#:#links_existing_params#:#Létező paraméterek: common#:#links_name#:#Paraméter neve common#:#links_no_name_given#:#Válasszon paraméternevet! @@ -4508,16 +4538,16 @@ common#:#links_user_name#:#ILIAS-felhasználónév common#:#links_value#:#Paraméterérték common#:#list#:#Lista common#:#list_of_questions#:#Kérdések listája -common#:#list_view#:#List View###28 10 2024 new variable -common#:#listaction_learning_progress_settings#:#Learning Progress Settings###26 08 2024 new variable +common#:#list_view#:#Lista nézet +common#:#listaction_learning_progress_settings#:#Tanulási haladás common#:#lm#:#Tananyag common#:#lm_add#:#ILIAS-tananyag létrehozása common#:#lm_added#:#Sikeresen létrehozott egy ILIAS-tananyagot. common#:#lm_new#:#Új ILIAS-tananyag common#:#lm_type_scorm#:#SCORM 1.2 common#:#lm_type_scorm2004#:#SCORM 2004 3rd/4th Edition -common#:#lm_type_scorm2004_info#:#These are newer versions of SCORM with significantly enhanced functionality. The learning module is launched in an iFrame.###26 08 2024 new variable -common#:#lm_type_scorm_info#:#This is the most widely used version of SCORM. The learning module is launched in a frame.###26 08 2024 new variable +common#:#lm_type_scorm2004_info#:#Ezek a SCORM újabb verziói jelentősen továbbfejlesztett funkcionalitásokkal. A tananyag iFrame keretben indul el. +common#:#lm_type_scorm_info#:#Ez a SCORM legszélesebb körben használt verziója. A tananyag keretben indul el. common#:#lng#:#Nyelv common#:#lngf#:#Nyelvek common#:#lo#:#Tananyagobjektum @@ -4538,7 +4568,7 @@ common#:#login_data#:#Bejelentkezési adatok common#:#login_exists#:#Már van ilyen felhasználónév. Válasszon másikat! common#:#login_invalid#:#A választott felhasználónév nem érvényes! Csak a következő karakterek használhatók (minimum 3 karakter): A-Z a-z 0-9 _.+*@!$%~ common#:#login_to_ilias#:#Bejelentkezés az ILIAS-ba -common#:#login_to_ilias_via_login_form#:#Login to ILIAS###29 10 2025 new variable +common#:#login_to_ilias_via_login_form#:#Bejelentkezés az ILIAS-ba common#:#login_to_ilias_via_saml#:#Bejelentkezés az ILIAS-ba SAML hitelesítésen keresztül common#:#login_to_ilias_via_shibboleth#:#ILIAS-ba bejelentkezés ezen keresztül: common#:#loginname_already_exists#:#Már van ilyen felhasználónév. @@ -4558,40 +4588,43 @@ common#:#lso_edit#:#Tanulási sor módosítása common#:#lso_import#:#Tanulási sor importálása common#:#lso_new#:#Új tanulási sor common#:#lso_wizard_page#:#Tanulási sor másolása (2/2 lépés) -common#:#lti_outcome#:#LTI tanulási haladás bejelentése -common#:#lti_outcome_info#:#LTI-felhasználó tanulási haladási állapotát küldjük egy LTI-eszközfogyasztónak. +common#:#lti_outcome#:#LTI Tanulási haladási értesítő +common#:#lti_outcome_info#:#LTI-felhasználó tanulási haladási állapotának megküldése LTI-eszközfogyasztó / LTI-Platform részére.. common#:#mail#:#Levelek common#:#mail_addressbook#:#Címtár common#:#mail_at_the_ilias_installation#:#%1$s új levelet kapott a(z) %2$s ILIAS-ban. common#:#mail_attachment#:#E-mail melléklet common#:#mail_b_inbox#:#Beérkező levelek common#:#mail_c_trash#:#Kuka -common#:#mail_cron_scheduled_mails#:#Send scheduled mails.###29 10 2025 new variable -common#:#mail_cron_scheduled_mails_desc#:#Sends scheduled user mails according to their defined delivery times###29 10 2025 new variable +common#:#mail_cron_scheduled_mails#:#Ütemezett levelek küldése. +common#:#mail_cron_scheduled_mails_desc#:#Ütemezett felhasználói levelek küldése a megadott kézbesítési időnek megfelelően common#:#mail_d_drafts#:#Piszkozatok common#:#mail_delete_error#:#Törlés közben hiba lépett fel -common#:#mail_e_outbox#:#Outbox###29 10 2025 new variable +common#:#mail_e_outbox#:#Kimenő common#:#mail_e_sent#:#Elküldött levelek common#:#mail_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Levelezés jogosultsági beállításait -common#:#mail_f_sent#:#Sent###29 10 2025 new variable +common#:#mail_f_sent#:#Elküldött common#:#mail_folders#:#E-mail mappák common#:#mail_import_file#:#Fájl importálása common#:#mail_mails_of#:#Levél common#:#mail_maxsize_attach#:#Mellékletek maximális összmérete common#:#mail_member#:#E-mail a tagoknak common#:#mail_members#:#Levél küldése tagoknak -common#:#mail_message_scheduled#:#Scheduled mail###29 10 2025 new variable -common#:#mail_message_scheduled_info#:#Mails remain in the outbox until the scheduled sending time.###29 10 2025 new variable +common#:#mail_message_scheduled#:#Ütemezett levél +common#:#mail_message_scheduled_info#:#A levelek a kimenő mappában maradnak a megadott küldési időpontig. common#:#mail_not_sent#:#A levelet nem küldte el! -common#:#mail_schedule_error_no_datetime#:#To schedule a mail, a delivery date and time must be specified.###29 10 2025 new variable -common#:#mail_schedule_error_past_datetime#:#You cannot schedule emails in the past.###29 10 2025 new variable -common#:#mail_scheduled#:#Mail stored in outbox for later delivery.###29 10 2025 new variable +common#:#mail_schedule_error_no_datetime#:#A kézbesítés ütemezéséhez meg kell adni a kézbesítés dátumát és időpontját. +common#:#mail_schedule_error_past_datetime#:#Nem ütemezhetsz leveleket a múltba. +common#:#mail_schedule_scheduled_datetime#:#Ütemezett küldési idő +common#:#mail_scheduled#:#A leveleket a kimenő mappában tároljuk későbbi kézbesítés céljából. +common#:#mail_scheduled_edit_compose_info#:#You are editing a scheduled mail. Sending is paused until you schedule the mail again.###07 07 2026 new variable +common#:#mail_scheduled_edit_moved_info#:#This scheduled mail was temporarily moved to drafts so it will not be sent while you are editing it. After scheduling again, it will reappear in the outbox.###07 07 2026 new variable common#:#mail_search_no#:#Egy bejegyzés sem felel meg a keresési feltételnek. common#:#mail_select_one#:#Legalább egy levelet ki kell választania! common#:#mail_send_error#:#Hiba lépett fel az e-mail küldése közben -common#:#mail_sent#:#E-mail elküldve. +common#:#mail_sent#:#Az e-mailt elküldtük. common#:#mail_settings#:#Levelezési beállítások -common#:#mail_to_global_roles_not_allowed#:#%1$s (nem engedélyezett levél küldése globális szerepeknek) +common#:#mail_to_global_roles_not_allowed#:#%1$s (nem engedélyezett levél küldése a globális szerepköröknek) common#:#mail_z_local#:#Saját mappák common#:#mails#:#Levelek common#:#mails_at_the_ilias_installation#:#%1$s új levelet kapott a(z) %2$s ILIAS-ban. @@ -4644,7 +4677,7 @@ common#:#metabar_aria_label#:#Metamenü common#:#mgs_objects_linked_to_the_following_folders_p#:#Az objektumokat a következő mappába/mappákba sikeresen linkelte. common#:#mgs_objects_linked_to_the_following_folders_s#:#Az objektumot a következő mappába/mappákba sikeresen linkelte. common#:#migrate#:#Migráció -common#:#minimize#:#Minimize###29 07 2022 new variable +common#:#minimize#:#Minimalizálás common#:#minute#:#perc common#:#minutes#:#perc common#:#missing#:#Hiányzik @@ -4652,14 +4685,14 @@ common#:#missing_perm#:#Jogosultsághiány common#:#missing_precondition#:#Hiányzó előfeltétel common#:#mm_achievements#:#Teljesítmények common#:#mm_administration#:#Rendszerbeállítások -common#:#mm_badges#:#Érmek +common#:#mm_badges#:#Érdemérmek common#:#mm_calendar#:#Naptár common#:#mm_certificates#:#Tanúsítványok -common#:#mm_comments#:#Hozzászólások +common#:#mm_comments#:#Nyilvános megjegyzések common#:#mm_communication#:#Kommunikáció common#:#mm_contacts#:#Kapcsolatok common#:#mm_dashboard#:#Műszerfal -common#:#mm_enrolments#:#Beiratkozások +common#:#mm_enrolments#:#Kurzustagságok common#:#mm_favorites#:#Kedvenceim common#:#mm_learning_history#:#Tanulási történelem common#:#mm_learning_progress#:#Tanulási haladás @@ -4670,7 +4703,7 @@ common#:#mm_organisation#:#Szervezeti egység common#:#mm_personal_and_shared_r#:#Személyes és megosztott erőforrások common#:#mm_personal_workspace#:#Személyes munkaterület common#:#mm_portfolio#:#Portfólió -common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable +common#:#mm_private_chats#:#Privát csevegések common#:#mm_repo_tree_view#:#Fa nézet common#:#mm_repo_tree_view_act#:#Fa bekapcsolása common#:#mm_repo_tree_view_deact#:#Fa kikapcsolása @@ -4721,26 +4754,26 @@ common#:#msg_bt_download_started#:#Az ILIAS az összes elérhető fájlból arch common#:#msg_cancel#:#Tevékenység megszakítva. common#:#msg_clear_clipboard#:#A vágólap üres. common#:#msg_cloned#:#Kiválasztott objektum(ok) lemásolva -common#:#msg_copy_clipboard#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a 'Beillesztés' gombra. -common#:#msg_copy_clipboard_container#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a 'Folytatás' gombra. -common#:#msg_copy_clipboard_source#:#Most válassza ki azt a kurzust vagy csoportot, amelynek tartalmát másolni szeretné, majd kattintson a 'Folytatás' gombra. -common#:#msg_cut_clipboard#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a 'Beillesztés' gombra. +common#:#msg_copy_clipboard#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a ‘Beillesztés’ gombra. +common#:#msg_copy_clipboard_container#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a ‘Folytatás’ gombra. +common#:#msg_copy_clipboard_source#:#Most válassza ki azt a kurzust vagy csoportot, amelynek tartalmát másolni szeretné, majd kattintson a ‘Folytatás’ gombra. +common#:#msg_cut_clipboard#:#Most válassza ki, hová szeretné beilleszteni a kiválasztott objektumokat, majd kattintson a ‘Beillesztés’ gombra. common#:#msg_cut_copied#:#A kiválasztott objektum(ok) sikeresen áthelyezte. common#:#msg_deleted_export_files#:#Az exportfájlokat sikeresen törölte -common#:#msg_deleted_role#:#A szerepet sikeresen törölte -common#:#msg_deleted_roles_rolts#:#A szerepeket és szerepmintákat sikeresen törölte +common#:#msg_deleted_role#:#A szerepkört sikeresen törölte +common#:#msg_deleted_roles_rolts#:#A szerepköröket és szerepkörmintákat sikeresen törölte common#:#msg_failed#:#A tevékenység meghiúsult common#:#msg_form_save_error#:#Az űrlapadatok nem menthetők. Nézze meg az inputmezők hibaüzeneteit! common#:#msg_info_blacklisted#:#A fájlok nem tölthetőek fel biztonsági okok miatt. -common#:#msg_input_char_limit_max#:#You have entered more characters than allowed.###26 08 2024 new variable -common#:#msg_input_char_limit_min#:#You have to enter the minimum of characters specified.###26 08 2024 new variable +common#:#msg_input_char_limit_max#:#A megengedettnél több karakter adott meg. +common#:#msg_input_char_limit_min#:#A megengedettnél kevesebb karakter adott meg. common#:#msg_input_does_not_match_regexp#:#Érvényes értéket adjon meg! common#:#msg_input_is_required#:#Kötelező megadni ezt az adatot. Adjon meg egy értéket! -common#:#msg_invalid_value_css_rect_input#:#The entered value is incorrect, do not use any plus or minus symbols in combination with the entered integer. Please check your input.###29 10 2025 new variable -common#:#msg_is_last_role#:#Eltávolította az utolsó szerepet az alábbi felhasználókról -common#:#msg_last_role_for_registration#:#Legalább egy elérhető szerepnek kell lennie a regisztrációs űrlapon az új felhasználók számára. Jelenleg ez az egyetlen elérhető szerep. -common#:#msg_link_clipboard_p#:#Válassza ki a helyet, ahová a kiválasztott objektumokat linkelni szeretné, majd kattintson a 'Beillesztés' gombra. -common#:#msg_link_clipboard_s#:#Válassza ki a helyet, ahová a kiválasztott objektumot linkelni szeretné, majd kattintson a 'Beillesztés' gombra. +common#:#msg_invalid_value_css_rect_input#:#A megadott érték érvénytelen. Ne használjon plusz vagy mínusz jelet. Ellenőrizze az értéket. +common#:#msg_is_last_role#:#Eltávolította az utolsó szerepkört az alábbi felhasználókról +common#:#msg_last_role_for_registration#:#Legalább egy elérhető szerepnek kell lennie a regisztrációs űrlapon az új felhasználók számára. Jelenleg ez az egyetlen elérhető szerepkör. +common#:#msg_link_clipboard_p#:#Válassza ki a helyet, ahová a kiválasztott objektumokat linkelni szeretné, majd kattintson a ‘Beillesztés’ gombra. +common#:#msg_link_clipboard_s#:#Válassza ki a helyet, ahová a kiválasztott objektumot linkelni szeretné, majd kattintson a ‘Beillesztés’ gombra. common#:#msg_linked#:#Sikeresen belinkelte a választott objektumo(ka)t. common#:#msg_may_not_contain#:#Ez az objektum feltehetőleg nem tartalmazhatja a következő objektumtípusokat: common#:#msg_min_one_role#:#Minden felhasználónak legalább egy aktív globális szerepe kell legyen. @@ -4748,60 +4781,60 @@ common#:#msg_multi_language_selected#:#Ugyanazt a nyelvet választotta egy mási common#:#msg_no_default_language#:#Nincs alapértelmezett nyelv. Egy fordítási nyelvet alapértelmezettnek meg kell jelölnie. common#:#msg_no_delete_yourself#:#Nem törölheti a saját ILIAS-fiókját. common#:#msg_no_file#:#Nem választott fájlt. -common#:#msg_no_files_selected#:#No files selected###29 07 2022 new variable +common#:#msg_no_files_selected#:#Egy fájlt sem választott ki common#:#msg_no_language_selected#:#Nincs fordítási nyelv meghatározva. Minden fordításhoz meg kell adnia egy nyelvet. -common#:#msg_no_perm_assign_role_to_user#:#Nincs jogosultsága a felhasználói szerep-összerendelés módosításához -common#:#msg_no_perm_assign_user_to_role#:#Nincs jogosultsága a felhasználói hozzárendelések módosításához +common#:#msg_no_perm_assign_role_to_user#:#Nincs jogosultsága a felhasználói szerep-összerendelés módosításához. +common#:#msg_no_perm_assign_user_to_role#:#Nincs jogosultsága a felhasználói hozzárendelések módosításához. common#:#msg_no_perm_copy#:#Nem jogosult az alábbi objektum(ok) másolására: -common#:#msg_no_perm_create_rolt#:#Nincs jogosultsága szerepminták létrehozására +common#:#msg_no_perm_create_rolt#:#Nincs jogosultsága szerepkörminták létrehozására. common#:#msg_no_perm_cut#:#Nincs jogosultsága kivágni az alábbi objektumo(ka)t: common#:#msg_no_perm_delete#:#Nincs jogosultsága törölni az alábbi objektumo(ka)t: common#:#msg_no_perm_link#:#Nincs jogosultsága linket létrehozni az alábbi objektum(ok)ból: -common#:#msg_no_perm_modify_rolt#:#Nincs jogosultsága szerepmintákat módosítani -common#:#msg_no_perm_modify_user#:#Nincs jogosultsága felhasználói adatokat módosítani +common#:#msg_no_perm_modify_rolt#:#Nincs jogosultsága szerepkörmintákat módosítani. +common#:#msg_no_perm_modify_user#:#Nincs jogosultsága felhasználói adatokat módosítani. common#:#msg_no_perm_paste#:#Nincs jogosultsága beilleszteni az alábbi objektumo(ka)t: common#:#msg_no_perm_paste_object_in_folder#:#Nincs jogosultsága a(z) %s objektumot beilleszteni a(z) %s mappába. -common#:#msg_no_perm_perm#:#Nincs jogosultsága szerkeszteni a jogosultság-beállításokat +common#:#msg_no_perm_perm#:#Nincs jogosultsága módosítani a jogosultsági beállításokat. common#:#msg_no_perm_read#:#Nincs jogosultsága ezekhez az elemekhez. -common#:#msg_no_perm_read_item#:#Nincs jogosultsága elérni: '%s'. +common#:#msg_no_perm_read_item#:#Nincs jogosultsága elérni. common#:#msg_no_perm_read_lm#:#Nincs olvasási jogosultsága ehhez a tananyaghoz. -common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable -common#:#msg_no_perm_write#:#Nincs írási jogosultsága -common#:#msg_no_search_result#:#Nem találhatóak bejegyzések -common#:#msg_no_search_string#:#Adjon meg egy keresési kifejezést +common#:#msg_no_perm_view_roles_of_user#:#Nincs jogosultsága megtekinteni a felhasználó szerepköreit +common#:#msg_no_perm_write#:#Nincs jogosultsága módosítani a beállításokat. +common#:#msg_no_search_result#:#Egy bejegyzés sem található +common#:#msg_no_search_string#:#Adjon meg egy keresési kifejezést. common#:#msg_no_title#:#Adjon meg egy címet. common#:#msg_not_available_for_anon#:#A kiválasztott oldal csak bejelentkezett felhasználók számára érhető el. -common#:#msg_not_in_itself#:#Objektumot nem lehet saját magába beilleszteni +common#:#msg_not_in_itself#:#Objektumot nem lehet saját magába beilleszteni. common#:#msg_obj_already_deleted#:#Az objektumot már törölték. common#:#msg_obj_created#:#Sikeresen létrehozott egy objektumot. -common#:#msg_obj_exists#:#Ez az objektum már létezik ebben a mappában +common#:#msg_obj_exists#:#Ez az objektum már létezik ebben a mappában. common#:#msg_obj_exists_in_folder#:#A(z) %s objektum már benne van a(z) %s mappában. common#:#msg_obj_may_not_contain_objects_of_type#:#A(z) %s objektum nem tartalmazhat ilyen típusú objektumokat: %s. common#:#msg_obj_modified#:#Módosításokat sikeresen mentette. common#:#msg_obj_no_download#:#nem letölthető. common#:#msg_obj_no_link#:#Technika okok miatt tároló objektumok (kategória, kurzus, csoport, illetve mappa) linkelése nem lehetséges. Linkelni tudja az abban lévő objektumokat vagy hozzon létre kategória-, kurzus-, illetve csoportlinket. common#:#msg_obj_perm_download#:#Nincs jogosultsága az alábbi objektumok letöltéséhez: -common#:#msg_paste_object_not_in_itself#:#Nem lehet beilleszteni a(z) '%s' objektumot saját magába. +common#:#msg_paste_object_not_in_itself#:#Nem lehet beilleszteni a(z) ‘%s’ objektumot saját magába. common#:#msg_perm_adopted_from1#:#A jogosultsági beállítások elődje common#:#msg_perm_adopted_from2#:#(Beállításokat sikeresen mentettük!) -common#:#msg_perm_adopted_from_itself#:#Nem alkalmazhat jogosultsági beállításokat magából a jelenlegi szerepből/szerepmintából. +common#:#msg_perm_adopted_from_itself#:#Nem alkalmazhat jogosultsági beállításokat magából a jelenlegi szerepből/szerepkörmintából. common#:#msg_removed#:#Az objektumo(ka)t sikeresen eltávolította a rendszerből. -common#:#msg_role_reserved_prefix#:#Az 'il_' prefix az automatikusan generált szerepekhez van fenntartva. Válasszon másik megnevezést. -common#:#msg_roleassignment_changed#:#Szerep-összerendelés megváltoztatva. -common#:#msg_sysrole_not_deletable#:#A rendszerszerepet nem lehet törölni. -common#:#msg_sysrole_not_editable#:#A rendszerszerep jogosultsági beállításai valószínűleg nem módosíthatóak. Ez a szerep korlátlan hozzáférést biztosít a hozzárendelt felhasználók számára minden objektumhoz és funkcióhoz. -common#:#msg_to_many_files#:#Too many files selected, allowed amount of files:###29 07 2022 new variable +common#:#msg_role_reserved_prefix#:#Az ‘il_’ prefix az automatikusan generált szerepkörökhöz van fenntartva. Válasszon másik megnevezést. +common#:#msg_roleassignment_changed#:#Szerep-összerendelést sikeresen módosította +common#:#msg_sysrole_not_deletable#:#A rendszerszerepkört nem lehet törölni +common#:#msg_sysrole_not_editable#:#A rendszerszerepkör jogosultsági beállításai valószínűleg nem módosíthatók. Ez a szerepkör korlátlan hozzáférést biztosít a hozzárendelt felhasználók számára minden objektumhoz és funkcióhoz. +common#:#msg_to_many_files#:#Túl sok fájl választott ki, többet, mint common#:#msg_trash_empty#:#Nincs törölt objektum common#:#msg_undeleted#:#Objektum(ok) törlése visszavonva. common#:#msg_unit_is_required#:#Ez az bemenet egy mértékegységet vár. Odaillő értéket adjon meg! common#:#msg_unknown_value#:#Ismeretlen érték került átadásra. -common#:#msg_user_last_role1#:#Ehhez a szerephez csak az alábbi felhasználók vannak hozzárendelve: -common#:#msg_user_last_role2#:#Törölje a felhasználókat vagy rendelje őket másik szerephez, hogy törölhető legyen ez a szerep! +common#:#msg_user_last_role1#:#Ehhez a szerepkörhöz csak az alábbi felhasználók vannak hozzárendelve: +common#:#msg_user_last_role2#:#Törölje a felhasználókat vagy rendelje őket másik szerepkörhöz, hogy törölhető legyen ez a szerep! common#:#msg_userassignment_changed#:#A felhasználó-hozzárendelés megváltozott common#:#msg_wrong_filetypes#:#Engedélyezett fájltípusok: common#:#msg_wrong_format#:#A megadott érték nem érvényes formátumú. common#:#my_bms#:#Webcímek -common#:#my_certificates#:#Igazolásaim +common#:#my_certificates#:#Tanúsítványaim common#:#my_contacts#:#Ismerőseim common#:#my_courses#:#Kurzusaim common#:#my_courses_groups#:#Kurzusaim és csoportjaim @@ -4814,14 +4847,14 @@ common#:#nc_contact_requests_prop_time#:#Időpont common#:#never#:#soha common#:#new#:#Új common#:#new_language#:#Új nyelv -common#:#new_pass_equals_old_pass#:#Az új jelszó megegyezik a régivel. +common#:#new_pass_equals_old_pass#:#Az új jelszó megegyezik a régivel, használjon attól eltérőt. common#:#newline#:#Új sor common#:#news#:#Hírek common#:#next#:#Következő common#:#no#:#Nem common#:#no_access_item#:#Nincs jogosultsága ezeknek az elemeknek az eléréséhez. common#:#no_access_item_public#:#Ennek az elemnek az eléréséhez be kell jelentkeznie, és megfelelő jogosultsággal kell rendelkeznie. -common#:#no_accessibility_control_concept_description#:#Jelenleg nincs hozzáférés-vezérlés koncepciója ennek a telepítésnek. Kérem, további információkért lépjen kapcsolatba a kapcsolat hozzáférési pontjával. +common#:#no_accessibility_control_concept_description#:#Jelenleg nincs Hozzáférhetőségi dokumentuma ennek a telepítésnek. Kérem, további információkért lépjen kapcsolatba az üzemeltetőkkel. common#:#no_checkbox#:#Semmit sem választott ki. common#:#no_condition_selected#:#Válasszon ki egy előfeltételt. common#:#no_date#:#Nincs dátum @@ -4833,13 +4866,13 @@ common#:#no_limit#:#Nincs korlát common#:#no_mkisofs_configured#:#Konfigurálnia kell az mkisofs utility-t az ILIAS-setupban az ISO-export futtatásához common#:#no_parent_access#:#Nincs hozzáférés felettes objektumhoz. common#:#no_permission#:#Nincs meg a megfelelő jogosultsága. -common#:#no_roles_user_can_be_assigned_to#:#Nincsenek globális szerepek, amelyekhez hozzá lehetne rendelni a felhasználót. Így Ön nem vehet fel felhasználókat. +common#:#no_roles_user_can_be_assigned_to#:#Nincsenek globális szerepkörök, amelyekhez hozzá lehetne rendelni a felhasználót. Így Ön nem vehet fel felhasználókat. common#:#no_start_file#:#Nincs kezdőfájl. common#:#no_title#:#Nincs cím common#:#no_users_selected#:#Egy felhasználót válasszon ki! common#:#no_xml_file_found_in_zip#:#Nem található XML fájl ZIP-fájlban: common#:#noc#:#Értesítési Központ -common#:#non_internal_local_roles_only#:#Helyi szerepek (csak felhasználó által létrehozottak) +common#:#non_internal_local_roles_only#:#Helyi szerepkörök (csak felhasználó által létrehozottak) common#:#none#:#Nincs common#:#normal#:#Normál common#:#not_available#:#Nem elérhető @@ -4851,27 +4884,27 @@ common#:#notes#:#Privát jegyzetek common#:#notes_and_comments#:#Feljegyzések common#:#notice#:#Jegyzet common#:#notifications#:#Értesítések -common#:#nr_following_sessions#:#%1d alábbi munkamenet(ek)... +common#:#nr_following_sessions#:#%1d alábbi munkamenet(ek)… common#:#num_of_selected_files#:#%s fájlt választott ki common#:#num_users#:#Felhasználók száma -common#:#numberedlist_action#:#Insert Numbered List - Click to insert a numbered list.###26 08 2024 new variable +common#:#numberedlist_action#:#Számozott lista beillesztése - Kattintson számozott lista beillesztéséhez. common#:#obj#:#Objektum common#:#obj_accs#:#Könnyű kezelés common#:#obj_accs_desc#:#Könnyű kezelés beállításai common#:#obj_adm#:#Rendszerbeállítások common#:#obj_adm_desc#:#Itt talál mindent az ILIAS rendszerbeállításainak kezeléséhez. -common#:#obj_adma#:#General Settings###29 10 2025 new variable -common#:#obj_adma_desc#:#Important settings for the whole installation###29 10 2025 new variable -common#:#obj_adn#:#Administrative Notifications +common#:#obj_adma#:#Általános beállítások +common#:#obj_adma_desc#:#Az egész telepítés fontos beállításai +common#:#obj_adn#:#Rendszerértesítések common#:#obj_adve#:#Szerkesztés -common#:#obj_adve_desc#:#Rendszergazdai beállítások ILIAS-lapszerkesztőhöz és TinyMCE-hez +common#:#obj_adve_desc#:#Rendszergazdai beállítások az ILIAS-lapszerkesztőhöz és a TinyMCE szerkesztőhöz common#:#obj_ass#:#Asset common#:#obj_assf#:#Teszt és értékelés common#:#obj_assf_desc#:#Teszt és értékelés globális beállításai common#:#obj_auth#:#Hitelesítés és regisztráció -common#:#obj_auth_desc#:#Hitelesítési mód konfigurálása (helyi, LDAP, ...) és új ILIAS-fiók regisztrációs beállításai -common#:#obj_awra#:#'Ki van online?'-eszköz -common#:#obj_awra_desc#:#'Ki van online?'-eszköz kezelése +common#:#obj_auth_desc#:#Hitelesítési mód konfigurálása (helyi, LDAP, …) és új ILIAS-fiók regisztrációs beállításai +common#:#obj_awra#:#‘Ki van online?’-eszköz +common#:#obj_awra_desc#:#‘Ki van online?’-eszköz kezelése common#:#obj_bdga#:#Érdemérmek common#:#obj_bdga_desc#:#Érdemérem-típusok, sablonképek és aktivitások kezelése common#:#obj_bgtk#:#Háttérfolyamat @@ -4880,8 +4913,8 @@ common#:#obj_bibs#:#Bibliográfia common#:#obj_bibs_desc#:#Bibliográfia rendszerbeállításai common#:#obj_blog#:#Blog common#:#obj_blog_duplicate#:#Blog másolása -common#:#obj_bnmk#:#Benchmarking###29 10 2025 new variable -common#:#obj_bnmk_desc#:#Recording and display of database query durations###29 10 2025 new variable +common#:#obj_bnmk#:#Teljesítménymérés +common#:#obj_bnmk_desc#:#Az adatbázis-lekérdezések időtartamának rögzítése és megjelenítése common#:#obj_book#:#Foglalásgyűjtemény common#:#obj_cadm#:#Kapcsolatok common#:#obj_cadm_desc#:#Kapcsolatok kezelése @@ -4890,14 +4923,14 @@ common#:#obj_cals_desc#:#Általános naptárbeállítások common#:#obj_cat#:#Kategória common#:#obj_cat_duplicate#:#Kategória másolása common#:#obj_catr#:#Kategórialink -common#:#obj_cert#:#Igazolás -common#:#obj_cert_desc#:#Beállítások az igazolásokhoz +common#:#obj_cert#:#Tanúsítvány +common#:#obj_cert_desc#:#Beállítások a tanúsítványokhoz common#:#obj_chap#:#Fejezet common#:#obj_chta#:#Csevegőszoba common#:#obj_chtr#:#Csevegőszoba -common#:#obj_chtr_duplicate#:#Copy Chat Room###29 07 2022 new variable -common#:#obj_cmis#:#xAPI/cmi5 -common#:#obj_cmis_desc#:#Learning Record Store Types Configuration +common#:#obj_chtr_duplicate#:#Csevegőszoba másolása +common#:#obj_cmis#:#LRS +common#:#obj_cmis_desc#:#A tanulásibejegyzés-tárolók típusainak beállítása common#:#obj_cmix#:#xAPI/cmi5 common#:#obj_cmps#:#Bővítmények common#:#obj_cmps_desc#:#Bővítmények általános beállításai @@ -4907,36 +4940,34 @@ common#:#obj_copa#:#Tartalomlap common#:#obj_cpad#:#Tartalomlapok common#:#obj_cpad#_desc#:#Tartalomlap kezelése common#:#obj_cpad_desc#:#Tartalomlap kezelése -common#:#obj_cron#:#Cron Jobs###29 10 2025 new variable -common#:#obj_cron_desc#:#List of all Cron Jobs###29 10 2025 new variable +common#:#obj_cron#:#Ütemezett feladatok +common#:#obj_cron_desc#:#Az összes ütemezett feladat listája common#:#obj_crs#:#Kurzus common#:#obj_crs_duplicate#:#Kurzus másolása common#:#obj_crsr#:#Kurzuslink common#:#obj_crss#:#Kurzus common#:#obj_crss_desc#:#Kurzus általános beállításai -common#:#obj_crsv#:#Kurzus Igazolás +common#:#obj_crsv#:#Kurzus-tanúsítvány common#:#obj_dbk#:#Digitális könyvtári könyv common#:#obj_dcl#:#Adatgyűjtés common#:#obj_dcl_duplicate#:#Adatgyűjtés másolása -common#:#obj_dpro#:#Declaration of Data Protection###26 08 2024 new variable -common#:#obj_dpro_desc#:#Declaration of Data Protection Settings###26 08 2024 new variable +common#:#obj_dpro#:#Adatvédelemi Nyilatkozat +common#:#obj_dpro_desc#:#Adatvédelmi Nyilatkozat beállításai common#:#obj_dshs#:#Műszerfal common#:#obj_dshs_desc#:#Műszerfal beállításai common#:#obj_ecss#:#ECS common#:#obj_ecss_desc#:#Általános ECS beállítások -common#:#obj_etal#:#Employee Talk +common#:#obj_etal#:#Beosztotti megbeszélés common#:#obj_exc#:#Beadandó feladat common#:#obj_exc_duplicate#:#Feladat másolása common#:#obj_excv#:#Beadandó feladat tanúsítványa -common#:#obj_extt#:#Harmadik fél szoftvere -common#:#obj_extt_desc#:#ILIAS által támogatott külső szoftverek, szolgáltatások konfigurálása common#:#obj_facs#:#Fájlok common#:#obj_facs_desc#:#Fájlok és fájlkezelési beállítások common#:#obj_file#:#Fájl common#:#obj_file_duplicate#:#Fájl duplikálása -common#:#obj_file_inline#:#Tananyagfájl -common#:#obj_fils#:#File Services -common#:#obj_fils_desc#:#Configuration of File Service Settings. +common#:#obj_file_inline#:#Tananyagfájl###Inline file +common#:#obj_fils#:#Fájlszolgáltatás +common#:#obj_fils_desc#:#A Fájlszolgáltatás beállításai. common#:#obj_fold#:#Mappa common#:#obj_fold_duplicate#:#Mappa másolása common#:#obj_frm#:#Fórum @@ -4950,8 +4981,8 @@ common#:#obj_grp_duplicate#:#Csoport másolása common#:#obj_grpr#:#Csoportlink common#:#obj_grps#:#Csoport common#:#obj_grps_desc#:#Csoport általános beállításai -common#:#obj_gsfo#:#Footer###29 10 2025 new variable -common#:#obj_gsfo_desc#:#Administrate Footer Layout and Content###29 10 2025 new variable +common#:#obj_gsfo#:#Lábléc +common#:#obj_gsfo_desc#:#Lábléc és tartalma rendszerbeállításai common#:#obj_hlps#:#Súgórendszer common#:#obj_hlps_desc#:#Beállítások az online súgóhoz common#:#obj_htlm#:#HTML-tananyag @@ -4981,9 +5012,9 @@ common#:#obj_ltis#:#LTI common#:#obj_ltis_desc#:#Tanulási eszközök átjárhatósága (Learning Tools Interoperability) common#:#obj_mail#:#Levelezés common#:#obj_mail_desc#:#Levelezés globális beállításai -common#:#obj_mailr#:#Read Mail###28 10 2024 new variable -common#:#obj_mailu#:#Unread Mail###28 10 2024 new variable -common#:#obj_maps#:#Maps###29 10 2025 new variable +common#:#obj_mailr#:#Olvasott +common#:#obj_mailu#:#Olvasatlan +common#:#obj_maps#:#Térképek common#:#obj_mcst#:#Médiasugárzás common#:#obj_mcst_duplicate#:#Médiagyűjtemény másolása common#:#obj_mcts#:#Médiasugárzás @@ -4995,43 +5026,42 @@ common#:#obj_mob#:#Multimédiaobjektum common#:#obj_mobs#:#Médiaobjektumok és -gyűjtemények common#:#obj_mobs_desc#:#Beállítások médiaobjektumokhoz és médiagyűjteményekhez common#:#obj_not_found#:#Nem található objektum. -common#:#obj_nota#:#Notifications###29 07 2022 new variable -common#:#obj_nota_desc#:#Notification Administration###29 07 2022 new variable +common#:#obj_nota#:#Értesítések +common#:#obj_nota_desc#:#Rendszerértesítések common#:#obj_nots#:#Jegyzetek common#:#obj_nots_desc#:#Jegyzetek beállításai common#:#obj_nwss#:#Hírek és webhírforrások common#:#obj_nwss_desc#:#Beállítások belső hírekhez és külső hírforrásokhoz common#:#obj_objf#:#Objektumdefiníciók -common#:#obj_objf_desc#:#ILIAS-objektumtípusok és jogosultságok. (Csak szakértőknek!) common#:#obj_orgu#:#Szervezeti egység common#:#obj_orgu_description#:#Szervezeti felépítés létrehozása és módosítása common#:#obj_page#:#Lap -common#:#obj_peac#:#Accordion -common#:#obj_peadl#:#Advanced List -common#:#obj_peadt#:#Advanced Table -common#:#obj_pecd#:#Code -common#:#obj_pech#:#Consultation Hour -common#:#obj_pecl#:#Column Layout -common#:#obj_peclp#:#Clipboard -common#:#obj_pecom#:#Competences -common#:#obj_pecrs#:#Course -common#:#obj_pecrt#:#Certificate -common#:#obj_pecs#:#Content Snippet -common#:#obj_pedt#:#Data Table -common#:#obj_pefl#:#File List -common#:#obj_peim#:#interactive Media -common#:#obj_pelh#:#Learning History -common#:#obj_pemed#:#Image/Audio/Video -common#:#obj_pemp#:#Map -common#:#obj_pepd#:#Personal Data -common#:#obj_pepe#:#Plugin Element -common#:#obj_pepl#:#Page List -common#:#obj_peplh#:#Placeholder -common#:#obj_pequ#:#Questions -common#:#obj_perl#:#Ressource List -common#:#obj_pesc#:#Section -common#:#obj_petmp#:#Page Template -common#:#obj_peusr#:#User +common#:#obj_peac#:#Harmonika +common#:#obj_peadl#:#Fejlett felsorolás +common#:#obj_peadt#:#Fejlett táblázat +common#:#obj_pecd#:#Kód +common#:#obj_pech#:#Fogadóórák +common#:#obj_pecl#:#Oszlopos elrendezés +common#:#obj_peclp#:#Vágólap +common#:#obj_pecom#:#Kompetenciák +common#:#obj_pecrs#:#Kurzus +common#:#obj_pecrt#:#Tanúsítvány +common#:#obj_pecs#:#Tartalom-építőelem +common#:#obj_pedt#:#Adattábla +common#:#obj_pefl#:#Fájllista +common#:#obj_peim#:#Interaktív média +common#:#obj_pelh#:#Tanulási történelem +common#:#obj_pemed#:#Kép/Hang/Videó +common#:#obj_pemp#:#Térkép +common#:#obj_pepd#:#Személyes adat +common#:#obj_pepe#:#Bővítményelem +common#:#obj_pepl#:#Oldallista +common#:#obj_peplh#:#Helyőrzők +common#:#obj_pequ#:#Kérdések +common#:#obj_perl#:#Erőforráslista +common#:#obj_pesc#:#Fejezet +common#:#obj_petmp#:#Oldalsablon +common#:#obj_peusr#:#Felhasználó common#:#obj_pg#:#Lap common#:#obj_poll#:#Szavazás common#:#obj_poll_dupliate:#:#Szavazások másolása @@ -5039,8 +5069,8 @@ common#:#obj_poll_duplicate#:#Szavazás másolása common#:#obj_prg#:#Képzési program common#:#obj_prg_duplicate#:#Képzési program másolása common#:#obj_prg_select#:#-- Válasszon egy Képzési programot -- -common#:#obj_prgr#:#Képzési programra mutató link -common#:#obj_prgrs#:#Képzési programokra mutató linkek +common#:#obj_prgr#:#Képzésiprogram-link +common#:#obj_prgrs#:#Képzésiprogram-linkek common#:#obj_prgs#:#Képzési programok common#:#obj_prgs_desc#:#Képzési program kezelése common#:#obj_prss#:#Személyes erőforrások kezelése @@ -5064,33 +5094,32 @@ common#:#obj_rfil#:#ECS fájl common#:#obj_rglo#:#ECS fogalomtár common#:#obj_rgrp#:#ECS csoport common#:#obj_rlm#:#ECS tananyag -common#:#obj_role#:#Szerep -common#:#obj_rolf#:#Szerepek -common#:#obj_rolf_desc#:#Szerepek kezelése -common#:#obj_rolf_local#:#Helyi szerepek +common#:#obj_role#:#Szerepkör +common#:#obj_rolf#:#Szerepkörök +common#:#obj_rolf_desc#:#Szerepkörök kezelése +common#:#obj_rolf_local#:#Helyi szerepkörök common#:#obj_rolf_local_desc#:#Objektum helyi szerepeit tartalmazza. -common#:#obj_rolt#:#Szerepminta +common#:#obj_rolt#:#Szerepkörminta common#:#obj_root#:#Tartalomtár - kezdőlap common#:#obj_rtst#:#ECS teszt common#:#obj_rwik#:#ECS wiki common#:#obj_sahs#:#SCORM-tananyag common#:#obj_sahs_duplicate#:#Tananyag másolása common#:#obj_sco#:#SCO -common#:#obj_scov#:#SCORM Igazolás +common#:#obj_scov#:#SCORM Tanúsítvány common#:#obj_seas#:#Keresés common#:#obj_seas_desc#:#Keresési beállítások kezelése -common#:#obj_serv#:#Server###29 10 2025 new variable -common#:#obj_serv_desc#:#Settings of the sever###29 10 2025 new variable +common#:#obj_serv#:#Szerver +common#:#obj_serv_desc#:#A szerver állapota, beállításai és PDF beállítások common#:#obj_sess#:#Esemény common#:#obj_sess_duplicate#:#Esemény másolása common#:#obj_skmg#:#Kompetenciamenedzsment common#:#obj_skmg_desc#:#Kompetenciák és kompetenciakategóriák kezelése common#:#obj_spl#:#Kérdőívkérdés-gyűjtemény -common#:#obj_spl_select#:#-- Válasszon egy kérdőívkérdés-gyűjteményt -- common#:#obj_st#:#Fejezet -common#:#obj_stus#:#Shortlinks###29 10 2025 new variable -common#:#obj_stus_desc#:#Global Shortlinks Settings###29 10 2025 new variable -common#:#obj_sty#:#Stílus +common#:#obj_stus#:#Gyorslink +common#:#obj_stus_desc#:#Gyorslink globális beállításai +common#:#obj_sty#:#Tartalomstílus common#:#obj_stys#:#Stílus és elrendezés common#:#obj_stys_desc#:#Stílusok és elrendezések rendszerbeállításainak kezelése common#:#obj_svy#:#Kérdőív @@ -5101,21 +5130,21 @@ common#:#obj_sysc#:#Rendszerellenőrzés common#:#obj_sysc_desc#:#Rendszerellenőrző és -javító eszközök common#:#obj_tags#:#Címkézés common#:#obj_tags_desc#:#Címkézési tulajdonság beállításai -common#:#obj_tala#:#Talk Templates -common#:#obj_tala_desc#:#Talk Templates -common#:#obj_tals#:#Employee Talk Series -common#:#obj_talt#:#Talk Template +common#:#obj_tala#:#Megbeszélési sablonok +common#:#obj_tala_desc#:#Megbeszélési sablonok +common#:#obj_tals#:#Beosztotti megbeszéléssorozat +common#:#obj_talt#:#Megbeszélési sablon common#:#obj_task#:#Feladat common#:#obj_tax#:#Taxonómia common#:#obj_taxf#:#Taxonómiák common#:#obj_tool_setting_calendar#:#Naptár megjelenítése common#:#obj_tool_setting_calendar_active#:#Naptár common#:#obj_tool_setting_calendar_active_info#:#A naptár elérhető. -common#:#obj_tool_setting_calendar_info#:#A 'Naptár' blokk megjelenik a 'Tartalom' fül alatt. +common#:#obj_tool_setting_calendar_info#:#A ‘Naptár’ blokk megjelenik a ‘Tartalom’ lapon. common#:#obj_tool_setting_custom_metadata#:#Egyéni metaadat -common#:#obj_tool_setting_custom_metadata_info#:#Ha be van kapcsolva, a metaadatok konfigurálhatóak. +common#:#obj_tool_setting_custom_metadata_info#:#A ‘Metaadat’ lapon egyéni metaadatok hozhatók létre. common#:#obj_tool_setting_news#:#Hírek megjelenítése -common#:#obj_tool_setting_news_info#:#A 'Hír' blokk megjelenik a 'Tartalom' fül alatt. +common#:#obj_tool_setting_news_info#:#A ‘Hír’ blokk megjelenik a ‘Tartalom’ lapon. common#:#obj_tos#:#Szolgáltatási feltételek common#:#obj_tos_desc#:#Szolgáltatási feltételek beállításai common#:#obj_trac#:#Statisztikák és tanulási haladás @@ -5129,7 +5158,7 @@ common#:#obj_usr#:#Felhasználó common#:#obj_usrf#:#ILIAS-fiókok common#:#obj_usrf_desc#:#ILIAS-fiókok kezelése common#:#obj_wbdv#:#WebDAV -common#:#obj_wbdv_desc#:#Configuration of WebDAV Settings. +common#:#obj_wbdv_desc#:#A WebDAV beállításai. common#:#obj_wbrs#:#Weblinkek common#:#obj_wbrs_desc#:#Weblinkek általános beállításai common#:#obj_webr#:#Weblink @@ -5145,7 +5174,7 @@ common#:#object_copy_in_progress#:#Másolás megkezdve. common#:#object_duplicated#:#Az objektumot sikeresen lemásolta. common#:#object_id#:#Objektum-ID common#:#object_imported#:#Az objektumot sikeresen importálta. -common#:#object_list#:#List of Objects###29 10 2025 new variable +common#:#object_list#:#Objetumok felsorolása common#:#objects#:#Objektumok common#:#objf#:#Objektumdefiníciók common#:#objs_bibl#:#Bibliográfiák @@ -5154,12 +5183,12 @@ common#:#objs_book#:#Foglalásgyűjtemények common#:#objs_cat#:#Kategóriák common#:#objs_catr#:#Kategórialink common#:#objs_chtr#:#Csevegőszoba -common#:#objs_cmix#:#xAPI/cmi5 objektum +common#:#objs_cmix#:#xAPI/cmi5-objektum common#:#objs_copa#:#Tartalomlapok common#:#objs_crs#:#Kurzusok common#:#objs_crsr#:#Kurzuslink common#:#objs_dcl#:#Adatgyűjtések -common#:#objs_etal#:#Employee Talks +common#:#objs_etal#:#Munkavállói megbeszélések common#:#objs_exc#:#Beadandó feladatok common#:#objs_file#:#Fájlok common#:#objs_fold#:#Mappák @@ -5180,7 +5209,7 @@ common#:#objs_mep#:#Médiagyűjtemény common#:#objs_orgu#:#Szervezeti egységek common#:#objs_poll#:#Szavazások common#:#objs_prg#:#Képzési programok -common#:#objs_prgr#:#Links to Study Programmes###29 07 2022 new variable +common#:#objs_prgr#:#Képzésiprogram-link common#:#objs_prtf#:#Portfóliók common#:#objs_prtt#:#Portfólió sablonok common#:#objs_qpl#:#Tesztkérdésgyűjtemény @@ -5191,18 +5220,18 @@ common#:#objs_rfil#:#ECS fájlok common#:#objs_rglo#:#ECS fogalomtárak common#:#objs_rgrp#:#ECS csoportok common#:#objs_rlm#:#ECS tananyagok -common#:#objs_role#:#Szerepek -common#:#objs_rolf#:#Role Folders###28 10 2024 new variable +common#:#objs_role#:#Szerepkörök +common#:#objs_rolf#:#Szerepkörmappák common#:#objs_rtst#:#ECS tesztek common#:#objs_rwik#:#ECS wikik common#:#objs_sahs#:#SCORM-tananyagok common#:#objs_sess#:#Események -common#:#objs_skee#:#Competence Trees###26 08 2024 new variable +common#:#objs_skee#:#Kompetencia-fák common#:#objs_spl#:#Kérdőívkérdés-gyűjtemény common#:#objs_st#:#Fejezetek common#:#objs_svy#:#Kérdőívek -common#:#objs_tala#:#Talk Templates -common#:#objs_talt#:#Talk Templates +common#:#objs_tala#:#Megbeszéléssablonok +common#:#objs_talt#:#Megbeszéléssablonok common#:#objs_tst#:#Tesztek common#:#objs_webr#:#Weblinkek common#:#objs_wiki#:#Wikik @@ -5227,7 +5256,7 @@ common#:#optional_filters#:#Választható szűrők common#:#options#:#Beállítások common#:#order_by#:#Sorrend: common#:#order_by_date#:#Dátum alapján -common#:#org_op_access_enrolments#:#Szerződésállapot megjelenítése +common#:#org_op_access_enrolments#:#Kurzustagság-állapot megjelenítése common#:#org_op_manage_members#:#Alárendelt tagok kezelése common#:#org_op_read_learning_progress#:#Alárendelt felhasználók tanulási haladásának megjelenítése common#:#org_permission_settings#:#Szervezeti egység pozícióinak jogosultságai @@ -5254,7 +5283,7 @@ common#:#passwd_not_match#:#A begépelt nem illeszkedik az új jelszóra. Adja m common#:#passwd_wrong#:#A megadott jelszó hibás. common#:#password#:#Jelszó common#:#password_allow_chars#:#Engedélyezett karakter: %s -common#:#password_assistance_info#:#Ha be van kapcsolva a jelszósegédlet, 'Elfelejtette jelszavát?' szövegű link jelenik meg az ILIAS bejelentkező képernyőjén. A felhasználók a link segítségével új jelszót adhatnak meg ILIAS-fiókjukhoz rendszergazdai segítség igénybevétele nélkül. +common#:#password_assistance_info#:#Az ‘Elfelejtette jelszavát?’ szövegű link jelenik meg az ILIAS bejelentkező képernyőjén. A felhasználók a link segítségével új jelszót adhatnak meg ILIAS-fiókjukhoz rendszergazdai segítség igénybevétele nélkül. common#:#password_change_on_first_login_demand#:#Kezdeti jelszavát meg kell változtatnia mielőtt megkezdi az ILIAS használatát! common#:#password_contains_invalid_chars#:#A jelszó érvénytelen karaktereket tartalmaz common#:#password_contains_parts_of_login_err#:#A jelszó tartalmazza a felhasználóneved. Másik jelszót adj meg. @@ -5283,7 +5312,7 @@ common#:#pd_items_news#:#Személyes objektumok híreit beleértve common#:#pdf_export#:#PDF-export common#:#perm_settings#:#Jogosultságok common#:#perma_link#:#Állandó link -common#:#perma_link_copied#:#Link to this page has been copied to the clipboard.###29 10 2025 new variable +common#:#perma_link_copied#:#Az erre az oldalra mutató linket a vágólapra másolta common#:#permission#:#Jogosultság common#:#permission_denied#:#Hozzáférés elutasítva. common#:#permission_settings#:#Jogosultságok beállítása @@ -5293,7 +5322,7 @@ common#:#personal_picture#:#Fénykép common#:#personal_profile#:#Profil és adatvédelem common#:#personal_resources#:#Személyes erőforrások common#:#personal_settings#:#Beállítások -common#:#personalise_date_time#:#Personalise Date and Time Settings###29 10 2025 new variable +common#:#personalise_date_time#:#Dátum és idő beállításainak személyre szabása common#:#persons#:#Személyek common#:#pg_add#:#Lap létrehozása common#:#pg_new#:#Új lap @@ -5308,7 +5337,7 @@ common#:#please_enter_title#:#Adjon meg címet. common#:#please_select#:#-- Válasszon -- common#:#please_select_a_delivered_file_to_delete#:#Legalább egy átadott fájlt ki kell választani a törléshez. common#:#please_select_a_delivered_file_to_download#:#Legalább egy átadott fájlt ki kell választania a letöltéshez. -common#:#please_wait#:#Kérem, várjon... +common#:#please_wait#:#Kérem, várjon… common#:#port#:#Port common#:#portfolio#:#Portfólió common#:#pos_bottom#:#Alulra @@ -5319,7 +5348,7 @@ common#:#position#:#Pozíció common#:#position_permission_settings#:#Szervezeti egység alapú jogosultságok common#:#precondition#:#Előfeltétel common#:#precondition_not_accessible#:#Nem rendelkezik megfelelő jogosultsággal ezen elemek előfeltételeinek megtekintéséhez. -common#:#precondition_required_itemlist#:#Elvárt előfeltételek +common#:#precondition_required_itemlist#:#Kötelező előfeltétel common#:#precondition_toggle#:#Ennek az objektumnak az eléréséhez teljesítendő előfeltételek common#:#preconditions#:#Előfeltételek common#:#preconditions_obligatory_hint#:#Teljesítenie kell az alábbi előfeltételeket @@ -5330,33 +5359,33 @@ common#:#presentation_table_more#:#Több megjelenítése common#:#preview#:#Előnézet common#:#preview_create#:#Előnézet létrehozása common#:#preview_delete#:#Előnézet törlése -common#:#preview_image_size#:#Size of Preview Images###26 08 2024 new variable -common#:#preview_learner_info#:#Ha be van kapcsolva, a kurzus- és csoportvezető a tagok nézetből is megtekintheti a tartalmat. -common#:#preview_loading#:#Előnézet betöltése... +common#:#preview_image_size#:#Előnézeti képek mérete +common#:#preview_learner_info#:#A kurzus- és csoportvezető a tagok nézetből is megtekintheti a tartalmat. +common#:#preview_loading#:#Előnézet betöltése… common#:#preview_none#:#Előnézet (még nem készült el) -common#:#preview_not_possible#:#Creation of Previews is currently not possible, please read the documentation in %s.###26 08 2024 new variable -common#:#preview_renderers#:#Preview Renderers +common#:#preview_not_possible#:#Előképek előállítása jelenleg nem lehetséges, kérem, olvassa el a dokumentációt: %s. +common#:#preview_renderers#:#Előképrenderelők common#:#preview_settings#:#Fájlelőnézet common#:#preview_show#:#Előnézet megjelenítése -common#:#preview_status_creating#:#Készül az előnézet. Ez egy kis időt igénybe vehet... -common#:#preview_status_deleting#:#Előnézet törlése... +common#:#preview_status_creating#:#Készül az előnézet. Ez egy kis időt igénybe vehet… +common#:#preview_status_deleting#:#Előnézet törlése… common#:#preview_status_failed#:#Előnézet készítése sikertelen. common#:#preview_status_missing#:#Nincs előnézet ehhez a fájlhoz. common#:#preview_status_pending#:#Az előnézet még nem készült el. Próbálja később. common#:#previous#:#Előző common#:#prg_copy_threads_info#:#Válassza ki a Képzési program mely elemit másolja, linkeli vagy hagyja figyelmen kívül. common#:#prg_wizard_page#:#Képzési program másolása (2/2 lépés) -common#:#prgr_add#:#Add Study Programme Link###29 07 2022 new variable -common#:#prgr_edit_info#:#Please choose one Study Programme for creating a new link.###29 07 2022 new variable -common#:#prgr_new#:#Create Study Programme Link###29 07 2022 new variable -common#:#prgr_settings#:#Settings of Study Programme Link###26 08 2024 new variable +common#:#prgr_add#:#Képzési program link hozzáadása +common#:#prgr_edit_info#:#Kérem, válasszon egy képzési programot az új link elkészítéséhez. +common#:#prgr_new#:#Képzési programra mutató link létrehozása +common#:#prgr_settings#:#Képzési program link beállításai common#:#print#:#Nyomtatás common#:#print_view#:#Nyomtatási nézet common#:#private_notes#:#Privát jegyzeteim common#:#pro#:#Pozitívum common#:#proceed#:#Folytatás common#:#profile#:#Adatok -common#:#profile_changed#:#ILIAS - Adatai módosultak +common#:#profile_changed#:#Adatai módosultak common#:#profile_incomplete#:#Adatai hiányosak. Adjon meg minden kötelező adatot. common#:#profile_of#:#Adatai: common#:#properties#:#Tulajdonságok @@ -5375,15 +5404,15 @@ common#:#ps_export_scorm#:#Személyes adat a protokolladatban common#:#ps_password_lowercase_chars_num#:#Kisbetűk common#:#ps_password_lowercase_chars_num_info#:#Adja meg, a jelszónak hány kisbetűt kell tartalmaznia. 0 esetén nincs ilyen elvárás. common#:#ps_password_must_not_contain_loginame#:#Felhasználónév megakadályozás a jelszóban -common#:#ps_password_must_not_contain_loginame_info#:#Ha be van kapcsolva, a jelszó nem tartalmazhatja a felhasználónevet. +common#:#ps_password_must_not_contain_loginame_info#:#A jelszó nem tartalmazhatja a felhasználónevet. common#:#ps_password_uppercase_chars_num#:#Nagybetűk common#:#ps_password_uppercase_chars_num_info#:#Adja meg, a jelszónak hány nagybetűt kell tartalmaznia. 0 esetén nincs ilyen elvárás. common#:#pub_section#:#Nyilvános terület -common#:#pub_section_info#:#Ha be van kapcsolva, a rendszer részei (például Tartalomtár, magánterület, felhasználói profilok) bejelentkezés nélkül elérhetőek az internetről. Az 'Anonymous' szerep jogosultságai határozzák meg a Tartalomtár objektumainak elérhetőségét. +common#:#pub_section_info#:#A rendszer részei (például Tartalomtár, magánterület, felhasználói profilok) bejelentkezés nélkül elérhetőek az internetről. Az ‘Anonymous’ szerepkör jogosultságai határozzák meg a Tartalomtár objektumainak elérhetőségét. common#:#public#:#nyilvános common#:#public_notes#:#Nyilvános jegyzetek common#:#public_profile#:#Profil -common#:#public_room#:#Nyilvános szoba +common#:#public_room#:#Nyilvános csevegőszoba common#:#purpose#:#Cél common#:#qpl#:#Tesztkérdésgyűjtemény common#:#qpl_add#:#Tesztkérdésgyűjtemény létrehozása @@ -5404,19 +5433,21 @@ common#:#refresh#:#Frissítés common#:#refresh_languages#:#Összes nyelv frissítése common#:#refuse#:#Visszautasítás common#:#reg_account_confirmation_successful#:#ILIAS-fiókját aktiválták. +common#:#reg_delete_expired_pending_registrations#:#Lejárt, függőben lévő regisztrációk törlése +common#:#reg_delete_expired_pending_registrations_desc#:#Törli az összes olyan ILIAS fiókot, amelyet e-mailben történő visszaigazolással történő regisztráció után nem erősítettek meg. common#:#reg_goto_parent_membership_info#:#Csak tagok érhetik el a célobjektumot. -common#:#reg_mail_body_2_confirmation#:#A link csak ehhez lesz jó: %s, aztán meg kell próbálnia ismét a kezdetektől. +common#:#reg_mail_body_2_confirmation#:#A link csak eddig működik: %s, után az elejéről kell kezdenie a regisztrációs folyamatot. common#:#reg_mail_body_3_confirmation#:#Ha ez a levél nem jelent Önnek semmit, lehet hogy valaki más is belépett az Ön postafiókjába szándékosan vagy véletlenül. Kérjük, tekintse semmisnek ezt a levelet! -common#:#reg_mail_body_forgot_password_info#:#Ehhez az ILIAS-fiókhoz új jelszó kéréséhez használja a bejelentkező képernyőn található « Elfelejtette jelszavát? » linket. +common#:#reg_mail_body_forgot_password_info#:#Ehhez az ILIAS-fiókhoz új jelszó kéréséhez használja a bejelentkező képernyőn található ‘Elfelejtette jelszavát?’ linket. common#:#reg_mail_body_salutation#:#Tisztelt common#:#reg_mail_body_text1#:#üdvözöljük ILIAS e-learning rendszerünkben! common#:#reg_mail_body_text2#:#Az ILIAS-t az alábbi adatokkal érheti el: common#:#reg_mail_body_text3#:#További felhasználói adatai: -common#:#reg_mail_subject#:#ILIAS e-learning - bejelentkezési adatai -common#:#reg_mail_subject_confirmation#:#ILIAS e-learning - visszaigazoló linkje +common#:#reg_mail_subject#:#Bejelentkezési adatai +common#:#reg_mail_subject_confirmation#:#Visszaigazoló link common#:#reg_passwd_via_mail#:#Jelszavát e-mail címére fogjuk elküldeni. common#:#register#:#Regisztráció -common#:#register_notification#:#ezúton értesítjük, hogy '%s' jelezte résztvételi szándékát '%s' eseményre. +common#:#register_notification#:#ezúton értesítjük, hogy ‘%s’ jelezte részvételi szándékát ‘%s’ eseményre. common#:#registered_since#:#Regisztráció kezdete common#:#registered_user#:#regisztrált felhasználó common#:#registered_users#:#regisztrált felhasználó @@ -5431,16 +5462,17 @@ common#:#renderer_supported_file_types#:#Támogatott fájltípusok common#:#renderer_supported_repo_types#:#Támogatott Tartalomtár-típusok common#:#renderer_type_builtin#:#Beépített common#:#rep_main_page#:#Kezdőlap -common#:#repeat_scan#:#Víruskeresés ismétlése... +common#:#rep_main_page_logo_alt#:#ILIAS logó - a kezdőoldalra +common#:#repeat_scan#:#Víruskeresés ismétlése… common#:#repeat_scan_failed#:#Ismételt keresés sikertelen. common#:#repeat_scan_succeded#:#Ismételt keresés sikerült. common#:#replace_file#:#Fájl cseréje common#:#reply#:#Válasz common#:#report_accessibility_issue#:#Hozzáférési probléma jelzése common#:#report_accessibility_link#:#Bejelentett link: -common#:#report_accessibility_link_mailto#:#Reported%20Link:###29 07 2022 new variable +common#:#report_accessibility_link_mailto#:#Bejelentett%20link: common#:#repository#:#Tartalomtár -common#:#repository_admin#:#Tartalomtár-lomtár és jogosultságok +common#:#repository_admin#:#Tartalomtár-lomtár common#:#repository_admin_desc#:#Tartalomtár objektumaira jogosultságok beállítása, objektumok visszaállítása vagy eltávolítása a rendszer lomtárából common#:#require_email#:#E-mail kötelező common#:#require_gender#:#Nem kötelező @@ -5455,58 +5487,55 @@ common#:#reset_filter#:#Szűrő törlése common#:#resources#:#Források common#:#right#:#Jog common#:#rights#:#Jogok -common#:#role#:#Szerep -common#:#role_add_user#:#Felhasználó(k) szerephez adása -common#:#role_added#:#Sikeresen létrehozott egy szerepet. +common#:#role#:#Szerepkör +common#:#role_add_user#:#Felhasználó(k) szerepkörhöz adása +common#:#role_added#:#Sikeresen létrehozott egy szerepkört. common#:#role_assignment#:#Szerep-összerendelés common#:#role_assignment_updated#:#A szerep-összerendelést sikeresen frissítette. -common#:#role_edit#:#Szerep módosítása +common#:#role_edit#:#Szerepkör módosítása common#:#role_mailto#:#Levél minden hozzárendelt felhasználónak -common#:#role_new#:#Új szerep +common#:#role_new#:#Új szerepkör common#:#role_new_search#:#Új keresés -common#:#role_no_roles_selected#:#Válasszon ki egy szerepet! +common#:#role_no_roles_selected#:#Válasszon ki egy szerepkört! common#:#role_protect_permissions#:#Jogosultságok megvédése -common#:#role_protect_permissions_desc#:#Az objektum jogosultsági beállításai rendszerművelettel már nem módosítható. A rendszergazda magasabb szinten továbbra is módosíthatja a jogosultságokat. +common#:#role_protect_permissions_desc#:#Az objektum jogosultsági beállításai rendszerművelettel már nem módosíthatók evvel a szereppel. A rendszergazdák magasabb szinten továbbra is módosíthatják a jogosultságokat. common#:#role_select_one_item#:#Egy objektumot válasszon! common#:#role_sure_delete_desk_items#:#Biztos, hogy törli az alábbi munkaasztal-linkeket? -common#:#role_templates_only#:#Csak szerepminták -common#:#roles#:#Szerepek +common#:#role_templates_only#:#Csak szerepkörminták +common#:#roles#:#Szerepkörök common#:#roles_of_import_global#:#Importfájl globális szerepei common#:#roles_of_import_local#:#Importfájl helyi szerepei -common#:#rolf#:#Szerepek -common#:#rolf_added#:#Sikeresen létrehozott egy szerepmappát. -common#:#rolf_create_role#:#Új szerep létrehozása -common#:#rolf_create_rolt#:#Új szerepminta létrehozása -common#:#rolf_delete#:#Szerepek / szerepminták törlése +common#:#rolf#:#Szerepkörök +common#:#rolf_added#:#Sikeresen létrehozott egy szerepkörmappát. +common#:#rolf_create_role#:#Új szerepkör létrehozása +common#:#rolf_create_rolt#:#Új szerepkörminta létrehozása +common#:#rolf_delete#:#Szerepkörök / szerepkörminták törlése common#:#rolf_edit_permission#:#Jogosultsági beállítások változtatása -common#:#rolf_edit_userassignment#:#Szerep és felhasználó összerendelésének változtatása -common#:#rolf_read#:#Olvasási elérés szerepekhez / szerepmintákhoz -common#:#rolf_visible#:#Szerepek / szerepminták láthatók -common#:#rolf_write#:#Szerepek / szerepminták alapértelmezett jogosultsági beállításainak módosítása -common#:#rolt#:#Szerepminta -common#:#rolt_added#:#Sikeresen létrehozott egy szerepmintát. -common#:#rolt_edit#:#Szerepminta módosítása -common#:#rolt_new#:#Új szerepminta +common#:#rolf_edit_userassignment#:#Szerepkör és felhasználó összerendelésének változtatása +common#:#rolf_read#:#Olvasási elérés szerepkörökhöz / szerepkörmintákhoz +common#:#rolf_visible#:#Szerepkörök / szerepkörminták láthatók +common#:#rolf_write#:#Szerepkörök / szerepkörminták alapértelmezett jogosultsági beállításainak módosítása +common#:#rolt#:#Szerepkörminta +common#:#rolt_added#:#Sikeresen létrehozott egy szerepkörmintát. +common#:#rolt_edit#:#Szerepkörminta módosítása +common#:#rolt_new#:#Új szerepkörminta common#:#row#:#sor common#:#rows#:#Sorok -common#:#rpc_pdf_font#:#Betűtípusok -common#:#rpc_pdf_font_info#:#PDF fájlok generáláshoz további betűtípusok. A 'Helvetica' és a 'unifont' betűtípusoktól eltérőket az ILIAS szerverre telepíteni kell. -common#:#rpc_pdf_generation#:#PDF-Generálás common#:#sad#:#Szomorú common#:#sahs#:#SCORM-tananyag common#:#sahs_added#:#Sikeresen létrehozott egy SCORM-tananyagot. -common#:#sahs_export_file#:#ILIAS exportált SCORM-archívum fájl -common#:#sahs_export_file_info#:#Use this option for a ZIP file that was exported directly from ILIAS. The file typically has titles such as 1675257903__4105__sahs_132295.zip.###26 08 2024 new variable +common#:#sahs_export_file#:#ILIAS XML export fájl (.zip) +common#:#sahs_export_file_info#:#Ezt a beállítást olyan ZIP-fájl esetén használja, amelyet közvetlenül az ILIAS-ból exportáltak. A fájl általában hasonló nevű: 1675257903__4105__sahs_132295.zip. common#:#sahs_insert_chap_from_clip#:#Fejezetek beillesztése vágólapról common#:#sahs_insert_page_from_clip#:#Lapok beillesztése vágólapról common#:#sahs_insert_sco_from_clip#:#SCO-k beillesztése vágólapról -common#:#sahs_new#:#Create New Learning Module###26 08 2024 new variable +common#:#sahs_new#:#Új tananyag létrehozása common#:#salutation#:#Megszólítás common#:#salutation_f#:#Asszony common#:#salutation_m#:#Úr common#:#salutation_n#:#Nincs megszólítás common#:#saml_log_in#:#Közvetlen bejelentkezés -common#:#saml_login_form_info_txt#:#A 'Közvetlen bejelentkezés' gomb használatával felhasználónév és jelszó megadás nélkül jelentkezhet be. +common#:#saml_login_form_info_txt#:#A ‘Közvetlen bejelentkezés’ gomb használatával felhasználónév és jelszó megadás nélkül jelentkezhet be. common#:#saml_login_form_txt#:#Bejelentkezés az ILIAS-ba SAML-en keresztül common#:#save#:#Mentés common#:#save_and_back#:#Mentés és vissza @@ -5517,17 +5546,17 @@ common#:#save_return#:#Mentés és vissza common#:#save_settings#:#Beállítások mentése common#:#save_user_related_data#:#Felhasználó hozzáféréssel kapcsolatos adatainak mentése common#:#saved_successfully#:#Módosításait sikeresen mentette. -common#:#saving#:#Mentés... -common#:#scope#:#Scope###28 10 2024 new variable +common#:#saving#:#Mentés… +common#:#scope#:#Hatókör common#:#scorm_create_export_file_html#:#Exportfájl létrehozása (HTML) common#:#scorm_create_export_file_pdf#:#Exportfájl létrehozása (PDF) common#:#scorm_create_export_file_scrom12#:#Exportfájl létrehozása (SCORM 1.2) common#:#scorm_create_export_file_scrom2004#:#Exportfájl létrehozása (SCORM 2004 3rd Edition) common#:#scorm_create_export_file_scrom2004_4th#:#Exportfájl létrehozása (SCORM 2004 4th Edition) common#:#scorm_login_as_learner_id#:#SCORM 2004: ILIAS felhasználónév legyen a cmi.learner_id -common#:#scorm_login_as_learner_id_info#:#Ha be van kapcsolva, Felhasználó-ID helyett a felhasználónév lesz a cmi.learner_id. +common#:#scorm_login_as_learner_id_info#:#User_id helyett a felhasználónév lesz a cmi.learner_id. common#:#scorm_lp_auto_activate#:#Tanulási haladás alapértelmezett beállítása -common#:#scorm_lp_auto_activate_info#:#A tanulási haladás alapértelmezetten beállítása SCORM-tananyaghoz az, hogy az új SCORM-tananyag hozzáadása esetén annak tanulási haladási beállítása 'Kiválasztott SCORM-elemek' lesz oly módon, hogy az összes SCO-elem bekerül a tanulási haladás meghatározói közé. Ez a beállítás SCORM-tananyagonként módosítható. +common#:#scorm_lp_auto_activate_info#:#A tanulási haladás alapértelmezetten beállítása SCORM-tananyaghoz az, hogy az új SCORM-tananyag hozzáadása esetén annak tanulási haladási beállítása ‘Kiválasztott SCORM-elemek’ lesz oly módon, hogy az összes SCO-elem bekerül a tanulási haladás meghatározói közé. Ez a beállítás SCORM-tananyagonként módosítható. common#:#scorm_new#:#SCORM-tananyag létrehozása (szerzői mód) common#:#scorm_without_session#:#SCORM 2004: munkamenet nélkül lehetséges az adattárolás common#:#scorm_without_session_info#:#Az ILIAS munkamenet lejárta után is biztosítva van az SCORM 2004 tanulási adatok tárolása. SCORM 1.2 esetén a munkamenet nélküli tárolás mindig biztosított. @@ -5536,16 +5565,16 @@ common#:#search_active#:#Beleértve az aktív felhasználókat common#:#search_at_current_position#:#A jelenlegi helyen common#:#search_engine#:#Keresőbarát URL-ek common#:#search_for#:#Keresendő -common#:#search_globally#:#Globálisan +common#:#search_globally#:#Összes tartalom common#:#search_in#:#Keresés helye common#:#search_inactive#:#Beleértve az inaktív felhasználókat common#:#search_new#:#Új keresés common#:#search_result#:#Keresési találat common#:#search_results#:#Keresési találatok common#:#search_user#:#Felhasználó keresése -common#:#search_users#:#Look Up Users###29 10 2025 new variable -common#:#seas_max_hits#:#Maximális találat -common#:#seas_max_hits_info#:#Adja meg a keresési találatok maximális számát! +common#:#search_users#:#Felhasználók keresése +common#:#seas_max_hits#:#Találatok maximális száma +common#:#seas_max_hits_info#:#Adja meg, maximum hány találatot szeretne kapni. common#:#seas_settings#:#Keresési beállítások common#:#second#:#másodperc common#:#second_email#:#Másodlagos e-mail cím @@ -5554,7 +5583,8 @@ common#:#sel_country#:#Ország common#:#select#:#Kiválasztás common#:#select_all#:#Összes kijelölése common#:#select_at_least_one_object#:#Legalább egy objektumot jelöljön ki! -common#:#select_file#:#Fájl kijelölése +common#:#select_file#:#Fájl kiválasztása +common#:#select_file_from_computer#:#Válassza ki a fájlt a számítógépéről common#:#select_files_from_computer#:#Válassza ki a fájlokat a számítógépéről common#:#select_max_one_item#:#Kérem, csak egy elemet válasszon ki common#:#select_object_to_link#:#Kérem, válassza ki a linkelni kívánt objektumot. @@ -5565,7 +5595,7 @@ common#:#selected#:#Kijelölve. common#:#selected_files#:#Kiválasztott fájlok common#:#selected_items#:#Kiválasztott objektumok common#:#selected_items_back#:#Vissza -common#:#selected_languages_updated#:#Az alábbi nyelvek frissültek (ha telepítve vannak): +common#:#selected_languages_updated#:#A következő nyelveket sikeresen frissítette: common#:#send#:#Mehet common#:#send_mail#:#Levél küldése common#:#sender#:#Feladó @@ -5580,13 +5610,13 @@ common#:#sess#:#Esemény common#:#sess_fixed_duration#:#Rögzített munkamenet időtartam common#:#session_config#:#Munkamenet beállítások common#:#session_config_maintenance_disabled#:#A kliens nem változtathatja meg a beállításokat -common#:#session_mail_subject_deletion#:#'%s' lejelentkezett '%s' eseményről -common#:#session_mail_subject_entered#:#'%s' csatlakozott '%s' eseményhez -common#:#session_mail_subject_registered#:#'%s' jelentkezett '%s' eseményre +common#:#session_mail_subject_deletion#:#‘%s’ lejelentkezett ‘%s’ eseményről +common#:#session_mail_subject_entered#:#‘%s’ csatlakozott ‘%s’ eseményhez +common#:#session_mail_subject_registered#:#‘%s’ jelentkezett ‘%s’ eseményre common#:#session_reminder#:#Munkamenet-emlékeztető common#:#session_reminder_alert#:#Munkamenete lejár %1$s múlva, %2$s-kor. Kattintson az OK gombra, ha folytatni szeretné munkamenetét! Amennyiben a Mégsem gombra kattint, nem kap több emlékeztetőt jelenlegi munkamenete alatt. Üdvözlettel: %3$s. -common#:#session_reminder_default_lead_time_info#:#Please specify how many minutes before the expiration of a session a reminder should be shown.
    The function is deactivated when the value is '%s'. The recommended value is %s.
    The current length of a session is %s.###29 10 2025 new variable -common#:#session_reminder_input#:#Session Reminder (in Minutes)###28 10 2024 new variable +common#:#session_reminder_default_lead_time_info#:#Meghatározza, hogy hány perccel a munkamenet lejárta előtt jelenjen meg emlékeztető a felhasználónak.
    Kikapcsolt állapot értéke: ‘%s’. Az ajánlott érték: %s.
    Jelenleg a munkamenet hossza: %s. +common#:#session_reminder_input#:#Munkamenet-emlékeztető (percben) common#:#session_reminder_lead_time#:#Rendelkezésre álló idő common#:#session_reminder_lead_time_info#:#Adja meg percben a munkamenet-emlékeztetőhöz a rendelkezésre álló időt. Az emlékeztető egy figyelmeztetést jelenít meg megadott idővel a munkamenet lejárta előtt. A javasolt érték 5 (perc).
    A felhasználói munkamenet jelenlegi hossza %s. common#:#session_reminder_session_duration#:#(Munkamenet időtartama: %s). @@ -5612,7 +5642,7 @@ common#:#shib_department#:#Osztály attribútuma common#:#shib_email#:#E-mail cím attribútuma common#:#shib_federation_name#:#Az Ön Shibboleth-szövetségének neve common#:#shib_firstname#:#Családnév attribútuma -common#:#shib_gender#:#Nem attribútuma ('f' vagy 'n' kell legyen) +common#:#shib_gender#:#Nem attribútuma (‘n’, ‘m’ vagy ‘f’ kell, hogy legyen) common#:#shib_general_login_instructions#:#%s keresztüli bejelentkezéshez kattintson a bejelentkezési gombra és válassza ki szervezetét a következő lapon.
    Ha ezzel kapcsolatban kérdése van, keresse: common#:#shib_general_wayf_login_instructions#:#Abban az esetben, ha nem csatlakozott a megadott szervezetekhez, és hozzá szeretne férni a szerver egy kurzusához, vegye fel a kapcsolatot: common#:#shib_idp_list#:#Az azonosító-szolgáltatók felsorolása, amelyből a felhasználók az ILIAS bejelentkezési lapon választhatnak.
    Az egyes sorokban vesszővel elválasztva a következő párnak kell szerepelnie: szolgáltató-azonosító IdP-je (lásd Shibboleth metaadatfájl) és IdP neve, mivel ezeket egy legördülő listában kell megjeleníteni.
    Opcionálisan megadható egy harmadik paraméter is, a Shibboleth-munkamenet kezdeményező, amelyet abban az esetben kell használni, ha az Ön ILIAS-installációja többszörös szövetség része. @@ -5637,20 +5667,21 @@ common#:#shib_settings_saved#:#A Shibboleth-beállításokat sikeresen mentett common#:#shib_street#:#Utca attribútuma common#:#shib_title#:#Cím attribútuma common#:#shib_update#:#A mező módosítása a bejelentkezés alapján -common#:#shib_user_default_role#:#Shibboleth-felhasználókhoz rendelt alapértelmezett szerep +common#:#shib_user_default_role#:#Shibboleth-felhasználókhoz rendelt alapértelmezett szerepkör common#:#shib_zipcode#:#Irányítószám attribútuma common#:#short_inst_name#:#Rövid cím -common#:#short_inst_name_info#:#Ez a cím fog megjelenni a böngésző fejléccím csíkjában. Ha nincs megadott érték, az 'ILIAS' kerül felhasználásra. +common#:#short_inst_name_info#:#Ez a cím fog megjelenni a böngésző fejléccím csíkjában. Ha nincs megadott érték, az ‘ILIAS’ kerül felhasználásra. common#:#show#:#Megjelenítés common#:#show_all_details#:#Összes részlet megjelenítése -common#:#show_content#:#Show Content###29 07 2022 new variable +common#:#show_content#:#Tartalom megjelenítése common#:#show_details#:#Részletek megjelenítése common#:#show_filter#:#Szűrő megjelenítése common#:#show_hidden_sections#:#További információk megjelenítése » +common#:#show_less#:#Show less###07 07 2026 new variable common#:#show_list#:#Lista megjelenítése common#:#show_members#:#Tagok megjelenítése -common#:#show_more#:#Több... -common#:#show_preview#:#Show Preview###26 08 2024 new variable +common#:#show_more#:#Több… +common#:#show_preview#:#Előnézet megjelenítése common#:#show_users_online#:#Bejelentkezett felhasználók megjelenítése common#:#show_who_is_online#:#Online felhasználók megjelenítése common#:#side_frame#:#Oldalkeret @@ -5662,27 +5693,27 @@ common#:#smtp#:#SMTP common#:#soap_connect_timeout#:#Kapcsolat megszakadása időtúllépés miatt common#:#soap_connect_timeout_info#:#Maximális idő másodpercben, amíg a kapcsolódási kísérletet a SOAP-Webszolgáltatáshoz nem szakítjuk meg. common#:#soap_user_administration#:#Kezelés SOAP-on keresztül -common#:#soap_user_administration_desc#:#Ha be van kapcsolva, az ILIAS kezelhető SOAP-on keresztül. +common#:#soap_user_administration_desc#:#Az ILIAS kezelhető SOAP-on keresztül. common#:#soap_wsdl_path#:#WSDL útvonal common#:#soap_wsdl_path_info#:#Adja meg a webszolgáltatásokhoz használandó ILIAS WSDL fájl útját. Ha üresen hagyja ezt a mezőt, az alábbi útvonal lesz alapértelmezett: %s -common#:#sort#:#Sort###28 10 2024 new variable +common#:#sort#:#Rendezés common#:#sort_ascending#:#Rendezés növekvő sorrendben -common#:#sort_ascending_long#:#Change Sort Direction to Ascending###26 08 2024 new variable +common#:#sort_ascending_long#:#Rendezés irányának módosítása növekvőre common#:#sort_by_this_column#:#Rendezés erre az oszlopra common#:#sort_descending#:#Rendezés csökkenő sorrendben -common#:#sort_descending_long#:#Change Sort Direction to Descending###26 08 2024 new variable +common#:#sort_descending_long#:#Rendezés irányának módosítása csökkenőre common#:#sort_inherit_prefix#:#Alapértelmezett common#:#sorting_asc#:#Növekvő common#:#sorting_creation_header#:#Létrehozás ideje szerinti -common#:#sorting_creation_info#:#Az objektumokat a létrehozásuk ideje szerint rendezzük. +common#:#sorting_creation_info#:#Az ebben a tárolóban lévő objektumokat a létrehozásuk ideje szerint rendezzük. common#:#sorting_desc#:#Csökkenő common#:#sorting_direction#:#Rendezés iránya -common#:#sorting_header#:#Rendezés -common#:#sorting_info_inherit#:#A rendezés típusát a kurzustárolótól/csoporttárolótól vesszük át. -common#:#sorting_info_manual#:#Objektumok sorrendjének kézi beállítása a Tartalom » Rendezés alatt. Továbbá kérjük, adja meg az új objektumok alapértelmezett rendezési szempontját. +common#:#sorting_header#:#Tartalom rendezési beállítása +common#:#sorting_info_inherit#:#A rendezés típusát a szülő kurzustárolótól/csoporttárolótól vesszük át. +common#:#sorting_info_manual#:#Az ebben a tárolóban lévő objektumok sorrendjének kézi beállítása a Tartalom » Rendezés alatt módosítható. Továbbá kérjük, adja meg az új objektumok alapértelmezett rendezési szempontját. common#:#sorting_info_title#:#Az objektumokat a címük szerint rendezzük. common#:#sorting_manual_header#:#Kézi -common#:#sorting_save#:#Rendezés mentése +common#:#sorting_save#:#Sorrend mentése common#:#sorting_title_header#:#Cím szerinti common#:#spacer#:#Térközállító common#:#spl#:#Kérdőívkérdés-gyűjtemény @@ -5707,7 +5738,7 @@ common#:#subject#:#Tárgy common#:#submit#:#Mehet common#:#subobjects#:#Alobjektum common#:#subscription#:#Felvétel -common#:#subtabs#:#Alfülek +common#:#subtabs#:#Allapok common#:#success_message#:#Sikeres üzenet common#:#summary#:#Összefoglalás common#:#sure_delete_selected_users#:#Biztos, hogy törli a kiválasztott felhasználó(ka)t? @@ -5717,8 +5748,8 @@ common#:#svy#:#Kérdőív common#:#svy_add#:#Kérdőív létrehozása common#:#svy_finished#:#Befejezte a kérdőív kitöltését. common#:#svy_new#:#Új kérdőív -common#:#svy_not_finished#:#Még nem fejezte be a kérdőív kitöltését. -common#:#svy_not_started#:#Nem vett részt ennek a kérdőívnek a kitöltésében. +common#:#svy_not_finished#:#Elkedzte, de még nem fejezte be a kérdőív kitöltését. +common#:#svy_not_started#:#Még nem vett részt ennek a kérdőívnek a kitöltésében. common#:#svy_run#:#Indítás common#:#svy_warning_survey_not_complete#:#A kérdőívet még nem fejezte be. common#:#switch_language#:#Nyelv módosítása @@ -5734,7 +5765,7 @@ common#:#tabs#:#Tabok common#:#tagging_my_tags#:#Saját címkéim common#:#tags#:#Címkék common#:#take_over_structure#:#Struktúra adaptálása -common#:#take_over_structure_info#:#Ha be van kapcsolva, a ZIP-fájlban levő mappák csoportokban és kurzusokban mappaként, különben kategóriaként jönnek létre. +common#:#take_over_structure_info#:#A ZIP-fájlban levő mappák csoportokban és kurzusokban mappaként, különben kategóriaként jönnek létre. common#:#tals_etal#:#Talk common#:#talt_etal#:#Talk common#:#target#:#Cél @@ -5747,7 +5778,7 @@ common#:#tests#:#Tesztek common#:#textbox#:#Szövegdoboz common#:#thread#:#Téma common#:#thumbnail#:#Bélyegkép -common#:#tile_view#:#Tile View###28 10 2024 new variable +common#:#tile_view#:#Csempenézet common#:#time#:#Idő common#:#time_limit#:#Hozzáférés common#:#time_limit_add_time_limit_for_selected#:#Adjon meg egy időszakot a kiválasztott felhasználó(k)hoz @@ -5766,25 +5797,25 @@ common#:#today#:#Ma common#:#toggleGlobalDefault#:#Globálisan alapértelmezett átkapcsolása common#:#toggleGlobalFixed#:#Globálisan meghatározott átkapcsolása common#:#toggle_dropdown#:#Legördülő váltása -common#:#toggle_off#:#OFF### Don't translate this label to prevent rendering problems of the related Toggle Button! -common#:#toggle_on#:#ON### Don't translate this label to prevent rendering problems of the related Toggle Button! +common#:#toggle_off#:#KI +common#:#toggle_on#:#BE common#:#tomorrow#:#Holnap -common#:#toolbar_more_actions#:#More Actions###26 08 2024 new variable -common#:#tools#:#Tools###29 07 2022 new variable +common#:#toolbar_more_actions#:#További műveletek +common#:#tools#:#Eszközök common#:#top_of_page#:#Oldal tetejére -common#:#tos_accept_usr_agreement#:#Accept Terms of Service?###26 08 2024 new variable -common#:#tos_accept_usr_agreement_intro#:#There are new terms of service. You need to accept them before proceeding with the use of ILIAS. Read the following document carefully and give your consent or dissent at the bottom of the page.###26 08 2024 new variable -common#:#tos_force_accept_usr_agreement#:#You must accept the Terms of Service!###26 08 2024 new variable -common#:#tos_no_agreement_description#:#There is currently no Terms of Service document available for this installation. Please contact the system administrator.###26 08 2024 new variable -common#:#tos_refuse_acceptance#:#Refuse to Accept Terms of Service###26 08 2024 new variable -common#:#tos_usr_agreement#:#Terms of Service###26 08 2024 new variable -common#:#tos_usr_agreement_footer_intro#:#You have declared your consent to these terms of service.###26 08 2024 new variable -common#:#tos_withdraw_consent_description#:#Withdraw your consent to our Terms of Service here.###26 08 2024 new variable -common#:#tos_withdraw_consent_description_external#:#Please return to your ILIAS installation and log in again to complete the process of withdrawing your consent to the Terms of Service.###26 08 2024 new variable -common#:#tos_withdraw_consent_description_internal#:#Please log in again to complete the process of withdrawing your consent to the Terms of Service.###26 08 2024 new variable -common#:#tos_withdraw_consent_header#:#Withdraw Terms of Service Consent###26 08 2024 new variable -common#:#tos_withdraw_consent_info#:#Withdraw your consent to our Terms of Service.###26 08 2024 new variable -common#:#tos_withdraw_consent_info_external#:#Please contact the administrator of your authentication system and inform them of your intention to withdraw your consent to the Terms of Service.###26 08 2024 new variable +common#:#tos_accept_usr_agreement#:#Elfogadja a Szolgáltatási feltételeket? +common#:#tos_accept_usr_agreement_intro#:#Ezek az új Szolgáltatási feltételek, amit az ILIAS további használatához el kell fogadnia. Olvassa el figyelmesen a dokumentumot, és az oldal alján fogadja vagy utasítsa el. +common#:#tos_force_accept_usr_agreement#:#El kell fogadnia a Szolgáltatási feltételeket! +common#:#tos_no_agreement_description#:#Jelenleg nem érhető el Szolgáltatási feltételek. Kérem, keresse az üzemeltetőt. +common#:#tos_refuse_acceptance#:#A Szolgáltatási feltételek elutasítása +common#:#tos_usr_agreement#:#Szolgáltatási feltételek +common#:#tos_usr_agreement_footer_intro#:#Ön kinyilakoztatta, hogy beleegyezik a jelen Szolgáltatási feltételekbe. +common#:#tos_withdraw_consent_description#:#A Szerződési feltételekhez hozzájárulás visszavonása +common#:#tos_withdraw_consent_description_external#:#Kérem, jelentkezzen be újra az ILIAS-telepítésbe, hogy befejezze a Szolgáltatási feltételekhez való hozzájárulásának visszavonását. +common#:#tos_withdraw_consent_description_internal#:#Kérem, jelentkezzen be újra, hogy befejezze a Szolgáltatási feltételekhez való hozzájárulásának visszavonását. +common#:#tos_withdraw_consent_header#:#A Szerződési feltételekhez hozzájárulás visszavonása +common#:#tos_withdraw_consent_info#:#A Szerződési feltételekhez hozzájárulás visszavonása +common#:#tos_withdraw_consent_info_external#:#Kérem, tájékoztassa a hitelesítő rendszer üzemeltetőjét, hogy visszavonta hozzájárulását a Szolgátatási feltételekhez. common#:#total#:#Összesen common#:#tracking_settings#:#Beállítások common#:#translation#:#Fordítás @@ -5795,16 +5826,16 @@ common#:#treeview#:#Oldalsáv megjelenítése common#:#tst#:#Teszt common#:#tst_add#:#Teszt létrehozása common#:#tst_edit_questions#:#Kérdések módosítása -common#:#tst_history_read#:#View History###26 08 2024 new variable +common#:#tst_history_read#:#Előzmények megtekintése common#:#tst_new#:#Új teszt common#:#tst_results#:#Teszteredmények common#:#tst_run#:#Indítás common#:#tst_user_not_invited#:#Nem vehet részt ebben a tesztben. common#:#tst_warning_test_not_complete#:#A teszt még nincs kész. common#:#tutors#:#Tutorok -common#:#txt_registered#:#Sikeresen regisztrálta magát az ILIAS-ba. Kattintson a lenti gombra, hogy felhasználóként bejelentkezhessen! -common#:#txt_registered_passw_gen#:#Sikeresen regisztrálta magát az ILIAS-ba. Hamarosan kap majd egy e-mailt generált jelszavával. -common#:#txt_submitted#:#Sikeresen küldött egy regisztrációkérést az ILIAS-ba. Regisztrációkérését áttekinti egy rendszergazda, és hamarosan aktiválja. A regisztráció aktiválásáig nem tudni bejelentkezni. +common#:#txt_registered#:#Sikeresen regisztrált az ILIAS-ba. Bejelentkezhez kattintson a lenti gombra. +common#:#txt_registered_passw_gen#:#Sikeresen regisztrált az ILIAS-ba. Hamarosan kap egy e-mailt a generált jelszavával. +common#:#txt_submitted#:#Regisztrációkérését sikeresen elküldte az ILIAS-ba. Regisztrációkérését áttekintjük és hamarosan visszajelzünk. A regisztrációja aktiválásáig nem tudni bejelentkezni. common#:#typ#:#Objektumtípus meghatározása common#:#type#:#Típus common#:#udf_added_field#:#Sikeresen létrehozott egy új mezőt. @@ -5812,7 +5843,7 @@ common#:#udf_delete_sure#:#Biztos, hogy törli ezt a mezőt és minden hozzáren common#:#udf_duplicate_entries#:#Az értékeknek egyedieknek kell lenniük. common#:#udf_field_deleted#:#Törölt mező common#:#udf_name_already_exists#:#Ez a mezőnév már létezik. Válasszon egy másik nevet! -common#:#udf_required_requires_visib_reg#:#Ha a mező 'kötelező', a 'Látható a Regisztráció alatt' opciót is be kell állítani +common#:#udf_required_requires_visib_reg#:#Ha a mező ‘kötelező’, akkor a ‘Látható a Regisztráció alatt’ opciót is be kell állítani common#:#udf_type_date#:#Dátum common#:#udf_type_datetime#:#Dátum és idő common#:#udf_type_select#:#Kiválasztólista (egyválasztásos) @@ -5824,9 +5855,9 @@ common#:#udf_update_wysiwyg_field#:#Szövegterület (WYSIWYG) mező módosítás common#:#uid#:#Felhasználói azonosító (UID) common#:#ums_create_new_account#:#Új ILIAS-fiók létrehozása common#:#ums_explanation#:#Külső bejelentkezésével nem tud csatlakozni ILIAS-fiókhoz. Az ILIAS emellett talált az Ön e-mail címével egy ILIAS-fiókot. Ha ez az Öné, jelentkezzen be ILIAS-jelszavával. -common#:#ums_explanation_2#:#Ha ez nem az Ön ILIAS-fiókja, válassza az 'Új ILIAS-fiók létrehozása' műveletet! +common#:#ums_explanation_2#:#Ha ez nem az Ön ILIAS-fiókja, válassza az ‘Új ILIAS-fiók létrehozása’ műveletet! common#:#ums_explanation_3#:#Külső bejelentkezésével nem tud csatlakozni ILIAS-fiókhoz. Az ILIAS emellett több ILIAS-fiókot talált az Ön e-mail címével. Ha ezek közül valamelyik az Öné, jelentkezzen be ILIAS-jelszavával. -common#:#ums_explanation_4#:#Ha egyik sem az Ön ILIAS-fiókja, válassza az 'Új ILIAS-fiók létrehozása' műveletet! +common#:#ums_explanation_4#:#Ha egyik sem az Ön ILIAS-fiókja, válassza az ‘Új ILIAS-fiók létrehozása’ műveletet! common#:#unambiguousness#:#Egyedi jellemző common#:#uncheck_all#:#Összes kijelölés megszüntetése common#:#unchecked#:#Nem bejelölve @@ -5840,20 +5871,21 @@ common#:#up#:#Fel common#:#update#:#Módosítás common#:#update_applied#:#Frissítés alkalmazva common#:#update_language#:#Nyelv frissítése -common#:#update_on_conflict#:#Frissítés konfliktus esetén. +common#:#update_on_conflict#:#A beszúrási/frissítési művelet automatikusan észlelése common#:#update_orgunits#:#Hozzárendelt szervezeti egységek frissítése -common#:#update_orgunits_desc#:#Ha be van kapcsolva, a 'Szervezeti egység' mező az összes ILIAS-fiókban módosul. +common#:#update_orgunits_desc#:#A ‘Szervezeti egység’ mező az összes ILIAS-fiókban módosul. common#:#upload#:#Feltöltés common#:#upload_error_file_not_found#:#Feltöltési hiba: a fájl nem található. -common#:#upload_ok#:#The upload was successful###29 10 2025 new variable +common#:#upload_ok#:#A feltöltés sikerült common#:#upload_pending#:#Folyamatban common#:#upload_settings#:#Fájlok feltöltési beállításai -common#:#upload_svg_rejection_message#:#An uploaded SVG file contains possibily malicious code and cannot be processed.###26 08 2024 new variable -common#:#upload_svg_rejection_message_base64#:#The file contains base64 encoded content.###26 08 2024 new variable -common#:#upload_svg_rejection_message_elements#:#The file contains elements or attributes which are not allowed or known.###26 08 2024 new variable -common#:#upload_svg_rejection_message_script#:#The file contains script-Elements.###26 08 2024 new variable +common#:#upload_svg_rejection_message#:#Az SVG-fájl vélhetően rosszindulatú kódot tartalmaz, ezért nem dolgoztuk fel. +common#:#upload_svg_rejection_message_base64#:#A fájl base64 kódolású részeket tartalmaz. +common#:#upload_svg_rejection_message_elements#:#A fájl nem engedélyezettek vagy ismeretlen elemeket, attribútumokat tartalmaz. +common#:#upload_svg_rejection_message_foreign_object#:#A fájl idegen objektumkat tartalmaz. +common#:#upload_svg_rejection_message_script#:#A fájl script-elemeket tartalmaz. common#:#uploaded_and_checked#:#A fájlt feltöltötte és sikeresen ellenőriztük. Elkezdheti importálását. -common#:#uploading#:#Feltöltés... +common#:#uploading#:#Feltöltés… common#:#uri#:#URI common#:#url#:#URL common#:#url_not_found#:#A fájl nem található. @@ -5863,8 +5895,8 @@ common#:#user#:#Felhasználó common#:#user_activated#:#A felhasználót sikeresen jóváhagyta common#:#user_added#:#Sikeresen létrehozott egy felhasználót. common#:#user_assignment#:#Felhasználó-hozzárendelés -common#:#user_avatar#:#User Avatar###29 07 2022 new variable -common#:#user_avatar_of#:#User Avatar of###29 07 2022 new variable +common#:#user_avatar#:#Profilkép +common#:#user_avatar_of#:#Profilkép - common#:#user_cant_receive_mail#:#%1$s – a felhasználónak nem engedélyezett a levelezőrendszer használata. common#:#user_comment#:#Felhasználói megjegyzés common#:#user_deactivated#:#Felhasználót kikapcsolta @@ -5873,7 +5905,7 @@ common#:#user_defined_list#:#Felhasználó-definiált adatmezők common#:#user_deleted#:#Felhasználót sikeresen törölte. common#:#user_detail#:#Adatok részletezése common#:#user_ext_account#:#Külső belépési jogosultság -common#:#user_ext_account_desc#:#Belépési jogosultság külső hitelesítéshez (SOAP- veya LDAP-hitelesítéshez) +common#:#user_ext_account_desc#:#Belépési jogosultság külső hitelesítéshez (CAS-, SOAP- vagy LDAP-hitelesítéshez) common#:#user_image#:#Felhasználói kép common#:#user_import_failed#:#Felhasználó importálás sikertelen. common#:#user_imported#:#Felhasználó importálás befejeződött. @@ -5883,7 +5915,7 @@ common#:#user_never_logged_in#:#Bejelentkezés nélküli fiókok törlése common#:#user_never_logged_in_info#:#Az összes bejelentkezés nélküli felhasználói fiókot töröljük. common#:#user_never_logged_in_info_threshold_err_num#:#Csak pozitív egész számot fogadunk el. common#:#user_new_account_mail#:#Új felhasználónak levél -common#:#user_new_account_mail_desc#:#Értesítő e-mail új felhasználóknak +common#:#user_new_account_mail_desc#:#Ezt az e-mailt küldjök ki az új, saját magukat, illetve a ‘Felhasználó értesítése a módosításról’ beállítással regisztrált felhasználóknak. common#:#user_not_found#:#A felhasználó nem található common#:#user_not_found_to_delete#:#A törlendő felhasználó nem található. common#:#user_not_known#:#Érvényes felhasználónevet adjon meg! @@ -5898,54 +5930,54 @@ common#:#userfolder_export_file_size#:#Fájlméret common#:#userfolder_export_files#:#Fájlok common#:#userfolder_export_xml#:#XML common#:#username#:#Felhasználónév -common#:#username_assistance#:#Username Assistance###26 08 2024 new variable +common#:#username_assistance#:#Felhasználónév segédlet common#:#users#:#Felhasználók -common#:#users_not_imported#:#Az alábbi felhasználók nem léteznek, üzeneteik nem importálhatóak +common#:#users_not_imported#:#Az alábbi felhasználók nem léteznek, üzeneteik nem importálhatók common#:#users_online#:#Aktív felhasználók common#:#usr#:#Felhasználó common#:#usr_account_inactive#:#Interaktív számla common#:#usr_active_only#:#Csak aktív felhasználók common#:#usr_add#:#Felhasználó létrehozása common#:#usr_edit#:#Felhasználó módosítása -common#:#usr_field_change_components_listening#:#There is at least one component which is interested in the changed configuration. Would you like to confirm the changes with the consequences the component(s) announced below?###29 07 2022 new variable +common#:#usr_field_change_components_listening#:#Van legalább egy komponens, amelyikre hatással van a konfiguráció módosítása. Biztos, hogy jóváhagyja a módosításokat az alábbi komponenseknél annak következményeivel? common#:#usr_filter_coursemember#:#Kurzus tagja common#:#usr_filter_groupmember#:#Csoport tagja common#:#usr_filter_lastlogin#:#Felhasználó utolsó bejelentkezése -common#:#usr_filter_role#:#Hozzárendelt szerep +common#:#usr_filter_role#:#Hozzárendelt szerepkör common#:#usr_inactive_only#:#Csak inaktív felhasználók common#:#usr_limited_access_only#:#Csak korlátozott hozzáféréssel rendelkező felhasználók common#:#usr_name_undisclosed#:#Nem publikus common#:#usr_new#:#Új felhasználó -common#:#usr_settings_changeable_lua#:#Módosítható a 'Helyi ILIAS-fiókok kezelése' alatt -common#:#usr_settings_explanation_profile#:#A 'Látható' jelölőnégyzet kipipálása a Regisztrációs lapon és a Felhasználói adatok oldalon teszi láthatóvá a mezőket.
    A 'Módosítható' jelölőnégyzet kipipálása a felhasználónak engedélyezi az adatmódosítást. Ne felejtse el, hogy a látható mezőket kitölthetik a regisztrációs lapon.
    A 'Kötelező' jelölőnégyzettel kipipált adatot a regisztrációs űrlapon és a felhasználói adatok űrlapon kötelező kitölteni. Ezektől a beállításoktól függetlenül a Rendszerbeállítások » ILIAS-fiókok menü alatt az összes adat módosítható. +common#:#usr_settings_changeable_lua#:#Módosítható a ‘Helyi ILIAS-fiókok kezelése’ alatt +common#:#usr_settings_explanation_profile#:#A ‘Látható’ jelölőnégyzet kipipálása a Regisztrációs lapon és a Felhasználói adatok oldalon teszi láthatóvá a mezőket.
    A ‘Módosítható’ jelölőnégyzet kipipálása a felhasználónak engedélyezi az adatmódosítást. Ne felejtse el, hogy a látható mezőket kitölthetik a regisztrációs lapon.
    A ‘Kötelező’ jelölőnégyzettel kipipált adatot a regisztrációs űrlapon és a felhasználói adatok űrlapon kötelező kitölteni. Ezektől a beállításoktól függetlenül a Rendszerbeállítások » ILIAS-fiókok menü alatt az összes adat módosítható. common#:#usr_settings_header_profile#:#Standard felhasználói adatmezők common#:#usr_settings_saved#:#A globális felhasználói beállítások mentése sikerült. -common#:#usr_settings_visib_lua#:#Látható a 'Helyi ILIAS-fiókok kezelése' alatt +common#:#usr_settings_visib_lua#:#Látható a ‘Helyi ILIAS-fiókok kezelése’ alatt common#:#usr_skin_style#:#Skin / Stílus common#:#usr_without_courses#:#Hozzárendelt kurzus nélküli felhasználók common#:#usrf#:#ILIAS-fiókok common#:#usrf_profile_link#:#Link a személyes adatokhoz common#:#usrimport_action_ignored#:#%1$ művelet figyelmen kívül hagyva. common#:#usrimport_action_replaced#:#%1$ művelet cserélve erre: %2$. -common#:#usrimport_cant_delete#:#Nem hajtható végre a 'Törlés'. Nincs ilyen felhasználó az adatbázisban. -common#:#usrimport_cant_insert#:#Nem hajtható végre a 'Beszúrás'. Már van ilyen felhasználó az adatbázisban. -common#:#usrimport_cant_update#:#Nem hajtható végre a 'Frissítés'. Nincs ilyen felhasználó az adatbázisban. -common#:#usrimport_conflict_handling_info#:#Ha az 'Ellentmondás figyelmen kívül hagyása' van kiválasztva, az ILIAS elutasítja a tevékenységet, ha nem hajtható végre (például a 'Beszúrás' tevékenység nem hajtódik végre, ha már van felhasználó a megadott felhasználónévvel az adatbázisban). Ha a 'Frissítés konfliktus esetén' van kiválasztva, az ILIAS frissíti az adatbázist, ha nem hajtható végre egy tevékenység (például a 'Beszúrás' tevékenységet lecseréli a 'Frissítés'-sel és fordítva, ha ugyanazon a felhasználónéven létezik már felhasználó a rendszerben). +common#:#usrimport_cant_delete#:#Nem hajtható végre a ‘Törlés’. Nincs ilyen felhasználó az adatbázisban. +common#:#usrimport_cant_insert#:#Nem hajtható végre a ‘Beszúrás’. Már van ilyen felhasználó az adatbázisban. +common#:#usrimport_cant_update#:#Nem hajtható végre a ‘Frissítés’. Nincs ilyen felhasználó az adatbázisban. +common#:#usrimport_conflict_handling_info#:#Ha az ‘A beszúrási/frissítési művelet szigorúan betartása’ van kiválasztva, az ILIAS elutasítja a tevékenységet, ha nem hajtható végre (például a ‘Beszúrás’ tevékenység nem hajtódik végre, ha már van felhasználó a megadott felhasználónévvel az adatbázisban). Ha a ‘A beszúrási/frissítési művelet automatikusan észlelése’ van kiválasztva, az ILIAS frissíti az adatbázist, ha nem hajtható végre egy tevékenység (például a ‘Beszúrás’ tevékenységet lecseréli a ‘Frissítés’-sel és fordítva, ha ugyanazon a felhasználónéven létezik már felhasználó a rendszerben). common#:#usrimport_form_not_evaluabe#:#Az űrlapadat nem olvasható be. -common#:#usrimport_global_role_for_action_required#:#Legalább egy globális szerepet meg kell határozni a '%1$s' tevékenységhez. -common#:#usrimport_ignore_role#:#Szerep mellőzése +common#:#usrimport_global_role_for_action_required#:#Legalább egy globális szerepkört meg kell határozni a ‘%1$s’ tevékenységhez. +common#:#usrimport_ignore_role#:#Szerepkör mellőzése common#:#usrimport_login_is_not_unique#:#Nem egyedi a felhasználónév. -common#:#usrimport_no_insert_ext_account_exists#:#Nem hajtható végre a 'Beszúrás' művelet. A külső felhasználói fiók már létezik. -common#:#usrimport_no_update_ext_account_exists#:#Nem hajtható végre a 'Frissítés' művelet. A külső felhasználói fiók már létezik. +common#:#usrimport_no_insert_ext_account_exists#:#Nem hajtható végre a ‘Beszúrás’ művelet. A külső felhasználói fiók már létezik. +common#:#usrimport_no_update_ext_account_exists#:#Nem hajtható végre a ‘Frissítés’ művelet. A külső felhasználói fiók már létezik. common#:#usrimport_with_specified_role_not_permitted#:#Az import a megadott szereppel nem engedélyezett. common#:#usrimport_wrong_file_count#:#Túl sok a fájl az importálandó mappában. Próbálja újra. -common#:#usrimport_xml_anonymous_or_root_not_allowed#:#Neither the system-account nor the anonymous account can be changed through the import.###26 08 2024 new variable -common#:#usrimport_xml_attribute_missing#:#Hiányzik a '%2$s' tulajdonság a '%1$s' elemből. -common#:#usrimport_xml_attribute_value_illegal#:#Nem érvényes a '%2$s' tulajdonság '%3$s' értéke a '%1$s' elemben. -common#:#usrimport_xml_attribute_value_inapplicable#:#'%2$s' attribútum '%3$s' értéke '%1$s' elemben nem használható '%4$s' tevékenységhez. -common#:#usrimport_xml_element_content_illegal#:#'%1$s' elem '%2$s' tartalma érvénytelen. -common#:#usrimport_xml_element_for_action_required#:#'%1$s' elemet specifikálni kell '%2$s' tevékenységhez. -common#:#usrimport_xml_element_inapplicable#:#'%1$s' elem nem alkalmazható '%2$s' tevékenységhez. +common#:#usrimport_xml_anonymous_or_root_not_allowed#:#Sem a rendszer-, sem anonymous fiók nem módosítható importálással. +common#:#usrimport_xml_attribute_missing#:#Hiányzik a ‘%2$s’ tulajdonság a ‘%1$s’ elemből. +common#:#usrimport_xml_attribute_value_illegal#:#Nem érvényes a ‘%2$s’ tulajdonság ‘%3$s’ értéke a ‘%1$s’ elemben. +common#:#usrimport_xml_attribute_value_inapplicable#:#‘%2$s’ attribútum ‘%3$s’ értéke ‘%1$s’ elemben nem használható ‘%4$s’ tevékenységhez. +common#:#usrimport_xml_element_content_illegal#:#‘%1$s’ elem ‘%2$s’ tartalma érvénytelen. +common#:#usrimport_xml_element_for_action_required#:#‘%1$s’ elemet specifikálni kell ‘%2$s’ tevékenységhez. +common#:#usrimport_xml_element_inapplicable#:#‘%1$s’ elem nem alkalmazható ‘%2$s’ tevékenységhez. common#:#valid#:#Érvényes common#:#validate#:#Érvényesítés common#:#value#:#Érték @@ -5961,7 +5993,7 @@ common#:#view_content#:#Tartalom nézet common#:#view_learning_progress#:#Tanulási haladás megjelenítése common#:#view_learning_progress_rec#:#Egység és alegységei Tanulási haladásának megjelenítése common#:#visible#:#Látható -common#:#visible_registration#:#Látható a 'Regisztráció' alatt +common#:#visible_registration#:#Látható a ‘Regisztráció’ alatt common#:#visitor#:#Látogató common#:#visitors#:#látogató common#:#visits#:#Látogatások @@ -5993,8 +6025,8 @@ common#:#webdav_upload_instructions#:#Útmutató feltöltése common#:#webfolder_dir_info#:#Böngészője nem tud webmappákat megnyitni. Olvassa el az útmutatót a webmappák megnyitásához. common#:#webfolder_index_of#:#%1$s indexe common#:#webfolder_instructions#:#Leírás webmappa használatához -common#:#webfolder_instructions_info#:#Azokban a böngészőkben, amelyek nem tudnak webmappákat közvetlenül megnyitni, a webmappa-utasítások láthatók. HTML-kódot és az alábbi dzsókerelemeket használhatja: [WEBFOLDER_TITLE], [WEBFOLDER_URI], [WEBFOLDER_URI], [WEBFOLDER_URI_KONQUEROR], [WEBFOLDER_URI_NAUTILUS], [ADMIN_MAIL], [WINDOWS]...[/WINDOWS], [MAC]...[/MAC], [LINUX]...[/LINUX]. Törölje ki a mezőt, hogy megkapja az alapértelmezett utasításokat! -common#:#webfolder_instructions_text#:#[WINDOWS]

    Utasítások Windows rendszerrel történő csatlakozáshoz

    1. Nyissa meg a Fájlkezelőt (például Windows + E billentyűkombináció).
    2. Válassza a 'Hálózati meghajtó csatlakoztatása' opciót.
    3. Adja a meg hálózati csatlakoztatandó mappának az következőt (másolja majd illessze be az URL-t):

      [WEBFOLDER_URI]

    4. Kattintson a 'Befejezés' gombra.
    5. Amennyiben szükséges, adja meg felhasználónevét és jelszavát.
    6. Ezután a hálózati meghajtót a többi meghajtók között megtalálja.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a személyes beállításai alatt tudja megváltoztatni.[/WINDOWS][MAC]

    Utasítások Mac OS X rendszerrel történő csatlakozáshoz

    1. Nyissa meg a Keresőt (Finder).
    2. Válassza a 'Menj > Kapcsolódás Szerverhez...' menüt.
      Erre a 'Kapcsolódás szerverhez' dialógusablak nyílik meg.
    3. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI]
      és válassza a ’Kapcsolódás’-t.
    4. Adja meg felhasználónevét és jelszavát, majd nyomja meg az 'OK' gombot.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a 'Munkaasztal' 'Beállítások' menüben alatt tudja megváltoztatni.[/MAC][LINUX]

    Utasítások Linux rendszerhez Konquerorral történő csatlakozáshoz

    1. Indítsa el a Konqueror böngészőt.
    2. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI_KONQUEROR]
      majd nyomja meg az Enter billentyűt.
    3. Adja meg felhasználónevét és jelszavát, majd nyomja meg az 'OK' gombot.

    Utasítások Linux rendszerhez Nautilus-szal történő csatlakozáshoz

    1. Indítsa el a Nautilus böngészőt.
    2. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI_NAUTILUS]
      majd nyomja meg az Enter billentyűt..
    3. Adja meg felhasználónevét és jelszavát, majd nyomja meg az 'OK' gombot.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a 'Munkaasztal' 'Beállítások' menüben alatt tudja megváltoztatni.[/LINUX]

    Tippek & támogatás

    • Ezeket a lépéséket csak egyszer szükséges végrehajtani. Később is elérheti ezt a kapcsolatot.
    • Almappához csatlakozhat, de a mappától felfelé már nem tud lépni.
    • Ha nem sikerül elérnie a hálózati meghajtót, vegye fel a kapcsolatot egy rendszergazdával.
    +common#:#webfolder_instructions_info#:#Azokban a böngészőkben, amelyek nem tudnak webmappákat közvetlenül megnyitni, a webmappa-utasítások láthatók. HTML-kódot és az alábbi dzsókerelemeket használhatja: [WEBFOLDER_TITLE], [WEBFOLDER_URI], [WEBFOLDER_URI], [WEBFOLDER_URI_KONQUEROR], [WEBFOLDER_URI_NAUTILUS], [ADMIN_MAIL], [WINDOWS][/WINDOWS], [MAC][/MAC], [LINUX][/LINUX]. Törölje ki a mezőt, hogy megkapja az alapértelmezett utasításokat! +common#:#webfolder_instructions_text#:#[WINDOWS]

    Utasítások Windows rendszerrel történő csatlakozáshoz

    1. Nyissa meg a Fájlkezelőt (például Windows + E billentyűkombináció).
    2. Válassza a ‘Hálózati meghajtó csatlakoztatása’ opciót.
    3. Adja a meg hálózati csatlakoztatandó mappának az következőt (másolja majd illessze be az URL-t):

      [WEBFOLDER_URI]

    4. Kattintson a ‘Befejezés’ gombra.
    5. Amennyiben szükséges, adja meg felhasználónevét és jelszavát.
    6. Ezután a hálózati meghajtót a többi meghajtók között megtalálja.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a személyes beállításai alatt tudja megváltoztatni.[/WINDOWS][MAC]

    Utasítások Mac OS X rendszerrel történő csatlakozáshoz

    1. Nyissa meg a Keresőt (Finder).
    2. Válassza a ‘Menj > Kapcsolódás Szerverhez…’ menüt.
      Erre a ‘Kapcsolódás szerverhez’ dialógusablak nyílik meg.
    3. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI]
      és válassza a ’Kapcsolódás’-t.
    4. Adja meg felhasználónevét és jelszavát, majd nyomja meg az ‘OK’ gombot.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a ‘Munkaasztal’ ‘Beállítások’ menüben alatt tudja megváltoztatni.[/MAC][LINUX]

    Utasítások Linux rendszerhez Konquerorral történő csatlakozáshoz

    1. Indítsa el a Konqueror böngészőt.
    2. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI_KONQUEROR]
      majd nyomja meg az Enter billentyűt.
    3. Adja meg felhasználónevét és jelszavát, majd nyomja meg az ‘OK’ gombot.

    Utasítások Linux rendszerhez Nautilus-szal történő csatlakozáshoz

    1. Indítsa el a Nautilus böngészőt.
    2. Szerver URL-nek a következő URL-t adja meg:
      [WEBFOLDER_URI_NAUTILUS]
      majd nyomja meg az Enter billentyűt..
    3. Adja meg felhasználónevét és jelszavát, majd nyomja meg az ‘OK’ gombot.

    Felhasználóneve és jelszava ugyanaz, mint amivel az ILIAS-ba be tud jelentkezni. Jelszavát a ‘Munkaasztal’ ‘Beállítások’ menüben alatt tudja megváltoztatni.[/LINUX]

    Tippek & támogatás

    • Ezeket a lépéséket csak egyszer szükséges végrehajtani. Később is elérheti ezt a kapcsolatot.
    • Almappához csatlakozhat, de a mappától felfelé már nem tud lépni.
    • Ha nem sikerül elérnie a hálózati meghajtót, vegye fel a kapcsolatot egy rendszergazdával.
    common#:#webfolder_instructions_titletext#:#Megnyitás webmappaként common#:#webfolder_mount_dir_with#:#Nyissa meg webmappaként ezt a lapot Internet Explorerrel, Konquerorral, Nautilusszal, más böngészővel. common#:#webr#:#Weblink @@ -6013,39 +6045,39 @@ common#:#wiki#:#Wiki common#:#wiki_add#:#Wiki létrehozása common#:#wiki_new#:#Új wiki common#:#with#:#ezzel: -common#:#withdraw_consent#:#Withdraw Acceptance -common#:#withdraw_consent_info_internal#:#If you confirm here, your account will be deleted. -common#:#withdraw_usr_agreement#:#Withdraw -common#:#withdrawal_complete#:#Withdrawal of consent complete. -common#:#withdrawal_complete_deleted#:#Withdrawal of consent complete, account deleted. -common#:#withdrawal_complete_redirect#:#Withdrawal of consent complete. To have the account deleted, please contact your organisation. -common#:#withdrawal_mail_info#:#The following email will be sent to an administrator after confirming the withdrawal:[BR][BR] -common#:#withdrawal_mail_subject#:#Withdrawal of Consent to Terms of Service -common#:#withdrawal_mail_text#:#Dear Sir or Madam,[BR][BR]I hereby withdraw my consent to your ILIAS installations terms of service. Please update/remove my account accordingly.[BR][BR]Name: %1$s[BR]Login: %2$s[BR]External Account: %3$s[BR][BR]Kind regards[BR]%1$s -common#:#withdrawal_sure_account#:#Are you sure you want to confirm the withdrawal of consent? -common#:#withdrawal_sure_account_deletion#:#Are you sure you want to confirm the withdrawal of consent? Your user account will be irrevocably deleted. -common#:#withdrawal_sure_account_deletion_no_consent_yet#:#Are you sure that you do not want to accept the Terms of Service? This will result in your user account being irrevocably deleted.###29 07 2022 new variable -common#:#withdrawal_sure_account_no_consent_yet#:#Are you sure that you do not want to accept the Terms of Service?###29 07 2022 new variable +common#:#withdraw_consent#:#Elfogadások visszavonása +common#:#withdraw_consent_info_internal#:#Jóváhagyása esetén az ILIAS-fiókját töröljük. +common#:#withdraw_usr_agreement#:#Visszavonás +common#:#withdrawal_complete#:#Sikeresen visszavonta a Szolgáltatási feltételek elfogadását. +common#:#withdrawal_complete_deleted#:#Sikeresen visszavonta a Szolgáltatási feltételek elfogadását, ILIAS-fókját eltávolítottuk. +common#:#withdrawal_complete_redirect#:#Sikeresen visszavonta a Szolgáltatási feltételek elfogadását. ILIAS-fiókja eltávolításához keresse fel szervezetét. +common#:#withdrawal_mail_info#:#A visszavonás jóváhagyása után a következő e-mail küldjük el az üzemeltőknek:[BR][BR] +common#:#withdrawal_mail_subject#:#Szolgáltatási feltételek elfogadásának visszavonása +common#:#withdrawal_mail_text#:#Tisztelt Üzemeltető,[BR][BR]ezúton visszavonom a Szolgáltatási feltételek elfogadását. Kérem, módosítsa/törölje fiókomat.[BR][BR]Név: %1$s[BR]Felhasználónév: %2$s[BR]Külső fiók: %3$s[BR][BR]Üdvözlettel[BR]%1$s +common#:#withdrawal_sure_account#:#Biztos, hogy visszavonja a Szolgáltatási feltételek elfogadását? +common#:#withdrawal_sure_account_deletion#:#Biztos, hogy visszavonja a Szolgáltatási feltételek elfogadását? ILIAS-fiókáját végérvényesen töröljük. +common#:#withdrawal_sure_account_deletion_no_consent_yet#:#Biztos, hogy nem fogadja el a Szolgáltatási feltételeket? Ebben az esetben az ILIAS-fiójkját véglegesen töröljük. +common#:#withdrawal_sure_account_no_consent_yet#:#Biztos, hogy nem fogadja el a Szolgáltatási feltételeket? common#:#wizard_search_list#:#Keresése az alábbi találatokat eredményezte. Válasszon egyet közülük. -common#:#wizard_title_info#:#Keresse meg a duplikálandó objektumot. Adja meg az objektum teljes címét vagy csak a cím egy részét, majd kattintson a 'Folytatás' gombra a találatok megjelenítéséhez. +common#:#wizard_title_info#:#Keresse meg a duplikálandó objektumot. Adja meg az objektum teljes címét vagy csak a cím egy részét, majd kattintson a ‘Folytatás’ gombra a találatok megjelenítéséhez. common#:#write#:#Írás common#:#year#:#Év common#:#yearly#:#évente common#:#years#:#Év common#:#yes#:#Igen common#:#yesterday#:#Tegnap -common#:#zip#:#Irányítószám +common#:#zip#:#Irányítószám / Postafiók common#:#zip_structure_error#:#Az archívum fájl azonos nevű fájlokat tartalmaz. A feltöltés megszakadt. common#:#zip_test_failed#:#ZIP tesztelése sikertelen. Lépjen kapcsolatba egy rendszergazdával. -common#:#zipcode#:#Irányítószám +common#:#zipcode#:#Irányítószám / Postafiók cond#:#cond_under_parent_control#:#Az előfeltételek a szülő objektumnál vannak beállítva. cont#:#cont_add_global_profile#:#Globális profil hozzáadása cont#:#cont_add_local_profile#:#Helyi profil hozzáadása cont#:#cont_add_skill#:#Kompetencia hozzáadása cont#:#cont_assign_competence#:#Kompetenciák tagokhoz rendelése cont#:#cont_assign_skills#:#Kompetenciák hozzárendelése -cont#:#cont_block_limit#:#Elemek számának korlátozás blokkonként -cont#:#cont_block_limit_info#:#Amennyiben a blokk több elemet tartalmaz, egy 'Több megjelenítése' gomb fog megjelenni. +cont#:#cont_block_limit#:#Objektumok számának korlátozás blokkonként +cont#:#cont_block_limit_info#:#Amennyiben a blokk több objektumot tartalmaz, egy ‘Több megjelenítése’ gomb fog megjelenni. cont#:#cont_cont_skills#:#Tagokhoz rendelt kompetenciák cont#:#cont_deassign_competence#:#Kompetenciák hozzárendeléseinek eltávolítása cont#:#cont_filter#:#Szűrés @@ -6054,20 +6086,21 @@ cont#:#cont_filter_fields#:#Szűrőmezők cont#:#cont_filter_record#:#Bejegyzések cont#:#cont_found_objects#:#Talált objektumok cont#:#cont_item_list#:#Felsorolás -cont#:#cont_item_list_info#:#Objects located within this container are displayed in the form of a list.###26 08 2024 new variable -cont#:#cont_list_presentation#:#Elemek megjelenítése +cont#:#cont_item_list_info#:#Ebben a tárolóban lévő objektumok felsorolásban jelennek meg. +cont#:#cont_list_presentation#:#Tartalom megjelenítési beállításai cont#:#cont_mem_skills#:#Kompetenciák cont#:#cont_news_edited#:#Módosította cont#:#cont_news_settings#:#Hírek beállításai cont#:#cont_news_timeline#:#Hírek idővonala cont#:#cont_news_timeline_auto_entries#:#Automatikus bejegyzések is megjelenjenek cont#:#cont_news_timeline_auto_entries_info#:#Összes automatikusan létrehozott hír is megjelenjen, mint például fórumhozzászólások, fájlok létrehozása. -cont#:#cont_news_timeline_info#:#Hírek idővonal fülének bekapcsolása +cont#:#cont_news_timeline_info#:#Hírek idővonal lapjának bekapcsolása cont#:#cont_news_timeline_landing_page#:#Kezdőoldal -cont#:#cont_news_timeline_landing_page_info#:#Idővonal lesz a kezdőoldal. +cont#:#cont_news_timeline_landing_page_info#:#Az Idővonal lap lesz a kezdőoldal. cont#:#cont_news_timeline_tab#:#Idővonal -cont#:#cont_no_title#:#Empty Title###26 08 2024 new variable -cont#:#cont_page_type_cont#:#Tartalomtár oldal (kurzusok, csoportok, ...) +cont#:#cont_no_title#:#Üres cím +cont#:#cont_only_crs_grp_fold_download#:#Csak kurzusok, csoportok, mappák vagy fájlok tölthetők le. +cont#:#cont_page_type_cont#:#Tartalomtár oldal (kurzusok, csoportok, …) cont#:#cont_page_type_cstr#:#Kurzus kezdő oldala (tanulási cél nézet) cont#:#cont_path#:#Útvonal cont#:#cont_publish_assignment#:#Összerendelések közzététele @@ -6077,15 +6110,15 @@ cont#:#cont_really_remove_skill_from_course#:#Biztos, hogy eltávolítja ezeket cont#:#cont_select_fields#:#Válasszon mezőket cont#:#cont_show_more#:#Több megjelenítése cont#:#cont_skill#:#Kompetencia -cont#:#cont_skill_ass_profiles#:#Assigned Profiles of Members###26 08 2024 new variable +cont#:#cont_skill_ass_profiles#:#Tagokhoz rendelt profilok cont#:#cont_skill_assigned_comp#:#Kompetencia kiválasztása cont#:#cont_skill_assigned_profiles#:#Profil kiválasztása cont#:#cont_skill_deletion_not_possible#:#Globális kompetenciaprofilok törlése nem lehetésges. Csak helyi kompetenciaprofilokat jelöljön ki. cont#:#cont_skill_do_not_set#:#Nem állít be cont#:#cont_skill_members#:#Tagok cont#:#cont_skill_no_profile_selected#:#Kérem, válasszon egy profilt. -cont#:#cont_skill_no_skill#:#Nincs érték (reszet) -cont#:#cont_skill_no_skills_selected#:#No competences have been selected yet. Please add at least one competence first under "Competence Selection".###26 08 2024 new variable +cont#:#cont_skill_no_skill#:#Nincs érték (alapértékre állítás) +cont#:#cont_skill_no_skills_selected#:#Egy kompetncia sincs még kiválasztva. Legalább egy kompetenciát adjon hozzá a "Kompetencia kiválasztása" alatt. cont#:#cont_skill_profile#:#Profil cont#:#cont_skill_profiles#:#Tagok profiljai cont#:#cont_skill_publish#:#Közzététel @@ -6097,8 +6130,8 @@ cont#:#cont_skill_really_delete_profile_from_list#:#Biztos, hogy törli ezt a pr cont#:#cont_skill_really_delete_profiles_from_list#:#Biztos, hogy törli ezeket a profilokat? cont#:#cont_skill_really_remove_profile_from_list#:#Biztos, hogy eltávolítja ezt a profilt a felsorolásból? cont#:#cont_skill_really_remove_profiles_from_list#:#Biztos, hogy eltávolítja ezeket a profilokat a felsorolásból? -cont#:#cont_skill_records#:#Competence Records###26 08 2024 new variable -cont#:#cont_skill_removal_not_possible#:#Lokális kompetenciaprofilok eltávolítsa nem lehetésges. Csak globális kompetenciaprofilokat jelöljön ki. +cont#:#cont_skill_records#:#Kompetencia-bejegyzések +cont#:#cont_skill_removal_not_possible#:#Lokális kompetenciaprofilok eltávolítsa nem lehetséges. Csak globális kompetenciaprofilokat jelöljön ki. cont#:#cont_std_filter_title_1#:#Cím cont#:#cont_std_filter_title_2#:#Leírás cont#:#cont_std_filter_title_3#:#Cím/Leírás @@ -6109,32 +6142,32 @@ cont#:#cont_std_filter_title_7#:#Oktatói támogatás cont#:#cont_std_filter_title_8#:#Objektumtípus cont#:#cont_std_filter_title_9#:#Online/Offline cont#:#cont_std_record_title#:#Standard -cont#:#cont_tile_size#:#Tile Size###29 07 2022 new variable -cont#:#cont_tile_size_0#:#normal (up to four tiles in a row)###29 07 2022 new variable -cont#:#cont_tile_size_1#:#small (up to six tiles in a row)###29 07 2022 new variable -cont#:#cont_tile_size_2#:#large (up to three tiles in a row)###29 07 2022 new variable -cont#:#cont_tile_size_3#:#extra large (up to two tiles in a row)###29 07 2022 new variable -cont#:#cont_tile_size_4#:#full (one tile in a row)###29 07 2022 new variable +cont#:#cont_tile_size#:#Csempeméret +cont#:#cont_tile_size_0#:#normal (1-4 csempe soronként) +cont#:#cont_tile_size_1#:#kicsi (1-6 csempe soronként) +cont#:#cont_tile_size_2#:#nagy (1-3 csempe soronként) +cont#:#cont_tile_size_3#:#extra nagy (1-2 csempe soronként) +cont#:#cont_tile_size_4#:#teljes (1 csempe soronként) cont#:#cont_tile_view#:#Csempék -cont#:#cont_tile_view_info#:#Objects located within this container are displayed in the form of thumbnail-style tiles. Images for these tiles can be uploaded in the settings of each individual object.###26 08 2024 new variable -cont#:#cont_trash_general_usage#:#If you want to remove a huge amount of old, deleted objects from the system it is highly advisable to start with non-container objects (i.e. Files, Glossaries, Tests,..) and thus removing all objects from the containers (Categories, Courses, Groups, Learning Sequences,...) . Using the filters "Type" and "Deleted on" helps this process. Then finally remove the containers.###28 10 2024 new variable +cont#:#cont_tile_view_info#:#Az ebben a tárolóban lévő objektumok megjelenítése mint miniatűrstílusú csempeként. Csempekép minden objektum saját beállításaiban tölthető fel. +cont#:#cont_trash_general_usage#:#Ha nagy mennyiségű régi, törölt objektumot kíván eltávolítani a rendszerből, akkor erősen tanácsos a nem tároló típusú objektumokkal kezdeni (például fájlok, fogalomtárak, tesztek), azaz célszerű először minden objektumot eltávolítani a tárolókból (kategóriákból, kurzusokból, csoportokból, tanulási sorokból stb. ). A ‘Típus" és a ‘Törlés helye’ szűrők használata segíti ezt a folyamatot. Végül távolítsa el a tárolókat. contact#:#contact_awrn_ap_contacts#:#Elfogadott jelölések contact#:#contact_awrn_ap_contacts_info#:#A felhasználó összes elfogadott jelölését felsoroljuk. -contact#:#contact_awrn_req_contacts#:#'Ismerősnek jelölés' kérések -contact#:#contact_awrn_req_contacts_info#:#Az összes felhasználót felsoroljuk, aki 'Ismerősnek jelölés' kérést küldött. +contact#:#contact_awrn_req_contacts#:#‘Ismerősnek jelölés’ kérések +contact#:#contact_awrn_req_contacts_info#:#Az összes felhasználót felsoroljuk, aki ‘Ismerősnek jelölés’ kérést küldött. content#:#Pages#:#Lapok content#:#add_menu_entry#:#Menübejegyzés hozzáadása content#:#all_pages#:#a teljes tananyag content#:#citate#:#Idéz -content#:#citate_from#:#Idéz honnan ... +content#:#citate_from#:#Idéz honnan … content#:#citate_page#:#Idézi ezt a lapot -content#:#citate_to#:#Idéz hol ... +content#:#citate_to#:#Idéz hol … content#:#cont_Additional#:#Egyéb információ content#:#cont_AdvancedKnowledge#:#Mélyebb ismeretek content#:#cont_Attention#:#Figyelmeztetés content#:#cont_Background#:#Háttér content#:#cont_Block#:#Blokk -content#:#cont_Book#:#Book###29 07 2022 new variable +content#:#cont_Book#:#Könyv content#:#cont_Circle#:#Kör content#:#cont_Citation#:#Idézet content#:#cont_Confirmation#:#Megerősítés @@ -6146,12 +6179,10 @@ content#:#cont_Headline2#:#Címsor 2 content#:#cont_Headline3#:#Címsor 3 content#:#cont_Information#:#Információ content#:#cont_Interaction#:#Kölcsönhatás -content#:#cont_Link#:#Link content#:#cont_List#:#Lista content#:#cont_Literature#:#Irodalom -content#:#cont_Media#:#Média (standard) content#:#cont_Mnemonic#:#Emlékezést segítő -content#:#cont_Numbers#:#Numbers###29 07 2022 new variable +content#:#cont_Numbers#:#Számok content#:#cont_Poly#:#Sokszög content#:#cont_Rect#:#Téglalap content#:#cont_Remark#:#Megjegyzés @@ -6159,8 +6190,8 @@ content#:#cont_Separator#:#Elválasztó content#:#cont_Special#:#Különösen content#:#cont_StandardCenter#:#Szövegtörzs középre content#:#cont_StandardTable#:#Standard táblázat -content#:#cont_TableContent#:#Tartalomtáblázat -content#:#cont_Verse#:#Verse/Stanza###29 07 2022 new variable +content#:#cont_TableContent#:#Táblázattartalom +content#:#cont_Verse#:#Verssor/Strófa content#:#cont_WholePicture#:#Teljes kép content#:#cont_accented#:#Ékezetes content#:#cont_act_number#:#Fejezetszámozás @@ -6176,18 +6207,18 @@ content#:#cont_active_from#:#Aktiválás kezdete content#:#cont_active_to#:#Aktiválás vége content#:#cont_add_area#:#Terület hozzáadása content#:#cont_add_cell#:#Oszlop hozzáadása -content#:#cont_add_elements#:#Új elem hozzáadásához kattintson egy csíkozott helyőrzőre. +content#:#cont_add_elements#:#Egy új tartalomelem hozzáadásához kattintson egy + jelre. content#:#cont_add_file#:#Fájl hozzáadása content#:#cont_add_images#:#Kép hozzáadása content#:#cont_add_popup#:#Felugró ablak hozzáadása content#:#cont_add_tab#:#Panel hozzáadása -content#:#cont_add_url#:#From URL +content#:#cont_add_url#:#URL megadása content#:#cont_added_cell#:#Az oszlopot sikeresen hozzáadta. -content#:#cont_added_comment#:#A megjegyzést felvette az előzményekbe. +content#:#cont_added_comment#:#A megjegyzést felvette a tananyag előzményeibe (lásd Tartalom » Előzmények lap). content#:#cont_added_tab#:#Sikeresen létrehozott egy panelt. content#:#cont_added_term#:#A fogalmat sikeresen hozzáadta. content#:#cont_adjust_size#:#Méretre igazítás -content#:#cont_advanced_settings#:#Advanced Settings +content#:#cont_advanced_settings#:#További beállítások content#:#cont_align#:#Igazítás content#:#cont_alignment#:#Elrendezés content#:#cont_all_answers_correct#:#Helyes! @@ -6196,8 +6227,8 @@ content#:#cont_all_languages#:#Összes nyelv content#:#cont_all_pages#:#Összes lap content#:#cont_all_topics#:#Összes téma content#:#cont_all_usages#:#Korábbi verziók, amik használják -content#:#cont_alphabetic#:#Alfabetikus A, B, ... -content#:#cont_alphabetic_s#:#Alfabetikus a, b, ... +content#:#cont_alphabetic#:#Alfabetikus A, B, … +content#:#cont_alphabetic_s#:#Alfabetikus a, b, … content#:#cont_always#:#Mindig content#:#cont_anchor#:#Horgony content#:#cont_annex#:#Melléklet @@ -6209,12 +6240,12 @@ content#:#cont_assign_std#:#Ez legyen az alapértelmezett content#:#cont_assign_to_parent#:#Szülőhöz rendelés content#:#cont_auto_glossaries#:#Automatikusan linkelt fogalomtárak content#:#cont_auto_last_visited#:#Folytatás az utoljára megtekintett fejezettel -content#:#cont_auto_last_visited_info#:#A leggyakrabban megtekintett SCO/Asset megjelenítése, amikor a felhasználó újra megnyitja a tananyagot. +content#:#cont_auto_last_visited_info#:#A SCORM-tananyag újbóli megnyitásakor az utoljára megtekintett szakasz jelenik meg. content#:#cont_auto_suspend#:#Nyomkövetési adatok védelme -content#:#cont_auto_suspend_info#:#Ez az opció olyan SCORM-tananyagokhoz van, melyek hibás módon támogatják a SCORM 2004-et, hibás értékeket küldve a cmi.exit részére.
    Ez biztosítja a nyomkövetési adatok tárolását akkor is, amikor a felhasználó nem megfelelően zárja be a tananyagot (például bezárja a böngészőt). +content#:#cont_auto_suspend_info#:#Ez az opció olyan SCORM-tananyagokhoz van, melyek hibás módon támogatják a SCORM-ot, hibás értékeket küldve a cmi.exit részére.
    Ez biztosítja a nyomkövetési adatok tárolását akkor is, amikor a felhasználó nem megfelelően zárja be a tananyagot (például bezárja a böngészőt). content#:#cont_auto_time#:#Automatikus animáció várakozási ideje content#:#cont_autoindent#:#Automatikus behúzás -content#:#cont_automatically_set_store_tries#:#'$2' opció aktiválása automatikusan bekapcsolta a(z) '$1' opciót. +content#:#cont_automatically_set_store_tries#:#‘$2’ opció aktiválása automatikusan bekapcsolta a(z) ‘$1’ opciót. content#:#cont_autostart#:#Automatikus indítás content#:#cont_back#:#Vissza content#:#cont_base_image#:#Háttérkép @@ -6223,10 +6254,10 @@ content#:#cont_behavior#:#Viselkedés content#:#cont_biblio#:#Bibliográfiai adat content#:#cont_biblio_info#:#Bibliográfiai adattulajdonság bekapcsolása content#:#cont_blist#:#Listajeles felsorolás -content#:#cont_block_format#:#Section Format +content#:#cont_block_format#:#Kijelölés formátuma content#:#cont_blocked_users#:#Blokkolt felhasználók content#:#cont_blocked_users_mail_link#:#Kattintson az alábbi linkre a tananyag megnyitásához: -content#:#cont_bottom#:#Aljára +content#:#cont_bottom#:#Alulra content#:#cont_bullet_list#:#Listajeles felsorolás content#:#cont_cach_mode#:#Mód content#:#cont_cach_mode_automatic#:#Automatikus @@ -6237,21 +6268,21 @@ content#:#cont_cant_copy_folders#:#A mappák nem másolhatók a vágólapra. content#:#cont_cant_del_full#:#A teljes képernyős fájl nem törölhető. content#:#cont_cant_del_std#:#A szabvány nézetű fájl nem törölhető. content#:#cont_caption#:#Felirat -content#:#cont_caption_style#:#Caption Style Class###29 07 2022 new variable +content#:#cont_caption_style#:#Felirat stílusosztály content#:#cont_cc_emp#:#Dőlt content#:#cont_cc_imp#:#Fontos content#:#cont_cc_str#:#Félkövér content#:#cont_cc_sub#:#Alsó index content#:#cont_cc_sup#:#Felső index -content#:#cont_cell_properties#:#Table Cell Properties###26 08 2024 new variable +content#:#cont_cell_properties#:#Cellák tulajdonságai content#:#cont_center#:#Középre -content#:#cont_change_alignment#:#Change Alignment###26 08 2024 new variable +content#:#cont_change_alignment#:#Igazítás módosítása content#:#cont_change_notification_salutation#:#Tisztelt %s, -content#:#cont_change_notification_subject_lm#:#'%1$s' tananyag megváltozott: %2$s +content#:#cont_change_notification_subject_lm#:#‘%1$s’ tananyag megváltozott: %2$s content#:#cont_change_object_reference#:#Objektumhivatkozás cseréje -content#:#cont_change_style#:#Change Style###26 08 2024 new variable +content#:#cont_change_style#:#Stílus módosítása content#:#cont_change_type#:#Típus cseréje -content#:#cont_change_width#:#Change Width###26 08 2024 new variable +content#:#cont_change_width#:#Szélesség módosítása content#:#cont_chap_and_pages#:#Fejezetek és lapok content#:#cont_chap_select_target_now#:#A fejezet áthelyezésre bejelölt. Most jelölje ki, hogy mi után kerüljön beszúrásra! content#:#cont_chapters#:#Fejezetek @@ -6259,24 +6290,26 @@ content#:#cont_chapters_after_pages#:#Ne felejtse el, hogy a lapoknak ugyanazon content#:#cont_chapters_and_pages#:#Fejezetek és lapok content#:#cont_chapters_only#:#Csak fejezetek content#:#cont_char_format#:#Karakter +content#:#cont_char_link#:#Link +content#:#cont_char_media#:#Média (Standard) content#:#cont_char_style_acc#:#Kiemelt content#:#cont_char_style_code#:#Kód content#:#cont_char_style_com#:#Megjegyzés content#:#cont_char_style_quot#:#Idézet content#:#cont_characteristic#:#Stílusosztály -content#:#cont_characteristic_table#:#Style Class###26 08 2024 new variable +content#:#cont_characteristic_table#:#Stílusosztály content#:#cont_check_values#:#SCO-ból küldött értékek ellenőrzése content#:#cont_check_values_info#:#A Teszteszköz ellenőrzi, hogy a SCO-k a SCORM-szabványoknak megfelelő adatokat küld-e.
    A SCORM-szabvány nagyon pontosan előírja az értékek mentését. Nem minden tananyag felel meg ezeknek az elvárásoknak. Ezen opcióval ellenőrizhető, hogy a tananyag ezen szabványnak megfelel-e vagy sem. Ne kapcsolja be, ha csak arra kíváncsi, hogy az ILIAS képes-e a tananyagot futtatni. content#:#cont_choose_characteristic#:#Válasszon jellemzőt content#:#cont_choose_characteristic_section#:#Részek content#:#cont_choose_characteristic_text#:#Szövegelemek content#:#cont_choose_file_source#:#Forrás -content#:#cont_choose_from_clipboard#:#Choose from Clipboard###29 07 2022 new variable -content#:#cont_choose_from_pool#:#Select from Media Pool +content#:#cont_choose_from_clipboard#:#Válasszon a vágólapról +content#:#cont_choose_from_pool#:#Választás médiagyűjteményből content#:#cont_choose_glo#:#Fogalomtár választása content#:#cont_choose_lm#:#Tananyag választása content#:#cont_choose_local#:#Helyi mappa -content#:#cont_choose_media_pool#:#Select Pool +content#:#cont_choose_media_pool#:#Gyűjtemény kiválasztása content#:#cont_choose_mep#:#Médiagyűjtemény választása content#:#cont_choose_pages_or_chapters_only#:#Vagy csak lapokat vagy csak fejezeteket válasszon! content#:#cont_choose_upload_dir#:#Feltöltési mappa @@ -6285,14 +6318,14 @@ content#:#cont_citation_selection_not_valid#:#A választása nem érvényes content#:#cont_click_br_corner#:#Kattintson a kívánt terület jobb alsó sarkára. content#:#cont_click_center#:#Kattintson a kívánt terület középpontjára. content#:#cont_click_circle#:#Kattintson a kívánt területet határoló körvonal egy pontjára. -content#:#cont_click_edit#:#Click on elements to edit its properties.###29 07 2022 new variable -content#:#cont_click_multi_select#:#Click on elements to select or deselect them.###29 07 2022 new variable +content#:#cont_click_edit#:#Módosításhoz kattintson a kívánt tartalomelemre. +content#:#cont_click_multi_select#:#Kijelöléshez kattintson a kívánt tartalomelemre. content#:#cont_click_next_or_save#:#Kattintson a sokszög következő pontjára, vagy mentse a területet. (Nem szükséges újra a sokszög kezdőpontjára kattintani.) content#:#cont_click_next_point#:#Kattintson a sokszög következő pontjára. content#:#cont_click_starting_point#:#Kattintson a sokszög kezdőpontjára. content#:#cont_click_tl_corner#:#Kattintson a kívánt terület bal felső sarkába. -content#:#cont_code_import_file#:#Import###26 08 2024 new variable -content#:#cont_code_manual_editing#:#Manuelle Eingabe###26 08 2024 new variable +content#:#cont_code_import_file#:#Importálás +content#:#cont_code_manual_editing#:#Kézi bevitel content#:#cont_colspan#:#Col. Span content#:#cont_commented_by#:#A hozzászólást írta content#:#cont_comments#:#Megjegyzések tárolása @@ -6311,7 +6344,7 @@ content#:#cont_correct_answer_also#:#Szintén helyes: content#:#cont_correct_answers_also#:#Szintén helyesek: content#:#cont_correct_answers_shown#:#A helyes válaszok fent láthatók. content#:#cont_could_not_determine_resource_size#:#Az ILIAS nem tudja automatikusan meghatározni a forrás méretét. -content#:#cont_could_not_save_duplicate_pc_ids#:#Page could not be saved (duplicate PC IDs).###29 07 2022 new variable +content#:#cont_could_not_save_duplicate_pc_ids#:#Az oldal nem menthető (duplikált PC ID-k). content#:#cont_cp_question_diff_formats_info#:#Vegye figyelembe, hogy néhány formázás nem támogatott a tartalmakban. content#:#cont_create_link#:#Link létrehozása content#:#cont_create_mob#:#Médiaobjektum létrehozása @@ -6337,7 +6370,7 @@ content#:#cont_deactivated#:#Kikapcsolva content#:#cont_debug#:#Teszteszköz engedélyezése content#:#cont_debug_deactivate#:#A Teszteszköz a tananyag megjelenítésekor válik láthatóvá, a tananyag és az ILIAS interakciója alapján létrejövő adatokat vizsgálja. A Teszteszköz használatához a Navigációs-fát ki kell kapcsolni.### content#:#cont_debug_deactivate12#:#A Teszteszköz a tananyag megjelenítési módjában fog megjelenni. Az általa szolgáltatott adatok alapján értékelhető a tananyag és az ILIAS interakciója. -content#:#cont_debug_deactivated#:#A Teszteszköz használatát központilag letiltották (Rendszerbeállítások » Tanulási források alatt módosítható). +content#:#cont_debug_deactivated#:#A Teszteszköz használatát központilag letiltották (Rendszerbeállítások » Tananyagok menüpont alatt módosítható). content#:#cont_debugging#:#Nyomkövetés content#:#cont_decimal#:#Decimális content#:#cont_def_feedb_activated#:#Az alapértelmezett visszajelzés-szövegek be vannak kapcsolva a tananyag beállításiban. @@ -6348,7 +6381,7 @@ content#:#cont_def_map_areas#:#Alapértelmezett linkterületek content#:#cont_def_organization#:#alapértelmezett content#:#cont_default#:#Alapértelmezett content#:#cont_definition#:#Meghatározás -content#:#cont_delete_content#:#Delete Content +content#:#cont_delete_content#:#Tartalom törlése content#:#cont_delete_selected#:#Törlés content#:#cont_delete_style#:#Stílus törlése content#:#cont_delete_track_data#:#Nyomkövetési adatok törlése @@ -6358,11 +6391,11 @@ content#:#cont_dir_deleted#:#A mappát sikeresen törölte. content#:#cont_dir_file#:#Mappa / fájl content#:#cont_dir_renamed#:#A mappát sikeresen átnevezte. content#:#cont_disable_def_feedback#:#Alapértelmezett kérdés-visszajelzés tiltása -content#:#cont_disable_def_feedback_info#:#Ha ki van kapcsolva, megválaszolt kérdések semmilyen visszajelzést nem jelenítenek meg a hallgatónak. Egyéni visszajelzéseket szükséges megadni a kérdésekhez. +content#:#cont_disable_def_feedback_info#:#A kérdés általános visszajelzése nem jelenik meg a kérdés megválaszolás után. content#:#cont_download#:#Letöltés content#:#cont_download_title#:#Letöltési cím -content#:#cont_drag_and_drop_elements#:#Tartalom mozgatásához fogja meg egérrel annak helyőrzőjét, majd vigye egy csíkozott helyőrzőre. -content#:#cont_drag_element_click_save#:#Fogja és vigye az elemet a kívánt pozícióba, majd kattintson a 'Mentés' gombra. +content#:#cont_drag_and_drop_elements#:#Tartalomelem mozgatásához fogja meg egérrel, majd vigye egy + jelre. +content#:#cont_drag_element_click_save#:#Fogja és vigye az elemet a kívánt pozícióba, majd kattintson a ‘Mentés’ gombra. content#:#cont_ed_align_center#:#Igazítás: középre content#:#cont_ed_align_left#:#Igazítás: balra content#:#cont_ed_align_left_float#:#Igazítás: körbefuttatás jobbról @@ -6395,38 +6428,38 @@ content#:#cont_ed_go#:#OK content#:#cont_ed_grid_col_width#:#Oszlopszélesség content#:#cont_ed_grid_col_width_info#:#Az oszlopszélesség - a képernyő méretétől függően - a sor 1/12-ed részének többszöröse. Eszközöket adunk meg példának, a képernyő mérete határozza meg a konkrét viselkedést. 12/12 a 100%-os szélesség. content#:#cont_ed_grid_col_widths#:#Oszlopszélességek -content#:#cont_ed_insert_amdfrm#:#Insert Advanced Metadata###29 07 2022 new variable -content#:#cont_ed_insert_amdpl#:#Insert Page List###29 07 2022 new variable +content#:#cont_ed_insert_amdfrm#:#Fejlett metaadat beszúrása +content#:#cont_ed_insert_amdpl#:#Oldallista beszúrása content#:#cont_ed_insert_blog#:#Blog beszúrása -content#:#cont_ed_insert_cach#:#Insert Consultation Hours###29 07 2022 new variable +content#:#cont_ed_insert_cach#:#Konzultációs időpontok beszúrása content#:#cont_ed_insert_dtab#:#Táblázat beszúrása -content#:#cont_ed_insert_flst#:#Insert File List###29 07 2022 new variable +content#:#cont_ed_insert_flst#:#Fájllista beszúrása content#:#cont_ed_insert_grid#:#Oszlopos elrendezés beszúrása content#:#cont_ed_insert_grid_info#:#Soronként 12 egységre osztott reszponzív oszlopos elrendezés hozzáadása. content#:#cont_ed_insert_iim#:#Interaktív kép beszúrása content#:#cont_ed_insert_incl#:#Tartalom-építőelem beszúrása -content#:#cont_ed_insert_lay#:#Insert Layout Template###26 08 2024 new variable -content#:#cont_ed_insert_lhist#:#Insert Learning History###29 07 2022 new variable +content#:#cont_ed_insert_lay#:#Elrendezéssablon beszúrása +content#:#cont_ed_insert_lhist#:#Tanulási történelem beszúrása content#:#cont_ed_insert_list#:#Fejlettebb felsorolás beszúrása -content#:#cont_ed_insert_lpe#:#Insert Login Page Element###29 07 2022 new variable +content#:#cont_ed_insert_lpe#:#Bejelentkezési lap elemének beszúrása content#:#cont_ed_insert_map#:#Térkép beszúrása -content#:#cont_ed_insert_mcrs#:#Insert My Courses###29 07 2022 new variable +content#:#cont_ed_insert_mcrs#:#Kurzusaim beszúrása content#:#cont_ed_insert_media#:#Kép/média beszúrása content#:#cont_ed_insert_par#:#Szöveg beszúrása content#:#cont_ed_insert_pcqst#:#Kérdés beszúrása content#:#cont_ed_insert_plach#:#Helyőrző beszúrása -content#:#cont_ed_insert_prof#:#Insert Personal Data###29 07 2022 new variable +content#:#cont_ed_insert_prof#:#Személyes adatok beszúrása content#:#cont_ed_insert_qover#:#Kérdésáttekintés beszúrása content#:#cont_ed_insert_repobj#:#Forráslista beszúrása content#:#cont_ed_insert_sec#:#Bekezdés beszúrása content#:#cont_ed_insert_skills#:#Kompetenciák beszúrása -content#:#cont_ed_insert_src#:#Kód beszúrása +content#:#cont_ed_insert_src#:#Forráskód beszúrása content#:#cont_ed_insert_tab#:#Fejlettebb táblázat beszúrása content#:#cont_ed_insert_tabs#:#Harmonika beszúrása content#:#cont_ed_insert_templ#:#Tartalomsablon beillesztése -content#:#cont_ed_insert_vrfc#:#Insert Certificate###29 07 2022 new variable -content#:#cont_ed_item_down#:#Elem lefelé mozgatása -content#:#cont_ed_item_up#:#Elem felfelé mozgatása +content#:#cont_ed_insert_vrfc#:#Tanúsítvány beszúrása +content#:#cont_ed_item_down#:#Elem mozgatása lefelé +content#:#cont_ed_item_up#:#Elem mozgatása felfelé content#:#cont_ed_list#:#Fejlettebb felsorolás content#:#cont_ed_moveafter#:#Mozgatás utána content#:#cont_ed_movebefore#:#Mozgatás elé @@ -6436,8 +6469,8 @@ content#:#cont_ed_new_item_after#:#Új elem utána content#:#cont_ed_new_item_before#:#Új elem elé content#:#cont_ed_new_row_after#:#Új sor utána content#:#cont_ed_new_row_before#:#Új sor elé -content#:#cont_ed_nr_cols#:#Number of Columns###26 08 2024 new variable -content#:#cont_ed_nr_rows#:#Number of Rows###26 08 2024 new variable +content#:#cont_ed_nr_cols#:#Oszlopok száma +content#:#cont_ed_nr_rows#:#Sorok száma content#:#cont_ed_par#:#Szöveg content#:#cont_ed_paste#:#Beillesztés content#:#cont_ed_paste_clip#:#Beillesztés vágólapról @@ -6446,7 +6479,7 @@ content#:#cont_ed_plachmedia#:#Kép-/médiahelyőrző content#:#cont_ed_plachprop#:#Helyőrző-tulajdonságok content#:#cont_ed_plachquestion#:#Kérdéshelyőrző content#:#cont_ed_plachtext#:#Szöveghelyőrző -content#:#cont_ed_plachverification#:#Helyőrző tanúsítvány +content#:#cont_ed_plachverification#:#Tanúsítványhelyőrző content#:#cont_ed_row_down#:#Sor lefelé mozgatása content#:#cont_ed_row_up#:#Sor felfelé mozgatása content#:#cont_ed_select_pctext#:#Szövegtétel kiválasztása @@ -6455,16 +6488,16 @@ content#:#cont_ed_split_page_next#:#Következő lapra tördelés content#:#cont_ed_textitem#:#Szövegtétel content#:#cont_ed_width#:#szélesség content#:#cont_edit_base_image#:#Háttérkép módosítása -content#:#cont_edit_comp#:#Editing +content#:#cont_edit_comp#:#Szerkesztés content#:#cont_edit_definition#:#Meghatározás módosítása content#:#cont_edit_file_list_properties#:#Fájllista-tulajdonságok módosítása content#:#cont_edit_language_version#:#Verzió módosítása content#:#cont_edit_lrs_settings#:#Beállítások módosítása -content#:#cont_edit_marker_position#:#Jelző helyének módosítása +content#:#cont_edit_marker_position#:#Jelölő helyének módosítása content#:#cont_edit_mob#:#Médiaobjektum módosítása content#:#cont_edit_mob_alias_prop#:#Médiaobjektum-példány tulajdonságainak módosítása content#:#cont_edit_mode#:#Szerkesztőmód -content#:#cont_edit_multi#:#Selection +content#:#cont_edit_multi#:#Kiválasztása content#:#cont_edit_overlay_position#:#Fedés helyének módosítása content#:#cont_edit_par#:#Szöveg módosítása content#:#cont_edit_personal_data#:#Személyes adatok módosítása @@ -6476,16 +6509,16 @@ content#:#cont_edit_shape_rectangle#:#Alakzat (téglalap) módosítása content#:#cont_edit_shape_whole_picture#:#Alakzat módosítása (teljes kép) content#:#cont_edit_src#:#Forráskód módosítása content#:#cont_edit_style#:#Stílus módosítása -content#:#cont_edit_table#:#Edit Table###26 08 2024 new variable +content#:#cont_edit_table#:#Táblázat módosítása content#:#cont_edit_tabs#:#Tulajdonságok content#:#cont_edit_term#:#Fogalom módosítása -content#:#cont_edit_title#:#Change Title###26 08 2024 new variable +content#:#cont_edit_title#:#Cím módosítása content#:#cont_element_refers_removed_itgr#:#Ez a tartalomelem olyan objektumcsoportra hivatkozik, amelyet időközben eltávolítottak. content#:#cont_empty_question#:#A kérdésszerkesztés nem fejeződött be. Kattintson a kérdésre és szerkessze azt, vagy törölje. content#:#cont_enable_page_history#:#Lapelőzmények content#:#cont_enable_page_history_info#:#A lapok régebbi verzióinak tárolása és az azokra visszagörgetés lehetősége. content#:#cont_enable_time_scheduled_page_activation#:#Lapaktiválás ütemezése -content#:#cont_enable_time_scheduled_page_activation_info#:#Ha be van kapcsolva, aktiválási időszak (dátum/időpont) állítható a lapokhoz a tananyagszerkesztőben. +content#:#cont_enable_time_scheduled_page_activation_info#:#Aktiválási időszak (dátum/időpont) állítható a lapokhoz a tananyagszerkesztőben. content#:#cont_end#:#Záró időpont content#:#cont_enough_answers_correct#:#Helyes, de nem a legjobb megoldás! content#:#cont_enter_a_dir_name#:#Adjon meg egy mappanevet! @@ -6503,10 +6536,10 @@ content#:#cont_file_deleted#:#A fájlt törölték. content#:#cont_file_from_repository#:#Fájl a Tartalomtárból content#:#cont_file_from_workspace#:#Fájl a Személyes Erőforrásokből content#:#cont_file_renamed#:#A fájl neve megváltozott. -content#:#cont_file_unzipped#:#A fájlt kicsomagoltuk. +content#:#cont_file_unzipped#:#A fájlt sikeresen kicsomagolta. content#:#cont_files#:#Fájlok content#:#cont_finish_editing#:#Szerkesztés befejezése -content#:#cont_finish_table_editing#:#Finish Data Table Editing###26 08 2024 new variable +content#:#cont_finish_table_editing#:#Adattábla szerkesztésének befejezése content#:#cont_first_open#:#Első panel kinyitva content#:#cont_first_page#:#Első oldal content#:#cont_first_row_style#:#Első sor stílusosztálya @@ -6514,23 +6547,23 @@ content#:#cont_fix_tree#:#Struktúrajavítás content#:#cont_fix_tree_confirm#:#Csak akkor hajtsa végre ezt az utasítást, ha ennek a tananyagnak a faszerkezete hibás, például ha üres elemek jelennek meg a böngészőnézetben. content#:#cont_fn#:#Lábjegyzet content#:#cont_footer#:#Lábléc -content#:#cont_footnote#:#Footnote###29 07 2022 new variable +content#:#cont_footnote#:#Lábjegyzet content#:#cont_force_all_open#:#Összes kinyitásának kényszerítése content#:#cont_format#:#Formátum -content#:#cont_format_cells#:#Format Cells###26 08 2024 new variable +content#:#cont_format_cells#:#Cellák formázása content#:#cont_fourth_edition#:#SCORM 2004 4th edition content#:#cont_fourth_edition_info#:#SCORM 2004 4th edition néhány előnnyel bír a 3rd edition-hoz képest: adat lehet átvinni SCO-k között. Ezek a lehetőségeket azonban csak ritkán használjuk, és negatív hatással vannak a sebességre. content#:#cont_free_pages#:#Szabad lapok content#:#cont_full_is_in_dir#:#A törlés nem lehetséges. Teljes képernyős fájl van a mappában. content#:#cont_fullscreen#:#Teljes képernyő content#:#cont_general_properties#:#Általános tulajdonságok -content#:#cont_get_link#:#link lekérdezése +content#:#cont_get_link#:#→ célobjektum kiválasztása content#:#cont_glo_assign#:#Fogalomtárhoz rendelés content#:#cont_glo_create#:#Fogalomtár létrehozása content#:#cont_glo_detach#:#Fogalomtár leválasztása content#:#cont_glo_properties#:#Fogalomtár tulajdonságai content#:#cont_glossaries#:#Fogalomtárak -content#:#cont_got_lock_release#:#Ezt a lapot zároltuk, mert Ön szerkesztésre megnyitotta. A 'Szerkesztés befejezése' gomb megnyomásával a zárolást feloldhatja manuálisan, vagy azt automatikusan feloldjuk ekkor: %1. +content#:#cont_got_lock_release#:#Ezt a lapot a megnyitotta szerkesztésre, evvel zárolta is. A ‘Szerkesztés befejezése’ gomb megnyomásával a zárolást feloldhatja manuálisan, vagy azt automatikusan feloldjuk ekkor: %1. content#:#cont_grid_cell#:#Oszlop content#:#cont_grid_cell_confirm_deletion#:#Biztos, hogy törli a kiválasztott oszlopo(ka)t? content#:#cont_grid_nr_cells#:#Oszlopok száma @@ -6552,9 +6585,9 @@ content#:#cont_grid_width_s#:#Kicsi content#:#cont_grid_width_s_info#:#Például mobil content#:#cont_grid_width_xl#:#Extra nagy content#:#cont_grid_width_xl_info#:#Például széles asztali monitor -content#:#cont_hacc_needs_height#:#Please set a content height for horizontal accordions.###26 08 2024 new variable -content#:#cont_hacc_needs_width#:#Please set a content width for horizontal accordions.###26 08 2024 new variable -content#:#cont_has_row_header#:#Has a Header Row###26 08 2024 new variable +content#:#cont_hacc_needs_height#:#Kérjük, állítsa be a vízszintes harmonika tartalommagasságát. +content#:#cont_hacc_needs_width#:#Kérjük, állítsa be a függőleges harmonika tartalommagasságát. +content#:#cont_has_row_header#:#Van fejléce content#:#cont_header#:#Fejléc content#:#cont_height#:#Magasság pixelben content#:#cont_help_no_valid_tooltip_id#:#A megadott tooltip_id nem érvényes. @@ -6574,27 +6607,27 @@ content#:#cont_ie_compatibility#:#Internet Explorer 7 kompatibilitási mód content#:#cont_ie_compatibility_info#:#Internet Explorer-re optimalizált SCORM-tananyagok megjelenítési problémáinak számát csökkenti. Ez nem túl hatékony, ha az Internet Explorer újabb verzióiban ki van kapcsolva a kompatibilitási mód. content#:#cont_ie_force_render#:#Internet Explorer újrarenderelés kikényszerítése content#:#cont_ie_force_render_info#:#A sok kerettel (frame és iframe) rendelkező tananyagok tartalma az újabb renderelés után már helyesen fog megjelenni. -content#:#cont_iim_add_overlay#:#Add Overlay###26 08 2024 new variable -content#:#cont_iim_add_trigger#:#Add Trigger###26 08 2024 new variable -content#:#cont_iim_add_trigger_text#:#Please add a trigger. Afterwards edit size and position on the right screen.###26 08 2024 new variable -content#:#cont_iim_background_image#:#Background Image###26 08 2024 new variable -content#:#cont_iim_background_image_and_caption#:#Background Image and Caption###26 08 2024 new variable -content#:#cont_iim_edit#:#Edit Interactive Image###26 08 2024 new variable -content#:#cont_iim_edit_trigger#:#Edit Trigger###26 08 2024 new variable -content#:#cont_iim_finish_editing#:#Finish Editing Interactive Image###26 08 2024 new variable -content#:#cont_iim_horizontal#:#Horizontal###26 08 2024 new variable -content#:#cont_iim_lg#:#Large###26 08 2024 new variable -content#:#cont_iim_md#:#Medium###26 08 2024 new variable -content#:#cont_iim_no_overlay#:#No Overlay###26 08 2024 new variable -content#:#cont_iim_overview#:#Overview###26 08 2024 new variable -content#:#cont_iim_select_overlay#:#Select Overlay###26 08 2024 new variable -content#:#cont_iim_select_trigger#:#To edit an existing trigger, click it on the right screen.###26 08 2024 new variable -content#:#cont_iim_size#:#Size###26 08 2024 new variable -content#:#cont_iim_sm#:#Small###26 08 2024 new variable -content#:#cont_iim_tr_add_popup#:#Add Content-Popup###26 08 2024 new variable -content#:#cont_iim_tr_properties_info#:#The trigger will be presented on the right side. You may alter position and size using the mouse.###26 08 2024 new variable -content#:#cont_iim_trigger#:#Trigger###26 08 2024 new variable -content#:#cont_iim_vertical#:#Vertical###26 08 2024 new variable +content#:#cont_iim_add_overlay#:#Átfedés hozzáadása +content#:#cont_iim_add_trigger#:#Trigger hozzáadása +content#:#cont_iim_add_trigger_text#:#Adjon hozzá egy triggert, aminek a méretét és helyét a jobb oldalon tudja majd módosítani. +content#:#cont_iim_background_image#:#Háttérkép +content#:#cont_iim_background_image_and_caption#:#Háttérkép és felirat +content#:#cont_iim_edit#:#Interaktív kép módosítása +content#:#cont_iim_edit_trigger#:#Trigger módosítása +content#:#cont_iim_finish_editing#:#Interaktív kép módosításának befejezése +content#:#cont_iim_horizontal#:#Vízszintes +content#:#cont_iim_lg#:#Nagy +content#:#cont_iim_md#:#Közepes +content#:#cont_iim_no_overlay#:#Nincs átfedés +content#:#cont_iim_overview#:#Áttekintés +content#:#cont_iim_select_overlay#:#Átfedés kiválasztása +content#:#cont_iim_select_trigger#:#A meglévő trigger módosításához kattintson rá a jobb oldalon. +content#:#cont_iim_size#:#Méret +content#:#cont_iim_sm#:#Kicsi +content#:#cont_iim_tr_add_popup#:#Felugró tartalom létrehozása +content#:#cont_iim_tr_properties_info#:#A trigger a jobb oldalon jelenik meg, helyét és méretét egérrel tudja megváltoztatni. +content#:#cont_iim_trigger#:#Trigger +content#:#cont_iim_vertical#:#Függőleges content#:#cont_imagemap#:#Képtérkép content#:#cont_import#:#Importálás content#:#cont_import_id#:#azonosító @@ -6619,7 +6652,7 @@ content#:#cont_insert_mob#:#Médiaobjektum beszúrása content#:#cont_insert_my_courses#:#Kurzusaim beszúrása content#:#cont_insert_page#:#Lap beszúrása content#:#cont_insert_page_from_clip#:#Lap beillesztése a vágólapról -content#:#cont_insert_pagelayout#:#Oldalsablon beszúrása +content#:#cont_insert_pagelayout#:#Oldal beszúrása sablonból content#:#cont_insert_par#:#Szöveg beszúrása content#:#cont_insert_profile#:#Személyes adatok közzététele content#:#cont_insert_resources#:#Forráslista beszúrása @@ -6629,7 +6662,7 @@ content#:#cont_insert_src#:#Forráskód beszúrása content#:#cont_insert_subchapter#:#Alfejezet beszúrása content#:#cont_insert_subchapter_from_clip#:#Alfejezet beillesztése a vágólapról content#:#cont_insert_table#:#Táblázat beszúrása -content#:#cont_insert_verification#:#Igazolás létrehozása +content#:#cont_insert_verification#:#Tanúsítvány létrehozása content#:#cont_inst_map_areas#:#Példány linkterületek content#:#cont_interactions#:#Interakció-eredmények tárolása content#:#cont_interactions_info#:#A tananyagban lévő interakciók szokásos eredményeit egyszerű módon tároljuk, újraolvasás, újratöltés nélkül. Ez növeli a teljesítményt, de csak akkor kapcsolja be, ha ismeri a tananyag működési mechanizmusát. @@ -6639,11 +6672,11 @@ content#:#cont_internal_links#:#Belső linkek content#:#cont_invalid_new_module#:#Inkompatibilis tananyag! Bizonyosodjon meg arról, hogy nem változott meg az imsmanifest.xml! content#:#cont_is_visible#:#látható content#:#cont_item#:#Elem -content#:#cont_keyword#:#Keyword###29 07 2022 new variable +content#:#cont_keyword#:#Kulcsszó content#:#cont_language#:#Nyelv content#:#cont_languages#:#Nyelvek content#:#cont_last_try#:#Utolsó próbálkozás -content#:#cont_last_update#:#Last Update +content#:#cont_last_update#:#Utolsó módosítás content#:#cont_last_visited_page#:#Utoljára látogatott oldal content#:#cont_latest_rev#:#Legfrissebb átdolgozás content#:#cont_layout#:#Elrendezés @@ -6656,7 +6689,7 @@ content#:#cont_layout_3window_desc#:#A tartalom a bal keretben jelenik meg. A GY content#:#cont_layout_fullscreen#:#Teljes képernyő content#:#cont_layout_fullscreen_desc#:#A tartalom a főkeretben jelenik meg. A GYIK- és a médiahivatkozások külön ablakban nyílnak meg. Nincs ILIAS-főmenü és navigációs rész. content#:#cont_layout_per_page#:#Elrendezés laponként -content#:#cont_layout_per_page_info#:#Az egyes lapokhoz engedélyezett egyedi elrendezés beállítása. Ez automatikusan kikapcsolja a 'Keretek szinkronizálása' beállítást. +content#:#cont_layout_per_page_info#:#Az egyes lapokhoz engedélyezett egyedi elrendezés beállítása. Ez automatikusan kikapcsolja a ‘Keretek szinkronizálása’ beállítást. content#:#cont_layout_presentation#:#Prezentáció content#:#cont_layout_presentation_desc#:#A tartalom a főkeretben jelenik meg. A GYIK-, a fogalomtár- és a médiahivatkozások külön ablakban nyílnak meg. Nincs ILIAS-főmenü. content#:#cont_layout_template#:#Elrendezéssablon @@ -6664,43 +6697,43 @@ content#:#cont_layout_toc2win#:#Tartalomjegyzék content#:#cont_layout_toc2win_desc#:#A tartalomjegyzék a bal, a tartalom a jobb oldali keretben jelenik meg. A GYIK-, a fogalomtár- és a médiahivatkozások külön ablakban nyílnak meg. content#:#cont_layout_toc2windyn#:#Dinamikus tartalomjegyzék content#:#cont_layout_toc2windyn_desc#:#A tartalomjegyzék a bal, a tartalom a jobb oldali keretben jelenik meg. A GYIK-, a fogalomtár- és a médiahivatkozások dinamikusan nyílnak meg a jobb alsó kertben. -content#:#cont_left#:#Bal +content#:#cont_left#:#Balra content#:#cont_left_float#:#Balra, körbefuttatás -content#:#cont_license#:#Licence -content#:#cont_license_info#:#Licencelés bekapcsolása +content#:#cont_license#:#Licensz +content#:#cont_license_info#:#Licenszelés bekapcsolása content#:#cont_light#:#Világos content#:#cont_link#:#Link content#:#cont_link_area#:#Linkterület -content#:#cont_link_ext#:#Link (külső) +content#:#cont_link_ext#:#Külső link content#:#cont_link_glo_in_lm#:#A fogalomtár összes fogalmát linkké alakítsuk a tananyagban? -content#:#cont_link_int#:#Link (belső) +content#:#cont_link_int#:#Belső link content#:#cont_link_no#:#Nincs link content#:#cont_link_select#:#belső link content#:#cont_link_to_external#:#Link külső weboldalra content#:#cont_link_to_internal#:#Link ILIAS-forrásra content#:#cont_link_to_wiki#:#Link wikilapra (zárójelek beszúrása) content#:#cont_link_type#:#Hivatkozástípus -content#:#cont_link_user#:#User Link +content#:#cont_link_user#:#Felhasználói profil content#:#cont_linked_mobs#:#Hivatkozott médiaobjektumok content#:#cont_links#:#Linkek content#:#cont_list_files#:#Fájlok felsorolása content#:#cont_list_indent#:#Behúzáscsökkentett felsorolás -content#:#cont_list_item_style#:#List Item Style###26 08 2024 new variable +content#:#cont_list_item_style#:#Felsoroláselem stílusa content#:#cont_list_outdent#:#Behúzott felsorolás -content#:#cont_list_properties#:#Listatulajdonságok -content#:#cont_lists#:#Listák +content#:#cont_list_properties#:#Felsorolástulajdonságok +content#:#cont_lists#:#Felsorolások content#:#cont_lk_chapter#:#Fejezet -content#:#cont_lk_chapter_new#:#Fejezet (új keret) +content#:#cont_lk_chapter_new#:#Fejezet új lapon content#:#cont_lk_file#:#Fájl/dokumentum -content#:#cont_lk_media_faq#:#Média (GYIK-keret) +content#:#cont_lk_media_faq#:#Média GYIK-keretben content#:#cont_lk_media_inline#:#Média (sorban) -content#:#cont_lk_media_media#:#Média (médiakeret) -content#:#cont_lk_media_new#:#Média (új keret) +content#:#cont_lk_media_media#:#Média médiakeretben +content#:#cont_lk_media_new#:#Média új lapon content#:#cont_lk_page#:#Lap -content#:#cont_lk_page_faq#:#Lap (GYIK-keret) -content#:#cont_lk_page_new#:#Lap (új keret) +content#:#cont_lk_page_faq#:#Lap GYIK-keretben +content#:#cont_lk_page_new#:#Lap új keretben content#:#cont_lk_term#:#Fogalomtár fogalma -content#:#cont_lk_term_new#:#Fogalomtár fogalma (új keret) +content#:#cont_lk_term_new#:#Fogalomtár fogalma új keretben content#:#cont_lm_comments_desc#:#A felhasználóknak a tananyag minden lapján engedélyezett megjegyzések megosztása. content#:#cont_lm_default_layout#:#Alapértelmezett elrendezés a tananyagokhoz content#:#cont_lm_mail_permanent_link#:#Kattintson a következő linkre a tananyag eléréséhez: @@ -6710,50 +6743,50 @@ content#:#cont_lm_starting_point#:#ILIAS tananyag kezdőpontja content#:#cont_lm_starting_point_info#:#A tananyag címére kattintáskor megnyíló oldal. content#:#cont_localfile#:#Helyi fájl content#:#cont_localization#:#Lokalizáció -content#:#cont_localization_info#:#A nyelv előre definiált szövegeket használ, például 'Előző', 'Következő'. +content#:#cont_localization_info#:#A nyelv előre definiált szövegeket használ, például ‘Előző’, ‘Következő’. content#:#cont_location#:#Elhelyezkedés -content#:#cont_lpe_dpro_agreement_link#:#Declaration of Data Protection Link###26 08 2024 new variable +content#:#cont_lpe_dpro_agreement_link#:#Az Adatvédelmi nyilatkozatra mutató link content#:#cont_lpe_language_selection#:#Nyelvválasztás content#:#cont_lpe_login_form#:#Bejelentkezési űrlap content#:#cont_lpe_openid_connect_login#:#OpenID-felhasználónév content#:#cont_lpe_openid_login_form#:#OpenID bejelentkezési űrlap content#:#cont_lpe_registration_link#:#Új regisztráció linkje -content#:#cont_lpe_saml_login#:#SAML Login###29 07 2022 new variable +content#:#cont_lpe_saml_login#:#SAML-bejelentkezés content#:#cont_lpe_shib_login_form#:#Shibboleth bejelentkezési űrlap content#:#cont_lpe_user_agreement_link#:#Szolgáltatási feltételek linkje content#:#cont_lrs_settings#:#Beállítások content#:#cont_lvalue#:#Adatelem content#:#cont_maintenance#:#Karbantartás content#:#cont_manifest#:#Manifest -content#:#cont_manual_item_group#:#Manually Create Item Group###26 08 2024 new variable +content#:#cont_manual_item_group#:#Manuálisan létrehozott elemcsoport content#:#cont_map_file_not_generated#:#Sajnos nem lehet térképfájlt generálni a szerkesztéshez. -content#:#cont_marker#:#Jelző -content#:#cont_master_language_only#:#Fordításhoz mesternyelv -content#:#cont_master_language_only_no_media#:#Mesternyelv média nélkül +content#:#cont_marker#:#Jelölő +content#:#cont_master_language_only#:#Fordításhoz főnyelv +content#:#cont_master_language_only_no_media#:#Főnyelv média nélkül content#:#cont_mastery_score#:#adlcp:masteryscore content#:#cont_mastery_score_12#:#mastery_score felülírása content#:#cont_mastery_score_12_info#:#Ha egy SCO nem automatikusan határoz meg egy állapotot, egy SCO teljesítettként kerül figyelembe vételre, ha a pontszám egy bizonyos szintet elér - ez a mastery_score. Ezt az értéket lehet itt felülírni, például csökkenteni így az elvárt szintet. Amennyiben ez a mező üres, a SCORM manifest-ben lévő információ a valid. Az alábbi következő értékek szerepelnek a manifest-fájlban: content#:#cont_mastery_score_2004#:#scaled_passing_score felülírása content#:#cont_mastery_score_2004_info#:#Ennek a tananyagnak a központi tanulási céljai teljesítettként kerül figyelembe vételre, ha a pontszám egy bizonyos szintet elér - ez a scaled_passing_score. Ezt az értéket - ami százalékérték - lehet itt felülírni, például csökkenteni így az elvárt szintet. Amennyiben ez a mező üres, a SCORM manifest-ben lévő információ a valid. Az alábbi következő értékek szerepelnek a manifest-fájlban: content#:#cont_max_time_allowed#:#adlcp:maxtimeallowed -content#:#cont_media#:#Images/Media###29 07 2022 new variable +content#:#cont_media#:#Képek/Média content#:#cont_media_placeh#:#Kattintson és szerkesszen média beszúrásához content#:#cont_media_placehl#:#Kép-/médiahelyőrző content#:#cont_media_source#:#Médiaforrás -content#:#cont_merge_cells#:#Merge Cells###26 08 2024 new variable -content#:#cont_missing_preconditions#:#'%s' fejezet eléréséhez az alábbi előfeltételeket teljesítenie kell. +content#:#cont_merge_cells#:#Cellák egyesítése +content#:#cont_missing_preconditions#:#‘%s’ fejezet eléréséhez az alábbi előfeltételeket teljesítenie kell. content#:#cont_missing_snippet#:#Hiányzó tartalom-építőelem. Ezt az építőelemet törölték. content#:#cont_mob_def_prop#:#Alapértelmezett tulajdonságok content#:#cont_mob_from_media_pool#:#Választás a médiagyűjteményből content#:#cont_mob_inst_prop#:#Példánytulajdonságok content#:#cont_mob_usages#:#Felhasználás -content#:#cont_more_character_styles#:#...további karakterstílusok +content#:#cont_more_character_styles#:#…további karakterstílusok content#:#cont_more_functions#:#Továbbiak content#:#cont_moved_srt_files#:#Feliratfájlokat sikeresen hozzárendelte a médiaobjektumokhoz. -content#:#cont_multi_srt_files#:#SRT-fájlok +content#:#cont_multi_srt_files#:#Feliratfájlok content#:#cont_mycourses_sortorder#:#Alapértelmezett rendezés content#:#cont_mycourses_sortorder_alphabetical#:#Alfabetikus -content#:#cont_mycourses_sortorder_info#:#Ez az alapértelmezett beállítás. Az összes felhasználó egyéni rendezést választhat, ami bármelyik portfólió összes 'Kurzusaim' elemeire vonatkozik. +content#:#cont_mycourses_sortorder_info#:#Ez az alapértelmezett beállítás. Az összes felhasználó egyéni rendezést választhat, ami bármelyik portfólió összes ‘Kurzusaim’ elemeire vonatkozik. content#:#cont_mycourses_sortorder_location#:#Hely szerint content#:#cont_name#:#Név content#:#cont_never#:#Soha @@ -6773,7 +6806,7 @@ content#:#cont_new_trigger_area#:#Új triggerterület content#:#cont_next_rev#:#Következő átdolgozás content#:#cont_nlist#:#Számozott felsorolás content#:#cont_no_access#:#Nincs hozzáférés -content#:#cont_no_block#:#No Section +content#:#cont_no_block#:#Nincs fejezet content#:#cont_no_caption#:#Nincs felirat content#:#cont_no_glossary#:#Nincs hozzárendelt fogalomtár content#:#cont_no_manifest#:#Nem található imsmanifest.xml fájl a főmappában. @@ -6782,20 +6815,20 @@ content#:#cont_no_page_access_unansw_q#:#Az oldal megtekintéséhez az összes k content#:#cont_no_page_in_chapter#:#Elnézést, jelenleg nincs aktív tartalom ebben a fejezetben. content#:#cont_no_parameters#:#Nincsenek paraméterek content#:#cont_no_read#:#Nincs olvasási jogosultsága -content#:#cont_no_subdir_in_zip#:#ZIP parancs végrehajtása sikertelen, vagy érvénytelen az importfájl.
    Nem tartalmaz almappát '%s'. +content#:#cont_no_subdir_in_zip#:#ZIP parancs végrehajtása sikertelen, vagy érvénytelen az importfájl.
    Nem tartalmaz almappát ‘%s’. content#:#cont_no_text#:#Nincs szöveg content#:#cont_nomenu#:#Felső navigációs sáv elrejtése content#:#cont_nomenu_info#:#A felső Navigációs sáv elrejthető, ha a SCORM-tananyag elegendő funkcionalitást tartalmaz a felfüggesztéséhez, a befejezéséhez és a tartalomban navigálásához. content#:#cont_none#:#Semmi content#:#cont_not_saved_edit_lock_expired#:#Sajnáljuk, módosításait nem sikerült menteni, mert időközben egy másik felhasználó szerkesztésre zárolta ezt az oldalt. Az üzenet bezárása után a tartalmat vágólapra másolhatja. -content#:#cont_notification_activate_lm#:#Értesítések bekapcsolva a tananyagra -content#:#cont_notification_activate_page#:#Értesítések bekapcsolva az oldalra -content#:#cont_notification_activated#:#Értesítések aktiválva (teljes tananyagra) +content#:#cont_notification_activate_lm#:#Értesítés bekapcsolása a tananyagra +content#:#cont_notification_activate_page#:#Értesítés bekapcsolása az oldalra +content#:#cont_notification_activated#:#Értesítés aktiválva (teljes tananyagra) content#:#cont_notification_comment_lm#:#ezúton tájékoztatjuk, hogy a következő tananyagoldalhoz írtak hozzászólást content#:#cont_notification_comment_subject_lm#:#Egy új hozzászólás jött létre %s: %s -content#:#cont_notification_deactivate_lm#:#Értesítések kikapcsolva a tananyagra -content#:#cont_notification_deactivate_page#:#Értesítések kikapcsolva az oldalra -content#:#cont_notification_deactivated#:#Értesítések kikapcsolva +content#:#cont_notification_deactivate_lm#:#Értesítés kikapcsolása a tananyagra +content#:#cont_notification_deactivate_page#:#Értesítés kikapcsolása az oldalra +content#:#cont_notification_deactivated#:#Értesítés kikapcsolva content#:#cont_notification_update_lm#:#ezúton tájékoztatjuk, hogy a következő tananyag frissült content#:#cont_notify_on_blocked_users#:#Blokkolt felhasználókról értesítés content#:#cont_notify_on_blocked_users_info#:#Értesítést kap, amikor egy felhasználót blokkolunk, mert elhasználta a tananyagban az összes válaszadási lehetőségét. @@ -6815,25 +6848,25 @@ content#:#cont_obj_removed#:#Az objektum eltávolítva. content#:#cont_objectives#:#Tanulási célokra vonatkozó adatok tárolása content#:#cont_objectives_info#:#Ez növeli a teljesítményt, de csak akkor kapcsolja be, ha a tananyag hibátlanul fut. content#:#cont_online#:#Online -content#:#cont_online_help_ids#:#Képernyő-ID-k +content#:#cont_online_help_ids#:#Screen-ID-k content#:#cont_online_info#:#Állítsa online-ra a SCORM-tananyagot, hogy látható és elérhető legyen a felhasználók számára. Offline állapotban csak a szerkesztési jogosultsággal rendelkezők érhetik el. content#:#cont_open#:#Tananyag megjelenítése -content#:#cont_open_clipboard#:#Open Clipboard###29 07 2022 new variable -content#:#cont_open_iframe#:#Ugyanabban az ablakban nyíljon meg, az ILIAS-főmenü alatt -content#:#cont_open_iframe_info#:#The learning module starts in the same window (iFrame) next to the ILIAS main menu.###26 08 2024 new variable -content#:#cont_open_normal#:#Új fülön vagy pedig új ablakban nyíljon meg, ILIAS főmenü nélkül -content#:#cont_open_normal_info#:#The learning module starts in a new tab or alternatively in a new window without the ILIAS main menu.###26 08 2024 new variable +content#:#cont_open_clipboard#:#Vágólap megnyitása +content#:#cont_open_iframe#:#iFrame-ben +content#:#cont_open_iframe_info#:#A tananyag ugyanabban az ablakban nyílik meg (iFrame) az ILIAS főmenü mellett. +content#:#cont_open_normal#:#Új lapon vagy pedig új ablakban nyíljon meg, ILIAS főmenü nélkül +content#:#cont_open_normal_info#:#A tananyag új lapon vagy pedig új ablakban nyílik meg az ILIAS főmenü nélkül. content#:#cont_open_window#:#Új ablakban nyíljon meg, ILIAS-főmenü nélkül -content#:#cont_open_window_info#:#The learning module must start in a new window without the ILIAS main menu.###26 08 2024 new variable +content#:#cont_open_window_info#:#A tananyag mindenképpen új ablakban nyílik meg az ILIAS főmenü nélkül. content#:#cont_operation_not_allowed#:#Nem engedélyezett ez a művelet. content#:#cont_organization#:#Szervezet content#:#cont_organizations#:#Szervezetek content#:#cont_orig_size#:#Eredeti méret -content#:#cont_other_resources#:#Content (Other Remaining Resources)###26 08 2024 new variable +content#:#cont_other_resources#:#Tartalom (egyéb források) content#:#cont_out_of_focus_message#:#Ez az oldal többé nincs összefüggésben a jelenlegi tanulási céljával. content#:#cont_out_of_focus_message_last_page#:#Jelenleg ez a tanulási céljaihoz kapcsolódó tartalom utolsó oldala. content#:#cont_ov_all_correct#:#Helyesen válaszolt minden kérdésre. -content#:#cont_ov_preview#:#A kérdésáttekintés nem működik lapszerkesztő környezetben. Használja inkább az SCO- vagy a SCORM-szint előnézet. +content#:#cont_ov_preview#:#A kérdésáttekintés nem működik az ILIAS-lapszerkesztőben. Használja inkább az SCO- vagy a SCORM-szint előnézet. content#:#cont_ov_some_correct#:#Helyesen válaszolt meg [x] kérdést a(z) [y] kérdésből. content#:#cont_ov_wrong_answered#:#Az alábbi kérdéseket még nem vagy hibásan válaszolta meg. content#:#cont_overlay_image#:#Fedőkép @@ -6848,12 +6881,12 @@ content#:#cont_page_deactivated#:#Lap deaktiválva. content#:#cont_page_deactivated_elements#:#A lap deaktivált elemeket tartalmaz. content#:#cont_page_header#:#Lap fejléce content#:#cont_page_layout#:#Lapelrendezés -content#:#cont_page_lock_released#:#Szerkesztése véget ért. Az oldal zárolását feloldottuk. -content#:#cont_page_notification_activated#:#Értesítések bekapcsolva (egy oldalra) +content#:#cont_page_lock_released#:#Szerkesztése véget ért. Az oldal zárolását sikeresen feloldotta. +content#:#cont_page_notification_activated#:#Értesítés bekapcsolva (egy oldalra) content#:#cont_page_template#:#Oldalsablon content#:#cont_page_toc#:#Lapáttekintés -content#:#cont_page_translation_does_not_exist#:#A fordítási oldal még nem létezik és a mesternyelvi oldal tartalmának másolásával fog létrejönni. -content#:#cont_page_usage#:#Page Usage###29 10 2025 new variable +content#:#cont_page_translation_does_not_exist#:#A fordítási oldal még nem létezik és a főnyelvi oldal tartalmának másolásával fog létrejönni. +content#:#cont_page_usage#:#Lapfelhasználás content#:#cont_pages#:#Lapok content#:#cont_pages_and_subchapters#:#Alfejezetek és lapok content#:#cont_par_format#:#Bekezdés @@ -6861,7 +6894,7 @@ content#:#cont_paragraph_styles#:#Bekezdésstílus content#:#cont_parameter#:#Paraméter content#:#cont_parameters#:#paraméterek content#:#cont_paste_from_clipboard#:#Beillesztés vágólapról -content#:#cont_paste_from_spreadsheet#:#Paste From Spreadsheet###26 08 2024 new variable +content#:#cont_paste_from_spreadsheet#:#Beillesztés a táblázatból content#:#cont_paste_table#:#Táblázat beszúrása content#:#cont_pc_amdpl#:#Oldallista content#:#cont_pc_blog#:#Blog @@ -6874,28 +6907,28 @@ content#:#cont_pc_grid#:#Oszlopos elrendezés content#:#cont_pc_hacc#:#Harmonika (vízszintes) content#:#cont_pc_iim#:#Interaktív kép content#:#cont_pc_incl#:#Tartalom-építőelem -content#:#cont_pc_lay#:#Layout Template###26 08 2024 new variable +content#:#cont_pc_lay#:#Kinézetsablon content#:#cont_pc_list#:#Fejlettebb felsorolás content#:#cont_pc_map#:#Térkép -content#:#cont_pc_media#:#Image/Media###29 07 2022 new variable +content#:#cont_pc_media#:#Kép/Média content#:#cont_pc_mob#:#Média content#:#cont_pc_modified#:#Módosított tartalom content#:#cont_pc_new#:#Új tartalom content#:#cont_pc_par#:#Szöveg -content#:#cont_pc_plach#:#Placeholder###26 08 2024 new variable +content#:#cont_pc_plach#:#Helyőrző content#:#cont_pc_prof#:#Személyes adatok content#:#cont_pc_qover#:#Kérdésáttekintés content#:#cont_pc_qst#:#Kérdés -content#:#cont_pc_repobj#:#Item Group###26 08 2024 new variable +content#:#cont_pc_repobj#:#Elemcsoport content#:#cont_pc_res#:#Forrás content#:#cont_pc_sec#:#Szekció content#:#cont_pc_skills#:#Kompetencia -content#:#cont_pc_src#:#Source Code###26 08 2024 new variable +content#:#cont_pc_src#:#Forráskód content#:#cont_pc_tab#:#Fejlettebb táblázat -content#:#cont_pc_tabs#:#Accordion/Carousel###26 08 2024 new variable +content#:#cont_pc_tabs#:#Harmonika/körhinta content#:#cont_pc_vacc#:#Harmonika (függőleges) -content#:#cont_pc_vrfc#:#Igazolás -content#:#cont_permission_handling#:#Permission Handling###26 08 2024 new variable +content#:#cont_pc_vrfc#:#Tanúsítvány +content#:#cont_permission_handling#:#Jogosultság kezelése content#:#cont_permission_object#:#Jogosultságobjektum content#:#cont_permission_object_desc#:#A fejezet csak megfelelő jogosultsággal rendelkező felhasználók számára érhető el. content#:#cont_personal_clipboard#:#Személyes vágólap @@ -6908,7 +6941,7 @@ content#:#cont_position#:#Pozíció content#:#cont_prereq_type#:#adlcp:prerequisites.type content#:#cont_prerequisites#:#adlcp:prerequisites content#:#cont_presentation#:#Megjelenítés -content#:#cont_presentation_view#:#Megjelenítési nézet +content#:#cont_presentation_view#:#Előnézet content#:#cont_preview#:#Előnézet content#:#cont_previous_rev#:#Korábbi átdolgozás content#:#cont_print_no_page_selected#:#Legalább egy lapot válasszon! @@ -6923,24 +6956,24 @@ content#:#cont_profile_mode_manual_info#:#Használja az alábbi adatokat: content#:#cont_profile_mode_template_inherit_info#:#Profilbeállítások használata content#:#cont_progress_icons#:#Haladási ikonok content#:#cont_progress_icons_info#:#A tanulási haladás ikonjai látszódjanak a fejezetek oldalikonjai helyett. -content#:#cont_prtf_page#:#Portfolióoldal -content#:#cont_prtt_page#:#Portfolió-sablonoldal +content#:#cont_prtf_page#:#Portfólióoldal +content#:#cont_prtt_page#:#Portfólió-sablonoldal content#:#cont_public_access#:#Nyilvános hozzáférés content#:#cont_purpose#:#Cél content#:#cont_qover_list_wrong_q#:#Hibásan megválaszolt kérdések listája content#:#cont_qover_list_wrong_q_info#:#A hibásan vagy meg nem válaszolt kérdések megjelennek. content#:#cont_qover_short_message#:#Állapotüzenet -content#:#cont_qover_short_message_info#:#'Ön helyesen válaszolta meg ennek a résznek X kérdését az Y-ból.' üzenet jelenik majd meg. +content#:#cont_qover_short_message_info#:#‘Ön helyesen válaszolta meg ennek a résznek X kérdését az Y-ból.’ üzenet jelenik majd meg. content#:#cont_qtries#:#Próbálkozások száma a kérdésekhez content#:#cont_qtries_info#:#Újonnan létrehozott kérdések esetén a próbálkozások számának alapértelmezett értéke. -content#:#cont_question#:#Question###29 10 2025 new variable -content#:#cont_question_page_usage#:#Questions on Pages###29 10 2025 new variable +content#:#cont_question#:#Kérdés +content#:#cont_question_page_usage#:#Kérdések az lapokon content#:#cont_question_placeh#:#Kattintson és szerkesszen kérdés beszúrásához content#:#cont_question_placehl#:#Kérdéshelyőrző content#:#cont_question_stats#:#Statisztikák content#:#cont_question_type#:#Kérdéstípus -content#:#cont_question_usage#:#Usages###29 10 2025 new variable -content#:#cont_quit_text_editing#:#Finish Text Editing###26 08 2024 new variable +content#:#cont_question_usage#:#Felhasználások +content#:#cont_quit_text_editing#:#Szövegszerkesztés befejezése content#:#cont_rand_start#:#Véletlenszerű kezdet content#:#cont_really_delete_overlays#:#Biztos, hogy törli az alábbi fedéseket? content#:#cont_really_delete_popups#:#Biztos, hogy törli az alábbi felugró ablakokat? @@ -6968,8 +7001,8 @@ content#:#cont_right#:#Jobbra content#:#cont_right_float#:#Jobbra, körbefuttatás content#:#cont_rollback#:#Visszagörgetés content#:#cont_rollback_confirmation#:#Biztos, hogy visszaállítja ennek a lapnak a régi változatát? -content#:#cont_roman#:#Római I, II, ... -content#:#cont_roman_s#:#Római i, ii, ... +content#:#cont_roman#:#Római I, II, … +content#:#cont_roman_s#:#Római i, ii, … content#:#cont_rowspan#:#Összevont sorok content#:#cont_rte_settings#:#RTE beállítások content#:#cont_rvalue#:#Érték @@ -6983,41 +7016,41 @@ content#:#cont_saved_export_ids#:#A HTML export-ID-k mentette. content#:#cont_saved_interactive_image#:#Létrehozott interaktív kép content#:#cont_saved_map_area#:#A térképterületet sikeresen mentette. content#:#cont_saved_map_data#:#A térképadatokat sikeresen mentette. -content#:#cont_saving#:#Mentés... +content#:#cont_saving#:#Mentés… content#:#cont_sc_auto_continue#:#Felhasználók átirányítása content#:#cont_sc_auto_continue_info#:#A felhasználókat az utolsó aktivitásuk befejeztével automatikusan át fogjuk irányítani a következő SCO-ra. Ezt a funkciót nem az összes SCROM 1.2-es tananyag támogatja. -content#:#cont_sc_auto_review_2004#:#Nyomkövetési állapot zárolása, amit az létrejött -content#:#cont_sc_auto_review_completed#:#nyomkövetési adatok megtartása, ha korábbi állapot befejezte -content#:#cont_sc_auto_review_completed_and_passed#:#nyomkövetési adatok megtartása, ha korábbi állapot befejezte és sikeresen teljesítette -content#:#cont_sc_auto_review_completed_not_failed_or_passed#:#nyomkövetési adatok megtartása, ha korábbi állapot befejezte vagy sikeresen teljesítette, de nem nem teljesítette -content#:#cont_sc_auto_review_completed_or_passed#:#nyomkövetési adatok megtartása, ha korábbi állapot befejezte vagy sikeresen teljesítette -content#:#cont_sc_auto_review_info_2004#:#Amint egy felhasználó nyomkövetési állapota megállításra került egy fejezethez/SCO-hoz, zároljuk azt. Későbbi látogatások során keletkezett nyomkövetési adatokat már nem tárolunk ezekhez a fejezetekhez/SCO-okhoz. Válassza a 'Mindig' beállítást, ha a tananyag használja a SCORM 2004 szerinti 'Szekvenálás & Navigáció'-t. -content#:#cont_sc_auto_review_no#:#mindig (ajánlott) +content#:#cont_sc_auto_review_2004#:#Adatrögzítés befejezése +content#:#cont_sc_auto_review_completed#:#ha a korábbi állapot befejezte +content#:#cont_sc_auto_review_completed_and_passed#:#ha a korábbi állapot befejezte és sikeresen teljesítette +content#:#cont_sc_auto_review_completed_not_failed_or_passed#:#ha a korábbi állapot befejezte vagy sikeresen teljesítette, de nem nem teljesítette +content#:#cont_sc_auto_review_completed_or_passed#:#ha a korábbi állapot befejezte vagy sikeresen teljesítette +content#:#cont_sc_auto_review_info_2004#:#A felhasználó nyomkövetési állapotát zároljuk egy fejezetnél/SCO-nál, amikor a fentebbiek közül a kiválasztottra vált. Későbbi látogatások során az állapot már nem módosul.
    Válassza a ‘soha (megfelel a SCORM specifikációnak)’ beállítást, ha a tananyag használja a SCORM 2004 szerinti ‘Szekvenálás & Navigáció’-t. +content#:#cont_sc_auto_review_no#:#soha (megfelel a SCORM specifikációnak) content#:#cont_sc_auto_review_passed#:#nyomkövetési adatok megtartása, ha korábbi állapot sikeresen teljesítette content#:#cont_sc_auto_review_passed_or_failed#:#nyomkövetési adatok megtartása, ha korábbi állapot sikeresen teljesítette vagy nem teljesítette content#:#cont_sc_id_setting#:#student_id a SCORM 1.2 alapján content#:#cont_sc_id_setting_2004#:#learner_id a SCORM 2004 alapján -content#:#cont_sc_id_setting_info#:#Amennyiben student_id (SCORM 1.2) vagy a learner_id (SCORM 2004) számértéke problémát okoz a tananyagban, használja az 'ILIAS felhasználónév' lehetőséget. A további RefId vagy ObjId külső szerverhez kapcsolódó tananyagnál lehet hasznos. -content#:#cont_sc_id_setting_user_id#:#ILIAS Felhasználó Id (standard) -content#:#cont_sc_id_setting_user_id_plus_obj_id#:#ILIAS Felhasználó_id plusz a tananyag obj_id-je -content#:#cont_sc_id_setting_user_id_plus_ref_id#:#ILIAS Felhasználó_id plusz a tananyag ref_id-je +content#:#cont_sc_id_setting_info#:#Amennyiben student_id (SCORM 1.2) vagy a learner_id (SCORM 2004) számértéke problémát okoz a tananyagban, használja az ‘ILIAS felhasználónév’ lehetőséget. A további RefId vagy ObjId külső szerverhez kapcsolódó tananyagnál lehet hasznos. +content#:#cont_sc_id_setting_user_id#:#ILIAS user_id (standard) +content#:#cont_sc_id_setting_user_id_plus_obj_id#:#ILIAS user_id plusz a tananyag obj_id-je +content#:#cont_sc_id_setting_user_id_plus_ref_id#:#ILIAS user_id plusz a tananyag ref_id-je content#:#cont_sc_id_setting_user_login#:#ILIAS Bejelentkezési név content#:#cont_sc_id_setting_user_login_plus_obj_id#:#LIAS Bejelentkezési név plusz a tananyag obj_id-je content#:#cont_sc_id_setting_user_login_plus_ref_id#:#ILIAS Bejelentkezési név plusz a tananyag ref_id-je -content#:#cont_sc_less_mode_browse#:#Böngészés -content#:#cont_sc_less_mode_browse_info#:#The SCORM mode is set to "browse".###26 08 2024 new variable -content#:#cont_sc_less_mode_normal#:#Normál -content#:#cont_sc_less_mode_normal_info#:#The SCORM mode is set to "normal".###26 08 2024 new variable +content#:#cont_sc_less_mode_browse#:#Előnézeti mód +content#:#cont_sc_less_mode_browse_info#:#A SCORM mód ‘böngészés’ értéket vesz fel. +content#:#cont_sc_less_mode_normal#:#Tanulási mód +content#:#cont_sc_less_mode_normal_info#:#A SCORM mód ‘normál’ értéket vesz fel. content#:#cont_sc_max_attempt_exceed#:#A próbálkozások száma elérte a tananyaghoz rendelt maximálisat. content#:#cont_sc_name_setting#:#student_name a SCORM 1.2 alapján content#:#cont_sc_name_setting_2004#:#learner_name a SCORM 2004 alapján -content#:#cont_sc_name_setting_first_lastname#:#Családnév és keresztnév +content#:#cont_sc_name_setting_first_lastname#:#Családnév és utónév content#:#cont_sc_name_setting_first_name#:#Családnév -content#:#cont_sc_name_setting_fullname#:#Titulus, keresztnév és családnév +content#:#cont_sc_name_setting_fullname#:#Titulus, utónév és családnév content#:#cont_sc_name_setting_info#:#A tananyagban a tanuló nevét sokféleképpen megjeleníthetjük. Amikor a tananyag külső szerveren van, célszerű a hallgató nevét nem nyilvánossá tenni. -content#:#cont_sc_name_setting_last_firstname#:#Keresztnév, családnév +content#:#cont_sc_name_setting_last_firstname#:#Utónév, családnév content#:#cont_sc_name_setting_no_name#:#nincs név -content#:#cont_sc_name_setting_salutation_lastname#:#Megszólítás és keresztnév +content#:#cont_sc_name_setting_salutation_lastname#:#Megszólítás és utónév content#:#cont_sc_new_version#:#Új verzió feltöltése content#:#cont_sc_preview#:#Előnézet content#:#cont_sc_stat_browsed#:#Megtekintett @@ -7027,10 +7060,10 @@ content#:#cont_sc_stat_incomplete#:#Befejezetlen content#:#cont_sc_stat_not_attempted#:#Nem próbált content#:#cont_sc_stat_passed#:#Sikeresen teljesítette content#:#cont_sc_stat_running#:#Futó (aktív) -content#:#cont_sc_store_if_previous_score_was_lower#:#nyomkövetési adatok megtartása, ha korábbi próbálkozásokból elért pontszám ugyanakkora vagy nagyobb +content#:#cont_sc_store_if_previous_score_was_lower#:#ha a korábbi próbálkozásból elért pontszám ugyanakkora vagy nagyobb content#:#cont_sc_title#:#cím content#:#cont_sc_usession#:#Automatikus kijelentkeztetés megakadályozása -content#:#cont_sc_usession_info#:#Időközönként kérés küldése az ILIAS-nak, hogy a munkamenet életben maradjon. Máskülönben az ILIAS tétlennek ítéli a tananyagon végzett munkát, így lejár a munkamenet és a nyomkövetési adatok elvesznek. +content#:#cont_sc_usession_info#:#Tanulási modulok szerkesztése közben az ILIAS-ból való kijelentkezés zavaró lehet, és a tanulási adatok elvesztéséhez vezethet. A SCORM RTE rendszeresen küld kéréseket az ILIAS-nak az automatikus kijelentkezések megakadályozása érdekében. A SCORM 2004 tanulási adatainak elvesztésének elkerülése érdekében kérjük, aktiválja a ‘SCORM 2004: Adattárolás munkamenet nélkül’ opciót is. A SCORM 1.2 esetében ez az opció állandóan engedélyezve van. Ezt az opciót a tanulási modulok rendszerszintű adminisztrációjában találja. content#:#cont_sc_version#:#Tananyag verziója content#:#cont_sc_version_info#:#A tananyag verziókezelője határozza meg automatikusan a verziószámot. content#:#cont_scheduled_activation#:#Ütemezett aktiválás @@ -7039,22 +7072,22 @@ content#:#cont_score#:#Pont content#:#cont_scorm_ed_properties#:#Tananyag tulajdonságai content#:#cont_scorm_options#:#SCORM opciók content#:#cont_scorm_type#:#adlcp:scormtype -content#:#cont_screen_ids#:#Képernyő-ID-k -content#:#cont_sec_protected#:#Protected###29 07 2022 new variable -content#:#cont_sec_protected_text#:#The following section is protected and can not be edited.###29 07 2022 new variable +content#:#cont_screen_ids#:#Screen-ID-k +content#:#cont_sec_protected#:#Védett +content#:#cont_sec_protected_text#:#Az alábbi fejezett védett, nem szerkeszthető. content#:#cont_second#:#Másodszorra -content#:#cont_sel_el_use_paste#:#A kiválasztott elemek a vágólapra kerültek. Kattintson a kívánt helyőrzőre, majd válassza a 'Beillesztés'-t. +content#:#cont_sel_el_use_paste#:#A kiválasztott elemek a vágólapra kerültek. Kattintson a kívánt helyőrzőre, majd válassza a ‘Beillesztés’-t. content#:#cont_select#:#Kiválasztás content#:#cont_select_file#:#Fájl választása content#:#cont_select_from_upload_dir#:#-- Válasszon a feltöltési mappából -- content#:#cont_select_item#:#Legalább egy elemet válasszon ki! content#:#cont_select_max_one_item#:#Csak egy elemet válasszon! content#:#cont_select_media_pool#:#Médiagyűjtemény kiválasztása -content#:#cont_select_none#:#Clear Selection +content#:#cont_select_none#:#Kijelölés törlése content#:#cont_select_other_qpool#:#Másik gyűjtemény választása content#:#cont_select_par_or_section#:#Legalább egy bekezdést vagy fejezetet válasszon! -content#:#cont_selected_items_have_been_copied#:#A kijelölt elemeket a vágólapra másolta. Kattintson a cél helyőrzőjére, hogy beillessze őket a tananyagba. -content#:#cont_selected_items_have_been_cut#:#A kijelölt elemeket a vágólapra kivágta. Kattintson a cél helyőrzőjére, hogy beillessze őket a tananyagba. +content#:#cont_selected_items_have_been_copied#:#A kijelölt elemeket a vágólapra másolta. Kattintson a cél helyőrzőjére, hogy elé vagy mögé beillessze őket a tananyagba. +content#:#cont_selected_items_have_been_cut#:#A kijelölt elemeket a vágólapra kivágta. Kattintson a cél helyőrzőjére, hogy elé vagy mögé beillessze őket a tananyagba. content#:#cont_selected_pg_chap#:#Kiválasztott lapok/fejezetek content#:#cont_selected_terms#:#Kiválasztott fogalmak content#:#cont_selected_topic#:#Kiválasztott téma @@ -7065,14 +7098,14 @@ content#:#cont_sequencing_info#:#A tananyagban definiált szekvencia és navigá content#:#cont_set_alignment#:#Elrendezés beállítása content#:#cont_set_layout#:#Elrendezés beállítása content#:#cont_set_link#:#Link módosítása -content#:#cont_set_manuall#:#Set Manually###26 08 2024 new variable -content#:#cont_set_properties#:#Set Properties###26 08 2024 new variable +content#:#cont_set_manuall#:#Kezi beállítás +content#:#cont_set_properties#:#Tulajdonságok beállítása content#:#cont_set_start_file#:#Indítófájl beállítása content#:#cont_set_styles#:#Stílus beállítása content#:#cont_set_tab_style_info#:#Táblázatcellákban levő jelölőnégyzetek aktiválása stílusbeállításhoz. content#:#cont_settings#:#Tananyag beállításai content#:#cont_shape#:#Alakzat -content#:#cont_shift_click_to_select#:#Shift-click on an element to select it and switch to selection mode.###29 07 2022 new variable +content#:#cont_shift_click_to_select#:#SHIFT-kattints egy helyőrzőre annak kijelöléséhez és a kijelölési mód megváltoztatásához. content#:#cont_short_title#:#Rövid cím content#:#cont_short_title_info#:#A rövid címek a bal oldalon lévő faszerkezetben és az előző/következő navigációnál jelennek meg. content#:#cont_short_titles#:#Rövid címek @@ -7080,7 +7113,7 @@ content#:#cont_show_activation_info#:#Aktiválási információ megjelenítése content#:#cont_show_activation_info_info#:#Az aktív időszakon előtt nem a lap tartalmát jelenítjük meg, hanem azt információt, hogy a lap mikortól lesz aktív. content#:#cont_show_adv#:#Mélyebb ismeretek megjelenítése content#:#cont_show_content_after_focus#:#Tovább a tananyaghoz -content#:#cont_show_fullscreen#:#Show Fullscreen +content#:#cont_show_fullscreen#:#Teljes képernyő content#:#cont_show_info#:#Információ megjelenítése content#:#cont_show_line_numbers#:#Sorok számozása content#:#cont_show_print_view#:#Nyomtatási nézet @@ -7090,7 +7123,7 @@ content#:#cont_snippet_from_another_installation#:#Építőelem másik telepít content#:#cont_snippets_used#:#Felhasznált tartalom-építőelemek content#:#cont_span#:#Span content#:#cont_special_page#:#Speciális tartalomlap -content#:#cont_split_cell#:#Split Cell###26 08 2024 new variable +content#:#cont_split_cell#:#Cellák felosztása content#:#cont_spreadsheet_table#:#Munkafüzet-táblázat content#:#cont_sqst#:#Kérdőívkérdés (segédanyag) content#:#cont_src#:#Forráskód @@ -7109,41 +7142,41 @@ content#:#cont_structure#:#struktúra content#:#cont_style#:#Stílus content#:#cont_subchapters#:#Alfejezetek content#:#cont_submit_answers#:#Mehet -content#:#cont_subtitle_file#:#SRT ZIP-fájl +content#:#cont_subtitle_file#:#Felirat ZIP-fájl content#:#cont_subtitle_files#:#Médiafeliratok -content#:#cont_sur_block_format#:#Surrounding Section###29 07 2022 new variable +content#:#cont_sur_block_format#:#Körülölelő fejezet content#:#cont_switch_to_media_pool#:#Váltás mások médiagyűjteményre content#:#cont_syntax_help#:#Szintaktikai segítség -content#:#cont_tab_add_above#:#Add Panel Above###26 08 2024 new variable -content#:#cont_tab_add_below#:#Add Panel Below###26 08 2024 new variable +content#:#cont_tab_add_above#:#Panel hozzáadás fölé +content#:#cont_tab_add_below#:#Panel hozzáadás alá content#:#cont_tab_cont_height#:#Tartalommagasság content#:#cont_tab_cont_width#:#Tartalomszélesség -content#:#cont_tab_delete#:#Delete Panel###26 08 2024 new variable -content#:#cont_tab_move_bottom#:#Move To Bottom###26 08 2024 new variable -content#:#cont_tab_move_down#:#Move Downwards###26 08 2024 new variable -content#:#cont_tab_move_top#:#Move To Top###26 08 2024 new variable -content#:#cont_tab_move_up#:#Move Upwards###26 08 2024 new variable +content#:#cont_tab_delete#:#Panel törlése +content#:#cont_tab_move_bottom#:#Mozgatás alulra +content#:#cont_tab_move_down#:#Mozgatás lefelé +content#:#cont_tab_move_top#:#Mozgatás felülre +content#:#cont_tab_move_up#:#Mozgatás felfelé content#:#cont_table#:#Táblázat -content#:#cont_table_adv_settings#:#Erweiterte Einstellungen###26 08 2024 new variable +content#:#cont_table_adv_settings#:#További beállítások content#:#cont_table_border#:#Táblázatszegély content#:#cont_table_border_info#:#A tartalomstílus beállításainak érvényre juttatásához hagyja üresen. Az értékeknél a mértékegységet is adja meg (például px). -content#:#cont_table_cell_edit_info_1#:#Click on a table cell to select or deselect it.###26 08 2024 new variable -content#:#cont_table_cell_edit_info_2#:#Click on a row or column header to select or deselect the corresponding row or column.###26 08 2024 new variable -content#:#cont_table_cell_edit_info_3#:#Click on a second cell while holding shift to select all the cells in between.###26 08 2024 new variable +content#:#cont_table_cell_edit_info_1#:#A cella kijelöléséhez, illetve a kijelölés eltávolításához kattintson a cellára. +content#:#cont_table_cell_edit_info_2#:#Egy sor, illetve a fejléc oszlop kijelöléséhez, illetve a kijelölés eltávolításához kattintson megfelelő sorra, illetve a fejléc oszlopra. +content#:#cont_table_cell_edit_info_3#:#A SHIFT nyomvatartása mellett kattintson a második cellára a tartomány kijelöléséhez. content#:#cont_table_cell_properties#:#Táblázatcella tulajdonságai content#:#cont_table_cellpadding#:#Táblázatcellák margója content#:#cont_table_cellpadding_info#:#A tartalomstílus beállításainak érvényre juttatásához hagyja üresen. Az értékeknél a mértékegységet is adja meg (például px). -content#:#cont_table_edit_cells#:#Edit Cells -content#:#cont_table_import_info#:#Please enter the table data separated by semicolon or TAB character for each column. Start a new row for each table row. Spreadsheet applications will usually use TAB characters for separation when transfered via clipboard. It should be possible to paste this data directly into the input field. No further formattings will be imported.###26 08 2024 new variable +content#:#cont_table_edit_cells#:#Cellák módosítása +content#:#cont_table_import_info#:#Kérjük, adja meg a táblázat adatait pontosvesszővel vagy TAB karakterrel elválasztva oszloponként. Kezdjen új sort minden táblázatsorhoz. A táblázatkezelő alkalmazások általában TAB karaktereket használnak az elválasztáshoz, ha vágólapon keresztül viszi át az adatokat. Az adatokat közvetlenül a beviteli mezőbe illesztésének működnie kellene. A program nem importál egyéb formázásokat. content#:#cont_table_properties#:#Táblázat tulajdonságai -content#:#cont_table_style#:#Style###26 08 2024 new variable +content#:#cont_table_style#:#Stílus content#:#cont_table_width#:#Táblázatszélesség content#:#cont_tabs#:#Panelek content#:#cont_tabs_acc_hor#:#Vízszintes harmonika content#:#cont_tabs_acc_ver#:#Függőleges harmonika content#:#cont_tabs_carousel#:#Körhinta (Carousel) -content#:#cont_tabs_confirm_deletion#:#Biztos, hogy törli az összes fület és azok tartalmát? -content#:#cont_target#:#Target###26 08 2024 new variable +content#:#cont_tabs_confirm_deletion#:#Biztos, hogy törli az összes lapot és azok tartalmát? +content#:#cont_target#:#Cél content#:#cont_target_missing#:#A cél hiányzik content#:#cont_target_within_source#:#A célútvonal nem lehet a forrásobjektumon belül. content#:#cont_template#:#Sablon @@ -7153,10 +7186,10 @@ content#:#cont_tex#:#Latex kód content#:#cont_text_acc#:#Kiemelt: content#:#cont_text_code#:#Kód: content#:#cont_text_com#:#Megjegyzés: -content#:#cont_text_editing#:#Edit Text###26 08 2024 new variable +content#:#cont_text_editing#:#Szöveg szerkesztése content#:#cont_text_emp#:#Hangsúlyos szöveg: content#:#cont_text_fn#:#Lábjegyzet: -content#:#cont_text_iln_link#:#Internal Link###29 07 2022 new variable +content#:#cont_text_iln_link#:#Belső link content#:#cont_text_imp#:#Fontos: content#:#cont_text_keyword#:#Kulcsszó content#:#cont_text_placeh#:#Kattintson és szerkesszen szöveg beszúrásához @@ -7176,9 +7209,9 @@ content#:#cont_to_focus_beginning#:#Vissza a tanulási célhoz kapcsolódó tart content#:#cont_to_focus_return_crs#:#Vissza a kurzushoz content#:#cont_toc#:#Tartalomjegyzék content#:#cont_toc_mode#:#Tartalom -content#:#cont_tool_faq#:#GyÍK +content#:#cont_tool_faq#:#GyIK content#:#cont_tool_media#:#Média -content#:#cont_top#:#Felül +content#:#cont_top#:#Felülre content#:#cont_topic#:#Téma content#:#cont_total_time#:#Teljes idő content#:#cont_tracking_bysco#:#Fejezet szerint @@ -7186,15 +7219,15 @@ content#:#cont_tracking_byuser#:#Felhasználó szerint content#:#cont_tracking_data#:#Nyomkövetési adatok content#:#cont_tracking_items#:#Nyomkövetési tételek content#:#cont_tracking_modify#:#Adatmódosítás -content#:#cont_trans_import_info#:#Ha ezt a modult 'XML/Fordításhoz mesternyelv'-ként exportálta egy másik telepítésbe, akkor most újra importálhatja a lefordított exportfájlokat innen a második telepítésből. +content#:#cont_trans_import_info#:#Ha ezt a modult ‘XML/Fordításhoz főnyelv’-ként exportálta egy másik telepítésbe, akkor most újra importálhatja a lefordított exportfájlokat innen a második telepítésből. content#:#cont_transl_master_language_not_allowed#:#Fordítás importáláshoz legalább egy további nyelvet aktiválnia kell a Beállítások » Többnyelvűség alatt. content#:#cont_tree_fixed#:#A szerkezetet javította. content#:#cont_tries#:#Válasz állapotának tárolása, próbálkozások számolása content#:#cont_tries_remaining#:#Fennmaradó próbálkozások száma content#:#cont_tries_reset_on_visit#:#Oldal megnyitásakor állítsuk alaphelyzetbe -content#:#cont_tries_reset_on_visit_info#:#A kérdések 0 próbálkozásszámról indulnak minden oldalmegnyitás esetén. A tanulónak minden oldalmegtekintés során meg kell válaszolni a kérdéseket. +content#:#cont_tries_reset_on_visit_info#:#A kérdések 0 próbálkozásszámról indulnak minden oldalmegnyitáskor. A tanulónak minden oldalmegnyitáskor meg kell válaszolniuk a kérdéseket. content#:#cont_tries_store#:#Válaszok állapotát tároljuk -content#:#cont_tries_store_info#:#A próbálkozások számát összegezve tároljuk. A már megválaszolt kérdéseket nem szükséges újra megválaszolnia. A hallgató kifogyhat a próbálkozások számából. +content#:#cont_tries_store_info#:#A próbálkozások számát összeadva tároljuk. A helyesen megválaszolt kérdéseket nem válaszolhatja meg újra. A tanuló kifogyhat a próbálkozások számából. content#:#cont_trigger_area#:#Triggerterület content#:#cont_type#:#Típus content#:#cont_type_not_allowed#:#Tartalom típus nem lehet ezen helyen. @@ -7210,16 +7243,16 @@ content#:#cont_update_profile#:#Személyes adatok módosítása content#:#cont_update_resources#:#Forráslista módosítása content#:#cont_update_section#:#Bekezdés módosítása content#:#cont_update_skills#:#Kompetencia módosítása -content#:#cont_update_verification#:#Igazolás módosítása +content#:#cont_update_verification#:#Tanúsítvány módosítása content#:#cont_upload_dir#:#Feltöltési mappa -content#:#cont_upload_file#:#Upload File -content#:#cont_upload_multi_srt_howto#:#Ennek a funkciónak a használatával lehetősége van a tananyag médiaobjektumaihoz többnyelvű feliratok (SRT-fájlok) feltöltésére ZIP-fájlban. A .zip fájl ne tartalmazzon mappát, egyik .srt fájl se legyen mappában. Az összes SRT-fájl vége legyen '_<nyelvi kód>.srt', ahol a nyelvi kód például hu, en, de. A fájlnév eleje célszerű hogy a videófájl nevéhez illeszkedjen, például 'video.mp4' -> 'video_hu.srt'. +content#:#cont_upload_file#:#Fájl feltöltése +content#:#cont_upload_multi_srt_howto#:#Ennek a funkciónak a használatával lehetősége van a tananyag médiaobjektumaihoz többnyelvű feliratok (VTT-fájlok) feltöltésére ZIP-fájlban. A .zip fájl ne tartalmazzon mappát, egyik .vtt fájl se legyen mappában. Az összes VTT-fájl vége legyen ‘_<nyelvi kód>.vtt’, ahol a nyelvi kód például hu, en, de. A fájlnév eleje célszerű hogy a videófájl nevéhez illeszkedjen, például ‘video.mp4’ ➜ ‘video_hu.vtt’. content#:#cont_uploaded_file#:#Létező fájl. -content#:#cont_url_info#:#URL of a media file or Youtube URL. +content#:#cont_url_info#:#Médiafájl vagy Youtube URL. content#:#cont_usage#:#Felhasználás content#:#cont_use_same_resource_as_above#:#Használja ugyanazt a forrást, mint fent content#:#cont_user#:#Felhasználó -content#:#cont_user_blocked#:#'%s' felhasználó elhasználta a tananyagban az összes válaszadási lehetőségét. +content#:#cont_user_blocked#:#‘%s’ felhasználó elhasználta a tananyagban az összes válaszadási lehetőségét. content#:#cont_user_blocked2#:#Egy felhasználó elhasználta a tananyagban az összes válaszadási lehetőségét. Az Ön beavatkozás nélkül ez a felhasználó nem tud tovább haladni a tananyagban. content#:#cont_user_blocked3#:#Nyissa meg a tananyagot szerkesztési módban és menjen ide: content#:#cont_user_search_did_not_match#:#Keresése nem illeszkedik egy felhasználóra sem. @@ -7227,21 +7260,21 @@ content#:#cont_users_answered#:#Választ adó felhasználók content#:#cont_users_have_mob_in_clip1#:#Ez a médiaobjektum a vágólapján van: content#:#cont_users_have_mob_in_clip2#:#felhasználó(k). content#:#cont_validate_file#:#Fájl érvényesítése -content#:#cont_verification_object#:#Igazolás +content#:#cont_verification_object#:#Tanúsítvány content#:#cont_verification_placeh#:#Kattints és szerkessz a tanúsítvány beszúrásához content#:#cont_verification_placehl#:#Tanúsítvány-helyőrző content#:#cont_version#:#verzió content#:#cont_versions#:#Verziók content#:#cont_whole_glossary#:#Teljes fogalomtár -content#:#cont_width#:#Szélesség +content#:#cont_width#:#Szélesség (pixel) content#:#cont_width_height_info#:#A megjelenítés fix méretűre állítható. Bevált érték a 950 pixel szélesség és a 650 pixel magasság. Amennyiben nem ad meg értéket, a böngésző megpróbálja meghatározni a megjelenítés méretét. -content#:#cont_wiki_link_dialog#:#Link wikilapra (párbeszédablakos) +content#:#cont_wiki_link_dialog#:#Wikilap (párbeszédablakos) content#:#cont_wiki_page#:#Wiki oldal content#:#cont_wiki_page_link#:#Wikilap link content#:#cont_wrong_answers#:#Hibás válaszok content#:#cont_wrong_answers_single#:#Hibás válasz. content#:#cont_xml_base#:#xml:base -content#:#cont_zip_file_invalid#:#A fájl nem érvényes importfájl.
    Nem tartalmaz fájlt '%s'. +content#:#cont_zip_file_invalid#:#A fájl nem érvényes importfájl.
    Nem tartalmaz fájlt ‘%s’. content#:#content_no_edit_lock#:#Másik felhasználó jelenleg zárolja az oldalt. content#:#content_page_history#:#Lapelőzmények content#:#content_plugin_not_activated#:#Az oldal tartalmi elem bővítmény jelenleg nem aktív. @@ -7256,7 +7289,7 @@ content#:#glo_full_definitions#:#Teljes meghatározások content#:#glo_full_definitions_info#:#Fogalmak és meghatározásaik teljes egészében megjelennek a főnézetben. content#:#glo_hide_taxonomy#:#Taxonómia elrejtése content#:#glo_list_usages#:#Előfordulások listája -content#:#glo_mode_normal_info#:#Csak az ebben a fogalomtárban létrehozott fogalmakat fogja tartalmazni. +content#:#glo_mode_normal_info#:#Az ebben a fogalomtárban létrehozott összes fogalmat fogja tartalmazni. content#:#glo_presentation_mode#:#Megjelenítés módja content#:#glo_presentation_view#:#Megjelenítési nézet content#:#glo_quick_navigation#:#Gyors navigáció @@ -7270,7 +7303,7 @@ content#:#glo_text_snippet_length#:#Meghatározások hossza content#:#glo_text_snippet_length_info#:#A meghatározás áttekintésben megjelenő szövegrészének hossza. content#:#glo_usages#:#Fogalomtárat használó(k) content#:#glo_used_in_scorm#:#A fogalomtárat használja a SCORM-tananyag. Ha törli, a fogalomtárra hivatkozások nem oldhatók majd fel. -content#:#help_assign_help_ids#:#Fejezet/Képernyő-ID-k hozzárendelés +content#:#help_assign_help_ids#:#Fejezet/Screen-ID-k hozzárendelés content#:#htlm_import#:#HTML-tananyag importálása content#:#import_sco_object#:#SCO importálása content#:#info_stop_offline_mode_sure#:#Megjegyzés: A tanulási haladás adatai offline módban elvesznek. Biztos, hogy ezt szeretné? @@ -7284,7 +7317,7 @@ content#:#lm_menu_new_entry#:#Új menübejegyzés létrehozása content#:#lm_menu_select_internal_object#:#Belső objektum kiválasztása >> content#:#lm_menu_select_object_to_add#:#Válassza ki az objektumot, amelyet fel szeretne venni a menübe! content#:#lm_no_download_files#:#Jelenleg nem áll rendelkezésre letölthető fájl. -content#:#lm_only_one_download_per_type#:#Kérjük, vegye figyelembe, hogy típusonként (XML, HTML, SCORM) csak egy fájlt tehet nyilvánosan elérhetővé. +content#:#lm_only_one_download_per_type#:#Típusonként (XML, HTML) csak egy fájlt tehet nyilvánosan elérhetővé. content#:#lm_rate_page#:#Oldal értékelése content#:#lm_rating#:#Tananyag értékelése content#:#mep_folder_created#:#Új mappát hozott létre @@ -7306,7 +7339,7 @@ content#:#sahs_insert_pg_from_clip#:#Oldalak importálása ILIAS-tananyagból content#:#sahs_insert_st_from_clip#:#Fejezetek importálása ILIAS-tananyagból content#:#sahs_insert_st_from_clip_inside_chap#:#Fejezetek importálása ILIAS-tananyagból (fejezeten belül) content#:#save_new#:#Mentés és új -content#:#saved_media_object#:#Mentett médiaobjektum. +content#:#saved_media_object#:#A médiaobjektumot sikeresen mentette. content#:#scplayer_collapsetree#:#Összes becsukása content#:#scplayer_continue#:#Folytatás content#:#scplayer_debugger#:#Teszteszköz megjelenítése @@ -7329,10 +7362,10 @@ content#:#seq_error#:#Belső hiba fordult elő a sorrendezőben. content#:#seq_toc#:#Kérjük, válasszon a bal oldali tartalomjegyzékből. content#:#set_public_mode#:#Nyilvános elérési mód beállítása content#:#st#:#Fejezet -content#:#start_lm#:#Launch Learning Module###26 08 2024 new variable +content#:#start_lm#:#Tananyag indítása content#:#text_repr#:#Kép szöveges leírása -content#:#text_repr_info#:#A kép 'alt' attribútumához használva. -copa#:#copa_activation_online_info#:#Set the Content Page online to make it visible and available to other users. If not, only administrators will have access to it.###29 07 2022 new variable +content#:#text_repr_info#:#A kép ‘alt’ attribútumához használva. +copa#:#copa_activation_online_info#:#Állítsa a Tartalomlapot online-ra, hogy a felhasználók láthassák és elérhessék, különben csak magasabb jogosultsággal érhető el. copa#:#copa_add#:#Tartalomlap hozzáadása copa#:#copa_btn_lp_toggle_state_completed#:#Beállítás nem teljesítettre copa#:#copa_btn_lp_toggle_state_not_completed#:#Beállítás teljesítettre @@ -7345,46 +7378,48 @@ copa#:#copa_prop_reading_time#:#Olvasási idő copa#:#copa_value_reading_time_f_p#:#%s perc copa#:#copa_value_reading_time_f_s#:#%s perc copa#:#obj_copa_duplicate#:#Tartalomlap duplikálása -copg#:#copg_active_to_small#:#This date must be higher than the starting date.###26 08 2024 new variable +copg#:#copg_active_to_small#:#A dátumnak a kezdő dátumnál későbbinek kell lennie. +copg#:#copg_add_content#:#Tartalom hozzáadása copg#:#copg_allow_html#:#HTML/Javascript bekapcsolása copg#:#copg_allow_html_info#:#HTML, illetve Javascript oldaltartalmakat használhat. Ez biztonsági rést okozhat, ezért ne kapcsolja be, ha lehet ártó szándékú felhasználója. Az ilyen módú HTML-tartalom hozzáadása várhatóan már nem lesz támogatott a későbbi verziókban. -copg#:#copg_an_error_occured#:#An error occured.###29 07 2022 new variable +copg#:#copg_an_error_occured#:#Hiba történt. copg#:#copg_confirm_el_deletion#:#Biztos, hogy törli a kijelölt elemeket? -copg#:#copg_cron_days#:#Delete pages older than###29 07 2022 new variable -copg#:#copg_cron_days_info#:#Page history entries older than this period will be deleted.###29 07 2022 new variable -copg#:#copg_cron_keep_entries#:#Keep Minimum###29 07 2022 new variable -copg#:#copg_cron_keep_entries_info#:#This number is the minimum of entries that will be kept, even if they are older than the deletion period.###29 07 2022 new variable -copg#:#copg_days#:#Days###29 07 2022 new variable -copg#:#copg_details#:#Details###29 07 2022 new variable -copg#:#copg_edit_iframe_title#:#Text Editing of Page Editor###26 08 2024 new variable -copg#:#copg_entries#:#Entries###29 07 2022 new variable -copg#:#copg_error#:#Error###29 07 2022 new variable -copg#:#copg_error_occured_modal#:#An error occured while processing the page. Hit "Reload Page" to return to the previously saved state.###29 07 2022 new variable -copg#:#copg_est_reading_time#:#Estimated Reading Time###29 07 2022 new variable -copg#:#copg_history_cleanup_cron#:#Page Editor History Cleanup###29 07 2022 new variable -copg#:#copg_history_cleanup_cron_info#:#Removes older entries from the page history.###29 07 2022 new variable -copg#:#copg_list_item_style#:#List Item###26 08 2024 new variable -copg#:#copg_list_style#:#List###26 08 2024 new variable -copg#:#copg_list_styles#:#List Formats###26 08 2024 new variable -copg#:#copg_more_character_formats#:#More Styles for Characters###26 08 2024 new variable -copg#:#copg_obj_types#:#Object Types###26 08 2024 new variable -copg#:#copg_page_element_not_found#:#Page element not found.###29 07 2022 new variable +copg#:#copg_cron_days#:#Ennél régebbi lapok törlése: +copg#:#copg_cron_days_info#:#Töröljük a megadottnál régebbi lapelőzményeket. +copg#:#copg_cron_keep_entries#:#Minimálisan megtartandók +copg#:#copg_cron_keep_entries_info#:#Legalább ennyi bejegyzést akkor is megtartunk, ha azok régebbiek a megadottnál. +copg#:#copg_days#:#Napok +copg#:#copg_details#:#Részletek +copg#:#copg_edit_iframe_title#:#Az oldalszerkesztő szövegszerkesztése +copg#:#copg_entries#:#Bejegyzések +copg#:#copg_error#:#Hiba +copg#:#copg_error_occured_modal#:#Hiba az oldal betöltése közben. Kattintson az oldal újratöltésére, így visszatér a korábban mentett állapothoz. +copg#:#copg_est_reading_time#:#Becsült olvasási idő +copg#:#copg_history_cleanup_cron#:#Oldalszerkesztőelőzmény-tisztítás +copg#:#copg_history_cleanup_cron_info#:#Régi bejegyzések eltávolítása az oldalelőzményekből. +copg#:#copg_list_item_style#:#Felsorolás eleme +copg#:#copg_list_style#:#Felsorolás +copg#:#copg_list_styles#:#Felsorolási formátumok +copg#:#copg_more_character_formats#:#További karakterstílusok +copg#:#copg_obj_types#:#Objektumtípusok +copg#:#copg_page_element_not_found#:#Az oldalelem nem található. copg#:#copg_page_type_stys#:#Lapelrendezés -copg#:#copg_pages#:#Pages###29 10 2025 new variable -copg#:#copg_par_format_selection#:#Paragraph Format Selection###26 08 2024 new variable -copg#:#copg_pc_mob_does_not_exist#:#This media object does not exist.###26 08 2024 new variable -copg#:#copg_plugin#:#Plugin###29 10 2025 new variable -copg#:#copg_plugin_not_avail#:#Plugin %s not available.###29 10 2025 new variable +copg#:#copg_pages#:#Lapok +copg#:#copg_par_format_selection#:#Bekezdésformátumok +copg#:#copg_pc_mob_does_not_exist#:#Ez a médiaelem nem létezik. +copg#:#copg_plugin#:#Bővítmény +copg#:#copg_plugin_not_avail#:#‘%s’ bővítmény nem érhető el copg#:#copg_questions_not_supported_here#:#Ebben a kontextusban a kérdéseket nem támogatjuk. -copg#:#copg_reload_page#:#Reload Page###29 07 2022 new variable -copg#:#copg_remove_formats#:#Remove Formatting###26 08 2024 new variable -copg#:#copg_sec_link_info#:#Ha erre az egész blokkra állít be egy linket, győződjön meg arról, hogy a blokk más interaktív elemet (például másik linket) nem tartalmaz, mert azok helyes működése így nem biztosított. +copg#:#copg_reload_page#:#Oldal újratöltése +copg#:#copg_remove_formats#:#Formázás eltávolítása +copg#:#copg_sec_link_info#:#Válassza ki a célt, amire a blokk mutat. Figyelem: Ebben az esetben a blokk nem tartalmazhat további linket! copg#:#copg_snippet_cannot_be_edited#:#Ez egy előre definiált tartalom-építőelem, ezért itt nem módosítható. -copg#:#copg_templates#:#Templates###29 10 2025 new variable -copg#:#copg_unsupported_media_type#:#This media object has an unsupported media type.###26 08 2024 new variable -copg#:#copg_x_minutes#:#%s minute(s)###29 07 2022 new variable +copg#:#copg_templates#:#Sablonok +copg#:#copg_unsupported_media_type#:#Nem támogatott médiatípus. +copg#:#copg_use_template#:#Sablon használata +copg#:#copg_x_minutes#:#%s perc cpad#:#cpad_reading_time_status#:#Olvasási idő -cpad#:#cpad_reading_time_status_desc#:#If enabled, the estimated reading time for content page objects will be determined and displayed. +cpad#:#cpad_reading_time_status_desc#:#A tartalomlap becsült olvasási idejét megállapítjuk és megjelenítjük. cptch#:#cptch_freetype_support_needed#:#Ennek a funkciónak a használatához a PHP freetype támogatását engedélyeznie kell. cptch#:#cptch_wrong_input#:#Hibás bemenet cron#:#cro_job_rc_job_auto_deactivation_time_limit#:#Az ütemezett feladatot deaktiváltuk, mert több, mint 3 órája inaktív @@ -7392,26 +7427,26 @@ cron#:#cro_job_rc_job_manual_reset#:#Az üzemeltető újraaktiválta az ütemeze cron#:#cro_job_rc_job_no_result#:#Az ütemezett feladat nem megfelelő eredményt adott vissza cron#:#cron_action_activate#:#Bekapcsolás cron#:#cron_action_activate_success#:#Ütemezett feladatot sikeresen bekapcsolta. -cron#:#cron_action_activate_sure#:#Biztos, hogy bekapcsolja az ütemezett feladatot: '%s'? +cron#:#cron_action_activate_sure#:#Biztos, hogy bekapcsolja az ütemezett feladatot: ‘%s’? cron#:#cron_action_activate_sure_multi#:#Biztos, hogy bekapcsolja az alábbi ütemezett feladatot? cron#:#cron_action_deactivate#:#Kikapcsolás cron#:#cron_action_deactivate_success#:#Ütemezett feladatot sikeresen kikapcsolta. -cron#:#cron_action_deactivate_sure#:#Biztos, hogy kikapcsolja az ütemezett feladatot: '%s'? +cron#:#cron_action_deactivate_sure#:#Biztos, hogy kikapcsolja az ütemezett feladatot: ‘%s’? cron#:#cron_action_deactivate_sure_multi#:#Biztos, hogy kikapcsolja az alábbi ütemezett feladatot? cron#:#cron_action_edit#:#Ütemezés módosítása cron#:#cron_action_edit_success#:#Az ütemezést sikeresen frissítette. cron#:#cron_action_reset#:#Reszetelés -cron#:#cron_action_reset_success#:#Az ütemezett feladatot sikeresen reszetelte. -cron#:#cron_action_reset_sure#:#Biztos, hogy megállítja az ütemezett feladatot: '%s'? -cron#:#cron_action_reset_sure_multi#:#Biztos, hogy reszeteli az alábbi ütemezett feladatot? +cron#:#cron_action_reset_success#:#Az ütemezett feladatot sikeresen alapértékre állította. +cron#:#cron_action_reset_sure#:#Biztos, hogy megállítja az ütemezett feladatot: ‘%s’? +cron#:#cron_action_reset_sure_multi#:#Biztos, hogy alapértékre állítja az alábbi ütemezett feladatot? cron#:#cron_action_run#:#Futtatás cron#:#cron_action_run_fail#:#Ütemezett feladat futása sikertelen. cron#:#cron_action_run_success#:#Az ütemezett feladata sikeresen lefutott. -cron#:#cron_action_run_sure#:#Biztos, hogy futtatja az ütemezett feladatot: '%s'? +cron#:#cron_action_run_sure#:#Biztos, hogy futtatja az ütemezett feladatot: ‘%s’? cron#:#cron_changed_by_crontab#:#RENDSZER cron#:#cron_component#:#Komponens cron#:#cron_job_id#:#Azonosító -cron#:#cron_jobs_with_required_intervention#:#The following jobs may require an intervention.###29 10 2025 new variable +cron#:#cron_jobs_with_required_intervention#:#A következő feladatok igényelhetnek beavatkozást. cron#:#cron_last_run#:#Utolsó futás cron#:#cron_no_executable_job_selected#:#Legalább egy ütemezett feladatok jelöljön ki! cron#:#cron_result#:#Eredmény @@ -7441,8 +7476,8 @@ cron#:#cron_status_info#:#Állapotinformáció crs#:#activation_times_not_valid#:#Az elérési időszak nem érvényes. crs#:#assigned#:#Engedélyezve crs#:#contact_email_not_valid#:#A kapcsolattartó e-mail címe nem érvényes. -crs#:#crs_accept_subscriber#:#'%s'-hoz a regisztráció megerősítve -crs#:#crs_accept_subscriber_body#:#Megerősítjük regisztrációjukat a '%s' kurzushoz. +crs#:#crs_accept_subscriber#:#‘%s’-hoz a regisztráció megerősítve +crs#:#crs_accept_subscriber_body#:#Megerősítjük regisztrációjukat a ‘%s’ kurzushoz. crs#:#crs_access#:#Hozzáférés crs#:#crs_activate_notification#:#Értesítés bekapcsolása crs#:#crs_activation#:#Aktiválás @@ -7454,11 +7489,11 @@ crs#:#crs_add_grouping#:#Tagságkorlátozás létrehozása crs#:#crs_add_html_archive#:#HTML-archívum létrehozása crs#:#crs_add_objective#:#Cél létrehozása crs#:#crs_add_remove_from_desktop#:#Hozzáadása a kedvencekhez -crs#:#crs_add_remove_from_desktop_info#:#A kurzus elemeit a tagok a kedvenceik közé tehetik -crs#:#crs_add_starter#:#Kezdőobjektum létrehozása +crs#:#crs_add_remove_from_desktop_info#:#A kurzus elemeit a tagok a kedvenceik közé tehetik. +crs#:#crs_add_starter#:#Kezdőobjektum beállítása crs#:#crs_add_to_group#:#Csoportba felvétel -crs#:#crs_added_member#:#'%s' kurzushoz csatlakozás -crs#:#crs_added_member_body#:#ezúton tájékoztatjuk, hogy '%s' kurzushoz sikeresen csatlakozott. +crs#:#crs_added_member#:#‘%s’ kurzushoz csatlakozás +crs#:#crs_added_member_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzushoz sikeresen csatlakozott. crs#:#crs_added_new_archive#:#Új archívum jött létre crs#:#crs_added_objective#:#Új tanulási célt adott hozzá. crs#:#crs_added_starters#:#Engedélyezett kezdő objektum(ok). @@ -7470,7 +7505,7 @@ crs#:#crs_admission_link_failure_invalid_code#:#Nem rögzíthető: érvénytelen crs#:#crs_admission_link_failure_membership_limited#:#Nem regisztrálhat, mert a kurzus tagsága korlátozott. crs#:#crs_admission_link_failure_offline#:#Nem regisztrálhat: a kurzus offline. crs#:#crs_admission_link_failure_registration_period#:#Nem regisztrálhat, mert jelenleg nincs regisztrációs időszak. -crs#:#crs_admission_link_success_registration#:#'%s' kurzusba sikeresen regisztrált. +crs#:#crs_admission_link_success_registration#:#‘%s’ kurzusba sikeresen regisztrált. crs#:#crs_agree#:#Elfogadás crs#:#crs_agreement_header#:#Felhasználói megállapodás crs#:#crs_agreement_required#:#El kell fogadnia a felhasználói megállapodást, ha regisztrálni szeretne erre a kurzusra. @@ -7480,20 +7515,20 @@ crs#:#crs_auto_notification_info#:#Kurzuscsatlakozáskor levelet küldünk az ú crs#:#crs_awrn_current_course#:#Jelenlegi kurzus crs#:#crs_awrn_current_course_info#:#Ha a felhasználó a kurzushoz navigál a Tartalomtárban, a kurzus összes tagját felsoroljuk. crs#:#crs_awrn_support_contacts#:#Tutori segítségnyújtók -crs#:#crs_awrn_support_contacts_info#:#A jelenlegi felhasználó összes kurzusának tutori segítségnyújtóinak felsorolása. Ezek a megfelelők kurzus 'Tagok' fülén lévő 'Tutori segítségnyújtók' részben található felhasználók. +crs#:#crs_awrn_support_contacts_info#:#A jelenlegi felhasználó összes kurzusának tutori segítségnyújtóinak felsorolása. Ezek a megfelelők kurzus ‘Tagok’ lapján lévő ‘Tutori segítségnyújtók’ részben található felhasználók. crs#:#crs_blocked#:#Hozzáférés megtagadva -crs#:#crs_blocked_member#:#'%s' kurzustagság blokkolása -crs#:#crs_blocked_member_body#:#ezúton tájékoztatjuk, hogy '%s' kurzustagságát blokkolták. +crs#:#crs_blocked_member#:#‘%s’ kurzustagság blokkolása +crs#:#crs_blocked_member_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzustagságát blokkolták. crs#:#crs_breadcrumb_crs_only#:#Kurzustól indul crs#:#crs_breadcrumb_full_path#:#Teljes útvonal crs#:#crs_cancel_subscr_request#:#Tagsági kérelem törlése -crs#:#crs_cancel_subscription#:#'%s' kurzust elhagyta egy tag -crs#:#crs_cancel_subscription_body#:#'%s' kurzustagságát egy tag lemondta. +crs#:#crs_cancel_subscription#:#‘%s’ kurzust elhagyta egy tag +crs#:#crs_cancel_subscription_body#:#‘%s’ kurzustagságát egy tag lemondta. crs#:#crs_cancel_subscription_body2#:#Lehet, hogy vannak még a kurzus várólistáján. A várólistát most kell ellenőriznie. Kurzusának tagjait ide kattintva tekintheti meg: -crs#:#crs_cancellation_end#:#'Lejelentkezés a kurzusról' időkorlátja +crs#:#crs_cancellation_end#:#‘Lejelentkezés a kurzusról’ időkorlátja crs#:#crs_cancellation_end_info#:#Az itt megadott ideig tudnak a résztvevők lejelentkezni a kurzusról. crs#:#crs_cancellation_end_rbac_info#:#A lemondást határideje %s volt, lemondása utána már nem lehetséges. -crs#:#crs_cannot_find_role#:#Ez a szerep nem található. +crs#:#crs_cannot_find_role#:#Ez a szerepkör nem található. crs#:#crs_cdf_edit_member#:#Felhasználó kurzushoz kötődő adatainak módosítása crs#:#crs_cdf_tbl_last_edit#:#Módosítva (kurzusspecifikus adat) crs#:#crs_checklist_objective#:#Célkitűzés-ellenőrzőlista @@ -7511,14 +7546,14 @@ crs#:#crs_course_period_not_valid#:#A kurzusidőszak nem érvényes. crs#:#crs_course_status_of_users#:#Kurzus teljesítése crs#:#crs_create_date#:#Dátum létrehozása crs#:#crs_custom_user_fields#:#Kurzushoz tartozó felhasználói adatok -crs#:#crs_custom_user_fields_infobox#:#Create additional data fields for course members to fill in when joining. You can show this information as an additional column in the "Members" tab.###26 08 2024 new variable -crs#:#crs_custom_user_fields_table_title#:#Relevant User Data of This Course###26 08 2024 new variable +crs#:#crs_custom_user_fields_infobox#:#További adatmezők létrehozása a kurzustagok számára, amelyeket csatlakozáskor ki kell töltenük. Ezt az információt további oszlopként is megjelenítheti a ‘Tagok’ lapon. +crs#:#crs_custom_user_fields_table_title#:#A kurzus releváns felhasználói adatai crs#:#crs_dates#:#Dátumok crs#:#crs_deactivate_notification#:#Értesítés kikapcsolása crs#:#crs_delete_objectve_sure#:#Biztos, hogy törli a kiválasztott célokat? crs#:#crs_details#:#Kurzusrészletek -crs#:#crs_dismiss_member#:#'%s' tagságát megszüntették -crs#:#crs_dismiss_member_body#:#ezúton tájékoztatjuk, hogy '%s' kurzusban tagságát megszüntették. +crs#:#crs_dismiss_member#:#‘%s’ tagságát megszüntették +crs#:#crs_dismiss_member_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzusban tagságát megszüntették. crs#:#crs_edit_lo_introduction#:#Bevezető üzenet módosítása crs#:#crs_edit_timings#:#Időzítés beállítása crs#:#crs_enable_map#:#Kurzustérkép engedélyezése @@ -7538,7 +7573,7 @@ crs#:#crs_groupings#:#Kurzuscsoportosítás crs#:#crs_groups_nr#:#Csoporttagságok száma crs#:#crs_grp_added_grouping#:#Új tagságkorlátozás jött létre crs#:#crs_grp_already_assigned#:#Már tagja ennek a kurzuscsoportosításnak. -crs#:#crs_grp_assign_crs#:#Kurzus hozzárendelése +crs#:#crs_grp_assign_crs#:#A tagságkorlátozás hozzárendelt objektumai crs#:#crs_grp_assignments#:#Kurzustagok csoportokba rendezése crs#:#crs_grp_enter_title#:#Adjon meg egy címet. crs#:#crs_grp_info_reg#:#Az alábbi kurzusokra tagsági korlátozás van érvényben. Ezekből csak egy kurzusra jelentkezhet: @@ -7567,7 +7602,7 @@ crs#:#crs_intro_course_group_notification_index#:#Az alábbi csoportokhoz és ku crs#:#crs_item_presetting_info#:#Válassza ezt a beállítást a tanulóknak ajánlott tanulási/feldolgozási időszak megadásához. Ez csak ajánlás, ettől függetlenül mindig elérhető. crs#:#crs_join_request#:#Küldés crs#:#crs_lhist_objective_completed#:#$3$ elsajátítva $1$ alatt. -crs#:#crs_lim_assigned#:#'%s' kurzusnak már tagja. +crs#:#crs_lim_assigned#:#‘%s’ kurzusnak már tagja. crs#:#crs_link_hide_next_sessions#:#Közelgő események elrejtése crs#:#crs_link_hide_prev_sessions#:#Előző esemény elrejtése crs#:#crs_link_show_all_next_sessions#:#Összes közelgő esemény @@ -7577,11 +7612,11 @@ crs#:#crs_lobj_pm_score#:#Eredményei crs#:#crs_loc_btn_new_assignment#:#Új teszthozzárendelés crs#:#crs_loc_confirm_delete_tst#:#Biztos, hogy törli ennek a tanulásicél-orientált kurzusnak a tesztjét? crs#:#crs_loc_delete_assignment#:#Teszt hozzárendelésének törlése -crs#:#crs_loc_err_no_active_it#:#Tanulási célok belépő teszt nélkül +crs#:#crs_loc_err_no_active_it#:#Belépő teszt nélküli tanulási célok crs#:#crs_loc_err_no_active_lo#:#Nincsenek aktív tanulási célok -crs#:#crs_loc_err_no_active_mat#:#Tanulási célok hozzárendelt tartalom nélkül -crs#:#crs_loc_err_no_active_qst#:#Tanulási célok kérdések nélkül -crs#:#crs_loc_err_no_active_qt#:#Tanulási célok záró teszt nélkül +crs#:#crs_loc_err_no_active_mat#:#Tartalom nélküli tanulási célok +crs#:#crs_loc_err_no_active_qst#:#Kérdések nélküli tanulási célok +crs#:#crs_loc_err_no_active_qt#:#Záró teszt nélküli tanulási célok crs#:#crs_loc_err_nr_tries_exceeded#:#Az objektumonkénti kitöltési lehetőségeinek száma meghaladja a záró teszt kitöltési lehetőségeinek számát. crs#:#crs_loc_err_stat_no_it#:#Nincs elérhető belépő teszt crs#:#crs_loc_err_stat_no_materials#:#Nincs elérhető kurzussegédanyag @@ -7590,16 +7625,16 @@ crs#:#crs_loc_err_stat_tst_offline#:#Nem online az összes teszt. crs#:#crs_loc_form_assign#:#Meglévő teszt használata crs#:#crs_loc_form_assign_initial_info#:#Ebben a kurzusban lévő egyik teszt kiválasztása belépő tesztnek crs#:#crs_loc_form_assign_it#:#Teszt hozzárendelése -crs#:#crs_loc_form_assign_qualified_info#:#-- +crs#:#crs_loc_form_assign_qualified_info#:#Ebben a kurzusban lévő egyik teszt kiválasztása záró tesztnek crs#:#crs_loc_form_available_tsts#:#Elérhető tesztek crs#:#crs_loc_form_create_objectives#:#Tanulási célok létrehozása crs#:#crs_loc_form_random_limits_it#:#Belépő teszt kérdéseinek létrehozása crs#:#crs_loc_form_random_limits_qt#:#Záró teszt kérdéseinek létrehozása crs#:#crs_loc_form_tst_new#:#Új teszt létrehozása -crs#:#crs_loc_form_tst_new_initial_info#:#Új teszt létrehozása belépő tesztnek -crs#:#crs_loc_form_tst_new_qualified_info#:#-- +crs#:#crs_loc_form_tst_new_initial_info#:#Új belépő teszt létrehozása +crs#:#crs_loc_form_tst_new_qualified_info#:#Új záró teszt létrehozása crs#:#crs_loc_itest_info#:#Belépő teszt -crs#:#crs_loc_itst_for_objective#:#'%1$s' belépő teszt +crs#:#crs_loc_itst_for_objective#:#‘%1$s’ belépő teszt crs#:#crs_loc_learning_objective#:#Tanulási célok crs#:#crs_loc_mem_show_res#:#Teszteredmények megjelenítése crs#:#crs_loc_num_qst#:#Kérdések száma @@ -7616,13 +7651,13 @@ crs#:#crs_loc_progress_no_result_no_initial#:#Kérem, újra dolgozza fel az alá crs#:#crs_loc_progress_objective_complete#:#Tanulási célokat sikeresen teljesített. crs#:#crs_loc_progress_result_itest#:#Belépő teszt eredménye crs#:#crs_loc_progress_result_qtest#:#Végeredmény -crs#:#crs_loc_qst_resume_tst_itest#:#Különböző tanulás célokhoz belépő tesztek nem indíthatóak el párhuzamosan. Egy tanulási célhoz már elkezdett kitölteni egy tesztet. Vagy folytassa a már elkezdett tesztet vagy kezdjen újat. -crs#:#crs_loc_qst_resume_tst_qtest#:#Különböző tanulás célokhoz záró tesztek nem indíthatóak el párhuzamosan. Egy tanulási célhoz már elkezdett kitölteni egy záró tesztet. Vagy folytassa a már elkezdett tesztet vagy kezdjen újat. +crs#:#crs_loc_qst_resume_tst_itest#:#Különböző tanulás célokhoz belépő tesztek nem indíthatók el párhuzamosan. Egy tanulási célhoz már elkezdett kitölteni egy tesztet. Vagy folytassa a már elkezdett tesztet vagy kezdjen újat. +crs#:#crs_loc_qst_resume_tst_qtest#:#Különböző tanulás célokhoz záró tesztek nem indíthatók el párhuzamosan. Egy tanulási célhoz már elkezdett kitölteni egy záró tesztet. Vagy folytassa a már elkezdett tesztet vagy kezdjen újat. crs#:#crs_loc_qtest_info#:#Záró teszt -crs#:#crs_loc_qtst_for_objective#:#'%1$s' záró teszt +crs#:#crs_loc_qtst_for_objective#:#‘%1$s’ záró teszt crs#:#crs_loc_rand_assign_qpl#:#Hozzárendelés kérdésgyűjteményből crs#:#crs_loc_rand_qpl#:#Elérhető kérdésgyűjtemények -crs#:#crs_loc_settings_err_qstart#:#A 'Záró teszt legyen kezdőobjektum' beállítása nem lehetséges, mert azt csak belépő teszt nélküli kurzusnál lehet bekapcsolni. +crs#:#crs_loc_settings_err_qstart#:#A ‘Záró teszt legyen kezdőobjektum’ beállítása nem lehetséges, mert azt csak belépő teszt nélküli kurzusnál lehet bekapcsolni. crs#:#crs_loc_settings_it_start_object#:#A Belépő teszt legyen a kezdőobjektum crs#:#crs_loc_settings_it_type#:#Belépő teszt crs#:#crs_loc_settings_itest_tbl#:#Belépő teszt beállításai @@ -7633,8 +7668,8 @@ crs#:#crs_loc_settings_qt_all#:#Záró teszt crs#:#crs_loc_settings_qt_start_object#:#Záró teszt legyen kezdőobjektum crs#:#crs_loc_settings_qtest_tbl#:#Záró teszt beállításai crs#:#crs_loc_settings_reset#:#Teszteredmények -crs#:#crs_loc_settings_reset_enable#:#'Teszteredmények visszaállításának' engedélyezése -crs#:#crs_loc_settings_reset_enable_info#:#Ha be van kapcsolva, minden felhasználó visszaállíthatja a saját teszteredményeit és újrakezdheti a kurzust. +crs#:#crs_loc_settings_reset_enable#:#‘Teszteredmények visszaállításának’ engedélyezése +crs#:#crs_loc_settings_reset_enable_info#:#Minden felhasználó visszaállíthatja a saját teszteredményeit és újrakezdheti a kurzust. crs#:#crs_loc_settings_tbl#:#Tanulásicél-orientált kurzus beállításai crs#:#crs_loc_settings_tbl_it_nq#:#Szintfelmérő belépő teszt a tanulási célhoz crs#:#crs_loc_settings_tbl_it_q#:#Elővizsga belépő teszt a tanulási célhoz @@ -7678,14 +7713,14 @@ crs#:#crs_loc_tt_info#:#%1$d%%-ot ért el. %2$d%%-tól sikeresen teljesített a crs#:#crs_loc_type_initial_all_info#:#Az ILIAS a belépő teszt végeredménye alapján személyre szabott tananyagot ajánl a még nem teljesített tanulási célok eléréséhez. A végső záró teszt azt méri, hogy a résztvevő elsajátította-e a tanulási célokat, vagy további tanulásra és képzésre van-e szüksége. crs#:#crs_loc_type_qualified_info#:#A kurzus egy teszttel indul, ami felméri, hogy a kurzustag elsajátította-e már a tanulási célokat. A kurzustagnak a sikeresen teljesíti tanulási célok tananyagaival nincs teendője, több tesztet sem kell kitölteni. Az el nem ért tanulási célok teljesítéséhez az ILIAS tananyagot ajánl, teljesítését további teszt vizsgálja. crs#:#crs_mail_all#:#Összes tag -crs#:#crs_mail_all_info#:#Tagok, vezetők és tutorok is használhatják a 'Tagok' fülön lévő 'Levél küldése tagoknak' lehetőséget. +crs#:#crs_mail_all_info#:#Tagok, vezetők és tutorok is használhatják a ‘Tagok’ lapon lévő ‘Levél küldése tagoknak’ lehetőséget. crs#:#crs_mail_context_member_info#:#Egy kurzus információs lapján lévő e-mail címekre crs#:#crs_mail_context_member_title#:#Kurzus: infolap crs#:#crs_mail_context_tutor_info#:#Egy kurzus tagok és tanulási haladás lapján lévő résztvevők e-mail címeire -crs#:#crs_mail_context_tutor_title#:#Kurzsu: levél kurzustagoknak +crs#:#crs_mail_context_tutor_title#:#Kurzus: levél kurzustagoknak crs#:#crs_mail_permanent_link#:#Az alábbi linken érheti el a kurzust: crs#:#crs_mail_tutors_only#:#Csak tutorok és kurzusvezetők -crs#:#crs_mail_tutors_only_info#:#Csak vezetők és tutorok használhatják a 'Tagok' fülön lévő 'Levél küldése tagoknak' lehetőséget. +crs#:#crs_mail_tutors_only_info#:#Csak vezetők és tutorok használhatják a ‘Tagok’ lapon lévő ‘Levél küldése tagoknak’ lehetőséget. crs#:#crs_mail_type#:#Levél küldése tagoknak crs#:#crs_map_location#:#Kurzustérkép helye crs#:#crs_map_settings#:#Térkép @@ -7702,19 +7737,19 @@ crs#:#crs_member#:#Tag crs#:#crs_member_administration#:#Résztvevők módosítása crs#:#crs_member_passed_status_changed#:#Teljesítési állapot változása crs#:#crs_members#:#Tagok -crs#:#crs_members_deleted#:#A tago(ka)t sikeresen törölte +crs#:#crs_members_deleted#:#A tago(ka)t sikeresen eltávolította a kurzusból crs#:#crs_members_groups#:#Csoporttagságok crs#:#crs_members_map#:#Kurzustagok térképe crs#:#crs_members_print_title#:#Kurzustagok crs#:#crs_min_one_admin#:#Legalább egy vezetőt hozzá kell rendelni ehhez a kurzushoz. -crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable +crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#A korlátozott regisztrációs időszak nem állítható be, amíg a ‘Senki sem regisztrálhatja saját magát’ beállítás aktív. +crs#:#crs_my_courses_groups_enabled#:#Kurzusaim és csoportjaim +crs#:#crs_my_courses_groups_enabled_info#:#Ha bekapcsolja, a ‘Kurzusaim és csoportjaim’ rész megjelenik. crs#:#crs_new_status#:#Az Ön új állapota: -crs#:#crs_new_subscription#:#'%s' kurzusba felhasználó regisztrált -crs#:#crs_new_subscription_body#:#ezúton értesítjük, hogy %s regisztrált a(z) '%s' kurzusba. -crs#:#crs_new_subscription_request#:#Jelentkezés erre a kurzusra: '%s' -crs#:#crs_new_subscription_request_body#:#ezúton értesítjük, hogy %s tagsági kérelmet adott be a(z) '%s' kurzushoz. +crs#:#crs_new_subscription#:#‘%s’ kurzusba felhasználó regisztrált +crs#:#crs_new_subscription_body#:#ezúton értesítjük, hogy %s regisztrált a(z) ‘%s’ kurzusba. +crs#:#crs_new_subscription_request#:#Jelentkezés erre a kurzusra: ‘%s’ +crs#:#crs_new_subscription_request_body#:#ezúton értesítjük, hogy %s tagsági kérelmet adott be a(z) ‘%s’ kurzushoz. crs#:#crs_new_subscription_request_body2#:#Regisztráció megerősítéséhez kattintson ide: crs#:#crs_news#:#Kurzushírek crs#:#crs_no_archive_selected#:#Egy archívum sincs kiválasztva @@ -7759,19 +7794,19 @@ crs#:#crs_objective_pretest#:#Belépő teszt után crs#:#crs_objective_qst_summary#:#Kérdés-hozzárendelés áttekintése crs#:#crs_objective_random_warn#:#Nem használhat véletlen-kiválasztásos tesztet tanulási célokkal kombinálva. crs#:#crs_objective_result#:#Befejezőteszt után -crs#:#crs_objective_result_details#:#« Show Details###29 07 2022 new variable -crs#:#crs_objective_result_summary_initial#:#Placement Test: %1$s (%2$s required)###29 07 2022 new variable -crs#:#crs_objective_result_summary_qualifying#:#Achievement Test: %1$s (%2$s required)###29 07 2022 new variable +crs#:#crs_objective_result_details#:#⬅︎ Eredmények megjelenítése +crs#:#crs_objective_result_summary_initial#:#Belépő teszt: %1$s (%2$s kötelező) +crs#:#crs_objective_result_summary_qualifying#:#Elővizsga belépő teszt: %1$s (%2$s kötelező) crs#:#crs_objective_saved_sorting#:#Mentett csoportosítás. crs#:#crs_objective_self_assessment#:#Belépő teszt kérdései crs#:#crs_objective_status#:#Cél állapota crs#:#crs_objective_status_configure#:#Kurzus ellenőrzőlistája -crs#:#crs_objective_status_itest#:#Belépő teszt hozzárendelései -crs#:#crs_objective_status_materials#:#Kurzustartalom létrehozása -crs#:#crs_objective_status_materials_info#:#The course is currently empty. Add course materials that can be assigned to learning objectives.###26 08 2024 new variable +crs#:#crs_objective_status_itest#:#Belépő teszt beállítása +crs#:#crs_objective_status_materials#:#Kurzustartalom beállítása +crs#:#crs_objective_status_materials_info#:#A kurzus jelenleg még üres. Adjon hozzá a tanulási célokhoz rendelhető segédanyagokat. crs#:#crs_objective_status_objective_creation#:#Tanulási cél létrehozása crs#:#crs_objective_status_objectives#:#Tanulási célok beállítása -crs#:#crs_objective_status_qtest#:#Záró teszt hozzárendelései +crs#:#crs_objective_status_qtest#:#Záró teszt beállítása crs#:#crs_objective_status_settings#:#Kurzusbeállítások crs#:#crs_objective_tbl_col_final_tsts#:#Záró tesztek crs#:#crs_objective_wiz_final#:#Záró teszt kérdései @@ -7808,7 +7843,7 @@ crs#:#crs_print_list#:#Névsor létrehozása crs#:#crs_ref_delete_confirmation_info#:#Biztos, hogy eltávolítja az alábbi tagokat a kurzusból? Amennyiben ezeket a tagokat az ide linkelő forráskurzusból is el kívánja távolítani, pipálja be a megfelelő jelölőnégyzetet. crs#:#crs_ref_member_update#:#Új tagok felvétele crs#:#crs_ref_member_update_info#:#A szülőkurzus új tagját automatikusan hozzáadjuk tagként a forráskurzushoz is. -crs#:#crs_ref_missing_access#:#Ezt az lehetőséget nem lehet kiválasztani, mert nem rendelkezik mind a két kurzuhoz a 'Tagok kezelése' jogosultsággal. +crs#:#crs_ref_missing_access#:#Ezt az lehetőséget nem lehet kiválasztani, mert nem rendelkezik mind a két kurzuhoz a ‘Tagok kezelése’ jogosultsággal. crs#:#crs_ref_missing_parent_crs#:#Ezt az lehetőséget nem lehet kiválasztani, mert ennek a kurzuslinkek nem található a forráskurzusa. crs#:#crs_reg#:#Regisztrációs beállítások crs#:#crs_reg_code#:#Regisztráció linkkel @@ -7817,7 +7852,7 @@ crs#:#crs_reg_code_link#:#Link a közvetlen regisztrációhoz crs#:#crs_reg_max_info#:#Adja meg a kurzushoz rendelhető felhasználók maximális számát. crs#:#crs_reg_no_selfreg#:#Senki sem regisztrálhatja saját magát crs#:#crs_reg_password_info#:#A felhasználóknak a kurzushoz való csatlakozáskor ezt a jelszót kell majd begépelniük. -crs#:#crs_reg_selfreg#:#Self-Enrolment###26 08 2024 new variable +crs#:#crs_reg_selfreg#:#Önregisztráció crs#:#crs_reg_subject#:#Üzenet crs#:#crs_reg_until#:#Regisztrációs időszak crs#:#crs_reg_user_already_subscribed#:#Már adott le tagsági kérelmet ehhez a kurzushoz. @@ -7828,8 +7863,8 @@ crs#:#crs_registration_limited#:#Regisztrációs időszak időbeni korlátozása crs#:#crs_registration_limited_info#:#Csak egy meghatározott ideig lehet regisztrálni a kurzusra. crs#:#crs_registration_period#:#Regisztrációs időszak crs#:#crs_registration_type#:#Regisztráció módja -crs#:#crs_reject_subscriber#:#'%s' kurzushoz elutasított regisztráció -crs#:#crs_reject_subscriber_body#:#sajnálattal közöljük, hogy '%s' kurzusra jelentkezését elutasították. +crs#:#crs_reject_subscriber#:#‘%s’ kurzushoz elutasított regisztráció +crs#:#crs_reject_subscriber_body#:#sajnálattal közöljük, hogy ‘%s’ kurzusra jelentkezését elutasították. crs#:#crs_reset_results#:#Eredmények alapállapotba állítása crs#:#crs_role_status#:#Szerep/állapot crs#:#crs_search_users#:#Felhasználók keresése @@ -7840,9 +7875,9 @@ crs#:#crs_settings#:#Kurzusbeállítások crs#:#crs_settings_saved#:#A beállításokat sikeresen mentette. crs#:#crs_shorten_breadcrumb#:#Navigációs sor crs#:#crs_show_all_obj#:#Összes kibontása -crs#:#crs_show_member_export#:#Résztvevők listája +crs#:#crs_show_member_export#:#Névsor crs#:#crs_show_member_export_info#:#A kurzus tagjai kinyomtathatják a kurzustagok listáját. -crs#:#crs_show_member_export_settings#:#Résztvevők listája +crs#:#crs_show_member_export_settings#:#Névsor crs#:#crs_show_members#:#Tagok megjelenítése crs#:#crs_show_members_info#:#Kurzustagok megtekinthetik a tagok képtárát. crs#:#crs_size#:#Fájlméret @@ -7856,19 +7891,19 @@ crs#:#crs_starter_delete_sure#:#Biztos, hogy törli az alábbi kezdőobjektumoka crs#:#crs_starter_deleted#:#Hozzárendelés eltávolítva. crs#:#crs_starters_already_assigned#:#Ez az objektum már hozzá van rendelve. crs#:#crs_status#:#Állapot -crs#:#crs_status_changed#:#'%s' kurzusban állapotváltozás -crs#:#crs_status_changed_body#:#ezúton értesítjük, hogy '%s' kurzusban állapota megváltozott. -crs#:#crs_status_determination#:#'Sikeresen teljesítette' állapot meghatározása +crs#:#crs_status_changed#:#‘%s’ kurzusban állapotváltozás +crs#:#crs_status_changed_body#:#ezúton értesítjük, hogy ‘%s’ kurzusban állapota megváltozott. +crs#:#crs_status_determination#:#‘Sikeresen teljesítette’ állapot meghatározása crs#:#crs_status_determination_lp#:#Tanulási haladás alapján -crs#:#crs_status_determination_lp_info#:#Amikor a tanulási haladás 'Teljesített'-re vált, a kurzusállapot automatikusan 'Sikeresen teljesítette' lesz. Ettől függetlenül a tutorok kézzel is módosíthatják az állapotot. +crs#:#crs_status_determination_lp_info#:#Amikor a tanulási haladás ‘Teljesített’-re vált, a kurzusállapot automatikusan ‘Sikeresen teljesítette’ lesz. Ettől függetlenül a tutorok kézzel is módosíthatják az állapotot. crs#:#crs_status_determination_manual#:#Csak a tutorok manuálisan -crs#:#crs_status_determination_sync#:#A kurzusállapot értéke automatikusan 'Sikeresen teljesítette' lesz, amint a tanuló a tanulási haladását befolyásoló összes objektumot teljesítette. A beállítások módosítása előtti tanulási haladásokat figyelembe vesszük, a kézzel állított 'Sikeresen teljesítette' állapotok sem változnak. Biztos, hogy módosítja az összes tag kurzusállapotát a jelenlegi tanulási haladásai alapján? +crs#:#crs_status_determination_sync#:#A kurzusállapot értéke automatikusan ‘Sikeresen teljesítette’ lesz, amint a tanuló a tanulási haladását befolyásoló összes objektumot teljesítette. A beállítások módosítása előtti tanulási haladásokat figyelembe vesszük, a kézzel állított ‘Sikeresen teljesítette’ állapotok sem változnak. Biztos, hogy módosítja az összes tag kurzusállapotát a jelenlegi tanulási haladásai alapján? crs#:#crs_structure#:#Kurzusszerkezet crs#:#crs_subject_course_group_notification#:#Napi levél ehhez: %s -crs#:#crs_subscribe_member#:#'%s' kurzusra regisztráció -crs#:#crs_subscribe_member_body#:#ezúton értesítjük, hogy '%s' kurzusra sikeresen regisztrált. -crs#:#crs_subscribe_wl#:#'%s' kurzusra regisztráció -crs#:#crs_subscribe_wl_body#:#ezúton értesítjük, hogy '%s' kurzus várólistájára felkerült. Ön a(z) %s. a listán. A kurzusvezető üzenetet fog küldeni kérésének elfogadásáról vagy elutasításáról. +crs#:#crs_subscribe_member#:#‘%s’ kurzusra regisztráció +crs#:#crs_subscribe_member_body#:#ezúton értesítjük, hogy ‘%s’ kurzusra sikeresen regisztrált. +crs#:#crs_subscribe_wl#:#‘%s’ kurzusra regisztráció +crs#:#crs_subscribe_wl_body#:#ezúton értesítjük, hogy ‘%s’ kurzus várólistájára felkerült. Ön a(z) %s. a listán. A kurzusvezető üzenetet fog küldeni kérésének elfogadásáról vagy elutasításáról. crs#:#crs_subscriber#:#Csatlakozni kívánó crs#:#crs_subscribers_deleted#:#Törölt csatlakozni kívánó(k) crs#:#crs_subscription#:#Feliratkozás @@ -7878,7 +7913,7 @@ crs#:#crs_subscription_max_members_short#:#Tagok számának korlátozása crs#:#crs_subscription_max_members_short_info#:#A minimális, illetve a maximális taglétszám, továbbá várólista is beállítható. crs#:#crs_subscription_min_members#:#Minimális szám crs#:#crs_subscription_min_members_err#:#A résztvevők minimális száma nem lehet kisebb a résztvevők maximális számánál. -crs#:#crs_subscription_min_members_info#:#A kurzus indulásához szükséges minimális létszámot határozza meg. Amennyiben a kurzuslétszám nem éri el ezt a számot a kurzus regisztrációs, illetve lejelentkezési határidejéig, figyelmeztető levelet küldünk a kurzus azon vezetőinek és tutorainak, akinél aktív az értesítés a kurzus 'Tagok' fülén. +crs#:#crs_subscription_min_members_info#:#A kurzus indulásához szükséges minimális létszámot határozza meg. Amennyiben a kurzuslétszám nem éri el ezt a számot a kurzus regisztrációs, illetve lejelentkezési határidejéig, figyelmeztető levelet küldünk a kurzus azon vezetőinek és tutorainak, akinél aktív az értesítés a kurzus ‘Tagok’ lapján. crs#:#crs_subscription_options_confirmation#:#Tagság kérése crs#:#crs_subscription_options_direct#:#Csatlakozás közvetlenül crs#:#crs_subscription_options_password#:#Csatlakozás kurzusjelszóval @@ -7888,8 +7923,8 @@ crs#:#crs_syllabus#:#Kurzustematika crs#:#crs_sys_default#:#Alapértelmezett crs#:#crs_table_start_objects#:#Kezdőobjektumok crs#:#crs_target_group#:#Célcsoport -crs#:#crs_tile_and_objective_view_not_supported#:#A 'Csempe' módot és a 'Tanulásicél-orientált' megjelenítést egyszerre nem kapcsolhatja be. -crs#:#crs_tile_and_session_limit_not_supported#:#A 'Csempe' módot és 'A megjelenítendő események számának korlátozását' egyszerre nem kapcsolhatja be. +crs#:#crs_tile_and_objective_view_not_supported#:#A ‘Csempe’ módot és a ‘Tanulásicél-orientált’ megjelenítést egyszerre nem kapcsolhatja be. +crs#:#crs_tile_and_session_limit_not_supported#:#A ‘Csempe’ módot és ‘A megjelenítendő események számának korlátozását’ egyszerre nem kapcsolhatja be. crs#:#crs_timing_err_start_end#:#A záró dátum nem lehet korábbi, mint a nyitó dátum. crs#:#crs_timings_activate_optional#:#Kurzus időzítésének önkéntes módja crs#:#crs_timings_activate_optional_own#:#Kurzusom időzítésének önkéntes módja @@ -7909,7 +7944,7 @@ crs#:#crs_timings_not_changed#:#Az időzítés nem módosult crs#:#crs_timings_optional_checked#:#Az önkéntes módot bekapcsoltuk ennél a felhasználónál crs#:#crs_timings_optional_off#:#Az önkéntes mód nem aktív. crs#:#crs_timings_optional_on#:#Az önkéntes mód aktív. -crs#:#crs_timings_optional_on_and_passed#:#Az önkéntes mód aktív, nem módosítható, mert a felhasználó állapota 'Elmúlt'. +crs#:#crs_timings_optional_on_and_passed#:#Az önkéntes mód aktív, nem módosítható, mert a felhasználó állapota ‘Elmúlt’. crs#:#crs_timings_optional_unchecked#:#Az önkéntes módot kikapcsoltuk ennél a felhasználónál crs#:#crs_timings_planed_info#:#Tervezett tanulási idő crs#:#crs_timings_planed_start#:#Tervezett @@ -7938,11 +7973,11 @@ crs#:#crs_to#:#Meddig: crs#:#crs_tutor#:#Tutor crs#:#crs_tutors#:#Tutorok crs#:#crs_unblocked#:#Nincs korlátozva a belépés -crs#:#crs_unblocked_member#:#'%s' kurzushoz hozzáférés -crs#:#crs_unblocked_member_body#:#ezúton tájékoztatjuk, hogy '%s' kurzushozzáférésének blokkolását feloldották. +crs#:#crs_unblocked_member#:#‘%s’ kurzushoz hozzáférés +crs#:#crs_unblocked_member_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzushozzáférésének blokkolását feloldották. crs#:#crs_unlimited#:#Nem korlátozott -crs#:#crs_unsubscribe_member#:#'%s' kurzustagság törlése -crs#:#crs_unsubscribe_member_body#:#ezúton tájékoztatjuk, hogy '%s' kurzusról tagságát sikeresen töröltük. +crs#:#crs_unsubscribe_member#:#‘%s’ kurzustagság törlése +crs#:#crs_unsubscribe_member_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzusról tagságát sikeresen töröltük. crs#:#crs_unsubscribe_member_explanation#:#Azért kapta ezt a levelet, mert leiratkozott a fentebb említett kurzusról. crs#:#crs_unsubscribe_sure#:#Biztos, hogy lejelentkezik erről a kurzusról? crs#:#crs_unsubscribed_from_crs#:#Sikeresen lejelentkezett a kurzusról. @@ -7964,15 +7999,15 @@ crs#:#crs_view_timing#:#Időzítésnézet crs#:#crs_view_timing_absolute#:#Abszolút dátumok crs#:#crs_view_timing_relative#:#Relatív dátumok crs#:#crs_view_timings#:#Időzítés típusa -crs#:#crs_visibility#:#Visibility###26 08 2024 new variable +crs#:#crs_visibility#:#Láthatóság crs#:#crs_visibility_limitless#:#Korlátlan crs#:#crs_visibility_until#:#Elérhetőség időbeni korlátozása crs#:#crs_visibility_until_info#:#A kurzus egy meghatározott ideig marad látható tagjai számára. -crs#:#crs_visibility_unvisible#:#The course is not visible.###26 08 2024 new variable -crs#:#crs_wait_info#:#Ha be van kapcsolva, és a kurzushoz rendelhető maximális felhasználói létszám betelt, az új regisztrálók várólistára kerülnek be. +crs#:#crs_visibility_unvisible#:#A kurzus nem látható. +crs#:#crs_wait_info#:#Ha a kurzushoz rendelhető maximális felhasználói létszám betelt, az új regisztrálók várólistára kerülnek be. crs#:#crs_waiting_list#:#Várólista crs#:#crs_waiting_list_autofill#:#Automatikus feltöltéssel -crs#:#crs_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról tagság lemondásakor. Ez nem alkalmazható együtt a 'Tagság kérése' regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. +crs#:#crs_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról tagság lemondásakor. Ez nem alkalmazható együtt a ‘Tagság kérése’ regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. crs#:#crs_waiting_list_no_autofill#:#Automatikus feltöltés nélkül crs#:#crs_warn_no_max_set_on_waiting_list#:#A kurzus elérte a maximális kurzuslétszámát. Feliratkozhat a várólistára. A kurzusvezető üzenetet fog küldeni Önnek, ha kérését jóváhagyják vagy elutasítják. crs#:#crs_warn_wl_set_on_waiting_list#:#Van már néhány felhasználó a várólistán. Csatlakozási kérelmével Ön is feliratkozhat a várólistára. A kurzusvezető üzenetet fog küldeni Önnek, ha kérését jóváhagyják vagy elutasítják. @@ -8020,25 +8055,25 @@ crs#:#event_title#:#Cím crs#:#event_tutor_data#:#Előadó: crs#:#event_unregister#:#Lejelentkezés crs#:#event_unregistered#:#Sikeresen lejelentkezett az eseményről. -crs#:#event_updated#:#Beállítások mentése. +crs#:#event_updated#:#A beállításokat sikeresen mentette. crs#:#event_user_selection#:#Felhasználók kiválasztása -crs#:#event_user_selection_include_filter#:#'%1$s' is +crs#:#event_user_selection_include_filter#:#‘%1$s’ is crs#:#event_user_selection_include_requests#:#Csatlakozási kérelemmel rendelkezők is -crs#:#event_user_selection_include_role#:#'%1$s' szereppel rendelkezők is +crs#:#event_user_selection_include_role#:#‘%1$s’ szereppel rendelkezők is crs#:#event_user_selection_include_waiting_list#:#Várólistán lévők is crs#:#events#:#Események -crs#:#export_members#:#Résztvevők exportálása +crs#:#export_members#:#Résztvevők adatainak exportálása crs#:#grouping_change_assignment#:#Hozzárendelés változtatása crs#:#grp_grp_already_assigned#:#Már tagja ennek a csoportosításnak. -crs#:#grp_not_all_users_assigned_msg#:#%s user(s) assigned as group member(s), %s user(s) were already in the group.###26 08 2024 new variable +crs#:#grp_not_all_users_assigned_msg#:#%s felhasználót felvettünk a csoportba, %s felhasználó már tagja volt a csportnak. crs#:#mem_cron_min_members_intro#:#Ezúton értesítjük, hogy az alábbi kurzusok és csoportok esetén nincs meg a minimális taglétszám (még): -crs#:#mem_cron_min_members_reason#:#Ezt a levelet azért kapta, mert a tagok fülön beállította, hogy kér értesítést. +crs#:#mem_cron_min_members_reason#:#Ezt a levelet azért kapta, mert a tagok lapon beállította, hogy kér értesítést. crs#:#mem_cron_min_members_subject#:#Kurzus/Csoport: Minimális taglétszám ellenőrzése crs#:#mem_cron_min_members_task#:#Kérem, ha elegendő jelentkező hiányában a kurzus nem indul el, értesítse a résztvevőket és módosítsa a kurzus beállításait. -crs#:#obj_count_members#:#Number of members###26 08 2024 new variable +crs#:#obj_count_members#:#Tagok száma crs#:#sess_attendance_list#:#Jelenléti ív crs#:#sess_gen_attendance_list#:#Névsor létrehozása -crs#:#sess_join_info#:#Kattintson a 'Feljelentkezés' gombra, ha részt szeretne venni ezen az eseményen. +crs#:#sess_join_info#:#Kattintson a ‘Feljelentkezés’ gombra, ha részt szeretne venni ezen az eseményen. crs#:#sess_limit#:#A megjelenítendő események számának korlátozása crs#:#sess_limit_info#:#A résztvevők nem jelennek meg az összes, csak a korlátozott számú események felsorolásakor crs#:#sess_num_next#:#Jövőbeli események száma (holnapig) @@ -8061,7 +8096,7 @@ crs#:#timings_cron_reminder_started_subject#:#Megkezdődött a feldolgozási id crs#:#timings_edit#:#Időzítés beállítása crs#:#timings_of#:#Időzítésen kívül crs#:#timings_reminder_notifications#:#A kurzusértesítések időzítése -crs#:#timings_reminder_notifications_info#:#Ha be van kapcsolva, a kurzusrésztvevők értesítést kapnak a lejárú határidejű segédanyagokról. +crs#:#timings_reminder_notifications_info#:#A kurzusrésztvevők értesítést kapnak a lejárú határidejű segédanyagokról. crs#:#timings_timings#:#Időzítés crs#:#timings_timings_off#:#Időzítéskezelés kikapcsolása crs#:#timings_timings_on#:#Időzítéskezelés bekapcsolása @@ -8069,69 +8104,84 @@ crs#:#timings_usr_edit#:#Időzítés beállítása crs#:#tutor_email#:#E-mail cím crs#:#tutor_name#:#Név crs#:#tutor_phone#:#Telefon -crs#:#tutorial_support_block_byline#:#The 'Tutorial Support' block is displayed in the 'Contents' tab. The user selected as "Contact Person" in the "Members" Tab is shown.###28 10 2024 new variable -crs#:#tutorial_support_block_contact#:#Contact###28 10 2024 new variable -crs#:#tutorial_support_block_send_mail#:#send email###28 10 2024 new variable -crs#:#tutorial_support_block_setting_desc#:#The 'Tutorial Support' block is displayed in the 'Contents' tab.###28 10 2024 new variable -crs#:#tutorial_support_block_setting_title#:#Tutorial Support Block###28 10 2024 new variable -crs#:#tutorial_support_block_title#:#Contact Person###28 10 2024 new variable +crs#:#tutorial_support_block_byline#:#Az ‘Oktatóanyag támogatási blokk’ a ‘Tartalom’ lapon jelenik meg. A ‘Kapcsolattartó’ személye a ‘Tagok’ lapon jelenik meg. +crs#:#tutorial_support_block_contact#:#Kapcsolat +crs#:#tutorial_support_block_send_mail#:#e-mail küldése +crs#:#tutorial_support_block_setting_desc#:#Az ‘Oktatóanyag támogatási blokk’ a ‘Tartalom’ lapon jelenik meg. +crs#:#tutorial_support_block_setting_title#:#Oktatóanyag támogatási blokk +crs#:#tutorial_support_block_title#:#Kapcsolattartó crs#:#user_fields#:#Felhasználói mezők -crsv#:#crsv_create#:#Kurzusigazolás létrehozása -crsv#:#crsv_create_info#:#Válasszon egy teljesített kurzust, hogy igazolást generálhassunk hozzá +crsv#:#crsv_create#:#Kurzustanúsítvány létrehozása +crsv#:#crsv_create_info#:#Válasszon egy teljesített kurzust, hogy tanúsítványt generálhassunk hozzá +dash#:#add_to_favourites#:#Hozzáadás a Kedvencekhez +dash#:#added_to_favourites#:#az elemet sikeresen hozzáadta a kedvenceihez. dash#:#dash_activation#:#aktiválás dash#:#dash_added_to_favs#:#Az ajánlást sikeresen hozzáadta a kedvenceihez. dash#:#dash_avail_presentation#:#Elérhető megjelenítések dash#:#dash_avail_sortation#:#Elérhető rendezések dash#:#dash_click_here#:#Kattintson ide -dash#:#dash_co_delete#:#Delete Dashboard style###28 10 2024 new variable -dash#:#dash_co_lang#:#Dashboard style by languages###28 10 2024 new variable -dash#:#dash_customization#:#Customize Dashboard Content###28 10 2024 new variable +dash#:#dash_co_delete#:#Műszerfalstílus törlése +dash#:#dash_co_lang#:#Műszerfalstílus nyelvek szerint +dash#:#dash_customization#:#Műszerfal tartalmának személyre szabása +dash#:#dash_dash_fav_remove#:#Eltávolítás +dash#:#dash_dash_fav_remove_info#:#Biztos, hogy eltávolítja a következő objektumokat a Kedvencek közül? +dash#:#dash_dash_fav_remove_multiple#:#Több kedvenc eltávolítása +dash#:#dash_dash_ls_remove#:#Lejelentkezés +dash#:#dash_dash_ls_remove_info#:#Biztos, hogy lejelentkezik a következő tanulási sorról? +dash#:#dash_dash_ls_remove_multiple#:#Lejelentkezés több tanulási sorról +dash#:#dash_dash_mem_remove#:#Lejelentkezés +dash#:#dash_dash_mem_remove_info#:#Biztos, hogy lejelentkezik a következő kurzusokról és csoportokról? +dash#:#dash_dash_mem_remove_multiple#:#Lejelentkezés több kurzusról és csoportról +dash#:#dash_dash_rc_remove#:#Lejelentkezés +dash#:#dash_dash_rc_remove_info#:#Biztos, hogy eltávolítja a következő objektumokat az ajánlott tartalmak közül? +dash#:#dash_dash_rc_remove_multiple#:#Több tartalom eltávolítása dash#:#dash_dashboard#:#Műszerfal dash#:#dash_default_presentation#:#Alapértelmezett megjelenítése dash#:#dash_default_sortation#:#Alapértelmezett rendezés dash#:#dash_enable_cal#:#Naptár dash#:#dash_enable_favourites#:#Kedvenceim -dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable +dash#:#dash_enable_learning_sequences#:#Tanulási sorok dash#:#dash_enable_mail#:#Levelezés dash#:#dash_enable_memberships#:#Kurzusaim és csoportjaim dash#:#dash_enable_news#:#Hírek -dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable -dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable +dash#:#dash_enable_recommended_content#:#Ajánlott tartalom +dash#:#dash_enable_study_programmes#:#Képzési programok dash#:#dash_enable_task#:#Feladatok dash#:#dash_favourites#:#Kedvenceim -dash#:#dash_info_sure_remove_from_favs#:#Biztos, hogy eltávolítja a kiválasztott objektumokat a Kedvencei közül? dash#:#dash_item_removed#:#Az ajánlást sikeresen törölték a listáról. -dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable +dash#:#dash_learning_sequences#:#Tanulási soraim dash#:#dash_list#:#Felsorolás dash#:#dash_main_panel#:#Főpanel -dash#:#dash_make_favourite#:#Hozzáadás a Kedvenceimhez -dash#:#dash_manual_new_item_pos#:#Position of New Objects###29 10 2025 new variable -dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable -dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable -dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable -dash#:#dash_member_main_alt#:#A kurzusok és a csoportok szintén beállíthatóak, mint egy különálló főmenü-bejegyzés. +dash#:#dash_manual_new_item_pos#:#Új objektumok pozíciója +dash#:#dash_manual_new_item_pos_bot#:#Alul +dash#:#dash_manual_new_item_pos_top#:#Felül +dash#:#dash_manual_sorting_title#:#Kedvencek kézi rendezése +dash#:#dash_member_main_alt#:#A kurzusok és a csoportok szintén beállíthatók, mint egy különálló főmenü-bejegyzés. dash#:#dash_memberships#:#Kurzusaim és csoportjaim -dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable +dash#:#dash_no_items_to_manage#:#Nincs eltávolítható elem. +dash#:#dash_page_edit_info#:#Ennek a lapnak a tartalma az összes felhasználó műszefalán megjelenik. Lentenn látható a műszerfal különböző blokkjainak tartalma. dash#:#dash_presentation#:#Megjelenítés -dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable +dash#:#dash_recommended_content#:#Ajánlott tartalom dash#:#dash_remove_from_list#:#Eltávolítás a listáról dash#:#dash_side_panel#:#Oldalpanel -dash#:#dash_sort_by_alphabet#:#Sort by Alphabet###29 07 2022 new variable -dash#:#dash_sort_by_location#:#Hely alapján -dash#:#dash_sort_by_manually#:#Manually###29 10 2025 new variable -dash#:#dash_sort_by_start_date#:#Kezdődátum alapján -dash#:#dash_sort_by_type#:#Típus alapján -dash#:#dash_sort_option_bot#:#Bottom###29 10 2025 new variable -dash#:#dash_sort_option_top#:#Top###29 10 2025 new variable -dash#:#dash_sort_options#:#Postition of new Objects###29 10 2025 new variable +dash#:#dash_sort_by_alphabet#:#Betűrend +dash#:#dash_sort_by_location#:#Hely +dash#:#dash_sort_by_manually#:#Manuálisan +dash#:#dash_sort_by_start_date#:#Kezdődátum +dash#:#dash_sort_by_type#:#Típus +dash#:#dash_sort_option_bot#:#Alul +dash#:#dash_sort_option_top#:#Felül +dash#:#dash_sort_options#:#Új objektum pozíciója dash#:#dash_sortation#:#Rendezés -dash#:#dash_study_programmes#:#My Study Programmes###26 08 2024 new variable +dash#:#dash_study_programmes#:#Képzési programjaim dash#:#dash_tile#:#Csempe -dash#:#dash_view_courses_groups#:#'Kurzusaim és csoportjaim' rész -dash#:#dash_view_favourites#:#'Kedvenceim' rész -dash#:#favourites_disabled_info#:#Add to favorites is deactivated. You may change this inside the repository settings.###26 08 2024 new variable -dash#:#memberships_disabled_info#:#Subscriptions are deactivated. You may change this inside the course settings.###26 08 2024 new variable -dash#:#topitem_block#:#Block###26 08 2024 new variable +dash#:#dash_view_courses_groups#:#‘Kurzusaim és csoportjaim’ rész +dash#:#dash_view_favourites#:#‘Kedvenceim’ rész +dash#:#favourites_disabled_info#:#A kedvencekhez hozzáadás ki van kapcsolva. Ezen a Tartalomtár beállításainál módosíthat. +dash#:#memberships_disabled_info#:#A feliratkozás ki van kapcsolva. Ezen a kurzus beállításainál módosíthat. +dash#:#remove_from_favourites#:#Eltávolítás a kedvencek közül +dash#:#removed_from_favourites#:#Az elemet sikeresen eltávolította a kedvencek közül. +dash#:#topitem_block#:#Blokk dateplaner#:#Fr_long#:#Péntek dateplaner#:#Fr_short#:#P dateplaner#:#Mo_long#:#Hétfő @@ -8168,33 +8218,33 @@ dateplaner#:#cal_agenda#:#Napirend dateplaner#:#cal_all_day#:#Teljes nap dateplaner#:#cal_app_info#:#Találkozóinformáció dateplaner#:#cal_app_other_materials_num#:#További segédanyagok megjelenítése -dateplaner#:#cal_appointment_notifications#:#Notification###29 10 2025 new variable +dateplaner#:#cal_appointment_notifications#:#Értesítés dateplaner#:#cal_appointments#:#Esemény(ek) dateplaner#:#cal_apps#:#Események száma dateplaner#:#cal_assigned_appointments#:#Hozzárendelt események dateplaner#:#cal_back_to_cal#:#Vissza a naptárhoz dateplaner#:#cal_back_to_list#:#Vissza a listához dateplaner#:#cal_back_to_search#:#Vissza a kereséshez -dateplaner#:#cal_batch_file_downloads#:#Kötegelt fájl letöltése a naptárban -dateplaner#:#cal_batch_file_downloads_info#:#A jelenlegi naptár/találkozó nézetéhez kapcsolódó összes fájl letöltése -dateplaner#:#cal_belongs_to#:#Belongs to Calendar###29 10 2025 new variable +dateplaner#:#cal_batch_file_downloads#:#Naptárfájlok kötegelt letöltése +dateplaner#:#cal_batch_file_downloads_info#:#A jelenlegi naptár/találkozó nézetéhez kapcsolódó összes fájl letöltését lehetővé vevő gomb megjelenítése. +dateplaner#:#cal_belongs_to#:#Naptárhoz tartozik dateplaner#:#cal_book_free#:#foglalható dateplaner#:#cal_booked_out#:#betelt dateplaner#:#cal_booking_cancellation_body#:#ezúton tájékoztatjuk, hogy időpontfoglalását a következővel töröltük: %s. -dateplaner#:#cal_booking_cancellation_subject#:#'%s' találkozóról időpontfoglalás-törlés +dateplaner#:#cal_booking_cancellation_subject#:#‘%s’ találkozóról időpontfoglalás-törlés dateplaner#:#cal_booking_cancellation_user#:#Ennek az e-mailnek az eredeti példányát az alábbi felhasználónak küldtük el: dateplaner#:#cal_booking_confirmation_body#:#ezúton tájékoztatjuk, hogy időpontfoglalását a következővel rögzítettük: %s. dateplaner#:#cal_booking_confirmation_link#:#Link a találkozóra: -dateplaner#:#cal_booking_confirmation_subject#:#'%s' találkozóra időpontfoglalás +dateplaner#:#cal_booking_confirmation_subject#:#‘%s’ találkozóra időpontfoglalás dateplaner#:#cal_booking_confirmation_user#:#Ennek az e-mailnek az eredeti példányát az alábbi felhasználónak küldtük el: dateplaner#:#cal_booking_confirmed#:#Az eseményre sikeresen jelentkezett. dateplaner#:#cal_booking_failed_info#:#Az esemény betelt. Kérem, válasszon másikat. -dateplaner#:#cal_booking_manager_confirmation_body#:#%s has booked an appointment with %s.###29 10 2025 new variable -dateplaner#:#cal_booking_owner_confirmation_body#:#%s has booked an appointment with you.###29 10 2025 new variable +dateplaner#:#cal_booking_manager_confirmation_body#:#%s időpontot foglalt %s felhasználóval. +dateplaner#:#cal_booking_owner_confirmation_body#:#%s időpontot foglalt velem. dateplaner#:#cal_cache#:#Naptár gyorsítótárazása dateplaner#:#cal_cache_disabled#:#Letiltva dateplaner#:#cal_cache_enabled#:#Engedélyezett -dateplaner#:#cal_cache_info#:#Ha be van kapcsolva, a személyes és a Tartalomtárban a naptárbejegyzések megjelenítése csak x percenként frissül. +dateplaner#:#cal_cache_info#:#A személyes és a Tartalomtárban a naptárbejegyzések megjelenítése csak x percenként frissül. dateplaner#:#cal_cache_settings#:#Gyorsítótárazás dateplaner#:#cal_cal_deleted#:#A naptárat sikeresen törölte dateplaner#:#cal_cal_details#:#Naptár részletei @@ -8220,38 +8270,38 @@ dateplaner#:#cal_ch_app_grp#:#Konzultációs időpontcsoportok dateplaner#:#cal_ch_app_list#:#Konzultációs időpontok alkalmai dateplaner#:#cal_ch_assign_participants#:#Felhasználók hozzárendelése dateplaner#:#cal_ch_assigned_apps#:#Alkalmak száma -dateplaner#:#cal_ch_book#:#Eseményen résztvétel +dateplaner#:#cal_ch_book#:#Eseményen részvétel dateplaner#:#cal_ch_booking#:#Forrásfoglalás -dateplaner#:#cal_ch_booking_col_comments#:#Comments###28 10 2024 new variable -dateplaner#:#cal_ch_booking_comment#:#Comment:###28 10 2024 new variable -dateplaner#:#cal_ch_booking_link#:#Link to Consultation Hours:###28 10 2024 new variable +dateplaner#:#cal_ch_booking_col_comments#:#Megjegyzések +dateplaner#:#cal_ch_booking_comment#:#Megjegyzés: +dateplaner#:#cal_ch_booking_link#:#Fogadóóra linkje: dateplaner#:#cal_ch_booking_message_tbl#:#Megjegyzés -dateplaner#:#cal_ch_booking_num_available#:#Available Slots###28 10 2024 new variable -dateplaner#:#cal_ch_booking_num_free_short#:#%s free###28 10 2024 new variable -dateplaner#:#cal_ch_booking_other_participants#:#Other Participants:###28 10 2024 new variable +dateplaner#:#cal_ch_booking_num_available#:#Elérhető helyek +dateplaner#:#cal_ch_booking_num_free_short#:#%s szabad +dateplaner#:#cal_ch_booking_other_participants#:#További részvevők: dateplaner#:#cal_ch_booking_owner#:#Tulajdonos -dateplaner#:#cal_ch_booking_participants#:#Participants###28 10 2024 new variable -dateplaner#:#cal_ch_booking_reminder_body#:#ezúton értesítjük, hogy találkozója '%s' személlyel hamarosan kezdődik. -dateplaner#:#cal_ch_booking_reminder_subject#:#'%s' részére emlékeztető -dateplaner#:#cal_ch_booking_start#:#Start###28 10 2024 new variable -dateplaner#:#cal_ch_booking_your_comment#:#Your comment:###28 10 2024 new variable +dateplaner#:#cal_ch_booking_participants#:#Részvevők +dateplaner#:#cal_ch_booking_reminder_body#:#ezúton értesítjük, hogy találkozója ‘%s’ személlyel hamarosan kezdődik. +dateplaner#:#cal_ch_booking_reminder_subject#:#‘%s’ részére emlékeztető +dateplaner#:#cal_ch_booking_start#:#Indítás +dateplaner#:#cal_ch_booking_your_comment#:#Megjegyéseim: dateplaner#:#cal_ch_bookings#:#Résztvevők dateplaner#:#cal_ch_bookings_tbl#:#Foglalat események dateplaner#:#cal_ch_cancel_booking#:#Jelentkezés törlése -dateplaner#:#cal_ch_cancel_booking_info#:#A 'Foglalás lemondása' e-mailben értesíti a felhasználókat. Amennyiben szeretné, hogy a felhasználók ne kapjanak értesítést, használja a 'Foglalás törlése' lehetőséget. +dateplaner#:#cal_ch_cancel_booking_info#:#A ‘Foglalás lemondása’ e-mailben értesíti a felhasználókat. Amennyiben szeretné, hogy a felhasználók ne kapjanak értesítést, használja a ‘Foglalás törlése’ lehetőséget. dateplaner#:#cal_ch_cancel_booking_sure#:#Biztos, hogy lemondja a kiválasztott foglalásokat? dateplaner#:#cal_ch_canceled_bookings#:#A kiválasztott foglalásokat sikeresen lemondta. dateplaner#:#cal_ch_ch#:#Konzultációs időpontok dateplaner#:#cal_ch_cron_reminder#:#Emlékeztető küldése konzultációs időpontról dateplaner#:#cal_ch_cron_reminder_days#:#Napok száma -dateplaner#:#cal_ch_cron_reminder_info#:#Ha be van kapcsolva, a soron következő konzultációs időpontról értesítő levelet küldünk. -dateplaner#:#cal_ch_current_booking_comment#:#Comment###28 10 2024 new variable +dateplaner#:#cal_ch_cron_reminder_info#:#A soron következő konzultációs időpontról értesítő levelet küldünk. +dateplaner#:#cal_ch_current_booking_comment#:#Megjegyzés dateplaner#:#cal_ch_current_bookings#:#Jelenlegi résztvevők dateplaner#:#cal_ch_deadline#:#Legkésőbbi időpont dateplaner#:#cal_ch_deadline_info#:#Adja meg, amikortól az időpontfoglalás már nem lehetséges. dateplaner#:#cal_ch_delete_app_booking_info#:#Az alábbi eseményekhez van létező foglalás. A felhasználók nem kapnak értesítést, ha törli ezeket az eseményeket. dateplaner#:#cal_ch_delete_booking#:#Foglalás törlése -dateplaner#:#cal_ch_delete_booking_info#:#A 'Foglalás törlése' nem értesíti e-mailben a felhasználókat. Amennyiben szeretné, hogy a felhasználók értesítést kapjanak, használja a 'Foglalás lemondása' lehetőséget. +dateplaner#:#cal_ch_delete_booking_info#:#A ‘Foglalás törlése’ nem értesíti e-mailben a felhasználókat. Amennyiben szeretné, hogy a felhasználók értesítést kapjanak, használja a ‘Foglalás lemondása’ lehetőséget. dateplaner#:#cal_ch_delete_booking_sure#:#Biztos, hogy törli a kiválasztott foglalásokat? dateplaner#:#cal_ch_deleted_bookings#:#A kiválasztott foglalásokat sikeresen törölte. dateplaner#:#cal_ch_duration#:#Az egyes események időtartama @@ -8260,7 +8310,7 @@ dateplaner#:#cal_ch_field_ch#:#Konzultációs időpont események dateplaner#:#cal_ch_form#:#Konzultációs időpontok engedélyezése dateplaner#:#cal_ch_form_header#:#Konzultációs időpontok dateplaner#:#cal_ch_form_info#:#Ez a beállítás lehetővé teszi a személyes konzultációs időpontok kezelését a naptárban. -dateplaner#:#cal_ch_free_of_available#:#%s of %s###28 10 2024 new variable +dateplaner#:#cal_ch_free_of_available#:#%s / %s dateplaner#:#cal_ch_grp_add_tbl#:#Új konzultációs időpontcsoport létrehozása dateplaner#:#cal_ch_grp_delete_sure#:#Biztos, hogy törli az alábbi konzultációs időpontcsoportokat? dateplaner#:#cal_ch_grp_header#:#Konzultációs időpontcsoport @@ -8273,7 +8323,7 @@ dateplaner#:#cal_ch_grps#:#Konzultációs időpontcsoportok dateplaner#:#cal_ch_manager#:#Konzultációs időpontok kezelése dateplaner#:#cal_ch_manager_info#:#Annak a felhasználóneve, aki az Ön konzultációs időpontjait kezelheti. dateplaner#:#cal_ch_max_books#:#Felhasználónkénti foglalások -dateplaner#:#cal_ch_minutes#:#Duration (min)###28 10 2024 new variable +dateplaner#:#cal_ch_minutes#:#Hossz (perc) dateplaner#:#cal_ch_multi_edit_sequence#:#Konzultációi időpontok módosítása dateplaner#:#cal_ch_num_appointments#:#Események száma dateplaner#:#cal_ch_num_appointments_info#:#Adja meg a találkák számát. @@ -8281,46 +8331,46 @@ dateplaner#:#cal_ch_num_bookings#:#Foglalások száma dateplaner#:#cal_ch_personal_book#:#Személyes foglalások dateplaner#:#cal_ch_personal_ch#:#Személyes konzultációs időpontok dateplaner#:#cal_ch_reject_booking#:#Foglalás lemondása -dateplaner#:#cal_ch_send_mail#:#Send Mail###28 10 2024 new variable +dateplaner#:#cal_ch_send_mail#:#E-mail küldése dateplaner#:#cal_ch_target_object#:#Tartalomtárbeli objektum dateplaner#:#cal_ch_target_object_info#:#A konzultációs órák a kurzus-/csoporttartalom mellett jelenik meg. Csak bizonyos kurzusokra/csoportokra korlátozni a megjelenítést úgy lehet, hogy azok Ref-ID-it vesszővel elválasztva felsorolja. A Ref-ID-t a böngésző címsorából tudja kiolvasni. dateplaner#:#cal_ch_unknown_repository_object#:#Az adott Tartalomtárbeli objektum hivatkozási ID-je nem érvényes. dateplaner#:#cal_ch_unknown_user#:#Az adott felhasználónév nem létezik. dateplaner#:#cal_ch_user_assignment_failed_info#:#A kiválasztott eseményekhez az alábbi felhasználók hozzárendelése sikertelen, mert elérték a foglalások maximális számát. -dateplaner#:#cal_ch_vm_period_all#:#All###28 10 2024 new variable -dateplaner#:#cal_ch_vm_period_past#:#Past###28 10 2024 new variable -dateplaner#:#cal_ch_vm_period_upcoming#:#Upcoming###28 10 2024 new variable -dateplaner#:#cal_ch_vm_status_all#:#All###28 10 2024 new variable -dateplaner#:#cal_ch_vm_status_booked#:#Booked Slots###28 10 2024 new variable -dateplaner#:#cal_ch_vm_status_open#:#Open Slots###28 10 2024 new variable -dateplaner#:#cal_change_calendar_view#:#Change Calendar View###29 07 2022 new variable +dateplaner#:#cal_ch_vm_period_all#:#Összes +dateplaner#:#cal_ch_vm_period_past#:#Elmúlt +dateplaner#:#cal_ch_vm_period_upcoming#:#Közelgő +dateplaner#:#cal_ch_vm_status_all#:#Összes +dateplaner#:#cal_ch_vm_status_booked#:#Lefoglalt helyek +dateplaner#:#cal_ch_vm_status_open#:#Nyitott helyek +dateplaner#:#cal_change_calendar_view#:#Naptárnézet módosítása dateplaner#:#cal_change_responsible_users#:#Felelős felhasználók cseréje dateplaner#:#cal_changed_events_header#:#Új és megváltozott időpontok dateplaner#:#cal_confirm_booking#:#Jelentkezés megerősítése dateplaner#:#cal_confirm_booking_info#:#Erősítse meg jelentkezését erre az eseményre. dateplaner#:#cal_confirm_reg_info#:#Erősítse meg foglalását erre az eseményre! -dateplaner#:#cal_confirm_unreg_info#:#Erősítse meg résztvételének lemondását! +dateplaner#:#cal_confirm_unreg_info#:#Erősítse meg részvételének lemondását! dateplaner#:#cal_consultation_hours_for#:#Konzultációs időpontok: dateplaner#:#cal_consultation_hours_for_user#:#%1 konzultációs időpontjai dateplaner#:#cal_contained_in#:#Tartalmazza ebben: dateplaner#:#cal_create#:#Létrehozás dateplaner#:#cal_created_appointment#:#Új esemény létrehozása. -dateplaner#:#cal_created_milestone#:#Létrehozott mérföldkő -dateplaner#:#cal_created_milestone_resp_q#:#Létrehozott mérföldkő. Válassza ki a felhasználókat, akik felelősek a mérföldkő eléréséért. -dateplaner#:#cal_cronjob_remote_description#:#If activated, appointments of the calendar type "Web calendar" are automatically synchronised after the specified time interval.###26 08 2024 new variable -dateplaner#:#cal_cronjob_remote_title#:#External Calendar Synchronisation###26 08 2024 new variable +dateplaner#:#cal_created_milestone#:#A mérföldkővet sikeresen hozzáadta. +dateplaner#:#cal_created_milestone_resp_q#:#A mérföldkővet sikeresen hozzáadta. Válassza ki a felhasználókat, akik felelősek a mérföldkő eléréséért. +dateplaner#:#cal_cronjob_remote_description#:#Ha bekapcsolja, a ‘Webnaptár’ típusú naptárak eseményei automatikusan szinkronizálódnak a meghatározott időintervallum után. +dateplaner#:#cal_cronjob_remote_title#:#Külső naptár szinkornizálása dateplaner#:#cal_crs_info#:#Kurzusinformáció -dateplaner#:#cal_crs_new_notification_body#:#ezúton tájékoztatjuk, hogy '%s' kurzusban új esemény jött létre. -dateplaner#:#cal_crs_new_notification_sub#:#'%s' kurzusban új esemény -dateplaner#:#cal_crs_notification_body#:#ezúton tájékoztatjuk, hogy '%s' kurzusban egy esemény megváltozott. -dateplaner#:#cal_crs_notification_sub#:#'%s' kurzusban esemény módosult +dateplaner#:#cal_crs_new_notification_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzusban új esemény jött létre. +dateplaner#:#cal_crs_new_notification_sub#:#‘%s’ kurzusban új esemény +dateplaner#:#cal_crs_notification_body#:#ezúton tájékoztatjuk, hogy ‘%s’ kurzusban egy esemény megváltozott. +dateplaner#:#cal_crs_notification_sub#:#‘%s’ kurzusban esemény módosult dateplaner#:#cal_crs_timing_end#:#Javasolt befejezés dateplaner#:#cal_crs_timing_start#:#Javasolt kezdés dateplaner#:#cal_daily#:#Naponta -dateplaner#:#cal_date_and_time#:#Date and Time###29 10 2025 new variable +dateplaner#:#cal_date_and_time#:#Dátum és idő dateplaner#:#cal_date_booked#:#foglalt dateplaner#:#cal_date_format_info#:#Válasszon formátumot a dátum beviteléhez. -dateplaner#:#cal_date_time_title#:#Date and Time###29 10 2025 new variable +dateplaner#:#cal_date_time_title#:#Dátum és idő dateplaner#:#cal_day_end#:#Záró időpont dateplaner#:#cal_day_of_month#:#A hónap napja dateplaner#:#cal_day_overview#:#Napi áttekintés @@ -8346,9 +8396,9 @@ dateplaner#:#cal_default_settings#:#Alapértelmezett beállítások dateplaner#:#cal_del_app_sure#:#Biztos, hogy törli a kiválasztott időponto(ka)t? dateplaner#:#cal_del_cal_sure#:#Biztos, hogy törli a kiválasztott naptára(ka)t? dateplaner#:#cal_delete_app_sure#:#Biztos, hogy törli az alábbi időponto(ka)t? -dateplaner#:#cal_delete_booking_info#:#Please confirm the deletion of this booking###28 10 2024 new variable +dateplaner#:#cal_delete_booking_info#:#Kérem, erősítse meg ennek a foglalásnak a törlését. dateplaner#:#cal_delete_cal#:#Naptár törlése -dateplaner#:#cal_delete_recurrence_rule#:#Delete Series of Appoinments###29 07 2022 new variable +dateplaner#:#cal_delete_recurrence_rule#:#Elfoglaltságsorozat törlése dateplaner#:#cal_delete_recurrences#:#Ismétlődések törlése dateplaner#:#cal_delete_single#:#Csak ennek az eseménynek a törlése dateplaner#:#cal_deleted_app#:#A kiválasztott időponto(ka)t sikeresen törölte. @@ -8359,14 +8409,14 @@ dateplaner#:#cal_download_files#:#Fájlok letöltése dateplaner#:#cal_download_files_started#:#Az ILIAS az összes elérhető fájlból archívumot készít. Ezeket az archívumokat az Éresítési Központból (felső sorban lévő harang ikon) töltheti le. dateplaner#:#cal_dstart_dend_warn#:#Ellenőrizze az adatokat! A kezdő dátum a záró dátuma előtt kell legyen. dateplaner#:#cal_duration#:#Időtartam -dateplaner#:#cal_duration_end#:#End###29 10 2025 new variable -dateplaner#:#cal_duration_start#:#Start###29 10 2025 new variable +dateplaner#:#cal_duration_end#:#Vége +dateplaner#:#cal_duration_start#:#Eleje dateplaner#:#cal_edit_appointment#:#Esemény módosítása dateplaner#:#cal_edit_category#:#Naptár módosítása dateplaner#:#cal_edit_milestone#:#Mérföldkő módosítása dateplaner#:#cal_edit_recurrences#:#Összes esemény módosítása dateplaner#:#cal_edit_single#:#Esemény módosítása -dateplaner#:#cal_edit_single_or_all_info#:#Do you want to edit only this appointment or all in its series?###26 08 2024 new variable +dateplaner#:#cal_edit_single_or_all_info#:#Csak ezt az egy eseményt vagy az összeset módosítja? dateplaner#:#cal_enable_group_milestones#:#Mérföldkövek engedélyezése dateplaner#:#cal_enable_group_milestones_desc#:#Ez a beállítás engedélyezi a mérföldkőtervezést a naptárban. dateplaner#:#cal_err_invalid_notification_rcps#:#Az értesítés címzettjeinek listája nem érvényes. Csak ILIAS felhasználóneveket vagy érvényes e-mail címet válasszon! @@ -8378,7 +8428,7 @@ dateplaner#:#cal_exc_open#:#Találkozó megnyitása dateplaner#:#cal_exc_peer_review_deadline#:#Visszajelzés határideje dateplaner#:#cal_export_timezone#:#Időzóna a naptár exportáláshoz dateplaner#:#cal_export_timezone_tz#:#ILIAS-időzóna használata -dateplaner#:#cal_export_timezone_utc#:#UTC időzóna használata (MS Outlook kompatibilitáshoz) +dateplaner#:#cal_export_timezone_utc#:#UTC-időzóna használata (MS Outlook kompatibilitáshoz) dateplaner#:#cal_fifth#:#Ötödik dateplaner#:#cal_first#:#Első dateplaner#:#cal_fourth#:#Negyedik @@ -8389,25 +8439,25 @@ dateplaner#:#cal_grp_curr_crs#:#Jelenlegi kurzus dateplaner#:#cal_grp_curr_crs_cons#:#Konzultációs időpontok dateplaner#:#cal_grp_curr_grp#:#Jelenlegi csoport dateplaner#:#cal_grp_info#:#Csoportinformáció -dateplaner#:#cal_grp_new_notification_body#:#ezúton tájékoztatjuk, hogy '%s' csoportban új esemény jött létre. -dateplaner#:#cal_grp_new_notification_sub#:#'%s' csoportban új esemény -dateplaner#:#cal_grp_notification_body#:#ezúton tájékoztatjuk, hogy '%s' csoportban egy esemény megváltozott. -dateplaner#:#cal_grp_notification_sub#:#'%s' csoportban esemény módosult +dateplaner#:#cal_grp_new_notification_body#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportban új esemény jött létre. +dateplaner#:#cal_grp_new_notification_sub#:#‘%s’ csoportban új esemény +dateplaner#:#cal_grp_notification_body#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportban egy esemény megváltozott. +dateplaner#:#cal_grp_notification_sub#:#‘%s’ csoportban esemény módosult dateplaner#:#cal_grp_others#:#További dateplaner#:#cal_grp_personal#:#Személyes dateplaner#:#cal_ical_infoscreen#:#Feliratkozás dateplaner#:#cal_ical_url#:#iCal-URL -dateplaner#:#cal_ical_url_google#:#iCal-URL for Google Calendar###26 08 2024 new variable +dateplaner#:#cal_ical_url_google#:#Google Naptárra mutató iCal-URL dateplaner#:#cal_import_appointments#:#Események importja dateplaner#:#cal_import_file#:#Fájl importja dateplaner#:#cal_import_file_info#:#Válassza ki a naptárjának eseményeit tartalmazó fájlt. dateplaner#:#cal_import_tbl#:#Események importja dateplaner#:#cal_imported_success#:#Importált %1$s esemény. -dateplaner#:#cal_in#:#in +dateplaner#:#cal_in#:#> dateplaner#:#cal_last#:#Utoljára dateplaner#:#cal_list#:#Lista dateplaner#:#cal_mail_notification_body#:#ezúton értesítjük, hogy Ön meghívót kapott egy eseményre. -dateplaner#:#cal_mail_notification_subject#:#Eseményre meghívás: '%s' +dateplaner#:#cal_mail_notification_subject#:#Eseményre meghívás: ‘%s’ dateplaner#:#cal_manage#:#Naptár dateplaner#:#cal_materials#:#Segédanyagok dateplaner#:#cal_milestone_settings#:#Mérföldkövek @@ -8415,43 +8465,43 @@ dateplaner#:#cal_month_overview#:#Havi áttekintés dateplaner#:#cal_month_s#:#Hónap dateplaner#:#cal_month_selection#:#Hónap kiválasztása dateplaner#:#cal_monthly#:#Havonta -dateplaner#:#cal_monthly_by_date#:#Monthly by Date###29 10 2025 new variable -dateplaner#:#cal_monthly_by_day#:#Monthly by Day###29 10 2025 new variable +dateplaner#:#cal_monthly_by_date#:#Havonta dátum szerint +dateplaner#:#cal_monthly_by_day#:#Havonta nap szerint dateplaner#:#cal_ms_details#:#Mérföldkőrészletek dateplaner#:#cal_ms_users_responsible#:#Felelős felhasználók dateplaner#:#cal_new_app#:#Új esemény dateplaner#:#cal_new_ms#:#Új mérföldkő dateplaner#:#cal_no_ending#:#Nincs záró dátum -dateplaner#:#cal_no_events_block#:#Nincsenek elérhető dátumai.###Egy eseménye sincs. +dateplaner#:#cal_no_events_block#:#Egy elérhető dátum sincs. dateplaner#:#cal_no_events_info#:#Egy esemény sem található a megjelölt időszakban. dateplaner#:#cal_no_recurrence#:#Nincsenek ismétlődések dateplaner#:#cal_notification#:#E-mail értesítés dateplaner#:#cal_notification_crsgrp#:#Értesítés kurzus-/csoportrésztvevőknek -dateplaner#:#cal_notification_info#:#Ha be van kapcsolva, minden kurzus-/csoporttagnak e-mail értesítést küldünk erről az eseményről. +dateplaner#:#cal_notification_info#:#Minden kurzus-/csoporttagnak e-mail értesítést küldünk erről az eseményről. dateplaner#:#cal_notification_users#:#Értesítés kiválasztott felhasználóknak dateplaner#:#cal_on#:#Ekkor: dateplaner#:#cal_on_the#:#Ekkor: dateplaner#:#cal_open_calendar#:#Naptár megnyitása dateplaner#:#cal_origin#:#Származás dateplaner#:#cal_owner#:#Tulajdonos -dateplaner#:#cal_period#:#Period###26 08 2024 new variable -dateplaner#:#cal_rec_err_limit#:#Érvényes esemény számot adjon meg! -dateplaner#:#cal_recurrence_confirm_deletion#:#Please decide wether you want to delete single appointments or the complete series of appointments.###29 07 2022 new variable -dateplaner#:#cal_recurrence_count#:#Number of Appointments###29 10 2025 new variable -dateplaner#:#cal_recurrence_day_interval#:#Every x Day(s)###29 10 2025 new variable -dateplaner#:#cal_recurrence_end_date#:#End Date###29 10 2025 new variable -dateplaner#:#cal_recurrence_end_date_info#:#Last possible date for an appointment.###29 10 2025 new variable -dateplaner#:#cal_recurrence_month_interval#:#Every x Month(s)###29 10 2025 new variable -dateplaner#:#cal_recurrence_until#:#Recurrence End###29 10 2025 new variable -dateplaner#:#cal_recurrence_until_count#:#Fixed Number of Appointments###29 10 2025 new variable -dateplaner#:#cal_recurrence_until_end_date#:#Repeat Until End Date###29 10 2025 new variable -dateplaner#:#cal_recurrence_week_interval#:#Every x Week(s)###29 10 2025 new variable -dateplaner#:#cal_recurrence_year_interval#:#Every x Year(s)###29 10 2025 new variable +dateplaner#:#cal_period#:#Időszak +dateplaner#:#cal_rec_err_limit#:#Érvényes eseményszámot adjon meg! +dateplaner#:#cal_recurrence_confirm_deletion#:#Kérem, válasszon, hogy egy foglaltságot vagy egy teljes foglaltságsorozatot töröl. +dateplaner#:#cal_recurrence_count#:#Foglalások száma +dateplaner#:#cal_recurrence_day_interval#:#Minden x. nap +dateplaner#:#cal_recurrence_end_date#:#Záró dátum +dateplaner#:#cal_recurrence_end_date_info#:#Foglalás utolsó lehetséges napja +dateplaner#:#cal_recurrence_month_interval#:#Minden x. hónap +dateplaner#:#cal_recurrence_until#:#Ismétlődés vége +dateplaner#:#cal_recurrence_until_count#:#Adott számú foglalás +dateplaner#:#cal_recurrence_until_end_date#:#Ismétlődés a záró dátumig +dateplaner#:#cal_recurrence_week_interval#:#Minden x. hét +dateplaner#:#cal_recurrence_year_interval#:#Minden x. év dateplaner#:#cal_recurrences#:#Ismétlődés -dateplaner#:#cal_reg_register#:#Résztvétel +dateplaner#:#cal_reg_register#:#Részvétel dateplaner#:#cal_reg_registered#:#Ön regisztrált. dateplaner#:#cal_reg_registered_users#:#Résztvevők -dateplaner#:#cal_reg_unregister#:#Résztvétel lemondása +dateplaner#:#cal_reg_unregister#:#Részvétel lemondása dateplaner#:#cal_reg_unregistered#:#Ön még nem regisztrált. dateplaner#:#cal_registrations#:#Esemény regisztrációi dateplaner#:#cal_remote_url#:#URL @@ -8460,18 +8510,18 @@ dateplaner#:#cal_repo_obj#:#Objektumok dateplaner#:#cal_responsible#:#Felelős dateplaner#:#cal_save_responsible_users#:#Felelős felhasználók mentése dateplaner#:#cal_search#:#Keresőkifejezés -dateplaner#:#cal_search_info_share#:#Adja meg a kívánt felhasználó/szerep nevét a naptár megosztásához. +dateplaner#:#cal_search_info_share#:#Adja meg a kívánt felhasználó/szerepkör nevét a naptár megosztásához. dateplaner#:#cal_second#:#Második dateplaner#:#cal_server_tz#:#Szerver időzónája dateplaner#:#cal_sess_info#:#Munkamenetinformáció dateplaner#:#cal_setting_global_crs_act#:#Bekapcsolás kurzusokban -dateplaner#:#cal_setting_global_crs_act_info#:#Ha be van kapcsolva, a naptár alapértelmezetten aktív a kurzusokban. A naptár bármikor ki-/bekapcsolható a kurzusbeállításokban. +dateplaner#:#cal_setting_global_crs_act_info#:#A naptár alapértelmezetten aktív a kurzusokban. A naptár bármikor ki-/bekapcsolható a kurzusbeállításokban. dateplaner#:#cal_setting_global_crs_vis#:#Kurzusokban megjelenjen -dateplaner#:#cal_setting_global_crs_vis_info#:#Ha be van kapcsolva, a naptár alapértelmezetten megjelenik a kurzusokban. A megjelenítése bármikor ki-/bekapcsolható a kurzusbeállításokban. +dateplaner#:#cal_setting_global_crs_vis_info#:#A naptár alapértelmezetten megjelenik a kurzusokban. A megjelenítése bármikor ki-/bekapcsolható a kurzusbeállításokban. dateplaner#:#cal_setting_global_grp_act#:#Bekapcsolás csoportokban -dateplaner#:#cal_setting_global_grp_act_info#:#Ha be van kapcsolva, a naptár alapértelmezetten aktív a csoportokban. A naptár bármikor ki-/bekapcsolható a csoportbeállításokban. +dateplaner#:#cal_setting_global_grp_act_info#:#A naptár alapértelmezetten aktív a csoportokban. A naptár bármikor ki-/bekapcsolható a csoportbeállításokban. dateplaner#:#cal_setting_global_grp_vis#:#Csoportokban megjelenjen -dateplaner#:#cal_setting_global_grp_vis_info#:#Ha be van kapcsolva, a naptár alapértelmezetten megjelenik a csoportokban. A megjelenítése bármikor ki-/bekapcsolható a csoportbeállításokban. +dateplaner#:#cal_setting_global_grp_vis_info#:#A naptár alapértelmezetten megjelenik a csoportokban. A megjelenítése bármikor ki-/bekapcsolható a csoportbeállításokban. dateplaner#:#cal_setting_global_vis_repos#:#Tartalomtárbeli naptár dateplaner#:#cal_share#:#Naptár megosztása dateplaner#:#cal_share_accept#:#Elfogadott meghívások @@ -8486,7 +8536,7 @@ dateplaner#:#cal_shared_access_read_write#:#Olvasásható és írásható dateplaner#:#cal_shared_access_table_col#:#Hozzáférés dateplaner#:#cal_shared_calendars#:#Megosztott naptárak (meghívások) dateplaner#:#cal_shared_header#:#Megosztott naptárak -dateplaner#:#cal_shared_selected_usr#:#A naptárt megosztotta a kiválasztott felhasználókkal/szerepekkel. +dateplaner#:#cal_shared_selected_usr#:#A naptárt megosztotta a kiválasztott felhasználókkal/szerepkörökkel. dateplaner#:#cal_show_weeks#:#Hetek megjelenítése dateplaner#:#cal_show_weeks_info#:#A hetek oszlopot bekapcsolja az oldalblokk naptárában. dateplaner#:#cal_start#:#Kezdő időpont @@ -8495,7 +8545,7 @@ dateplaner#:#cal_subscription_header#:#Naptár címe: dateplaner#:#cal_subscription_info#:#Használja az alábbi címet, hogy más alkalmazásokból is elérje naptárját. Bármely naptár-termékbe másolhatja és beillesztheti, amely támogatja az ical-formátumot. dateplaner#:#cal_subscription_url#:#Naptár URL-je dateplaner#:#cal_sync_cache#:#Naptár gyorsítótárazása -dateplaner#:#cal_sync_cache_info#:#Ha be van kapcsolva, az új/módosított naptárbejegyzések csak x percenként frissülnek. +dateplaner#:#cal_sync_cache_info#:#Az új/módosított naptárbejegyzések csak x percenként frissülnek. dateplaner#:#cal_sync_disabled#:#Letiltva dateplaner#:#cal_sync_enabled#:#Engedélyezve dateplaner#:#cal_table_categories#:#Naptár kiválasztása @@ -8506,14 +8556,14 @@ dateplaner#:#cal_timezone_info#:#Válassza ki a legközelebbi várost az időzó dateplaner#:#cal_type_crs#:#Kurzusnaptár dateplaner#:#cal_type_exc#:#Beadandó feladat naptára dateplaner#:#cal_type_grp#:#Csoportnaptár -dateplaner#:#cal_type_info#:#Válasszon egy naptártípust. A 'Nyilvános naptár' minden ILIAS-felhasználó számára látható. +dateplaner#:#cal_type_info#:#Válasszon egy naptártípust. A ‘Nyilvános naptár’ minden ILIAS-felhasználó számára látható. dateplaner#:#cal_type_local#:#Helyi naptár dateplaner#:#cal_type_personal#:#Privát naptár dateplaner#:#cal_type_remote#:#Webes naptár dateplaner#:#cal_type_rl#:#Naptár helye dateplaner#:#cal_type_sess#:#Eseménynaptár dateplaner#:#cal_type_system#:#Nyilvános naptár -dateplaner#:#cal_type_tals#:#Talks###26 08 2024 new variable +dateplaner#:#cal_type_tals#:#Megbeszélések dateplaner#:#cal_unshare#:#Megosztás törlése dateplaner#:#cal_unshare_cal#:#Megosztás megállítása dateplaner#:#cal_unshared_selected_usr#:#Naptármegosztás befejezése a kiválasztott felhasználókkal. @@ -8524,11 +8574,11 @@ dateplaner#:#cal_user_notification_info#:#A megadott felhasználóknak e-mail é dateplaner#:#cal_user_settings#:#Naptárbeállítások dateplaner#:#cal_user_time_format#:#Időformátum dateplaner#:#cal_user_timezone#:#ILIAS-időzóna -dateplaner#:#cal_usr_info#:#Kinevezési információk +dateplaner#:#cal_usr_info#:#Találkozó információi dateplaner#:#cal_usr_show_weeks#:#Hetek oszlop megjelenítése dateplaner#:#cal_usr_show_weeks_info#:#Az oldalsó naptár blokkban aktiválja a hetek oszlopot. dateplaner#:#cal_webcal_sync#:#Külső naptár szinkronizációja -dateplaner#:#cal_webcal_sync_info#:#Automatikus szinkronizáció külső naptárakkal x percenként. +dateplaner#:#cal_webcal_sync_info#:#Automatikus szinkronizáció külső naptárakkal x óránként. dateplaner#:#cal_week_abbrev#:#H dateplaner#:#cal_week_month_view#:#Heti/havi nézet beállításai dateplaner#:#cal_week_overview#:#Heti áttekintés @@ -8540,16 +8590,16 @@ dateplaner#:#cal_weekly#:#Hetente dateplaner#:#cal_where#:#Hely dateplaner#:#cal_year_s#:#Év dateplaner#:#cal_yearly#:#Évente -dateplaner#:#cal_yearly_by_date#:#Yearly by Date###29 10 2025 new variable -dateplaner#:#cal_yearly_by_day#:#Yearly by Day###29 10 2025 new variable -dateplaner#:#consultation_hours_block_title#:#Consultation Hours###26 08 2024 new variable +dateplaner#:#cal_yearly_by_date#:#Évente dátum szerint +dateplaner#:#cal_yearly_by_day#:#Évente nap szerint +dateplaner#:#consultation_hours_block_title#:#Fogadóórák dateplaner#:#crs_cal_activation_end#:#Kurzus láthatóságának vége dateplaner#:#crs_cal_activation_start#:#Kurzus láthatóságának kezdete dateplaner#:#crs_cal_end#:#Kurzus záró időpontja dateplaner#:#crs_cal_reg_end#:#Regisztráció vége dateplaner#:#crs_cal_reg_start#:#Regisztráció kezdete dateplaner#:#crs_cal_start#:#Kurzus kezdő időpontja -dateplaner#:#date_format#:#m/d/Y H:i +dateplaner#:#date_format#:#Y.m.d H:i dateplaner#:#end_date#:#Záró idő dateplaner#:#err_end_before_start#:#Az esemény nem kezdődhet a befejezése után. dateplaner#:#err_missing_title#:#Adjon az eseménynek címet! @@ -8577,19 +8627,19 @@ dcl#:#dcl_add_new_field#:#Új mező létrehozása dcl#:#dcl_add_new_record#:#Új bejegyzés létrehozása dcl#:#dcl_add_new_table#:#Új tábla létrehozása dcl#:#dcl_add_new_view#:#Új nézet létrehozása -dcl#:#dcl_add_perm#:#A felhasználó felvehet rekordokat -dcl#:#dcl_add_perm_desc#:#A felhasználók bejegyzéseket hozhatnak létre ebben a táblázatban. +dcl#:#dcl_add_perm#:#Rekord felvétele +dcl#:#dcl_add_perm_desc#:#A felhasználók bejegyzéseket hozhatnak létre ebben a táblázatban. Ha az adatok importálása ebbe a táblázatba engedélyezett, akkor egy Excel importálási funkció is elérhető lesz. dcl#:#dcl_all_entries#:#Összes bejegyzés dcl#:#dcl_any#:#Bármi -dcl#:#dcl_asc#:#Növekvő sorrend (NÖV) -dcl#:#dcl_boolean#:#Logikai -dcl#:#dcl_boolean_desc#:#'Kipipált'/'Nem kipipált' jelölőnégyzet. +dcl#:#dcl_asc#:#Növekvő sorrend (↑) +dcl#:#dcl_boolean#:#Jelölőnégyzet +dcl#:#dcl_boolean_desc#:#‘Kipipált’/‘Nem kipipált’ jelölőnégyzet. dcl#:#dcl_cant_delete_last_table#:#Nem távolíthatja el teljes egészében ezt a táblát, mert ez az adatgyűjtéshez egyetlen táblája. Tartalmát és szerkezetét viszont töröltük. dcl#:#dcl_change_notification_dcl_delete_record#:#ezúton tájékoztatjuk, hogy az alábbi bejegyzést törölték dcl#:#dcl_change_notification_dcl_new_record#:#ezúton tájékoztatjuk, hogy az alábbi bejegyzés jött létre dcl#:#dcl_change_notification_dcl_update_record#:#ezúton tájékoztatjuk, hogy az alábbi bejegyzés megváltozott dcl#:#dcl_change_notification_link#:#URL -dcl#:#dcl_change_notification_subject#:#'%s' adatgyűjtés megváltozott +dcl#:#dcl_change_notification_subject#:#‘%s’ adatgyűjtés megváltozott dcl#:#dcl_changed_by#:#Módosította dcl#:#dcl_checked#:#Kipipált dcl#:#dcl_comments#:#Megjegyzések @@ -8597,70 +8647,66 @@ dcl#:#dcl_comments_desc#:#Megjegyzések számának megjelenítése a bejegyzésh dcl#:#dcl_confirm_delete_field#:#Biztos, hogy törli ezt a mezőt? dcl#:#dcl_confirm_delete_fields#:#Biztos, hogy törli ezeket a mezőket? dcl#:#dcl_confirm_delete_record#:#Biztos, hogy törli ezt a bejegyzést? -dcl#:#dcl_confirm_delete_records#:#Biztos, hogy törli az alábbi bejegyzéseket? +dcl#:#dcl_confirm_delete_records#:#Biztos, hogy törli az alábbi bejegyzéseket?### dcl#:#dcl_confirm_delete_table#:#Biztos, hogy törli a táblát annak tartalmával és szerkezetével? dcl#:#dcl_confirm_storing_records#:#Kérem, ellenőrizze és hagyja jóvá beírt adatát. dcl#:#dcl_confirm_storing_records_no_permission#:#Nincs jogosultsága a bejegyzést utólag módosítani. dcl#:#dcl_copy#:#Adatgyűjtés másolása -dcl#:#dcl_copy_field#:#Copy###29 10 2025 new variable -dcl#:#dcl_copy_field_desc#:#Field to copy options stored in a different field of a table.###29 10 2025 new variable -dcl#:#dcl_copy_title#:#Copy of table and field###29 10 2025 new variable +dcl#:#dcl_copy_field#:#Másolás +dcl#:#dcl_copy_field_desc#:#Mező a táblázat másik mezőjében tárolt lehetőségek másolásához. +dcl#:#dcl_copy_title#:#Tábla és mezők másolata dcl#:#dcl_create_date#:#Létrehozás dátuma -dcl#:#dcl_create_entry_rules#:#Létrehozás +dcl#:#dcl_create_entry_rules#:#Bejegyzés létrehozása dcl#:#dcl_create_field#:#Mező létrehozása -dcl#:#dcl_create_fields#:#Kattintson egy táblára a 'Táblák' fül alatt, majd hozzon létre mezőket az 'Új mező létrehozása' gombbal. +dcl#:#dcl_create_fields#:#Kattintson egy táblára a ‘Táblák’ lap alatt, majd hozzon létre mezőket az ‘Új mező létrehozása’ gombbal. dcl#:#dcl_creation_date#:#Létrehozás dátuma dcl#:#dcl_creation_date_description#:#A bejegyzés létrehozásának dátuma. dcl#:#dcl_datatype#:#Adattípus -dcl#:#dcl_date#:#Date Entry###29 10 2025 new variable -dcl#:#dcl_date_desc#:#Users can enter a date of their choice or select one using a calendar.###29 10 2025 new variable +dcl#:#dcl_date#:#Dátum +dcl#:#dcl_date_desc#:#Dátum beviteli mező. dcl#:#dcl_date_selection#:#Dátumválasztó dcl#:#dcl_date_selection_desc#:#Dátumlehetőségek választásának felkínálása. dcl#:#dcl_datetime#:#Dátum dcl#:#dcl_datetime_desc#:#Dátum beviteli mező. -dcl#:#dcl_datetime_selection#:#Datetime Selection###29 10 2025 new variable -dcl#:#dcl_datetime_selection_desc#:#Allow a date and time to be chosen from among a predefined selection of datetime options.###29 10 2025 new variable -dcl#:#dcl_deactivate_view#:#Nézet kikapcsolása +dcl#:#dcl_datetime_selection#:#Dátum/idő választó +dcl#:#dcl_datetime_selection_desc#:#Lehetővé teszi a dátum és az időpont kiválasztását az előre meghatározott dátum/idő lehetőségek közül. dcl#:#dcl_default_sort_field#:#Alapértelmezett rendezési mező dcl#:#dcl_default_sort_field_order#:#Alapértelmezett rendezési irány -dcl#:#dcl_default_sort_field_order_desc#:#Arrange the order of the entries in the table based on this field.###29 10 2025 new variable +dcl#:#dcl_default_sort_field_order_desc#:#A táblázatot alapértelmezetten ezen mező alapján rendezzük. dcl#:#dcl_delete_fields#:#Mezők törlése -dcl#:#dcl_delete_fields_no_selection#:#Please select at least one field to delete###26 08 2024 new variable +dcl#:#dcl_delete_fields_no_selection#:#Legalább egy törlendő mezőt válasszon ki dcl#:#dcl_delete_perm#:#A felhasználó törölhet rekordokat dcl#:#dcl_delete_records#:#Bejegyzések törlése -dcl#:#dcl_deleted_entries#:#Deleted Entries###29 10 2025 new variable +dcl#:#dcl_deleted_entries#:#Törölt bejegyzések dcl#:#dcl_deleted_records#:#Sikeresen törölt %s bejegyzéseket -dcl#:#dcl_deprecated_copy#:#(Deprecated)###29 10 2025 new variable -dcl#:#dcl_desc#:#Csökkenő sorrend (CSÖKK) +dcl#:#dcl_deprecated_copy#:#(Elavult) +dcl#:#dcl_desc#:#Csökkenő sorrend (↓) dcl#:#dcl_description#:#Mező leírása -dcl#:#dcl_detailed_view#:#Egyszerű -dcl#:#dcl_display_action_menu#:#Hivatkozott tananyag másolásának és linkelésének engedélyezése -dcl#:#dcl_display_action_menu_desc#:#The object can be copied from the entry.###29 10 2025 new variable +dcl#:#dcl_detailed_view#:#Részletes nézet +dcl#:#dcl_display_action_menu#:#Másolás +dcl#:#dcl_display_action_menu_desc#:#Az objektummásolható a bejegyzésből dcl#:#dcl_display_record_alt#:#Bejegyzés megjelenítése -dcl#:#dcl_duplicate_non_unique_entries_exist#:#This may also concern existing records.###23 02 2024 new variable -dcl#:#dcl_edit#:#Adatgyűjtés módosítása -dcl#:#dcl_edit_entry_rules#:#Módosítás +dcl#:#dcl_duplicate_non_unique_entries_exist#:#A mezőben található néhány bejegyzés ismétlődik. Ahhoz, hogy a mező ‘Egyedi’ tulajdonságú legyen, a meglévő bejegyzéseknek is egyedieknek kell lenniük (azaz nem lehetnek azonosak). Kérjük, lépjen a ‘Tartalom’ lapra, és szerkessze a mezőben található bejegyzéseket úgy, hogy minden bejegyzés különböző legyen. +dcl#:#dcl_edit#:#Adatgyűjtés beállításai +dcl#:#dcl_edit_entry_rules#:#Bejegyzés módosítása dcl#:#dcl_edit_field#:#Mező módosítása dcl#:#dcl_edit_perm#:#A felhasználó szerkeszthet rekordokat dcl#:#dcl_edit_table#:#Táblabeállítások módosítása -dcl#:#dcl_edit_view#:#Edit Settings of View "%s"###29 10 2025 new variable +dcl#:#dcl_edit_view#:#‘%s’ nézet beállításainak módosítása dcl#:#dcl_editable_in_table_gui#:#Táblanézetben szavazzon! -dcl#:#dcl_err_formula_field_not_found#:#Nincs '%s' nevű mező. +dcl#:#dcl_err_formula_field_not_found#:#Nincs ‘%s’ nevű mező. dcl#:#dcl_error_parsing_expression#:#Hiba a kifejezés elemezésekor dcl#:#dcl_export_enabled#:#Export használatának engedélyezése az összes felhasználó számára dcl#:#dcl_export_enabled_desc#:#Az összes felhasználó exportálhatja a táblázat adatait. Az exportálható tulajdonság a mezőknél külön-külön állítható. -dcl#:#dcl_export_finished#:#Export befejeződött -dcl#:#dcl_export_started#:#Az aszinkron exportálás elkezdődött dcl#:#dcl_field_datatype#:#Adattípus dcl#:#dcl_field_description#:#Leírás -dcl#:#dcl_field_description_desc#:#The description will be shown below the input field when making a new entry.###29 10 2025 new variable -dcl#:#dcl_field_required#:#Kötelező (NOT NULL) +dcl#:#dcl_field_description_desc#:#A leírás a nyitó űrlapon, a mező alatt jelenik meg. dcl#:#dcl_field_title_change_warning#:#Megváltoztatta a mező címét, ezért bizonyos körülmények között néhány helyőrző a meghatározási nézetben megtörhetett. Ezeket kézzel kell beállítani, ha szükséges. dcl#:#dcl_field_title_unique#:#Ilyen mezőnév már létezik. A mezőnévnek egyedinek kell lennie. dcl#:#dcl_field_visible#:#Látható dcl#:#dcl_fieldtitle#:#Mező címe -dcl#:#dcl_file#:#Fileupload###26 08 2024 new variable -dcl#:#dcl_file_desc#:#Field to upload arbitrary files. They can be downloaded with a link.###26 08 2024 new variable +dcl#:#dcl_file#:#Fájlfeltöltés +dcl#:#dcl_file_desc#:#Fájlok feltöltésének mezője, melyek közvetlen az adatgyűjtésből letölthetők. dcl#:#dcl_file_format_description#:#A fájl Excel (.xlsx) fájl legyen, első munkalapján az importálandó adatokkal. Az első sorban legyenek pontosan írva a mezőnevek (kis- és nagybetű megkülönböztetve), az alatta lévő sorokban az értékeik. Először ajánlott az importot szimulálni. Hivatkozás vagy kijelölt mezők többszörös kijelölésével történő importáláskor vesszőt, illetve pontosvesszőt használható elválasztójelként. dcl#:#dcl_file_not_readable#:#A fájl nem olvasható. Győződjön meg róla, hogy Excel (.xlsx) fájlt tölt fel. dcl#:#dcl_filter#:#Szűrőként használható @@ -8669,13 +8715,12 @@ dcl#:#dcl_formula#:#Képlet dcl#:#dcl_formula_desc#:#Képlet segítségével bejegyzések értékeit aggregálhatja. dcl#:#dcl_formula_detail_desc#:#Automatikusan generált, nem módosítható bejegyzések. dcl#:#dcl_height#:#Magasság -dcl#:#dcl_height_desc#:#The height of the file will be reduced to this value during upload.###29 10 2025 new variable +dcl#:#dcl_height_desc#:#A fájlt átméretezzük a megadott magasságra dcl#:#dcl_id#:#ID dcl#:#dcl_id_description#:#A belső azonosító (internal-ID). -dcl#:#dcl_ilias_reference#:#Link egy ILIAS-tananyaghoz +dcl#:#dcl_ilias_reference#:#Link egy ILIAS objektumhoz dcl#:#dcl_ilias_reference_desc#:#Keresési mező ILIAS-ban lévő objektum kiválasztására. -dcl#:#dcl_ilias_reference_link#:#Táblanézetben linkként jelenjen meg -dcl#:#dcl_import#:#Adatgyűjtés importálása +dcl#:#dcl_ilias_reference_link#:#A kiválasztott objektumra mutató link dcl#:#dcl_import_enabled#:#Importálás engedélyezése az összes felhasználó számára dcl#:#dcl_import_enabled_desc#:#Bármelyik felhasználó adatokat importálhat a táblába, ha a szükséges írási jogosultsággal rendelkezik. dcl#:#dcl_import_records .xls#:#Importálás Excel (.xlsx) fájlból @@ -8688,29 +8733,26 @@ dcl#:#dcl_last_edited_by_description#:#Az a felhasználó, aki utoljára módos dcl#:#dcl_last_update#:#Utolsó módosítás dátuma dcl#:#dcl_last_update_description#:#Az a dátum, amikor a rekordot utoljára módosították. dcl#:#dcl_learning_progress#:#Linkelt tananyag tanulási haladásának megjelenítése -dcl#:#dcl_learning_progress_desc#:#Show each user their own learning progress for the selected object.###29 10 2025 new variable +dcl#:#dcl_learning_progress_desc#:#A megtekintett linkelt tananyag tanulási haladását jeleníti meg dcl#:#dcl_legend_placeholders#:#Dzsókerelem dcl#:#dcl_length#:#Hosszúság -dcl#:#dcl_length_info#:#(több mint 200 karakter esetén használjon szövegterületet) +dcl#:#dcl_length_info#:#A felhasználó által beírható karakterek maximális száma. 200 felett a bevitel többsorosként jelenik meg. dcl#:#dcl_limit_end#:#Záró időpont dcl#:#dcl_limit_start#:#Kezdő időpont dcl#:#dcl_limited#:#Korlátozott létrehozási/szerkesztési/törlési időszak dcl#:#dcl_limited_desc#:#A felhasználók csak adott időszakban hozhatnak létre, módosíthat, törölhetnek bejegyzéseket. dcl#:#dcl_link_detail_page#:#Link a nézetsablon oldalra -dcl#:#dcl_link_detail_page_desc#:#Additionally, a detailed view template must have been created and activated within the tab ‘Detailed View’.###29 10 2025 new variable +dcl#:#dcl_link_detail_page_desc#:#Ezenkívül a részletes nézetet az ‘Egyedül’ lapon kell aktiválni és konfigurálni. dcl#:#dcl_list_fields#:#Mezők -dcl#:#dcl_list_visibility_and_filter#:#Felsorolás -dcl#:#dcl_locked#:#Zárolt -dcl#:#dcl_locked_tooltip#:#Ha bekapcsolja, a felhasználók ezt a mezőt nem szerkeszthetik. Ez nincs hatással a 'Beállítások módosítása' jogosultsággal rendelkezőkre. +dcl#:#dcl_list_visibility_and_filter#:#Áttekintés dcl#:#dcl_manage#:#Kezelése dcl#:#dcl_max_digits#:#Számjegyek maximális hossza dcl#:#dcl_max_import#:#Elértük a maximálisan importálható rekordok számát. -dcl#:#dcl_max_text_length#:#Maximális hossz +dcl#:#dcl_max_text_length#:#Maximális hossz: %s dcl#:#dcl_mob#:#Médiaobjektum dcl#:#dcl_mob_desc#:#Kép-, hang-, illetve videófájl feltöltési lehetőség. A fájl az adatgyűjtésben jelenik meg. Engedélyezett fájltípusok: %s dcl#:#dcl_msg_field_modified#:#Mezőt sikeresen módosította dcl#:#dcl_msg_fields_deleted#:#Törölt mezők -dcl#:#dcl_msg_info_alternatives#:#Nincs megfelelő jogosultsága ezen rekord megtekintéséhez, vagy nincs részletes változata ennek a nézetnek. A rekord megtekintéséhez válasszon egy nézetet a felsorolásból. dcl#:#dcl_msg_mc_to_sc_confirmation#:#Többszörös kiválasztásról egyszeres kiválasztásra váltás a már meglévő bejegyzésben adatvesztést okozhat. Biztos, hogy folytatja? dcl#:#dcl_msg_no_perm_edit#:#Nincs jogosultsága a bejegyzés szerkesztéséhez dcl#:#dcl_msg_no_perm_view#:#Nincs jogosultsága a bejegyzés megtekintéséhez @@ -8720,78 +8762,64 @@ dcl#:#dcl_msg_tableview_created#:#Nézetet sikeresen létrehozta dcl#:#dcl_msg_tableview_deleted#:#Nézetet sikeresen törölte dcl#:#dcl_msg_tableview_updated#:#Nézetet sikeresen módosította dcl#:#dcl_msg_tableviews_delete_all#:#Nem törölhető: legalább egy nézetnek maradni kell -dcl#:#dcl_msg_tableviews_order_updated#:#Nézetek sorrendjét sikeresen mentette dcl#:#dcl_multiple_selection#:#Többszörös kiválasztás dcl#:#dcl_new#:#Új adatgyűjtés létrehozása -dcl#:#dcl_new_entries#:#New Entries###29 10 2025 new variable +dcl#:#dcl_new_entries#:#Új bejegyzések dcl#:#dcl_new_field#:#Új mező dcl#:#dcl_new_table#:#Új tábla -dcl#:#dcl_new_view#:#New View###29 10 2025 new variable -dcl#:#dcl_next_record#:#Következő bejegyzés -dcl#:#dcl_no_entries#:#Action not permitted###29 10 2025 new variable +dcl#:#dcl_new_view#:#Új nézet +dcl#:#dcl_no_entries#:#A művelet nem engedélyezett dcl#:#dcl_no_entry#:#Egy bejegyzés sem található -dcl#:#dcl_no_export_async_config#:#No SOAP Configuration for asyncronous exports available.###29 10 2025 new variable +dcl#:#dcl_no_export_async_config#:#Nincs elérhető SOAP konfiguráció aszinkron exportálásokhoz. dcl#:#dcl_no_export_data_available#:#Nincs exportálható mező, illetve bejegyzés. -dcl#:#dcl_no_fields_yet#:#Nincsenek mezők definiálva ehhez a táblához, így nem hozhat létre még egy rekordot sem. -dcl#:#dcl_no_read_access_on_any_standard_view#:#A táblázat alapértelmezett nézetéhez nincs olvasási hozzáférése. +dcl#:#dcl_no_fields_yet#:#Ez az adatkészlet még nem tartalmaz mezőket. A metaadatokat a különböző mezőtípusok egyikébe kell bevinni. A metaadatok megadásához hozzon létre legalább egy adatmezőt. dcl#:#dcl_no_search_results_found_for#:#Egyetlen tananyagot sem sikerült találni ez alapján: dcl#:#dcl_no_such_reference#:#Az alábbi érték nem érhető el a referenciatáblában: -dcl#:#dcl_no_tableview_found#:#No visible tableview found!###29 10 2025 new variable +dcl#:#dcl_no_table_found#:#Egy látható tábla se található! +dcl#:#dcl_no_tableview_found#:#Egy látható táblanézet se található! dcl#:#dcl_not_checked#:#Nem kipipált dcl#:#dcl_not_supported_in_import#:#Ez a mezőtípus nem támogatott az importban. -dcl#:#dcl_notification_activate#:#Activate Notification for Data Collection###29 10 2025 new variable +dcl#:#dcl_notification_activate#:#Értesítések bekapcsolása adatgyűjtéshez dcl#:#dcl_notification_activated#:#Értesítés bekapcsolva -dcl#:#dcl_notification_deactivate#:#Deactivate Notification for Data Collection###29 10 2025 new variable +dcl#:#dcl_notification_deactivate#:#Értesítések kikapcsolása adatgyűjtéshez dcl#:#dcl_notification_deactivated#:#Értesítés kikapcsolva dcl#:#dcl_notification_info#:#Minden felhasználó maga dönt az értesítésről -dcl#:#dcl_notification_settings#:#Notification Settings###29 10 2025 new variable -dcl#:#dcl_notimage_exception#:#A fájl kép kell legyen. -dcl#:#dcl_noturl_exception#:#Linket kell megadnia (http://-rel vagy www.-tal kezdődőt) vagy e-mail címet. +dcl#:#dcl_notification_settings#:#Értesítési beállítások +dcl#:#dcl_noturl_exception#:#Linket adjon meg (http://-rel vagy www.-tal kezdődőt) vagy e-mail címet. dcl#:#dcl_number#:#Egész szám dcl#:#dcl_number_desc#:#Egész szám típusú beviteli mező (max. 9 számjegy). Közönséges és tizedes törtek nem engedélyezettek. dcl#:#dcl_online_info#:#Az adatgyűjtést csak online állapotában használhatják a felhasználók. -dcl#:#dcl_open_detail_view#:#Open detail view###29 10 2025 new variable -dcl#:#dcl_open_url#:#Open link###29 10 2025 new variable +dcl#:#dcl_open_detail_view#:#Részletes nézet megnyitása +dcl#:#dcl_open_url#:#Link megnyitása dcl#:#dcl_order#:#Sorrend -dcl#:#dcl_origin_not_found#:#Origin field was not found!###29 10 2025 new variable +dcl#:#dcl_origin_not_found#:#Az eredeti mező nem található! dcl#:#dcl_own_entries#:#Csak a saját bejegyzéseim dcl#:#dcl_owner#:#Tulajdonos dcl#:#dcl_owner_description#:#Az a felhasználó, aki a bejegyzés tulajdonosa. dcl#:#dcl_owner_name#:#Tulajdonos (név) dcl#:#dcl_page_type_dclf#:#Részletes nézet -dcl#:#dcl_placeholder_info#:#To use data from the data collection in this view, please use the corresponding placeholders. These are available in the page element 'Text' and 'Data Table'.###29 10 2025 new variable +dcl#:#dcl_placeholder_info#:#TAz adatgyűjteményből származó adatok ebben a nézetben való használatához kérjük, használja a megfelelő helyőrzőket. Ezek a ‘Szöveg’ és az ‘Adattábla’ lapelemekben érhetők el. dcl#:#dcl_please_select#:#--- Válasszon --- -dcl#:#dcl_plugin#:#Bővítmény -dcl#:#dcl_plugin_desc#:#Adatgyűjtésmező-bővítmények -dcl#:#dcl_plugin_no_hooks_available#:#Egy aktív mezőtípusú bővítmény sem található -dcl#:#dcl_prev_record#:#Előző bejegyzés dcl#:#dcl_prop_expression#:#Kifejezés -dcl#:#dcl_prop_expression_info#:#Használható operátorok: %s
    Használható függvények: %s
    Zárójeleket is használhat '(', ')' a számítások csoportosításához.

    Szöveget és mezőket is összefűzhet: 'Az eredmény ' & [[Int 1]] * [[Int 2]]
    Függvényeket is használhat: SUM([[Int 1]];[[Int 2]])

    Az alábbi mezők használhatóak fel a kifejezésben (kattints a mező címére a kifejezésbe történő beemeléséhez):
    %s -dcl#:#dcl_public_comments#:#Nyilvános megjegyzések engedélyezése -dcl#:#dcl_public_comments_desc#:#Felhasználók hozzászólásokat készíthetnek a táblázat bejegyzéseihez. +dcl#:#dcl_prop_expression_info#:#Használható operátorok: %s
    Használható függvények: %s
    Zárójeleket is használhat ‘(’, ‘)’ a számítások csoportosításához.

    Szöveget és mezőket is összefűzhet: ‘Az eredmény ‘ & [[Int 1]] * [[Int 2]]
    Függvényeket is használhat: SUM([[Int 1]];[[Int 2]])

    Az alábbi mezők használhatók fel a kifejezésben (kattintson a mező címére a kifejezésbe történő beemeléséhez):
    %s
    (Az engedélyezett mezők logikai, szám, szöveg és dátum, amelyek címükben nem tartalmaznak képletérzékeny karaktereket) dcl#:#dcl_rating#:#Értékelés -dcl#:#dcl_rating_desc#:#Felhasználók értékelhetik a bejegyzéseket, legfeljebb öt csillagig. -dcl#:#dcl_rbac_roles_without_read_access_on_any_standard_view#:#A következő szerepeknek van olvasási hozzáférése az adatgyűjtéshez, de nincs a tábla alapértelmezett nézetéhez: +dcl#:#dcl_rating_desc#:#A bejegyzések értékelhetők legfeljebb öt csillagig. dcl#:#dcl_record#:#Bejegyzés dcl#:#dcl_record_deleted#:#Bejegyzést sikeresen törölte -dcl#:#dcl_record_from_total#:#%d / %d -dcl#:#dcl_record_settings#:#Record Settings###29 10 2025 new variable +dcl#:#dcl_record_settings#:#Bejegyzés beállításai dcl#:#dcl_reference#:#Hivatkozás másik mezőre dcl#:#dcl_reference_desc#:#Másik mező vagy táblázat kiválasztási lehetőségét biztosítja. dcl#:#dcl_reference_link#:#Link megjelenítése hivatkozott bejegyzésként dcl#:#dcl_reference_link_info#:#A részletes megjelenítést be kell kapcsolni a hivatkozott táblában -dcl#:#dcl_reference_title#:#Hivatkozás táblázatra és mezőre. -dcl#:#dcl_reference_title_desc#:#The data entries of the selected field will be the selectable options in this field.###29 10 2025 new variable +dcl#:#dcl_reference_title#:#Hivatkozott mező +dcl#:#dcl_reference_title_desc#:#A kiválasztott mezők rekordjai lesznek a célmező kiválasztható értékei. dcl#:#dcl_regex#:#Reguláris kifejezés dcl#:#dcl_regex_info#:#(határolójel nélkül) -dcl#:#dcl_required#:#Kötelező (NOT NULL) dcl#:#dcl_row_not_found#:# - Ez a mező nem található a táblában. dcl#:#dcl_save_confirmation#:#Mentés megerősítése dcl#:#dcl_save_confirmation_desc#:#Felhasználóknak jóvá kell hagyniuk minden új adatgyűjtemény bejegyzést. -dcl#:#dcl_save_order#:#Sorrend mentése -dcl#:#dcl_select#:#Kiválasztás megjelenítéshez dcl#:#dcl_selection_options#:#Lehetőségek -dcl#:#dcl_selection_type#:#Típus +dcl#:#dcl_selection_type#:#Formátum dcl#:#dcl_selection_type_combobox#:#Legördülő választék (combobox) dcl#:#dcl_selection_type_multi#:#Többszörös kiválasztás dcl#:#dcl_selection_type_single#:#Egyszeres kiválasztás @@ -8799,17 +8827,13 @@ dcl#:#dcl_simulate_import#:#Import szimulálása dcl#:#dcl_simulate_info#:#Az importálás szimulálása egy új mezőt sem ad az adatgyűjtéshez, de az esetleges importálási fájl hibáit jelzi, így megelőzheti a hibás rekordokat. dcl#:#dcl_skipped_delete_records#:#%s bejegyzések törlése sikertelen jogosultsági beállítások miatt dcl#:#dcl_status#:#Az Ön állapota -dcl#:#dcl_std_field_not_importable#:# - Standard mezők nem importálhatóak. -dcl#:#dcl_std_filter#:#Standard szűrő +dcl#:#dcl_std_field_not_importable#:# - Standard mezők nem importálhatók. +dcl#:#dcl_std_filter#:#Alapértelmezett szűrő dcl#:#dcl_supported_filetypes#:#Engedélyezett fájlkiterjesztések dcl#:#dcl_supported_filetypes_desc#:#Az engedélyezni kívánt fájlkiterjesztéseket vesszővel elválasztva adja meg. Például: pdf, docx -dcl#:#dcl_switch_table#:#Switch Table###26 08 2024 new variable -dcl#:#dcl_switch_view#:#Change View###26 08 2024 new variable dcl#:#dcl_table#:#Tábla dcl#:#dcl_table_id#:#Tábla-ID -dcl#:#dcl_table_list_fields#:#Kiválasztott tábla mezői -dcl#:#dcl_table_list_tables#:#Elérhető táblák -dcl#:#dcl_table_settings#:#Table Settings.###29 10 2025 new variable +dcl#:#dcl_table_settings#:#Tábla beállításai. dcl#:#dcl_table_settings_saved#:#A táblabeállításokat sikeresen mentette. dcl#:#dcl_table_title_not_matching#:#Az Excel munkalap neve és az adatgyűjtés neve nem azonos, kérem, nevezze át a munkalapot. dcl#:#dcl_table_title_unique#:#Ilyen táblanév már létezik. A táblanévnek egyedinek kell lennie. @@ -8823,16 +8847,13 @@ dcl#:#dcl_tableview_default_value_fail#:#Néhány érték nem menthető, mert be dcl#:#dcl_tableview_field_access#:#Mezőelérés dcl#:#dcl_tableview_fieldsettings#:#Mezőfüggő beállítások dcl#:#dcl_tableview_fieldtitle#:#Mezőcím -dcl#:#dcl_tableview_locked#:#Zárolt dcl#:#dcl_tableview_locked_visible#:#Zárolt & látható dcl#:#dcl_tableview_not_visible#:#Nem látható dcl#:#dcl_tableview_required#:#Kötelező dcl#:#dcl_tableview_required_visible#:#Kötelező & látható dcl#:#dcl_tableview_visible#:#Látható dcl#:#dcl_tableviews#:#Nézetek -dcl#:#dcl_tableviews_confirm_delete#:#Biztos, hogy törli az alábbi nézeteket? -dcl#:#dcl_tableviews_of_X#:#Views of table %s###26 08 2024 new variable -dcl#:#dcl_tableviews_table#:#Kiválasztott tábla nézetei +dcl#:#dcl_tableviews_of_X#:#‘%s’ tábla nézetei dcl#:#dcl_text#:#Szöveg dcl#:#dcl_text_desc#:#Beviteli mező szöveg, link vagy e-mail cím tárolására. dcl#:#dcl_text_email_detail_desc#:#Érvényes URL-t vagy e-mail címet adjon meg. @@ -8840,41 +8861,42 @@ dcl#:#dcl_text_email_title#:#Cím dcl#:#dcl_text_email_title_info#:#Az alábbi URL-hez vagy e-mail címhez címke (nem kötelező). dcl#:#dcl_text_selection#:#Szövegválasztó dcl#:#dcl_text_selection_desc#:#Szöveglehetőségek választásának felkínálása. -dcl#:#dcl_title_standardview#:#Standard nézetek +dcl#:#dcl_title_standard#:#Standard dcl#:#dcl_unique#:#Egyedi dcl#:#dcl_unique_desc#:#Ebben a mezőben minden értéknek különböznie kell egymástól. dcl#:#dcl_unique_exception#:#Az Ön által megadott értéket már másik bejegyzés tartalmazza. -dcl#:#dcl_unknown#:#Unkown###29 10 2025 new variable +dcl#:#dcl_unknown#:#Ismeretlen dcl#:#dcl_unknown_exception#:#Az Ön által megadott érték nem érvényes. -dcl#:#dcl_unknown_plugin#:#Unknown plugin type###29 10 2025 new variable +dcl#:#dcl_unknown_plugin#:#Ismeretlen bővítménytípus dcl#:#dcl_update_field#:#Mező frissítése dcl#:#dcl_update_record#:#Bejegyzés módosítása -dcl#:#dcl_updated_entries#:#Updated Entries###29 10 2025 new variable +dcl#:#dcl_updated_entries#:#Módosított bejegyzések dcl#:#dcl_url#:#URL -dcl#:#dcl_view_configuration#:#Konfiguráció megjelenítése dcl#:#dcl_view_own_records_perm#:#Csak a saját bejegyzések megjelenítése -dcl#:#dcl_view_own_records_perm_desc#:#The entries of other users are not visible.###29 10 2025 new variable +dcl#:#dcl_view_own_records_perm_desc#:#A bejegyzés elrejtése a többi felhasználó elől. dcl#:#dcl_view_viewdefinition#:#Nézetsablon dcl#:#dcl_visible#:#Az összes felhasználó láthatja -dcl#:#dcl_visible_desc#:#Felhasználók a 'Táblázat' menüben hozzáférhetnek ehhez a táblázathoz. +dcl#:#dcl_visible_desc#:#Felhasználók a ‘Táblázat’ menüben hozzáférhetnek ehhez a táblázathoz. dcl#:#dcl_width#:#Szélesség -dcl#:#dcl_width_desc#:#The width of the file will be reduced to this value during upload.###29 10 2025 new variable +dcl#:#dcl_width_desc#:#A fájlt átméretezzük a megadott szélességűre. dcl#:#dcl_wrong_input_type#:#Az Ön által megadott érték nem illeszkedik a specifikációhoz (rossz típus). dcl#:#dcl_wrong_length#:#Az Ön által megadott szöveg túl hosszú. dcl#:#dcl_wrong_regex#:#Az Ön által megadott szöveg nem illeszkedik ennek a mezőnek a specifikációjához (reguláris kifejezéshez). -dcl#:#dcl_xls_async_export#:#Asynchronous XLSX-Export###26 08 2024 new variable -dcl#:#disable_comments#:#Disable comments###26 08 2024 new variable -dcl#:#disable_visible#:#Disable visible###26 08 2024 new variable -dcl#:#duplicate_entries_exist#:#The existing records already contain duplicated entries.###29 10 2025 new variable -dcl#:#enable_comments#:#Enable comments###26 08 2024 new variable -dcl#:#enable_visible#:#Enable visible###26 08 2024 new variable -dcl#:#entry_of#:#Entry %1$d of %2$d###26 08 2024 new variable +dcl#:#dcl_xls_async_export#:#Aszinkron Excel (.xlsx) exportálás +dcl#:#disable_comments#:#Megjegyzések kikapcsolása +dcl#:#disable_visible#:#Láthatóság kikapcsolása +dcl#:#duplicate_entries_exist#:#A meglévő rekordok már tartalmaznak ismétlődő bejegyzéseket. +dcl#:#enable_comments#:#Megjegyzések bekapcsolása +dcl#:#enable_visible#:#Láthatóság bekapcsolása +dcl#:#entry_of#:#%1$d / %2$d bejegyzés dcl#:#fieldtitle_allow_chars#:#Nem engedélyezett karakterek: %s -dcl#:#fileupload_not_migrated#:#File has not yet been migration and cannot be displayed. Please contact your System-Administrator.###26 08 2024 new variable -dcl#:#role_limitation#:#Role-based View Limitation###29 10 2025 new variable -dcl#:#roles#:#Roles with Access###29 10 2025 new variable -dcl#:#roles_desc#:#Define wich roles have access to the view.###29 10 2025 new variable -dcl#:#set_as_default#:#Set as default###26 08 2024 new variable +dcl#:#fileupload_not_migrated#:#Ezt fájlt még nem migrálták, ezért nem jeleníthető meg. Kérem, keresse a rendszerüzemeltetőt. +dcl#:#role_limitation#:#Szerepköralapú megtekintéskorlátozás +dcl#:#roles#:#Szerepkörök hozzáféréssel +dcl#:#roles_desc#:#Határozza meg, hogy mely szerepkörök férhetnek hozzá a nézethez. +dcl#:#set_as_default#:#Beállításnak alapértelmezettnek +dcl#:#table_not_found#:#A tábla nem található! +dcl#:#tableview_not_found#:#A táblanézet nem található! didactic#:#activate_exclusive_template#:#Alapértelmezetten őszülő didactic#:#activate_exclusive_template_info#:#A standard sablon nem lesz elérhető ahol ez a sablon aktív. didactic#:#activate_local_didactic_template#:#Alkalmazás hatásköre @@ -8901,7 +8923,7 @@ didactic#:#didactic_filter_without_icon#:#Ikon nélkü didactic#:#didactic_global#:#Globális didactic#:#didactic_icon#:#Ikon didactic#:#didactic_icon_error#:#Ikon csak tárolóobjektumokhoz rendelhető. -didactic#:#didactic_icon_info#:#Ez az ikon jelenik meg az összes, ezt a sablont használó objektumnál. Az 'Egyedi ikon'-nal ez felülírható. Ikon csak tárolóobjektumokhoz rendelhető (például kurzus, kategória). +didactic#:#didactic_icon_info#:#Ez az ikon jelenik meg az összes, ezt a sablont használó objektumnál. Az ‘Egyedi ikon’-nal ez felülírható. Ikon csak tárolóobjektumokhoz rendelhető (például kurzus, kategória). didactic#:#didactic_import_btn#:#Didaktikai sablonok importálása didactic#:#didactic_import_failed#:#Didaktikai sablon importálása sikertelen, hibaüzenete: didactic#:#didactic_import_success#:#Sikeresen importált didaktikai sablon @@ -8915,30 +8937,31 @@ didactic#:#didactic_selected_tpl_option#:#Alkalmazott oktatási sablon: didactic#:#didactic_template_applied#:#Alkalmazott oktatási sablon. didactic#:#didactic_template_update_import#:#Didaktikai sablon frissítése didactic#:#didactic_template_update_import_info#:#Tulajdonságok ettől az importtól függően módosulnak. A már ezt a sablon használó objektumok nem módosulnak. +didactic#:#didactic_translation_add_languages#:#Nyelv hozzáadása didactic#:#dtpl_obj_type_info#:#Az a didaktikai sablon nem alkalmazható erre az objektumtípusra. didactic#:#effective_form#:#Sablon hatályos innentől: didactic#:#grp_closed#:#Zárt csoport -didactic#:#grp_closed_info#:#Akik nem tagok, nem láthatják a csoportot. +didactic#:#grp_closed_info#:#A csoportot csak tagjaik láthatják. didactic#:#more_translations#:#További fordítások didactic#:#sess_closed#:#Zárt esemény -didactic#:#sess_closed_info#:#Az eseményt csak a résztvevők láthatják. -dpro#:#dpro_accept_usr_agreement_anonymous#:#Declaration of Data Protection###26 08 2024 new variable -dpro#:#dpro_accept_usr_agreement_anonymous_intro#:#Before you proceed to ILIAS you accept the following Declaration of Data Protection.###26 08 2024 new variable -dpro#:#dpro_account_reg_not_possible#:#Self-registration is currently not possible because there is no Declaration of Data Protection agreement available. Please contact your system administrator for further information.###26 08 2024 new variable -dpro#:#dpro_agree_date#:#Declaration of Data Protection agreed on###26 08 2024 new variable -dpro#:#dpro_last_reset_date#:#The Declaration of Data Protection were reset on %s. Only reset the Declaration of Data Protection if changes have been made to the document(s) and you require all users to agree to the documents.###26 08 2024 new variable -dpro#:#dpro_mode#:#Agreement Mode###26 08 2024 new variable -dpro#:#dpro_mode_desc#:#Please configure when and how the Declaration of Data Protection should be accepted.###26 08 2024 new variable -dpro#:#dpro_no_acceptance#:#Never, only informative###26 08 2024 new variable -dpro#:#dpro_no_documents_exist#:#There are currently no Declaration of Data Protection documents available.###26 08 2024 new variable -dpro#:#dpro_no_documents_exist_cant_save#:#There are currently no Declaration of Data Protection documents available. Please add at least one document in order to activate this service.###26 08 2024 new variable -dpro#:#dpro_once#:#Accept once###26 08 2024 new variable -dpro#:#dpro_reset_for_all_users#:#Reset the Declaration of Data Protection###26 08 2024 new variable -dpro#:#dpro_status_enable#:#Enable the Declaration of Data Protection###26 08 2024 new variable -dpro#:#dpro_status_enable_desc#:#Display relevant language-based Declaration of Data Protection documents at the end of the registration form for new users and, if applicable, upon the user’s first login. Users are required to accept the Declaration of Data Protection before they can enter ILIAS.###26 08 2024 new variable -dpro#:#dpro_sure_reset_tos#:#Are you sure you want to reset the Declaration of Data Protection for all users in the system? This also applies, for example, to those accounts that are used for the SOAP web services.###26 08 2024 new variable -dpro#:#dpro_withdrawal_usr_deletion#:#Account deletion upon Declaration of Data Protection withdrawal###26 08 2024 new variable -dpro#:#dpro_withdrawal_usr_deletion_desc#:#If a user withdraws their acceptance from a previously accepted Declaration of Data Protection document, this will result in the deletion of the user’s account.###26 08 2024 new variable +didactic#:#sess_closed_info#:#Az eseményt csak a résztvevőik láthatják. +dpro#:#dpro_accept_usr_agreement_anonymous#:#Adatvédelmi Nyilatkozat +dpro#:#dpro_accept_usr_agreement_anonymous_intro#:#Mielőtt továbblép az ILIAS-hoz, elfogadja az alábbi Adatvédelmi Nyilatkozatot. +dpro#:#dpro_account_reg_not_possible#:#A regisztráció jelenleg nem lehetséges, mert nincs Adatvédelmi Nyilatkozat. Kérem, további információért keresse a rendszer üzemeltetőjét. +dpro#:#dpro_agree_date#:#Adatvédelmi Nyilatkozat elfogadása +dpro#:#dpro_last_reset_date#:#Az Adatvédelmi Nyilatkozatot elfogadásait törölték (%s). Csak akkor tegye ezt meg újra, ha módosult az Adatvédelmi Nyilatkozat tartalma és ezért azt újra el kell fogadtatni a felhasználókkal. +dpro#:#dpro_mode#:#Elfogadás módja +dpro#:#dpro_mode_desc#:#Kérem, adja meg, hogy az Adatvédelmi Nyilatkozatot mikor és hogyan fogadják el. +dpro#:#dpro_no_acceptance#:#Soha, csak informatív +dpro#:#dpro_no_documents_exist#:#Jelenleg nincs beállítva Adatvdelmi Nyilatkozat. +dpro#:#dpro_no_documents_exist_cant_save#:#A szolgáltatás jelenleg nem kapcsolható be, mert nincs beállítva Adatvdelmi Nyilatkozat. Leaglább egyet adjon hozzá +dpro#:#dpro_once#:#Egyszer +dpro#:#dpro_reset_for_all_users#:#Adatvédelem Nyilatkozat elfogadásainak törlése +dpro#:#dpro_status_enable#:#Adatvédelem bekapcsolása +dpro#:#dpro_status_enable_desc#:#A nyelvfüggő Adatvédelmi Nyilatkozat megjelenítése az új felhasználó regisztrációs űrlapján, illetve az első bejelentkezéskor. Az Adatvédelmi Nyilatkozatot el kell fogadni a bejelentkezéskor. +dpro#:#dpro_sure_reset_tos#:#Biztos, hogy törli az összes felhasználó Adatvédelmi Nyilatkozat elfogadását? Figyeljen arra, hogy ez hatással lesz például a SOAP webszolgáltatást használó fiókra is. +dpro#:#dpro_withdrawal_usr_deletion#:#Fiók törlése az Adatvédelmi Nyilatkozat visszavonásakor +dpro#:#dpro_withdrawal_usr_deletion_desc#:#Amikor egy felhasználó visszavonja az Adatvédelmi Nyilatkozat elfogadását, az az ILIAS-fiókjának törlését vonja maga után. ecs#:#cert_serial#:#Tanúsítvány sorozatszáma ecs#:#ecs_abr#:#Rövidítés ecs#:#ecs_account_duration#:#Aktiválási időszak meghosszabbítása @@ -9020,11 +9043,11 @@ ecs#:#ecs_cms_tree_synchronized#:#A fát szinkronizáltuk. ecs#:#ecs_communities#:#Résztvevők ecs#:#ecs_confirm_delete_tree#:#Biztos, hogy törli ennek a campus-menedzsment fának minden hozzárendelését? ecs#:#ecs_connection_settings#:#Kapcsolódási beállítások -ecs#:#ecs_consent_modal_btn_accept#:#Agree and Proceed###29 10 2025 new variable -ecs#:#ecs_consent_modal_title#:#Consent for data transfer###26 08 2024 new variable -ecs#:#ecs_consent_reset_confirm_title#:#Reset user consent for this participant###26 08 2024 new variable +ecs#:#ecs_consent_modal_btn_accept#:#Elfogadom és folytatom +ecs#:#ecs_consent_modal_title#:#Hozzájárulás az adatátvitelhez +ecs#:#ecs_consent_reset_confirm_title#:#Felhasználói hozzájárulás visszaállítása ecs#:#ecs_cron_task_scheduler#:#ECS-feladatütemező -ecs#:#ecs_cron_task_scheduler_info#:#Az ECS-feladatütemező a beállításai szerint fog lefutni. Ez csak akkor szükséges, amikor be van állítva ECS-szerver. +ecs#:#ecs_cron_task_scheduler_info#:#Az ECS-feladatütemező a beállításai szerint fog lefutni. Ez csak akkor lehtséges, amikor be van állítva ECS-szerver. ecs#:#ecs_crs_alloc#:#Kurzus lefoglalása ecs#:#ecs_crs_alloc_set#:#Kurzusfoglalás módosítása ecs#:#ecs_crs_export#:#Kurzuskiadás @@ -9051,17 +9074,17 @@ ecs#:#ecs_err_missing_value#:#Ellenőrizze a tulajdonságértékre megadott beme ecs#:#ecs_error_extract_serial#:#Nem olvasható a tanúsítvány sorozatszáma. Ellenőrizze a klienstanúsítvány elérési útját! ecs#:#ecs_event_appointment#:#Eseménydátum ecs#:#ecs_export#:#Kurzuskibocsátások -ecs#:#ecs_export_auth_type#:#Authentication method for users with external user attribute###26 08 2024 new variable -ecs#:#ecs_export_auth_type_ilias#:#User authentication via LDAP###26 08 2024 new variable -ecs#:#ecs_export_auth_type_info#:#Please choose the authentication method for users to authenticate via ECS, for whom an external user attribute was transferred via ECS.###26 08 2024 new variable -ecs#:#ecs_export_auth_type_none#:#Do not allow users with external user attribute###26 08 2024 new variable -ecs#:#ecs_export_auth_type_oidc#:#User authentication via OpenID Connect###29 10 2025 new variable -ecs#:#ecs_export_auth_type_shib#:#User authentication via Shibboleth###26 08 2024 new variable +ecs#:#ecs_export_auth_type#:#Hitelesítési módszer külső felhasználói attribútummal rendelkező felhasználók számára +ecs#:#ecs_export_auth_type_ilias#:#Felhasználó hitelesítés LDAP-pal +ecs#:#ecs_export_auth_type_info#:#Kérjük, válassza ki a hitelesítési módot az ECS-n keresztül történő hitelesítéshez azon felhasználók számára, akiknél külső felhasználói attribútumot adunk át az ECS-n keresztül +ecs#:#ecs_export_auth_type_none#:#Külső felhasználói attribútumokkal rendelkező felhasználók tiltása +ecs#:#ecs_export_auth_type_oidc#:#Felhasználói hitelesítés OpenID Connecten keresztül +ecs#:#ecs_export_auth_type_shib#:#Felhasználó hitelesítés Shibboleth-tel ecs#:#ecs_export_created_body_a#:#Új kurzus került kibocsátásra ecs#:#ecs_export_disabled#:#Ne bocsássa ki ezt a kurzust ecs#:#ecs_export_enabled#:#Bocsássa ki ezt a kurzust -ecs#:#ecs_export_local_account#:#Local ILIAS accounts###26 08 2024 new variable -ecs#:#ecs_export_local_account_info#:#If enabled, will allow the creation of local accounts via ECS. ECS users without external user attribute will receive a local user account on your installation.###26 08 2024 new variable +ecs#:#ecs_export_local_account#:#Helyi ILIAS-fiókok +ecs#:#ecs_export_local_account_info#:#Ha van bekapcsolva, lehetővé teszi a helyi fiókok létrehozását az ECS-n keresztül. A külső felhasználói attribútum nélküli ECS-felhasználók helyi felhasználói fiókot kapnak. ecs#:#ecs_export_obj_settings#:#Kurzuskibocsátási beállítások ecs#:#ecs_export_types#:#Exportálható objektumtípusok ecs#:#ecs_field_begin#:#Kezdő időpont @@ -9084,47 +9107,47 @@ ecs#:#ecs_file_export#:#Fájlkiadások ecs#:#ecs_file_export_disabled#:#Ne legyen kiadva ez a fájl ecs#:#ecs_file_export_enabled#:#Ezen fájl felszabadítása ecs#:#ecs_file_export_obj_settings#:#Fájlkiadás beállításai -ecs#:#ecs_firstname#:#First name###26 08 2024 new variable -ecs#:#ecs_form_consent#:#Consent###26 08 2024 new variable -ecs#:#ecs_form_consent_option_title#:#I hereby consent to the transfer of the following data to the above-mentioned target system:###26 08 2024 new variable -ecs#:#ecs_form_target_platform#:#Target system###26 08 2024 new variable +ecs#:#ecs_firstname#:#Utónév +ecs#:#ecs_form_consent#:#Hozzájárulás +ecs#:#ecs_form_consent_option_title#:#Hozzájárulok az alábbi adatok fent említett célrendszerbe történő továbbításához: +ecs#:#ecs_form_target_platform#:#Célrendszer ecs#:#ecs_general_info#:#Általános információk ecs#:#ecs_glo_export#:#Fogalomtár kiadásai ecs#:#ecs_glo_export_disabled#:#Ne legyen kiadva ez a fogalomtár ecs#:#ecs_glo_export_enabled#:#Ezen fogalomtár kiadása ecs#:#ecs_glo_export_obj_settings#:#Fogalomtár kiadás beállításai -ecs#:#ecs_global_role_info#:#A kiválasztott szerep hozzá lesz rendelve az újonnan létrehozott ECS-felhasználóhoz. +ecs#:#ecs_global_role_info#:#A kiválasztott szerepkör hozzá lesz rendelve az újonnan létrehozott ECS-felhasználóhoz. ecs#:#ecs_grp_export#:#Csoport kiadásai ecs#:#ecs_grp_export_disabled#:#Ne legyen kiadva ez a csoport ecs#:#ecs_grp_export_enabled#:#Ezen csoport kiadása ecs#:#ecs_grp_export_obj_settings#:#Csoportkiadás beállításai ecs#:#ecs_ignore_field#:#A mező exportjának/frissítésének letiltása ecs#:#ecs_import#:#Importált kurzusok -ecs#:#ecs_import_auth_mode#:#Allow accounts of authentication method %s for transmission via ECS###26 08 2024 new variable -ecs#:#ecs_import_auth_type_default#:#Allow accounts authentication method "Default" for transmission via ECS###26 08 2024 new variable +ecs#:#ecs_import_auth_mode#:#‘%s’ hitelesítési mód fiókjainak engedélyezése az ECS-n keresztüli továbbításhoz +ecs#:#ecs_import_auth_type_default#:#Az ‘Alapértelmezett’ fiókhitelesítési módú felhasználók engedélyezése az ECS-n keresztüli továbbításhoz ecs#:#ecs_import_cms#:#Campus-menedzsment ecs#:#ecs_import_id#:#ID importálása ecs#:#ecs_import_id_info#:#Adja meg annak a kategóriának az ID-jét, ahová az új kurzuslinkek lesznek létrehozva! ecs#:#ecs_import_types#:#Importálható objektumtípusok -ecs#:#ecs_import_user_credentials_by_auth_mode#:#Configuration of authentication methods for transmission via ECS###26 08 2024 new variable -ecs#:#ecs_import_user_credentials_by_auth_mode_info#:#Enable this option to allow accounts of authentication method "Default" to access participant's resources via ECS.###26 08 2024 new variable +ecs#:#ecs_import_user_credentials_by_auth_mode#:#Hitelesítési módszerek konfigurálása ECS-n keresztüli átvitelhez +ecs#:#ecs_import_user_credentials_by_auth_mode_info#:#Kapcsolja be ezt az opciót, hogy az ‘Alapértelmezett’ hitelesítési módszerrel rendelkező fiókok hozzáférjenek a résztvevő erőforrásaihoz az ECS-n keresztül ecs#:#ecs_imported_content#:#Importált e-tartalom ecs#:#ecs_imported_from#:#Importálva innen -ecs#:#ecs_institution#:#Institution###26 08 2024 new variable -ecs#:#ecs_invalid_import_type_cms#:#A 'Campus-menedzsment' importtípus csak egyszer választható. +ecs#:#ecs_institution#:#Intézet +ecs#:#ecs_invalid_import_type_cms#:#A ‘Campus-menedzsment’ importtípus csak egyszer választható. ecs#:#ecs_key_password#:#Kulcsjelszó -ecs#:#ecs_lastname#:#Last name###26 08 2024 new variable +ecs#:#ecs_lastname#:#Utónév ecs#:#ecs_lm_export#:#Tananyag kiadásai ecs#:#ecs_lm_export_disabled#:#Ne legyen kiadva ez a tananyag ecs#:#ecs_lm_export_enabled#:#Ezen tananyag kiadása ecs#:#ecs_lm_export_obj_settings#:#Tananyag kiadásának beállításai ecs#:#ecs_local_information#:#További információk ecs#:#ecs_local_settings#:#Helyi beállítások -ecs#:#ecs_login#:#Username or External user account###26 08 2024 new variable +ecs#:#ecs_login#:#Felhasználónév vagy Külső felhasználói fiók ecs#:#ecs_mapping_crs#:#Leképezés kurzusokra -ecs#:#ecs_mapping_exp_tbl#:#ILIAS bővített metaadatok leképezése ECS-adatokba +ecs#:#ecs_mapping_exp_tbl#:#ILIAS egyéni metaadatok leképezése ECS-adatokba ecs#:#ecs_mapping_rcrs#:#Leképezés ECS kurzushoz -ecs#:#ecs_mapping_tbl#:#ECS-adatok ILIAS fejlettebb metaadatokra való leképezése +ecs#:#ecs_mapping_tbl#:#ECS-adatok ILIAS egyéni metaadatokra való leképezése ecs#:#ecs_mappings#:#ECS-adatleképezés ecs#:#ecs_member_auth_type#:#Hitelesítési mód (résztvevők) ecs#:#ecs_meta_data#:#Metaadat @@ -9134,7 +9157,7 @@ ecs#:#ecs_new_econtent_subject#:#Új e-tartalom jött létre ecs#:#ecs_new_user_body#:#Új ECS-felhasználó jött létre. ecs#:#ecs_new_user_profile#:#Felhasználó adatai: ecs#:#ecs_new_user_subject#:#Új ECS-felhasználó -ecs#:#ecs_no_adv_md#:#Nincsenek bővített metaadatok. +ecs#:#ecs_no_adv_md#:#Nincsenek egyéni metaadatok. ecs#:#ecs_no_owner#:#Válasszon egy közösségnevet. ecs#:#ecs_no_value#:#Nem elérhető ecs#:#ecs_node_mapping_activate#:#Mappaleképezés engedélyezése @@ -9146,8 +9169,8 @@ ecs#:#ecs_node_mapping_status_3#:#Nem leképezett ecs#:#ecs_not_configured#:#Nem konfigurált ecs#:#ecs_not_published#:#Nincs kiválasztva jóváhagyás. ecs#:#ecs_notifications#:#Értesítések -ecs#:#ecs_outgoing_user_credentials#:#User attribute###26 08 2024 new variable -ecs#:#ecs_outgoing_user_credentials_info#:#Please specify which user attribute should be used for transmission. Possible values [Login], [EXTERNAL_ACCOUNT]. You can modify the specified attribute by prepending or appending any strings. Example: [LOGIN]@example.com###26 08 2024 new variable +ecs#:#ecs_outgoing_user_credentials#:#Felhasználói attribútum +ecs#:#ecs_outgoing_user_credentials_info#:#Kérjük, adja meg, hogy milyen felhasználói attribútumot használja az átvitelhez. Lehetséges értékek [Login], [EXTERNAL_ACCOUNT]. Módosíthatja a megadott attribútumot bármilyen karakterlánc elé- vagy mögéfűzésével. Példa: [LOGIN]@pelda.hu ecs#:#ecs_part_settings#:#Résztvevők beállításai: ecs#:#ecs_participants#:#Résztvevők ecs#:#ecs_participants_infos#:#További információk @@ -9159,7 +9182,7 @@ ecs#:#ecs_protocol#:#Protokoll ecs#:#ecs_publish_as#:#Közzététel mint: ecs#:#ecs_publish_for#:#Kibocsátás ennek: ecs#:#ecs_published_for#:#Publikálva neki: -ecs#:#ecs_rcat_created_body_a#:#A new ECS Category has been created:###28 10 2024 new variable +ecs#:#ecs_rcat_created_body_a#:#Új ECS-kategória jött létre: ecs#:#ecs_rcrs_created_body_a#:#Új ECS-kurzus jött létre: ecs#:#ecs_read_remote_links#:#ECS-kurzusok frissítése ecs#:#ecs_refresh_participants#:#ECS-résztvevők frissítése @@ -9169,7 +9192,7 @@ ecs#:#ecs_remote_imported#:#Az ECS-kurzusról az információkat sikeresen friss ecs#:#ecs_remote_user_settings#:#Beállítások ECS-felhasználókhoz ecs#:#ecs_role#:#Szerep-összerendelés ecs#:#ecs_role_mapping_value#:#Attribútum értéke -ecs#:#ecs_role_mappings#:#Kurzus/Csoport szerep összerendelések +ecs#:#ecs_role_mappings#:#Kurzus/Csoport szerepkör összerendelések ecs#:#ecs_server_addr#:#Szervercím ecs#:#ecs_server_deleted#:#Törölt szerver ecs#:#ecs_server_settings#:#ECS-funkcionalitások @@ -9187,14 +9210,14 @@ ecs#:#ecs_sync_trees#:#Mappafaszerkezet szinkronizálása ecs#:#ecs_tab_export#:#Export ecs#:#ecs_tab_import#:#Import ecs#:#ecs_tbl_active#:#Aktív -ecs#:#ecs_tbl_active_rules#:#Aktív szerepek kategória-összerendeléshez +ecs#:#ecs_tbl_active_rules#:#Aktív szerepkörök kategória-összerendeléshez ecs#:#ecs_tbl_export#:#Export ecs#:#ecs_tbl_import#:#Import ecs#:#ecs_tbl_import_type#:#Importtípus ecs#:#ecs_tbl_settings_for_server#:#ECS beállítások ehhez: %s ecs#:#ecs_title_updates#:#Átvitelcím frissítések ecs#:#ecs_token_mechanism#:#Token hitelesítés -ecs#:#ecs_token_mechanism_info#:#Ha be van kapcsolva, az ECS-Token-Eljárás végzi a hitelesítést a távoli objektumok szerverplatformján. +ecs#:#ecs_token_mechanism_info#:#Az ECS-Token-Eljárás végzi a hitelesítést a távoli objektumok szerverplatformján. ecs#:#ecs_tree_updates#:#Átvitelfa frissítések ecs#:#ecs_tst_export#:#Tesztkiadások ecs#:#ecs_tst_export_disabled#:#Ne legyen kiadva ez a teszt @@ -9209,49 +9232,51 @@ ecs#:#ecs_wiki_export_enabled#:#Ezen wiki kiadása ecs#:#ecs_wiki_export_obj_settings#:#Wikikiadás beállításai error#:#error_back_to_repository#:#Vissza a Tartalomtárba error#:#error_sry_error#:#Sajnáljuk, hiba történt. -etal#:#appointments#:#Appointments -etal#:#cal_type_tals#:#Talks -etal#:#change_date_of_series#:#Change date of talk series -etal#:#change_date_of_talk#:#Change date of talk -etal#:#date_of_talk#:#Start Date -etal#:#etal_add#:#Add Talk -etal#:#etal_add_new_item#:#Add new Talk -etal#:#etal_create_invalid_template_ref#:#Invalid Talk Template ID###26 08 2024 new variable -etal#:#etal_date_appointment_edit#:#Date of Talk -etal#:#etal_date_series_edit#:#Date of Talk Series -etal#:#etal_delete_confirmation_msg#:#Are you sure that you want to delete the following talk?###26 08 2024 new variable -etal#:#etal_edit#:#General -etal#:#etal_invalid_user#:#This user either does not exist or can't be invited.###26 08 2024 new variable -etal#:#etal_location#:#Location###29 10 2025 new variable -etal#:#etal_new#:#New Talk -etal#:#etal_open#:#Open Employee Talk -etal#:#etal_recurrence#:#Recurrence###29 10 2025 new variable -etal#:#etal_status_all#:#All -etal#:#etal_status_completed#:#Completed -etal#:#etal_status_pending#:#Pending -etal#:#etal_unknown_username#:#Unknown User -etal#:#lock_edititng_for_others#:#Lock editing for others -etal#:#meta_adv_records#:#Metadata -etal#:#mm_org_etal#:#Talks -etal#:#mm_talk_template#:#Talk Templates -etal#:#notification_talks_created#:#You have been invited by %s to the following employee talks. -etal#:#notification_talks_date_list_header#:#Dates -etal#:#notification_talks_removed#:#The following appointments have been canceled by %s. -etal#:#notification_talks_subject#:#Invitation -etal#:#notification_talks_subject_update#:#Update: %s###26 08 2024 new variable -etal#:#notification_talks_updated#:#The following talk appointments have been changed by %s. -etal#:#pending_talks_warning#:#The following pending talk appointments will be replaced:###26 08 2024 new variable -etal#:#tala_no_content_without_admin_info#:#The Administrator role is required for access to Talk Templates.###29 10 2025 new variable -etal#:#talk_serial#:#Talk Serial -etal#:#tals_add#:#Add Talks -etal#:#tals_new#:#New Talks -etal#:#talt_activation_online_info#:#Set the talk template online to make it visible and available for employees. If not, only administrators will have access to it. -etal#:#talt_add#:#Add Template -etal#:#talt_edit#:#General -etal#:#talt_etal#:#Employee Talk -etal#:#talt_new#:#New Talk Template -etal#:#will_update_series_info_lock#:#Lock the editing of all appointments in this series###26 08 2024 new variable -etal#:#will_update_series_info_title#:#Changes to the title will be made to all appointments in this series.###26 08 2024 new variable +error#:#http_404_not_found#:#A kért oldal nem található. +error#:#http_500_internal_server_error#:#Belső szerverhiba történt. +etal#:#appointments#:#Találkozók +etal#:#cal_type_tals#:#Megbeszélések +etal#:#change_date_of_series#:#Megbeszéléssorozat dátumának módosítása +etal#:#change_date_of_talk#:#Megbeszélés dátumának módosítása +etal#:#date_of_talk#:#Megbeszélés dátuma +etal#:#etal_add#:#Megbeszélés hozzáadása +etal#:#etal_add_new_item#:#Új Megbeszélés hozzáadása +etal#:#etal_create_invalid_template_ref#:#Érvénytelen Megbeszéléssablon ID +etal#:#etal_date_appointment_edit#:#Megbeszélés dátuma +etal#:#etal_date_series_edit#:#Megbeszéléssorozat dátuma +etal#:#etal_delete_confirmation_msg#:#Biztos, hogy törli az alábbi megbeszélést? +etal#:#etal_edit#:#Általános +etal#:#etal_invalid_user#:#A felhasználó nem létezik vagy nem hívható meg. +etal#:#etal_location#:#Helyszín +etal#:#etal_new#:#Új Talk +etal#:#etal_open#:#Munkavállalói megbeszélés megnyitása +etal#:#etal_recurrence#:#Ismétlődés +etal#:#etal_status_all#:#Összes +etal#:#etal_status_completed#:#Befejezve +etal#:#etal_status_pending#:#Függőben +etal#:#etal_unknown_username#:#Ismeretlen felhasználó +etal#:#lock_edititng_for_others#:#Szerkesztés zárolása a többeiknél +etal#:#meta_adv_records#:#Metaadat +etal#:#mm_org_etal#:#Megbeszélés +etal#:#mm_talk_template#:#Megbeszéléssablonok +etal#:#notification_talks_created#:#Önt meghívták a következő munkavállalói megbeszélésre. +etal#:#notification_talks_date_list_header#:#Dátumok +etal#:#notification_talks_removed#:#Az alábbi találkozókat törölték. +etal#:#notification_talks_subject#:#Meghívás: %s +etal#:#notification_talks_subject_update#:#Módosítás: %s +etal#:#notification_talks_updated#:#Az alábbi találkozókat módosították. +etal#:#pending_talks_warning#:#A következő függőben lévő megbeszéléseket cseréljük le: +etal#:#tala_no_content_without_admin_info#:#Az Administrator szerepkörnek hozzáféréssel kell rendelkezni a Megbeszéléssablonokhoz. +etal#:#talk_serial#:#Megbeszéléssorozat +etal#:#tals_add#:#Megbeszélés hozzáadása +etal#:#tals_new#:#Új Megbeszélés +etal#:#talt_activation_online_info#:#Állítsa be a megbeszéléssablont onlinera, hogy láthatóvá és elérhetővé tegye az alkalmazottak számára. Ha nem, akkor csak a rendszergazdák férhetnek hozzá. +etal#:#talt_add#:#Sablon hozzáadása +etal#:#talt_edit#:#Általános +etal#:#talt_etal#:#Munkavállalói megbeszélés +etal#:#talt_new#:#Új Megbeszéléssablon +etal#:#will_update_series_info_lock#:#A sorozat összes időpontjának szerkesztésének zárolása +etal#:#will_update_series_info_title#:#A sorozat összes talákozójának címének módosítása. exc#:#exc_add_assignment#:#Feladat létrehozása exc#:#exc_add_criteria#:#Szempont hozzáadása exc#:#exc_add_criteria_catalogue#:#Szempontgyűjtemény hozzáadása @@ -9260,15 +9285,15 @@ exc#:#exc_add_participant#:#Résztvevő hozzáadása exc#:#exc_adopt_group_teams#:#Csapatok átemelése a csoportokból exc#:#exc_adopt_group_teams_added#:#%s felhasználót sikeresen hozzáadta. exc#:#exc_adopt_group_teams_blocked#:#%s felhasználót már hozzárendelték. -exc#:#exc_adopt_group_teams_conflict#:#'%1$s' felhasználót a(z) '%2$s' csoporthoz már kiválasztotta. +exc#:#exc_adopt_group_teams_conflict#:#‘%1$s’ felhasználót a(z) ‘%2$s’ csoporthoz már kiválasztotta. exc#:#exc_adopt_group_teams_no_members#:#Nincsenek tagok exc#:#exc_after_submission#:#Beküldés után -exc#:#exc_all#:#All###26 08 2024 new variable +exc#:#exc_all#:#Összes exc#:#exc_all_new_files_offered_already#:#Az összes új fájlt már felkínáltuk letöltésre. További letörléshez kattintson az alul lévő Műveletek lehetőségre. exc#:#exc_ass_submission_zip#:#Beadott megoldások exc#:#exc_ass_team_wiki#:#Csatlakozás wikicsapathoz exc#:#exc_assignment#:#Feladat -exc#:#exc_assignment_list#:#Assignments List###26 08 2024 new variable +exc#:#exc_assignment_list#:#Feladatok felsorolása exc#:#exc_assignment_type#:#Beadás módja exc#:#exc_assignment_view#:#Feladatnézet exc#:#exc_assignments#:#Feladatok @@ -9276,14 +9301,14 @@ exc#:#exc_assignments_deleted#:#A feladatokat sikeresen törölte. exc#:#exc_blog_created#:#Sikeresen létrehozott egy blogot. exc#:#exc_blog_returned#:#Hozzárendelt blog exc#:#exc_blog_selected#:#A blogot sikeresen hozzárendelte. -exc#:#exc_cannot_submit_any_files#:#You cannot submit any files anymore.###29 10 2025 new variable +exc#:#exc_cannot_submit_any_files#:#Ezentúl nem adhat be fájlt. exc#:#exc_chars_remaining#:#Fennmaradó karakterszám: exc#:#exc_comment_for_learner_edit#:#Megjegyzés írása exc#:#exc_comment_for_learner_info#:#Értesítést küldünk a felhasználónak, valamint a visszajelzés bekerül a felhasználó feladatnézetébe. exc#:#exc_compare_selected_submissions#:#A kiválasztott beküldések összehasonlítása exc#:#exc_compare_submissions#:#Beadások összehasonlítása exc#:#exc_completion_by_submission#:#Teljesítve elküldéssel -exc#:#exc_completion_by_submission_info#:#Ha be van kapcsolva, legalább egy fájl elküldése ennek a feladatnak a teljesítését jelenti a maximális pontszám megszerzésével. A pont a későbbiekben manuálisan módosítható. Ennek a beállításnak a bekapcsolása nincs hatással a már beküldött megoldásokra. +exc#:#exc_completion_by_submission_info#:#Legalább egy fájl elküldése ennek a feladatnak a teljesítését jelenti a maximális pontszám megszerzésével. A pont a későbbiekben manuálisan módosítható. Ennek a beállításnak a bekapcsolása nincs hatással a már beküldött megoldásokra. exc#:#exc_completion_by_tutor#:#Csak manuálisan a tutor exc#:#exc_conf_del_assignments#:#Biztos, hogy törli az alábbi feladatokat? exc#:#exc_copy#:#Beadandó feladat másolása @@ -9314,8 +9339,8 @@ exc#:#exc_deadline#:#Határidő exc#:#exc_deadline_ext_mismatch#:#A türelmi időszaknak a határidő után kell véget érnie! exc#:#exc_deadline_extended#:#Türelmi időszak exc#:#exc_deadline_extended_info#:#A határidő és a türelmi idő között késői beadások lehetségesek. -exc#:#exc_deadline_not_set_yet#:#Not Set Yet###26 08 2024 new variable -exc#:#exc_deadline_requested#:#Requested###26 08 2024 new variable +exc#:#exc_deadline_not_set_yet#:#Még nincs beállítva +exc#:#exc_deadline_requested#:#Kötelező exc#:#exc_delete_team#:#Csapat törlése exc#:#exc_deleted_user#:#Törölt felhasználó exc#:#exc_denied_has_peer_reviews#:#Ok: néhány feladathoz aktiválták a tanulói visszajelzést. @@ -9326,17 +9351,17 @@ exc#:#exc_direct_submit#:#Jóváhagyás exc#:#exc_direct_submit_blog#:#Szeretné most elküldeni a blog jelenlegi verzióját? Ezt a későbbiekben is bármikor megteheti a blogszerkesztőből. exc#:#exc_direct_submit_portfolio#:#Szeretné most elküldeni a portfólió jelenlegi verzióját? Ezt a későbbiekben is bármikor megteheti a portfóliószerkesztőből. exc#:#exc_down_files_started_bg#:#A beküldött fájlok letöltése megkezdődött. Kérem, ellenőrizze a háttérfolyamatokat a jobb felső sarokban. -exc#:#exc_download_selected#:#Download Selected Submission###26 08 2024 new variable +exc#:#exc_download_selected#:#Kiválasztott beadások leadása exc#:#exc_download_zip_structure#:#ZIP-mappastruktúra letöltése exc#:#exc_earliest_start_time#:#Legkorábbi kezdési idő exc#:#exc_edit_assignment#:#Feladat módosítása exc#:#exc_edit_assignments#:#Feladatok módosítása -exc#:#exc_edit_blog#:#Edit Blog###26 08 2024 new variable +exc#:#exc_edit_blog#:#Blog módosítása exc#:#exc_edit_criterias#:#Szempont módosítása -exc#:#exc_edit_portfolio#:#Edit Portfolio###26 08 2024 new variable +exc#:#exc_edit_portfolio#:#Portfólió módosítása exc#:#exc_edit_submission#:#Megoldás módosítása -exc#:#exc_edit_wiki#:#Edit Wiki###26 08 2024 new variable -exc#:#exc_ended#:#Ended###26 08 2024 new variable +exc#:#exc_edit_wiki#:#Wiki módosítása +exc#:#exc_ended#:#Befejezve exc#:#exc_ended_on#:#Lezárva exc#:#exc_export_excel#:#Exportálás Excel (.xls) fájlba exc#:#exc_fb_files#:#Értékelésfájlok @@ -9345,16 +9370,16 @@ exc#:#exc_feedback#:#Tutori értékelés exc#:#exc_feedback_notification_body#:#ezúton értesítjük, hogy az alábbi feltöltéséhez új visszajelzés érkezett. exc#:#exc_feedback_notification_link#:#Link a beadandó feladathoz exc#:#exc_feedback_notification_reason#:#Ezt a levelet azért kapta, mert fent említett beadandó feladatnak résztvevője. -exc#:#exc_feedback_notification_subject#:#'%s' beadandó feladathoz visszajelzés +exc#:#exc_feedback_notification_subject#:#‘%s’ beadandó feladathoz visszajelzés exc#:#exc_files_returned_text#:#Hozzárendelt szöveg exc#:#exc_find_zip_error#:#A beküldés nem nyitható meg. Az eredeti fájl nem található. exc#:#exc_fixed_date#:#Megadott dátum -exc#:#exc_fixed_date_individual#:#Individual Deadlines Only###26 08 2024 new variable -exc#:#exc_fixed_date_individual_info#:#There is no common deadline. Tutors must set individual deadlines for each participant individually.###26 08 2024 new variable +exc#:#exc_fixed_date_individual#:#Csak egyéni határidők +exc#:#exc_fixed_date_individual_info#:#Nincs általános határidő, minden résztvevőnek egyéni határidőt kell beállítani. exc#:#exc_fixed_date_info#:#Az összes felhasználónak ugyanaz a határidő. -exc#:#exc_fullscreen#:#Fullscreen###29 07 2022 new variable -exc#:#exc_future#:#Upcoming###26 08 2024 new variable -exc#:#exc_given_feedback#:#Given Feedback###26 08 2024 new variable +exc#:#exc_fullscreen#:#Teljes képernyő +exc#:#exc_future#:#Közelgő +exc#:#exc_given_feedback#:#Elküldött visszajelzések exc#:#exc_global_feedback_file#:#Mintamegoldás exc#:#exc_global_feedback_file_after_date#:#Megadott dátum után exc#:#exc_global_feedback_file_cron#:#Értesítés @@ -9363,24 +9388,25 @@ exc#:#exc_global_feedback_file_date#:#Elérhető exc#:#exc_global_feedback_file_date_deadline#:#Határidő után exc#:#exc_global_feedback_file_date_upload#:#Beadás után exc#:#exc_go_to_exercise#:#Ugrás a feladathoz -exc#:#exc_graded_mem_notified#:#All graded participants have been notified.###26 08 2024 new variable +exc#:#exc_graded_mem_notified#:#Az összes értékelt résztvevőt értesítettük. exc#:#exc_grades#:#Értékelések exc#:#exc_grades_overview#:#Értékelések exc#:#exc_hand_in#:#Beadás -exc#:#exc_hand_in_lead_text#:#%s to Submit###26 08 2024 new variable -exc#:#exc_idl_request_and_tutor_needed#:#Please send a request to your tutor for setting an individual deadline for you.###26 08 2024 new variable -exc#:#exc_idl_tutor_needed#:#You already requested a deadline. The request is still pending. You will be notified once the individual deadline is set.###26 08 2024 new variable +exc#:#exc_hand_in_lead_text#:#%s a beadásig +exc#:#exc_idl_request_and_tutor_needed#:#Kérem, írjon egy üzenetet a tutornak, hogy állítson be egyéni határidőt. +exc#:#exc_idl_tutor_needed#:#Már kért határidőt, kérése még függőben van. Értesítjük, amint beállítják határidejét. exc#:#exc_import#:#Beadandó feladat importálása exc#:#exc_individual_deadline#:#Egyéni határidő exc#:#exc_individual_deadline_action#:#Egyéni határidő beállításai exc#:#exc_individual_deadline_before_global#:#Ennek az időpontnak a legutolsó határidőnél későbbre kell esnie: %s. exc#:#exc_instruction_files#:#Utasításfájlok -exc#:#exc_instruction_migration_not_run#:#The instruction file migration has not been finished yet. Please contact your system administrator.###26 08 2024 new variable +exc#:#exc_instruction_migration_not_run#:#Az utasításfájl migrációja még nem készült el. Kérem, keresse a rendszerüzemeltetőt. exc#:#exc_late_submission#:#Késői beadás exc#:#exc_late_submission_warning#:#%s utáni beadások későinek lesznek megjelölve. -exc#:#exc_lead_request_idl#:#Request Deadline###26 08 2024 new variable -exc#:#exc_lead_wait_for_idl#:#Waiting For Individual Deadline###26 08 2024 new variable +exc#:#exc_lead_request_idl#:#Határidő kérése +exc#:#exc_lead_wait_for_idl#:#Várakozás az egyéni határidőre exc#:#exc_limit_characters#:#Karakterszám korlátozása +exc#:#exc_link_to_assignment#:#Link a feladathoz exc#:#exc_list_submission#:#Az összes megoldás módosítása exc#:#exc_list_text_assignment#:#Összes beadott megjelenítése exc#:#exc_mail_context_grade_reminder_info#:#A feladat értékelésére hívja fel a tutor/oktató figyelmét @@ -9408,46 +9434,46 @@ exc#:#exc_min_nr#:#Feladatok száma exc#:#exc_min_nr_info#:#Ez az érték a kötelező feladatok számánál nem lehet kisebb. exc#:#exc_min_team_participants#:#Minimális szám exc#:#exc_msg_all_mandatory_ass#:#Minden kötelező feladatot meg kell oldania a beadandó feladat teljesítéséhez. -exc#:#exc_msg_deadline_request_body#:#the following user requested an individual deadline.###26 08 2024 new variable -exc#:#exc_msg_deadline_request_subject#:#A deadline has been requested in exercise "%s".###26 08 2024 new variable +exc#:#exc_msg_deadline_request_body#:#az alábbi felhasználók kértek egyéni határidőt. +exc#:#exc_msg_deadline_request_subject#:#‘%s’ beadandó feladathoz határidőt kértek exc#:#exc_msg_failed_mandatory#:#Nem sikerült legalább egy kötelező feladat. -exc#:#exc_msg_grading_done#:#An assignment has been graded in exercise "%s".###26 08 2024 new variable -exc#:#exc_msg_grading_done_body#:#a tutor has graded your submission in exercise "%s".###26 08 2024 new variable -exc#:#exc_msg_idl_set_body#:#a new individual deadline has been set.###26 08 2024 new variable -exc#:#exc_msg_idl_set_subject#:#A new deadline has been set in exercise "%s".###26 08 2024 new variable +exc#:#exc_msg_grading_done#:#‘%s’ beadandó feladatban egyy értékelés született +exc#:#exc_msg_grading_done_body#:#‘%s’ beadandó feladatban értékelést kapott +exc#:#exc_msg_idl_set_body#:#új egyéni határidőt állítottak be. +exc#:#exc_msg_idl_set_subject#:#‘%s’ beadandó feladatban új határidőt állítottak be. exc#:#exc_msg_min_number_ass#:#Legalább %s feladatot kell megoldania a beadandó feladat teljesítéséhez. exc#:#exc_msg_missed_minimum_number#:#Nem oldotta meg a minimális számú feladatot. -exc#:#exc_msg_new_feedback_file_uploaded#:#'%s' beadandó feladathoz új visszajelzésfájl +exc#:#exc_msg_new_feedback_file_uploaded#:#‘%s’ beadandó feladathoz új visszajelzésfájl exc#:#exc_msg_new_feedback_file_uploaded2#:#ezúton tájékoztatjuk, hogy új visszajelzésfájlt töltöttek fel az Ön megoldásához. -exc#:#exc_msg_new_feedback_text_uploaded#:#'%s' beadandó feladathoz új megjegyzés jött létre +exc#:#exc_msg_new_feedback_text_uploaded#:#‘%s’ beadandó feladathoz új megjegyzés jött létre exc#:#exc_msg_new_feedback_text_uploaded2#:#ezúton tájékoztatjuk, hogy egy tutor megjegyzést írt Önnek. -exc#:#exc_msg_new_message_from_pf_giver#:#A new message from a peer feedback giver has been added to exercise "%s".###26 08 2024 new variable -exc#:#exc_msg_new_message_from_pf_giver2#:#a peer feedback giver has added a new message for you:###26 08 2024 new variable -exc#:#exc_msg_new_message_from_pf_recipient#:#A new message from a peer feedback recipient has been added to exercise "%s".###26 08 2024 new variable -exc#:#exc_msg_new_message_from_pf_recipient2#:#a peer feedback recipient has added a new message for you:###26 08 2024 new variable +exc#:#exc_msg_new_message_from_pf_giver#:#‘%s’ feladathoz egy visszajelző üzenetet küldött. +exc#:#exc_msg_new_message_from_pf_giver2#:#Egy visszajelző üzenetet küldött Önnek: +exc#:#exc_msg_new_message_from_pf_recipient#:#‘%s’ feladathoz egy visszajelzett üzenetet küldött. +exc#:#exc_msg_new_message_from_pf_recipient2#:#egy visszajelzett üzenetet küldött Önnek: exc#:#exc_msg_participants_removed#:#A résztvevőket eltávolítottuk a beadandó feladatból. exc#:#exc_msg_public_submission#:#Összes megoldást publikáltuk a határidő után. exc#:#exc_msg_saved_grades#:#Az értékeléseket és a megjegyzéseket mentettük. exc#:#exc_msg_sure_to_deassign_participant#:#Biztos, hogy eltávolítja a résztvevőket a beadandó feladat összes feladatából? Ezzel törli a megoldásaikat is! -exc#:#exc_multi_feedb_info#:#Ezen az oldalon több visszajelzést tölthet fel egy fájlban. Először kattintson a 'ZIP-mappastruktúra letöltése' gombra, mentse és csomagolja ki a fájlt a saját gépéden. Helyezze a visszajelzés-fájlokat a megfelelő felhasználó-mappákba. Csomagolja be az egész mappát ZIP-fájl-ba. A 'Többszörös fájl-visszajelzés' alatt tallózza ki ezt a ZIP-fájlt, majd kattintson a 'Feltöltés' gombra, végül mentse a visszajelzés-fájlokat. Ne használjon speciális karaktereket a fájlnevekben. +exc#:#exc_multi_feedb_info#:#Ezen az oldalon több visszajelzést tölthet fel egy fájlban. Először kattintson a ‘ZIP-mappastruktúra letöltése’ gombra, mentse és csomagolja ki a fájlt a saját gépéden. Helyezze a visszajelzés-fájlokat a megfelelő felhasználó-mappákba. Csomagolja be az egész mappát ZIP-fájl-ba. A ‘Többszörös fájl-visszajelzés’ alatt tallózza ki ezt a ZIP-fájlt, majd kattintson a ‘Feltöltés’ gombra, végül mentse a visszajelzés-fájlokat. Ne használjon speciális karaktereket a fájlnevekben. exc#:#exc_multi_feedback#:#Több résztvevő értékelése exc#:#exc_multi_feedback_file#:#Többszörös-visszajelző fájl exc#:#exc_multi_feedback_files#:#Többszörös-visszajelző fájlok exc#:#exc_needs_deadline#:#Ez a funkció csak hozzárendelt határidővel működik. exc#:#exc_needs_fixed_deadline#:#Ez a funkció csak megadott dátum esetén működik. exc#:#exc_new_assignment#:#Új feladat -exc#:#exc_no_assignments#:#No assignments available.###26 08 2024 new variable -exc#:#exc_no_assignments_available#:#Nincs még összerendelés. Nyissa meg az 'Összerendelés'-t és a 'Szerkesztés'-t az első összerendelés létrehozásához. -exc#:#exc_no_deadline#:#No Deadline###26 08 2024 new variable -exc#:#exc_no_deadline_info#:#There is no submission deadline for participants.###26 08 2024 new variable +exc#:#exc_no_assignments#:#Nincsenek beaadandó feladatok. +exc#:#exc_no_assignments_available#:#Nincs még összerendelés. Nyissa meg az ‘Összerendelés’-t és a ‘Szerkesztés’-t az első összerendelés létrehozásához. +exc#:#exc_no_deadline#:#Nincs határidő +exc#:#exc_no_deadline_info#:#A résztvevőknek nincs határidő a feladat beadására. exc#:#exc_no_deadline_specified#:#Nincs megadva határidő. exc#:#exc_no_feedback_dir_found_in_zip#:#A feltöltött ZIP-archívum fájl mappaszerkezetét nem lehet feldolgozni. exc#:#exc_no_get_target#:#Egy valós célt még nem küldött el. -exc#:#exc_no_graded_mem_selected#:#Please select at least one graded participant.###26 08 2024 new variable +exc#:#exc_no_graded_mem_selected#:#Válaaszon legalább egy értékelt résztvevőt. exc#:#exc_no_participants#:#Jelenleg nincsenek résztvevők. -exc#:#exc_no_peer_feedback_deadline#:#No Deadline for Giving Feedback###26 08 2024 new variable +exc#:#exc_no_peer_feedback_deadline#:#Nincs határidő visszajelzés küldésére exc#:#exc_no_portfolio_templates#:#Egy portfóliósablon sem érhető el. -exc#:#exc_no_submission_yet#:#No submission yet.###26 08 2024 new variable +exc#:#exc_no_submission_yet#:#Még nem adta be senki. exc#:#exc_no_team_yet#:#Nincs csapathoz hozzárendelve exc#:#exc_no_team_yet_info#:#Létrehozhat saját magának egy csapatot, vagy meglévő csapathoz hozzáadhatják annak tagjai. exc#:#exc_no_team_yet_info_tutor#:#A beadandó feladat tutorai kezelik a csapatokat. @@ -9456,8 +9482,8 @@ exc#:#exc_note_for_tutor#:#Megjegyzés a tutornak exc#:#exc_notification#:#Személyes értesítés exc#:#exc_nr_random_mand#:#Kötelező hozzárendelések száma exc#:#exc_num_teams#:#Szám -exc#:#exc_ongoing#:#Ongoing###26 08 2024 new variable -exc#:#exc_optional#:#Optional###26 08 2024 new variable +exc#:#exc_ongoing#:#Folyamatban lévő +exc#:#exc_optional#:#Választható exc#:#exc_order_by_deadline#:#Rendezés határidő szerint exc#:#exc_overview#:#Áttekintés exc#:#exc_participant#:#Résztvevő @@ -9469,20 +9495,21 @@ exc#:#exc_pass_minimum_nr#:#Feladatok minimális száma exc#:#exc_pass_minimum_nr_info#:#a beadandó feladat teljesítéséhez minimálisan ennyi feladatot kell megoldani. Ez a szám egyenlő vagy magasabb kell legyen, mint a kötelező feladatok száma. exc#:#exc_pass_mode#:#Beadandó feladat befejezettsége exc#:#exc_pass_mode_not_changeable_info#:#A kitöltés módja már nem módosítható. -exc#:#exc_passed_status_determination#:#'Sikeresen teljesítette' állapot meghatározása +exc#:#exc_passed_status_determination#:#‘Sikeresen teljesítette’ állapot meghatározása exc#:#exc_passing_exc#:#Beadandó feladat teljesítése -exc#:#exc_past#:#Past###26 08 2024 new variable +exc#:#exc_past#:#Elmúlt exc#:#exc_peer_deadline_mismatch#:#Hogy visszajelzést lehessen küldeni, a visszajelzés határideje nem lehet korábbi, mint a feladata beadási határideje. +exc#:#exc_peer_feedback_status#:#Visszajelzés állapota exc#:#exc_peer_review#:#Tanulói visszajelzés -exc#:#exc_peer_review_ass_setting_info#:#Felhasználók értékelhetik a társaik megoldását a határidő után és amennyiben létezik türelmi idő, annak lejárta után. A visszajelzés néhány tulajdonságát az adott fülön lehet beállítani. Ezen opció aktiválása és mentése után megjelenik a 'Visszajelzés' fül. +exc#:#exc_peer_review_ass_setting_info#:#Felhasználók értékelhetik a társaik megoldását a határidő után és amennyiben létezik türelmi idő, annak lejárta után. A visszajelzés néhány tulajdonságát az adott lapon lehet beállítani. Ezen opció aktiválása és mentése után megjelenik a ‘Visszajelzés’ lap. exc#:#exc_peer_review_chars_invalid#:#Visszajelzésének hossza nem éri a szükséges %s karaktert. -exc#:#exc_peer_review_completion#:#'Sikeresen megfelelt' állapot meghatározása +exc#:#exc_peer_review_completion#:#‘Sikeresen megfelelt’ állapot meghatározása exc#:#exc_peer_review_completion_all#:#Az összes szükséges visszajelzés -exc#:#exc_peer_review_completion_all_info#:#A beadandó feladat automatikusan 'Sikeresen teljesítette' lesz a megoldás beadása és az összes szükséges visszajelzés beérkezése után. +exc#:#exc_peer_review_completion_all_info#:#A beadandó feladat automatikusan ‘Sikeresen teljesítette’ lesz a megoldás beadása és az összes szükséges visszajelzés beérkezése után. exc#:#exc_peer_review_completion_none#:#Nem szükséges a tanulói visszajelzés -exc#:#exc_peer_review_completion_none_info#:#A beadandó feladat automatikusan 'Sikeresen teljesítette' lesz a megoldás beadása után, attól függetlenül,hogy érkezett-e visszajelzés vagy sem. +exc#:#exc_peer_review_completion_none_info#:#A beadandó feladat automatikusan ‘Sikeresen teljesítette’ lesz a megoldás beadása után, attól függetlenül,hogy érkezett-e visszajelzés vagy sem. exc#:#exc_peer_review_completion_one#:#Legalább egy visszajelzés -exc#:#exc_peer_review_completion_one_info#:#A beadandó feladat automatikusan 'Sikeresen teljesítette' lesz a megoldás beadása és egy visszajelzés beérkezése után. +exc#:#exc_peer_review_completion_one_info#:#A beadandó feladat automatikusan ‘Sikeresen teljesítette’ lesz a megoldás beadása és egy visszajelzés beérkezése után. exc#:#exc_peer_review_deadline#:#Visszajelzés határideje exc#:#exc_peer_review_deadline_info#:#Visszajelzés eddig az időpontig adható, és a kapott visszajelzés is csak ekkortól elérhető el. exc#:#exc_peer_review_deadline_info_button#:#Határidő: %s @@ -9513,17 +9540,17 @@ exc#:#exc_peer_review_rating#:#5 csillagos értékelés exc#:#exc_peer_review_recipient#:#Visszajelzés címzettje exc#:#exc_peer_review_reset#:#Törlése, és a visszajelzések alapértelmezettre állítása exc#:#exc_peer_review_reset_done#:#Az összes visszajelzéssel kapcsolatos adatot sikeresen törölte. -exc#:#exc_peer_review_reset_sure#:#Biztos, hogy törli '%s' összes visszajelzését? +exc#:#exc_peer_review_reset_sure#:#Biztos, hogy törli ‘%s’ összes visszajelzését? exc#:#exc_peer_review_show#:#Beérkezett visszajelzések megjelenítése exc#:#exc_peer_review_show_missing#:#Még nem tekintheti meg a kapott visszajelzéseit, mert még nem adott elegendő számú visszajelzést. exc#:#exc_peer_review_show_received_none#:#Még egy visszajelzést sem kapott. exc#:#exc_peer_review_simple_unlock#:#Hozzáférés a kapott visszajelzésekhez exc#:#exc_peer_review_simple_unlock_active#:#Legalább egy érvényes visszajelzés beérkezése után. -exc#:#exc_peer_review_simple_unlock_immed#:#Always show received peer feedback###26 08 2024 new variable +exc#:#exc_peer_review_simple_unlock_immed#:#A kapott visszajelzések mindig látszódjanak. exc#:#exc_peer_review_simple_unlock_inactive#:#Az összes szükséges visszajelzés beérkezése után. exc#:#exc_peer_review_text#:#Szöveg exc#:#exc_peer_review_updated#:#Visszajelzését mentettük. -exc#:#exc_peer_reviews_in_lead_text#:#%s to Give Feedback###26 08 2024 new variable +exc#:#exc_peer_reviews_in_lead_text#:#%s visszajelzést küldéeni exc#:#exc_peer_reviews_invalid_warning#:#Érvénytelen visszajelző csoportok exc#:#exc_portfolio_created#:#Sikeresen létrehozott egy portfóliót. exc#:#exc_portfolio_returned#:#Hozzárendelt portfólió @@ -9531,7 +9558,7 @@ exc#:#exc_portfolio_selected#:#A portfóliót sikeresen hozzárendelte. exc#:#exc_portfolio_template#:#Portfóliósablon exc#:#exc_portfolio_unlinked_from_assignment#:#A portfóliót sikeresen eltávolította a hozzárendelésből exc#:#exc_presentation_order#:#Megjelenítési sorrend -exc#:#exc_print_pdf#:#Print/PDF###29 07 2022 new variable +exc#:#exc_print_pdf#:#Nyomtatás/PDF exc#:#exc_public_submission#:#Nyilvános megoldások exc#:#exc_publishing#:#Közzététel exc#:#exc_rand_nr_mandatory#:#Kötelező feladatok száma @@ -9542,14 +9569,14 @@ exc#:#exc_random_assignment_info#:#A feladat indulásakor néhány hozzárendelt exc#:#exc_random_selection#:#Véletlenszerű kiválasztás exc#:#exc_random_selection_info#:#Az összes felhasználóhoz véletlenszerűen rendelünk kötelező feladatokat. exc#:#exc_random_selection_not_changeable_info#:#Ez a mód nem aktiválható. -exc#:#exc_received_feedback#:#Received Feedbacks###26 08 2024 new variable +exc#:#exc_received_feedback#:#Beérkezett visszajelzések exc#:#exc_rel_last_submission#:#Utolsó lehetséges beadás exc#:#exc_rel_last_submission_info#:#Ha ez az opcionális dátum be van állítva, eddig a határidőig az összes felhasználónak be kell adnia a megoldását. -exc#:#exc_rel_start_latest_lead_text#:#%s the Latest###26 08 2024 new variable -exc#:#exc_rel_start_lead_text#:#Submit %s Days After Start###26 08 2024 new variable +exc#:#exc_rel_start_latest_lead_text#:#%s a legkésőbbi +exc#:#exc_rel_start_lead_text#:#Submit %s nappal a kezdés után exc#:#exc_relative_date#:#Relatív Dátum exc#:#exc_relative_date_info#:#Az összes felhasználónál a feladat megkezdésétől számítjuk a határidőt. -exc#:#exc_relative_date_period#:#Working Time###26 08 2024 new variable +exc#:#exc_relative_date_period#:#Munkaidő exc#:#exc_rem_time_after_start#:#Hátralévő idő exc#:#exc_reminder_cron_ok#:#Emlékeztető kiküldve: exc#:#exc_reminder_end#:#Emlékeztetők vége @@ -9558,23 +9585,23 @@ exc#:#exc_reminder_feedback_start#:#Emlékeztetők indítása a visszajelzés ha exc#:#exc_reminder_frequency#:#Gyakoriság exc#:#exc_reminder_grade_body#:#ezúton értesítem, hogy az alábbi feladatokat még nem értékelte exc#:#exc_reminder_grade_setting#:#A tutorok emlékeztetése az értékelésre -exc#:#exc_reminder_grade_subject#:#'%s' feladatot még nem értékelte +exc#:#exc_reminder_grade_subject#:#‘%s’ feladatot még nem értékelte exc#:#exc_reminder_link#:#URL exc#:#exc_reminder_mail_no_tpl#:#Levélsablon használata nélkül exc#:#exc_reminder_mail_template#:#Levélsablon exc#:#exc_reminder_peer_body#:#ezúton értesítem, hogy az alábbi feladatokra még nem jelzett vissza -exc#:#exc_reminder_peer_subject#:#'%s' feladatra még nem jelzett vissza +exc#:#exc_reminder_peer_subject#:#‘%s’ feladatra még nem jelzett vissza exc#:#exc_reminder_salutation#:#Tisztelt %s, exc#:#exc_reminder_start#:#Emlékeztetők indítása a határidő előtt -exc#:#exc_reminder_start_info#:#A szülőkurzus/-csoport összes tagjának küldünk emlékeztetőket.
    Egy szülőkurzus/-csoport sincs - egy emlékeztetőt sem fogunk küldeni! +exc#:#exc_reminder_start_info#:#A szülőkurzus/-csoport összes tagjának küldünk emlékeztetőket.
    Egy szülőkurzus/-csoport sincs - egy emlékeztetőt sem fogunk küldeni! exc#:#exc_reminder_submit_body#:#ezúton értesítem, hogy az alábbi feladatokat még nem fejezte be exc#:#exc_reminder_submit_setting#:#Felhasználók emlékeztetése a beküldésre -exc#:#exc_reminder_submit_subject#:#'%s' feladatot még nem fejezte be +exc#:#exc_reminder_submit_subject#:#‘%s’ feladatot még nem fejezte be exc#:#exc_reminders_cron#:#Emlékeztetés a feladatokra -exc#:#exc_reminders_cron_info#:#Ha be van kapcsolva, 3 emlékeztető lesz aktív: felhasználókat a beadásra, tutorokat az értékelésére és résztvevőket a visszajelzésre. -exc#:#exc_request_deadline#:#Request Deadline###26 08 2024 new variable -exc#:#exc_requirement#:#Requirement###26 08 2024 new variable -exc#:#exc_review_anytime#:#Give Feedback Anytime###26 08 2024 new variable +exc#:#exc_reminders_cron_info#:#3 emlékeztető lesz aktív: felhasználókat a beadásra, tutorokat az értékelésére és résztvevőket a visszajelzésre. +exc#:#exc_request_deadline#:#Határidő kérése +exc#:#exc_requirement#:#Követelmény +exc#:#exc_review_anytime#:#Visszajelzés küldése tetszőleges időpontban exc#:#exc_save_all#:#Összes mentése exc#:#exc_save_order#:#Sorrend mentése exc#:#exc_save_selected#:#Kijelöltek mentése @@ -9583,15 +9610,15 @@ exc#:#exc_select_ass#:#Feladat kiválasztása exc#:#exc_select_blog#:#Meglévő blog használata exc#:#exc_select_blog_change#:#Másik blog használata exc#:#exc_select_blog_info#:#Válasszon ki egyet blogjai közül ehhez az értékeléshez. -exc#:#exc_select_blog_unlink#:#Remove Blog###26 08 2024 new variable +exc#:#exc_select_blog_unlink#:#Blog eltávolítása exc#:#exc_select_portfolio#:#Meglévő portfólió használata exc#:#exc_select_portfolio_change#:#Másik portfólió használata exc#:#exc_select_portfolio_info#:#Válasszon ki egyet a portfóliói közül ehhez az értékeléshez. exc#:#exc_select_portfolio_unlink#:#Portfólió eltávolítása exc#:#exc_send_assignment#:#Feladat elküldése e-mailben -exc#:#exc_send_grading_notification#:#Send Grading Notification###26 08 2024 new variable -exc#:#exc_set_failed#:#Set as Failed###26 08 2024 new variable -exc#:#exc_set_passed#:#Set as Passed###26 08 2024 new variable +exc#:#exc_send_grading_notification#:#Értékelési értesítés küldése +exc#:#exc_set_failed#:#Beállítás nem teljesítettként +exc#:#exc_set_passed#:#Beállítás sikeresen teljesítettként exc#:#exc_settings_feedback#:#Értékelés exc#:#exc_settings_feedback_file#:#Fájlban exc#:#exc_settings_feedback_file_info#:#A tutorok fájl töltenek fel, melyről a résztvevők értesítést kapnak. A fájlt feladat áttekintésénél tudják letölteni. @@ -9599,35 +9626,36 @@ exc#:#exc_settings_feedback_mail#:#Levélben exc#:#exc_settings_feedback_mail_info#:#A tutorok az értékeléseiket egy levél űrlapon adják meg, amit elküldünk a résztvevőknek. exc#:#exc_settings_feedback_text#:#Szövegdobozban exc#:#exc_settings_feedback_text_info#:#A tutorok az értékeléseiket egy szöveges mezőben adják meg, melyről a résztvevők értesítést kapnak. Az értékelés a feladat áttekintésénél jelenik meg. -exc#:#exc_show_instructions#:#Show Work Instructions###26 08 2024 new variable +exc#:#exc_show_instructions#:#Munkautasítások megjelenítése +exc#:#exc_show_more#:#Több… exc#:#exc_show_peer_review#:#Hallgatói visszajelzések megjelenítése exc#:#exc_show_submissions#:#Megoldások közzététele a határidő után -exc#:#exc_show_submissions_info#:#A megoldásokat elküldjük a tanulóknak a határidő lejártával. +exc#:#exc_show_submissions_info#:#A fix beadási határidővel rendelkező feladatok esetén a résztvevők a beadási határidő lejárta után az összes megoldást megtekinthetik. exc#:#exc_start_assignment#:#Feladat elkezdése exc#:#exc_start_exercise#:#Feladat indítása exc#:#exc_start_time#:#Kezdő időpont exc#:#exc_starting_on#:#Kezdő időpont: -exc#:#exc_submission_and_grades_notification_link#:#Link a feladat 'Megoldások és értékelések' részére: %s +exc#:#exc_submission_and_grades_notification_link#:#Link a feladat ‘Megoldások és értékelések’ részére: %s exc#:#exc_submission_downloads_notification_link#:#Új megoldások letöltése: %s exc#:#exc_submission_file#:#Fájl beadása exc#:#exc_submission_no_new_files#:#Egy új megoldás sem érhető el. exc#:#exc_submission_notification#:#E-mail értesítés beadásról -exc#:#exc_submission_notification_body#:#ezúton értesítjük, hogy '%s' beadandó feladathoz új megoldás töltöttek fel. +exc#:#exc_submission_notification_body#:#ezúton értesítjük, hogy ‘%s’ beadandó feladathoz új megoldás töltöttek fel. exc#:#exc_submission_notification_info#:#Értesítjük, ha megoldást feltöltenek fel. exc#:#exc_submission_notification_link#:#A beadandó feladat linkje: %s -exc#:#exc_submission_notification_subject#:#'%s' beadandó feladat - új megoldást feltöltöttek fel -exc#:#exc_submission_open_notification_link#:#Open submission: %s###26 08 2024 new variable +exc#:#exc_submission_notification_subject#:#‘%s’ beadandó feladat - új megoldást feltöltöttek fel +exc#:#exc_submission_open_notification_link#:#Feladat nyitása: %s exc#:#exc_submission_text#:#Szöveg beadása exc#:#exc_submissions_and_grades#:#Megoldások és értékelések -exc#:#exc_submit_anytime#:#Submit Anytime###26 08 2024 new variable -exc#:#exc_submit_convenience_no_deadline#:#Bármikor beadhatja, nincs határidőhöz kötve. +exc#:#exc_submit_anytime#:#Bármikor beadható +exc#:#exc_submit_convenience_no_deadline#:#Nincs határidőhöz kötve a beadás. exc#:#exc_submitted_files_deleted#:#A kiválasztott fájlt sikeresen törölte. -exc#:#exc_sure_unlink_blog#:#Are you sure to remove this blog form this assignment?###26 08 2024 new variable +exc#:#exc_sure_unlink_blog#:#Biztos, hogy eltávolítja ezt a blogot a hozzárendelésből? exc#:#exc_sure_unlink_portfolio#:#Biztos, hogy eltávolítja ezt a portfóliót a hozzárendelésből? exc#:#exc_target_not_valid#:#A kívánt cél még nem való vagy nem teljes. -exc#:#exc_task_grading#:#'%1' feladat értékelése -exc#:#exc_task_peer_feedback#:#'%1' feladatban visszajelzése küldése -exc#:#exc_task_submission#:#'%1' feladat beadása +exc#:#exc_task_grading#:#‘%1’ feladat értékelése +exc#:#exc_task_peer_feedback#:#‘%1’ feladatban visszajelzése küldése +exc#:#exc_task_submission#:#‘%1’ feladat beadása exc#:#exc_tbl_action_download_all_files#:#Összes beadott letöltése exc#:#exc_tbl_action_download_files#:#Beadottak letöltése exc#:#exc_tbl_action_download_new_files#:#Új beadottak letöltése @@ -9645,8 +9673,8 @@ exc#:#exc_tbl_feedback_time#:#Szöveges értékelés időpontja exc#:#exc_tbl_filter_has_no_submission#:#Még adták be exc#:#exc_tbl_filter_has_submission#:#Beadták exc#:#exc_tbl_filter_submission#:#Beadás -exc#:#exc_tbl_filter_submission_after#:#Submission After###26 08 2024 new variable -exc#:#exc_tbl_filter_submission_before#:#Submission Before###26 08 2024 new variable +exc#:#exc_tbl_filter_submission_after#:#Beküldés után +exc#:#exc_tbl_filter_submission_before#:#Beküldés előtt exc#:#exc_tbl_individual_deadline#:#Egyéni határidő exc#:#exc_tbl_mark#:#Érdemjegy exc#:#exc_tbl_notice#:#Megjegyzés a tutoroknak @@ -9680,7 +9708,7 @@ exc#:#exc_team_log#:#Csapatlog exc#:#exc_team_log_add_file#:#Felvett fájl: %s. exc#:#exc_team_log_add_member#:#Felvett tag: %s. exc#:#exc_team_log_create_team#:#Sikeresen létrehozott egy csapatot. -exc#:#exc_team_log_remove_file#:#Removed file %s.###26 08 2024 new variable +exc#:#exc_team_log_remove_file#:#Eltávolított fájl: %s. exc#:#exc_team_log_remove_member#:#Eltávolított tag: %s. exc#:#exc_team_max_small_than_members#:#A csapat résztvevőinek maximális száma nem lehet %s, mert néhány csapatnak %s résztvevőt kell befogadnia. exc#:#exc_team_member_add#:#Csapattag hozzáadása (keresés) @@ -9696,24 +9724,25 @@ exc#:#exc_team_notification_body_add#:#ezúton tájékoztatjuk, hogy tag lett eg exc#:#exc_team_notification_body_rmv#:#ezúton tájékoztatjuk, hogy tagsága megszűnt egy csapatfeltöltési feladatban. exc#:#exc_team_notification_link#:#Link a beadandó feladathoz exc#:#exc_team_notification_reason#:#Ezt a levelet azért kapta, mert fent említett csoportnak tagja. -exc#:#exc_team_notification_subject_add#:#'%s' feladatban csapattagság -exc#:#exc_team_notification_subject_rmv#:#'%s' feladatban csapattagság megszűnése +exc#:#exc_team_notification_subject_add#:#‘%s’ feladatban csapattagság +exc#:#exc_team_notification_subject_rmv#:#‘%s’ feladatban csapattagság megszűnése exc#:#exc_teams_assignment_adopted#:#A csapatokat sikeresen örökítettük egy már létező feladatból exc#:#exc_template#:#Sablon exc#:#exc_text_assignment_edit#:#Szöveg módosítása exc#:#exc_text_assignment_show#:#Szöveg megjelenítése exc#:#exc_text_saved#:#A szöveget sikeresen mentette. -exc#:#exc_too_many_files#:#The upload contains too many files.###29 10 2025 new variable +exc#:#exc_too_many_files#:#Túlsok fájlt próbál feltölteni. exc#:#exc_total_exc#:#Összes beadandó feladat exc#:#exc_total_members#:#Feladat résztvevőinek összszáma: -exc#:#exc_type#:#Type###26 08 2024 new variable +exc#:#exc_type#:#Típus exc#:#exc_type_blog#:#Blog exc#:#exc_type_portfolio#:#Portfólió exc#:#exc_type_text#:#Szöveg exc#:#exc_type_upload#:#Feltöltés exc#:#exc_type_upload_team#:#Csapatfeltöltés exc#:#exc_value_can_not_set#:#Ez az érték nem állítható be. -exc#:#exc_view_portfolio#:#View Portfolio###26 08 2024 new variable +exc#:#exc_view_portfolio#:#Portfólió megtekintése +exc#:#exc_view_wiki#:#Wiki megjelenítése exc#:#exc_wait_for_files#:#Letöltése automatikusan elindul 5 másodpercen belül. Amennyiben mégsem, kattintson ide exc#:#exc_wiki_container#:#Wikitároló exc#:#exc_wiki_container_info#:#A hely, ahová a résztvevők a wikijeit létrehozzák. @@ -9726,7 +9755,7 @@ exc#:#exc_without_template_info#:#A résztvevő a porfóliójukat a semmiből é exc#:#exc_without_wiki_template#:#Wikisablon nélkül exc#:#exc_without_wiki_template_info#:#A résztvevők a semmiből hozzák létre a saját wikijüket. exc#:#exc_work_instructions#:#Utasítások a feladat elvégzéséhez -exc#:#exc_x_of_y#:#of###26 08 2024 new variable +exc#:#exc_x_of_y#:#/ exc#:#exc_your_text#:#Szövege exc#:#feedback_from#:#Visszajelzés feladója exc#:#feedback_given#:#Visszajelzés elküldve @@ -9737,8 +9766,8 @@ exc#:#not_yet#:#még nem exc#:#submissions_feedback#:#A beadványok és a tanulói visszajelzések exc#:#submissions_only#:#Csak a beadványok exc#:#text_assignment#:#Szövegkiosztás -excv#:#excv_create#:#Beadandó feladat igazolásának létrehozása -excv#:#excv_create_info#:#Válasszon ki egy befejezett beadandó feladatot, hogy igazolást generáljon hozzá. +excv#:#excv_create#:#Beadandó feladat tanúsítványának létrehozása +excv#:#excv_create_info#:#Válasszon ki egy befejezett beadandó feladatot, hogy tanúsítványt generáljon hozzá. exercise#:#exc_admin_settings#:#Beadandó feladat beállításainak kezelése exercise#:#exc_comment#:#Szöveges értékelés exercise#:#exc_comment_for_learner#:#Szöveges értékelés @@ -9754,40 +9783,40 @@ exercise#:#exc_your_submission#:#Az Ön megoldása exp#:#exp_create_file#:#Exportfájl létrehozása exp#:#exp_error_disabled#:#A tárolók exportálása le van tilta. Vegye fel a kapcsolatot az üzemeltetővel. exp#:#exp_error_too_many_objects#:#Az exportálás túllépi a maximálisan megngedett objektumszámot (%1). Kérem, kevesebb objektumot jelöljön ki. -exp#:#exp_export_dropdown#:#Export###29 10 2025 new variable +exp#:#exp_export_dropdown#:#Exportálás exp#:#exp_export_files#:#Exportfájlok -exp#:#exp_export_single_option#:#Export %s###29 10 2025 new variable +exp#:#exp_export_single_option#:#Exportálás %s exp#:#exp_file_created#:#Elkészült az exportfájl. -exp#:#exp_format_dropdown-csv#:#as CSV###29 10 2025 new variable -exp#:#exp_format_dropdown-html#:#as HTML###29 10 2025 new variable -exp#:#exp_format_dropdown-xls#:#as XLS###29 10 2025 new variable -exp#:#exp_format_dropdown-xml#:#as XML###29 10 2025 new variable -exp#:#exp_html#:#HTML###28 10 2024 new variable -exp#:#exp_import_validation_err_no_matching_xsd#:#No valid schema file for version %s exists.###26 08 2024 new variable -exp#:#exp_not_public_access_status#:#Not published###29 10 2025 new variable -exp#:#exp_print_pdf#:#Print/PDF###29 07 2022 new variable -exp#:#exp_print_pdf_info#:#To create a PDF please use the "Print to PDF" target as soon as the print view is presented.###29 07 2022 new variable -exp#:#exp_public_access_status#:#Available in ‘Info’-tab###29 10 2025 new variable -exp#:#exp_really_delete#:#Biztos, hogy törli ezeket az exportfájlokat? -exp#:#exp_show_print_view#:#Show Print View###29 07 2022 new variable +exp#:#exp_format_dropdown-csv#:#mint CSV +exp#:#exp_format_dropdown-html#:#mint HTML +exp#:#exp_format_dropdown-xls#:#mint XLS +exp#:#exp_format_dropdown-xml#:#mint XML +exp#:#exp_html#:#HTML +exp#:#exp_import_validation_err_no_matching_xsd#:#%s verzióhoz nincs érvényes sémafájl. +exp#:#exp_not_public_access_status#:#Nem publikált +exp#:#exp_print_pdf#:#Nyomtatás/PDF +exp#:#exp_print_pdf_info#:#PDF létrehozásához válassza a ‘Nyomtatás PDF-be’ lehetőséget a ‘Nyomtatási nézet’ megjelenése után. +exp#:#exp_public_access_status#:#Elérhető az ‘Információ’ lapon +exp#:#exp_really_delete#:#Biztos, hogy törli a következő az exportfájlokat? +exp#:#exp_show_print_view#:#Nyomtatási nézet megjelenítése exp#:#exp_xml#:#XML exp#:#export_created#:#Új exportfájl jött létre. -exp#:#export_files_deleted#:#The selected export files have been deleted.###26 08 2024 new variable -exp#:#export_options#:#Export Options###28 10 2024 new variable -exp#:#export_type#:#Export Type###28 10 2024 new variable -export#:#exp_file#:#File Name###28 10 2024 new variable -export#:#exp_public_access#:#Public Access###28 10 2024 new variable -export#:#exp_size#:#File Size (MB)###28 10 2024 new variable -export#:#exp_timestamp#:#Creation Date###28 10 2024 new variable -export#:#exp_toggle_public_access#:#Toggle Public Access###28 10 2024 new variable -export#:#exp_type#:#Type###28 10 2024 new variable +exp#:#export_files_deleted#:#A kijelölt exportfájlokat sikeresen törölte. +exp#:#export_options#:#Exportálás beállításai +exp#:#export_type#:#Exportálás típusa +export#:#exp_file#:#Fáj neve +export#:#exp_public_access#:#Elérhető az ‘Információó’ lapon +export#:#exp_size#:#Fájl mérete (MB) +export#:#exp_timestamp#:#Létrehozás dátuma +export#:#exp_toggle_public_access#:#Nyilvános elérés módosítása +export#:#exp_type#:#Típus export#:#export_create#:#Létrehozás export#:#export_create_new_file#:#Új exportfájl létrehozása export#:#export_existing#:#Újrafelhasználás export#:#export_export_date#:#Exportálási dátum -export#:#export_info_public_access#:#Public Access Export###28 10 2024 new variable -export#:#export_info_public_access_download#:#Download###28 10 2024 new variable -export#:#export_last_export#:#Utolsó export +export#:#export_info_public_access#:#Exportálás nyilvános elérése +export#:#export_info_public_access_download#:#Letöltés +export#:#export_last_export#:#Utolsó exportálás export#:#export_last_export_file#:#Utolsó exportfájl használata export#:#export_last_file#:#Utolsó fájl export#:#export_omit#:#Kihagyás @@ -9796,122 +9825,122 @@ export#:#export_resource#:#Forrás export#:#export_save_selection#:#Export indítása export#:#export_select_resources#:#Források kiválasztása export#:#no_file#:#Nincs fájl -file#:#add_icon#:#Add Icon###26 08 2024 new variable -file#:#amount_of_downloads#:#Downloads###26 08 2024 new variable -file#:#amount_of_downloads_since#:#%d times since %s###26 08 2024 new variable -file#:#copyright_custom#:#Custom###26 08 2024 new variable -file#:#copyright_custom_info#:#Choose a custom copyright which will be applied to all unzipped files of this archive.###26 08 2024 new variable -file#:#copyright_inherited#:#Inherited###26 08 2024 new variable -file#:#copyright_inherited_info#:#Apply the copyright of the zip archive to its unzipped files.
    Copyright of zip archive: %s.###26 08 2024 new variable -file#:#could_not_create_file_objs#:#An error occurred while creating your file objects. Please contact the administrators of this platform.###26 08 2024 new variable -file#:#de_activate_icon#:#Activate / Deactivate###26 08 2024 new variable -file#:#download_ascii_filename#:#Allow Only ASCII Characters in Downloaded Filenames###26 08 2024 new variable -file#:#download_ascii_filename_info#:#Downloaded files should only have ASCII-characters in their filename. Deactivate to use all characters.###26 08 2024 new variable -file#:#file_action_download#:#Download file or view content###29 10 2025 new variable -file#:#file_action_download_info#:#If WOPI is activated and the permission 'View Content' is given, the file is shown in tab 'Content'. If not, the file will be offered for direct download.###29 10 2025 new variable -file#:#file_action_show#:#Redirect user to the file’s ‘Info’ tab###29 10 2025 new variable -file#:#file_action_show_info#:#The 'Info' tab is shown where the file could be downloaded in a second step.###29 10 2025 new variable -file#:#file_btn_lp_toggle_state_completed#:#Set Not Completed###26 08 2024 new variable -file#:#file_btn_lp_toggle_state_not_completed#:#Set Completed###26 08 2024 new variable +file#:#add_icon#:#Ikon hozzáadása +file#:#amount_of_downloads#:#Letöltések +file#:#amount_of_downloads_since#:#%d alkalommal %s óta +file#:#copyright_custom#:#Egyéni +file#:#copyright_custom_info#:#Válasszon egy szerzői jogot, amely az archívum összes kicsomagolt fájljára vonatkozik. +file#:#copyright_inherited#:#Örökölt +file#:#copyright_inherited_info#:#ZIP-archívum szerzői jogi beállításának alkalmazása a kicsomagolt fájlokra.
    A ZIP-archívum szerzői joga: %s. +file#:#could_not_create_file_objs#:#Hiba történt a fájlok létrehozásakor, keresse a rendszerüzemeltetőt. +file#:#de_activate_icon#:#(De-)Aktív +file#:#download_ascii_filename#:#A letöltési fájlnévben csak ASCII-karekterek használata +file#:#download_ascii_filename_info#:#A letöltött fájlok nevében csak ASCII-karakterek legyenek. Deaktiválja tetszőleges karakterek használatához. +file#:#file_action_download#:#Közvetlen letöltés bekapcsolása +file#:#file_action_download_info#:#Ha a WOPI be van kapcsolva és a ‘Tartalom megtekintése’ engedéllyel rendelkezik, a fájl a ‘Tartalom’ fülön megjelenik. Ha nem, akkor a fájl közvetlen letöltésre ajánlljuk fel. +file#:#file_action_show#:#Átiránytás az Információ lapra +file#:#file_action_show_info#:#A második lépésben a fájl az ‘Info’ lapról letölthető. +file#:#file_btn_lp_toggle_state_completed#:#Beállítás nem teljesítettre +file#:#file_btn_lp_toggle_state_not_completed#:#Beállítás teljesítettre file#:#file_copy#:#Fájl másolása file#:#file_download#:#Fájl letöltése file#:#file_import#:#Fájlok importálása file#:#file_new_version#:#Új verzió létrehozása file#:#file_new_version_info#:#Új fájlverzió létrehozása. A korábbi verziók nem módosulnak. -file#:#file_publish#:#Publish Draft###26 08 2024 new variable -file#:#file_rollback_rollback_first#:#The selected version could not be published because an unpublished draft exists.###26 08 2024 new variable -file#:#file_rollback_same_version#:#This is already the published version!###26 08 2024 new variable -file#:#file_unpublish#:#Mark as Draft###26 08 2024 new variable -file#:#file_upload_info_file_with_critical_extension#:#A feltöltött fájl kritikus vagy ismeretlen fájlvégződést tartalmaz. Minden fájl minden feltöltött példányának a végét lecseréljük '.sec'-re. +file#:#file_publish#:#Piszkozat közzététele +file#:#file_rollback_rollback_first#:#A verziót nem lehetett visszaállítani, mert létezik egy közzé nem tett piszkozat. +file#:#file_rollback_same_version#:#Ez már a közzétett verzió +file#:#file_unpublish#:#Megjelölés piszkozatként +file#:#file_upload_info_file_with_critical_extension#:#Legalább egy feltöltött fájl kritikus vagy ismeretlen fájlvégződést tartalmaz. Minden fájl minden feltöltött példányának a végét lecseréljük ‘.sec’-re. A fájl(ok): %s file#:#file_uploaded_by#:#Feltöltötte -file#:#file_version_draft#:#Draft Version###26 08 2024 new variable -file#:#file_version_draft_info#:#The latest version of this file has the status ‘Draft’. As long as this version has not been published, no new versions can be created. People with read permission for the file get the most recent previously published version.###26 08 2024 new variable -file#:#form_icon_creation#:#Create Icon###26 08 2024 new variable -file#:#form_icon_updating#:#Update Icon###26 08 2024 new variable +file#:#file_version_draft#:#Piszkozat verziója +file#:#file_version_draft_info#:#A legújabb verzió ‘Piszkozat’ állapotban van. Amíg a verziót nem tették közzé, új verzió nem hozható létre. A fájlhoz olvasási engedéllyel rendelkező személyek a legújabb közzétett verziót kapják meg. +file#:#form_icon_creation#:#Ikon létrehozása +file#:#form_icon_updating#:#Ikon módosítása file#:#general_upload_error_occured#:#A feltöltés alatt ismeretlen hiba lépett fel. -file#:#important_info#:#Important Information###26 08 2024 new variable -file#:#important_info_byline#:#The information will be displayed in the ‘Info’ tab.###26 08 2024 new variable -file#:#input_active#:#Active###26 08 2024 new variable -file#:#input_desc_active#:#Activate this icon.###26 08 2024 new variable -file#:#input_desc_icon#:#Image to be used as the icon for files with the specified suffixes.###26 08 2024 new variable -file#:#input_desc_suffixes#:#List of comma-separated suffixes (characters and numbers only, without preceding full stop).###26 08 2024 new variable -file#:#input_icon#:#Icon###26 08 2024 new variable -file#:#input_suffixes#:#Suffixes###26 08 2024 new variable -file#:#migrated#:#Status###29 07 2022 new variable -file#:#mime_type#:#MIME Type###26 08 2024 new variable -file#:#msg_cant_unpublish#:#File could not be unpublished.###26 08 2024 new variable -file#:#msg_confirm_entry_deletion#:#Are you sure you want to delete the following entry?:###26 08 2024 new variable -file#:#msg_error_active_suffixes_blacklisted#:#One of the selected file extensions is on the global blacklist and cannot therefore be currently used.###26 08 2024 new variable -file#:#msg_error_active_suffixes_conflict#:#Error: It is not possible to have multiple icons activated for the same suffix. Please deactivate either this icon or the other activated icon whose suffixes overlap with those of this icon.###26 08 2024 new variable -file#:#msg_error_active_suffixes_not_whitelisted#:#The selected file extension is not on the global whitelist. The file suffixes will be changed to ‘.sec’ when downloaded.###26 08 2024 new variable -file#:#msg_error_duplicate_suffix_entries#:#Error: the comma separated list of suffixes contains duplicate entries.###26 08 2024 new variable -file#:#msg_error_icon_deletion#:#Error: icon deletion failed.###26 08 2024 new variable -file#:#msg_error_suffixes_with_forbidden_characters#:#Error: forbidden characters. Only letters, numbers, spaces and commas are allowed.###26 08 2024 new variable -file#:#msg_icon_missing_from_db#:#Icon missing from database.###26 08 2024 new variable -file#:#msg_icon_missing_from_irss#:#Icon missing from resource storage.###26 08 2024 new variable -file#:#msg_success_icon_activated#:#Icon successfully activated.###26 08 2024 new variable -file#:#msg_success_icon_created#:#Icon successfully created.###26 08 2024 new variable -file#:#msg_success_icon_deactivated#:#Icon successfully deactivated.###26 08 2024 new variable -file#:#msg_success_icon_deletion#:#Icon successfully deleted.###26 08 2024 new variable -file#:#msg_success_icon_updated#:#Icon successfully updated.###26 08 2024 new variable -file#:#msg_unzip_success#:#Archive has been successfully unziped.###29 07 2022 new variable -file#:#on_click_action#:#Action When Title Clicked###26 08 2024 new variable -file#:#preview_caption#:#Preview %sof %s###26 08 2024 new variable -file#:#preview_image_size_info#:#The preview versions of images will be downscaled or upscaled as appropriate, so that their longest side is the length (in px) entered here.###26 08 2024 new variable -file#:#preview_persisting#:#Persistent Preview Images###26 08 2024 new variable -file#:#preview_persisting_info#:#Generated preview images will be stored by ILIAS and used from then on each time the preview icon for that file is clicked on. If deactivated, previews will be generated anew each time.###26 08 2024 new variable -file#:#previews_for_tiles#:#Tiles###29 10 2025 new variable -file#:#previews_for_tiles_info#:#Use Preview for Tiles where possible.###29 10 2025 new variable -file#:#publish_before_delete#:#It was not possible to delete any of the existing versions because an unpublished draft exists.###26 08 2024 new variable +file#:#important_info#:#Fontos információ +file#:#important_info_byline#:#Az ‘Információ’ lapon jelenik meg. +file#:#input_active#:#Aktív +file#:#input_desc_active#:#Ikon aktiválása +file#:#input_desc_icon#:#A megadott kiterjesztésű fájlokhoz ikonként megjelenő kép. +file#:#input_desc_suffixes#:#Kiterjesztések vesszővel elválasztott felsorolása (csak betűk és számok, pont nélkül). +file#:#input_icon#:#Ikon +file#:#input_suffixes#:#Kiterjesztés(ek) +file#:#migrated#:#Állapot +file#:#mime_type#:#MIME-Típus +file#:#msg_cant_unpublish#:#A művelet nem hajtható végre +file#:#msg_confirm_entry_deletion#:#Biztos, hogy törlöd a következő bejegyzést? +file#:#msg_error_active_suffixes_blacklisted#:#A fájlkiterjesztés nem használható, mert a globális fektetelista tartalmazza. +file#:#msg_error_active_suffixes_conflict#:#Hiba: egy kiterjesztéshez nem tartozhat több ikon. Kérem, vagy deaktiválja ezt az ikont vagy azt, amelyik ugyanehhez a kitrejesztéshez van rendelve. +file#:#msg_error_active_suffixes_not_whitelisted#:#A kiválasztott fájlt átnevezzük ‘.sec’ végűre, mert a kiterjesztése nincs benne a globális fehérlistában. +file#:#msg_error_duplicate_suffix_entries#:#Hiba: a kiterjesztések vesszőfelsorolt listája ismétlődést tartalmaz. +file#:#msg_error_icon_deletion#:#Hiba: az ikon törlése sikertelen. +file#:#msg_error_suffixes_with_forbidden_characters#:#Hiba: tiltott karakterek. Csak betűk, számok, whitespace-ek és vesszők engedélyezettek. +file#:#msg_icon_missing_from_db#:#Az ikon hiányzik az adatbázisból. +file#:#msg_icon_missing_from_irss#:#Az ikon hiányzik erőforrás tárolóból. +file#:#msg_success_icon_activated#:#Az ikont sikeresen aktiválta. +file#:#msg_success_icon_created#:#Az ikont sikeresen létrehozta. +file#:#msg_success_icon_deactivated#:#Az ikont sikeresen deaktiválta. +file#:#msg_success_icon_deletion#:#Az ikont sikeresen törölte. +file#:#msg_success_icon_updated#:#Az ikont sikeresen módosította. +file#:#msg_unzip_success#:#A ZIP-fájlt sikeresen kibontotta. +file#:#on_click_action#:#A csempére kattintás művelete +file#:#preview_caption#:#%s/%s előnézet +file#:#preview_image_size_info#:#Az előnézeti képek maximális hossza px-ben. +file#:#preview_persisting#:#Állandó előnézeti képek +file#:#preview_persisting_info#:#A generált előképeket eltároljuk, különben azokat menet közben állítjuk elő. +file#:#previews_for_tiles#:#Csempék +file#:#previews_for_tiles_info#:#Csempe előnézet használata, ha lehetséges. +file#:#publish_before_delete#:#A verzió(k) nem törölhető(k), mert nincs közzétett változata. file#:#replace_file_info#:#Az összes korábbi fájlverziót törli. -file#:#resource_id#:#Resource ID###29 07 2022 new variable -file#:#service_settings#:#Additional Features###26 08 2024 new variable -file#:#service_settings_saved#:#Changes saved.###26 08 2024 new variable -file#:#set_license_for_all_files#:#Set License for All Files###26 08 2024 new variable -file#:#show_amount_of_downloads#:#Show Number of Downloads###26 08 2024 new variable -file#:#show_amount_of_downloads_info#:#Display the number of times a file object has been downloaded on its 'Info' page.###26 08 2024 new variable -file#:#storage_id#:#Storage ID###29 07 2022 new variable -file#:#suffix_specific_icons#:#Suffix-Specific Icons###26 08 2024 new variable -file#:#suffixes#:#Suffixes###26 08 2024 new variable -file#:#upload_files#:#Upload Files###26 08 2024 new variable -file#:#upload_files_limit#:#The maximum file size allowed is %s.###26 08 2024 new variable -file#:#upload_files_title#:#Upload Files###26 08 2024 new variable +file#:#resource_id#:#Erőforrás-ID +file#:#service_settings#:#További tulajdonságok +file#:#service_settings_saved#:#Sikeres mentés +file#:#set_license_for_all_files#:#Licensz beállítása az össze fájlra +file#:#show_amount_of_downloads#:#Letöltések számának megjelenítése +file#:#show_amount_of_downloads_info#:#Az Informació oldal megjelenik, hogy a fájlt hányszor töltötték le. +file#:#storage_id#:#Tároló-ID +file#:#suffix_specific_icons#:#Kiterjesztésfüggő ikonok +file#:#suffixes#:#Kiterjesztés(ek) +file#:#upload_files#:#Fájlok feltöltése +file#:#upload_files_limit#:#Egy fájl maximális mérete %s. +file#:#upload_files_title#:#Fájlok feltöltése file#:#upload_info#:#Fájl -file#:#upload_info_desc#:#Feltöltések és verziók kezelése a 'Verziók' fül alatt -file#:#version_uploaded#:#Version uploaded###29 07 2022 new variable -file#:#versionname#:#Title###29 07 2022 new variable -fils#:#add_upload_policy#:#Add Policy###26 08 2024 new variable -fils#:#edit_upload_policy#:#Edit Policy###26 08 2024 new variable -fils#:#file_services#:#File Services -fils#:#file_services_description#:#Configuration of File Service Settings. -fils#:#file_suffix_custom_expl_negative#:#Prohibited File Suffixes -fils#:#file_suffix_custom_expl_negative_info#:#Files with these suffixes won't be accepted for upload. -fils#:#file_suffix_custom_negative#:#File Suffixes: Negative List (Adaptations) -fils#:#file_suffix_custom_negative_info#:#These file suffixes will be removed from the positive list. -fils#:#file_suffix_custom_positive#:#File Suffixes: Positive List (Adaptations) -fils#:#file_suffix_custom_positive_info#:#These file suffixes will be added to the positive list. -fils#:#file_suffix_default_positive#:#File Suffixes: Positive List (Default List) -fils#:#file_suffix_default_positive_info#:#Preset default list of accepted file suffixes. -fils#:#file_suffix_overall_positive#:#Overall Positive List -fils#:#file_suffix_overall_positive_info#:#This is the final list of accepted file suffixes. -fils#:#policy_audience#:#Target Group###26 08 2024 new variable -fils#:#policy_audience_all_users_option_desc#:#Apply policy to all users.###26 08 2024 new variable -fils#:#policy_audience_global_roles_option_desc#:#Apply policy to users with specific global roles.###26 08 2024 new variable -fils#:#policy_confirm_deletion#:#Are you sure you want to delete the policy with the following properties?:###26 08 2024 new variable -fils#:#policy_deletion_failure_not_found#:#Error: Deletion failed because policy could not be found.###26 08 2024 new variable -fils#:#policy_deletion_successful#:#Policy successfully deleted.###26 08 2024 new variable -fils#:#policy_filter#:#Policy Filter###26 08 2024 new variable -fils#:#policy_no_validity_limitation_set#:#Valid indefinitely###26 08 2024 new variable -fils#:#policy_scope#:#Scope###26 08 2024 new variable -fils#:#policy_table_info_no_policies#:#No upload policies have been created yet.###26 08 2024 new variable -fils#:#policy_title_desc#:#Descriptive title for this policy.###26 08 2024 new variable -fils#:#policy_upload_limit#:#Upload Limit###26 08 2024 new variable -fils#:#policy_upload_limit_desc#:#Upload limit (in MB) imposed by this policy.###26 08 2024 new variable -fils#:#policy_valid_until#:#Valid Until###26 08 2024 new variable -fils#:#policy_valid_until_desc#:#Set an optional ‘valid until’ date, after which the policy expires.###26 08 2024 new variable -fils#:#policy_validity#:#Validity###26 08 2024 new variable -fils#:#upload_limits#:#Upload Limits###26 08 2024 new variable -fils#:#upload_policies#:#Upload Policies###26 08 2024 new variable +file#:#upload_info_desc#:#Feltöltések és verziók kezelése a ‘Verziók’ lap alatt +file#:#version_uploaded#:#A verziót sikeresen feltöltötte +file#:#versionname#:#Cím +fils#:#add_upload_policy#:#Szabály hozzáadása +fils#:#edit_upload_policy#:#Szabály módosítása +fils#:#file_services#:#Fájlszolgáltatás +fils#:#file_services_description#:#A Fájlszolgáltatás beállításai. +fils#:#file_suffix_custom_expl_negative#:#Tiltott kiterjesztések +fils#:#file_suffix_custom_expl_negative_info#:#Ezeket a fájlnévkiterjesztéseket nem fogadjuk el feltöltéskor. +fils#:#file_suffix_custom_negative#:#Negatív kiterjesztések (kiegészítés) +fils#:#file_suffix_custom_negative_info#:#Ezek a fájlnévkiterjesztések kikerülnek a pozitív listából. +fils#:#file_suffix_custom_positive#:#Pozitív kiterjesztések (kiegészítés) +fils#:#file_suffix_custom_positive_info#:#Ezek a fájlnévkiterjesztések bekerülnek a pozitív listába. +fils#:#file_suffix_default_positive#:#Pozitív kiterjesztések (alapértelmezett lista) +fils#:#file_suffix_default_positive_info#:#Az alapértelmezetten elfogadott fájlnévkiterjesztések. +fils#:#file_suffix_overall_positive#:#Összesített pozitív lista +fils#:#file_suffix_overall_positive_info#:#Ez az elfogadott fájlnévkiterjesztések végleges listája. +fils#:#policy_audience#:#Felhasználói kör +fils#:#policy_audience_all_users_option_desc#:#Szabály alkalmazása az összes felhasználóra. +fils#:#policy_audience_global_roles_option_desc#:#Szabály alkalmazása meghatározott szerepkörrel rendelkező felhasználókra. +fils#:#policy_confirm_deletion#:#Biztos, hogy törli a következő szabályt? +fils#:#policy_deletion_failure_not_found#:#HIBA: A szabály nem található. +fils#:#policy_deletion_successful#:#A szabályt sikeresen törölte. +fils#:#policy_filter#:#Szűrő +fils#:#policy_no_validity_limitation_set#:#Korlátlan ideig érvényes +fils#:#policy_scope#:#Hatókör +fils#:#policy_table_info_no_policies#:#Még egy feltöltési szabály sincs. +fils#:#policy_title_desc#:#A szabály leíró címe +fils#:#policy_upload_limit#:#Feltöltési korlát +fils#:#policy_upload_limit_desc#:#A szabályban beállított felöltési korlát MB-ban. +fils#:#policy_valid_until#:#Érvényességi idő +fils#:#policy_valid_until_desc#:#Az ‘Érvényességi idő’ után a szabály lejár. +fils#:#policy_validity#:#Érvényesség +fils#:#upload_limits#:#Feltöltési korlátok +fils#:#upload_policies#:#Feltöltési szabályok fold#:#fold_copy#:#Mappa másolása fold#:#fold_import#:#Mappa importálása fold#:#fold_presentation#:#Mappa megjelenítése @@ -9930,9 +9959,9 @@ form#:#form_hierarchy_add_elements#:#Kattintson a helyőrzőkre új oldal vagy f form#:#form_hierarchy_drag_drop_help#:#Fogd-és-vidd az ikonokat a helyőrzőkre az oldal vagy fejezet mozgatásához. form#:#form_hours#:#Óra form#:#form_image_file_input#:#Képfájl-input -form#:#form_invalid_uri#:#Invalid URI format.###29 07 2022 new variable -form#:#form_link_external#:#World Wide Web -form#:#form_link_internal#:#ILIAS-on belül +form#:#form_invalid_uri#:#Érvénytelen URI formátum. +form#:#form_link_external#:#Külső link +form#:#form_link_internal#:#Belső link form#:#form_location_radius#:#rádiusz form#:#form_location_radius_km#:#km form#:#form_max_value#:#Maximális érték @@ -9950,11 +9979,11 @@ form#:#form_msg_file_upload_stopped_ext#:#A kiterjesztés miatt megszakítottuk form#:#form_msg_file_virus_found#:#A feltöltendő fájlban vírus található. form#:#form_msg_file_wrong_file_type#:#Rossz fájltípus. form#:#form_msg_formula_is_required#:#Helyes képletet adjon meg! -form#:#form_msg_max_upload#:#Maximum number of simultaneously uploadable files:###29 07 2022 new variable +form#:#form_msg_max_upload#:#Egyidőben feltölthető fájlok maximális száma: form#:#form_msg_numeric_value_required#:#Számértéket adjon meg! form#:#form_msg_value_too_high#:#Az érték túl magas. Adjon meg alacsonyabb értéket! form#:#form_msg_value_too_low#:#Az érték túl alacsony. Adjon meg magasabb értéket! -form#:#form_msg_wrong_date#:#Hibás dátum. Érvényes dátumot adjon meg. +form#:#form_msg_wrong_date#:#Kérjük, ellenőrizze a dátumokat. Mind a kezdő, mind a záró dátum megadása kötelező, és a kezdő dátum nem lehet későbbi a záró dátumnál. form#:#form_no_link#:#Nincs link form#:#form_open_answer#:#Szabadszöveges form#:#form_password_not_allowed_for_auth#:#A választott hitelesítési módhoz nem lehet megváltoztatni a jelszót. @@ -9963,20 +9992,20 @@ form#:#form_please_select#:#Válasszon form#:#form_retype_email#:#E-mail újragépelése form#:#form_retype_password#:#Új jelszó megerősítése form#:#form_seconds#:#Másodperc -form#:#form_take_snapshot#:#Take Snapshot###29 07 2022 new variable -form#:#form_use_camera#:#Use Camera###29 07 2022 new variable +form#:#form_take_snapshot#:#Pillanatkép készítése +form#:#form_use_camera#:#Kamera használata forum#:#activate_new_posts#:#Új hozzászólások jóváhagyása forum#:#activate_only_current#:#Hozzászólás jóváhagyása forum#:#activate_post#:#Jóváhagyás forum#:#activate_post_txt#:#Biztos, hogy jóváhagyja ezt a hozzászólást? forum#:#add_new_answer#:#Új hozzászólás -forum#:#add_re_to_subject#:#'Re:' hozzáadása a válasz tárgyához +forum#:#add_re_to_subject#:#‘Re:’ hozzáadása a válasz tárgyához forum#:#adm_autosave_drafts#:#Piszkozatok automatikus mentése -forum#:#adm_autosave_drafts_desc#:#Ha be van kapcsolva, a szerkesztés alatt lévő piszkozatokat automatikusan mentjük. +forum#:#adm_autosave_drafts_desc#:#A szerkesztés alatt lévő piszkozatokat automatikusan mentjük. forum#:#adm_autosave_ival#:#Időköz -forum#:#adm_save_drafts#:#Piszkozatok mentése -forum#:#adm_save_drafts_desc#:#Ha be van kapcsolva, a regisztrált felhasználók piszkozatként menthetik fórumhozzászólásaikat. -forum#:#allow_file_upload_desc#:#Ha be van kapcsolva, a felhasználók hozzászólásaikhoz csatolhatnak fájlokat. +forum#:#adm_save_drafts#:#Vázlatok bekapcsolása +forum#:#adm_save_drafts_desc#:#A regisztrált felhasználók piszkozatként menthetik fórumhozzászólásaikat. +forum#:#allow_file_upload_desc#:#A felhasználók hozzászólásaikhoz csatolhatnak fájlokat. forum#:#ascending_order#:#Legújabb hozzászólás alul forum#:#autosave_draft_info#:#Ezt a piszkozatot automatikusan mentjük %s másodpercenként. forum#:#autosave_post_draft_info#:#Ezt a hozzászólást automatikusan piszkozatként mentjük %s másodpercenként. @@ -9989,24 +10018,24 @@ forum#:#deletePosting#:#Hozzászólás törlése forum#:#deletePostingDraft#:#Piszkozat törlése forum#:#delete_draft_successfully#:#Piszkozatot sikeresen mentette. forum#:#delete_drafts_successfully#:#Piszkozatokat sikeresen törölte. -forum#:#delete_thread#:#Delete Thread###26 08 2024 new variable +forum#:#delete_thread#:#Téma törlése forum#:#descending_order#:#Legújabb hozzászólás felül -forum#:#edit_thread_draft#:#Témapiszkozat módosítása###Edit thread draft postings created in forums. +forum#:#edit_thread_draft#:#Témapiszkozatok módosítása. forum#:#empty_subject#:#A válaszban a felhasználónak új címet kell adnia -forum#:#empty_thread#:#Empty Thread###29 07 2022 new variable +forum#:#empty_thread#:#Üres téma forum#:#enable_send_attachments#:#Csatolmányok küldése fórumértesítésekkel forum#:#enable_send_attachments_desc#:#Megjegyzés: ez nagy tárhelyhasználatot okozhat a szerveren, mert minden csatolt fájlt minden értesítendő felhasználóhoz külön-külön mentünk. forum#:#enable_thread_ratings#:#Téma értékelése -forum#:#enable_thread_ratings_info#:#Ha be van kapcsolva, a felhasználók értékelhetnek témákat. -forum#:#enter_new_subject#:#Adjon meg új tárgyat! -forum#:#error_no_target_selected#:#Please select a forum.###29 07 2022 new variable +forum#:#enable_thread_ratings_info#:#A felhasználók értékelhetnek témákat. +forum#:#enter_new_subject#:#Adjon meg egy új tárgyat. +forum#:#error_no_target_selected#:#Válasszon egy fórumot. forum#:#error_reading_file#:#Hiba történt a fájl olvasása közben forum#:#error_same_thread_ids#:#A kijelölt és a cél témának különböznie kell. forum#:#file_upload_allowed#:#Csatolmányok engedélyezése forum#:#file_upload_allowed_fora#:#Csatolmányok -forum#:#file_upload_allowed_fora_desc#:#Ha a 'Csatolmányok engedélyezése bizonyos fórumokban' be van kapcsolva, az adott fórum beállításában a fórummoderátor engedélyezheti fájlok csatolását a hozzászóláshoz. Új fórumban ez csatolás alapértelmezetten nem lehetséges. +forum#:#file_upload_allowed_fora_desc#:#A csatolmányokat fórumonként lehet engedélyezni. Új fórumban a csatolás alapértelmezetten nem lehetséges. forum#:#file_upload_option_allow#:#Csatolmányok engedélyezése az összes fórumban -forum#:#file_upload_option_allow_info#:#Files can be attached to posts in all forums.###29 07 2022 new variable +forum#:#file_upload_option_allow_info#:#Fájl csatolása az összes fórumban lehetséges. forum#:#file_upload_option_disallow#:#Csatolmányok engedélyezése bizonyos fórumokban forum#:#fmr_copy_threads_info#:#Lehetősége van egyszerű hozzászólások másolására. Csak a kiválasztott hozzászólások kezdetét duplázzuk meg. forum#:#forum_add_quote#:#Előző hozzászólás beillesztése @@ -10022,8 +10051,8 @@ forum#:#forums_download_attachment#:#Fájl letöltése forum#:#forums_edit_draft#:#Piszkozat módosítása forum#:#forums_edit_post#:#Hozzászólás módosítása forum#:#forums_enable_notification#:#Értesítés kérése ehhez a témához -forum#:#forums_forum_notification#:#Send Forum Notifications###28 10 2024 new variable -forum#:#forums_forum_notification_desc#:#If enabled, all users, who want to be informed about new posts in specified forum threads, will get notifications by mail.###28 10 2024 new variable +forum#:#forums_forum_notification#:#Fórumértesítés küldése +forum#:#forums_forum_notification_desc#:#Ha bekapcsolja, a felhasználók értesítő levelek kérhetnek az adott fórumban született új bejegyzésről. forum#:#forums_forum_notification_disabled#:#Nem kap a továbbiakban értesítést, ha új hozzászólás születik ebben a fórumban. forum#:#forums_info_censor2_post#:#Cenzúrázás visszavonása? forum#:#forums_info_censor_post#:#Biztos, hogy elrejti ezt a hozzászólást? @@ -10035,7 +10064,7 @@ forum#:#forums_no_posts_available#:#Ennek a témának egy hozzászólása sincs. forum#:#forums_notification_disabled#:#Értesítés kikapcsolva forum#:#forums_notification_enabled#:#Értesítés bekapcsolva forum#:#forums_notification_intro#:#%s automatikusan küldte Önnek ezt a levelet, %s -forum#:#forums_notification_show_frm#:#'%s' fórum megjelenítése +forum#:#forums_notification_show_frm#:#‘%s’ fórum megjelenítése forum#:#forums_notification_show_post#:#Link a hozzászólásra: %s forum#:#forums_post_activation_mail#:#csak jóváhagyásuk után látják a fórumfelhasználók az alábbi hozzászólásokat. Mivel Ön a fórum egyik moderátora, jogosult a hozzászólások jóváhagyására. forum#:#forums_post_deleted#:#A hozzászólást sikeresen törölte. @@ -10060,14 +10089,14 @@ forum#:#forums_your_reply#:#Az Ön válasza forum#:#frm_action_not_possible_parent_deleted#:#Ez a művelet nem hajtható végre, mert a szülőhozzászólását törölték. forum#:#frm_action_not_possible_thr_closed#:#Ez a művelet nem hajtható végre, mert a témát zárolták. forum#:#frm_action_not_possible_thr_deleted#:#Ez a művelet nem hajtható végre, mert a témát törölték. -forum#:#frm_activation_online_info#:#Set the forum online to make it visible and available to other users. If not, only administrators will have access to it.###29 07 2022 new variable -forum#:#frm_adm_sec_default_settings#:#Default Object Settings###26 08 2024 new variable -forum#:#frm_adm_sec_drafts#:#Drafts###26 08 2024 new variable -forum#:#frm_adm_sec_features#:#Forum Features###26 08 2024 new variable -forum#:#frm_adm_sec_notifications#:#Notifications###26 08 2024 new variable -forum#:#frm_all_threads#:#All Threads###26 08 2024 new variable +forum#:#frm_activation_online_info#:#Allítsa online-ra a fórumot, hogy mások számára is látható elérhető legyen. Különben csak Administrator-orok érhetik azt el. +forum#:#frm_adm_sec_default_settings#:#Alapértelmezett objektumtulajdonságok +forum#:#frm_adm_sec_drafts#:#Vázlatok +forum#:#frm_adm_sec_features#:#Fórumtulajdonságok +forum#:#frm_adm_sec_notifications#:#Értesítések +forum#:#frm_all_threads#:#Összes téma forum#:#frm_anonymous_posting#:#Hozzászólás álnéven -forum#:#frm_anonymous_posting_desc#:#Ha be van kapcsolva, a regisztrált felhasználók csak álnéven vagy név nélkül szólhatnak hozzá ehhez a fórumhoz. Ha a 'Moderátor-hozzászólások megjelölése' be van kapcsolva, a moderátorok nem használhatnak álneveket. +forum#:#frm_anonymous_posting_desc#:#A regisztrált felhasználók csak álnéven vagy név nélkül szólhatnak hozzá ehhez a fórumhoz. Ha a ‘Moderátor-hozzászólások megjelölése’ be van kapcsolva, a moderátorok nem használhatnak álneveket. forum#:#frm_at_least_one_moderator#:#Legalább egy moderátor kell legyen. forum#:#frm_censorship#:#Cenzúra forum#:#frm_censorship_applied#:#A cenzúrázást sikeresen végrehajtotta. @@ -10075,8 +10104,8 @@ forum#:#frm_censorship_revoked#:#A cenzúrázást sikeresen visszavonta. forum#:#frm_copy#:#Fórum másolása forum#:#frm_default_view#:#Alapértelmezett nézet forum#:#frm_edit_title#:#Cím módosítása -forum#:#frm_enable_print_option#:#Enable print option###26 08 2024 new variable -forum#:#frm_enable_print_option_desc#:#If disabled, nobody is able to select the print option in Forum.###26 08 2024 new variable +forum#:#frm_enable_print_option#:#Nyomtatási lehetőség bekapcsolása +forum#:#frm_enable_print_option_desc#:#Ha ki van kapcsolva, senki sem tud nyomtatni a fórumból. forum#:#frm_mark_as_read#:#Megjelölés olvasottként forum#:#frm_mark_as_unread#:#Megjelölés olvasatlanként forum#:#frm_max_notification_age#:#Max. értesítési életidő @@ -10089,23 +10118,23 @@ forum#:#frm_moderator_m#:#Moderátor forum#:#frm_moderator_n#:#Moderálás forum#:#frm_moderator_role_added_successfully#:#A felhasználót sikeresen felvette a moderátorok közé. forum#:#frm_moderators#:#Moderátorok -forum#:#frm_moderators_detached_role_successfully#:#A moderátorszerepet sikeresen elvette minden kiválasztott felhasználótól. +forum#:#frm_moderators_detached_role_successfully#:#A moderátorszerepkört sikeresen elvette minden kiválasztott felhasználótól. forum#:#frm_moderators_not_exist_yet#:#Válasszon egy moderátort! forum#:#frm_moderators_select_at_least_one#:#Legalább egy moderátort válasszon! forum#:#frm_moderators_select_one#:#Legalább egy felhasználót válasszon! -forum#:#frm_move_invalid_file_type#:#'%s' témához tiltott típusú fájlt töltöttek fel. Távolítsa el a fájlt vagy jelezze az üzemeltetőknek, hogy adják hozzá ezt a fájltípust az engedélyezettekhez. +forum#:#frm_move_invalid_file_type#:#‘%s’ témához tiltott típusú fájlt töltöttek fel. Távolítsa el a fájlt vagy jelezze az üzemeltetőknek, hogy adják hozzá ezt a fájltípust az engedélyezettekhez. forum#:#frm_noti_message#:#Üzenet: -forum#:#frm_noti_new_post#:#ezúton értesítjük, hogy '%1$s' fórumban új hozzászólás jött létre. -forum#:#frm_noti_obj_crs#:#course###29 07 2022 new variable -forum#:#frm_noti_obj_grp#:#group###29 07 2022 new variable -forum#:#frm_noti_subject_act_post#:#'%1$s' fórumban '%2$s' témát aktiválták -forum#:#frm_noti_subject_answ_post#:#'%1$s' fórumban '%2$s' témában hozzászólásra válasz érkezett -forum#:#frm_noti_subject_cens_post#:#'%1$s' fórumban '%2$s' témában hozzászólást cenzúráztak -forum#:#frm_noti_subject_del_post#:#'%1$s' fórumban '%2$s' témában hozzászólást töröltek -forum#:#frm_noti_subject_del_thread#:#'%1$s' fórumban '%2$s' témát törölték -forum#:#frm_noti_subject_new_post#:#'%1$s' fórumban '%2$s' témában új hozzászólás -forum#:#frm_noti_subject_uncens_post#:#'%1$s' fórumban '%2$s' témában hozzászólás cenzúrázását visszavonták -forum#:#frm_noti_subject_upt_post#:#'%1$s' fórumban '%2$s' témában hozzászólást módosítottak +forum#:#frm_noti_new_post#:#ezúton értesítjük, hogy ‘%1$s’ fórumban új hozzászólás jött létre. +forum#:#frm_noti_obj_crs#:#kurzus +forum#:#frm_noti_obj_grp#:#csoport +forum#:#frm_noti_subject_act_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témát aktiválták +forum#:#frm_noti_subject_answ_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában hozzászólásra válasz érkezett +forum#:#frm_noti_subject_cens_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában hozzászólást cenzúráztak +forum#:#frm_noti_subject_del_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában hozzászólást töröltek +forum#:#frm_noti_subject_del_thread#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témát törölték +forum#:#frm_noti_subject_new_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában új hozzászólás +forum#:#frm_noti_subject_uncens_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában hozzászólás cenzúrázását visszavonták +forum#:#frm_noti_subject_upt_post#:#‘%1$s"%2$s’ fórumban ‘%3$s’ témában hozzászólást módosítottak forum#:#frm_notification_activated#:#Értesítés bekapcsolva forum#:#frm_notification_deactivated#:#Értesítés kikapcsolva forum#:#frm_post_not_activated_yet#:#Még nincs aktiválva. @@ -10121,54 +10150,54 @@ forum#:#frm_settings_mod_functions_header#:#Moderátori funkciók forum#:#frm_settings_privacy_header#:#Adatvédelem forum#:#frm_settings_user_functions_header#:#Felhasználói funkciók forum#:#frm_statistics#:#Statisztika -forum#:#frm_statistics_disabled_for_participants#:#A statisztikákat nem tekinthetik meg a fórumtagok. A Beállítások fülön tudja ezt megváltoztatni. +forum#:#frm_statistics_disabled_for_participants#:#A statisztikákat nem tekinthetik meg a fórumtagok. A Beállítások lapon tudja ezt megváltoztatni. forum#:#frm_statistics_enabled#:#Statisztika engedélyezése forum#:#frm_statistics_enabled_desc#:#Az összes résztvevő megnézheti a statisztikákat. forum#:#frm_statistics_ranking#:#Hozzászólások száma forum#:#frm_subject_setting#:#Tárgy beállításai forum#:#frm_sure_delete_threads#:#Biztos, hogy törli az alábbi témákat? forum#:#frm_sure_merge_threads#:#Biztos, hogy összevonja a témákat? Figyelmeztetés: A folyamat vissza nem fordítható. -forum#:#frm_task_publishing_draft_title#:#'%s' piszkozat közzététele +forum#:#frm_task_publishing_draft_title#:#‘%s’ piszkozat közzététele forum#:#frm_wizard_page#:#Fórum másolása (2/2. lépés) forum#:#is_read#:#Megjelölés olvasottként forum#:#make_topics_non_sticky#:#Témák kiemelésének megszüntetése forum#:#make_topics_sticky#:#Témák kiemelése forum#:#mark_moderator_posts#:#Moderátor-hozzászólások megjelölése -forum#:#mark_moderator_posts_desc#:#Ha be van kapcsolva, a moderátorszereppel rendelkező felhasználók hozzászólásait színnel kiemeljük. +forum#:#mark_moderator_posts_desc#:#A moderátorszereppel rendelkező felhasználók hozzászólásait színnel kiemeljük. forum#:#merge#:#Összevon forum#:#merge_posts_into_thread#:#Hozzászólások áthelyezése másik témába forum#:#merged_threads_successfully#:#Összevonás sikeres. forum#:#move_chosen_topics#:#Kiválasztott témák áthelyezése forum#:#move_thread_to_forum#:#Téma áthelyezése másik fórumba forum#:#new_post#:#Új hozzászólás -forum#:#new_thread_with_post#:#New Thread with Posting###29 07 2022 new variable +forum#:#new_thread_with_post#:#Új téma hozzászólással forum#:#no_forum_selected#:#Nem választott ki fórumot a kijelölt témák áthelyezéséhez. forum#:#not_allowed_to_merge_into_another_forum#:#Különböző fórumok témái nem lehet összevonni. -forum#:#notification_settings#:#Notification Settings###29 07 2022 new variable -forum#:#notify_censored#:#Censored Posts###29 07 2022 new variable -forum#:#notify_modified#:#Modified Posts###29 07 2022 new variable -forum#:#notify_post_deleted#:#Deleted Posts###29 07 2022 new variable -forum#:#notify_thread_deleted#:#Deleted Threads###29 07 2022 new variable -forum#:#notify_uncensored#:#Uncensored Posts###29 07 2022 new variable +forum#:#notification_settings#:#Értesítési beállítások +forum#:#notify_censored#:#Censored hozzászólások +forum#:#notify_modified#:#Módosított hozzászolások +forum#:#notify_post_deleted#:#Törölt hozzászólások +forum#:#notify_thread_deleted#:#Törölt témák +forum#:#notify_uncensored#:#Uncensored hozzászólások forum#:#number_of_threads#:#Témák oldalankénti száma forum#:#please_choose_target#:#Válasszon témát, melyhez hozzáfűzzük. forum#:#post_activation_desc#:#Közzététel előtt minden hozzászólást jóvá kell hagynia egy moderátornak. -forum#:#post_censored_by#:#ezúton értesítjük, hogy '%1$s' cenzúrázott '%2$s' fórumban hozzászólást: +forum#:#post_censored_by#:#ezúton értesítjük, hogy ‘%1$s’ cenzúrázott ‘%2$s’ fórumban hozzászólást: forum#:#post_censored_comment_by_moderator#:#A hozzászólást cenzúrázták, a megjegyzést a moderátor írta. -forum#:#post_deleted_by#:#ezúton értesítjük, hogy '%1$s' törölt hozzászólást '%2$s' fórumban: -forum#:#post_draft_info#:#This post draft is only visible for you.###26 08 2024 new variable +forum#:#post_deleted_by#:#ezúton értesítjük, hogy ‘%1$s’ törölt hozzászólást ‘%2$s’ fórumban: +forum#:#post_draft_info#:#Ezt a piszkozatot más nem látja. forum#:#post_reply#:#Re: forum#:#post_reply_count#:#Válasz(%s): -forum#:#post_uncensored_by#:#ezúton értesítjük, hogy '%1$s' cenzúrázott egy hozzászólást. -forum#:#post_updated_by#:#ezúton értesítjük, hogy '%1$s' módosított '%2$s' fórumban hozzászólást: +forum#:#post_uncensored_by#:#ezúton értesítjük, hogy ‘%1$s’ cenzúrázott egy hozzászólást. +forum#:#post_updated_by#:#ezúton értesítjük, hogy ‘%1$s’ módosított ‘%2$s’ fórumban hozzászólást: forum#:#preset_subject#:#Előre beállított téma a válaszban forum#:#publish#:#Közzététel -forum#:#relevance#:#Relevance###26 08 2024 new variable +forum#:#relevance#:#Relevancia forum#:#reopen_topics#:#Újra megnyitás forum#:#reply_to_postings#:#Válasz -forum#:#reset_limited_view#:#Limited view on this post an all posts below it.###29 07 2022 new variable -forum#:#reset_limited_view_button#:#Show entire thread###29 07 2022 new variable -forum#:#reset_limited_view_info#:#Limited view on this post and all posts below it.###29 07 2022 new variable +forum#:#reset_limited_view#:#Ennek a hozzászólásnak és az után lévőknek a limitált megjelenítése. +forum#:#reset_limited_view_button#:#A teljes téma megjelenítése +forum#:#reset_limited_view_info#:#Ennek a hozzászólásnak és az után lévőknek a limitált megjelenítése. forum#:#restore#:#Visszaállítás forum#:#restore_draft_from_autosave#:#Piszkozat visszaállítása forum#:#save_draft_successfully#:#A piszkozatot sikeresen mentette. @@ -10181,94 +10210,94 @@ forum#:#select_max_one_thread#:#Csak egy szálat válasszon! forum#:#selected_threads_closed#:#A kiválasztott témákat sikeresen lezárta. forum#:#selected_threads_reopened#:#A kiválasztott témákat sikeresen újranyitotta. forum#:#sort_by_date#:#Dátum szerint -forum#:#sort_by_date_desc#:#The thread is presented in a flat view. The posts are shown in chronological order of creation.###26 08 2024 new variable +forum#:#sort_by_date_desc#:#A témát lapos nézetben jelenítjük meg. A hozzászólásokat létrehozásuk szerint rendezzük. forum#:#sort_by_posts#:#Válasz szerint -forum#:#sort_by_posts_desc#:#The thread is presented in a tree view. Replies to posts are shown in the order in which they relate to each other.###26 08 2024 new variable +forum#:#sort_by_posts_desc#:#A témát fa nézetben jelenítjük meg. A válaszokat aszerint rendezzük, hogy melyik hozzászóláshoz készültek. forum#:#sorting#:#Rendezés forum#:#sticky#:#Kiemelt forum#:#sure_delete_drafts#:#Biztos, hogy törli a kijelölt piszkozatokat? forum#:#switch_threads_for_merge#:#A kijelölt téma régebbi, mint a cél. A sikeres összevon érdekében a kijelölt és a cél témát felcseréljük. -forum#:#target_select#:#Select posting for limited view###29 07 2022 new variable -forum#:#thema#:#Threads###26 08 2024 new variable +forum#:#target_select#:#Hozzászólások kiválasztása a limitált megjelenítéshez +forum#:#thema#:#Témák forum#:#thread#:#Téma -forum#:#thread_deleted_by#:#ezúton értesítjük, hogy '%1$s' törölte '%2$s' fórumban az alábbi témákat: -forum#:#thread_overview#:#Thread-Overview###26 08 2024 new variable +forum#:#thread_deleted_by#:#ezúton értesítjük, hogy ‘%1$s’ törölte ‘%2$s’ fórumban az alábbi témákat: +forum#:#thread_overview#:#Témaáttekintő forum#:#threads_moved_successfully#:#A kiválasztott témákat sikeresen áthelyezte másik fórumba. -forum#:#top_thema#:#Top-Threads###26 08 2024 new variable +forum#:#top_thema#:#Top témák forum#:#topic_close#:#Lezárt forum#:#topics_please_select_one_action#:#Válasszon ki egy tevékenységet! forum#:#user_decides_notification#:#Az értesítéseket a tagok manuálisan kell, hogy aktiválják -glo#:#glo_add_from_other#:#Kifejezések gyűjtése -glo#:#glo_add_glossary#:#Add Glossary###26 08 2024 new variable -glo#:#glo_add_to_collection#:#Add Glossary to Collection Glossary###26 08 2024 new variable -glo#:#glo_added_to_collection_info#:#The selected glossary has been added to the collection glossary.###26 08 2024 new variable -glo#:#glo_answered_correctly#:#I got it right###26 08 2024 new variable -glo#:#glo_answered_not_correctly#:#I was wrong###26 08 2024 new variable -glo#:#glo_box#:#Box###26 08 2024 new variable -glo#:#glo_box_completed#:#You have completed the box.###26 08 2024 new variable -glo#:#glo_box_last_presented#:#Box Last Presented###26 08 2024 new variable -glo#:#glo_boxes#:#Boxes###26 08 2024 new variable -glo#:#glo_boxes_really_reset#:#Do you really want to reset all boxes? All flashcards will be moved to the first box.###26 08 2024 new variable -glo#:#glo_boxes_reset#:#The boxes have been reset successfully.###26 08 2024 new variable -glo#:#glo_bulk_confirmation#:#Please check if all terms and definitions are listed correctly.###26 08 2024 new variable -glo#:#glo_bulk_creation#:#Bulk Creation###26 08 2024 new variable -glo#:#glo_change_to_collection_unavailable_info#:#To change the type of content assembly to "Collection Glossary", you first have to delete all existing terms within this glossary in tab "Content".###26 08 2024 new variable -glo#:#glo_change_to_standard_unavailable_info#:#To change the type of content assembly to "Standard Glossary", you first have to remove the selected glossaries in tab "Content".###26 08 2024 new variable -glo#:#glo_check#:#Check###29 10 2025 new variable -glo#:#glo_collection#:#Collection Glossary###29 07 2022 new variable -glo#:#glo_collection_empty_info#:#This collection glossary is currently empty. Please add at least one glossary to it.###26 08 2024 new variable -glo#:#glo_collection_info#:#The glossary collects additional terms of other glossaries.###29 07 2022 new variable -glo#:#glo_content_assembly#:#Content Assembly###29 07 2022 new variable +glo#:#glo_add_from_other#:#Fogalmak gyűjtése +glo#:#glo_add_glossary#:#Fogalomtár létrehozása +glo#:#glo_add_to_collection#:#A fogalomtárat hozzáadása a gyűjtő fogalomtárhoz +glo#:#glo_added_to_collection_info#:#A kiválasztott fogalomtárat sikeresen hozzáadta a gyűjtő fogalomtárhoz +glo#:#glo_answered_correctly#:#Eltaláltam +glo#:#glo_answered_not_correctly#:#Nem tudtam +glo#:#glo_box#:#Doboz +glo#:#glo_box_completed#:#A dobozt sikeresen teljesítette. +glo#:#glo_box_last_presented#:#A doboz utolsó megjelenítése +glo#:#glo_boxes#:#Dobozok +glo#:#glo_boxes_really_reset#:#Biztos, hogy alaphelyzetbe állítja vissza a dobozokat? Az összes kártya az első dobozba került. +glo#:#glo_boxes_reset#:#A dobozokat sikeresen alaphelyzetbe állította. +glo#:#glo_bulk_confirmation#:#Kérjük, ellenőrizze, hogy az összes fogalom és meghatározás helyesen szerepel-e. +glo#:#glo_bulk_creation#:#Beillesztés Excelből +glo#:#glo_change_to_collection_unavailable_info#:#Ha a tartalom-összeállítás típusát ‘Gyűjtő fogalomtár’-ra módosítja, először törölnie kell az összes létező fogalmat a fogalomtárból a ‘Tartalom’ lapon. +glo#:#glo_change_to_standard_unavailable_info#:#Ha a tartalom-összeállítás típusát ‘Szokásos fogalomtár’-ra módosítja, először el kell távolítania a kiválasztott fogalomtárat a ‘Tartalom’ lapon. +glo#:#glo_check#:#Ellenőrzés +glo#:#glo_collection#:#Gyűjtő fogalomtár +glo#:#glo_collection_empty_info#:#Ez a gyűjtő fogalomtár jelenleg üres. Kérem, adjon hozzá legalább egy fogalmat. +glo#:#glo_collection_info#:#A gyűjtő fogalomtár más fogalomtárak tartalmát jeleníti meg. +glo#:#glo_content_assembly#:#Tartalom összeállítása glo#:#glo_copy#:#Fogalomtár másolása -glo#:#glo_copy_terms#:#Kifejezések másolása -glo#:#glo_create_term_definition_pairs#:#Create Term/Definition Pairs###26 08 2024 new variable -glo#:#glo_days_ago#:#%s days ago###26 08 2024 new variable -glo#:#glo_def_vs_term#:#Definition vs. Term###26 08 2024 new variable -glo#:#glo_def_vs_term_info#:#Show a definition first, the learner has to guess the term.###26 08 2024 new variable -glo#:#glo_flashcard_training#:#Flashcard Training###26 08 2024 new variable -glo#:#glo_flashcard_training_info#:#Offers a presentation as flashcards allowing the user to train the terms/definitions one by one.###26 08 2024 new variable -glo#:#glo_flashcards#:#Flashcards###26 08 2024 new variable -glo#:#glo_flashcards_from_today_confirmation#:#The box contains %s flashcards already presented today. Do you want to include only the remaining %s flashcards or all %s flashcards?###26 08 2024 new variable -glo#:#glo_flashcards_from_today_only_info#:#The box contains only flashcards already presented today. Please confirm that these %s flashcards will be shown to you again.###26 08 2024 new variable -glo#:#glo_flashcards_intro#:#Your goal is to correctly remember each flashcard four times in a row.
    To begin with, all of the flashcards are in box 1.
    Flagging a flashcard as "I got it right" will advance it to the next box.
    Flagging a flashcard as "I was wrong" will return the card to the first box.
    To start, select a box. This will reveal the flashcards.###26 08 2024 new variable -glo#:#glo_flashcards_progress#:#%s of %s###29 10 2025 new variable -glo#:#glo_introduction#:#Introduction###26 08 2024 new variable -glo#:#glo_link_glo_in_glo#:#Biztos, hogy a cél fogalomtár összes kifejezését linkeli a jelenlegi fogalomtárban? -glo#:#glo_link_to_usages#:#Link###29 10 2025 new variable -glo#:#glo_md_advanced#:#Further Details###29 10 2025 new variable +glo#:#glo_copy_terms#:#Fogalmak másolása +glo#:#glo_create_term_definition_pairs#:#Fogalom létrehozása/Meghatározások párosítása +glo#:#glo_days_ago#:#%s nappal ezelőtt +glo#:#glo_def_vs_term#:#Meghatározások vs. fogalmak +glo#:#glo_def_vs_term_info#:#Először a meghatározást mutatjuk, a fogalmat ez alapján kell kitalálni +glo#:#glo_flashcard_training#:#Gyakorlás kártyával +glo#:#glo_flashcard_training_info#:#Játékos lehetőség a fogalmak és meghatározások megtanulásához. +glo#:#glo_flashcards#:#Kártyák +glo#:#glo_flashcards_from_today_confirmation#:#A dobozból ma már megjelenítettünk %s kártyát. Csak a hátralévő %s vagy az összes %s kártyát jelenítsük meg? +glo#:#glo_flashcards_from_today_only_info#:#A dobozban lévő összes kártyát ma már megjelenítettük. Kérem, erősítse meg, hogy ezt a(z) %s kártyát még egyszer jelenítsük meg. +glo#:#glo_flashcards_intro#:#A cél az, hogy mindegyik kártyára egymás után négyszer helyesen emlékezzen.
    Kezdésnek az összes kártya az 1. dobozban található.
    Ha egy kártyát ‘Eltaláltam’-mal jelöl meg, az átkerül a következő dobozba.
    Ha egy kártyát ‘Tévedtem’-mel jelöl meg, akkor a kártya visszakerül az 1. dobozba.
    A kezdéshez jelöljön ki egy dobozt. Ez felfedi a kártyákat. +glo#:#glo_flashcards_progress#:#%s / %s +glo#:#glo_introduction#:#Bemutatkozás +glo#:#glo_link_glo_in_glo#:#Biztos, hogy a célfogalomtár összes fogalmát linkeli a jelenlegi fogalomtárban? +glo#:#glo_link_to_usages#:#Link +glo#:#glo_md_advanced#:#További részletek glo#:#glo_page_type_gdf#:#Fogalommeghatározás -glo#:#glo_please_select_other_glo#:#Please select another glossary.###29 07 2022 new variable -glo#:#glo_quit_box#:#Quit Box###26 08 2024 new variable -glo#:#glo_really_remove_from_collection#:#Are you sure you want to remove the following glossary from the collection glossary?###26 08 2024 new variable +glo#:#glo_please_select_other_glo#:#Válasszon másik fogalomtárat. +glo#:#glo_quit_box#:#Doboz bezárása +glo#:#glo_really_remove_from_collection#:#Biztos, hogy eltávolítja a következő fogalomtárat a gyűjtő fogalomtárból? glo#:#glo_reference#:#Hivatkozás glo#:#glo_reference_terms#:#Kifejezéshivatkozások -glo#:#glo_referenced_term#:#Hivatkozott kifejezés -glo#:#glo_removed_from_collection_info#:#The glossary has been removed from the collection glossary.###26 08 2024 new variable -glo#:#glo_reset_all_boxes#:#Reset All Boxes###26 08 2024 new variable -glo#:#glo_save_and_continue#:#Save and Continue###29 10 2025 new variable +glo#:#glo_referenced_term#:#Hivatkozott fogalom +glo#:#glo_removed_from_collection_info#:#A fogalomtárat sikeresen eltávolította a gyűjtő fogalomtárból. +glo#:#glo_reset_all_boxes#:#Az összes doboz alaphelyzetbe állítása. +glo#:#glo_save_and_continue#:#Mentés és folytatás glo#:#glo_select_source_glo#:#Válasszon forrás fogalomtárat. -glo#:#glo_select_terms#:#Kifejezések kiválasztása -glo#:#glo_selected_glossaries#:#Selected Glossaries###26 08 2024 new variable -glo#:#glo_selected_glossaries_info#:#Terms are collected from the following glossaries:###26 08 2024 new variable -glo#:#glo_selected_glossary_is_current_info#:#The selected glossary corresponds to the current glossary. Please select another glossary.###26 08 2024 new variable -glo#:#glo_selected_terms_have_been_copied#:#A kiválasztott kifejezéseket a vágólapra másoltuk. Nyissa meg a cél fogalomtárat, majd nyomja meg a 'Beillesztés' gombot. -glo#:#glo_show_in_presentation#:#Shown in Presentation View###26 08 2024 new variable -glo#:#glo_show_in_presentation_off#:#Hide in Presentation View###26 08 2024 new variable -glo#:#glo_show_in_presentation_on#:#Show in Presentation View###26 08 2024 new variable -glo#:#glo_tax_info#:#A taxonomy in a Glossary classifies and filters the terms. It always is available in the editing view. For the presentation view, the taxonomy must first be activated. In glossaries, only one taxonomy can be used.###26 08 2024 new variable +glo#:#glo_select_terms#:#Fogalmak kiválasztása +glo#:#glo_selected_glossaries#:#Fogalomtárak kiválasztása +glo#:#glo_selected_glossaries_info#:#A következő fogalomtárakból gyűjtöttük össze a kifejezeéseket: +glo#:#glo_selected_glossary_is_current_info#:#A jelenlegi a kiválasztott fogalomtár. Kérjük, válasszon másikat. +glo#:#glo_selected_terms_have_been_copied#:#A kiválasztott fogalmakat a vágólapra másoltuk. Nyissa meg a cél fogalomtárat, majd nyomja meg a ‘Beillesztés’ gombot. +glo#:#glo_show_in_presentation#:#Látszódjon megjelenítési nézetben +glo#:#glo_show_in_presentation_off#:#Ne látszódjon megjelenítési nézetben +glo#:#glo_show_in_presentation_on#:#Látszódjon megjelenítési nézetben +glo#:#glo_tax_info#:#A taxonomia használatával osztályokba rendezheti és szűrheti a foglmakat. Szerkesztő nézetben mindig elérhető. Megjelenítési módban be kell kapcsolni. A fogalomtárban csak egy taxonómia használható. glo#:#glo_term#:#Fogalom a fogalomtárban -glo#:#glo_term_definition_pairs#:#Term/Definition Pairs###26 08 2024 new variable -glo#:#glo_term_definition_pairs_info#:#Please enter a term and a definition pair in each line. Term and definition must be separated by a semicolon or a TAB character (usually provided by clipboard actions from spreadsheet applications).###26 08 2024 new variable -glo#:#glo_term_letter#:#Letter###26 08 2024 new variable -glo#:#glo_term_reference#:#Kifejezéshivatkozás -glo#:#glo_term_vs_def#:#Term vs. Definition###26 08 2024 new variable -glo#:#glo_term_vs_def_info#:#Show a term first, the learner has to guess the definition.###26 08 2024 new variable -glo#:#glo_terms_per_page#:#Terms per Page###26 08 2024 new variable -glo#:#glo_usage_link#:#Usage Link###29 10 2025 new variable -glo#:#glo_use_all_flashcards#:#Use All Flashcards (%s)###26 08 2024 new variable -glo#:#glo_use_remaining_flashcards#:#Use Remaining Flashcards (%s)###26 08 2024 new variable -glo#:#glo_what_means_definition#:#What does the following mean?###29 10 2025 new variable -glo#:#glo_what_means_term#:#What does "%s" mean?###29 10 2025 new variable +glo#:#glo_term_definition_pairs#:#Excelből másolt adatok +glo#:#glo_term_definition_pairs_info#:#Adjon meg minden sorban egy fogalmat és a hozzá tartozó meghatározást, pontosveszővel vagy tabulátorral elválasztva (általában egy táblázatkezelőből másolt két oszlop ilyen). +glo#:#glo_term_letter#:#Betű +glo#:#glo_term_reference#:#Fogalomhivatkozás +glo#:#glo_term_vs_def#:#Fogalom vs. meghatározás +glo#:#glo_term_vs_def_info#:#Először megjelenik a fogalom, ami alapján a meghatározást kell kitalálni. +glo#:#glo_terms_per_page#:#Fogalmak száma oldalanként +glo#:#glo_usage_link#:#Használati link +glo#:#glo_use_all_flashcards#:#Az összes kártya használata (%s) +glo#:#glo_use_remaining_flashcards#:#A hártalévő kártyák használata (%s) +glo#:#glo_what_means_definition#:#Mit jelent következő? +glo#:#glo_what_means_term#:#‘%s’ mit jelent? grp#:#crs_add_grouping#:#Tagságkorlátozás létrehozása grp#:#crs_grouping_delete_sure#:#Biztos, hogy törli ezt a tagsági korlátozást? grp#:#crs_grouping_deleted#:#Törölt tagsági korlátozás @@ -10279,16 +10308,16 @@ grp#:#crs_grp_no_courses_assigned#:#Egy csoport sincs hozzárendelve grp#:#events#:#Események grp#:#grouping_change_assignment#:#Hozzárendelés változtatása grp#:#grp_activate_notification#:#Értesítés bekapcsolása -grp#:#grp_activation_online_info#:#Set the group online to make it visible and available for group members. If not, only group administrators and roles with permission "Edit Settings" have access to it.###28 10 2024 new variable +grp#:#grp_activation_online_info#:#A csoport beállítása online, hogy látható és elérhető legyen a csoport tagjai számára. Ha nem online, akkor csak a csoportvezetők és a ‘Beállítások szerkesztése’ engedéllyel rendelkező szerepkörök férhetnek hozzá. grp#:#grp_add_to_group#:#Csoporthoz adás grp#:#grp_add_user#:#Felhasználó hozzáadása grp#:#grp_add_user_to_group#:#Felhasználó csoporthoz adása -grp#:#grp_added_to_list#:#Ön már a '%s' csoport várólistáján van. Ön a %s. a listán. +grp#:#grp_added_to_list#:#Ön már a ‘%s’ csoport várólistáján van. Ön a %s. a listán. grp#:#grp_admins#:#Vezetők grp#:#grp_admission_link_failure_invalid_code#:#Nem rögzíthető: érvénytelen link. grp#:#grp_admission_link_failure_membership_limited#:#Nem regisztrálhat, mert a csoport tagsága korlátozott. grp#:#grp_admission_link_failure_registration_period#:#Nem regisztrálhat, mert jelenleg nincs regisztrációs időszak. -grp#:#grp_admission_link_success_registration#:#'%s' csoportba sikeresen regisztrált. +grp#:#grp_admission_link_success_registration#:#‘%s’ csoportba sikeresen regisztrált. grp#:#grp_agree#:#Elfogadás grp#:#grp_agreement_header#:#Felhasználói megállapodás grp#:#grp_agreement_required#:#El kell fogadnia a felhasználói megállapodást, ha el szeretné érni a csoporttartalmat. @@ -10307,12 +10336,12 @@ grp#:#grp_contact#:#Támogatás grp#:#grp_copy#:#Csoport másolása grp#:#grp_create_and_add_user#:#Létrehozás és felhasználó hozzáadása grp#:#grp_create_new#:#Új csoport létrehozása -grp#:#grp_create_new_grp_in#:#Új csoport létrehozása ebben: '%1'. +grp#:#grp_create_new_grp_in#:#Új csoport létrehozása ebben: ‘%1’. grp#:#grp_create_or_use_existing#:#Meglévő vagy új csoporthoz hozzáadja a felhasználót? grp#:#grp_created_and_user_been_added#:#A csoportot sikeresen létrehozta és a felhasználót sikeresen hozzáadta. grp#:#grp_custom_user_fields#:#Csoporthoz tartozó felhasználói adatok -grp#:#grp_custom_user_fields_infobox#:#Create additional data fields for group members to fill in when they join. You can show this information as an additional column in the "Members" tab.###26 08 2024 new variable -grp#:#grp_custom_user_fields_table_title#:#Relevant User Data of This Group###26 08 2024 new variable +grp#:#grp_custom_user_fields_infobox#:#Hozzon létre további adatmezőket a csoporttagok számára, amelyeket csatlakozáskor ki kell töltenie. Ezt az információt további oszlopként is megjelenítheti a ‘Tagok’ lapon. +grp#:#grp_custom_user_fields_table_title#:#A csoport releváns felhasználói adatai grp#:#grp_deactivate_notification#:#Értesítés kikapcsolása grp#:#grp_enable_map#:#Csoporttérkép engedélyezése grp#:#grp_err_registration_limited#:#Valós dátumot adjon meg a regisztráció nyitó- és záródátumának @@ -10328,39 +10357,39 @@ grp#:#grp_info_agreement#:#A következő adattípusok láthatók a csoportvezet grp#:#grp_info_new_grp_type#:#Új csoporttípus grp#:#grp_info_settings#:#Csoportinformációk grp#:#grp_information#:#Fontos információk -grp#:#grp_information_info#:#Ez az információ az 'Információ' fül alatt és az új regisztráltaknak fog megjelenni. +grp#:#grp_information_info#:#Ez az információ az ‘Információ’ lapon és az új regisztráltaknak fog megjelenni. grp#:#grp_join_request#:#Küldés -grp#:#grp_lim_assigned#:#'%s' csoportnak már tagja. -grp#:#grp_mail_admission_new_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportban tag lett. -grp#:#grp_mail_admission_new_sub#:#'%s' csoporthoz csatlakozás +grp#:#grp_lim_assigned#:#‘%s’ csoportnak már tagja. +grp#:#grp_mail_admission_new_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportban tag lett. +grp#:#grp_mail_admission_new_sub#:#‘%s’ csoporthoz csatlakozás grp#:#grp_mail_all#:#Összes tag -grp#:#grp_mail_all_info#:#Tagok és vezetők használhatják a 'Tagok' fülön lévő 'Levél küldése tagoknak' lehetőséget. -grp#:#grp_mail_dismiss_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportban megszűnt a tagsága. -grp#:#grp_mail_dismiss_sub#:#'%s' csoporttagság megszűnése -grp#:#grp_mail_notification_reg_bod#:#%s regisztrált a(z) '%s' csoportba. -grp#:#grp_mail_notification_reg_req_bod#:#%s tagsági kérelmet adott be a(z) '%s' csoportba. +grp#:#grp_mail_all_info#:#Tagok és vezetők használhatják a ‘Tagok’ lapon lévő ‘Levél küldése tagoknak’ lehetőséget. +grp#:#grp_mail_dismiss_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportban megszűnt a tagsága. +grp#:#grp_mail_dismiss_sub#:#‘%s’ csoporttagság megszűnése +grp#:#grp_mail_notification_reg_bod#:#%s regisztrált a(z) ‘%s’ csoportba. +grp#:#grp_mail_notification_reg_req_bod#:#%s tagsági kérelmet adott be a(z) ‘%s’ csoportba. grp#:#grp_mail_notification_reg_req_bod2#:#A regisztráció megerősítéséhez keresse fel: -grp#:#grp_mail_notification_reg_req_sub#:#'%s' csoportcsatlakozási kérés -grp#:#grp_mail_notification_reg_sub#:#'%s' csoportba felhasználó regisztrált -grp#:#grp_mail_notification_unsub_bod#:#%s törölte tagságát a(z) '%s' csoportból. +grp#:#grp_mail_notification_reg_req_sub#:#‘%s’ csoportcsatlakozási kérés +grp#:#grp_mail_notification_reg_sub#:#‘%s’ csoportba felhasználó regisztrált +grp#:#grp_mail_notification_unsub_bod#:#%s törölte tagságát a(z) ‘%s’ csoportból. grp#:#grp_mail_notification_unsub_bod2#:#Csoportjának várólistáján lehet hogy vannak. Kérjük, ellenőrizze a várólistát. A csoporttagok listáját ide kattintva tekintheti meg: -grp#:#grp_mail_notification_unsub_sub#:#'%s' csoportot elhagyta egy felhasználó +grp#:#grp_mail_notification_unsub_sub#:#‘%s’ csoportot elhagyta egy felhasználó grp#:#grp_mail_permanent_link#:#Az alábbi linken érheti el a csoportot: -grp#:#grp_mail_status_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportban az állapota megváltozott. -grp#:#grp_mail_status_sub#:#'%s' csoportban állapotváltozás -grp#:#grp_mail_sub_acc_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportba tagsági kérelmét elfogadták. -grp#:#grp_mail_sub_acc_sub#:#'%s' csoportba tagsági kérelem elfogadása -grp#:#grp_mail_sub_dec_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportba tagsági kérelmét nem fogadták el. -grp#:#grp_mail_sub_dec_sub#:#'%s' csoportba tagsági kérelem elutasítása -grp#:#grp_mail_subscribe_member_bod#:#ezúton tájékoztatjuk, hogy '%s' csoporthoz sikeresen csatlakozott. -grp#:#grp_mail_subscribe_member_sub#:#'%s' csoporthoz csatlakozás +grp#:#grp_mail_status_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportban az állapota megváltozott. +grp#:#grp_mail_status_sub#:#‘%s’ csoportban állapotváltozás +grp#:#grp_mail_sub_acc_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportba tagsági kérelmét elfogadták. +grp#:#grp_mail_sub_acc_sub#:#‘%s’ csoportba tagsági kérelem elfogadása +grp#:#grp_mail_sub_dec_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportba tagsági kérelmét nem fogadták el. +grp#:#grp_mail_sub_dec_sub#:#‘%s’ csoportba tagsági kérelem elutasítása +grp#:#grp_mail_subscribe_member_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoporthoz sikeresen csatlakozott. +grp#:#grp_mail_subscribe_member_sub#:#‘%s’ csoporthoz csatlakozás grp#:#grp_mail_tutors_only#:#Csak vezetők -grp#:#grp_mail_tutors_only_info#:#Csak vezetők használhatják a 'Tagok' fülön lévő 'Levél küldése tagoknak' lehetőséget. +grp#:#grp_mail_tutors_only_info#:#Csak vezetők használhatják a ‘Tagok’ lapon lévő ‘Levél küldése tagoknak’ lehetőséget. grp#:#grp_mail_type#:#Levél küldése tagoknak -grp#:#grp_mail_unsubscribe_member_bod#:#ezúton tájékoztatjuk, hogy '%s' csoportból tagságát sikeresen töröltük. -grp#:#grp_mail_unsubscribe_member_sub#:#'%s' csoporttagság törlése -grp#:#grp_mail_wl_bod#:#'%s' csoport várólistájára felkerült. Ön a(z) %s. a listán. Üzenetben fogja értesíteni Önt a csoportvezető, amikor kérését elfogadják vagy elutasítják. -grp#:#grp_mail_wl_sub#:#'%s' csoportba regisztráció +grp#:#grp_mail_unsubscribe_member_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ csoportból tagságát sikeresen töröltük. +grp#:#grp_mail_unsubscribe_member_sub#:#‘%s’ csoporttagság törlése +grp#:#grp_mail_wl_bod#:#‘%s’ csoport várólistájára felkerült. Ön a(z) %s. a listán. Üzenetben fogja értesíteni Önt a csoportvezető, amikor kérését elfogadják vagy elutasítják. +grp#:#grp_mail_wl_sub#:#‘%s’ csoportba regisztráció grp#:#grp_map_location#:#Csoporttérkép helye grp#:#grp_map_settings#:#Térképbeállítások grp#:#grp_max_and_min_members_invalid#:#A tagok minimális száma kisebb kell, hogy legyen, mint a maximális. @@ -10371,7 +10400,7 @@ grp#:#grp_members#:#Tagok grp#:#grp_members_deleted#:#A tago(ka)t sikeresen törölte grp#:#grp_members_map#:#Csoporttagok térképe grp#:#grp_members_print_title#:#A csoport tagjai -grp#:#grp_min_one_admin#:#There has to be at least one administrator assigned to this group.###26 08 2024 new variable +grp#:#grp_min_one_admin#:#Legalább egy vezető kell, hogy legyen a csoportban. grp#:#grp_missing_grp_type#:#Válasszon csoporttípust! grp#:#grp_missing_password#:#Adjon meg csoportjelszót! grp#:#grp_new_status#:#Az Ön új állapota: @@ -10416,8 +10445,8 @@ grp#:#grp_setting_header_presentation#:#Csoportmegjelenítés grp#:#grp_setting_header_registration#:#Csoportregisztráció grp#:#grp_settings#:#Csoportbeállítások grp#:#grp_show_members#:#Tagok megjelenítése -grp#:#grp_show_members_info#:#Ha be van kapcsolva, a csoport tagjai elérhetik a tagok képtárát. -grp#:#grp_subscription_min_members_info#:#A csoport indulásához szükséges minimális létszámot határozza meg. Amennyiben a csoportlétszám nem éri el ezt a számot a csoport regisztrációs, illetve lejelentkezési határidejéig, figyelmeztető levelet küldünk a csoport azon vezetőinek és tutorainak, akinél aktív az értesítés a csoport 'Tagok' fülén. +grp#:#grp_show_members_info#:#A csoport tagjai elérhetik a tagok képtárát. +grp#:#grp_subscription_min_members_info#:#A csoport indulásához szükséges minimális létszámot határozza meg. Amennyiben a csoportlétszám nem éri el ezt a számot a csoport regisztrációs, illetve lejelentkezési határidejéig, figyelmeztető levelet küldünk a csoport azon vezetőinek és tutorainak, akinél aktív az értesítés a csoport ‘Tagok’ lapján. grp#:#grp_sure_add_user_to_group#:#Biztos, hogy hozzáadja ez a felhasználót a csoporthoz? grp#:#grp_sure_create_group_add_user#:#Biztos, hogy létrehozza a csoportot és hozzáadja felhasználót? grp#:#grp_typ#:#Csoporttípus @@ -10436,7 +10465,7 @@ grp#:#grp_view_inherit#:#Alapértelmezett grp#:#grp_view_inherit_info#:#A megjelenítés típusát a kurzustárolótól vesszük át. grp#:#grp_waiting_list#:#Várólista grp#:#grp_waiting_list_autofill#:#Automatikus feltöltéssel -grp#:#grp_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról lemondás esetén. Ez nem alkalmazható együtt a 'Résztvétel jóváhagyása' regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. +grp#:#grp_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról lemondás esetén. Ez nem alkalmazható együtt a ‘Részvétel jóváhagyása’ regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. grp#:#grp_waiting_list_info#:#A maximális felhasználószám elérése után regisztrálók várólistára kerülnek. grp#:#grp_waiting_list_no_autofill#:#Automatikus feltöltés nélkül grp#:#grp_warn_grp_type_changed#:#Biztos, hogy megváltoztatja a csoport típusát? Minden jogosultsági beállítás alapértelmezettre fog visszaállni. @@ -10448,104 +10477,112 @@ grp#:#grp_wrong_reg_time_limit#:#Ellenőrizze a regisztráció kezdő és záró grp#:#reg_grp_max_members#:#Tagok maximális száma grp#:#reg_grp_max_members_short#:#Felhasználószám korlátozása grp#:#reg_grp_min_members#:#Tagok minimális száma -gsfo#:#accessibility#:#Accessibility###28 10 2024 new variable -gsfo#:#confirm_delete#:#Do you really want to delete the following Item(s)?###28 10 2024 new variable -gsfo#:#confirm_reset#:#Resetting the footer will restore all entries to their original state. All customizations and manual entries will be deleted. Do you want to continue?###28 10 2024 new variable -gsfo#:#entries_add#:#Add Entry###28 10 2024 new variable -gsfo#:#entries_edit#:#entries_edit###28 10 2024 new variable -gsfo#:#entries_parent#:#Select Group###28 10 2024 new variable -gsfo#:#entries_select_parent#:#Move Entry to Group###28 10 2024 new variable -gsfo#:#entry_action#:#Link###28 10 2024 new variable -gsfo#:#entry_action_info#:#Provide the full URL including the protocol (e.g. https://www.ilias.de)###28 10 2024 new variable -gsfo#:#entry_activation_toggled#:#Activation has been toggled###28 10 2024 new variable -gsfo#:#entry_active#:#Active###28 10 2024 new variable -gsfo#:#entry_active_info#:#Activate this Entry###28 10 2024 new variable -gsfo#:#entry_add#:#Add Entry###28 10 2024 new variable -gsfo#:#entry_delete#:#Delete###28 10 2024 new variable -gsfo#:#entry_deleted#:#Deleted###28 10 2024 new variable -gsfo#:#entry_edit#:#Edit###28 10 2024 new variable -gsfo#:#entry_external#:#Open in new Tab###28 10 2024 new variable -gsfo#:#entry_move#:#Move###28 10 2024 new variable -gsfo#:#entry_moved#:#Entry has been moved###28 10 2024 new variable -gsfo#:#entry_title#:#Title (Default Language)###28 10 2024 new variable -gsfo#:#entry_toggle_activation#:#(De-)Activate###28 10 2024 new variable -gsfo#:#group_activation_toggled#:#Activation has been toggled###28 10 2024 new variable -gsfo#:#group_active#:#Active###28 10 2024 new variable -gsfo#:#group_active_info#:#Activate this Group###28 10 2024 new variable -gsfo#:#group_add#:#Add Group###28 10 2024 new variable -gsfo#:#group_delete#:#Delete###28 10 2024 new variable -gsfo#:#group_deleted#:#Deleted###28 10 2024 new variable -gsfo#:#group_edit#:#Edit Group###28 10 2024 new variable -gsfo#:#group_edit_entries#:#Edit Entries###28 10 2024 new variable -gsfo#:#group_items#:#Items###28 10 2024 new variable -gsfo#:#group_not_empty#:#This Group contains Entries. Please move or delete them first.###28 10 2024 new variable -gsfo#:#group_title#:#Title (Default Language)###28 10 2024 new variable -gsfo#:#group_title_info#:#Additional Translations can be added with the Action "Add Translation" after saving the Group.###28 10 2024 new variable -gsfo#:#group_toggle_activation#:#(De-)Activate###28 10 2024 new variable -gsfo#:#group_translate#:#Translate###28 10 2024 new variable -gsfo#:#info_not_deletable_core#:#Default Items cannot be deleted.###28 10 2024 new variable -gsfo#:#info_not_deletable_not_empty#:#Groups with Entries cannot be deleted.###28 10 2024 new variable -gsfo#:#legal_information#:#Legal Information###28 10 2024 new variable -gsfo#:#order_saved#:#Order saved###28 10 2024 new variable -gsfo#:#permanent#:#permanent###28 10 2024 new variable -gsfo#:#reset_footer#:#Reset Footer###28 10 2024 new variable -gsfo#:#reset_success#:#Footer has been reset successfully###28 10 2024 new variable -gsfo#:#services#:#Services###28 10 2024 new variable -gsfo#:#support#:#Support###28 10 2024 new variable -gsfo#:#translate#:#Translate###29 10 2025 new variable -gsfo#:#translations#:#Translations###29 10 2025 new variable -help#:#gdtr_active#:#Active###29 10 2025 new variable -help#:#gdtr_add_step#:#Add Step###29 10 2025 new variable -help#:#gdtr_add_tour#:#Add Tour###29 10 2025 new variable -help#:#gdtr_close#:#End Tour###29 10 2025 new variable -help#:#gdtr_delete_step#:#Delete Step###29 10 2025 new variable -help#:#gdtr_delete_step_mess#:#Are you sure you want to delete this step?###29 10 2025 new variable -help#:#gdtr_delete_tour#:#Delete Tour###29 10 2025 new variable -help#:#gdtr_delete_tour_mess#:#Are you sure you want to delete this tour?###29 10 2025 new variable -help#:#gdtr_deleted_step#:#Step has been deleted.###29 10 2025 new variable -help#:#gdtr_deleted_tour#:#Tour has been deleted.###29 10 2025 new variable -help#:#gdtr_edit_content#:#Edit Content###29 10 2025 new variable -help#:#gdtr_edit_page_info#:#Edit the content that should be presented to explain the selected UI element.###29 10 2025 new variable -help#:#gdtr_edit_properties#:#Edit Properties###29 10 2025 new variable -help#:#gdtr_edit_step_info#:#On this screen you define, which element on the screen should be explained in this step of the tour. A popover with the explanation text you define will be presented pointing to this element.###29 10 2025 new variable -help#:#gdtr_edit_steps#:#Edit Steps###29 10 2025 new variable -help#:#gdtr_element_id#:#Element ID###29 10 2025 new variable -help#:#gdtr_form#:#Form###29 10 2025 new variable -help#:#gdtr_form_info#:#The first form of the main content area. Usually views should only contain one form.###29 10 2025 new variable -help#:#gdtr_guided_tours#:#Guided Tours###29 10 2025 new variable -help#:#gdtr_id_pres_users#:#Show IDs for User Accounts###29 10 2025 new variable -help#:#gdtr_id_pres_users_info#:#Login names of user that should get element IDs presented. Separate multiple entries by comma.###29 10 2025 new variable -help#:#gdtr_id_settings#:#ID Settings###29 10 2025 new variable -help#:#gdtr_import_tour#:#Import Tour###29 10 2025 new variable -help#:#gdtr_language#:#Language###29 10 2025 new variable -help#:#gdtr_language_info#:#Activates a guided tour only for users with the selected language.###29 10 2025 new variable -help#:#gdtr_list_tours_mess#:#To activate the presentation of screen and element IDs as tooltips, switch to ID Settings and enter your account name.###29 10 2025 new variable -help#:#gdtr_mainbar#:#Mainbar###29 10 2025 new variable -help#:#gdtr_mainbar_info#:#The mainbar ist the main menu on the left side. If element-ID presentation is activated, the IDs will be shown in tooltips for the distinct items.###29 10 2025 new variable -help#:#gdtr_metabar#:#Metabar###29 10 2025 new variable -help#:#gdtr_metabar_info#:#The metabar is the menu on the top, right. If element-ID presentation is activated, the IDs will be shown in tooltips for the distinct items.###29 10 2025 new variable -help#:#gdtr_next_step#:#Next Step###29 10 2025 new variable -help#:#gdtr_permission#:#Permission###29 10 2025 new variable -help#:#gdtr_permission_info#:#Activates a guided tour only for users with a certain permission on the current repository object, e.g. only for users with "edit settings" permission for a course. If you "Create" is selected, the tour is active, if the user has any creation permission.###29 10 2025 new variable -help#:#gdtr_primary_button#:#Primary Button###29 10 2025 new variable -help#:#gdtr_primary_button_info#:#The first primary button of the main content area. Primary buttons are presented emphasised compared to standard buttons. Usually views should only contain one primary button.###29 10 2025 new variable -help#:#gdtr_reset_tour#:#Reset Tour###29 10 2025 new variable -help#:#gdtr_reset_tour_mess#:#If you reset the tour, all users that previously ended the tour, will get the tour presented again. Are you sure to proceed?###29 10 2025 new variable -help#:#gdtr_screen_ids#:#Screen IDs###29 10 2025 new variable -help#:#gdtr_screen_ids_info#:#Enable a guided tour only for distinct views of the system. If element IDs are activated, you find the Screen ID of a current view on top in the header. Multiple IDs must be separated by comma.###29 10 2025 new variable -help#:#gdtr_step#:#Step###29 10 2025 new variable -help#:#gdtr_step_type#:#User Interface Element###29 10 2025 new variable -help#:#gdtr_table#:#Table###29 10 2025 new variable -help#:#gdtr_table_info#:#The first table of the main content area. Usually views should only contain one table.###29 10 2025 new variable -help#:#gdtr_tabs#:#Tabs###29 10 2025 new variable -help#:#gdtr_tabs_info#:#The tabs are displayed below the main header of the screen. If element-ID presentation is activated, the IDs will be shown in tooltips for the distinct items.###29 10 2025 new variable -help#:#gdtr_toolbar#:#Toolbar###29 10 2025 new variable -help#:#gdtr_toolbar_info#:#The first toolbar of the main content area, usually presented below the tabs. Views should only contain one toolbar.###29 10 2025 new variable -help#:#gdtr_tour_has_been_reset#:#Tour has been reset.###29 10 2025 new variable -help#:#gdtr_tour_steps#:#Tour Steps###29 10 2025 new variable -help#:#gdtr_tours#:#Tours###29 10 2025 new variable -help#:#gdtr_type#:#Type###29 10 2025 new variable -help#:#guided_tour#:#Guided Tour###29 10 2025 new variable +gsfo#:#accessibility#:#Hozzáférhetőség +gsfo#:#confirm_delete#:#Biztos, hogy törli a következő elem(ek)et? +gsfo#:#confirm_reset#:#A lábléc alapértelmezettre állítása az összes elemet eredeti állapotába állítja. A személyre szabások és a kézi bejegyzések visszavonhatatlanul törlődnek. Biztos, hogy folytatja? +gsfo#:#entries_add#:#Elem hozzáadása +gsfo#:#entries_edit#:#Elem módosítása +gsfo#:#entries_parent#:#Blokk kiválasztása +gsfo#:#entries_select_parent#:#Elem mozgatása a csoportba +gsfo#:#entries_target_group#:#Select target group###07 07 2026 new variable +gsfo#:#entry_action#:#Link +gsfo#:#entry_action_info#:#Teljes link a protokollal (pl. https://www.ilias.hu) +gsfo#:#entry_activation_toggled#:#Az aktiválás megváltozott +gsfo#:#entry_active#:#Aktív +gsfo#:#entry_active_info#:#Elem aktiválása +gsfo#:#entry_add#:#Elem hozzáadása +gsfo#:#entry_delete#:#Törlés +gsfo#:#entry_deleted#:#Törölt +gsfo#:#entry_deleted_failed#:#Deletion not possible###07 07 2026 new variable +gsfo#:#entry_edit#:#Módosítás +gsfo#:#entry_external#:#Megnyitás új lapon +gsfo#:#entry_move#:#Áthelyezés +gsfo#:#entry_moved#:#Az elemet sikeresen áthelyezte +gsfo#:#entry_title#:#Cím (alapértelmezett nyelven) +gsfo#:#entry_toggle_activation#:#(In-)Aktiválás +gsfo#:#group_activation_toggled#:#Az aktiváció megváltozott +gsfo#:#group_active#:#Aktív +gsfo#:#group_active_info#:#Blokk aktiválása +gsfo#:#group_add#:#Blokk hozzáadása +gsfo#:#group_delete#:#Törlés +gsfo#:#group_deleted#:#Törölt +gsfo#:#group_edit#:#Blokk módosítása +gsfo#:#group_edit_entries#:#Elem módosítása +gsfo#:#group_items#:#Elemek +gsfo#:#group_not_empty#:#Ebben a blokkban vannak elemek. Először ezeket helyezze át vagy törölje +gsfo#:#group_title#:#Cím (alapértelmezett nyelv) +gsfo#:#group_title_info#:#A blokk mentése után további fordításokat adhat hozzá a ‘Fordítás hozzáadása’ művelettel. +gsfo#:#group_toggle_activation#:#(In-)aktiválás +gsfo#:#group_translate#:#Fordítás +gsfo#:#info_not_deletable_core#:#Az alapértelmezett elemek nem törölhetők +gsfo#:#info_not_deletable_not_empty#:#Csak üres blokk törlhetők. +gsfo#:#item_moved#:#Entry moved###07 07 2026 new variable +gsfo#:#legal_information#:#Jogi információk +gsfo#:#order_saved#:#A sorbarendezést sikeresen mentette +gsfo#:#permanent#:#állandó +gsfo#:#reset_footer#:#Lábléc alapértelmezettre állítása +gsfo#:#reset_success#:#A láblécet sikeresen alapértelmezettre állította +gsfo#:#services#:#Szolgáltatások +gsfo#:#support#:#Támogatás +gsfo#:#translate#:#Fordítás +gsfo#:#translations#:#Fordítások +help#:#gdtr_active#:#Aktív +help#:#gdtr_add_step#:#Lépés hozzáadása +help#:#gdtr_add_tour#:#Túra hozzáadása +help#:#gdtr_close#:#Túra vége +help#:#gdtr_delete_step#:#Lépés törlése +help#:#gdtr_delete_step_mess#:#Biztos, hogy törli ezt a lépést? +help#:#gdtr_delete_tour#:#Túra törlése +help#:#gdtr_delete_tour_mess#:#Biztos, hogy törli ezt a túrát? +help#:#gdtr_deleted_step#:#A lépést sikeresen törölte. +help#:#gdtr_deleted_tour#:#A túrát sikeresen törölte. +help#:#gdtr_edit_content#:#Tartalom módosítása +help#:#gdtr_edit_page_info#:#A kiválasztott felhasználói felület elemét elmagyarázó tartalom szerkesztése. +help#:#gdtr_edit_properties#:#Tulajdonságok módosítása +help#:#gdtr_edit_step_info#:#Itt azt határozhatja meg, hogy a képernyőn melyik elemét magyarázzuk a túra következő lépésében. Egy erre az elemre mutató felugró ablak az Ön által meghatározott magyarázó szöveggel jelenik meg. +help#:#gdtr_edit_steps#:#Lépések módosítása +help#:#gdtr_element_id#:#Elem ID +help#:#gdtr_form#:#Űrlap +help#:#gdtr_form_info#:#A fő tartalomterület első űrlapja. Minden nézet általában egy ilyen űrlapot tartalmaz. +help#:#gdtr_guided_tours#:#Vezetett túrák +help#:#gdtr_id_pres_users#:#Felhasználók, akiknek az ID-k megjelenítések +help#:#gdtr_id_pres_users_info#:#Felhasználónevek, akiknek a SCREEN-ID és túra lépésihez megadandó elem-ID-k megjelenjenek. Ha többet ad meg, azokat vesszővel válassza el. +help#:#gdtr_id_settings#:#ID beállítások +help#:#gdtr_import_tour#:#Túra importálása +help#:#gdtr_language#:#Nyelv +help#:#gdtr_language_info#:#Túra aktiválása csak a kiválasztott nyelvet használó felhasználók számára. +help#:#gdtr_list_tours_mess#:#A képernyő- és az elem-ID-k megjelenítéséhez, menjen az ID-beállításokhoz és adja meg felhasználónevét. +help#:#gdtr_mainbar#:#Fősáv +help#:#gdtr_mainbar_ID_info#:#A fősáv adott elemének ID-je. Húzza az egeret az elem fölé, hogy az ID buboréksúgóban megjelenjen. +help#:#gdtr_mainbar_info#:#A bal oldali menű a Fősáv. Ha az elem-ID megjelenítése aktív, az ID-k ez elemek buboréksúgójában jelennek meg. +help#:#gdtr_metabar#:#Metasáv +help#:#gdtr_metabar_ID_info#:#A metasáv adott elemének ID-je. Húzza az egeret az elem fölé, hogy az ID a buboréksúgóban megjelenjen. +help#:#gdtr_metabar_info#:#A metasáv a felül, jobb oldalon található menü. Ha az elem-ID megjelenítése be van kapcsolva, az ID-k az adott elem buboréksúgójában jelennek meg. +help#:#gdtr_next_step#:#Következő lépés +help#:#gdtr_permission#:#Jogosultság +help#:#gdtr_permission_info#:#A vezetett túrát csak az objektumhoz adott jogosultsággal rendelkező felhasználóknak kapcsoljuk be, például egy kurzuhoz csak ‘beállítások módosítása’ jogosultságggal rendelkezőknek. Amennyiben a ‘Létrehozás’-t választja, a vezetett túra csak a létrehozási jogosultsággal rendelkezőknek jelenik meg. +help#:#gdtr_presentation_limitation#:#A megjelenítés korlátja +help#:#gdtr_primary_button#:#Elsődleges gomb +help#:#gdtr_primary_button_info#:#A fő tartalomterület első elsődleges gombja. Az elsődleges gombok kiemelten jelennek meg a standard gombokhoz képest. Minden nézet általában egy ilyen gombot tartalmaz. +help#:#gdtr_reset_tour#:#Túra visszaállítása +help#:#gdtr_reset_tour_mess#:#Ha visszaállítja a túrát, akkor minden felhasználó, aki korábban befejezte a túrát, újra látni fogja azt. Biztos, hogy folytatja? +help#:#gdtr_screen_ids#:#Screen-ID-k +help#:#gdtr_screen_ids_info#:#Csak a rendszer különböző nézeteihez engedélyezzen vezetett túrát. Ha az elem-ID-k aktiválva vannak, az aktuális nézet Screen-ID a fejléc tetején található. Több ID-t vesszővel válasszon el. +help#:#gdtr_step#:#Lépés +help#:#gdtr_step_type#:#Felhasználói interfész elem +help#:#gdtr_table#:#Tábla +help#:#gdtr_table_info#:#A fő tartalomterület első táblázata. Minden nézet általában egy ilyen eszköztárat tartalmaz. +help#:#gdtr_tabs#:#Fülek +help#:#gdtr_tabs_ID_info#:#A fül azonosítója. Vigye az egérmutatót egy fül fölé, hogy az azonosító jelenjen meg. +help#:#gdtr_tabs_info#:#A fülek a képernyő fő fejléce alatt jelennek meg. Amennyiben az elem-ID megjelenítése be van kapcsolva, az ID-k az adott elem buboréksúgójában jelennek meg. +help#:#gdtr_toolbar#:#Eszköztár +help#:#gdtr_toolbar_info#:#A fő tartalomterület első eszköztára, amely általában a fülek alatt jelenik meg. Minden nézet csak egy ilyen eszköztárat tartalmaz. +help#:#gdtr_tour_has_been_reset#:#A túrát sikeresen reszetelte. +help#:#gdtr_tour_settings#:#Beállítások módosítása +help#:#gdtr_tour_steps#:#Túra lépései +help#:#gdtr_tours#:#Túrák +help#:#gdtr_type#:#Típus +help#:#guided_tour#:#Vezetett túra help#:#help_all#:#Összes help#:#help_component#:#Komponens help#:#help_filter#:#Szűrő @@ -10556,24 +10593,24 @@ help#:#help_module_uploaded#:#Súgócsomag feltöltve. help#:#help_modules#:#Súgócsomagok help#:#help_no_content#:#Nincs segítő tartalom ehhez a képernyőhöz. Megpróbálhatja a keresővel. help#:#help_open_online_help#:#Online súgó megnyitása -help#:#help_order#:#Order###26 08 2024 new variable -help#:#help_search_label#:#Search Help###29 07 2022 new variable -help#:#help_select_a_file#:#Please select a file.###26 08 2024 new variable +help#:#help_order#:#Rendezés +help#:#help_search_label#:#Súgó keresése +help#:#help_select_a_file#:#Válasszon egy fájlt. help#:#help_set_mode#:#Mód beállítása help#:#help_sure_delete_help_modules#:#Biztos, hogy törli ezeket a csomagokat? help#:#help_toggle_tooltips#:#Buboréksúgók -help#:#help_toggle_tooltips_info#:#Menüpontok és fülek buboréksúgójának megjelenítése. +help#:#help_toggle_tooltips_info#:#Menüpontok és lapok buboréksúgójának megjelenítése. help#:#help_tooltip_id#:#Buboréksúgó-ID help#:#help_tooltips#:#Buboréksúgó help#:#help_tooltips_and_help#:#Buboréksúgók és munkamenet súgó help#:#help_tooltips_only#:#Csak buboréksúgók help#:#help_topcis#:#Témasúgó help#:#help_tt_text#:#Szöveg -htlm#:#file_import_from_upload_dir_failed#:#File from Upload-Directory not imported###29 10 2025 new variable -htlm#:#file_imported_from_upload_dir#:#File imported from Upload-Directory###29 10 2025 new variable -htlm#:#import_from_upload_dir#:#Import from Upload-Directory###29 10 2025 new variable -htlm#:#import_from_upload_dir_file_name#:#Filename###29 10 2025 new variable -htlm#:#import_from_upload_dir_info#:#Please select file for import###29 10 2025 new variable +htlm#:#file_import_from_upload_dir_failed#:#A fájlt importálása a Feltöltési mappából sikertelen +htlm#:#file_imported_from_upload_dir#:#A fájlt sikeresen importálta a Feltöltési mappából +htlm#:#import_from_upload_dir#:#Importálás a Feltöltési mappából +htlm#:#import_from_upload_dir_file_name#:#Fáj neve +htlm#:#import_from_upload_dir_info#:#Válasszon egy importfájlt iass#:#download_assessment_paper#:#Felvétel-fájl letöltése iass#:#grading#:#Értékelés iass#:#grading_info#:#Értékelésinformáció @@ -10623,10 +10660,10 @@ iass#:#iass_mails#:#E-mail cím iass#:#iass_may_not_finalize#:#Az értékelés még nincs véglegesítve. Először értékelje a felhasználót. iass#:#iass_membership_finalized#:#Bejegyzés véglegesítve iass#:#iass_membership_saved#:#A bejegyzést sikeresen mentett, de az még nincs véglegesítve -iass#:#iass_mess_notification_completed#:#'%s' értékelést sikeresen teljesítette. Kérem, ellenőrizze az alábbi értékelési bejegyzés részleteit: -iass#:#iass_mess_notification_failed#:#'%s' értékelést nem sikerült teljesítenie. Kérem, ellenőrizze az alábbi értékelési bejegyzés részleteit: -iass#:#iass_notify#:#Véglegesítés után az értékelt értesítése -iass#:#iass_notify_explanation#:#A véglegesítésről levélben értesítjük az értékeltet, tovább hozzáférést biztosítunk számára a saját bejegyzéséhez az információs fülön. +iass#:#iass_mess_notification_completed#:#‘%s’ értékelést sikeresen teljesítette. Kérem, ellenőrizze az alábbi értékelési bejegyzés részleteit: +iass#:#iass_mess_notification_failed#:#‘%s’ értékelést nem sikerült teljesítenie. Kérem, ellenőrizze az alábbi értékelési bejegyzés részleteit: +iass#:#iass_notify#:#Az eredmény elérhetővé tétel a résztvevő számára +iass#:#iass_notify_explanation#:#A véglegesítésről levélben értesítjük az értékeltet, tovább hozzáférést biztosítunk számára a saját bejegyzéséhez az információs lapon. iass#:#iass_phone#:#Telefonszám iass#:#iass_place#:#Értékelés helyszíne iass#:#iass_record#:#Megjegyzés @@ -10636,14 +10673,14 @@ iass#:#iass_record_template_explanation#:#Értékelési sablon, melyet automatik iass#:#iass_remove_user_qst#:#Biztos, hogy eltávolítja az értékelendőt? iass#:#iass_responsibility#:#Felelősségi kör iass#:#iass_save_amend#:#Utólagos módosított értékelés mentése -iass#:#iass_settings_availability#:#Availability###26 08 2024 new variable +iass#:#iass_settings_availability#:#Elérhetőség iass#:#iass_settings_saved#:#A beállításokat sikeresen mentette. -iass#:#iass_sort_changetime_asc#:#Utolsó módosítás (növekvő) -iass#:#iass_sort_changetime_desc#:#Utolsó módosítás (csökkenő) -iass#:#iass_sort_examiner_login_asc#:#Értékelő (növekvő) -iass#:#iass_sort_examiner_login_desc#:#Értékelő (csökkenő) -iass#:#iass_sort_name_asc#:#Felhasználónév (növekvő) -iass#:#iass_sort_name_desc#:#Felhasználónév (csökkenő) +iass#:#iass_sort_changetime_asc#:#Utolsó módosítás ↑ +iass#:#iass_sort_changetime_desc#:#Utolsó módosítás ↓ +iass#:#iass_sort_examiner_login_asc#:#Értékelő A→Z +iass#:#iass_sort_examiner_login_desc#:#Értékelő Z→A +iass#:#iass_sort_name_asc#:#Felhasználónév A→Z +iass#:#iass_sort_name_desc#:#Felhasználónév Z→A iass#:#iass_status_completed#:#Sikeresen teljesítette iass#:#iass_status_failed#:#Nem teljesítette iass#:#iass_status_pending#:#Még nincs értékelve @@ -10653,134 +10690,142 @@ iass#:#iass_upload_file#:#Fájl rögzítése iass#:#iass_user_removed#:#A felhasználót sikeresen eltávolította. iass#:#iass_usr_amend#:#Értékelés utólagos módosítása iass#:#iass_usr_download_attachment#:#Csatolmány letöltése -iass#:#iass_usr_edit#:#Bejegyzés és tanulási haladás módosítása +iass#:#iass_usr_edit#:#Résztvevői bejegyzés módosítása iass#:#iass_usr_remove#:#Értékelendő eltávolítása a hozzárendelésből iass#:#iass_usr_view#:#Bejegyzés iass#:#il_iass_members#:#Értékelendők iass#:#lp_inactive#:#Megjegyzés: erre az objektumra a tanulási haladás ki van kapcsolva, így a tagságok lehet, hogy nem véglegesíthetőek. -iass#:#save_amend#:#Save Amended Record###26 08 2024 new variable +iass#:#save_amend#:#Módosított bejegyzés mentése impr#:#impr_page_type_impr#:#Impresszum init#:#init_error_authentication_fail#:#Hitelesítés sikertelen. init#:#init_error_maintenance#:#A szerver karbantartás miatt nem elérhető. Elnézést az esetleges kellemetlenségért. init#:#init_error_redirect_click#:#Kattintson a folytatáshoz. init#:#init_error_redirect_info#:#Az átirányítás nem támogatott. -irss#:#action_download#:#Download###26 08 2024 new variable -irss#:#action_goto#:#Open Resource###26 08 2024 new variable -irss#:#action_remove_resource#:#Delete Resource###26 08 2024 new variable -irss#:#action_remove_resource_msg#:#Do you want to delete the following Resource(s)?###26 08 2024 new variable -irss#:#action_remove_zip_path#:#Delete path###26 08 2024 new variable -irss#:#action_remove_zip_path_msg#:#Would you like to delete the following paths?###26 08 2024 new variable -irss#:#action_show_revisions#:#Show Revisions###26 08 2024 new variable -irss#:#by_creation_date_asc#:#By Creation Date (Ascending)###26 08 2024 new variable -irss#:#by_creation_date_desc#:#By Creation Date (Descending)###26 08 2024 new variable -irss#:#by_size_asc#:#By File Size (Ascending)###26 08 2024 new variable -irss#:#by_size_desc#:#By File Size (Descending)###26 08 2024 new variable -irss#:#by_title_asc#:#By Title (Ascending)###26 08 2024 new variable -irss#:#by_title_desc#:#By Title (Descending)###26 08 2024 new variable -irss#:#create_directory#:#Create Directory###26 08 2024 new variable -irss#:#creation_date#:#Creation Date (This Revision)###26 08 2024 new variable -irss#:#directory_name#:#Directory Name###26 08 2024 new variable -irss#:#directory_name_info#:#Name of the directory to be inserted at the current location.###26 08 2024 new variable -irss#:#download_zip#:#Download all files as ZIP###26 08 2024 new variable -irss#:#file_size#:#File Size (This Revision)###26 08 2024 new variable -irss#:#file_size_bigger_than#:#File Size > MB###26 08 2024 new variable -irss#:#full_size#:#Resource Size (All Revisions)###26 08 2024 new variable -irss#:#home_directory#:#Root-Directory###26 08 2024 new variable -irss#:#max_revision#:#Max. Revision###29 07 2022 new variable -irss#:#msg_error_adding_directory#:#The directory could not be created.###26 08 2024 new variable -irss#:#msg_success_adding_directory#:#The directory was created successfully.###26 08 2024 new variable -irss#:#msg_upload#:#Drop Files to upload###26 08 2024 new variable -irss#:#resource_id#:#Resource ID###29 07 2022 new variable -irss#:#resource_no_stakeholder_uri#:#No Stakeholder provides a valid Link to the usage of this Resource.###26 08 2024 new variable -irss#:#resource_overview#:#Resource Overview###26 08 2024 new variable -irss#:#revision#:#Revision###26 08 2024 new variable -irss#:#revision_status#:#Status###26 08 2024 new variable -irss#:#revision_status_10#:#Published###26 08 2024 new variable -irss#:#revision_status_20#:#Draft###26 08 2024 new variable -irss#:#revisions#:#Available Revisions###26 08 2024 new variable -irss#:#rid_deleted#:#File removed###26 08 2024 new variable -irss#:#rids_appended#:#Resource(s) added###26 08 2024 new variable -irss#:#rids_appended_failed#:#No Resource(s) added###29 10 2025 new variable -irss#:#rids_deleted#:#Resource(s) deleted###26 08 2024 new variable -irss#:#rids_updated#:#Ressource(n) updated###26 08 2024 new variable -irss#:#sorting#:#Default Ordering###26 08 2024 new variable -irss#:#sorting_1#:#By Title (Ascending)###26 08 2024 new variable -irss#:#sorting_2#:#By Title (Descending)###26 08 2024 new variable -irss#:#sorting_3#:#By File Size (Ascending)###26 08 2024 new variable -irss#:#sorting_4#:#By File Size (Descending)###26 08 2024 new variable -irss#:#sorting_5#:#By Creation Date (Ascending)###26 08 2024 new variable -irss#:#sorting_6#:#By Creation Date (Descending)###26 08 2024 new variable -irss#:#stakeholders#:#Stakeholders###29 07 2022 new variable -irss#:#storage_id#:#Storage ID###29 07 2022 new variable -irss#:#storage_info#:#Storage Information###29 07 2022 new variable -irss#:#title_manage_container#:#Manage files and folders###26 08 2024 new variable -irss#:#type#:#File Type###26 08 2024 new variable -irss#:#upload_field_title#:#Selected Files###26 08 2024 new variable -irss#:#upload_modal_title#:#Add Files###26 08 2024 new variable +irss#:#action_download#:#Letöltés +irss#:#action_goto#:#Erőforrás megnyitása +irss#:#action_remove_resource#:#Erőforrás törlése +irss#:#action_remove_resource_msg#:#Biztos, hogy törli a következő erőforrásokat? +irss#:#action_remove_zip_path#:#Útvonal törlése +irss#:#action_remove_zip_path_msg#:#Biztos, hogy törli a következő útvonalat? +irss#:#action_show_revisions#:#Felülvizsgálatok megjelenítése +irss#:#by_creation_date_asc#:#Létrehozás dátum szerint ↑ +irss#:#by_creation_date_desc#:#Létrehozás dátum szerint ↓ +irss#:#by_size_asc#:#Fájl mérete szerint ↑ +irss#:#by_size_desc#:#Fájl mérete szerint ↓ +irss#:#by_title_asc#:#Cím szerint A→Z +irss#:#by_title_desc#:#Cím szerint Z→A +irss#:#create_directory#:#Mappa létrehozása +irss#:#creation_date#:#Létrehozás dárum (Ez a felülvizsgálat) +irss#:#directory_name#:#Mappa neve +irss#:#directory_name_info#:#A jelenlegi helyre beillesztendő mappa neve. +irss#:#download_zip#:#Az összes fájl letöltés ZIP-ben +irss#:#entries_target_group#:#válasszon célcsoportot +irss#:#entry_deleted_failed#:#A törlés nem lehetséges +irss#:#file_size#:#Fájl mérete (Ez a felülvizsgálat) +irss#:#file_size_bigger_than#:#Fájl mérete nagyobb, mint (MB)###Fájlméret > MB +irss#:#full_size#:#Erőforrás mérete (Összes felülvizsgálat) +irss#:#home_directory#:#Gyökérkönyvtár +irss#:#item_moved#:#A bejegyzést sikeresen mozgatta +irss#:#max_revision#:#Felülvizsgálatok maximális száma +irss#:#msg_error_adding_directory#:#A mappát nem sikerült létrehozni. +irss#:#msg_paths_deleted#:#Útvonal(ak)at sikeresen törölte +irss#:#msg_success_adding_directory#:#A mappát sikeresen létrehozta. +irss#:#msg_upload#:#Dobd ide a feltöltendő fájlokat +irss#:#no_parent_selected#:#Nincs kiválasztva célcsoport +irss#:#resource_id#:#Erőforrás ID +irss#:#resource_no_stakeholder_uri#:#Ennek az erőforrásnak egy érvényes felhsználási linkje sincs. +irss#:#resource_overview#:#Áttekintés +irss#:#revision#:#Felülvizsgálat +irss#:#revision_status#:#Állapot +irss#:#revision_status_10#:#Közzétéve +irss#:#revision_status_20#:#Piszkozat +irss#:#revisions#:#Elérhető felülvizsgálatok +irss#:#rid_deleted#:#A fájl eltávolították +irss#:#rids_appended#:#Az erőforrás(oka)t sikeresen hozzáadta +irss#:#rids_appended_failed#:#Egy erőforrást sem sikerült hozzáadni +irss#:#rids_deleted#:#Az erőforrás(oka)t sikeresen törölte +irss#:#rids_updated#:#Az erőforrás(oka)t sikeresen frissítette +irss#:#sorting#:#Alapértelmezett rendezés +irss#:#sorting_1#:#Cím szerint A→Z +irss#:#sorting_2#:#Cím szerint Z→A +irss#:#sorting_3#:#Fájl mérete szerint ↑ +irss#:#sorting_4#:#Fájl mérete szerint ↓ +irss#:#sorting_5#:#Létrehozás dátum szerint ↑ +irss#:#sorting_6#:#Létrehozás dátum szerint ↓ +irss#:#stakeholders#:#Eredet +irss#:#storage_id#:#Tárolási ID +irss#:#storage_info#:#Tárolási információ +irss#:#title_manage_container#:#Fájlok és mappák kezelése +irss#:#type#:#Fájl típusa +irss#:#upload_field_title#:#Kiválasztott fájlok +irss#:#upload_modal_title#:#Fájlok hozzáadása itgr#:#itgr_always_open#:#Mindig nyitva -itgr#:#itgr_assign_materials#:#Assign Materials###29 07 2022 new variable +itgr#:#itgr_assign_materials#:#Objektumok hozzárendelése itgr#:#itgr_assigned_materials#:#Hozzárendelt objektumok itgr#:#itgr_assignment#:#Hozzárendelve -itgr#:#itgr_behaviour#:#Blokkviselkedés -itgr#:#itgr_behaviour_info#:#A rendszer megőrzi a nyitott/zárt állapotot a jelenlegi felhasználó számára kijelentkezéséig. itgr#:#itgr_desc_info#:#Az objektumcsoport leírása nem jelenik meg az objektumcsoport tárolójában. +itgr#:#itgr_display#:#Display###07 07 2026 new variable +itgr#:#itgr_display_with_title#:#With Title###07 07 2026 new variable +itgr#:#itgr_display_with_title_and_toggleable#:#With Title, Item Group collapsible###07 07 2026 new variable +itgr#:#itgr_display_with_title_and_toggleable_initially#:#Initial state###07 07 2026 new variable +itgr#:#itgr_display_with_title_and_toggleable_initially_closed#:#initially closed###07 07 2026 new variable +itgr#:#itgr_display_with_title_and_toggleable_initially_open#:#initially opened###07 07 2026 new variable +itgr#:#itgr_display_without_title#:#Without Title###07 07 2026 new variable itgr#:#itgr_edit#:#Objektumcsoportok módosítása itgr#:#itgr_expandable_closed#:#Kibontható (kezdetben zárt) itgr#:#itgr_expandable_open#:#Kibontható (kezdetben nyitott) itgr#:#itgr_item#:#Objektum -itgr#:#itgr_list#:#List###29 07 2022 new variable -itgr#:#itgr_list_default#:#Default###29 07 2022 new variable -itgr#:#itgr_list_default_info#:#Inherits value from upper container.###29 07 2022 new variable -itgr#:#itgr_list_presentation#:#Item Presentation###29 07 2022 new variable +itgr#:#itgr_list#:#Felsorolás +itgr#:#itgr_list_default#:#Alapértelmezett +itgr#:#itgr_list_default_info#:#Értékek örökítése a feljebbi tárolókból. +itgr#:#itgr_list_presentation#:#Elemmegjelenítés itgr#:#itgr_materials#:#Objektumok -itgr#:#itgr_show_title#:#Cím megjelenítése -itgr#:#itgr_show_title_info#:#A objektumcsoport címének megjelenítése. -itgr#:#itgr_tile#:#Tiles###29 07 2022 new variable -itgr#:#itgr_tile_size#:#Tile Size###29 07 2022 new variable +itgr#:#itgr_tile#:#Csempe +itgr#:#itgr_tile_size#:#Csempe mérete jscalendar#:#about_calendar#:#Súgó -jscalendar#:#about_calendar_long#:#Dátumválasztók: - Év léptetése: « » - Hónap léptetése: < > - Tartsa nyomva a gombot a gyorsabb kiválasztáshoz. DHTML dátum/időpont választó (c) dynarch.com 2002-2003 Legfrissebb verzió: http://dynarch.com/mishoo/calendar.epl Terjeszti a GNU LGPL. Lásd http://gnu.org/licenses/lgpl.html a részletekért. -jscalendar#:#about_time#:# Időválasztó: - Kattintson a megfelelő időrészen megnöveléséhez - vagy Shift-kattintással csökkentéséhez - vagy kattintás-húzás a gyorsabb kiválasztáshoz. +jscalendar#:#about_calendar_long#:#Dátumválasztók: - Év léptetése: « » - Hónap léptetése: < > - Tartsa nyomva a gombot a gyorsabb kiválasztáshoz. DHTML dátum/időpont választó (c) dynarch.com 2002-2003 Legfrissebb verzió: http://dynarch.com/mishoo/calendar.epl Terjeszti a GNU LGPL. Lásd http://gnu.org/licenses/lgpl.html a részletekért. +jscalendar#:#about_time#:#Időválasztó: - Kattintson a megfelelő időrészen megnöveléséhez - vagy Shift-kattintással csökkentéséhez - vagy kattintás-húzás a gyorsabb kiválasztáshoz. jscalendar#:#day_first#:#%s megjelenítése először jscalendar#:#def_date_format#:#%Y-%m-%d jscalendar#:#drag_to_move#:#Fogd-és-vidd az áthelyezéshez jscalendar#:#go_today#:#Ugrás a mai naphoz -jscalendar#:#l_01#:#Január -jscalendar#:#l_02#:#Február -jscalendar#:#l_03#:#Március -jscalendar#:#l_04#:#Április -jscalendar#:#l_05#:#Május -jscalendar#:#l_06#:#Június -jscalendar#:#l_07#:#Július -jscalendar#:#l_08#:#Augusztus -jscalendar#:#l_09#:#Szeptember -jscalendar#:#l_10#:#Október -jscalendar#:#l_11#:#November -jscalendar#:#l_12#:#December -jscalendar#:#l_fr#:#Péntek -jscalendar#:#l_mo#:#Hétfő -jscalendar#:#l_sa#:#Szombat -jscalendar#:#l_su#:#Vasárnap -jscalendar#:#l_th#:#Csütörtök -jscalendar#:#l_tu#:#Kedd -jscalendar#:#l_we#:#Szerda +jscalendar#:#l_01#:#január +jscalendar#:#l_02#:#február +jscalendar#:#l_03#:#március +jscalendar#:#l_04#:#április +jscalendar#:#l_05#:#május +jscalendar#:#l_06#:#június +jscalendar#:#l_07#:#július +jscalendar#:#l_08#:#augusztus +jscalendar#:#l_09#:#szeptember +jscalendar#:#l_10#:#október +jscalendar#:#l_11#:#november +jscalendar#:#l_12#:#december +jscalendar#:#l_fr#:#péntek +jscalendar#:#l_mo#:#hétfő +jscalendar#:#l_sa#:#szombat +jscalendar#:#l_su#:#vasárnap +jscalendar#:#l_th#:#csütörtök +jscalendar#:#l_tu#:#kedd +jscalendar#:#l_we#:#szerda jscalendar#:#next_month#:#Következő hónap (tipp: tartsa nyomva) jscalendar#:#next_year#:#Következő év (tipp: tartsa nyomva) jscalendar#:#open_calendar#:#Dátum kiválasztása naptárból jscalendar#:#part_today#:# (ma) jscalendar#:#prev_month#:#Előző hónap (tipp: tartsa nyomva) jscalendar#:#prev_year#:#Előző év (tipp: tartsa nyomva) -jscalendar#:#s_01#:#Jan -jscalendar#:#s_02#:#Febr -jscalendar#:#s_03#:#Márc -jscalendar#:#s_04#:#Ápr -jscalendar#:#s_05#:#Máj -jscalendar#:#s_06#:#Jún -jscalendar#:#s_07#:#Júl -jscalendar#:#s_08#:#Aug -jscalendar#:#s_09#:#Szept -jscalendar#:#s_10#:#Okt -jscalendar#:#s_11#:#Nov -jscalendar#:#s_12#:#Dec +jscalendar#:#s_01#:#jan +jscalendar#:#s_02#:#febr +jscalendar#:#s_03#:#márc +jscalendar#:#s_04#:#ápr +jscalendar#:#s_05#:#máj +jscalendar#:#s_06#:#jún +jscalendar#:#s_07#:#júl +jscalendar#:#s_08#:#aug +jscalendar#:#s_09#:#szept +jscalendar#:#s_10#:#okt +jscalendar#:#s_11#:#nov +jscalendar#:#s_12#:#dec jscalendar#:#s_fr#:#P jscalendar#:#s_mo#:#H jscalendar#:#s_sa#:#Szo @@ -10790,21 +10835,21 @@ jscalendar#:#s_tu#:#K jscalendar#:#s_we#:#Sze jscalendar#:#select_date#:#Dátum kiválasztása jscalendar#:#time#:#Idő -jscalendar#:#time_part#:#(Shift-) Kattintás vagy vonszolás értékváltoztatáshoz +jscalendar#:#time_part#:#(Shift-) Kattintson vagy fogja az értékváltoztatáshoz jscalendar#:#today#:#Ma jscalendar#:#tt_date_format#:#%a, %b %e jscalendar#:#wk#:#hét ldap#:#add_ldap_server#:#Szerver hozzáadása -ldap#:#ldap_add_missing#:#Hiányzó szerepek összerendelése -ldap#:#ldap_add_role_ass_rule#:#Új szerep a szerep-összerendelésekhez -ldap#:#ldap_add_roles#:#Add Roles###29 10 2025 new variable +ldap#:#ldap_add_missing#:#Hiányzó szerepkörök összerendelése +ldap#:#ldap_add_role_ass_rule#:#Új szerepkör a szerep-összerendelésekhez +ldap#:#ldap_add_roles#:#Szerepkör hozzáadása ldap#:#ldap_as_ds#:#Adatok forrásaként -ldap#:#ldap_as_ds_info#:#Ha be van kapcsolva, ez az LDAP-konfiguráció a többi hitelesítési módszerrel együtt csak a felhasználói fiókok szinkronizációjához használható. A közvetlen LDAP-hitelesítés így nem lehetséges. +ldap#:#ldap_as_ds_info#:#Ez az LDAP-konfiguráció a többi hitelesítési módszerrel együtt (például CAS) csak a felhasználói fiókok szinkronizációjához használható. A közvetlen LDAP-hitelesítés így nem lehetséges. ldap#:#ldap_assignment_type#:#Hozzárendelési típus ldap#:#ldap_authentication_settings#:#Hitelesítési beállítások ldap#:#ldap_bind_anonymous#:#Kapcsolódás névtelenül ldap#:#ldap_bind_user#:#Kapcsolódás felhasználóval -ldap#:#ldap_btn_add_role_ass#:#Új szerep hozzáadása +ldap#:#ldap_btn_add_role_ass#:#Új szerepkör hozzáadása ldap#:#ldap_check_role_assignment#:#Legutóbbi bejelentkezések utáni szerep-összerendelések ldap#:#ldap_choose_role#:#Válasszon szabályt ldap#:#ldap_confirm_del_role_ass#:#Szerep-összerendelés törlése @@ -10812,14 +10857,14 @@ ldap#:#ldap_deleted_role_mapping#:#Összerendelés törlése ldap#:#ldap_deleted_rule#:#Kiválasztott összerendelését sikeresen törölte. ldap#:#ldap_dn_info#:#Adja meg az LDAP-csoport megkülönböztető nevét. ldap#:#ldap_edit_role_ass_rule#:#Szerep-összerendelési szabály módosítása -ldap#:#ldap_edit_role_assignment#:#Szerep módosítása -> Csoporthoz rendelés +ldap#:#ldap_edit_role_assignment#:#Szerepkör módosítása ➜ Csoporthoz rendelés ldap#:#ldap_err_missing_plugin_id#:#Valós bővítmény azonosítót adjon meg! -ldap#:#ldap_escapedn#:#Escape DN###29 07 2022 new variable -ldap#:#ldap_escapedn_info#:#If enabled, special characters in the "Distinguished Name (DN)" of user accounts are escaped in queries for group membership.###29 07 2022 new variable +ldap#:#ldap_escapedn#:#DN maszkolása +ldap#:#ldap_escapedn_info#:#A felhasználói fiókok ‘Megkülönböztetett név (DN)’-ében lévő speciális karaktereket maszkoljuk a csoporttagság lekérdézésében. ldap#:#ldap_filter_info#:#Szűrő, amely a keresési szűrőhöz a következőképpen adódik hozzá: (&(userattr=username)(userfilter)). Például (objectclass=user) -ldap#:#ldap_global_role#:#Globális szerep -ldap#:#ldap_global_role_assignment#:#ILIAS-szerep hozzárendelése -ldap#:#ldap_global_role_info#:#Válasszon egy ILIAS-szerepet, melynek az új felhasználó automatikusan tagja lesz. * A szerepkiválasztás kötelező, ha választott szinkronizációt. +ldap#:#ldap_global_role#:#Globális szerepkör +ldap#:#ldap_global_role_assignment#:#ILIAS-szerepkör hozzárendelése +ldap#:#ldap_global_role_info#:#Válasszon egy ILIAS-szerepkört, melynek az új felhasználó automatikusan tagja lesz. * A szerepkiválasztás kötelező, ha választott szinkronizációt. ldap#:#ldap_group_attribute#:#Csoport attribútuma ldap#:#ldap_group_attribute_info#:#A csoport attribútumának neve. Például cn ldap#:#ldap_group_dn#:#Csoport DN @@ -10828,38 +10873,38 @@ ldap#:#ldap_group_dn_short#:#Csoport DN: ldap#:#ldap_group_filter#:#LDAP-szűrő ldap#:#ldap_group_filter_info#:#Szűrő, amely a keresési szűrőhöz a következőképpen adódik hozzá: (&(groupattr=group)(memberattr=username)(groupfilter)). ldap#:#ldap_group_member#:#Csoporttagság attribútuma -ldap#:#ldap_group_member_info#:#A csoport attribútuma, ahol valószínűleg felhasználó DN található. Válassza a 'Attribútum értéke DN'-t, ha a tag attribútuma a felhasználó egyedi neve. +ldap#:#ldap_group_member_info#:#A csoport attribútuma, ahol valószínűleg felhasználó DN található. Válassza a ‘Attribútum értéke DN’-t, ha a tag attribútuma a felhasználó egyedi neve. ldap#:#ldap_group_member_optional#:#A csoporttagság választható ldap#:#ldap_group_member_short#:#Attribútum: ldap#:#ldap_group_membership#:#Csoporttagság ldap#:#ldap_group_name#:#Csoportok nevei ldap#:#ldap_group_name_info#:#A sikeres hitelesítéshez szükséges, hogy a felhasználó a csoportok egyikének tagja legyen. A csoportokat vesszővel elválasztva sorolja fel. Például Hallgatok, Oktatok -ldap#:#ldap_group_optional_info#:#Ha be van kapcsolva, nem szükséges a csoporttagság a sikeres hitelesítéshez. Adja meg ezen csoportok tagjainak felhasználószűrőjét:
    (&(userattr=username)(userfilter)) +ldap#:#ldap_group_optional_info#:#Nem szükséges a csoporttagság a sikeres hitelesítéshez. Adja meg ezen csoportok tagjainak felhasználószűrőjét:
    (&(userattr=username)(userfilter)) ldap#:#ldap_group_restrictions#:#Csoporttagság megszorítások ldap#:#ldap_group_scope#:#Keresési hatókör -ldap#:#ldap_group_scope_info#:#Hatókör csoport kereséséhez. Ha bizonytalan, válassza az 'Al'-t. +ldap#:#ldap_group_scope_info#:#Hatókör csoport kereséséhez. Ha bizonytalan, válassza az ‘Al’-t. ldap#:#ldap_group_search_base#:#Csoportkeresési alap ldap#:#ldap_group_user_filter#:#Felhasználószűrő ldap#:#ldap_ilias_role#:#ILIAS-szerepnév ldap#:#ldap_info_text#:#Információs szöveg -ldap#:#ldap_info_text_info#:#Ha meg van adva, ez a szöveg fog megjelenni az információs képernyőn azokhoz az objektumokhoz, amelyek ehhez a szerephez vannak rendelve. Választhatóan ez a szöveg elérhető a Tartalomtárban. -ldap#:#ldap_local_role#:#Lokális szerep +ldap#:#ldap_info_text_info#:#Ha meg van adva, ez a szöveg fog megjelenni az információs képernyőn azokhoz az objektumokhoz, amelyek ehhez a szerepkörhöz vannak rendelve. Választhatóan ez a szöveg elérhető a Tartalomtárban. +ldap#:#ldap_local_role#:#Lokális szerepkör ldap#:#ldap_mapping_info_type#:#Információ megjelenítése a Tartalomtárban ldap#:#ldap_mapping_table#:#LDAP-tulajdonságok összerendelése ILIAS felhasználói profillal ldap#:#ldap_mapping_template#:#Sablon objectClass-hoz ldap#:#ldap_member_info#:#A csoportobjektum tulajdonsága, ahol a felhasználó DN valószínűleg található. ldap#:#ldap_memberisdn#:#Attribútum értéke DN -ldap#:#ldap_missing_bind_user#:#A 'Kapcsolódás felhasználónévvel' opciót választotta. Adjon meg egy érvényes LDAP-felhasználónevet és jelszót! -ldap#:#ldap_missing_role_assignment#:#Válasszon egy globális szerepet, amelyhez hozzárendelésre kerülnek majd az új felhasználók! +ldap#:#ldap_missing_bind_user#:#A ‘Kapcsolódás felhasználónévvel’ opciót választotta. Adjon meg egy érvényes LDAP-felhasználónevet és jelszót! +ldap#:#ldap_missing_role_assignment#:#Válasszon egy globális szerepkört, amelyhez hozzárendelésre kerülnek majd az új felhasználók! ldap#:#ldap_moment_sync#:#Szinkronizáció típusa -ldap#:#ldap_new_role_assignment#:#Új szerep hozzáadása -> Csoport-összerendelés +ldap#:#ldap_new_role_assignment#:#Új szerepkör hozzáadása ➜ Csoport-összerendelés ldap#:#ldap_plugin#:#Összerendelés bővítménnyel ldap#:#ldap_plugin_id#:#Bővítmény azonosító ldap#:#ldap_plugin_info#:#Szerep-összerendelés érvényesítése bővítménnyel. Adjon meg egy valós bővítmény azonosítót! ldap#:#ldap_referrals#:#Átirányítások ldap#:#ldap_referrals_info#:#Bejelölése azt jelenti, hogy az LDAP-kiszolgáló automatikusan követi az átirányításokat. Active Directory Server esetén ne használja. -ldap#:#ldap_remove_deprecated#:#Érvénytelenített szerepek összerendelésének megszüntetése -ldap#:#ldap_remove_roles#:#Remove Roles###29 10 2025 new variable +ldap#:#ldap_remove_deprecated#:#Érvénytelenített szerepkörök összerendelésének megszüntetése +ldap#:#ldap_remove_roles#:#Szerepkörök eltávolítása ldap#:#ldap_role_active#:#Csoportszinkronizáció engedélyezése ldap#:#ldap_role_assignments#:#Szerep-összerendelés ldap#:#ldap_role_at_info#:#A hozzárendelés az LDAP-ban megadott speciális tulajdonságon alapszik. @@ -10872,17 +10917,17 @@ ldap#:#ldap_role_bind_user_info#:#Adjon meg egy egyedi LDAP felhasználónevet! ldap#:#ldap_role_by_attribute#:#LDAP-tulajdonság ldap#:#ldap_role_by_group#:#Csoporttagság ldap#:#ldap_role_by_plugin#:#Bővítménnyel -ldap#:#ldap_role_group_assignments#:#Létező szerep -> Csoport-összerendelések +ldap#:#ldap_role_group_assignments#:#Létező szerepkör ➜ Csoport-összerendelések ldap#:#ldap_role_grp_at#:#Tulajdonság ldap#:#ldap_role_grp_dn_info#:#Adja meg az LDAP-csoport megkülönböztető nevét! -ldap#:#ldap_role_grp_info#:#A megadott LDAP-csoport tagjai hozzárendelésre fognak kerülni az adott ILIAS-szerephez. +ldap#:#ldap_role_grp_info#:#A megadott LDAP-csoport tagjai hozzárendelésre fognak kerülni az adott ILIAS-szerepkörhöz. ldap#:#ldap_role_grp_isdn#:#Attribútum értéke DN -ldap#:#ldap_role_info#:#Adjon meg egy ILIAS-szerepet, amely felügyeli az LDAP-csoport tagságot. -ldap#:#ldap_role_mapping#:#LDAP-szerep -> LDAP-leképezés -ldap#:#ldap_role_name_info#:#Válasszon egy globális szerepet, vagy adja meg egy helyi szerep nevét. -ldap#:#ldap_role_not_exists#:#Nem létezik ilyen névvel szerep +ldap#:#ldap_role_info#:#Adjon meg egy ILIAS-szerepkört, amely felügyeli az LDAP-csoport tagságot. +ldap#:#ldap_role_mapping#:#LDAP-szerepkör ➜ LDAP-leképezés +ldap#:#ldap_role_name_info#:#Válasszon egy globális szerepkört, vagy adja meg egy helyi szerepkör nevét. +ldap#:#ldap_role_not_exists#:#Nem létezik ilyen névvel szerepkör ldap#:#ldap_role_selection#:#Szerepkiválasztás -ldap#:#ldap_role_selection_info#:#Nem egyértelmű a választása. Egyet válasszon az alábbi szerepek közül. +ldap#:#ldap_role_selection_info#:#Nem egyértelmű a választása. Egyet válasszon az alábbi szerepkörök közül. ldap#:#ldap_role_settings#:#LDAP csoportszinkronizációs beállítások ldap#:#ldap_rule_condition#:#feltétel ldap#:#ldap_rule_type#:#Hozzárendelés típusa @@ -10903,7 +10948,7 @@ ldap#:#ldap_servers#:#LDAP Szerver ldap#:#ldap_settings#:#Kiszolgáló beállításai ldap#:#ldap_sync_cron#:#Ütemezett feladattal ldap#:#ldap_sync_login#:#Bejelentkezéskor -ldap#:#ldap_tbl_role_ass#:#Aktív szerepek +ldap#:#ldap_tbl_role_ass#:#Aktív szerepkörök ldap#:#ldap_tls_conflict#:#LDAPv2 nem használható TLS-titkosítással. Válassza az LDAPv3-at, vagy tiltsa le a TLS-titkosítás használatát. ldap#:#ldap_update_field_info#:#Automatikus frissítés ldap#:#ldap_update_roles#:#Szerep-összerendelés @@ -10914,77 +10959,78 @@ ldap#:#ldap_user_scope#:#Keresési hatókör ldap#:#ldap_user_scope_info#:#A keresése hatóköre (scope). Ha bizonytalan, válassza az Al-t. ldap#:#ldap_user_sync#:#Felhasználói szinkronizációs beállítások ldap#:#ldap_user_sync_cron#:#LDAP-felhasználók szinkronizálása -ldap#:#ldap_user_sync_cron_info#:#Ha be van kapcsolva, az LDAP-szerverről importáljuk és folyamatos szinkronizáljuk a felhasználói fiókokat. +ldap#:#ldap_user_sync_cron_info#:#Az LDAP-szerverről importáljuk és folyamatos szinkronizáljuk a felhasználói fiókokat. ldap#:#ldap_user_sync_info#:#Annak meghatározása, hogy az új felhasználói fiókok automatikusan jöjjenek létre bejelentkezéskor vagy rendszeres időközönként ütemezett feladattal. ldap#:#ldap_username_filter#:#Felhasználónév szűrése -ldap#:#ldap_username_filter_info#:#* = helyettesítő karakterek -ldoc#:#deleteDocument#:#Delete###26 08 2024 new variable -ldoc#:#detachCriterionAssignment#:#Delete###26 08 2024 new variable -ldoc#:#ldoc_acceptance_history#:#Acceptance History###26 08 2024 new variable -ldoc#:#ldoc_account_reg_not_possible#:#Self-registration is currently not possible. Please contact your system administrator for further information.###26 08 2024 new variable -ldoc#:#ldoc_add_document_btn_label#:#Add Document###26 08 2024 new variable -ldoc#:#ldoc_agreement_document#:#Document###26 08 2024 new variable -ldoc#:#ldoc_agreement_document_missing#:#Missing###26 08 2024 new variable -ldoc#:#ldoc_agreement_documents_tab_label#:#Documents###26 08 2024 new variable -ldoc#:#ldoc_agreement_exists#:#Existent###26 08 2024 new variable -ldoc#:#ldoc_agreement_missing#:#Missing###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_country#:#Profile Country###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_country_info#:#Your document is displayed (and must be accepted the first time a user logs in) if the country set in their user profile matches the country criterion selected from the list below. Subsequent changes to the country in a user’s profile do not automatically lead to a new document being displayed. You cannot use the same country as the display criterion for more than one document.###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_global_role#:#User Has Global Role###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_global_role_info#:#The document is displayed (and must be accepted the first time a user logs in) if the global role the user has matches the global role selected from the list below. Subsequent changes to a user’s global role do not automatically lead to a new ToS document being displayed.###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_language#:#Profile Language###26 08 2024 new variable -ldoc#:#ldoc_crit_type_usr_language_info#:#Your document is displayed (and must be accepted) during registration if the user’s language (selected from the list below) matches the language used during registration; or upon login if the user switches to this language in their preferences. Please note that each language can only be set as the display criterion for a single document.###26 08 2024 new variable -ldoc#:#ldoc_criterion_assignment_cannot_match#:#It is not possible to use this particular criterion for displaying your document. Because of another criterion this document would never match.###26 08 2024 new variable -ldoc#:#ldoc_criterion_assignment_must_be_unique#:#It is not possible to use this particular criterion for displaying your document. This criterion already exists.###26 08 2024 new variable -ldoc#:#ldoc_deleted_documents_p#:#The documents have been deleted.###26 08 2024 new variable -ldoc#:#ldoc_deleted_documents_s#:#The document has been deleted.###26 08 2024 new variable -ldoc#:#ldoc_disabled#:#Disabled###26 08 2024 new variable -ldoc#:#ldoc_doc_crit_attached#:#The criterion for displaying your document has been set successfully.###26 08 2024 new variable -ldoc#:#ldoc_doc_crit_changed#:#The criterion for displaying your document has been changed.###26 08 2024 new variable -ldoc#:#ldoc_doc_crit_detached#:#The criterion has been removed.###26 08 2024 new variable -ldoc#:#ldoc_doc_delete#:#Delete Document###26 08 2024 new variable -ldoc#:#ldoc_doc_detach_crit_confirm_title#:#Remove Criterion###26 08 2024 new variable -ldoc#:#ldoc_doc_sure_detach_crit#:#Are you sure that you want to remove this as the criterion for displaying your document?###26 08 2024 new variable -ldoc#:#ldoc_document#:#Document###26 08 2024 new variable -ldoc#:#ldoc_enabled#:#Enabled###26 08 2024 new variable -ldoc#:#ldoc_form_attach_criterion_head#:#Select Criterion for Displaying your Document###26 08 2024 new variable -ldoc#:#ldoc_form_criterion#:#Criterion###26 08 2024 new variable -ldoc#:#ldoc_form_document#:#Document###26 08 2024 new variable -ldoc#:#ldoc_form_document_content_changed#:#The uploaded file has had its html <head> information removed by ILIAS. Please check the result and upload a new file if necessary.###26 08 2024 new variable -ldoc#:#ldoc_form_document_info#:#Please select a file from your local filesystem. You can either upload a plain text file, or a simple HTML file. HTML files will have their <head/gt; information removed – only the contents of the body element will be used.###26 08 2024 new variable -ldoc#:#ldoc_form_document_new#:#Change Content###26 08 2024 new variable -ldoc#:#ldoc_form_document_new_info#:#Here you can select a file from your local filesystem to change the contents of the document. You can either upload a plain text file, or a simple HTML file. HTML files will have their <head> information removed - only the contents of the body element will be used. The existing contents of the document will be replaced. The acceptance history will not be affected.###26 08 2024 new variable -ldoc#:#ldoc_form_document_title#:#Title###26 08 2024 new variable -ldoc#:#ldoc_form_document_title_info#:#Please enter a title for the document.###26 08 2024 new variable -ldoc#:#ldoc_form_edit_criterion_head#:#Edit Criterion for Displaying Your Document###26 08 2024 new variable -ldoc#:#ldoc_form_edit_doc_head#:#Edit Document###26 08 2024 new variable -ldoc#:#ldoc_form_new_doc_head#:#Create Document###26 08 2024 new variable -ldoc#:#ldoc_last_modified#:#Last Change###26 08 2024 new variable -ldoc#:#ldoc_ldoc_settings#:#Settings###26 08 2024 new variable -ldoc#:#ldoc_period#:#Period###26 08 2024 new variable -ldoc#:#ldoc_period_from#:#From###26 08 2024 new variable -ldoc#:#ldoc_period_until#:#Until###26 08 2024 new variable -ldoc#:#ldoc_reevaluate_on_login#:#Re-evaluate on Successful Login###26 08 2024 new variable -ldoc#:#ldoc_reevaluate_on_login_desc#:#After a successful login, automatically have ILIAS check whether a previously-accepted document is still valid or not. If, for example, a user has changed a setting that is the criterion for displaying a particular document (for example their language setting or country], and ILIAS can find a document with that criterion, then the user has to accept the new agreement.###26 08 2024 new variable -ldoc#:#ldoc_saved_sorting#:#The new order has been saved.###26 08 2024 new variable -ldoc#:#ldoc_sure_delete_documents_p#:#Are you sure you want to delete the selected documents?###26 08 2024 new variable -ldoc#:#ldoc_sure_delete_documents_s#:#Are you sure you want to delete this document?###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_action_add_criterion#:#Add Criterion###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_cell_not_criterion#:#No criterion assigned###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_head_created#:#Creation Date###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_head_criteria#:#Criterion###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_head_last_change#:#Last Change###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_head_sorting#:#Order###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_head_title#:#Title###26 08 2024 new variable -ldoc#:#ldoc_tbl_docs_title#:#Documents###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_cell_not_criterion#:#No criterion assigned###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_acceptance_date#:#Date###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_criteria#:#Criterion###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_document#:#Document###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_firstname#:#First Name###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_lastname#:#Last Name###26 08 2024 new variable -ldoc#:#ldoc_tbl_hist_head_login#:#Username (Login)###26 08 2024 new variable -ldoc#:#ldoc_updated_document#:#Document uploaded###26 08 2024 new variable +ldap#:#ldap_username_filter_info#:#A felhasználónév-szűrő opcionálisan használható az LDAP-kiszolgáló konfigurációjának automatikus meghatározására a bejelentkezési oldalon megadott felhasználónév alapján. A * (csillag) karakter helyettesítő karakterként használható. Például az ‘*pelda\.hu’ megfelel minden olyan felhasználónak, akinek a megadott felhasználóneve ‘pelda.hu’-ra végződik. Ha a konfigurált szűrő megegyezik a megadott felhasználónévvel, akkor ezt az LDAP-kiszolgáló konfigurációt részesítjük előnyben, ha rögzített hitelesítési sorrendet állítottak be. +ldoc#:#deleteDocument#:#Törlés +ldoc#:#detachCriterionAssignment#:#Törlése +ldoc#:#ldoc_acceptance_history#:#Elfogadási előzmények +ldoc#:#ldoc_account_reg_not_possible#:#A regisztráció jelenleg nem lehetséges. További információért keresse a rendszer üzemeltetőjét. +ldoc#:#ldoc_add_document_btn_label#:#Dokumentum hozzáadása +ldoc#:#ldoc_agreement_document#:#Dokumentum +ldoc#:#ldoc_agreement_document_missing#:#Hiányzik +ldoc#:#ldoc_agreement_documents_tab_label#:#Documentumok +ldoc#:#ldoc_agreement_exists#:#Létező +ldoc#:#ldoc_agreement_missing#:#Hiányzik +ldoc#:#ldoc_crit_type_usr_country#:#Profil országa +ldoc#:#ldoc_crit_type_usr_country_info#:#A dokumentuma akkor jelenik meg (és el kell fogadnia a felhasználónak első bejelentkezésekor), ha a felhasználói profiljában beállított ország megfelel az alábbi listából kiválasztott országkritériumnak. A felhasználó profiljában az ország későbbi módosításai nem vezetnek automatikusan új dokumentum megjelenítéséhez. Egynél több dokumentumhoz nem használhatja ugyanazt az országot megjelenítési feltételként. +ldoc#:#ldoc_crit_type_usr_global_role#:#A felhasználó rendelkezik globál szereppel. +ldoc#:#ldoc_crit_type_usr_global_role_info#:#A dokumentum megjelenik (és első bejelentkezéskor el kell fogadni), amennyiben a felhasználó tagja az itt kiválasztott globális szerepkörök valamelyikének. A felhasználó globális szerepkörének esetleges későbbi módosítása esetén nem jelenik meg automatikusan a Szolgáltatási Feltételek dokumentuma. +ldoc#:#ldoc_crit_type_usr_language#:#Profil nyelve +ldoc#:#ldoc_crit_type_usr_language_info#:#A dokumentum megjelenik, (és azt el kell fogadni) regisztrációkor, ha a felhasználó nyelve (kiválasztva az alábbi felsorolásból) azonos a regisztrációkor használt nyelvvel; vagy bejelentkezéskor, ha a felhasználó erre a nyelve vált. Kérjük, vegye figyelembe, hogy minden nyelv csak egyetlen dokumentum megjelenítési feltételeként állítható be. +ldoc#:#ldoc_criterion_assignment_cannot_match#:#Ez a feltétel nem használható a dokumentum megjelenítéséhez, mert egy másik, már meglévő feltétellel kizáró lenne. +ldoc#:#ldoc_criterion_assignment_must_be_unique#:#Ez a feltétel nem használható a dokumentum megjelenítéséhez. Ez a feltétel már létezik. +ldoc#:#ldoc_deleted_documents_p#:#A dokumentumot sikeresen törölte. +ldoc#:#ldoc_deleted_documents_s#:#A dokumentumokat sikeresen törölte. +ldoc#:#ldoc_disabled#:#Kikapcsolva +ldoc#:#ldoc_doc_crit_attached#:#A dokumentum megjelenítési feltételeit sikeresen beállította. +ldoc#:#ldoc_doc_crit_changed#:#A dokumentum megjelenítési feltételeit sikeresen módosította. +ldoc#:#ldoc_doc_crit_detached#:#A feltételt sikeresen eltávolította. +ldoc#:#ldoc_doc_delete#:#Dokumentum törlése +ldoc#:#ldoc_doc_detach_crit_confirm_title#:#Feltétel törlése +ldoc#:#ldoc_doc_sure_detach_crit#:#Biztos, hogy eltávolítja a Szolgáltatási feltételek ezen megjelenítési feltételét? +ldoc#:#ldoc_document#:#Dokumentum +ldoc#:#ldoc_enabled#:#Bekapcsolva +ldoc#:#ldoc_form_attach_criterion_head#:#Válassza ki a dokumentum megjelenési feltételét +ldoc#:#ldoc_form_criterion#:#Feltétel +ldoc#:#ldoc_form_criterion_standard_fields_info_text#:#Kérjük, ellenőrizze a standard mezők beállításait a kritérium meghatározása előtt. +ldoc#:#ldoc_form_document#:#Dokumentum +ldoc#:#ldoc_form_document_content_changed#:#A feltöltött HTML-fájl <head> részét eltávolítottuk. Kérem, ellenőrizze az eredményt, szükség esetén töltsön fel egy újat. +ldoc#:#ldoc_form_document_info#:#Válasszon ki egy fájlt a saját gépéről. Feltölthet egy TEXT-fájlt, illetve egy HTML-fájlt. A HTML-fájl <head/gt; részét eltávolítjuk, annak csak a tartalmát, a <body/gt; részét tartjuk meg. +ldoc#:#ldoc_form_document_new#:#Tartalom módosítása +ldoc#:#ldoc_form_document_new_info#:#Kiválaszthat egy fájlt a helyi fájlrendszerből a dokumentum tartalmának módosításához. Feltölthet egyszerű szöveges fájlt vagy egyszerű HTML-fájlt. A HTML-fájlok <head> részét eltávolítjuk, csak a <body> rész tartalmát használjuk fel, a dokumentum jelenlegi tartalmát erre cseréljük le. Az elfogadási előzményeket ez nem érinti. +ldoc#:#ldoc_form_document_title#:#Cím +ldoc#:#ldoc_form_document_title_info#:#Adja meg a dokumentum címét +ldoc#:#ldoc_form_edit_criterion_head#:#A dokumentum megjelenési feltételének módosítása +ldoc#:#ldoc_form_edit_doc_head#:#Dokumentum módosítása +ldoc#:#ldoc_form_new_doc_head#:#Dokumentum létrehozása +ldoc#:#ldoc_last_modified#:#Utolsó módosítás +ldoc#:#ldoc_ldoc_settings#:#Beállítások +ldoc#:#ldoc_period#:#Időszak +ldoc#:#ldoc_period_from#:#Kezdő időpont +ldoc#:#ldoc_period_until#:#Záró időpont +ldoc#:#ldoc_reevaluate_on_login#:#Bejelentkezéskor ellenőrizze újra +ldoc#:#ldoc_reevaluate_on_login_desc#:#Sikeres bejelentkezés után automatikusan ellenőrizzük, hogy a korábban elfogadott dokumentum érvényben van-e még. Amennyiben már nincs, például a megjelenítés feltétele megváltozott(például nyelv vagy ország beállítása), és az új feltételekkel új dokumentum létezik, a felhasználónak az újat el kell fogadnia. +ldoc#:#ldoc_saved_sorting#:#Az új sorrendet sikeresen mentette. +ldoc#:#ldoc_sure_delete_documents_p#:#Biztos, hogy törli a kiválasztott dokumentumokat? +ldoc#:#ldoc_sure_delete_documents_s#:#Biztos, hogy törli ezt a dokumentumot? +ldoc#:#ldoc_tbl_docs_action_add_criterion#:#Feltétel hozzáadása +ldoc#:#ldoc_tbl_docs_cell_not_criterion#:#Egy feltétel sincs hozzárendelve +ldoc#:#ldoc_tbl_docs_head_created#:#Létrehozás dátum +ldoc#:#ldoc_tbl_docs_head_criteria#:#Feltétel +ldoc#:#ldoc_tbl_docs_head_last_change#:#Utolsó módosítás +ldoc#:#ldoc_tbl_docs_head_sorting#:#Sorrend +ldoc#:#ldoc_tbl_docs_head_title#:#Cím +ldoc#:#ldoc_tbl_docs_title#:#Dokumentumok +ldoc#:#ldoc_tbl_hist_cell_not_criterion#:#Egy feltétel sincs hozzárendelve +ldoc#:#ldoc_tbl_hist_head_acceptance_date#:#Dátum +ldoc#:#ldoc_tbl_hist_head_criteria#:#Feltétel +ldoc#:#ldoc_tbl_hist_head_document#:#Dokumentum +ldoc#:#ldoc_tbl_hist_head_firstname#:#Családnév +ldoc#:#ldoc_tbl_hist_head_lastname#:#Utónév +ldoc#:#ldoc_tbl_hist_head_login#:#Felhasználónév (Login) +ldoc#:#ldoc_updated_document#:#A dokumentumot sikeresen feltöltötte lhist#:#cont_create_lhist#:#Tanulási történelemelem létrehozása lhist#:#cont_update_lhist#:#Tanulási történelemelem módosítása lhist#:#lhist_all#:#Összes @@ -11005,38 +11051,40 @@ like#:#reaction#:#Reakció link#:#link_chapters#:#Fejezetek link#:#link_link#:#Link link#:#link_mobs#:#Médiaobjektumok -link#:#link_terms#:#Kifejezések +link#:#link_terms#:#Fogalmak link#:#link_wpages#:#Wiki oldalak -lm#:#lm_btn_lp_toggle_state_completed#:#Set Not Completed -lm#:#lm_btn_lp_toggle_state_not_completed#:#Set Completed +lm#:#lm_btn_lp_toggle_state_completed#:#Nem teljesítettre állítás +lm#:#lm_btn_lp_toggle_state_not_completed#:#Sikeresen teljesítettre állítás lm#:#lm_copy#:#Tananyag másolása -lm#:#lm_edit_chapters#:#Edit Chapters###26 08 2024 new variable -lm#:#lm_edit_lm_settings#:#Edit Learning Module Settings###26 08 2024 new variable -lm#:#lm_est_reading_time#:#Estimated Reading Time###29 07 2022 new variable -lm#:#lm_est_reading_time_info#:#In Learning Modules in the repository the estimated reading time can be determined and displayed.###29 07 2022 new variable -lm#:#lm_insert_chapter#:#Insert chapter###28 10 2024 new variable -lm#:#lm_insert_chapter_after#:#Insert chapter after###28 10 2024 new variable -lm#:#lm_insert_chapter_before#:#Insert chapter before###28 10 2024 new variable -lm#:#lm_insert_chapter_clip#:#Insert chapter from clipboard###29 10 2025 new variable -lm#:#lm_insert_chapter_clip_after#:#Insert chapter from clipboard after###29 10 2025 new variable -lm#:#lm_insert_chapter_clip_before#:#Insert chapter from clipboard before###29 10 2025 new variable -lm#:#lm_insert_layout_after#:#Insert template after###28 10 2024 new variable -lm#:#lm_insert_layout_before#:#Insert template before###28 10 2024 new variable -lm#:#lm_insert_page#:#Insert page###28 10 2024 new variable -lm#:#lm_insert_page_after#:#Insert page after###28 10 2024 new variable -lm#:#lm_insert_page_before#:#Insert page before###28 10 2024 new variable -lm#:#lm_insert_page_clip#:#Insert page from clipboard###28 10 2024 new variable -lm#:#lm_insert_page_clip_after#:#Insert page from clipboard after###28 10 2024 new variable -lm#:#lm_insert_page_clip_before#:#Insert page from clipboard before###28 10 2024 new variable -lm#:#lm_page_added#:#Page has been added.###26 08 2024 new variable +lm#:#lm_edit_chapters#:#Fejezetek módosítása +lm#:#lm_edit_content#:#Tartalom módosítás +lm#:#lm_edit_lm_settings#:#Tananyag beállításainak módosítása +lm#:#lm_est_reading_time#:#Becsült olvasási idő +lm#:#lm_est_reading_time_info#:#A tananyagokban a becsült olvasási idő megállapítható és megjeleníthető. +lm#:#lm_insert_chapter#:#Új fejezet +lm#:#lm_insert_chapter_after#:#Új fejezet beszúrása mögé +lm#:#lm_insert_chapter_before#:#Új fejezet beszúrása elé +lm#:#lm_insert_chapter_clip#:#Fejezet beszúrás a vágólapról +lm#:#lm_insert_chapter_clip_after#:#Fejezet beszúrás a vágólapról mögé +lm#:#lm_insert_chapter_clip_before#:#Fejezet beszúrás a vágólapról elé +lm#:#lm_insert_layout_after#:#Új sablon beszúrása mögé +lm#:#lm_insert_layout_before#:#Új sablon beszúrása elé +lm#:#lm_insert_page#:#Új lap +lm#:#lm_insert_page_after#:#Új lap beszúrása mögé +lm#:#lm_insert_page_before#:#Új lap beszúrása elé +lm#:#lm_insert_page_clip#:#Új lap beszúrása a vágólapről +lm#:#lm_insert_page_clip_after#:#Új lap beszúrása a vágólapről mögé +lm#:#lm_insert_page_clip_before#:#Új lap beszúrása a vágólapről elé +lm#:#lm_list_pages#:#Oldalak módosítása +lm#:#lm_page_added#:#Az oldalt sikeresen hozzáadta. lm#:#lm_page_type_lm#:#Tananyagoldal -lm#:#lm_pages_added#:#Pages have been added.###26 08 2024 new variable +lm#:#lm_pages_added#:#Az oldalakat sikeresen hozzáadta. lm#:#lm_save_titles#:#A címeket sikeresen mentette. -lng#:#language_detection#:#Language Detection###29 07 2022 new variable +lng#:#language_detection#:#Nyelvfelismerés lng#:#lng_disable_language_detection#:#Nyelvfelismerés tiltása lng#:#lng_download_deprecated#:#Elavultak listájának letöltése lng#:#lng_enable_language_detection#:#Nyelvfelismerés engedélyezése -lng#:#lng_switch_language_detection#:#Switch Language Detection###26 08 2024 new variable +lng#:#lng_switch_language_detection#:#Nyelvfelismerés váltása log#:#log_browser#:#Böngésző konzolnaplózása log#:#log_browser_users#:#Felhasználónevek használata a konzolnaplózásban log#:#log_cache_#:#Gyorsítótárazás @@ -11059,14 +11107,14 @@ log#:#log_level_off#:#Kikapcsolva log#:#log_level_warning#:#FIGYELMETETÉS log#:#log_log_level#:#Naplózás szintje log#:#log_memory#:#Memóriahasználat naplózása -logging#:#error_settings_saved#:#Beállításokat sikeresen mentette +logging#:#error_settings_saved#:#A beállításokat sikeresen mentette. logging#:#frm_clear_older_then#:#Ennél régebbi fájlok törlése: logging#:#frm_clear_older_then_info#:#Napokban adjon meg egy időszakot. logging#:#log_error_file_cleanup_info#:#Törli a hibanapló régi vagy árva fájljait. logging#:#log_error_file_cleanup_title#:#Régi vagy árva hibanapló-fájlok törlése logging#:#log_error_folder#:#Útvonal logging#:#log_error_mail#:#Címzett -logging#:#log_error_message#:#Sajnáljuk, hiba következett be. '%s' kóddal azonosítható naplófájlt hoztunk létre. +logging#:#log_error_message#:#Sajnáljuk, hiba következett be. ‘%s’ kóddal azonosítható naplófájlt hoztunk létre. logging#:#log_error_message_send_mail#:#Kérjük, küldjön levelet %s részére logging#:#log_error_path_not_configured_or_wrong#:#A hibafájlok útvonala (error_path) nincs megadva vagy nem érhető el. logging#:#log_error_settings#:#Hibanaplózás beállításai @@ -11076,8 +11124,8 @@ lso#:#abstract_img#:#Absztrakt képe lso#:#avail_time_period#:#Időköz lso#:#completed_steps#:#Megtett lépések lso#:#condition_always#:#Mindig -lso#:#cont_ed_insert_lsocurriculum#:#Insert Learning Sequence Curriculum###26 08 2024 new variable -lso#:#cont_ed_insert_lsostartbutton#:#Insert Learning Sequence Start Button###26 08 2024 new variable +lso#:#cont_ed_insert_lsocurriculum#:#Tanulási sor tantervének beillesztése +lso#:#cont_ed_insert_lsostartbutton#:#Tanulási sor indító gombjának beillesztése lso#:#curriculum#:#Tanterv lso#:#delete_confirmation#:#Biztos, hogy törli ezeket az objektumokat? lso#:#entries_deleted#:#Az objektumokat sikeresen törölte. @@ -11089,49 +11137,49 @@ lso#:#finished#:#Befejezett lso#:#first_access#:#Első hozzáférés lso#:#last_visited_step#:#Utoljára meglátogatott lépés lso#:#learner_view#:#Áttekintés -lso#:#lp_not_relevant_post_cond#:#currently not relevant for continuation###26 08 2024 new variable +lso#:#lp_not_relevant_post_cond#:#jelenleg nem releváns a folytatás szempontjából lso#:#lso_activation_online_info#:#Állítsa a tanulási haladást online-ra, hogy az látható és elérhető legyen a tanulás sor tagjai számára. A nem aktív sort csak a vezetők és a tutorok érhetik el. lso#:#lso_at_least_one_admin#:#Legalább egy vezetője kell, hogy legyen a tanulási sornak. lso#:#lso_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat lso#:#lso_header_delete_members#:#Biztos, hogy eltávolítja az alábbi tagokat a tanulási sorról? lso#:#lso_header_edit_members#:#Tagok módosítása -lso#:#lso_intropages_deprecationhint#:#You can edit the abstract and exit page in the tab "Content".###26 08 2024 new variable -lso#:#lso_legacy_info#:#The object will open in a new tab in your browser. Please return to this tab after processing/editing the contents. Reload the page if you have edited the content but the "Next" button remains disabled.###26 08 2024 new variable -lso#:#lso_mail_admission_new_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási sorra sikeresen regisztrált. -lso#:#lso_mail_admission_new_sub#:#'%s' tanulási sorra regisztráció -lso#:#lso_mail_dismiss_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási soron tagsága megszűnt. -lso#:#lso_mail_dismiss_sub#:#'%s' tanulási soron tagság megszűnése -lso#:#lso_mail_notification_reg_bod#:#%s regisztrált '%s' tanulási sorra. -lso#:#lso_mail_notification_reg_req_bod#:#ezúton tájékoztatjuk, hogy %s tagságot kér '%s' tanulási sorhoz. +lso#:#lso_intropages_deprecationhint#:#Az absztraktot és a kilépőoldalt a ‘Tartalom’ lapon szerkesztheti. +lso#:#lso_legacy_info#:#Az objektum a böngésző egy új lapján fog megnyílni. Kérem, térjen vissza erre a lapra a tartalom feldolgozása/szerkesztése után. Töltse be újra az oldalt, ha szerkesztette a tartalmat, de a ‘Tovább’ gomb le van tiltva. +lso#:#lso_mail_admission_new_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási sorra sikeresen regisztrált. +lso#:#lso_mail_admission_new_sub#:#‘%s’ tanulási sorra regisztráció +lso#:#lso_mail_dismiss_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási soron tagsága megszűnt. +lso#:#lso_mail_dismiss_sub#:#‘%s’ tanulási soron tagság megszűnése +lso#:#lso_mail_notification_reg_bod#:#%s regisztrált ‘%s’ tanulási sorra. +lso#:#lso_mail_notification_reg_req_bod#:#ezúton tájékoztatjuk, hogy %s tagságot kér ‘%s’ tanulási sorhoz. lso#:#lso_mail_notification_reg_req_bod2#:#A regisztráció jóváhagyásához kattintson ide: -lso#:#lso_mail_notification_reg_req_sub#:#'%s' tanulási sorhoz csatlakozás kérése -lso#:#lso_mail_notification_reg_sub#:#Felhasználó regisztrált '%s' tanulási sorra -lso#:#lso_mail_notification_unsub_bod#:#ezúton értesítjük, hogy %s lemondta tagságát '%s' tanulási sorban. +lso#:#lso_mail_notification_reg_req_sub#:#‘%s’ tanulási sorhoz csatlakozás kérése +lso#:#lso_mail_notification_reg_sub#:#Felhasználó regisztrált ‘%s’ tanulási sorra +lso#:#lso_mail_notification_unsub_bod#:#ezúton értesítjük, hogy %s lemondta tagságát ‘%s’ tanulási sorban. lso#:#lso_mail_notification_unsub_bod2#:#Elképzelhető, hogy további tagok vannak a tanulási sor várólistáján. Kérjük, mihamarabb ellenőrizze a várólistát. A tanulási sor tagjainak megtekintéséhez kattintson ide: -lso#:#lso_mail_notification_unsub_sub#:#'%s' tanulási sort egy felhasználó elhagyta +lso#:#lso_mail_notification_unsub_sub#:#‘%s’ tanulási sort egy felhasználó elhagyta lso#:#lso_mail_permanent_link#:#Kattintson az alábbi linkre a tanulási sorra kapcsolatos információkért: -lso#:#lso_mail_status_bod#:#ezúton tájékoztatjuk, hogy az Ön állapota módosult '%s' tanulási sorban. -lso#:#lso_mail_status_sub#:#'%s' tanulási sorban állapotváltozás -lso#:#lso_mail_sub_acc_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási sorhoz tagságát jóváhagyták. -lso#:#lso_mail_sub_acc_sub#:#'%s' tanulási sorhoz regisztrációját jóváhagyták -lso#:#lso_mail_sub_dec_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási sorhoz tagságát elutasították. -lso#:#lso_mail_sub_dec_sub#:#'%s' tanulási sorhoz regisztrációját visszautasították -lso#:#lso_mail_subscribe_member_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási sorra sikeresen regisztrált. -lso#:#lso_mail_subscribe_member_sub#:#'%s' tanulási sorra regisztrált -lso#:#lso_mail_unsubscribe_member_bod#:#ezúton megerősítjük, hogy '%s' tanulási sori tagsága megszűnt. Reméljük, hogy egy másik tanulási sorban hamarosan viszontlátjuk. -lso#:#lso_mail_unsubscribe_member_sub#:#'%s' tanulási sorra tagság lemondása -lso#:#lso_mail_wl_bod#:#ezúton tájékoztatjuk, hogy '%s' tanulási sor várólistájára felkerült. Jelenleg %s. helyet foglalja el a listán. Levélben értesítjük, amikor csatlakozási kérését elfogadják vagy elutasítják. -lso#:#lso_mail_wl_sub#:#'%s' tanulási sorhoz regisztrációja -lso#:#lso_mainbar_button_label_curriculum#:#Tanterv +lso#:#lso_mail_status_bod#:#ezúton tájékoztatjuk, hogy az Ön állapota módosult ‘%s’ tanulási sorban. +lso#:#lso_mail_status_sub#:#‘%s’ tanulási sorban állapotváltozás +lso#:#lso_mail_sub_acc_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási sorhoz tagságát jóváhagyták. +lso#:#lso_mail_sub_acc_sub#:#‘%s’ tanulási sorhoz regisztrációját jóváhagyták +lso#:#lso_mail_sub_dec_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási sorhoz tagságát elutasították. +lso#:#lso_mail_sub_dec_sub#:#‘%s’ tanulási sorhoz regisztrációját visszautasították +lso#:#lso_mail_subscribe_member_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási sorra sikeresen regisztrált. +lso#:#lso_mail_subscribe_member_sub#:#‘%s’ tanulási sorra regisztrált +lso#:#lso_mail_unsubscribe_member_bod#:#ezúton megerősítjük, hogy ‘%s’ tanulási sori tagsága megszűnt. Reméljük, hogy egy másik tanulási sorban hamarosan viszontlátjuk. +lso#:#lso_mail_unsubscribe_member_sub#:#‘%s’ tanulási sorra tagság lemondása +lso#:#lso_mail_wl_bod#:#ezúton tájékoztatjuk, hogy ‘%s’ tanulási sor várólistájára felkerült. Jelenleg %s. helyet foglalja el a listán. Levélben értesítjük, amikor csatlakozási kérését elfogadják vagy elutasítják. +lso#:#lso_mail_wl_sub#:#‘%s’ tanulási sorhoz regisztrációja +lso#:#lso_mainbar_button_label_curriculum#:#Tanulási sor lso#:#lso_mainbar_button_label_toc#:#Tartalom lso#:#lso_mem_tbl_header#:#Tanulási sor tagja lso#:#lso_member_administration#:#Résztvevők módosítása -lso#:#lso_members_deleted#:#Törölt tagok +lso#:#lso_members_deleted#:#A kiválasztott tagokat sikeresen eltávolította a Tanulási sorból. lso#:#lso_members_gallery#:#Tanulási sor tagképgalériája lso#:#lso_members_print_title#:#Tanulási sor tagjai lso#:#lso_min_one_admin#:#Legalább egy vezetője kell, hogy legyen a tanulási sornak. lso#:#lso_msg_member_assigned#:#A felhasználó(ka)t sikeresen hozzárendelte a tanulási sorhoz. -lso#:#lso_multidownload_not_available#:#Downloading multiple objects is currently not available for Learning Sequence Objects.###26 08 2024 new variable +lso#:#lso_multidownload_not_available#:#Több objektum egyszerre letöltése nem lehetséges ebben a tanulási sorban. lso#:#lso_new_status#:#Az Ön új állapota: lso#:#lso_notification#:#Értesítés lso#:#lso_notification_explanation_admin#:#Ezt az e-mail azért küldtük, mert Ön a tanulási sor vezetője és az értesítés be van kapcsolva. @@ -11141,26 +11189,25 @@ lso#:#lso_player_abstract#:#Absztrakt megjelenítése lso#:#lso_player_extro#:#Befejező oldal megjelenítése lso#:#lso_player_finish#:#Befejezés lso#:#lso_player_next#:#Következő -lso#:#lso_player_noitems#:#There are no available items in this Learning Sequence.###29 10 2025 new variable +lso#:#lso_player_noitems#:#Egy elérhető elem sincs ebben a Tanulási sorban. lso#:#lso_player_previous#:#Előző lso#:#lso_player_resume#:#Tanulási sor szüneteltetése lso#:#lso_player_review#:#Tanulási sor áttekintése lso#:#lso_player_start#:#Tanulási sor indítása lso#:#lso_player_suspend#:#Felfüggesztés -lso#:#lso_player_viewmodelabel#:#Learning Sequence###29 07 2022 new variable +lso#:#lso_player_viewmodelabel#:#Tanulási sor lso#:#lso_print_list#:#Lista nyomtatása lso#:#lso_read#:#A felhasználónak hozzáférés van a tanulási sorhoz lso#:#lso_search_users#:#Felhasználók keresése -lso#:#lso_settings_availability#:#elérhetőség -lso#:#lso_settings_availability_error#:#The end date can not be earlier than the start date###26 08 2024 new variable -lso#:#lso_settings_extro#:#Kilépő oldal beállításai -lso#:#lso_settings_intro#:#Bemutatkozó oldal beállításai -lso#:#lso_settings_old_extro#:#View Old Exit Page###26 08 2024 new variable -lso#:#lso_settings_old_intro#:#View Old Intro Page###26 08 2024 new variable +lso#:#lso_settings_availability#:#Elérhetőség +lso#:#lso_settings_extro#:#Kilépőoldal beállításai +lso#:#lso_settings_intro#:#Bemutatkozó-oldal beállításai +lso#:#lso_settings_old_extro#:#Korábbi Kilépőoldal megjelenítése +lso#:#lso_settings_old_intro#:#Korábbi Bemutatkozó-oldal megjelenítése lso#:#lso_show_members_info#:#Tagok megtekinthetik a tanulási sor tagjainak képgalériáját lso#:#lso_start_item#:#%s indítása -lso#:#lso_toast_completed_desc#:#You have completed this Learning Sequence. You might still keep looking through the content.###26 08 2024 new variable -lso#:#lso_toast_completed_title#:#Congratulations###26 08 2024 new variable +lso#:#lso_toast_completed_desc#:#Sikeresen teljesítette ezt a tanulási sort. Továbbra is megtekintheti a tartalmát. +lso#:#lso_toast_completed_title#:#Gratulálunk lso#:#lso_users_already_assigned#:#A felhasználó már hozzá van rendelve ehhez a tanulási sorhoz lso#:#mail_lso_roles#:#Levelek küldése a tanulási sor szerepeinek. lso#:#manage#:#Kezelés @@ -11168,10 +11215,10 @@ lso#:#manage_content_maintab#:#Tartalom lso#:#members_gallery#:#Tagok képgalériája lso#:#no_entries_selected_for_delete#:#Legalább egy bejegyzést ki kell választania. lso#:#not_finished#:#Nem befejezett -lso#:#notification_lso_completed_title#:#You completed the Learning Sequence %s.###26 08 2024 new variable +lso#:#notification_lso_completed_title#:#Sikeresen teljesített a ‘%s’ ranulási sort. lso#:#show_summary#:#Információ lso#:#table_actions#:#Műveletek -lso#:#table_lp_settings#:#Learning Progress Settings###26 08 2024 new variable +lso#:#table_lp_settings#:#Tanulási haladás lso#:#table_may_proceed#:#Tovább haladhat lso#:#table_online#:#Online lso#:#table_position#:#Pozíció @@ -11179,41 +11226,47 @@ lso#:#table_sequence_content#:#Tartalomkezelés lso#:#table_title#:#Cím lso#:#unparticipate#:#Leiratkozás lti#:#act_lti_for_obj_type#:#Objektumtípusra LTI aktiválása -lti#:#activity_id#:#Activity ID -lti#:#activity_id_info#:#This Activity ID is used by the LTI Kiszolgáló to identify Statements. +lti#:#activity_id#:#AktivításID +lti#:#activity_id_info#:#Ezt az AktivításID-t használja az LTI Kiszolgáló, hogy azonosítsa a Statement-eket. lti#:#auth_lti#:#LTI-hitelesítés -lti#:#conf_privacy_ident#:#User identification###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_SHA256#:#Hash combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_SHA256_info#:#This is identical to each call, but does not permit any direct conclusions about the ILIAS user.###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_ext_account#:#External User ID combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_ext_account_info#:#This is identical to each call, but may allow a direct conclusion about the user.###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_login#:#ILIAS Login combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_login_info#:#Sends the login name. This is identical to each call, but may allow a direct conclusion about the ILIAS user.###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_user_id#:#ILIAS user id combined with a unique ILIAS platform id formatted as an E-Mail address###26 08 2024 new variable -lti#:#conf_privacy_ident_il_uuid_user_id_info#:#Sends the internal numeric user id. This is identical to each call, but may allow conclusions about the ILIAS user.###26 08 2024 new variable -lti#:#conf_privacy_ident_info#:#Standard is frequently the email address. The unique ILIAS platform id is:###26 08 2024 new variable -lti#:#conf_privacy_ident_real_email#:#E-Mail Address###26 08 2024 new variable -lti#:#conf_privacy_ident_real_email_info#:#Sends E-Mail Address of user as identification (Warning: an E-Mail Address might be used by multiple users!)###26 08 2024 new variable -lti#:#conf_privacy_name#:#User name###26 08 2024 new variable -lti#:#conf_privacy_name_firstname#:#First name###26 08 2024 new variable -lti#:#conf_privacy_name_firstname_info#:#Sends the first name of the user name from ILIAS###26 08 2024 new variable -lti#:#conf_privacy_name_fullname#:#Entire name###26 08 2024 new variable -lti#:#conf_privacy_name_fullname_info#:#Sends title, first name and last name###26 08 2024 new variable -lti#:#conf_privacy_name_info#:#Sending an user name is usually not required.###26 08 2024 new variable -lti#:#conf_privacy_name_lastname#:#Title and last name###26 08 2024 new variable -lti#:#conf_privacy_name_lastname_info#:#Sends Mister or Ms/Mrs. (unless otherwise specified) and the last name###26 08 2024 new variable -lti#:#conf_privacy_name_none#:#No one###26 08 2024 new variable -lti#:#conf_privacy_name_none_info#:#Sends '-' instead of a name###26 08 2024 new variable -lti#:#conf_user_ident#:#Felhasználói azonosítás -lti#:#conf_user_ident_il_uuid_ext_account#:#A külső user id és az egyedi ILIAS platform id e-mail cím formátumban. +lti#:#conf_privacy_ident#:#Felhasználói azonosítás +lti#:#conf_privacy_ident_il_uuid_SHA256#:#Hash és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_SHA256_info#:#Ez azonosítja az összes hívást, de nem lehet belőle következtetni felhasználóra. +lti#:#conf_privacy_ident_il_uuid_ext_account#:#A külső user_id és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_ext_account_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged a felhasználóra. +lti#:#conf_privacy_ident_il_uuid_login#:#Az ILIAS felhasználónév és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_login_info#:#A felhasználónevet küldjük. Ez azonosítja az összes hívást, de esetleg következtetni enged az ILIAS felhasználóra. +lti#:#conf_privacy_ident_il_uuid_random#:#Véletlen id és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_random_info#:#Az összes ILIAS objektum és az összes ILIAS felhasználó számára egy véletlen azonosítót generálunk minden híváskor, így a felhasználóval kapcsolatos következtetések nagyon korlátozottak lesznek, mert gyakorlatilag lehetetlen objektumokra hivatkozó felhasználói profilokat létrehozni. +lti#:#conf_privacy_ident_il_uuid_sha256#:#Hash és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_sha256_info#:#Ez azonosítja az összes hívást, de nem lehet belőle következtetni felhasználóra. +lti#:#conf_privacy_ident_il_uuid_sha256url#:#Hash és az egyedi ILIAS domainnel e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_sha256url_info#:#Ez azonosítja az összes hívást, legfeljebb 80 karakterrel lényegesen rövidebb, mint az ILIAS platformazonosítójú változat, és csak nagyon korlátozott következtetéseket tesz lehetővé a felhasználóról. +lti#:#conf_privacy_ident_il_uuid_user_id#:#Az ILIAS user_id és az egyedi ILIAS platform_id e-mail cím formátumban. +lti#:#conf_privacy_ident_il_uuid_user_id_info#:#Ez azonosítja az összes hívást, de nem enged következtetni az ILIAS felhasználóra. +lti#:#conf_privacy_ident_info#:#A standard gyakran az e-mail cím. Az egyedi ILIAS platformazonosítója: +lti#:#conf_privacy_ident_real_email#:#E-mail cím +lti#:#conf_privacy_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelmezetés: egy e-mail címet több felhasználó is használhat!) +lti#:#conf_privacy_name#:#Felhasználó neve +lti#:#conf_privacy_name_firstname#:#Utónév +lti#:#conf_privacy_name_firstname_info#:#A felhasználó utónevét küldjük +lti#:#conf_privacy_name_fullname#:#Teljes név +lti#:#conf_privacy_name_fullname_info#:#A titulust, a családi és az utónevet is küldjük +lti#:#conf_privacy_name_info#:#A felhasználó névének küldése általában nem szükséges. +lti#:#conf_privacy_name_lastname#:#Titulus és családnév +lti#:#conf_privacy_name_lastname_info#:#Asszony vagy Úr megszólítást (eltérő rendelkezés hiányában) és a családnevet küldjük +lti#:#conf_privacy_name_none#:#Semmi +lti#:#conf_privacy_name_none_info#:#‘-’-et küldjük a név helyett +lti#:#conf_user_ident#:#Felhasználó azaonsítása +lti#:#conf_user_ident_il_uuid_ext_account#:#A külső user_id és az egyedi ILIAS platform_id e-mail cím formátumban. lti#:#conf_user_ident_il_uuid_ext_account_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged a felhasználóra. -lti#:#conf_user_ident_il_uuid_login#:#Az ILIAS felhasználónév és az egyedi ILIAS platform id e-mail cím formátumban. +lti#:#conf_user_ident_il_uuid_login#:#Az ILIAS felhasználónév és az egyedi ILIAS platform_id e-mail cím formátumban. lti#:#conf_user_ident_il_uuid_login_info#:#Ez azonosítja az összes hívást, de esetleg következtetni enged az ILIAS felhasználóra. -lti#:#conf_user_ident_il_uuid_user_id#:#Az ILIAS user id és az egyedi ILIAS platform id e-mail cím formátumban. +lti#:#conf_user_ident_il_uuid_user_id#:#Az ILIAS user_id és az egyedi ILIAS platform_id e-mail cím formátumban. lti#:#conf_user_ident_il_uuid_user_id_info#:#Ez azonosítja az összes hívást, de nem enged következtetni az ILIAS felhasználóra. lti#:#conf_user_ident_info#:#A standard gyakran az e-mail cím. Az egyedi ILIAS platformazonosítója: lti#:#conf_user_ident_real_email#:#E-mail cím -lti#:#conf_user_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelem: egy e-mail címet több felhasználó is használhat!) +lti#:#conf_user_ident_real_email_info#:#A felhasználó e-mail címét küldi azonosításként (Figyelmezetés: egy e-mail címet több felhasználó is használhat!) lti#:#conf_user_name#:#Felhasználó neve lti#:#conf_user_name_firstname#:#Utónév lti#:#conf_user_name_firstname_info#:#A felhasználó utónevét küldjük @@ -11223,146 +11276,155 @@ lti#:#conf_user_name_info#:#A felhasználó névének küldése általában nem lti#:#conf_user_name_lastname#:#Titulus és családnév lti#:#conf_user_name_lastname_info#:#Asszony vagy Úr megszólítást (eltérő rendelkezés hiányában) és a családnevet küldjük lti#:#conf_user_name_none#:#Semmi -lti#:#conf_user_name_none_info#:#'-'-et küldjük a név helyett +lti#:#conf_user_name_none_info#:#‘-’-et küldjük a név helyett lti#:#consumers#:#Fogyasztók -lti#:#description_info#:#The description will be shown below the title. -lti#:#field_provider_xml#:#XML-File -lti#:#field_provider_xml_info#:#Supported are XML-Files for Tool Fogyasztók and for Common Cartridge according to https://www.imsglobal.org/specs/lti/xml. -lti#:#form_import_provider#:#Import Global Kiszolgáló -lti#:#gbl_roles_to_users#:#LTI-felhasználókhoz rendelt globális szerep -lti#:#global_provider_subtab#:#Global Kiszolgálók for all Users -lti#:#grade_activity_progress_all#:#All Information on Activity Progress###26 08 2024 new variable -lti#:#grade_activity_progress_completed#:#Completed###26 08 2024 new variable -lti#:#grade_activity_progress_initialized#:#Initialized###26 08 2024 new variable -lti#:#grade_activity_progress_inprogress#:#In Progress###26 08 2024 new variable -lti#:#grade_activity_progress_started#:#Started###26 08 2024 new variable -lti#:#grade_activity_progress_submitted#:#Submitted###26 08 2024 new variable -lti#:#grade_grading_progress_all#:#All Information on Grading Progress###26 08 2024 new variable -lti#:#grade_grading_progress_failed#:#The Grading could not complete (Failed)###26 08 2024 new variable -lti#:#grade_grading_progress_fullygraded#:#The Grading Process is completed###26 08 2024 new variable -lti#:#grade_grading_progress_notready#:#No Grading Process is occurring (NotReady)###26 08 2024 new variable -lti#:#grade_grading_progress_pending#:#Final Grade is pending###26 08 2024 new variable -lti#:#grade_grading_progress_pendingmanual#:#Final Grade is pending; requires Human Intervention###26 08 2024 new variable -lti#:#highscore_achieved_ts#:#Date -lti#:#highscore_achieved_ts_description#:#A column containing the date will be included in the ranking. -lti#:#highscore_all_tables#:#Participant's Own Rank and Top Ranking -lti#:#highscore_all_tables_description#:#Participants get information about the top ranking and their own position in the ranking. -lti#:#highscore_description#:#The names of other users could be displayed if the right 'A többi felhasználó tanulási tapasztalatának megtekintése' is set. -lti#:#highscore_enabled#:#Ranking -lti#:#highscore_mode#:#Mode -lti#:#highscore_own_table#:#Participant's Own Rank -lti#:#highscore_own_table_description#:#Participants are advised of their own position in the ranking. -lti#:#highscore_percentage#:#Percentage -lti#:#highscore_percentage_description#:#A column containing the score as percentage will be included in the ranking. -lti#:#highscore_score#:#Score -lti#:#highscore_score_description#:#A column containing the score will be included in the ranking. -lti#:#highscore_top_num#:#Length of Top Ranking -lti#:#highscore_top_num_description#:#Specify how many ranks are to be included in the top ranking list. -lti#:#highscore_top_num_unit#:#entries -lti#:#highscore_top_table#:#Top Ranking -lti#:#highscore_top_table_description#:#Participants are presented with a table containing the top rankings. -lti#:#highscore_wtime#:#Duration -lti#:#highscore_wtime_description#:#A column containing the duration will be included in the ranking. -lti#:#launch_method#:#Options for Launch +lti#:#description_info#:#A leírás a cím alatt jelenik meg. +lti#:#field_provider_xml#:#XML-Fájl +lti#:#field_provider_xml_info#:#Eszközfogyasztók és Common Cartridge támogatásához XML-fájlok a https://www.imsglobal.org/specs/lti/xml szerint. +lti#:#form_import_provider#:#Globális Kiszolgáló importálása +lti#:#gbl_roles_to_users#:#LTI-felhasználókhoz rendelt globális szerepkör +lti#:#global_provider_subtab#:#Globális Kiszolgálók az összes felhasználó számára +lti#:#grade_activity_progress_all#:#összes állapotinformáció +lti#:#grade_activity_progress_completed#:#Befejezte +lti#:#grade_activity_progress_initialized#:#Initializált +lti#:#grade_activity_progress_inprogress#:#Folyamatban +lti#:#grade_activity_progress_started#:#Elkezdve +lti#:#grade_activity_progress_submitted#:#Beküldött +lti#:#grade_grading_progress_all#:#Az értékelési folyamat össze információja +lti#:#grade_grading_progress_failed#:#Az értékelési folyamat nem befejeződött be (Sikertelen) +lti#:#grade_grading_progress_fullygraded#:#Az értékelési folyamat befejeződött +lti#:#grade_grading_progress_notready#:#Nincs értékelési folyamat +lti#:#grade_grading_progress_pending#:#A végső értékelés kialakítása függőben +lti#:#grade_grading_progress_pendingmanual#:#A végső értékelés kialakítása függőben; kézi beavatkozást igényel +lti#:#highscore_achieved_ts#:#Dátum +lti#:#highscore_achieved_ts_description#:#A rangsorban megjelenik a dátumot eredményeket tartalmazó oszlop. +lti#:#highscore_all_tables#:#Résztvevő saját és top rangsora +lti#:#highscore_all_tables_description#:#A résztvevők tájékoztatást kapnak a legjobb helyezésekről és saját pozíciójukról a rangsorban. +lti#:#highscore_description#:#A többi felhasználó neve megjelenik, ha az ‘A többi felhasználó tanulási tapasztalatának megtekintése’ jogosultsággl bír. +lti#:#highscore_enabled#:#Helyezés +lti#:#highscore_mode#:#Mód +lti#:#highscore_own_table#:#Résztvevő saját helyezése +lti#:#highscore_own_table_description#:#A résztvevők láthatják a rangsorban elfoglalt helyüket. +lti#:#highscore_percentage#:#Százalék +lti#:#highscore_percentage_description#:#A rangsorban megjelenik a százalékos eredményeket tartalmazó oszlop. +lti#:#highscore_score#:#Pontszám +lti#:#highscore_score_description#:#A rangsorban megjelenik a pontszámokat tartalmazó oszlop. +lti#:#highscore_top_num#:#Legjobb helyezések száma +lti#:#highscore_top_num_description#:#A legjobbak rangsorában megjelenő résztvevők számát határozza meg. +lti#:#highscore_top_num_unit#:#bejegyzések +lti#:#highscore_top_table#:#Legjobb helyezések +lti#:#highscore_top_table_description#:#A résztvevők a legjobb helyezéseket tartalmazó táblázatban jelennek meg. +lti#:#highscore_wtime#:#Időtartam +lti#:#highscore_wtime_description#:#A rangsorban megjelenik az időtartamot tartalmazó oszlop. +lti#:#launch_method#:#Indítás beállításai lti#:#launch_method_embedded#:#Beágyazott tartalom -lti#:#launch_method_embedded_info#:#The content is opened within the ILIAS context. It is presented as embedded content within the content tab. +lti#:#launch_method_embedded_info#:#A tartalom az ILIAS környezetben nyílik meg. Beágyazott tartalomként jelenik meg a tartalom lapon. lti#:#launch_method_new_win#:#Új ablak -lti#:#launch_method_new_win_info#:#The content is opened in a new window. When leaving the content this window gets closed. +lti#:#launch_method_new_win_info#:#A tartalom új ablakban nyílik meg. A tartalom elhagyásakor ez az ablak bezárul. lti#:#launch_method_own_win#:#Saját ablak -lti#:#launch_method_own_win_info#:#The content is opened in the same window and replaces the ILIAS Screen. When leaving the content the user returns to ILIAS. -lti#:#launched#:#Resource was already launched. -lti#:#learning_progress_options#:#Options for Learning Progress -lti#:#lm_only_one_download_per_type#:#Kérjük, ügyeljen arra, hogy típusonként (XML, HTML, SCORM) csak egy fájlt tegyen nyilvánosan elérhetővé. -lti#:#lti13_hints#:#If the tool was created without dynamic registration, the following data must be entered for the tool to run.###26 08 2024 new variable -lti#:#lti_13_client_id#:#Client-ID###26 08 2024 new variable -lti#:#lti_13_deployment_id#:#Deployment-ID###26 08 2024 new variable -lti#:#lti_13_platform_id#:#Platform-ID###26 08 2024 new variable -lti#:#lti_13_step1#:#Step 1###26 08 2024 new variable -lti#:#lti_13_step1_info#:#For the initiating platform (consumer), enter the following address for Launch URL, Initiate Login URL, Redirection URI, and Registration URL:###26 08 2024 new variable -lti#:#lti_13_step2#:#Step 2###26 08 2024 new variable -lti#:#lti_13_step2_info#:#You will receive information from the initiating platform (Consumer), which you must enter in the following fields. After saving, the LTI 1.3 functionalities are available.###26 08 2024 new variable -lti#:#lti_action_accept_provider_as_global#:#Accept Kiszolgáló as Global Kiszolgáló for all Users -lti#:#lti_action_accept_providers_as_global#:#Accept Kiszolgálók as Global -lti#:#lti_action_delete_providers#:#Delete Kiszolgálós +lti#:#launch_method_own_win_info#:#A tartalom ugyanabban az ablakban nyílik meg, és helyettesíti az ILIAS képernyőt. A tartalom elhagyásakor a felhasználó visszatér az ILIAS-hoz. +lti#:#launched#:#Az erőforrás már elindult. +lti#:#learning_progress_options#:#Tanulási haladás beállításai +lti#:#lm_only_one_download_per_type#:#Típusonként (XML, HTML, SCORM) csak egy fájlt lehet nyilvánosan elérhető. +lti#:#lti13_hints#:#Ha az eszközt dinamikus regisztráció nélkül hozták létre, akkor az alábbi adatokat kell megadni az eszköz futtatásához. +lti#:#lti_13_authentication_url#:#Hitelesítési kérelem URL-je +lti#:#lti_13_client_id#:#Kliens-ID +lti#:#lti_13_deployment_id#:#Telepítés-ID +lti#:#lti_13_keyset_url#:#Nyilvános kulcskészlet URL-je +lti#:#lti_13_platform_id#:#Platform-ID +lti#:#lti_13_step1#:#1. lépés +lti#:#lti_13_step1_info#:#A kezdeményező platform (fogyasztó) esetében adja meg a következő címet az Indítási URL-hez, a Bejelentkezési URL-címhez, az Átirányítási URI-hez és a Regisztrációs URL-hez: +lti#:#lti_13_step2#:#2. lépés +lti#:#lti_13_step2_info#:#A kezdeményező platformtól (Fogyasztó) kap információkat, amelyeket a következő mezőkbe kell beírnia. Mentés után elérhetők az LTI 1.3 funkciói. +lti#:#lti_13_token_url#:#Hozzáférési token URL-je +lti#:#lti_action_accept_provider_as_global#:#A Kiszolgáló elfogadás mint Global Kiszolgáló az összes felhasználó számára +lti#:#lti_action_accept_providers_as_global#:#Kiszolgálók elfogadás mint Globális +lti#:#lti_action_delete_providers#:#Kiszolgálós törlése lti#:#lti_action_edit_provider#:#Edit Kiszolgáló lti#:#lti_action_reset_provider_to_user_scope#:#Reset Kiszolgáló as User Defined Kiszolgáló lti#:#lti_action_reset_providers_to_user_scope#:#Reset Kiszolgálók as User Defined -lti#:#lti_add_global_provider#:#Add Global Kiszolgáló for all Users -lti#:#lti_add_own_provider#:#Add Own Kiszolgáló (not for all Users) +lti#:#lti_add_global_provider#:#Globális Kiszolgáló hozzáadása az összes felhasználónak +lti#:#lti_add_own_provider#:#Saját Kiszolgáló létrehozása (nem az összes felhasználónak) lti#:#lti_admin#:#LTI-rendszergazda lti#:#lti_at_least_one_prov_has_usages#:#At least one provider could not be deleted because this provider has usages (might be in trash). lti#:#lti_auth_failed_invalid_key#:#A hitelesítés sikertelen, nem jó a fogyasztói kulcs. -lti#:#lti_con_content_item#:#Support for Deep Linking###26 08 2024 new variable -lti#:#lti_con_content_item_url#:#Content URL###26 08 2024 new variable -lti#:#lti_con_initiate_login_url#:#Initiate Login URL###26 08 2024 new variable -lti#:#lti_con_key_type#:#Public Key Type###26 08 2024 new variable -lti#:#lti_con_key_type_jwk#:#URL (Json Web Token)###26 08 2024 new variable -lti#:#lti_con_key_type_jwk_url#:#URL###26 08 2024 new variable -lti#:#lti_con_key_type_rsa#:#RSA-Key###26 08 2024 new variable -lti#:#lti_con_key_type_rsa_public_key#:#Public Key###26 08 2024 new variable -lti#:#lti_con_key_type_rsa_public_key_info#:#Insert the key provided by the tool (provider) in PEM format here.###26 08 2024 new variable -lti#:#lti_con_prov_always_learner#:#LTI User is always Learner -lti#:#lti_con_prov_always_learner_info#:#Usually the role in ILIAS is mapped to a LTI role. Course Administrators could have more rights in the Kiszolgáló, e.g. to manipulate the object. Activate this option to avoid the Role Mapping. -lti#:#lti_con_prov_authentication#:#Authentication -lti#:#lti_con_prov_availability#:#Availability -lti#:#lti_con_prov_availability_create#:#For Creating Objects -lti#:#lti_con_prov_availability_existing#:#Only for existing Objects -lti#:#lti_con_prov_availability_non#:#not available -lti#:#lti_con_prov_category#:#Category -lti#:#lti_con_prov_category_info#:#Category to filter entries when LTI Consumer Object is created. -lti#:#lti_con_prov_custom_params#:#Custom Parameters for this specific Kiszolgáló -lti#:#lti_con_prov_custom_params_info#:#Please enter them in the form param1=value1; param2=value2 -lti#:#lti_con_prov_description#:#Description +lti#:#lti_con_content_item#:#Deep Linking támogatása##XXX +lti#:#lti_con_content_item_url#:#Tartalom URL +lti#:#lti_con_grade_synchronization#:#Fejlett Osztályozási Szolgáltatás +lti#:#lti_con_grade_synchronization_info#:#Az LTI-eszköznek fel kell ajánlania ‘Hozzárendelési és Osztályozási Szolgáltatások’. +lti#:#lti_con_initiate_login_url#:#Bejelentkezési URL inicializálása +lti#:#lti_con_key_type#:#Nyilvános kulcs típusa +lti#:#lti_con_key_type_jwk#:#URL (Json Web Token) +lti#:#lti_con_key_type_jwk_url#:#URL +lti#:#lti_con_key_type_rsa#:#RSA-kulcs +lti#:#lti_con_key_type_rsa_public_key#:#Nyilvános kulcs +lti#:#lti_con_key_type_rsa_public_key_info#:#Ide illessze be az eszköz (szolgáltató) által biztosított PEM formátumú kulcsot. +lti#:#lti_con_prov_always_learner#:#Az LTI-felhasználó mindig tanuló +lti#:#lti_con_prov_always_learner_info#:#Az ILIAS szerepköre általában LTI-szerepre van leképezve. A kurzusvezetők több joguk lehetne a Kiszolgálóban, például kezelni az objektumot. Kapcsolja be ezt a lehetősget a szerepleképezés elkerüléséhez. +lti#:#lti_con_prov_authentication#:#Hitelesítés +lti#:#lti_con_prov_availability#:#Elérhetőség +lti#:#lti_con_prov_availability_create#:#Újonan létrehozott objektumok esetén +lti#:#lti_con_prov_availability_existing#:#Csak már létező objektumok esetén +lti#:#lti_con_prov_availability_non#:#nem érhető el +lti#:#lti_con_prov_category#:#Kategória +lti#:#lti_con_prov_category_info#:#Bejegyzések szűrésére LTI-Fogyasztói objektumok létrehozáskor. +lti#:#lti_con_prov_custom_params#:#Egyéni paraméter a megadott Kiszolgálóhoz +lti#:#lti_con_prov_custom_params_info#:#Adja meg a követező formátumban: param1=value1; param2=value2 +lti#:#lti_con_prov_description#:#Leírás +lti#:#lti_con_prov_dyn_reg_params#:#Opcionális paraméterek +lti#:#lti_con_prov_dyn_reg_params_info#:#Itt adhatók meg például hivatkozás az eszközben lévő célobjektumokra. +lti#:#lti_con_prov_dyn_reg_url#:#Az eszköz regisztrációs URL-je +lti#:#lti_con_prov_dyn_reg_url_info#:#Megjegyzés: Nem minden eszköz támogatja a dinamikus regisztrációt. lti#:#lti_con_prov_external_provider#:#Küldő kiszolgáló -lti#:#lti_con_prov_external_provider_info#:#A hint will be shown to users when dealing with an external Kiszolgáló. An external Kiszolgáló is characterized by insufficient influence on the Kiszolgáló by the operator of the ILIAS-installation. This is the case when there are no rights to delete. -lti#:#lti_con_prov_group_options#:#Options to group and filter Kiszolgálós -lti#:#lti_con_prov_has_outcome_service#:#Kiszolgáló supports Outcome Service -lti#:#lti_con_prov_has_outcome_service_info#:#If the LTI Outcome Service is supported, Learning Progress could be activated. The Kiszolgáló returns a value between 0 and 1 to indicate the Learning Progress. -lti#:#lti_con_prov_hints#:#Hints -lti#:#lti_con_prov_icon#:#Icon -lti#:#lti_con_prov_inc_usr_pic#:#Send User Picture -lti#:#lti_con_prov_inc_usr_pic_info#:#Links to ILIAS user pictures are included at launch of LTI consumer object. -lti#:#lti_con_prov_instructor_email#:#Instructor E-Mail###26 08 2024 new variable -lti#:#lti_con_prov_instructor_email_info#:#In difference to the previously selected settings, the e-mail address can be transferred for instructors. To do this, they must be course or group administrators.###26 08 2024 new variable -lti#:#lti_con_prov_instructor_name#:#Instructor Name###26 08 2024 new variable -lti#:#lti_con_prov_instructor_name_info#:#In difference to the previously selected settings, the name can be transferred for instructors.###26 08 2024 new variable -lti#:#lti_con_prov_key#:#Key -lti#:#lti_con_prov_keywords#:#Keywords -lti#:#lti_con_prov_keywords_info#:#The keywords must be separated by a Semicolon (;). The Keywords are automatically taken to the Metadata as Keywords. -lti#:#lti_con_prov_launch_options#:#Launch Options -lti#:#lti_con_prov_learning_progress_options#:#Options for Learning Progress -lti#:#lti_con_prov_mastery_score_default#:#Default Mastery Score -lti#:#lti_con_prov_mastery_score_default_info#:#The Learning Progress will be evaluated from the Kiszolgáló Outcome Service and the mastery score threshold. +lti#:#lti_con_prov_external_provider_info#:#Tipp jelenik meg a felhasználók számára, amikor külső Kiszolgálóval dogoznak. A külső Kiszolgálót az jellemzi, hogy az ILIAS-telepítés üzemeltetője nem tud kellőképpen befolyást gyakorolni a Kiszolgálóra. Ebben az esetben például nincs törlési jogsultsága. +lti#:#lti_con_prov_group_options#:#Kiszolgálók csopoprtosításának és szűrésének lehetőségei +lti#:#lti_con_prov_has_outcome_service#:#Kiszolgáló támogatja a Kimeneti Szolgáltatást +lti#:#lti_con_prov_has_outcome_service_info#:#Ha a Kiszolgáló támogatja az LTI Kimeneti Szolgáltatást, a tanulási haladást be lehet kapocsolni. A Kiszolgáló 0 és 1 közötti értéket ad vissza a tanulási haladásról. +lti#:#lti_con_prov_hints#:#Tippek +lti#:#lti_con_prov_icon#:#Ikon +lti#:#lti_con_prov_inc_usr_pic#:#A felhazsnáló képének küldése +lti#:#lti_con_prov_inc_usr_pic_info#:#Az LTI fogyasztói objektum indításakor az ILIAS felhasználói képeire mutató hivatkozások szerepelnek. +lti#:#lti_con_prov_instructor_email#:#Oktató e-mail címe +lti#:#lti_con_prov_instructor_email_info#:##A korábban kiválasztott beállításoktól eltérően az e-mail cím név átkerülhet az oktatókhoz. Ehhez kurzus- vagy csoportvezetőnek kell lennie. +lti#:#lti_con_prov_instructor_name#:#Oktató neve +lti#:#lti_con_prov_instructor_name_info#:#A korábban kiválasztott beállításoktól eltérően a név átkerülhet az oktatókhoz. +lti#:#lti_con_prov_key#:#Kulcs +lti#:#lti_con_prov_keywords#:#Kulcsszavak +lti#:#lti_con_prov_keywords_info#:#A kulcsszavakat pontoszvesszővel (;) kell elválasztani. A metaadatok közé automatikusan bekerülnek ezek a kulcsszavak. +lti#:#lti_con_prov_launch_options#:#Indítási beállítások +lti#:#lti_con_prov_learning_progress_options#:#Tanulási haladás beállításai +lti#:#lti_con_prov_mastery_score_default#:#Alapértelmezett Kötelező Pontszám +lti#:#lti_con_prov_mastery_score_default_info#:#A tanulási halaldást a Kiszolgáló Kimeneti Szolgáltatása és a kötelező pontszám küszöbértékel határozza meg. lti#:#lti_con_prov_privacy_setting_conf#:#Beállítási lehetőségek lti#:#lti_con_prov_privacy_setting_default#:#Alapértelmezett beállítások, módosíthatók az objektumoknál lti#:#lti_con_prov_privacy_setting_force#:#Az objektumok beállításai nem módosíthatók lti#:#lti_con_prov_privacy_setting_info#:#Konfigurációs beállítások az adatvédelmi beállításokhoz -lti#:#lti_con_prov_privacy_settings#:#Privacy Settings -lti#:#lti_con_prov_provider_key_global#:#Predefined Key and Secret -lti#:#lti_con_prov_provider_key_global_info#:#If not set, users have to add key and secret to use the provider. +lti#:#lti_con_prov_privacy_settings#:#Adatvédelmi beállítások +lti#:#lti_con_prov_provider_key_global#:#Előre meghatározott Kulcs és Titok +lti#:#lti_con_prov_provider_key_global_info#:#Ha nincs beállítva, a felhasználóknak hozzá kell adniuk a kulcsot és a titkot a szolgáltató használatához. lti#:#lti_con_prov_remarks#:#Internal Remarks -lti#:#lti_con_prov_secret#:#Secret -lti#:#lti_con_prov_title#:#Title -lti#:#lti_con_prov_url#:#URL of Kiszolgáló -lti#:#lti_con_prov_use_provider_id#:#Use Kiszolgáló ID -lti#:#lti_con_prov_use_provider_id_info#:#Usually the Ref-Id of the LTI Consumer is transferred to the Kiszolgáló. Some Kiszolgálók map this Ref-Id with the Resource of the Kiszolgáló. To get always the same Resource for these Kiszolgálók this Option should be activated. -lti#:#lti_con_prov_use_xapi#:#Kiszolgáló supports request of xAPI-Statements -lti#:#lti_con_prov_use_xapi_info#:#A kiszolgáló támogatja xAPI-nyilatkozatokat -lti#:#lti_con_prov_xapi_activity_id#:#Activity ID -lti#:#lti_con_prov_xapi_activity_id_info#:#The Activity ID is necessary to request data from the Learning Record Store. Only enter something here if the assignment of the provider's resource to an Activity Id is unique! If nothing is entered here, the Activity Id can be entered in LTI Consumer. The Activity Id could be requested from the LTI Kiszolgáló. +lti#:#lti_con_prov_secret#:#Titok +lti#:#lti_con_prov_title#:#Cím +lti#:#lti_con_prov_url#:#LTI kiszolgáló URL-je +lti#:#lti_con_prov_use_provider_id#:#Kiszolgáló-ID használata +lti#:#lti_con_prov_use_provider_id_info#:#Általában az LTI-Fogyasztó Ref-Id-je átkerül a Kiszolgálóba. Néhány Kiszolgálók leképezi ezt a Ref-Id-t a Kiszolgáló erőforrásával. Ahhoz, hogy ezekhez a Kiszolgálókhoz mindig ugyanaz az Erőforrás legyen, ezt az opciót aktiválni kell. +lti#:#lti_con_prov_use_xapi#:#Kiszolgáló támogatja az xAPI-Statements kéréseket +lti#:#lti_con_prov_use_xapi_info#:#A kiszolgáló támogatja xAPI-Nyilatkozatokat +lti#:#lti_con_prov_xapi_activity_id#:#Aktivitás ID +lti#:#lti_con_prov_xapi_activity_id_info#:#A tevékenységazonosító szükséges ahhoz, hogy adatokat kérjen a LRS-ből. Csak akkor írjon be ide valamit, ha a szolgáltató erőforrásának tevékenységazonosítóhoz való hozzárendelése egyedi! Ha itt nem ad meg semmit, akkor a tevékenységazonosító beírható az LTI-fogyasztóba. A tevékenységazonosítót az LTI-Kiszolgálótól lehetett igényelni. lti#:#lti_con_prov_xapi_launch_key#:#Az LRS-végpont kulcsa lti#:#lti_con_prov_xapi_launch_key_info#:#  -lti#:#lti_con_prov_xapi_launch_secret#:#Secret of LRS-végpont +lti#:#lti_con_prov_xapi_launch_secret#:#LRS-végpont titka lti#:#lti_con_prov_xapi_launch_secret_info#:#  lti#:#lti_con_prov_xapi_launch_url#:#Az LRS-végpont URL-je -lti#:#lti_con_prov_xapi_launch_url_info#:#Please add full URL with https:// -lti#:#lti_con_redirection_uris#:#Redirection URI###26 08 2024 new variable -lti#:#lti_con_tool_url#:#Launch URL###26 08 2024 new variable -lti#:#lti_con_version#:#LTI Version###26 08 2024 new variable -lti#:#lti_con_version_1.1#:#Version 1.1###26 08 2024 new variable -lti#:#lti_con_version_1.3#:#Version 1.3###26 08 2024 new variable -lti#:#lti_con_version_1.3_before_id#:#If dynamic registration is not used, after entering the data provided by the tool, additional data will appear that must be entered with the tool.###26 08 2024 new variable -lti#:#lti_confirm_delete_providers#:#Are you sure that you want to delete the following provider(s)? +lti#:#lti_con_prov_xapi_launch_url_info#:#Adja meg a teljes, ‘https://’ kezdetű URL-t +lti#:#lti_con_redirection_uris#:#Átirányitásai URI +lti#:#lti_con_tool_url#:#Bejelentkezési URL +lti#:#lti_con_version#:#LTI verzió +lti#:#lti_con_version_1.1#:#1.1 verzió +lti#:#lti_con_version_1.3#:#1.3 verzió +lti#:#lti_con_version_1.3_before_id#:#Ha nem használunk dinamikus regisztrációt, az eszköz által kért adatok megadása után további adatok jelennek meg, amelyeket az eszközzel kell megadni. +lti#:#lti_confirm_delete_providers#:#Biztos, hogy törli a következő kiszolgáló(ka)t? lti#:#lti_consumer#:#Megosztva vele: lti#:#lti_consumer_created#:#A fogyasztót sikeresen létrehozta lti#:#lti_consumer_deleted#:#A fogyasztót sikeresen törölte @@ -11371,117 +11433,118 @@ lti#:#lti_consumer_secret#:#Fogyasztótitok lti#:#lti_consumer_set_active#:#A fogyasztót sikeresen aktiválta lti#:#lti_consumer_set_inactive#:#A fogyasztót sikeresen deaktiválta lti#:#lti_consumer_updated#:#A fogyasztót sikeresen módosította -lti#:#lti_consuming_tab#:#Az ILIAS, mint LTI Fogyasztó -lti#:#lti_copy#:#Fogyasztók máasolása +lti#:#lti_consuming_tab#:#Az ILIAS mint LTI-Fogyasztó +lti#:#lti_copy#:#Fogyasztók másolása lti#:#lti_create_consumer#:#Fogyasztó létrehozása -lti#:#lti_create_lti_user_role#:#LTI-felhasználónak ajánlott globális szerep létrehozása +lti#:#lti_create_lti_user_role#:#LTI-felhasználónak ajánlott globális szerepkör létrehozása lti#:#lti_cron_title#:#LTI-kimeneti Szolgáltatás lti#:#lti_cron_title_desc#:#Az LTI-felhasználók tanulási haladási állapotát szinkronizálja egy LTI-eszközfogyasztóval, amennyiben az támogatja a kimeneti szolgáltatást. Erre az ütemezett feladatra csak a tanulási haladás beállításainak módosítása után van szükség. -lti#:#lti_custom_new#:#Create Own Kiszolgáló Settings +lti#:#lti_custom_new#:#Create Own Settings for Provider resp. Tool lti#:#lti_delete_consume_provider#:#Kiszolgáló törlése lti#:#lti_delete_consume_providers#:# Kiszolgálók törlése -lti#:#lti_delete_provider#:#Delete Kiszolgáló +lti#:#lti_delete_provider#:#Kiszolgáló törlése +lti#:#lti_dynamic_registration#:#Az eszközhöz saját beállítások létrehozása dinamikus regisztrációval (LTI 1.3) lti#:#lti_edit_consumer#:#LTI-fogyasztó módosítása lti#:#lti_exit#:#LTI-munkamenet lezárása lti#:#lti_exited#:#LTI-munkamenet lezárva lti#:#lti_exited_info#:#LTI-munkamenet sikeresen lezárult -lti#:#lti_form_provider_create#:#Create Kiszolgáló Settings -lti#:#lti_form_provider_edit#:#Edit Kiszolgáló Settings -lti#:#lti_form_section_appearance#:#Options for launch -lti#:#lti_global_settings_form#:#Global Settings -lti#:#lti_import_global_provider#:#Import Global Kiszolgáló for all Users with XML-File -lti#:#lti_info_external_provider_info#:#The used Kiszolgáló is an external Kiszolgáló. An external Kiszolgáló is characterized by insufficient influence on the Kiszolgáló by the operator of the ILIAS-Installation. This is the case e.g. if there are no rights to delete data. -lti#:#lti_info_external_provider_label#:#Additional Info about this Kiszolgáló -lti#:#lti_info_learning_progress_section#:#Info about Determination of the Learning Progress -lti#:#lti_info_privacy_section#:#Info about personal data transmitted to the provider at launch +lti#:#lti_form_provider_create#:#Kiszolgáló beállításainak létrehozása +lti#:#lti_form_provider_edit#:#Kiszolgáló beállításainak módosítása +lti#:#lti_form_section_appearance#:#Indítás beállításai +lti#:#lti_global_settings_form#:#Globális beállítások +lti#:#lti_import_global_provider#:#Az összes felhasználó Globális Kiszolgálójának importálása XML-fájlba +lti#:#lti_info_external_provider_info#:#A használatban lévő Kiszolgáló egy külső Kiszolgáló. A külső Kiszolgálót az jellemzi, hogy az ILIAS-telepítés üzemeltetője nem tud kellőképpen befolyást gyakorolni a Kiszolgálóra. Az ilyen esetben péládul nincs jogosultság az adatok törlésére. +lti#:#lti_info_external_provider_label#:#A Kiszolgáló kiegészítő információi +lti#:#lti_info_learning_progress_section#:#Információ a tanulási haladás meghatározásáról +lti#:#lti_info_privacy_section#:#Tájékoztatás a szolgáltatónak induláskor továbbított személyes adatokról lti#:#lti_launch_url#:#Url lti#:#lti_member#:#LTI-címke lti#:#lti_navigation#:#Navigáció lti#:#lti_no_provider_selected#:#No provider selected lti#:#lti_not_allowed#:#Hozzáférés megtagadva. Kérését átirányítjuk az LTI-objektum gyökérébe. -lti#:#lti_obj_active#:#LTI-Eszközszolgáltató -lti#:#lti_obj_active_info#:#Ha be van kapcsolva, ez az objektum egy LTI-eszközszolgáltatóként működik. Új LTI-felhasználókat automatikusan hozzárendeljük az alábbi helyi szerepekhez. -lti#:#lti_obj_version#:#LTI Version###26 08 2024 new variable -lti#:#lti_obj_version_11#:#Version 1.1###26 08 2024 new variable -lti#:#lti_obj_version_13#:#Version 1.3###26 08 2024 new variable +lti#:#lti_obj_active#:#LTI-Kiszolgáltató/-Eszköz +lti#:#lti_obj_active_info#:#Ez az objektum egy LTI-eszközszolgáltatóként működik. Új LTI-felhasználókat automatikusan hozzárendeljük az alábbi helyi szerepkörökhöz. +lti#:#lti_obj_version#:#LTI Version +lti#:#lti_obj_version_11#:#Version 1.1 +lti#:#lti_obj_version_13#:#Version 1.3 lti#:#lti_object_consumer#:#LTI-fogyasztók lti#:#lti_object_release_settings_form#:#LTI-megosztások módosítása lti#:#lti_provider#:#LTI-megosztások -lti#:#lti_provider_not_avail_msg#:#Az LTI-kiszolgáló értéke 'Nem érhető el' -lti#:#lti_provider_not_set_msg#:#Configuration of LTI Provider / tool is not completely finished.###29 10 2025 new variable +lti#:#lti_provider_not_avail_msg#:#Az LTI-kiszolgáló / -Eszköz értéke ‘Nem érhető el’ +lti#:#lti_provider_not_set_msg#:#Az LTI-kiszolgáló / -eszköz beállítása még nem teljes. lti#:#lti_providing_tab#:#Az ILIAS, mint LTI-Kiszolgáló lti#:#lti_released_objects#:#Megosztott objektumok -lti#:#lti_select_provider#:#Válasszon Kiszolgálót +lti#:#lti_select_provider#:#Válasszon Kiszolgáló resp. Eszközt lti#:#lti_session#:#LTI-munkamenet lti#:#lti_settings#:#LTI beállítások lti#:#lti_settings_form#:#Objektum beállításai -lti#:#lti_success_accept_as_global#:#Successfully accepted as Global Kiszolgáló for all Users -lti#:#lti_success_accept_as_global_multi#:#Successfully accepted as Global Kiszolgáló for all Users -lti#:#lti_success_delete_provider#:#Successfully deleted -lti#:#lti_success_reset_to_usr_def#:#Successfully reseted as User Defined Kiszolgáló -lti#:#lti_success_reset_to_usr_def_multi#:#Successfully reseted as User Defined Kiszolgáló +lti#:#lti_success_accept_as_global#:#Sikeresen elfogadta mint a Globális Kiszolgálót az összes felhasználó számára +lti#:#lti_success_accept_as_global_multi#:#Sikeresen elfogadta mint a Globális Kiszolgálót az összes felhasználó számára +lti#:#lti_success_delete_provider#:#Sikeresen törölte +lti#:#lti_success_reset_to_usr_def#:#Sikeresen resztelte mint a felhasználó által meghatározott Kiszolgálót +lti#:#lti_success_reset_to_usr_def_multi#:#Sikeresen reszetelte mint a felhasználó által meghatározott Kiszolgálót lti#:#lti_tutor#:#LTI-instruktor -lti#:#lti_user_role_created#:#Az LTI-felhasználónak ajánlott globális szerepet sikeresen létrehozta. -lti#:#lti_user_role_info#:#Ajánlott globális szerep még nem létezik az LTI-felhasználónak. Ez a speciális szerep csak a Tartalomtár és kategóriák 'látható' jogosultáságát tartalmazza. -lti#:#mastery_score#:#Mastery Score -lti#:#mastery_score_info#:#The Learning Progress will be evaluated from the Kiszolgáló Outcome Service and the mastery score threshold. -lti#:#obj_tile_image_info#:#Use an Image in Square Format -lti#:#online_info#:#This makes the object visible and usable for the users. +lti#:#lti_user_role_created#:#Az LTI-felhasználónak ajánlott globális szerepkört sikeresen létrehozta. +lti#:#lti_user_role_info#:#Ajánlott globális szerepkör még nem létezik az LTI-felhasználónak. Ez a speciális szerepkör csak a Tartalomtár és kategóriák ‘látható’ jogosultságát tartalmazza. +lti#:#mastery_score#:#Kötelező pontszám +lti#:#mastery_score_info#:#A tanulási haladást a Kiszolgáló kimeneti szolgáltatása és a kötelező pontszám határozza meg. +lti#:#obj_tile_image_info#:#Kép használata négyzet formában +lti#:#online_info#:#Ez a lehetőség a felhasználók számárá láthatóvá és elérhetővé teszi az objektumot. lti#:#prefix#:#Előtag -lti#:#provider_info#:#Used Kiszolgáló -lti#:#settings_subtab#:#Settings -lti#:#show_statements#:#Display Learning Experiences -lti#:#show_statements_info#:#The Learning Experiences of other users could be displayed if the right 'A többi felhasználó tanulási tapasztalatának megtekintése' is set. +lti#:#provider_info#:#Haszánaltban lévő Kiszolgáló +lti#:#settings_subtab#:#Beállítások +lti#:#show_statements#:#Tanulási tapasztalatok megjelenítése +lti#:#show_statements_info#:#A többi felhasználó tanulási tapasztalat akkor jelenik meg, ha az ‘A többi felhasználó tanulási tapasztalatának megtekintése’ jogosultsággal rendelkezik. lti#:#subtab_certificate#:#Tanúsítványok -lti#:#subtab_object_settings#:#Object Settings -lti#:#subtab_provider_settings#:#LTI-kiszolgáló Settings +lti#:#subtab_object_settings#:#Objektum beállításai +lti#:#subtab_provider_settings#:#Kiszolgáló resp. Eszköz beállításai lti#:#tab_content#:#Tartalom lti#:#tab_info#:#Info -lti#:#tab_scoring#:#Ranking +lti#:#tab_scoring#:#Helyezés lti#:#tab_settings#:#Beállítások -lti#:#tab_statements#:#Learning Experiences -lti#:#tbl_grade_activity_progress#:#Activity Progress###26 08 2024 new variable -lti#:#tbl_grade_actor#:#User###26 08 2024 new variable -lti#:#tbl_grade_date#:#Date###26 08 2024 new variable -lti#:#tbl_grade_grading_progress#:#Grading Progress###26 08 2024 new variable -lti#:#tbl_grade_period#:#Period###26 08 2024 new variable -lti#:#tbl_grade_score#:#Score###26 08 2024 new variable -lti#:#tbl_grade_stored#:#Transmitted to ILIAS###26 08 2024 new variable -lti#:#tbl_lti_prov_all_categories#:#All Categories +lti#:#tab_statements#:#Tanulási tapasztalatok +lti#:#tbl_grade_activity_progress#:#Állapot választása +lti#:#tbl_grade_actor#:#Felhasználó +lti#:#tbl_grade_date#:#Dátum +lti#:#tbl_grade_grading_progress#:#Értékelési folyamat +lti#:#tbl_grade_period#:#Időszak +lti#:#tbl_grade_score#:#Pont +lti#:#tbl_grade_stored#:#Átküldve az ILIAS-nak +lti#:#tbl_lti_prov_all_categories#:#Összes kategória lti#:#tbl_lti_prov_availability#:#Elérhetőség -lti#:#tbl_lti_prov_category#:#Category +lti#:#tbl_lti_prov_category#:#Kategória lti#:#tbl_lti_prov_description#:#Leírás -lti#:#tbl_lti_prov_icon#:#Icon +lti#:#tbl_lti_prov_icon#:#Ikon lti#:#tbl_lti_prov_internal#:#Internal Kiszolgáló -lti#:#tbl_lti_prov_keyword#:#Keyword -lti#:#tbl_lti_prov_keywords#:#Keywords +lti#:#tbl_lti_prov_keyword#:#Kulcsszó +lti#:#tbl_lti_prov_keywords#:#Kulcsszavak lti#:#tbl_lti_prov_outcome#:#Outcome Service -lti#:#tbl_lti_prov_own_provider#:#Own Kiszolgáló -lti#:#tbl_lti_prov_provider_creator#:#Creator -lti#:#tbl_lti_prov_title#:#Title of Kiszolgáló -lti#:#tbl_lti_prov_usages#:#Usages -lti#:#tbl_lti_prov_usages_trashed#:#Trashed Usages -lti#:#tbl_lti_prov_usages_untrashed#:#Repository Usages +lti#:#tbl_lti_prov_own_provider#:#Saját Kiszolgáló +lti#:#tbl_lti_prov_provider_creator#:#Létrehozó +lti#:#tbl_lti_prov_title#:#A Kiszolgáló resp. Eszköz címe +lti#:#tbl_lti_prov_usages#:#Használatok +lti#:#tbl_lti_prov_usages_trashed#:#Lomtárhasználat +lti#:#tbl_lti_prov_usages_untrashed#:#Tartalomtár-használat lti#:#tbl_lti_prov_used_by#:#Kiszolgáló Used by Objects in Tree lti#:#tbl_lti_prov_with_key#:#Predefined with Key / Secret -lti#:#tbl_provider_header#:#LTI Kiszolgáló -lti#:#tbl_provider_usage_header#:#LTI Kiszolgáló -lti#:#tbl_provider_usage_header_info#:#Before deleting providers, trashed usages must also be deleted. -lti#:#title_info#:#Give the object a title. -lti#:#usage_subtab#:#Használat +lti#:#tbl_provider_header#:#LTI-Kiszolgáló / Eszköz +lti#:#tbl_provider_usage_header#:#LTI-Kiszolgáló / Eszköz +lti#:#tbl_provider_usage_header_info#:#A kiszolgáló törlése előtt a lomtárat ki kell üríteni. +lti#:#title_info#:#Adjon az objektumnak címet +lti#:#usage_subtab#:#Használatban lti#:#use_xapi#:#Use xAPI-Support -lti#:#use_xapi_info#:#This LTI Kiszolgáló supports xAPI-Statements. +lti#:#use_xapi_info#:#Ez az LTI-Kiszolgáló támogatja az xAPI-Nyilatkozatokat. lti#:#user_lng#:#Felhasználó nyelve -lti#:#user_provider_subtab#:#Kiszolgálók Defined by Users -ltiv#:#ltiv_create#:#Create Certificate for LTI Fogyasztók Objektum###XXX -ltiv#:#ltiv_create_info#:#Select a completed LTI Fogyasztók objektum to generate a certificate for it +lti#:#user_provider_subtab#:#Felhasználó által definiált Kiszolgálók +ltiv#:#ltiv_create#:#Az LTI-Fogyasztóobjektumoknak tanúsítvány létrehozása +ltiv#:#ltiv_create_info#:#Válassza ki a teljesített LTI-Fogyasztóobjektumot, melyhez tanúsítványt kíván generálni mail#:#back_to_folder#:#Vissza a mappához mail#:#chat_users_have_been_invited#:#Az alábbi felhasználókat hívta meg mail#:#chat_users_without_login#:#Az alábbi felhasználóknak nincs ILIAS-fiókja, nem lehetnek meghívva csevegőszobába. mail#:#chat_users_without_permission#:#Az alábbi felhasználóknak nincs hozzáférése a kiválasztott csevegőszobához: mail#:#current_folder#:#Jelenlegi mappa: %s -mail#:#deleteTemplate#:#Delete###29 07 2022 new variable -mail#:#edit_attachments#:#Edit Attachments###29 10 2025 new variable +mail#:#deleteTemplate#:#Törlés +mail#:#edit_attachments#:#Csatolás módosítása mail#:#first_email_missing_info#:#Ez a kiválasztás nem lehetséges, mert nincs megadva e-mail cím. mail#:#forward#:#Továbbküld mail#:#goto_invitation_chat#:#A csevegőszoba nyitva. @@ -11490,47 +11553,48 @@ mail#:#link_check_affected_links#:#Érintett linkek: mail#:#link_check_introduction#:#az alábbi weblinkek érvénytelenek: mail#:#link_check_perma_link#:#Állandó link mail#:#link_check_reason#:#Ezt a levelet azért kapta, mert beállította, hogy kér értesítést érvénytelen weblink észrevételekor. -mail#:#mail_1#:#1 Mail###28 10 2024 new variable -mail#:#mail_absence_auto_responder_body#:#Message###26 08 2024 new variable -mail#:#mail_absence_auto_responder_body_hint#:#This is an automatically generated message. If you send further messages to this user during their absence, you will not receive another automatic reply until [NEXT_AUTO_RESPONDER_DATETIME].###26 08 2024 new variable -mail#:#mail_absence_auto_responder_body_info#:#This message will be sent automatically during your absence if users send you a Mail from within ILIAS.
    Users will be notified of your absence every %1$s days if they send further messages.###26 08 2024 new variable -mail#:#mail_absence_auto_responder_body_info_single_day#:#This message will be sent automatically during your absence if users send you a Mail from within ILIAS.
    Users will be notified again of your absence the next day if they send further messages.###26 08 2024 new variable -mail#:#mail_absence_auto_responder_subject#:#Subject###26 08 2024 new variable -mail#:#mail_absence_duration#:#Duration###26 08 2024 new variable -mail#:#mail_absence_status#:#Enable Autoresponder###26 08 2024 new variable -mail#:#mail_absence_status_info#:#Activate an automatic out-of-office message.###26 08 2024 new variable -mail#:#mail_absent_from#:#Absent from###26 08 2024 new variable -mail#:#mail_absent_until#:#Absent until###26 08 2024 new variable -mail#:#mail_account_mail#:#Bejelentkezési e-mail +mail#:#mail_1#:#1 levél +mail#:#mail_absence_auto_responder_body#:#Üzenet +mail#:#mail_absence_auto_responder_body_hint#:#Ez egy automatikus üzenet. Nem fog ilyen üzenetet kapni eddig: [NEXT_AUTO_RESPONDER_DATETIME]. +mail#:#mail_absence_auto_responder_body_info#:#Ezt az üzenetet a rendszer automatikusan elküldi távolléte alatt, amikor a felhasználók belső ILIAS-üzenetet küldenek Önnek.
    A felhasználók %1$s naponta értesítést kapnak távollétéről, ha további üzeneteket küldenek. +mail#:#mail_absence_auto_responder_body_info_single_day#:#Ezt az üzenetet a rendszer automatikusan elküldi távolléte alatt, amikor a felhasználók belső ILIAS-üzenetet küldenek Önnek.
    A felhasználók másnap ismét értesítést kapnak távollétéről, ha további üzeneteket küldenek. +mail#:#mail_absence_auto_responder_subject#:#Tárgy +mail#:#mail_absence_duration#:#Időtartam +mail#:#mail_absence_status#:#Automatikus válaszok +mail#:#mail_absence_status_info#:#A házon kívül vagyok üzenet automatikus küldésének bekapcsolása +mail#:#mail_absent_from#:#Kezdő időpont +mail#:#mail_absent_until#:#Záró időpont +mail#:#mail_account_mail#:#Az új fióktulajdonosok értesítése mail#:#mail_add_folder#:#Új almappa létrehozása mail#:#mail_add_recipient#:#Adja meg az elküldendő levél címzettjét! mail#:#mail_add_subfolder#:#Almappa létrehozása mail#:#mail_add_subject#:#Adja meg az elküldendő levél tárgyát! -mail#:#mail_all_in_trash#:#All in Trash###28 10 2024 new variable +mail#:#mail_adopt_selected_attachements#:#Kijelölt mellékletek elfogadása +mail#:#mail_all_in_trash#:#Az összeset a lomtárban mail#:#mail_allow_external#:#Külső levelek mail#:#mail_allow_external_info#:#Ha ki van kapcsolva, külső levelek küldése (SMTP-n keresztül) központilag le van tiltva. -mail#:#mail_assign_entry_to_mailing_list#:#Rendeljen hozzá egy névjegyet a csoporthoz -mail#:#mail_assign_to_mailing_list#:#Assign###26 08 2024 new variable +mail#:#mail_assign_entry_to_mailing_list#:#Rendeljen hozzá egy névjegyet ‘%s’ levelezési csoporthoz +mail#:#mail_assign_to_mailing_list#:#Hozzárendelés mail#:#mail_attachment_file_not_exist#:#Legalább az egyik csatolmány nem található: %1$s mail#:#mail_attachments#:#Mellékletek mail#:#mail_auto_generated_info#:#Ezt a levelet automatikusan küldte Önnek az ILIAS %s: %s -mail#:#mail_auto_responder#:#Autoresponder###26 08 2024 new variable -mail#:#mail_auto_responder_idle_time#:#Resend###26 08 2024 new variable -mail#:#mail_auto_responder_idle_time_info#:#Specify here how many days should elapse before your out-of-office reply is resent to a mail correspondent who has sent you further mails.###26 08 2024 new variable -mail#:#mail_bcc#:#BCC###26 08 2024 new variable +mail#:#mail_auto_responder#:#Automatikus válasz +mail#:#mail_auto_responder_idle_time#:#Újraküldés +mail#:#mail_auto_responder_idle_time_info#:#Ennyi napnak kell eltelnie a házon kívüli levél ugyanannak a feladónak történő újraküldése között. +mail#:#mail_bcc#:#Titkos másolat (BCC) mail#:#mail_bg_task_desc#:#Tárgy: %s mail#:#mail_bg_task_title#:#E-mail szállítás mail#:#mail_both_email#:#Mindkét e-mail cím -mail#:#mail_cc#:#CC###26 08 2024 new variable +mail#:#mail_cc#:#Másolat (CC) mail#:#mail_change_to_folder#:#Mappaváltás: %s mail#:#mail_create_tpl#:#Szövegminta létrehozása mail#:#mail_cronjob_notification_info#:#Periodikus értesítés aktiválása az új e-mailekről mail#:#mail_crs_list_members_not_available#:#Nem lehet felsorolni a kiválasztott kurzusok tagjait. mail#:#mail_crs_list_members_not_available_for_at_least_one_crs#:#Legalább egy kiválasztott kurzus tagjait nem lehet felsorolni. -mail#:#mail_crs_roles#:#Kurzusszerepeknek levélküldés +mail#:#mail_crs_roles#:#Kurzusszerepköröknek levélküldés mail#:#mail_deleted#:#A level(ek)et sikeresen törölte. mail#:#mail_deleted_entry#:#A névjegy(ek)et sikeresen törölte -mail#:#mail_download_attachment#:#Download Attachment###28 10 2024 new variable +mail#:#mail_download_attachment#:#Csatolmány letöltése mail#:#mail_download_zip_no_attachments#:#Egy csatolmány sem található. mail#:#mail_edit_tpl#:#Szövegminta módosítása mail#:#mail_email_sys_body#:#Ez a rendszer e-mailek külső e-mail címre küldésének tesztelése. @@ -11540,15 +11604,15 @@ mail#:#mail_email_usr_subject#:#Felhasználói teszt e-mail mail#:#mail_empty_trash#:#Kuka ürítése mail#:#mail_empty_trash_confirmation#:#Biztos, hogy minden levelet töröl a kukából? mail#:#mail_enable_crs_admin_notification#:#Kurzusvezetők értesítése -mail#:#mail_enable_crs_admin_notification_info#:#Új kurzus létrehozásakor az 'Új tagokról értesítés' alapértelmezetten aktív lesz. Ez a beállítás a kurzus 'Tagok' fülén található. A kurzusvezetők levélben értesítést kapnak, amikor valaki csatlakozik a kurzushoz vagy elhagyja azt, illetve ha a kurzushoz előírt minimális létszám nem jön össze. +mail#:#mail_enable_crs_admin_notification_info#:#Új kurzus létrehozásakor az ‘Új tagokról értesítés’ alapértelmezetten aktív lesz. Ez a beállítás a kurzus ‘Tagok’ lapján található. A kurzusvezetők levélben értesítést kapnak, amikor valaki csatlakozik a kurzushoz vagy elhagyja azt, illetve ha a kurzushoz előírt minimális létszám nem jön össze. mail#:#mail_enable_crs_member_notification#:#Kurzustagok értesítése mail#:#mail_enable_crs_member_notification_info#:#ILIAS automatikus értesítést küld a kurzustagság változásáról. Ez a beállítás a rendszer összes kurzusára hat. mail#:#mail_enable_grp_admin_notification#:#Csoportvezetők értesítése -mail#:#mail_enable_grp_admin_notification_info#:#Új csoport létrehozásakor az 'Értesítés' alapértelmezetten aktív lesz. Ez a beállítás a csoport 'Tagok' fülén található. A csoportvezetők levélben értesítést kapnak, amikor valaki csatlakozik a kurzushoz vagy elhagyja azt, illetve ha a csoporthoz előírt minimális létszám nem jön össze. +mail#:#mail_enable_grp_admin_notification_info#:#Új csoport létrehozásakor az ‘Értesítés’ alapértelmezetten aktív lesz. Ez a beállítás a csoport ‘Tagok’ lapján található. A csoportvezetők levélben értesítést kapnak, amikor valaki csatlakozik a kurzushoz vagy elhagyja azt, illetve ha a csoporthoz előírt minimális létszám nem jön össze. mail#:#mail_enable_grp_member_notification#:#Csoporttagok értesítése mail#:#mail_enable_grp_member_notification_info#:#ILIAS automatikus értesítést küld a csoporttagság változásáról. Ez a beállítás a rendszer összes csoportjára hat. mail#:#mail_enable_lso_admin_notification#:#Tanulási sor vezetőinek értesítése -mail#:#mail_enable_lso_admin_notification_info#:#Az új Tanulási sor létrehozásakor az 'Új tagokról értesítés' alapértelmezetten aktív lesz. Ez a beállítás a Tanulás sor 'Tagok' fülén található. A vezetők levélben értesítést kapnak, amikor valaki csatlakozik a Tanulási sorhoz vagy elhagyja azt. +mail#:#mail_enable_lso_admin_notification_info#:#Az új Tanulási sor létrehozásakor az ‘Új tagokról értesítés’ alapértelmezetten aktív lesz. Ez a beállítás a Tanulás sor ‘Tagok’ lapján található. A vezetők levélben értesítést kapnak, amikor valaki csatlakozik a Tanulási sorhoz vagy elhagyja azt. mail#:#mail_enable_lso_member_notification#:#Tanulási sor tagjainak értesítése mail#:#mail_enable_lso_member_notification_info#:#Az ILIAS automatikus értesítéset küld a résztvevőnek, amikor a tagsági állapota módosul. Ez az összes Tanulás sorra hat. mail#:#mail_entry_of_contacts#:#Névjegy @@ -11562,106 +11626,108 @@ mail#:#mail_files_deleted#:#A fájl(oka)t sikeresen törölte. mail#:#mail_filter#:#Szűrő mail#:#mail_filter_attach#:#Mellékletek mail#:#mail_filter_body#:#Törzsszöveg -mail#:#mail_filter_display#:#Display###28 10 2024 new variable -mail#:#mail_filter_field_placeholder#:#Keresett szöveg... +mail#:#mail_filter_display#:#Megjelenítés +mail#:#mail_filter_field_placeholder#:#Keresett szöveg… mail#:#mail_filter_period#:#Időszak mail#:#mail_filter_recipients#:#Címzett mail#:#mail_filter_sender#:#Feladó -mail#:#mail_filter_show_read#:#Show Read###28 10 2024 new variable -mail#:#mail_filter_show_system_mails#:#Show System Notifications###28 10 2024 new variable -mail#:#mail_filter_show_unread#:#Show Unread###28 10 2024 new variable -mail#:#mail_filter_show_user_mails#:#Show User Mails###28 10 2024 new variable -mail#:#mail_filter_show_with_attachments#:#Show With Attachments###28 10 2024 new variable -mail#:#mail_filter_show_without_attachment#:#Show Without Attachment###28 10 2024 new variable +mail#:#mail_filter_show_read#:#Olvasottak megjelenítése +mail#:#mail_filter_show_system_mails#:#Rendszerértesítések megjelenítése +mail#:#mail_filter_show_unread#:#Olvasatlanok megjelenítése +mail#:#mail_filter_show_user_mails#:#Felhasználói levelek megjelenítése +mail#:#mail_filter_show_with_attachments#:#Megjelenítés csatolmányokkal +mail#:#mail_filter_show_without_attachment#:#Megjelenítés csatolmányok nélkül mail#:#mail_filter_subject#:#Tárgy mail#:#mail_filter_txt#:#Keresés a következőkben mail#:#mail_first_email#:#Elsődleges e-mail cím -mail#:#mail_firstname_last_name_superior#:#Az összes felettes kereszt- és vezetékneve vesszővel elválasztott listája +mail#:#mail_firstname_last_name_superior#:#A felhasználó feletteseinek családi- és utóneve vesszővel elválasztott listája mail#:#mail_folder_created#:#Sikeresen létrehozott egy új mappát. mail#:#mail_folder_deleted#:#A mappát sikeresen törölte mail#:#mail_folder_exists#:#Mappa már létezik ezen a néven. mail#:#mail_folder_name_changed#:#A mappát sikeresen átnevezte. mail#:#mail_following_rcp_not_valid#:#Az alábbi címzettek érvénytelenek: -mail#:#mail_form_placeholders_label#:#Available Placeholders###26 08 2024 new variable +mail#:#mail_form_placeholders_label#:#Használható helyőrzők mail#:#mail_generic_rcp_error#:#Hiba a címzettek ellenőrzése közben: %1$s -mail#:#mail_global_reply_to_addr#:#Reply-To -mail#:#mail_global_reply_to_addr_info#:#Please enter the desired 'Reply-To' address. -mail#:#mail_grp_roles#:#Csoportszerepeknek levélküldés -mail#:#mail_hint_add_placeholder_x#:#Add the placeholder '%s' to the message body.###26 08 2024 new variable +mail#:#mail_global_reply_to_addr#:#Válaszcím +mail#:#mail_global_reply_to_addr_info#:#Adja meg a kívánt válaszcímet (‘Reply-To’) címet. +mail#:#mail_grp_roles#:#Csoportszerepköröknek levélküldés +mail#:#mail_hint_add_placeholder_x#:#Adja a(z) ‘%s’ helyőrzőt a levél szövegéhez. mail#:#mail_incoming#:#Beérkező levél -mail#:#mail_incoming_both#:#helyi és továbbküldendő -mail#:#mail_incoming_local#:#csak helyi +mail#:#mail_incoming_both#:#Levelek helyi fogadása és továbbküldése +mail#:#mail_incoming_local#:#Levelek csak helyi fogadása mail#:#mail_incoming_mail#:#Beérkező levél -mail#:#mail_incoming_smtp#:#továbbküldendő az e-mail címre +mail#:#mail_incoming_smtp#:#Továbbküldés az e-mail címre: mail#:#mail_insert_folder_name#:#Adjon meg mappanevet. mail#:#mail_insert_query#:#Írja be a keresendő szöveget. mail#:#mail_invite_users_to_chat#:#Felhasználók meghívása csevegésbe -mail#:#mail_is_read#:#gelesen###29 07 2022 new variable -mail#:#mail_is_unread#:#ungelesen###29 07 2022 new variable +mail#:#mail_is_read#:#olvasott +mail#:#mail_is_unread#:#olvasatlan mail#:#mail_list_members#:#Tagok felsorolása mail#:#mail_mailing_list#:#Névjegycsoport mail#:#mail_mailing_lists#:#Névjegycsoportok mail#:#mail_mailing_lists_all_contact_entries_assigned#:#Minden névjegyet hozzárendelte ehhez a csoporthoz. mail#:#mail_mailing_lists_no_contact_entries#:#Egy névjegy sincs a címtárában. -mail#:#mail_main_folder#:#Main Folder###29 10 2025 new variable -mail#:#mail_manage_attachments#:#Manage Attachments###26 08 2024 new variable -mail#:#mail_manage_attachments_back_to_compose#:#Back to Compose###26 08 2024 new variable -mail#:#mail_manage_attachments_drop_files_msg#:#Drop file to upload###26 08 2024 new variable +mail#:#mail_main_folder#:#Fő mappa +mail#:#mail_manage_attachments#:#Csatolmányok kezelése +mail#:#mail_manage_attachments_back_to_compose#:#Vissza a levélíráshoz +mail#:#mail_manage_attachments_drop_files_msg#:#Dobja ide a fájlt a feltöltéshez mail#:#mail_mark_read#:#Megjelölés olvasottként mail#:#mail_mark_unread#:#Megjelölés olvasatlanként mail#:#mail_max_size_attachments_total#:#Adja meg egy levél mellékleteinek maximálisan engedélyezett összméretét. Ez a beállítás független más korláttól (például upload_max_filesize, stb.), mert egy levélhez több fájlt is csatolhat mellékletként. mail#:#mail_max_size_attachments_total_error#:#Mellékletek maximálisan engedélyezett összmérete: mail#:#mail_maxsize_attachment_error#:#A feltöltési határ: mail#:#mail_member_notification#:#Résztvevők értesítése -mail#:#mail_members_of_mailing_list#:#Csoport névjegyei +mail#:#mail_members_of_mailing_list#:#‘%s’ levelezési csoport tagjai mail#:#mail_members_search_continue#:#Folytatás mail#:#mail_message_send#:#Üzenetet elküldte. +mail#:#mail_mode_switch_label#:#Váltás ‘Személyes levél’ és ‘Körlevél’ mód között +mail#:#mail_mode_switch_locked#:#Nem válthat ‘%s’ módba. mail#:#mail_move_error#:#Hiba a levél áthelyezésekor mail#:#mail_move_to#:#Áthelyezés ide: -mail#:#mail_move_to_folder_btn_label#:#Move Mail###26 08 2024 new variable -mail#:#mail_move_to_folder_x#:#to "%s"###26 08 2024 new variable -mail#:#mail_moved#:#A levelet sikeren áthelyezte. +mail#:#mail_move_to_folder_btn_label#:#Levél mozgatása +mail#:#mail_move_to_folder_x#:#‘%s’ mappába +mail#:#mail_moved#:#A levelet sikeresen áthelyezte. mail#:#mail_moved_to_trash#:#A levelet a kukába helyezte. -mail#:#mail_multiple_role_recipients_found#:#%1$s (címzetthez több szerep is létezik: %2$s) +mail#:#mail_multiple_role_recipients_found#:#%1$s (címzetthez több szerepkör is létezik: %2$s) mail#:#mail_my_courses#:#Kurzusaim mail#:#mail_my_groups#:#Csoportjaim mail#:#mail_my_mailing_lists#:#Névjegycsoportok mail#:#mail_nacc_admin_mail#:#Rendszergazda e-mail címe mail#:#mail_nacc_if_timelimit#:#Ezt a szöveget csak akkor tartalmazza, ha a felhasználónak korlátozott hozzáférési időszaka van. mail#:#mail_nacc_ilias_url#:#ILIAS linkje (URL) -mail#:#mail_nacc_installation_desc#:#Installation Description###26 08 2024 new variable -mail#:#mail_nacc_installation_name#:#Installation Name###26 08 2024 new variable +mail#:#mail_nacc_installation_desc#:#Telepítés leírása +mail#:#mail_nacc_installation_name#:#Telepítés neve mail#:#mail_nacc_login#:#Felhasználónév mail#:#mail_nacc_no_pw_block#:#Ez a szövegblokk csak akkor jelenik meg, ha az ILIAS-fiók jelszó nélkül jött létre. mail#:#mail_nacc_pw_block#:#Ez a szövegblokk csak akkor jelenik meg, ha az ILIAS-fiók jelszóval jött létre. mail#:#mail_nacc_salutation#:#Üdvözlés -mail#:#mail_nacc_target#:#A cél URL-je, például hivatkozott kurzus, amely az ILIAS-ba kívülről került be. +mail#:#mail_nacc_target#:#A cél URL-je, például egy ILIAS-on kívüli kurzusé. mail#:#mail_nacc_target_block#:#Ez a szöveg csak akkor jelenik meg, ha van cél. mail#:#mail_nacc_target_title#:#Cél címe, például kurzuscím. -mail#:#mail_nacc_target_type#:#Cél típusa, például 'Kurzus'. +mail#:#mail_nacc_target_type#:#Cél típusa, például ‘Kurzus’. mail#:#mail_nacc_timelimit#:#Hozzáférési időszak mail#:#mail_nacc_title#:#Cím -mail#:#mail_nacc_use_placeholder#:#Az alábbi helyőrzők használhatóak -mail#:#mail_nacc_user_fullname#:#User Full Name###26 08 2024 new variable -mail#:#mail_nacc_user_login#:#User Login###26 08 2024 new variable -mail#:#mail_new#:#New Mail###29 10 2025 new variable +mail#:#mail_nacc_use_placeholder#:#Az alábbi helyőrzők használhatók +mail#:#mail_nacc_user_fullname#:#A felhasználó teljes neve +mail#:#mail_nacc_user_login#:#Felhasználónév +mail#:#mail_new#:#Új levél mail#:#mail_new_template#:#Új szövegminta -mail#:#mail_no_mail_items#:#No unread mails.###26 08 2024 new variable +mail#:#mail_no_mail_items#:#Nincs olvasatlan üzenete mail#:#mail_no_permissions_write_smtp#:#Nincs jogosultsága külső levelet írni -mail#:#mail_no_subject#:#No subject available###29 07 2022 new variable +mail#:#mail_no_subject#:#Nincs tárgy mail#:#mail_no_valid_mailing_list#:#%1$s (egy használható névjegycsoport sincs) mail#:#mail_notification_membership_section#:#Tagság mail#:#mail_notification_subject#:#Új levele érkezett mail#:#mail_notify_orphaned#:#Értesítő levél -mail#:#mail_notify_orphaned_info#:#Ha 1 vagy nagyobb értéket ad meg, ILIAS levelet küld a felhasználónak belső levél törlése előtt. Ellenőrizze, hogy külső címzett megadása lehetséges. -mail#:#mail_operation_on_invalid_folder#:#It was not possible to carry out the requested operation. The folder given in the server request is invalid. Please contact an administrator.###26 08 2024 new variable -mail#:#mail_options#:#Mail Options###29 10 2025 new variable +mail#:#mail_notify_orphaned_info#:#Ha 1 vagy annál nagyobb értéket ad meg, ILIAS levelet küld a felhasználónak belső levél törlése előtt. Ellenőrizze, hogy külső címzett megadása lehetséges. +mail#:#mail_operation_on_invalid_folder#:#A műveletet nem lehet végrehajtani, a szerveren a mappakérés érvénytelen. Keresse az üzemeltetőt. +mail#:#mail_options#:#Beállítások mail#:#mail_options_saved#:#Beállításokat sikeresen mentette. mail#:#mail_orphaned_mails#:#Régi és gazdátlan levelek törlése mail#:#mail_orphaned_mails_desc#:#Régi és gazdátlan levelek törlése -mail#:#mail_recipient_not_found#:#%1$s (nem található érvényes címzett) +mail#:#mail_recipient_not_found#:#%1$s - Kérem, javítsd a ‘Címzett’ mezőt mail#:#mail_rename_folder#:#Mappa átnevezése -mail#:#mail_roles#:#to users with the following local roles###29 07 2022 new variable +mail#:#mail_roles#:#Az alábbi helyi szerepkörökkel bíró felhasználóknak mail#:#mail_s#:#levél mail#:#mail_salutation_anonymous#:#Tisztelt mail#:#mail_salutation_f#:#Tisztelt @@ -11672,21 +11738,21 @@ mail#:#mail_salutation_male#:#Üdvözlés {{MAIL_SALUTATION&rbrace mail#:#mail_salutation_n#:#Tisztelt mail#:#mail_saved#:#Az üzenetet mentette mail#:#mail_second_email#:#Másodlagos e-mail cím -mail#:#mail_sel_label#:#Choose the Recipients###29 07 2022 new variable +mail#:#mail_sel_label#:#Címzettek kiválasztása mail#:#mail_sel_users#:#Kiválasztott felhasználóknak levélküldés mail#:#mail_select_attachment#:#Válasszon egy mellékletet a letöltéshez! -mail#:#mail_select_crs#:#Please select at least one course.###26 08 2024 new variable -mail#:#mail_select_grp#:#Please select at least one group.###26 08 2024 new variable +mail#:#mail_select_crs#:#Legalább egy kurzust válasszon! +mail#:#mail_select_grp#:#Legalább egy csoportot válasszon! mail#:#mail_select_one_entry#:#Ki kell választania egy bejegyzést mail#:#mail_select_one_file#:#Ki kell választania egy fájlt mail#:#mail_send_html#:#Külső e-mailekhez HTML-keret -mail#:#mail_send_html_info#:#Ha be van kapcsolva, a külső e-mailek szövegrészét HTML-keretbe ágyazzuk. Ennek sablonja egyénre szabható a './Services/Mail/templates/default/tpl.html_mail_template.html' fájl './Customizing/global/skin/[SKIN]/Services/Mail/tpl.html_mail_template.html' fájlba másolásával. -mail#:#mail_sent_datetime#:#Date###26 08 2024 new variable +mail#:#mail_send_html_info#:#A külső e-mailek szövegrészét HTML-keretbe ágyazzuk. Ennek sablonja egyénre szabható a ‘./Services/Mail/templates/default/tpl.html_mail_template.html’ fájl ‘./Customizing/global/skin/[SKIN]/[STYLE]/Services/Mail/tpl.html_mail_template.html’ fájlba másolásával. +mail#:#mail_sent_datetime#:#Dátum mail#:#mail_serial_letter_placeholders#:#Körlevélhelyőrzők mail#:#mail_settings_external_frm_head#:#Külső levelek mail#:#mail_settings_external_tab#:#Külső mail#:#mail_settings_general_tab#:#Általános -mail#:#mail_settings_incoming_type_see_also#:#How incoming e-mails for users are handled can also be set here.###29 10 2025 new variable +mail#:#mail_settings_incoming_type_see_also#:#További lehetőséget a felhasználókhoz beérkező leveleinek módosítására itt talál. mail#:#mail_settings_system_frm_head#:#Rendszerlevelek mail#:#mail_settings_user_frm_head#:#Felhasználói levelek mail#:#mail_smtp_encryption#:#Titkosítás @@ -11699,38 +11765,38 @@ mail#:#mail_smtp_password_req#:#Ha hitelesítés céljából megad egy felhaszn mail#:#mail_smtp_port#:#Port mail#:#mail_smtp_port_info#:#Adja meg a levelezőszerver portját (például 25). mail#:#mail_smtp_status#:#Küldés SMTP-n keresztül -mail#:#mail_smtp_status_info#:#Ha be van kapcsolva, az ILIAS a PHP függvény (sendmail, mail() függvény) helyett SMTP szerveren keresztül küld külső leveleket. +mail#:#mail_smtp_status_info#:#Az ILIAS a PHP függvény (sendmail, mail() függvény) helyett SMTP szerveren keresztül küld külső leveleket. mail#:#mail_smtp_user#:#Felhasználó mail#:#mail_subject_prefix#:#Levél tárgya mail#:#mail_subject_prefix_info#:#Az automatikusan generált kimenő e-mailek tárgya elé kerülő szöveg, ami segíti, hogy a felhasználók szűrhessék az üzenetet. -mail#:#mail_subject_too_long#:#The subject is too long.###26 08 2024 new variable -mail#:#mail_success_removed_user#:#User(s) successfully removed from mailing list.###28 10 2024 new variable +mail#:#mail_subject_too_long#:#A tárgy túl hosszú. +mail#:#mail_success_removed_user#:#A felhasználó(ka)t sikeresen eltávolította a levelezési listáról. mail#:#mail_sure_delete_entry#:#Biztos, hogy törli az alábbi névjegy(ek)et? mail#:#mail_sure_delete_file#:#Biztos, hogy törli a kiválasztott fájlokat? -mail#:#mail_sure_delete_folder#:#A mappa és tartalma véglegesen el lesz távolítva. -mail#:#mail_sure_delete_p#:#Are you sure you want to delete the following mails?###29 10 2025 new variable -mail#:#mail_sure_delete_s#:#Are you sure you want to delete the following mail?###29 10 2025 new variable -mail#:#mail_sure_remove_user#:#Are you sure you want to remove the following user(s) from the members list?###28 10 2024 new variable +mail#:#mail_sure_delete_folder#:#A mappát annak tartalmával véglegesen eltávolítja. +mail#:#mail_sure_delete_p#:#Biztos, hogy törli a következő leveleket? +mail#:#mail_sure_delete_s#:#Biztos, hogy törli a következő levelet? +mail#:#mail_sure_remove_user#:#Biztos, hogy eltávolítja a felhasználó(ka)t a levelezési listáról? mail#:#mail_system_sys_env_from_addr#:#Technikai feladó mail#:#mail_system_sys_env_from_addr_info#:#Üres mező esetén a feladó e-mail címét használjuk, ha az SMTP be van kapcsolva. Különben a szerver rendszergazdájának a feladta beállítani ezt az értéket. mail#:#mail_system_sys_from_addr#:#Küldő e-mail címe (feladó) -mail#:#mail_system_sys_from_addr_info#:#Adja meg a 'Feladó' részbe szánt e-mail címet. A 'Feladó' rész a küldőt jeleníti meg a címzett e-mail kliensénél.

    Példa: info@intezmeny.hu vagy no-reply@intezmeny.hu/span> +mail#:#mail_system_sys_from_addr_info#:#Adja meg a ‘Feladó’ részbe szánt e-mail címet. A ‘Feladó’ rész a küldőt jeleníti meg a címzett e-mail kliensénél.

    Példa: info@intezmeny.hu vagy no-reply@intezmeny.hu/span> mail#:#mail_system_sys_from_name#:#Küldő teljes neve (feladó) -mail#:#mail_system_sys_general_signature#:#Signature###26 08 2024 new variable +mail#:#mail_system_sys_general_signature#:#Aláírás mail#:#mail_system_sys_reply_to_addr#:#Válaszcím mail#:#mail_system_usr_env_from_addr#:#Technikai feladó mail#:#mail_system_usr_env_from_addr_info#:#Üres mező esetén a feladó e-mail címét használjuk, ha az SMTP be van kapcsolva. Különben a szerver rendszergazdájának a feladta beállítani ezt az értéket. mail#:#mail_system_usr_from_addr#:#Küldő e-mail címe (feladó) -mail#:#mail_system_usr_from_addr_info#:#Adja meg a 'Feladó' részbe szánt e-mail címet. A 'Feladó' rész a küldőt jeleníti meg a címzett e-mail kliensénél. Az ILIAS-on keresztül e-mailt küldő felhasználó e-mail címét automatikusan betesszük a 'Válasz' részbe.

    Példa: info@intezmeny.hu vagy no-reply@intezmeny.hu/span> +mail#:#mail_system_usr_from_addr_info#:#Adja meg a ‘Feladó’ részbe szánt e-mail címet. A ‘Feladó’ rész a küldőt jeleníti meg a címzett e-mail kliensénél. Az ILIAS-on keresztül e-mailt küldő felhasználó e-mail címét automatikusan betesszük a ‘Válasz’ részbe.

    Példa: info@intezmeny.hu vagy no-reply@intezmeny.hu/span> mail#:#mail_system_usr_from_name#:#Küldő teljes neve (feladó) -mail#:#mail_system_usr_from_name_info#:#A [FULLNAME], [FIRSTNAME] és [LASTNAME] helyőrzőket használhatja, melyeket személy megfelelő adatára cseréljünk. -mail#:#mail_system_usr_general_signature#:#User Signature###26 08 2024 new variable +mail#:#mail_system_usr_from_name_info#:#A {{FULLNAME}}, {{FIRSTNAME}} és {{LASTNAME}} helyőrzőket használhatja, melyeket személy megfelelő adatára cseréljünk. +mail#:#mail_system_usr_general_signature#:#Felhasználó aláírása mail#:#mail_tbl_head_attachments#:#Csatolmány mail#:#mail_template_client#:#Szövegminta mail#:#mail_template_client_info#:#Válasszon egyet ez elérhető szövegminták közül, és használja annak helyőrzőit. Amikor egy szövegmintát választ, űrlapjának szövegében és tárgyában lévő helyőrzőket lecseréljük (ha azok léteznek a szövegmintában). mail#:#mail_template_context#:#Szövegkörnyezet mail#:#mail_template_default#:# (Alapértelmezett) -mail#:#mail_template_invalid_tpl_syntax#:#An invalid syntax has been detected. Please ensure a valid input, especially regarding the placeholder syntax.###26 08 2024 new variable +mail#:#mail_template_invalid_tpl_syntax#:#Szintaktikai hiba: ellenőrizze a bemenet érvénysségét, különösen a helyőrzőket. mail#:#mail_template_missing_id#:#Nem futtatható a művelet, mert hiányzik a szövegminta azonosítója. mail#:#mail_template_no_context_available#:#Egy ILIAS szolgáltatás, illetve modul által biztosított szövegkörnyezet sincs, ezért nem lehetséges szövegmintát sem létrehozni, sem szerkeszteni. mail#:#mail_template_no_valid_context#:#A megadott szövegkörnyezet nem érvényes. @@ -11740,44 +11806,46 @@ mail#:#mail_template_title#:#Megnevezés mail#:#mail_template_unset_as_default#:#Ne legyen ez az alapértelmezett mail#:#mail_templates#:#Szövegminták mail#:#mail_threshold#:#Küszöb -mail#:#mail_threshold_info#:#A küszöb értékénél régebbi belső leveleket (mellékleteikkel együtt) végérvényesen töröljük.
    Ezen ütemezett feladat első futásakor sok üzenetet törlünk, ezért figyelmeztető levél küldése nem lehetséges. +mail#:#mail_threshold_info#:#A küszöb értékénél régebbi belső leveleket (mellékleteikkel együtt) végérvényesen töröljük.
    Ezen ütemezett feladat első futásakor sok üzenetet törlünk, ezért figyelmeztető levél küldése nem lehetséges. mail#:#mail_to#:#Címzett mail#:#mail_tpl_deleted_p#:#Szövegmintákat sikeresen törölte. mail#:#mail_tpl_deleted_s#:#Szövegmintát sikeresen törölte. mail#:#mail_tpl_sure_delete_entries#:#Biztos, hogy törli a következő bejegyzéseket? mail#:#mail_tpl_sure_delete_entry#:#Biztos, hogy törli a szövegmintát? -mail#:#mail_use_global_reply_to_addr#:#Use Global Reply-To###XXX -mail#:#mail_use_global_reply_to_addr_info#:#If enabled, the email address entered below is used as value for the 'Reply-To' header. The sender's email address will be not disclosed to recipients. A direct reply is not possible anymore. +mail#:#mail_use_global_reply_to_addr#:#A globális válaszcím használata +mail#:#mail_use_global_reply_to_addr_info#:#Ha bekapcsolja, az itt beállított e-mail cím kerül a ‘Reply-To’ fejlécbe. A küldő e-mail címe nem jut el a címzettekhez, így arra válaszolni sem tudnak. mail#:#nc_mail_noti_item_title#:#Beérkezett üzenetek mail#:#nc_mail_prop_time#:#Időpont -mail#:#nc_mail_unread_messages#:#%s levele van a Beérkezett üzenetekben. -mail#:#nc_mail_unread_messages_number_p#:#%s olvasatlan levele van -mail#:#nc_mail_unread_messages_number_s#:#1 olvasatlan levele van +mail#:#nc_mail_unread_messages#:#%s van +mail#:#nc_mail_unread_messages_number_p#:#%s olvasatlan levele +mail#:#nc_mail_unread_messages_number_s#:#1 olvasatlan levele mail#:#only_inbox_trash#:#Csak Beérkező / Kuka -mail#:#only_inbox_trash_info#:#Ha be van kapcsolva, csak a Beérkező levelekben és a Kukában lévőket töröljük. Különben mappától függetlenül töröljük a leveleket. +mail#:#only_inbox_trash_info#:#Csak a Beérkező levelekben és a Kukában lévőket töröljük. Különben mappától függetlenül töröljük a leveleket. mail#:#orphaned_mail_body#:#Az alábbi levelezési fiókokban régi vagy gazdátlan levelek hevernek. Ezeket a leveleket automatikus töröljük hamarosan. mail#:#orphaned_mail_subject#:#Értesítés gazdátlan levelekről -mail#:#placeholders_advise#:#A címzettek személyes helyőrzőit csak a Címzett mezőben oldjuk fel.%sA Másolat (CC) és a Titkos másolat (BCC) mezőkben levőket nem módosítjuk. +mail#:#placeholders_advise#:#Csak a Címzett mezőben lévő felhasználók helyőrzőit oldjuk fel, %s a Másolat (CC) és a Titkos másolat (BCC) mezőkben lévőkét nem, azok helyőrzők maradnak. +mail#:#regular_mail#:#Személyes levél mail#:#search_content#:#Keresés eredménye mail#:#search_recipients#:#Címzettek keresése mail#:#second_email_missing_info#:#Ez a kiválasztás nem lehetséges, mert nincs megadva másodlagos e-mail cím. -mail#:#select_mail_with_subject_x#:#Select mail with subject „%s“###26 08 2024 new variable +mail#:#select_mail_with_subject_x#:#‘%s’ tárgyú levél kiválasztása mail#:#send_mail_admins#:#Összes vezető mail#:#send_mail_members#:#Összes tag mail#:#send_mail_to#:#Címzettek közé mail#:#send_mail_tutors#:#Összes tutor +mail#:#serial_letter#:#Körlevél mail#:#show_mail_settings#:#Levelezési beállítások megjelenítése -mail#:#show_mail_settings_info#:#Ha be van kapcsolva, a felhasználók 'Levelezési beállítások' elérhető a 'Személyes beállítások' vagy a 'Levelezés' részben. +mail#:#show_mail_settings_info#:#A ‘Levelezési beállítások’ elérhető a ‘Személyes beállítások’ vagy a ‘Levelezés’ részben. Ennek módosíthatósága függ a jogosultsági beállításoktól. mail#:#system_notification_installation_changed_by#:#Módosította -mail#:#usrFieldChange_second_mail_visible_in_personal_data#:#You have changed the attribute "%s" of the field "%s".
    This leads to all accounts settings being reset to "receive on primary address" for external delivery,
    not only for all new accounts but also dismissing the currently active settings made by users.###29 07 2022 new variable -maps#:#configure_geolocation#:#A címkeresés bekapcsolásához fejezze be a helymeghatározó beállítását a 'Rendszerbeállítások' » 'Harmadik fél szoftvere' alatt. -maps#:#maps_custom_geolocation_server_info#:#Szerver URL helymeghatározási adatok Nominatim használatával történő meghatározásához. Az URL-ben a kért hely információjának helyőrzője a [QUERY]. Például: nominatim.example.com/search/[QUERY]?format=json. -maps#:#maps_custom_tile_server_info#:#Szerver URL csempeadatok meghatározásához. Több URL-t szóközzel válasszon el. Alapértelmezett értéke '%s'. +mail#:#usrFieldChange_second_mail_visible_in_personal_data#:#A ‘%s’ attribútumot (‘%s’ mező) módosította.
    Ez azt eredményezi, hogy az összes fiók beállítása visszaáll az ‘Elsődleges címre történő fogadás’ értékre külső kézbesítésnél,
    nemcsak az új fiók esetében, hanem a felhasználók jelenleg beállításait is felülírjuk. +maps#:#configure_geolocation#:#A címkeresés bekapcsolásához fejezze be a helymeghatározó beállítását a ‘Rendszerbeállítások’ » ‘Harmadik fél szoftvere’ alatt. +maps#:#maps_custom_geolocation_server_info#:#Szerver URL helymeghatározási adatok Nominatim használatával történő meghatározásához. Az URL-ben a kért hely információjának helyőrzője a [QUERY]. Például: https://nominatim.example.com/search/[QUERY]?format=json. +maps#:#maps_custom_tile_server_info#:#Szerver URL csempeadatok meghatározásához. Több URL-t szóközzel válasszon el. Alapértelmezett értéke ‘%s’. maps#:#maps_enable_maps#:#Térképek engedélyezése maps#:#maps_enable_maps_info#:#Térképek engedélyezése felhasználói adatokban, csoportokban és kurzusokban. maps#:#maps_geolocation_server#:#Fordított helymeghatározáshoz szerver maps#:#maps_google_maps#:#Google-térképek -maps#:#maps_https_for_reverse_lookup#:#Https for Reverse Lookup###29 07 2022 new variable +maps#:#maps_https_for_reverse_lookup#:#Https a Reverse Lookup-hoz maps#:#maps_latitude#:#Földrajzi szélesség maps#:#maps_longitude#:#Földrajzi hosszúság maps#:#maps_lookup_address#:#Címkeresés @@ -11789,42 +11857,42 @@ maps#:#maps_std_location_desc#:#Kattintson a térképre a hely beállításához maps#:#maps_tile_server#:#Csempékhez szerver maps#:#maps_zoom_level#:#Nagyítás szintje mcst#:#mcst_add_new_item#:#Új médiasugárzás-objektum létrehozása -mcst#:#mcst_audio_files#:#Audio Files###29 07 2022 new variable +mcst#:#mcst_audio_files#:#Hangfájl mcst#:#mcst_audioportable_settings_info#:#Fájlkiterjesztések vesszővel elválasztott felsorolása mcst#:#mcst_audioportable_settings_title#:#Hangformátumok fájlkiterjesztési mcst#:#mcst_audioportable_title#:#További hangfájl hordozható eszközökhöz mcst#:#mcst_automatic_detection#:#Automatikus felismerés -mcst#:#mcst_autoplay#:#Autoplay###29 07 2022 new variable -mcst#:#mcst_autoplay_active#:#Autoplay (Default on)###29 07 2022 new variable -mcst#:#mcst_autoplay_inactive#:#Autoplay (Default off)###29 07 2022 new variable -mcst#:#mcst_autoplay_info#:#Starts automatically the next video when reaching the end of the previous one. This feature is not supported by youtube videos.###26 08 2024 new variable +mcst#:#mcst_autoplay#:#Autoplay +mcst#:#mcst_autoplay_active#:#Autoplay (Alapértelmezetten be) +mcst#:#mcst_autoplay_inactive#:#Autoplay (Alapértelmezetten ki) +mcst#:#mcst_autoplay_info#:#A videó automatikusan indul az előző befejezésekor. Youtube videók ezt nem támogatják. mcst#:#mcst_clear_purpose_title#:#Törlés -mcst#:#mcst_confirm_deletion#:#Confirm Deletion###26 08 2024 new variable +mcst#:#mcst_confirm_deletion#:#Törlés megerősítése mcst#:#mcst_converted_file#:#A fájlt konvertáltuk. mcst#:#mcst_copy#:#Médiasugárzás másolása mcst#:#mcst_current_value_info#:#Ezen formátum aktuális értékének megjelenítése mcst#:#mcst_default_visibility#:#Alapértelmezett elérés mcst#:#mcst_det_playtime#:#Lejátszási idő meghatározása -mcst#:#mcst_download_all#:#Download All###29 07 2022 new variable +mcst#:#mcst_download_all#:#Összes letöltése mcst#:#mcst_download_audioportable#:#Hangfájl letöltése mcst#:#mcst_download_cnt#:#Letöltve mcst#:#mcst_download_standard#:#Letöltés -mcst#:#mcst_download_started_bg#:#Download of files has started. Please check your background tasks in the top right corner.###29 07 2022 new variable +mcst#:#mcst_download_started_bg#:#A fájlok letöltése megkezdődött. Ellenőrizze a jobb felső sarokban a háttérfolyamatoknál. mcst#:#mcst_download_videoalternative#:#Alternatív fájl leöltése mcst#:#mcst_download_videoportable#:#Videófájl letöltése mcst#:#mcst_downloadable#:#Letöltési linkek -mcst#:#mcst_downloadable_info#:#Ha be van kapcsolva, linkek jelennek meg letöltéshez. +mcst#:#mcst_downloadable_info#:#Linkek jelennek meg a letöltéshez. mcst#:#mcst_duration#:#Lejátszási idő -mcst#:#mcst_duration_info#:#Ha nincs megadva érték, az ILIAS automatikusan megpróbálja meghatározni a lejátszási időt. +mcst#:#mcst_duration_info#:#Ha 00:00:00 az érték, kérem, módosítsa, mert az ILIAS automatikusan nem tudja meghatározni a lejátszási időt. mcst#:#mcst_edit_item#:#Médiasugárzás-objektum módosítása mcst#:#mcst_edit_settings#:#Médiasugárzás beállítások mcst#:#mcst_gallery#:#Csempék -mcst#:#mcst_img_gallery#:#Image Gallery###29 07 2022 new variable +mcst#:#mcst_img_gallery#:#Képgalléria mcst#:#mcst_import#:#Médiasugárzás importálása mcst#:#mcst_incl_files_in_rss#:#A médiafájlokat is beleértve csatolmányként -mcst#:#mcst_incl_files_in_rss_info#:#Ha be van kapcsolva, a médiafájlok csatolásként kerülnek be az RSS-csatornába. Máskülönben a csatorna csak értesíti a feliratkozottat az új objektumról. +mcst#:#mcst_incl_files_in_rss_info#:#A médiafájlok csatolásként kerülnek be az RSS-csatornába. Máskülönben a csatorna csak értesíti a feliratkozottat az új objektumról. mcst#:#mcst_input_either_file_or_url#:#Adjon meg egy fájlt vagy URL-t. Fájl esetén figyeljen a feltölthető maximális méretre. -mcst#:#mcst_items#:#Items###26 08 2024 new variable +mcst#:#mcst_items#:#Elemek mcst#:#mcst_last_submission#:#Utolsó elküldés mcst#:#mcst_list#:#Lista mcst#:#mcst_manage#:#Kezelés @@ -11835,48 +11903,48 @@ mcst#:#mcst_mimetype#:#MIME-típus mcst#:#mcst_mimetype_info#:# MIME-típus kiválasztása a visszajátszáshoz használt bővítmény vezérléséhez.
    Ne feledje: Legyen körültekintő, mert előfordulhat, hogy nem minden böngésző tartalmazza a használni kívánt bővítményt. mcst#:#mcst_mimetypes#:#MIME-típusok mcst#:#mcst_mimetypes_info#:#MIME-típusok vesszővel elválasztott felsorolása -mcst#:#mcst_new_items_det_lp#:#Add new items to learning progress###29 07 2022 new variable -mcst#:#mcst_new_items_det_lp_info#:#New items are automatically added to determine the overall learning progress.###29 07 2022 new variable +mcst#:#mcst_new_items_det_lp#:#Az új elem hozzáadása a tanulási haladáshoz +mcst#:#mcst_new_items_det_lp_info#:#Az új elemek automatikusan bekerülnek a tanulási haladásban. mcst#:#mcst_news_item_visibility_info#:#A nyilvános hírek bejelentkezés nélkül is elérhetők az ILIAS-on kívülről RSS-en keresztül. Ne tegyen bele bizalmas információkat! -mcst#:#mcst_next_items#:#Next Items###29 07 2022 new variable -mcst#:#mcst_no_autoplay#:#No Autoplay###29 07 2022 new variable +mcst#:#mcst_next_items#:#Következő elemek +mcst#:#mcst_no_autoplay#:#Nincs Autoplay mcst#:#mcst_nr_items#:#Objektumok száma -mcst#:#mcst_nr_videos#:#Number of Initial Videos###29 07 2022 new variable -mcst#:#mcst_ordering#:#Válogatás -mcst#:#mcst_ordering_creation_date_asc#:#Létrehozási dátum szerint (növekvő) -mcst#:#mcst_ordering_creation_date_desc#:#Létrehozási dátum szerint (csökkenő) +mcst#:#mcst_nr_videos#:#Kiinduló videók száma +mcst#:#mcst_ordering#:#Rendezés +mcst#:#mcst_ordering_creation_date_asc#:#Létrehozási dátum szerint ↑ +mcst#:#mcst_ordering_creation_date_desc#:#Létrehozási dátum szerint ↓ mcst#:#mcst_ordering_manual#:#Kézi mcst#:#mcst_ordering_title#:#Cím szerint mcst#:#mcst_play#:#Lejátszás mcst#:#mcst_play_cnt#:#Lejátszva mcst#:#mcst_play_time#:#Lejátszási idő -mcst#:#mcst_podcast#:#Podcast###29 07 2022 new variable -mcst#:#mcst_prev_items#:#Previous Items###29 07 2022 new variable -mcst#:#mcst_preview#:#Preview###26 08 2024 new variable -mcst#:#mcst_preview_picture#:#Kép előnézete -mcst#:#mcst_preview_picture_info#:#Csak az alábbi fő médiatípusokkal támogatott: +mcst#:#mcst_podcast#:#Podcast +mcst#:#mcst_prev_items#:#Előző elemek +mcst#:#mcst_preview#:#Előnézet +mcst#:#mcst_preview_picture#:#Előkép +mcst#:#mcst_preview_picture_info#:#Csak az alábbi fő médiatípusoknál támogatott: mcst#:#mcst_reference_info#:#URL a forráshoz mcst#:#mcst_save_order#:#Sorrend mentése mcst#:#mcst_set_playtime#:#A lejátszási időt sikeresen beállította. mcst#:#mcst_settings#:#Médiasugárzás beállítások -mcst#:#mcst_show_description#:#Show Description###29 07 2022 new variable +mcst#:#mcst_show_description#:#Leírás megjelenítése mcst#:#mcst_standard_settings_info#:#Fájlkiterjesztések vesszővel elválasztott felsorolása mcst#:#mcst_standard_settings_title#:#Általános formátumok fájlkiterjesztései mcst#:#mcst_standard_title#:#Normál médiafájl mcst#:#mcst_unable_to_determin_playtime#:#Nem lehet megállapítani a lejátszási időt. Állítsa be kézzel a szerkesztésre kattintva. -mcst#:#mcst_video_cast#:#Videocast###29 07 2022 new variable -mcst#:#mcst_video_completion_threshold#:#Video Completion Threshold###29 07 2022 new variable -mcst#:#mcst_video_completion_threshold_info#:#Amount of video that triggers the completion status. Please note that the user may skip forward to reach this point.###29 07 2022 new variable +mcst#:#mcst_video_cast#:#Videocast +mcst#:#mcst_video_completion_threshold#:#Video teljesítésének küszöbértéke +mcst#:#mcst_video_completion_threshold_info#:#A sikeresen teljesített állapot küszöbértéke. Kérjük, vegye figyelembe, hogy a felhasználók a videóban előreugrással is elérhetik ezt az értéket. mcst#:#mcst_videoalternative_title#:#Alternatív videófájl (böngészőben történő lejátszáshoz) mcst#:#mcst_videoportable_settings_info#:#Fájlkiterjesztések vesszővel elválasztott felsorolása mcst#:#mcst_videoportable_settings_title#:#Videóformátumok fájlkiterjesztései mcst#:#mcst_videoportable_title#:#További videófájl hordozható eszközökhöz -mcst#:#mcst_view_abandoned#:#The current presentation mode has been abandoned. Please open the settings and switch to another mode.###29 07 2022 new variable +mcst#:#mcst_view_abandoned#:#A beállított megjelenítési mód már nem támogatott, a beállításokban válasszon másikat. mcst#:#mcst_viewmode#:#Megjelenítés módja mcst#:#mcst_visibility_info#:#Nyilvános tételek elérhetők RSS-en keresztül hitelesítés nélkül. mcst#:#mcst_visibility_public#:#Nyilvános mcst#:#mcst_visibility_users#:#Bejelentkezett felhasználók -mcst#:#mcst_watched#:#watched###29 07 2022 new variable +mcst#:#mcst_watched#:#megtekintve mcst#:#mcst_webfeed#:#RSS Web hírcsatorna mem#:#mem_period_without_time#:#Időjelzés nélkül mem#:#mem_print_view_form#:#Nyomtatási nézet alapértelmezett beállításai @@ -11895,8 +11963,9 @@ mep#:#mep_all_mobs#:#Összes médiaobjektum mep#:#mep_bulk_upload#:#Tömeges feltöltés mep#:#mep_choose_from_folder#:#Válasszon a mappából mep#:#mep_choose_from_mep#:#Válasszon a gyűjteményből +mep#:#mep_clipboard_info#:#Ide feltölthet médiafájlokat, amelyeket bármely szerkeszthető oldalra beilleszthet. A vágólap a médiagyűjteményekben is elérhető. Ez a tároló csak az öné, azaz más felhasználók nem tekintheti meg a tartalmát. mep#:#mep_content#:#Tartalom -mep#:#mep_content_snippet_in_use#:#'%s' tartalom-építőelem használatban van, nem törölhető. +mep#:#mep_content_snippet_in_use#:#‘%s’ tartalom-építőelem használatban van, nem törölhető. mep#:#mep_content_snippet_used_in_older_versions#:#Ne feledje: néhány lap régebbi verziója használja ezt az építőelemet. Ha ezeket a lapokat visszaállítják egy olyan verzióra, amely tartalmazza ezt az építőelemet, az építőelem hiányozni fog a lapról. mep#:#mep_copy_to_mep#:#Másolás a médiagyűjteménybe mep#:#mep_create_content_snippet#:#Tartalom-építőelem létrehozása @@ -11914,38 +11983,38 @@ mep#:#mep_format#:#Formátum mep#:#mep_import#:#Médiagyűjtemény importálása mep#:#mep_import_lang#:#Célnyelv mep#:#mep_import_trans#:#Fordítás importálása -mep#:#mep_master_language_only#:#Fordításhoz mesternyelv -mep#:#mep_master_language_only_no_media#:#Mesternyelv média nélkül +mep#:#mep_master_language_only#:#Fordításhoz főnyelv +mep#:#mep_master_language_only_no_media#:#Főnyelv, média nélkül mep#:#mep_media_files#:#Mediafájlok mep#:#mep_media_subtitles#:#Feliratok mep#:#mep_mob#:#Mediaobjektum -mep#:#mep_move_select_insert#:#Navigate to target folder and click "Insert"###26 08 2024 new variable -mep#:#mep_mpg#:#Content Snippet###29 07 2022 new variable +mep#:#mep_move_select_insert#:#Navigáljon a célmappába és kattintson a ‘Beillesztés’-re +mep#:#mep_mpg#:#Tartalom-építőelem mep#:#mep_new_content_snippet#:#Új tartalom-építőelem mep#:#mep_new_folder#:#Új mappa mep#:#mep_page_properties#:#Laptulajdonságok mep#:#mep_page_type_mep#:#Tartalom-építőelem mep#:#mep_thumbnail#:#Bélyegkép mep#:#mep_title_and_description#:#Cím és leírás -mep#:#mep_trans_import_info#:#Ha ezt a modult 'XML/Fordításhoz mesternyelv'-ként exportálta egy másik telepítésbe, akkor most újra importálhatja a lefordított exportfájlokat innen a második telepítésből. +mep#:#mep_trans_import_info#:#Ha ezt a modult ‘XML/Fordításhoz mesternyelv’-ként exportálta egy másik telepítésbe, akkor most újra importálhatja a lefordított exportfájlokat innen a második telepítésből. mep#:#mep_unknown#:#Nem ismert mep#:#mep_up_dir_copy#:#Fájlok másolása a feltöltő mappából (a fájlokat a feltöltő mappában tartja) mep#:#mep_up_dir_move#:#Mozifájlok feltöltő mappából (gyorsabb) mep#:#mep_upload_dir_files#:#Fájlok feltöltési mappából mep#:#mobs_activate_pages#:#Tartalom-építőelemek használata -mep#:#mobs_activate_pages_info#:#Tartalom-építőelemek létrehozásának engedélyezése médiagyűjteményekben. Ezen építőelemek többször felhasználhatóak tananyagokban (de ott nem szerkeszthetőek). +mep#:#mobs_activate_pages_info#:#Tartalom-építőelemek létrehozásának engedélyezése médiagyűjteményekben. Ezen építőelemek többször felhasználhatók tananyagokban (de ott nem szerkeszthetőek). mep#:#mobs_always_show_file_manager#:#Mindig látszódjon a fájlkezelő mep#:#mobs_always_show_file_manager_info#:#Ha nincs bekapcsolva, a médiaobjektumok fájlkezelője el lesz rejtve az egyszerű MIME-típusok (például képek) esetén. mep#:#mobs_black_list_file_types#:#Tiltott fájltípusok -mep#:#mobs_black_list_file_types_and_allowed_info#:#Enter a comma separated list of mime types. This list will restrict the set of allowed file types. Currently allowed mime types are:###26 08 2024 new variable +mep#:#mobs_black_list_file_types_and_allowed_info#:#Ez a felsorolás korlátozza az engedélyezett fájltípusokat. Adja meg a mime-típusokat vesszővel elválasztva (például text/html, application/pdf). A jelenleg engedélyzett mime-típusok: mep#:#mobs_restrict_file_types#:#Engedélyezett fájltípusok mep#:#mobs_restrict_file_types_info#:#Adja meg a médiaobjektumokba feltölthető fájlok kiterjesztésének (például jpg, gif) vesszővel elválasztott listáját. Ha nem ad meg értéket, minden fájltípus feltölthető. -meta#:#adt_error_max_length#:#Kérem, rövidebb szöveget írjon. -meta#:#md_adn_int_error_no_default#:#Please select on activated language als "Default-Language". +meta#:#adt_error_max_length#:#A beírt szöveg túl hosszú, kérem, írjon rövidebbet. +meta#:#md_adn_int_error_no_default#:#Állítson be egy nyelvet ‘Alapértelmezett nyelv’-nek. meta#:#md_adv_active#:#Aktív -meta#:#md_adv_added_new_record#:#Hozzáadott új adatcsoport +meta#:#md_adv_added_new_record#:#Az új adatcsoport sikeresen hozzáadta. meta#:#md_adv_col_presentation_ordering#:#Pozíció -meta#:#md_adv_confirm_definition#:#Kérem, hagyja jóvá az új definíció beállításait. +meta#:#md_adv_confirm_definition#:#Kérem, hagyja jóvá az új beállításokat. meta#:#md_adv_confirm_definition_select_option#:#Törölt opció meta#:#md_adv_confirm_definition_select_option_all#:#Összes bejegyzése kezelése ugyanúgy meta#:#md_adv_confirm_definition_select_option_all_action#:#Új érték @@ -11955,162 +12024,162 @@ meta#:#md_adv_confirm_definition_select_option_single#:#Döntéshozatal bejegyz meta#:#md_adv_confirm_definition_select_section#:#Törölt opciók migrációja meta#:#md_adv_create_field#:#Új mező meta#:#md_adv_create_record#:#Új adatcsoport -meta#:#md_adv_delete_fields_sure#:#Biztos, hogy törli az alábbi meződefiníciókat? -meta#:#md_adv_delete_files_sure#:#Biztos, hogy törli az alábbi exportfájlokat? -meta#:#md_adv_delete_record_sure#:#Biztos, hogy törli az alábbi adatcsoportokat? -meta#:#md_adv_deleted_fields#:#A mezőket már törölték. -meta#:#md_adv_deleted_files#:#Törölt exportfájlok -meta#:#md_adv_deleted_records#:#Törölt adatcsoportok +meta#:#md_adv_delete_fields_sure#:#Biztos, hogy törli az alábbi meződefiníció(ka)t? +meta#:#md_adv_delete_files_sure#:#Biztos, hogy törli az alábbi exportfájl(oka)t? +meta#:#md_adv_delete_record_sure#:#Biztos, hogy törli az alábbi adatcsoporto(ka)t? +meta#:#md_adv_deleted_fields#:#A mező(ke)t sikeresen törölte. +meta#:#md_adv_deleted_files#:#Az exportfájl(oka)t sikeresen törölte. +meta#:#md_adv_deleted_records#:#Az adatcsoporto(ka)t sikeresen törölte. meta#:#md_adv_desc_show#:#Leírás megjelenítése meta#:#md_adv_edit_complex_option#:#Tulajdonságok módosítása meta#:#md_adv_edit_field#:#Mező módosítása meta#:#md_adv_edit_record#:#Adatcsoport módosítása meta#:#md_adv_field_fields#:#Mezők -meta#:#md_adv_field_filter_warning#:#%s mezőtípusok jelenleg nem használhatóak táblaszűrőként. -meta#:#md_adv_field_list#:#Fields###XXX +meta#:#md_adv_field_filter_warning#:#%s mezőtípusok jelenleg nem használhatók táblaszűrőként. +meta#:#md_adv_field_list#:#Mezők meta#:#md_adv_field_names#:#Mezőnevek meta#:#md_adv_field_table#:#Mezők módosítása meta#:#md_adv_fields_show#:#Mezőnevek megjelenítése meta#:#md_adv_file_list#:#Exportfájlok meta#:#md_adv_import_record#:#Metaadatcsoport importálása -meta#:#md_adv_int_current#:#Current Language: -meta#:#md_adv_int_default#:#Default Language: -meta#:#md_adv_int_translation_info#:#Translation: -meta#:#md_adv_no_fields#:#Nincsenek mezők definiálva -meta#:#md_adv_number_decimals#:#Tizedes tört +meta#:#md_adv_int_current#:#Jelenlegi nyelv: +meta#:#md_adv_int_default#:#Alapértelmezett nyelv: +meta#:#md_adv_int_translation_info#:#Fordítás: +meta#:#md_adv_no_fields#:#Ennek az adatcsoportnak még egy mezője sincs. +meta#:#md_adv_number_decimals#:#Tizedes helyek meta#:#md_adv_number_max#:#Maximális érték meta#:#md_adv_number_min#:#Minimális érték meta#:#md_adv_number_suffix#:#Utótag (Suffix) -meta#:#md_adv_presentation#:#Megjelenítés -meta#:#md_adv_record_activate_languages#:#Activate Languages +meta#:#md_adv_presentation#:#Megjelenítési beállítások +meta#:#md_adv_record_activate_languages#:#Nyelvek aktiválása meta#:#md_adv_record_list#:#Adatcsoportok -meta#:#md_adv_record_lng_table#:#Language Managment -meta#:#md_adv_record_lng_table_active#:#Active -meta#:#md_adv_record_lng_table_default#:#Default -meta#:#md_adv_record_lng_table_inst#:#Installed -meta#:#md_adv_record_lng_table_lng#:#Language +meta#:#md_adv_record_lng_table#:#Nyelvkezelés +meta#:#md_adv_record_lng_table_active#:#Aktív +meta#:#md_adv_record_lng_table_default#:#Alapértelmezett +meta#:#md_adv_record_lng_table_inst#:#Telepített +meta#:#md_adv_record_lng_table_lng#:#Nyelv meta#:#md_adv_records#:#Magába foglalt rekordok -meta#:#md_adv_records_exported#:#Egy új exportfájl jött létre. +meta#:#md_adv_records_exported#:#Az új exportfájl(ok) sikeresen létrejött(ek). meta#:#md_adv_scope#:#Hatókör -meta#:#md_adv_scope_info#:#Usage of this custom metadata set will be limited to selected parts of the repository.###26 08 2024 new variable +meta#:#md_adv_scope_info#:#Ennek az egyéni metaadat-készletnek a használata a tartalomtár kiválasztott részeire korlátozódik. meta#:#md_adv_scope_list_header#:#Korlátozva erre: -meta#:#md_adv_scope_objects#:#Data Set Effective From###26 08 2024 new variable +meta#:#md_adv_scope_objects#:#Az adatkészlet hatályos ekkortól: meta#:#md_adv_searchable#:#Kereshető -meta#:#md_adv_select_one_file#:#Válasszon ki egy fájlt! +meta#:#md_adv_select_one_file#:#Csak egy fáljt válasszon! meta#:#md_adv_show#:#Megjelenítés -meta#:#md_adv_substitution_table#:#Találatok a Tartalomtárban +meta#:#md_adv_substitution_table#:#Egyéni metaadatok megjelenítési beállításai a Tartalomtárban meta#:#md_adv_text_max_length#:#Maximális hossz meta#:#md_adv_text_multi#:#Többsoros -meta#:#md_adv_text_multi_val#:#Multilingual Values###26 08 2024 new variable -meta#:#md_adv_text_multi_val_info#:#Allow multilingual field values for this data field. Deactivating this option is recommended for texts that do not need translating, such as personal names.###26 08 2024 new variable +meta#:#md_adv_text_multi_val#:#Többnyelvű értékek +meta#:#md_adv_text_multi_val_info#:#Többnyelvű mezőértékek engedélyezése ehhez az adatmezőhöz. Ennek az opciónak a kikapcsolása olyan szövegeknél javasolt, amelyeket nem kell fordítani, mint például a személynevek. meta#:#md_advanced#:#Egyéni metaadatok -meta#:#md_aria_language_selection#:#Language Selection +meta#:#md_aria_language_selection#:#Nyelv választása meta#:#md_copyright#:#Szerzői jog -meta#:#md_copyright_add#:#Alapértelmezett szerzői jog hozzáadása -meta#:#md_copyright_admin_tab#:#Copyright & OER###28 10 2024 new variable -meta#:#md_copyright_alt_text#:#Text Representation###26 08 2024 new variable -meta#:#md_copyright_alt_text_info#:#Used for image ‘alt’ attribute###26 08 2024 new variable -meta#:#md_copyright_default#:#Default###26 08 2024 new variable +meta#:#md_copyright_add#:#Új szerzői jog hozzáadása +meta#:#md_copyright_admin_tab#:#Szerzői jog & NyOE +meta#:#md_copyright_alt_text#:#Szöveges alternatíva +meta#:#md_copyright_alt_text_info#:#A kép ‘alt’ attribútuma +meta#:#md_copyright_default#:#Alapértelmezett meta#:#md_copyright_edit#:#Alapértelmezett szerzői jog módosítása meta#:#md_copyright_enable_info#:#Válassza ezt az opciót előre meghatározott szerzői jogok ajánlására. meta#:#md_copyright_enabled#:#Szerzői jog kiválasztásának engedélyezése -meta#:#md_copyright_full_name#:#Full Name###26 08 2024 new variable -meta#:#md_copyright_image#:#Image###26 08 2024 new variable -meta#:#md_copyright_image_file#:#File###26 08 2024 new variable -meta#:#md_copyright_image_is_file#:#Upload File###26 08 2024 new variable -meta#:#md_copyright_image_is_link#:#Enter URL###26 08 2024 new variable -meta#:#md_copyright_image_link#:#URL###26 08 2024 new variable -meta#:#md_copyright_link#:#URL###26 08 2024 new variable -meta#:#md_copyright_link_info#:#Link to the licence###26 08 2024 new variable +meta#:#md_copyright_full_name#:#Teljes név +meta#:#md_copyright_image#:#Kép +meta#:#md_copyright_image_file#:#Fájl +meta#:#md_copyright_image_is_file#:#Fájl feltöltése +meta#:#md_copyright_image_is_link#:#Add meg az URL-t +meta#:#md_copyright_image_link#:#URL +meta#:#md_copyright_link#:#URL +meta#:#md_copyright_link_info#:#A licenszre mutató link meta#:#md_copyright_preview#:#Szerzői jog (előnézet) -meta#:#md_copyright_selection#:#Szerzői jog alapbeállítások +meta#:#md_copyright_selection#:#Elérhető Szerzői jogok meta#:#md_copyright_value#:#Szerzői jog meta#:#md_copyrights_deleted#:#A szerző jogot sikeresen törölte meta#:#md_days#:#Nap: meta#:#md_delete_cp_sure#:#Biztos, hogy törli az alábbi bejegyzéseket? meta#:#md_delimiter#:#Határolójel -meta#:#md_delimiter_info#:#A gyorsszerkesztő képernyőn a kulcsszavakhoz és más elválasztásokhoz határolójel használt. Az alapértelmezett a ','. -meta#:#md_editor_custom_input#:#Custom###28 10 2024 new variable -meta#:#md_editor_from_vocab_input#:#From Vocabulary###28 10 2024 new variable -meta#:#md_editor_value#:#Value###28 10 2024 new variable +meta#:#md_delimiter_info#:#A gyorsszerkesztő képernyőn a kulcsszavakhoz és más elválasztásokhoz határolójel használt. Az alapértelmezett a ‘,’. +meta#:#md_editor_custom_input#:#Egyéni +meta#:#md_editor_from_vocab_input#:#Szótárból +meta#:#md_editor_value#:#Érték meta#:#md_fields#:#Mezők -meta#:#md_import_file_vocab#:#Import File###28 10 2024 new variable -meta#:#md_import_vocab#:#Import###28 10 2024 new variable -meta#:#md_import_vocab_modal#:#Import From File###28 10 2024 new variable +meta#:#md_import_file_vocab#:#Importfájl +meta#:#md_import_vocab#:#Importálás +meta#:#md_import_vocab_modal#:#Importálás fájlból meta#:#md_months#:#Hónap: -meta#:#md_oai_contact_mail#:#Contact E-Mail###28 10 2024 new variable -meta#:#md_oai_identifier_prefix#:#OAI Prefix###28 10 2024 new variable -meta#:#md_oai_identifier_prefix_info#:#This prefix is used as a namespace in the identifiers of returned OER records.###28 10 2024 new variable -meta#:#md_oai_pmh_enabled#:#Allow Querying via OAI-PMH Interface###28 10 2024 new variable -meta#:#md_oai_pmh_enabled_info#:#If enabled, harvested OER can be queried by external interested parties, e.g. OER referatories.###28 10 2024 new variable -meta#:#md_oai_repository_name#:#Repository Name###28 10 2024 new variable -meta#:#md_oai_repository_name_info#:#This is returned as the name of this ILIAS installation when queried.###28 10 2024 new variable +meta#:#md_oai_contact_mail#:#A szervezet kontakt e-mail címe +meta#:#md_oai_identifier_prefix#:#OAI előtag +meta#:#md_oai_identifier_prefix_info#:#Ez az előtag névtérként használatos a visszaadott NyOE-rekordok azonosítóiban. +meta#:#md_oai_pmh_enabled#:#OAI-PMH Interfészen keresztüli lekérdezés engedélyezése +meta#:#md_oai_pmh_enabled_info#:#Ha bekapcsolja, az összegyűjtött NyOE-kat lekérdezhetik külső érdekelt felek, például NyOE-repozitorik. +meta#:#md_oai_repository_name#:#Repozitórium neve +meta#:#md_oai_repository_name_info#:#Ez az ILIAS-telepítés nevét adja vissza lekérdezéskor. meta#:#md_obj_types#:#Hozzárendelt objektumok meta#:#md_record_export_table#:#Exportfájlok meta#:#md_record_list_table#:#Egyéni metaadatbeállítások meta#:#md_separated_by#:#Elválasztva ezzel: %s -meta#:#md_settings#:#Settings###29 10 2025 new variable -meta#:#md_settings_harvester#:#OER Harvester###29 10 2025 new variable -meta#:#md_settings_licence#:#Terms of Usage###29 10 2025 new variable -meta#:#md_settings_publishing#:#Querying by Repositories###29 10 2025 new variable +meta#:#md_settings#:#Szerzői jogi beállítások +meta#:#md_settings_harvester#:#NyOE-összegyűjtő +meta#:#md_settings_licence#:#A használat feltételei +meta#:#md_settings_publishing#:#Repozitorik lekérdezése meta#:#md_time#:#Idő: -meta#:#md_unknown_vocabulary_flag#:#(unknown vocabulary)###28 10 2024 new variable -meta#:#md_used#:#Használat -meta#:#md_vocab_activate_action#:#Activate###28 10 2024 new variable -meta#:#md_vocab_active_column#:#Active###28 10 2024 new variable -meta#:#md_vocab_all_values_title#:#Values for %s (%s)###28 10 2024 new variable -meta#:#md_vocab_allow_custom_input_action#:#Allow Custom Input###28 10 2024 new variable -meta#:#md_vocab_custom_input_column#:#Custom Input Allowed###28 10 2024 new variable -meta#:#md_vocab_deactivate_action#:#Deactivate###28 10 2024 new variable -meta#:#md_vocab_delete_action#:#Delete###28 10 2024 new variable -meta#:#md_vocab_delete_confirmation_text#:#Are you sure you want to delete the vocabulary for %s (%s) with the following values?###28 10 2024 new variable -meta#:#md_vocab_delete_confirmation_title#:#Delete Vocabulary###28 10 2024 new variable -meta#:#md_vocab_deletion_successful#:#Vocabulary successfully deleted.###28 10 2024 new variable -meta#:#md_vocab_disallow_custom_input_action#:#Disallow Custom Input###28 10 2024 new variable -meta#:#md_vocab_element_column#:#Element###28 10 2024 new variable -meta#:#md_vocab_element_with_condition#:#%s where %s is %s###28 10 2024 new variable -meta#:#md_vocab_import_invalid#:#The import file is invalid:
    %s###28 10 2024 new variable -meta#:#md_vocab_import_successful#:#Vocabulary successfully imported.###28 10 2024 new variable -meta#:#md_vocab_import_upload_failed#:#Upload of the import file failed.###28 10 2024 new variable -meta#:#md_vocab_preview_column#:#Preview###28 10 2024 new variable -meta#:#md_vocab_show_all_action#:#Show All Values###28 10 2024 new variable -meta#:#md_vocab_source_column#:#Source###28 10 2024 new variable -meta#:#md_vocab_table_title#:#Vocabularies###28 10 2024 new variable -meta#:#md_vocab_type_column#:#Type###28 10 2024 new variable -meta#:#md_vocab_type_controlled_string#:#Controlled Text###28 10 2024 new variable -meta#:#md_vocab_type_controlled_vocab_value#:#Controlled Selection###28 10 2024 new variable -meta#:#md_vocab_type_copyright#:#Copyright###28 10 2024 new variable -meta#:#md_vocab_type_standard#:#Standard###28 10 2024 new variable -meta#:#md_vocab_update_successful#:#Vocabulary successfully updated.###28 10 2024 new variable -meta#:#md_vocabularies_config#:#LOM Vocabularies###28 10 2024 new variable -meta#:#meta_1#:#1###26 08 2024 new variable -meta#:#meta_2#:#2###26 08 2024 new variable -meta#:#meta_3#:#3###26 08 2024 new variable -meta#:#meta_4#:#4###26 08 2024 new variable +meta#:#md_unknown_vocabulary_flag#:#(ismeretlen szótár) +meta#:#md_used#:#Pillanatnyi használatok száma +meta#:#md_vocab_activate_action#:#Aktiválás +meta#:#md_vocab_active_column#:#Aktív +meta#:#md_vocab_all_values_title#:#‘%s’ (%s) értékei +meta#:#md_vocab_allow_custom_input_action#:#Egyéni bemenet engedélyezése +meta#:#md_vocab_custom_input_column#:#Egyéni bemenet engedélyezett +meta#:#md_vocab_deactivate_action#:#Inaktiválás +meta#:#md_vocab_delete_action#:#Törlés +meta#:#md_vocab_delete_confirmation_text#:#Biztos, hogy törli ‘%s’ (%s) szótárát a következő értékekkel? +meta#:#md_vocab_delete_confirmation_title#:#Szótár törlése +meta#:#md_vocab_deletion_successful#:#A szótárat sikeresen törölte +meta#:#md_vocab_disallow_custom_input_action#:#Egyéni bevitel nem egedélyezett +meta#:#md_vocab_element_column#:#Elem +meta#:#md_vocab_element_with_condition#:#%s ahol %s értéke %s +meta#:#md_vocab_import_invalid#:#Az importfájl érvénytelen:
    %s +meta#:#md_vocab_import_successful#:#A szótárat sikeresen importálta. +meta#:#md_vocab_import_upload_failed#:#Az importfájl feltöltése sikertelen. +meta#:#md_vocab_preview_column#:#Előnézet +meta#:#md_vocab_show_all_action#:#Összes érték megjelenítése +meta#:#md_vocab_source_column#:#Forrás +meta#:#md_vocab_table_title#:#Szótárak +meta#:#md_vocab_type_column#:#Típus +meta#:#md_vocab_type_controlled_string#:#Kontrolűlt típus +meta#:#md_vocab_type_controlled_vocab_value#:#Kontrolált kiválasztás +meta#:#md_vocab_type_copyright#:#Szerzői jog +meta#:#md_vocab_type_standard#:#Standard +meta#:#md_vocab_update_successful#:#A szótárat sikeresen módosította. +meta#:#md_vocabularies_config#:#LOM szótárak +meta#:#meta_1#:#1 +meta#:#meta_2#:#2 +meta#:#meta_3#:#3 +meta#:#meta_4#:#4 meta#:#meta_accessibility_restrictions#:#Hozzáférési korlátozások meta#:#meta_active#:#Aktív meta#:#meta_add#:#Hozzáadás -meta#:#meta_add_element#:#Add %s###26 08 2024 new variable -meta#:#meta_add_element_success#:#Element added successfully###26 08 2024 new variable -meta#:#meta_advmd_add_field#:#Add New Field###26 08 2024 new variable -meta#:#meta_advmd_select_delete_option#:#Delete This Entry###26 08 2024 new variable -meta#:#meta_advmd_select_first_position_identifier#:#First###26 08 2024 new variable -meta#:#meta_advmd_select_new_option#:#Add New Entry###26 08 2024 new variable -meta#:#meta_advmd_select_option_position#:#Position###26 08 2024 new variable -meta#:#meta_advmd_select_option_value#:#Value###26 08 2024 new variable +meta#:#meta_add_element#:#s hozzáadása +meta#:#meta_add_element_success#:#Az elemet sikeresen hozzáadta. +meta#:#meta_advmd_add_field#:#Új mező létrehozása +meta#:#meta_advmd_select_delete_option#:#Bejegyzés törlése +meta#:#meta_advmd_select_first_position_identifier#:#Első +meta#:#meta_advmd_select_new_option#:#Új bejegyzés létrehozása +meta#:#meta_advmd_select_option_position#:#Pozíció +meta#:#meta_advmd_select_option_value#:#Értéke meta#:#meta_advmd_select_options#:#Bejegyzések -meta#:#meta_advmd_select_options_edit#:#Edit Entries###26 08 2024 new variable -meta#:#meta_advmd_select_position_identifier#:#After %s###26 08 2024 new variable -meta#:#meta_aggregation_level#:#Aggregation Level###26 08 2024 new variable -meta#:#meta_amaya#:#Amaya###26 08 2024 new variable +meta#:#meta_advmd_select_options_edit#:#Bejegyzések módosítása +meta#:#meta_advmd_select_position_identifier#:#‘%s’ mögé +meta#:#meta_aggregation_level#:#Aggregációs szint +meta#:#meta_amaya#:#Amaya meta#:#meta_annotation#:#Kommentár -meta#:#meta_annotation_plural#:#Annotations###26 08 2024 new variable -meta#:#meta_any#:#Any###26 08 2024 new variable +meta#:#meta_annotation_plural#:#Annotációk +meta#:#meta_any#:#Bármelyik meta#:#meta_atomic#:#Atomi meta#:#meta_author#:#Szerző -meta#:#meta_authors#:#Authors###26 08 2024 new variable +meta#:#meta_authors#:#Szerkesztők meta#:#meta_browser#:#Böngésző -meta#:#meta_button_to_full_editor_label#:#Edit the Full Learning Object Metadata###26 08 2024 new variable +meta#:#meta_button_to_full_editor_label#:#A tanulási objektumok összes metaadatának módosítása meta#:#meta_c_AD#:#Andorra meta#:#meta_c_AE#:#Egyesült Arab Emirátusok meta#:#meta_c_AF#:#Afganisztán @@ -12235,7 +12304,7 @@ meta#:#meta_c_KR#:#Dél-Korea (Koreai Köztársaság) meta#:#meta_c_KW#:#Kuvait meta#:#meta_c_KY#:#Kajmán-szigetek meta#:#meta_c_KZ#:#Kazahsztán -meta#:#meta_c_LA#:#Laoi Népköztársaság +meta#:#meta_c_LA#:#Laoi Demokratikus Köztársaság meta#:#meta_c_LB#:#Libanon meta#:#meta_c_LC#:#Szent Lucia meta#:#meta_c_LI#:#Liechtenstein @@ -12253,7 +12322,7 @@ meta#:#meta_c_ME#:#Montenegro meta#:#meta_c_MF#:#Szent Martin (francia rész) meta#:#meta_c_MG#:#Madagaszkár meta#:#meta_c_MH#:#Marshall-szigetek -meta#:#meta_c_MK#:#Macedónia +meta#:#meta_c_MK#:#Észak-Macedónia meta#:#meta_c_ML#:#Mali meta#:#meta_c_MM#:#Mianmar meta#:#meta_c_MN#:#Mongólia @@ -12360,77 +12429,77 @@ meta#:#meta_c_ZM#:#Zambia meta#:#meta_c_ZW#:#Zimbabwe meta#:#meta_catalog#:#Katalógus meta#:#meta_classification#:#Besorolás -meta#:#meta_classification_plural#:#Classifications###26 08 2024 new variable +meta#:#meta_classification_plural#:#Besorolások meta#:#meta_collection#:#Gyűjtemény meta#:#meta_competency#:#Kompetencia meta#:#meta_contentprovider#:#Tartalomszolgáltató meta#:#meta_context#:#Kontextus -meta#:#meta_context_plural#:#Contexts###26 08 2024 new variable +meta#:#meta_context_plural#:#Kontextusok meta#:#meta_contribute#:#Közreműködés -meta#:#meta_contribute_plural#:#Contribute###26 08 2024 new variable +meta#:#meta_contribute_plural#:#Hozzájárulás meta#:#meta_copyright#:#Szerzői jog meta#:#meta_copyright_and_other_restrictions#:#Szerzői jogi és további megszorítások -meta#:#meta_copyright_change_info#:#Módosítani fogja az ehhez a tartalomhoz rendelt licencet. Ez csak a szerzői jog tulajdonosának a belegyezésével történhet csak meg, továbbá az új licenc nem lehet szigorúbb, korlátozóbb, mint a jelenlegi. -meta#:#meta_copyright_change_oer_info#:#The copyright licence you have selected makes this object eligible to be harvested as an Open Educational Resource. If you continue, it might be listed as such along with an export file, and it might get published beyond this platform.###28 10 2024 new variable +meta#:#meta_copyright_change_info#:#Módosítani fogja az ehhez a tartalomhoz rendelt licenszet. Ez csak a szerzői jog tulajdonosának a belegyezésével történhet csak meg, továbbá az új licensz nem lehet szigorúbb, korlátozóbb, mint a jelenlegi. +meta#:#meta_copyright_change_oer_info#:#A kiválasztott szerzői jogi licensz lehetővé teszi, hogy ez az objektum Nyílt Oktatási Erőforrásként begyűjthető legyen. Ha folytatja, előfordulhat, hogy egy exportfájllal együtt szerepel a felsorolásban, és közzétehető lehet ezen a platformon kívül is meta#:#meta_copyright_change_warning_title#:#Szerzői jogi beállítások módosítása meta#:#meta_copyright_in_use#:#Használatban -meta#:#meta_copyright_outdated#:#Elavult -meta#:#meta_copyright_outdated_error#:#The chosen copyright is outdated and no longer in use.###26 08 2024 new variable +meta#:#meta_copyright_outdated#:#Elavult / Már nincs használatban +meta#:#meta_copyright_outdated_error#:#A kiválasztott szerzői jog elavult és már nincs használatban. meta#:#meta_copyright_show_usages#:#Használat megjelenítése meta#:#meta_copyright_status#:#Állapot meta#:#meta_copyright_sub_items#:#Alelemek meta#:#meta_copyright_usage#:#Használat meta#:#meta_cost#:#Költség meta#:#meta_coverage#:#Terjedelem -meta#:#meta_coverage_plural#:#Coverage###26 08 2024 new variable +meta#:#meta_coverage_plural#:#Lefedettség meta#:#meta_cp_own#:#Saját szerzői jog információk: meta#:#meta_creator#:#Létrehozó meta#:#meta_current_value#:#Jelenlegi érték meta#:#meta_date#:#Dátum -meta#:#meta_date_time#:#Date###26 08 2024 new variable +meta#:#meta_date_time#:#Dárum meta#:#meta_delete#:#Törlés -meta#:#meta_delete_confirm#:#Are you sure you want to delete this element and its content?###26 08 2024 new variable -meta#:#meta_delete_element#:#Delete %s###26 08 2024 new variable -meta#:#meta_delete_element_success#:#Element deleted successfully###26 08 2024 new variable -meta#:#meta_delete_this_element#:#Delete This Element###26 08 2024 new variable +meta#:#meta_delete_confirm#:#Biztos, hogy törli ezt az elemet és annak tartalmát? +meta#:#meta_delete_element#:#%s törlése +meta#:#meta_delete_element_success#:#Az elemet sikeresen törölte +meta#:#meta_delete_this_element#:#Ennek az elemnek a törlése meta#:#meta_description#:#Leírás -meta#:#meta_description_plural#:#Descriptions###26 08 2024 new variable +meta#:#meta_description_plural#:#Leírások meta#:#meta_diagramm#:#Diagram meta#:#meta_difficult#:#Nehéz meta#:#meta_difficulty#:#Nehézség -meta#:#meta_discipline#:#Discipline###26 08 2024 new variable +meta#:#meta_discipline#:#Fegyelem meta#:#meta_draft#:#Tervezet meta#:#meta_duration#:#Időtartam meta#:#meta_easy#:#Könnyű -meta#:#meta_edit_element#:#Edit %s###26 08 2024 new variable -meta#:#meta_edit_element_success#:#Element edited successfully###26 08 2024 new variable +meta#:#meta_edit_element#:#%s szerkesztése +meta#:#meta_edit_element_success#:#Az elemet sikeresen szerkesztette meta#:#meta_editor#:#Szerkesztő meta#:#meta_education#:#Oktatás meta#:#meta_educational#:#Oktatási meta#:#meta_educational_level#:#Képzési szint meta#:#meta_educational_objective#:#Képzési cél -meta#:#meta_educational_plural#:#Educational###26 08 2024 new variable +meta#:#meta_educational_plural#:#Oktatási meta#:#meta_educationalvalidator#:#Oktatási jóváhagyó meta#:#meta_entity#:#Entitás -meta#:#meta_entity_plural#:#Entities###26 08 2024 new variable +meta#:#meta_entity_plural#:#Entitások meta#:#meta_entry#:#Bejegyzés -meta#:#meta_error_empty_input#:#Please make sure that at least one of the following input fields is not empty.###26 08 2024 new variable +meta#:#meta_error_empty_input#:#Győződjön meg arról, hogy az alábbi beviteli mezők közül legalább egy nem üres. meta#:#meta_exam#:#Vizsga meta#:#meta_exercise#:#Beadandó feladat meta#:#meta_experiment#:#Kísérlet meta#:#meta_expositive#:#Értelmező -meta#:#meta_figure#:#Mutatószám -meta#:#meta_final#:#Végső -meta#:#meta_first_author#:#First Author###26 08 2024 new variable +meta#:#meta_figure#:#Kép / Illusztráció +meta#:#meta_final#:#Végső verzió +meta#:#meta_first_author#:#Első szerkesztő meta#:#meta_format#:#Formátum -meta#:#meta_format_plural#:#Formats###26 08 2024 new variable -meta#:#meta_full_editor_navigation_info#:#To navigate and edit this metadata set, use the ‘LOM’-tree in the ‘Tools’ entry of the main menu.###26 08 2024 new variable +meta#:#meta_format_plural#:#Formátumok +meta#:#meta_full_editor_navigation_info#:#A metaadatkészletben való navigáláshoz és szerkesztéshez használja a főmenü ‘Eszközök’ bejegyzésében található ‘LOM’-fát meta#:#meta_general#:#Általános meta#:#meta_global#:#Globális meta#:#meta_graph#:#Grafikon -meta#:#meta_graphicaldesigner#:#Grafikus -meta#:#meta_has_format#:#Formátuma -meta#:#meta_has_part#:#Része +meta#:#meta_graphicaldesigner#:#Grafikai tervezés +meta#:#meta_has_format#:#Formátuma … +meta#:#meta_has_part#:#Része … meta#:#meta_has_version#:#Verziója meta#:#meta_hierarchical#:#Hierarchikus meta#:#meta_high#:#Magas @@ -12438,26 +12507,26 @@ meta#:#meta_higher_education#:#Felsőfokú képzés meta#:#meta_id#:#Azonosító meta#:#meta_idea#:#Ötlet meta#:#meta_identifier#:#Azonosító -meta#:#meta_identifier_plural#:#Identifiers###26 08 2024 new variable +meta#:#meta_identifier_plural#:#Azonosítók meta#:#meta_index#:#Index -meta#:#meta_info_licence_section#:#Licence and Use###28 10 2024 new variable -meta#:#meta_info_only_repository_objects#:#Csak Tartalomtár-objektumokat sorolunk fel (médiaobjektumokat nem, illetve tananyagoldalakat sem). +meta#:#meta_info_licence_section#:#Licensz és használata +meta#:#meta_info_only_repository_objects#:#Csak ILIAS-objektumokat sorolunk fel (médiaobjektumokat nem, illetve tananyagoldalakat sem). meta#:#meta_initiator#:#Kezdeményező meta#:#meta_installation_remarks#:#Észrevételek a telepítéshez meta#:#meta_instructionaldesigner#:#Oktatástervező -meta#:#meta_intended_end_user_role#:#Megcélzott végfelhasználói szerep -meta#:#meta_intended_end_user_role_plural#:#Intended End User Roles###26 08 2024 new variable +meta#:#meta_intended_end_user_role#:#A megcélzott végfelhasználói szerepkör +meta#:#meta_intended_end_user_role_plural#:#A megcélzott végfelhasználói szerepkörök meta#:#meta_interactivity_level#:#Interaktivitás szintje meta#:#meta_interactivity_type#:#Interaktivitás típusa -meta#:#meta_is_based_on#:#Ezen alapul -meta#:#meta_is_basis_for#:#Erre épül -meta#:#meta_is_format_of#:#Ilyen formátumú -meta#:#meta_is_part_of#:#Része ennek +meta#:#meta_is_based_on#:#Ezen alapul … +meta#:#meta_is_basis_for#:#Erre épül … +meta#:#meta_is_format_of#:#Ilyen formátumú … +meta#:#meta_is_part_of#:#Része ennek … meta#:#meta_is_referenced_by#:#Hivatkozza ez meta#:#meta_is_required_by#:#Szükséges ehhez meta#:#meta_is_version_of#:#Verziója ennek meta#:#meta_keyword#:#Kulcsszó -meta#:#meta_keyword_plural#:#Keywords###26 08 2024 new variable +meta#:#meta_keyword_plural#:#Kulcsszavak meta#:#meta_kind#:#Fajta meta#:#meta_l_aa#:#afar meta#:#meta_l_ab#:#abkhazian @@ -12488,9 +12557,9 @@ meta#:#meta_l_eo#:#eszperantó meta#:#meta_l_es#:#spanyol meta#:#meta_l_et#:#észt meta#:#meta_l_eu#:#baskír -meta#:#meta_l_fa#:#perzsa +meta#:#meta_l_fa#:#perzsa (farsi) meta#:#meta_l_fi#:#finn -meta#:#meta_l_fj#:#fiji +meta#:#meta_l_fj#:#fijii meta#:#meta_l_fo#:#feröeri meta#:#meta_l_fr#:#francia meta#:#meta_l_fy#:#fríz @@ -12538,12 +12607,12 @@ meta#:#meta_l_mr#:#marathi meta#:#meta_l_ms#:#maláj meta#:#meta_l_mt#:#máltai meta#:#meta_l_my#:#burmai -meta#:#meta_l_na#:#nauru +meta#:#meta_l_na#:#naurui meta#:#meta_l_ne#:#nepáli meta#:#meta_l_nl#:#holland meta#:#meta_l_no#:#norvég meta#:#meta_l_oc#:#occitan -meta#:#meta_l_om#:#afan (oromo) +meta#:#meta_l_om#:#oromo; afaan oromoo meta#:#meta_l_or#:#oriya meta#:#meta_l_pa#:#pandzsáb meta#:#meta_l_pl#:#lengyel @@ -12571,7 +12640,7 @@ meta#:#meta_l_ss#:#siswati meta#:#meta_l_st#:#sesotho meta#:#meta_l_su#:#sundanese meta#:#meta_l_sv#:#svéd -meta#:#meta_l_sw#:#swahili +meta#:#meta_l_sw#:#swahili; kiswahili meta#:#meta_l_ta#:#tamil meta#:#meta_l_te#:#telugu meta#:#meta_l_tg#:#tajik @@ -12580,7 +12649,7 @@ meta#:#meta_l_ti#:#tigrinya meta#:#meta_l_tk#:#türkmén meta#:#meta_l_tl#:#tagalog meta#:#meta_l_tn#:#setswana -meta#:#meta_l_to#:#tonga +meta#:#meta_l_to#:#tongai meta#:#meta_l_tr#:#török meta#:#meta_l_ts#:#tsonga meta#:#meta_l_tt#:#tatár @@ -12593,69 +12662,69 @@ meta#:#meta_l_vi#:#vietnámi meta#:#meta_l_vo#:#volapük meta#:#meta_l_wo#:#wolof meta#:#meta_l_xh#:#xhosa -meta#:#meta_l_xx#:#none###26 08 2024 new variable +meta#:#meta_l_xx#:#egyik sem meta#:#meta_l_yi#:#zsidó meta#:#meta_l_yo#:#yoruba meta#:#meta_l_za#:#zhuang meta#:#meta_l_zh#:#kínai meta#:#meta_l_zu#:#zulu meta#:#meta_language#:#Nyelv -meta#:#meta_language_plural#:#Languages###26 08 2024 new variable +meta#:#meta_language_plural#:#Nyelvek meta#:#meta_learner#:#Tanuló meta#:#meta_learning_resource_type#:#Tananyag típusa -meta#:#meta_learning_resource_type_plural#:#Learning Resource Types###26 08 2024 new variable +meta#:#meta_learning_resource_type_plural#:#Tananyag típusai meta#:#meta_lecture#:#Előadás meta#:#meta_lifecycle#:#Életciklus meta#:#meta_linear#:#Lineáris meta#:#meta_local#:#Helyi meta#:#meta_location#:#Helyszín -meta#:#meta_location_plural#:#Locations###26 08 2024 new variable -meta#:#meta_lom#:#Learning Object Metadata###26 08 2024 new variable -meta#:#meta_lom_short#:#LOM###26 08 2024 new variable +meta#:#meta_location_plural#:#Helyszínek +meta#:#meta_lom#:#Tanulási objektum metaadat +meta#:#meta_lom_short#:#LOM meta#:#meta_low#:#Alacsony -meta#:#meta_macos#:#MAC-OS###26 08 2024 new variable +meta#:#meta_macos#:#MAC-OS meta#:#meta_manager#:#Menedzser meta#:#meta_maximum_version#:#Maximális verzió meta#:#meta_medium#:#Közepes meta#:#meta_meta_metadata#:#Meta-metaadat meta#:#meta_metadatascheme#:#Metaadatséma -meta#:#meta_metadatascheme_plural#:#Metadata Schemas###26 08 2024 new variable +meta#:#meta_metadatascheme_plural#:#Metaadatsémák meta#:#meta_minimum_version#:#Minimális verzió meta#:#meta_mixed#:#Vegyes -meta#:#meta_ms-internet_explorer#:#MS-Internet Explorer###26 08 2024 new variable -meta#:#meta_ms-windows#:#MS-Windows###26 08 2024 new variable -meta#:#meta_multi-os#:#Multi-OS###26 08 2024 new variable +meta#:#meta_ms-internet_explorer#:#MS-Internet Explorer +meta#:#meta_ms-windows#:#MS-Windows +meta#:#meta_multi-os#:#Multi-OS meta#:#meta_name#:#Név meta#:#meta_narrative_text#:#Elbeszélés -meta#:#meta_netscape_communicator#:#Netscape Communicator###26 08 2024 new variable +meta#:#meta_netscape_communicator#:#Netscape Communicator meta#:#meta_networked#:#Hálózatos meta#:#meta_new_element#:#Új elem meta#:#meta_no#:#Nem -meta#:#meta_none#:#None###26 08 2024 new variable -meta#:#meta_obj_type_active#:#Dataset offered###29 07 2022 new variable +meta#:#meta_none#:#Egyik sem +meta#:#meta_obj_type_active#:#Adatkészletet felkínáljuk meta#:#meta_obj_type_inactive#:#Adatkészlet nincs használatban meta#:#meta_obj_type_mandatory#:#Adatkészletet mindig felkínáljuk meta#:#meta_obj_type_optional#:#Adatkészletet aktiválni kell meta#:#meta_oer_blocked#:#NyOE-összegyűjtő nem veszi figyelembe meta#:#meta_oer_blocked_info#:#Automatikusan nem Nyílt Oktatási Erőforrásként (Open Educational Resource, OER) soroljuk fel. -meta#:#meta_oer_categories#:#Categories for Objects Gathered###29 10 2025 new variable -meta#:#meta_oer_copyright_selection#:#Licenc kiválasztása -meta#:#meta_oer_copyright_selection_info#:#Csak a kiválasztott licenc alatt közzétett objektumokat vesszük figyelembe. -meta#:#meta_oer_exposed_source#:#Category for Published OER Content###28 10 2024 new variable -meta#:#meta_oer_harvested_licences#:#Licences for Harvesting###29 10 2025 new variable -meta#:#meta_oer_harvested_types#:#Types of Objects to be Harvested###29 10 2025 new variable +meta#:#meta_oer_categories#:#Kategórák az összegyűjtött objektumoknak +meta#:#meta_oer_copyright_selection#:#Licensz kiválasztása +meta#:#meta_oer_copyright_selection_info#:#Csak a kiválasztott licensz alatt közzétett objektumokat vesszük figyelembe. +meta#:#meta_oer_exposed_source#:#Kategória közzétett NyOE-tartalom számára +meta#:#meta_oer_harvested_licences#:#Licenszek az NyOE-összegyűjtőnek +meta#:#meta_oer_harvested_types#:#Az összegyűjtendő objektumok típusai meta#:#meta_oer_harvester#:#NyOE-összegyűjtő -meta#:#meta_oer_harvester_desc#:#NyOE-tartalmak (Nyílt Oktatási Erőforrások, OER) összegyűjtéséré szolgáltatás -meta#:#meta_oer_object_type_selection#:#Harvested Object Types###28 10 2024 new variable +meta#:#meta_oer_harvester_desc#:#A Tartalomtárban az összes fájl objektum végigpásztázása licenszeik után. A NyOE-tartalmak (Nyílt Oktatási Erőforrások, OER) összegyűjtője elhelyezi az összes erőforrást az ütemezett feladatokban kiválasztott licenszek alá. Ahhoz, hogy az ütemezett feladat eredményes legyen, szükséges bekapcsolni és beállítani a szerzői jog részt a Rendszerbeállítások » Metaadatok alatt. +meta#:#meta_oer_object_type_selection#:#Összegyűjtött objektumtípusok meta#:#meta_oer_target#:#NyOE-tartalmú kategóriák -meta#:#meta_opera#:#Opera###26 08 2024 new variable +meta#:#meta_opera#:#Opera meta#:#meta_operating_system#:#Operációs rendszer -meta#:#meta_or_composite#:#vagy összetett -meta#:#meta_or_composite_plural#:#Or Composites###26 08 2024 new variable +meta#:#meta_or_composite#:#vagy összetett … +meta#:#meta_or_composite_plural#:#vagy kompozitok meta#:#meta_order#:#Rendezés meta#:#meta_other#:#Egyéb meta#:#meta_other_plattform_requirements#:#További platformkövetelmények -meta#:#meta_pc-dos#:#PC-DOS###26 08 2024 new variable +meta#:#meta_pc-dos#:#PC-DOS meta#:#meta_pointofcontact#:#Kapcsolattartó(k) meta#:#meta_prerequisite#:#Előfeltétel meta#:#meta_problem_statement#:#Problémaállapot @@ -12664,18 +12733,18 @@ meta#:#meta_purpose#:#Cél meta#:#meta_questionnaire#:#Kérdőív meta#:#meta_references#:#Hivatkozások meta#:#meta_relation#:#Kapcsolat -meta#:#meta_relation_plural#:#Relations###26 08 2024 new variable +meta#:#meta_relation_plural#:#Kapcsolatok meta#:#meta_requirement#:#Követelmény -meta#:#meta_requirement_plural#:#Requirements###26 08 2024 new variable +meta#:#meta_requirement_plural#:#Követelmények meta#:#meta_requires#:#Igények meta#:#meta_resource#:#Forrás meta#:#meta_revised#:#Javított meta#:#meta_rights#:#Jogok -meta#:#meta_role#:#Szerep +meta#:#meta_role#:#Szerepkör meta#:#meta_save_order#:#Rendezés mentése meta#:#meta_school#:#Iskola meta#:#meta_scriptwriter#:#Szkriptíró -meta#:#meta_second_author#:#Second Author###26 08 2024 new variable +meta#:#meta_second_author#:#Második szerkesztő meta#:#meta_section#:#Fejezet meta#:#meta_security_level#:#Biztonsági szint meta#:#meta_self_assessment#:#Önértékelés @@ -12686,31 +12755,30 @@ meta#:#meta_skill_level#:#Kompetenciaszint meta#:#meta_slide#:#Dia meta#:#meta_source#:#Forrás meta#:#meta_status#:#Állapot -meta#:#meta_string#:#Text###26 08 2024 new variable +meta#:#meta_string#:#Szöveg meta#:#meta_structure#:#Szerkezet -meta#:#meta_subjectmatterexpert#:#Tantárgyi szakértő(k) meta#:#meta_tab_advmd#:#Egyéni metaadat meta#:#meta_tab_advmd_def#:#Egyéni metaadat meghatározása meta#:#meta_tab_lom#:#LOM meta#:#meta_table#:#Táblázat meta#:#meta_taxon#:#Rendszertan meta#:#meta_taxon_path#:#Rendszertani ágazat -meta#:#meta_taxon_path_plural#:#Taxon Paths###26 08 2024 new variable -meta#:#meta_taxon_plural#:#Taxons###26 08 2024 new variable +meta#:#meta_taxon_path_plural#:#Taxon útvonalai +meta#:#meta_taxon_plural#:#Taxonok meta#:#meta_teacher#:#Tanár meta#:#meta_technical#:#Technikai meta#:#meta_technicalimplementer#:#Technikai kivitelező meta#:#meta_technicalvalidator#:#Technikai jóváhagyó -meta#:#meta_terminator#:#Befejező -meta#:#meta_third_author#:#Third Author###26 08 2024 new variable +meta#:#meta_terminator#:#Végső szerkesztő +meta#:#meta_third_author#:#Harmadik szerző meta#:#meta_title#:#Cím meta#:#meta_training#:#Tréning meta#:#meta_type#:#Típus meta#:#meta_typical_age_range#:#Jellemző életkor -meta#:#meta_typical_age_range_plural#:#Typical Age Ranges###26 08 2024 new variable +meta#:#meta_typical_age_range_plural#:#Tipikus korosztályok meta#:#meta_typical_learning_time#:#Szokásos tanulási idő meta#:#meta_unavailable#:#Elérhetetlen -meta#:#meta_unix#:#Unix###26 08 2024 new variable +meta#:#meta_unix#:#Unix meta#:#meta_unknown#:#Ismeretlen meta#:#meta_validator#:#Jóváhagyó meta#:#meta_value#:#Érték @@ -12731,42 +12799,42 @@ mmbr#:#info_refuse_sure#:#Biztos, hogy elutasítja az alábbi felhasználó(ka)t mmbr#:#mmbr_awrn_my_groups_courses#:#Csoportjaim és kurzusaim mmbr#:#mmbr_awrn_my_groups_courses_info#:#A jelenlegi felhasználó kurzusainak vagy csoportjainak összes tagját felsoroljuk itt. mmbr#:#mmbr_btn_mail_selected_users#:#Levél küldése -mmbr#:#mmbr_info_delete_sure_unsubscribe#:#Biztos, hogy leiratkozik az alábbi objektumokról? mmbr#:#mmbr_memberships#:#Tagság -mmbr#:#mmbr_selected_users#:#Kiválasztott résztvevők +mmbr#:#mmbr_role_error#:#Minden tagnak legalább egy szerepkörrel kell rendelkeznie. mmbr#:#mmbr_unsubscribed_from_objs#:#Sikeresen leiratkozott a kiválaszott objektumokról. mme#:#add_languages#:#Nyelv hozzáadása mme#:#additional_langs#:#További nyelvek mme#:#button_save#:#Mentés mme#:#component_not_active#:#A komponens nincs aktiválva. mme#:#confirm_move#:#Biztos, hogy ezt az elemet a felső elemekhez mozgatja? -mme#:#deactived_by_configuration#:#Deactivated by configuration###29 10 2025 new variable -mme#:#edit_sub_tems#:#Edit Entries###29 10 2025 new variable +mme#:#deactived_by_configuration#:#Konfiguráció által kikapcsolva +mme#:#edit_sub_tems#:#Bejegyzések módosítása mme#:#err_uri_not_valid#:#Valós URL-t adjon meg mme#:#field_external#:#Külső link mme#:#field_external_info#:#A link új ablakban nyílik meg. mme#:#field_ref_id#:#ILIAS Reference-ID -mme#:#field_ref_id_info#:#A kívánt ILIAS-objektum Reference-ID-je, amit az objektum URL-ben is megtalálható (...?ref_id=123) +mme#:#field_ref_id_info#:#A kívánt ILIAS-objektum Reference-ID-je, amit az objektum URL-ben is megtalálható (…?ref_id=123) mme#:#field_url#:#URL mme#:#field_url_info#:#Link a kívánt weboldalra, elején http(s):// mme#:#flush#:#Elveszett elemek törlése mme#:#item_must_be_always_active#:#Az elemnek aktívnak kell lennie. -mme#:#item_updated#:#Item stored###29 10 2025 new variable +mme#:#item_updated#:#Az elemet eltároljuk mme#:#main#:#Főmenü mme#:#mm_translation_lang#:#Nyelv mme#:#mm_translation_trans#:#Fordítás -mme#:#move_to_item#:#Mozgatás ezt elemekhez -mme#:#move_to_top_item#:#Mozgatás a felső elemekhez +mme#:#mme_lost_items#:#Sehol sincs hozzárendelve +mme#:#move_to_item#:#Mozgatás az elemek közé +mme#:#move_to_top_item#:#Mozgatás a főelemek közé mme#:#msg_languages_added#:#Hozzáadott nyelvek mme#:#msg_moved#:#Az elemet sikeresen mozgatta -mme#:#msg_not_changed#:#The following entries could not be changed: %s###29 10 2025 new variable +mme#:#msg_not_changed#:#A következő bejegyzéseket nem lehetett módosítani: %s mme#:#msg_not_moved#:#Az elem mozgatása sikertelen, érvényes szülőt válasszon. -mme#:#msg_ref_id_not_callable#:#This reference ID cannot be used by Main-Menu. Only targets in the magazine are supported.###26 08 2024 new variable +mme#:#msg_ref_id_not_callable#:#Ez a referenciaazonosító nem használható a főmenüben. Csak a Tartalomtárba mutató használható. mme#:#msg_restore_confirm#:#Az összes egyéni elembeállítást és fordítást töröl, és az összes standard elem visszaáll annak alapértékére. Az összes személyre szabás elveszik. mme#:#msg_restored#:#A Főmenüt alapértékeit sikeresen visszaállította mme#:#msg_subitem_deleted#:#Az elemet sikeresen törölte. mme#:#msg_subitem_flushed#:#Az elveszett elemeket sikeresen törölte. -mme#:#msg_success#:#Successfully stored###29 10 2025 new variable +mme#:#msg_success#:#Sikeresen visszaállította. mme#:#msg_topitem_deleted#:#Az elemet sikeresen törölte. mme#:#msg_translations_deleted#:#A fordításokat sikeresen törölte mme#:#msg_translations_saved#:#A fordítást sikeresen mentette @@ -12775,21 +12843,21 @@ mme#:#select_parent#:#Szülő választása mme#:#sub_actions#:#Műveletek mme#:#sub_active#:#Aktív mme#:#sub_active_byline#:#Elem aktiválása az összes felhasználónak. -mme#:#sub_global_roles#:#Globália szerepek +mme#:#sub_global_roles#:#Globália szerepkörök mme#:#sub_icon#:#Ikon -mme#:#sub_icon_byline#:#Egyéni ikon feltöltése ehhez az objektumhoz. Kérem, vegye figyelembe, hogy SVG-ikonná alakítjuk. +mme#:#sub_icon_byline#:#Egyéni ikon feltöltése ehhez az objektumhoz. mme#:#sub_parent#:#Főelem mme#:#sub_position#:#Pozíció mme#:#sub_provider#:#Szolgáltató -mme#:#sub_role_based_visibility#:#Szerepek láthatósága -mme#:#sub_role_based_visibility_byline#:#Válassza ki, mely globális szerepek tagjai láthatják ezt az objektumot. Ha nincs bekapcsolva, az objektum mindenkinek megjelenik. +mme#:#sub_role_based_visibility#:#Szerepkörök láthatósága +mme#:#sub_role_based_visibility_byline#:#Válassza ki, mely globális szerepkörök tagjai láthatják ezt az objektumot. Ha nincs bekapcsolva, az objektum mindenkinek megjelenik. mme#:#sub_status#:#Állapot mme#:#sub_title#:#Cím mme#:#sub_title_default#:#Cím (alapértelmezett nyelven) -mme#:#sub_title_default_byline#:#További fordítások később a Műveletek / Fordítás alatt adhatóak hozzá. Elválasztó esetén a címet célszerű üresen hagyni. +mme#:#sub_title_default_byline#:#További fordítások később a Műveletek / Fordítás alatt adhatók hozzá. Elválasztó esetén a címet célszerű üresen hagyni. mme#:#sub_type#:#Típus mme#:#sub_type_byline#:#Az elemhez speciális típus beállítása további beállításokat igényelhet. -mme#:#subitem#:#Subitem###29 10 2025 new variable +mme#:#subitem#:#Alelemek mme#:#subitem_add#:#Elem hozzáadása mme#:#subitem_confirm_delete#:#Biztos, hogy törli az alábbi elemet? mme#:#subitem_delete#:#Törlés @@ -12807,13 +12875,13 @@ mme#:#topitem_confirm_delete#:#Biztos, hogy törli az alábbi elemet? mme#:#topitem_delete#:#Törlés mme#:#topitem_edit#:#Módosítás mme#:#topitem_icon#:#Ikon -mme#:#topitem_icon_byline#:#Egyéni ikon feltöltése ehhez az objektumhoz. Kérem, vegye figyelembe, hogy SVG-ikonná alakítjuk. +mme#:#topitem_icon_byline#:#Egyéni ikon feltöltése ehhez az objektumhoz. mme#:#topitem_position#:#Pozíciója mme#:#topitem_provider#:#Szolgáltató mme#:#topitem_subentries#:#Elemek mme#:#topitem_title#:#Cím mme#:#topitem_title_default#:#Cím (alapértelmezett nyelven) -mme#:#topitem_title_default_byline#:#További fordítások a Műveletek / Fordítás alatt adhatóak hozzá. +mme#:#topitem_title_default_byline#:#További fordítások a Műveletek / Fordítás alatt adhatók hozzá. mme#:#topitem_translate#:#Fordítás mme#:#topitem_type#:#Típus mme#:#topitem_type_byline#:#A főelemek tartalmazhatják az elemeket vagy linkelhetnek rájuk. @@ -12828,54 +12896,54 @@ mme#:#type_separator#:#Elválasztó mme#:#type_separator_info#:#Ennek az elemnek a címe egy szürke sávban fog megjelenni. Amennyiben nem ad meg címet, egy egyszerű vonal fog ott megjelenni. mme#:#type_top_link_item#:#Linkel mme#:#type_top_parent_item#:#Tartalmazza -mme#:#unable_to_render#:#Unable to show '%s' in '%s'.###26 08 2024 new variable -mob#:#mob_choose_from_pool#:#Choose from Media Pool -mob#:#mob_copyright#:#Copyright###29 10 2025 new variable -mob#:#mob_copyright_icon#:#Copyright Icon###29 10 2025 new variable -mob#:#mob_external_url#:#External URL -mob#:#mob_extract_preview_image#:#Extract Preview Image###26 08 2024 new variable +mme#:#unable_to_render#:#‘%s’ / ‘%s’ nem jeleníthető meg. +mob#:#mob_choose_from_pool#:#Választás médiagyűjteményből +mob#:#mob_copyright#:#Szerzői jog +mob#:#mob_copyright_icon#:#Szerzői jog ikonja +mob#:#mob_external_url#:#Külső URL +mob#:#mob_extract_preview_image#:#Előnézeti kép kicsomagolása mob#:#mob_file#:#Fájl mob#:#mob_file_could_not_be_uploaded#:#Fájl nem tölthető fel. mob#:#mob_general#:#Általános -mob#:#mob_image_extracted#:#Image has been extracted.###26 08 2024 new variable -mob#:#mob_internal_usages_in_object#:#Page Usages###29 10 2025 new variable +mob#:#mob_image_extracted#:#Az előnézeti képet sikeresen kicsomagolta. +mob#:#mob_internal_usages_in_object#:#Oldal felhasználásai mob#:#mob_language#:#Nyelv -mob#:#mob_last_update#:#Last Update###29 10 2025 new variable -mob#:#mob_media#:#Media###29 10 2025 new variable -mob#:#mob_media_objects_overview#:#Media Objects on Pages###29 10 2025 new variable -mob#:#mob_mime_type_not_allowed#:#The following mime types are not allowed at the destination.###29 07 2022 new variable -mob#:#mob_multi_srt_files#:#SRT-fájlok -mob#:#mob_no_extraction_possible#:#Sorry, it was not able to extract an image from the file.###26 08 2024 new variable +mob#:#mob_last_update#:#Utolsó módosítás +mob#:#mob_media#:#Média +mob#:#mob_media_objects_overview#:#Médiaobjektumok az oldalon +mob#:#mob_mime_type_not_allowed#:#A következő mime-típusok nem engedélyezettek a címzettnél. +mob#:#mob_multi_srt_files#:#Feliratfájlok +mob#:#mob_no_extraction_possible#:#A képet nem sikerült kicsomagolni a fájlból. mob#:#mob_no_fixed_size_map_editing#:#Térképterület használata előtt adja meg képének méretét. Ha a képét tartalomstílus vagy egyéb CSS szabály átméretezi, a térképterület nem fog illeszkedni. mob#:#mob_object#:#Objektum -mob#:#mob_please_select_pool#:#Bitte wählen Sie einen Medienpool aus.###26 08 2024 new variable -mob#:#mob_preview_picture#:#Preview Picture###26 08 2024 new variable -mob#:#mob_really_delete_srt#:#Biztos, hogy törli az alábbi SRT-fájlokat? -mob#:#mob_second#:#Second###26 08 2024 new variable -mob#:#mob_srt_files_deleted#:#A felirat fájlt töröltük. -mob#:#mob_srt_not_allowed#:#Files with a .srt suffix are currently not allowed to be uploaded. If you would like to use srt files, contact your system administrator.###26 08 2024 new variable -mob#:#mob_subtitle_file#:#Felirat fájl -mob#:#mob_subtitle_files#:#Felirat fájlok +mob#:#mob_please_select_pool#:#Kérem, válasszon ki egy médiagyűjteményt. +mob#:#mob_preview_picture#:#Előnézeti kép +mob#:#mob_really_delete_srt#:#Biztos, hogy törli az alábbi feliratfájlokat? +mob#:#mob_second#:#másodperc +mob#:#mob_srt_files_deleted#:#A feliratfájlt sikeresen törölte. +mob#:#mob_srt_not_allowed#:#A .vtt kiterjesztésű fájlok felöltése jelenleg nem megengedett. Kérem, keresse a rendszerüzemeltetőket. +mob#:#mob_subtitle_file#:#Feliratfájl +mob#:#mob_subtitle_files#:#Feliratfájlok mob#:#mob_subtitles#:#Feliratok -mob#:#mob_type_not_supported#:#Mime type not supported:###26 08 2024 new variable -mob#:#mob_upload_file#:#Upload File +mob#:#mob_type_not_supported#:#Mime-típus nem támogatott: +mob#:#mob_upload_file#:#Fájl feltöltése mob#:#mob_upload_multi_srt#:#ZIP-fájl feltöltése -mob#:#mob_upload_multi_srt_howto#:#A .zip fájl ne tartalmazzon mappát, egyik .srt fájl se legyen mappában. Az összes SRT-fájl vége legyen '_<nyelvi kód>.srt', ahol a nyelvi kód például hu, en, de. A fájlnév eleje célszerű, hogy a videófájl nevéhez illeszkedjen, például 'video.mp4' -> 'video_hu.srt'. +mob#:#mob_upload_multi_srt_howto#:#A .zip fájl ne tartalmazzon mappát, egyik .vtt fájl se legyen mappában. Az fájlnév vége legyen ‘_<nyelvi kód>.vtt’, ahol a nyelvi kód például hu, en, de. A fájlnév eleje célszerű, hogy a videófájl nevéhez illeszkedjen, például ‘video.mp4’ -> ‘video_hu.srt’. mob#:#mob_url#:#URL -mob#:#mob_url_info#:#Externe URL, z.B. Youtube oder Vimeo URL. -mob#:#mob_url_info1#:#External resource URL, allowed suffixes are:###26 08 2024 new variable -mob#:#mob_url_info_video#:#You may also refer to a Youtube or Vimeo URL.###26 08 2024 new variable -mob#:#mob_usages_in_media_pools#:#Media Pool Usages###29 10 2025 new variable -mob#:#mob_usages_in_other_objects#:#Other Usages###29 10 2025 new variable +mob#:#mob_url_info#:#Külső erőforrás URL-je, például Youtube vagy Vimeo URL. +mob#:#mob_url_info1#:#Külső erőforrás URL-je, az engedélyzett utótagok: +mob#:#mob_url_info_video#:#Hivatkozhat Youtube vagy Vimeo URL-re is. +mob#:#mob_usages_in_media_pools#:#Médiagyűjtemény felhasználása +mob#:#mob_usages_in_other_objects#:#További felhasználások mst#:#mst_cert_issued_on#:#Kiállítás dátuma -mst#:#mst_courses_of#:#%s beiratkozásai +mst#:#mst_courses_of#:#%s kurzustagságai mst#:#mst_download_certificate#:#Tanúsítvány letöltése mst#:#mst_list_certificates#:#Tanúsítványok mst#:#mst_list_competences#:#Kompetenciák -mst#:#mst_list_courses#:#Beiratkozások +mst#:#mst_list_courses#:#Kurzustagságok mst#:#mst_list_users#:#Munkatársak listája mst#:#mst_memb_status_registered#:#Regisztrált -mst#:#mst_memb_status_requested#:#Kérelem alatt +mst#:#mst_memb_status_requested#:#Elbírálás alatt mst#:#mst_memb_status_waitinglist#:#Várólista mst#:#mst_my_staff#:#Munkatárs mst#:#mst_opt_all#:#Összes @@ -12883,13 +12951,13 @@ mst#:#mst_please_select_course#:#Kérem, válasszon egy kurzust. mst#:#mst_profile_fulfilled#:#Teljesített mst#:#mst_profile_not_fulfilled#:#Még nem teljesített mst#:#mst_select_course#:#Válasszon kurzust -mst#:#mst_show_courses#:#Felvételek +mst#:#mst_show_courses#:##Kurzustagságok news#:#lso_news_online_title#:#A tanulási sorban egy új online objektum! news#:#lso_news_online_txt#:#A tanulási sorban egy új objektumot tettek elérhetővé. news#:#new_test_online#:#A teszt online lett. news#:#news_1_file_created#:#Egy fájlt sikeresen létrehozott. news#:#news_1_file_updated#:#Egy fájlt sikeresen frissített. -news#:#news_1_postings#:#One post has been added.###26 08 2024 new variable +news#:#news_1_postings#:#Egy új hozzászólás érkezett. news#:#news_add_news#:#Hír létrehozása news#:#news_all_items#:#Hírek az összes kedvenc elemhez news#:#news_allow_longer_periods#:#Hosszabb időszak engedélyezése @@ -12900,7 +12968,7 @@ news#:#news_attached_to#:#Ehhez kapcsolva: news#:#news_block_information#:#A Hírek blokk megjelenít minden olyan hírt, amely a Kedvencek elemeihez kapcsolódik. news#:#news_block_news_for_context#:#Hírek news#:#news_cache#:#Hírek gyorsítótárazása (perc) -news#:#news_cache_info#:#Hírblokk frissítése x percenként. A '0' azt jelenti, mindig. Magasabb érték növeli a teljesítményt, de lehet, hogy a hírek nem elérhető helyre linkelnek. +news#:#news_cache_info#:#Hírblokk frissítése x percenként. A ‘0’ azt jelenti, mindig. Magasabb érték növeli a teljesítményt, de lehet, hogy a hírek nem elérhető helyre linkelnek. news#:#news_default_visibility#:#Alapértelmezett elérés news#:#news_edit_news_settings#:#Beállítások módosítása news#:#news_enable_internal_news#:#Belső hírek engedélyezése @@ -12908,25 +12976,25 @@ news#:#news_enable_internal_news_info#:#Hírblokk aktiválása kategóriákhoz, news#:#news_enable_internal_rss#:#RSS engedélyezése belső hírekhez news#:#news_enable_internal_rss_info#:#Hírek engedélyezése RSS-ben. Ezek a hírek elérhetők lesznek a rendszeren kívülről, bejelentkezés nélkül. news#:#news_enable_private_feed#:#Személyes RSS-hírforrás engedélyezése -news#:#news_enable_private_feed_info#:#Ha be van kapcsolva, a nyilvános és a személyes hírek az ILIAS-on kívüli személyes RSS-ben is megkaphatók. A hitelesítés jelszóhoz között. +news#:#news_enable_private_feed_info#:#A nyilvános és a személyes hírek az ILIAS-on kívüli személyes RSS-ben is megkaphatók. A hitelesítés jelszóhoz között. news#:#news_feed_url#:#Hírforrás URL-je -news#:#news_feed_url_for#:#Hírforrás URL-je ehhez: '%s' +news#:#news_feed_url_for#:#Hírforrás URL-je ehhez: ‘%s’ news#:#news_first_letter_of_word_notification#:#É news#:#news_get_feed_info#:#Ez egy személyes hírforrás URL-je. A hírforrás csak olyan híreket tartalmaz, amelyeket a szerző nyilvánosnak minősített. A hírforrást nem védi semmilyen hitelesítési eljárás. Ne ossza meg másokkal ezt az URL-t! news#:#news_get_feed_title#:#Személyes hírforrás URL-je news#:#news_get_feed_url#:#Hírforrás URL-jének kérése -news#:#news_get_priv_feed_info#:#Ez egy személyes hírforrás URL-je. A hírforrás olyan híreket tartalmaz, amelyeket a szerző személyesnek és nyilvánosnak minősített. Ezt a hírforrást jelszó védi, amely a 'Beállítások' alatt módosítható. Ne ossza meg senkivel ezt az URL-t! Cserélje le -a jelszót- ezen az URL-en az ön hírforrásjelszavával! +news#:#news_get_priv_feed_info#:#Ez egy személyes hírforrás URL-je. A hírforrás olyan híreket tartalmaz, amelyeket a szerző személyesnek és nyilvánosnak minősített. Ezt a hírforrást jelszó védi, amely a ‘Beállítások’ alatt módosítható. Ne ossza meg senkivel ezt az URL-t! Cserélje le -a jelszót- ezen az URL-en az ön hírforrásjelszavával! news#:#news_get_priv_feed_title#:#Személyes URL-forrás news#:#news_hide_news_block#:#Hírblokkok elrejtése -news#:#news_hide_news_block_info#:#Blokkok elrejtése tanulói nézetben. A hírblokkok csak az írási joggal rendelkező felhasználók számára lesznek láthatóak. -news#:#news_hide_news_date#:#Kezdő dátum +news#:#news_hide_news_block_info#:#Blokkok elrejtése tanulói nézetben. A hírblokkok csak az írási joggal rendelkező felhasználók számára lesznek láthatók. +news#:#news_hide_news_date#:#Kezdő dátum/időpont news#:#news_hide_news_per_date#:#Későbbi hírek megjelenítése, mint -news#:#news_hide_news_per_date_info#:#Csak azok a hírek lesznek megjelenítve, amelyek újabbak egy megadott dátumnál. +news#:#news_hide_news_per_date_info#:#Csak a megadott dátumnál újabb hírek jelennek meg. news#:#news_inactive_private_feed_info#:#Az Ön privát hírcsatornája nincs engedélyezve. Kérem, adjon meg egy jelszót a beállításokban. news#:#news_internal_news#:#Hírek news#:#news_keep_minimal_x_items#:#Legalább x elem megtartása news#:#news_keep_minimal_x_items_info#:#Elérhető régi elemek száma, az RSS-életidőt figyelmen kívül hagyva. -news#:#news_loading_news#:#Hírek töltése... +news#:#news_loading_news#:#Hírek töltése… news#:#news_media#:#Mediafájl news#:#news_new_comments#:#Új hozzászólás news#:#news_new_reactions#:#Új reakciók @@ -12943,9 +13011,10 @@ news#:#news_news_item_visibility_info#:#A nyilvános hírek elérhetők bejelent news#:#news_news_items#:#hír news#:#news_no_js_click_here#:#Ha nem jelennek meg a hírek, kattintson ide! news#:#news_no_news_items#:#Nincsenek elérhető hírek. +news#:#news_not_available#:#El nem érhető hírek news#:#news_notifications#:#Értesítések news#:#news_notifications_public#:#Nyilvános értesítések -news#:#news_notifications_public_info#:#Ha be van kapcsolva, a személyes RSS-csatornák elérhetők az ILIAS-on kívül is. Tehát így bejelentkezés nélkül is elérhetővé teszi az értesítéseket. +news#:#news_notifications_public_info#:#A személyes RSS-csatornák elérhetők az ILIAS-on kívül is. Tehát így bejelentkezés nélkül is elérhetővé teszi az értesítéseket. news#:#news_nr_of_items#:#Objektumonkénti hírek max. száma news#:#news_nr_of_items_info#:#Objektumhoz (például fájlhoz vagy tananyaghoz) tartozó hírek maximális száma. Vegye figyelembe, hogy egy tárolóobjektum (például kategória, kurzus) több alobjektumot is tartalmazhat, és az alobjektumok is tartalmazhatnak híreket. news#:#news_pd_period#:#Műszerfalon megjelenő hírek időszaka @@ -12957,7 +13026,7 @@ news#:#news_period_x_days#:#Utolsó %s nap news#:#news_period_x_months#:#Utolsó %s hónap news#:#news_period_x_weeks#:#Utolsó %s hét news#:#news_public_feed#:#Extra RSS-csatorna -news#:#news_public_feed_info#:#Ha be van kapcsolva, külön RSS-csatorna lesz ehhez a médiasugárzáshoz. +news#:#news_public_feed_info#:#Saját RSS-csatornája lesz ennek a médiasugárzásnak. news#:#news_really_delete_news#:#Biztos, hogy törli ezt a hírt? news#:#news_rss#:#RSS news#:#news_rss_period#:#RSS-időhossz @@ -12967,8 +13036,8 @@ news#:#news_rss_title_format_obj_news#:#Objektumcím - hírek címsora news#:#news_settings#:#Hírek beállításai news#:#news_sorry_not_accessible_anymore#:#Sajnáljuk, ez már nem érhető el. news#:#news_time_period#:#Időszak -news#:#news_timline_add_entries_info#:#Jelenleg egy hír sincs, kattintson a 'Létrehozása' gombra. -news#:#news_timline_no_entries#:#No news have been found.###26 08 2024 new variable +news#:#news_timline_add_entries_info#:#Jelenleg egy hír sincs, kattintson a ‘Létrehozása’ gombra. +news#:#news_timline_no_entries#:#Egy hír sincs. news#:#news_visibility_public#:#Nyilvános news#:#news_visibility_users#:#Bejelentkezett felhasználók news#:#news_x_files_created#:#%s fájl elkészült. @@ -12980,122 +13049,126 @@ news#:#priv_feed_settings#:#Személyes hírforrás beállításai note#:#note_comment_notification_link#:#Link note#:#note_comment_notification_reason#:#Ezt az üzenetet azért kapta, mert felhasználói fiókja szerepel a Rendszerbeállítások » Műszerfal alatt az összes megjegyzésről értesítendők között. note#:#note_comment_notification_salutation#:#Tisztelt %s, -note#:#note_comment_notification_subject#:#Hozzászólás született itt: '%s' -note#:#note_comment_notification_subjectc#:#Hozzászólást módosítottak itt: '%s' +note#:#note_comment_notification_subject#:#Hozzászólás született itt: ‘%s’ +note#:#note_comment_notification_subjectc#:#Hozzászólást módosítottak itt: ‘%s’ note#:#note_comment_notification_user_has_written#:#%s írta: note#:#note_comments_notification#:#Az összes hozzászólásról általános értesítés note#:#note_comments_notification_info#:#A felhasználói fiókok vesszővel elválasztott felsorolása, akik az összes hozzászólásról értesítést kapnak note#:#note_enable_comments#:#Hozzászólások bekapcsolása note#:#note_enable_comments_del_tutor#:#A tutorok törlhetik bármelyik hozzászólást -note#:#note_enable_comments_del_tutor_info#:#A 'Beállítások módosítása' jogosultsággal rendelkező felhasználók törölhetik az objektumban lévő bármelyik hozzászólást. -note#:#note_enable_comments_del_user#:#A szerzők törlhetik hozzászólásaikat -note#:#note_enable_comments_del_user_info#:#Comments can be deleted by the person who created them.###26 08 2024 new variable -note#:#note_enable_comments_export_info#:#This option enables comments export for content objects like portfolio, blog and wiki. +note#:#note_enable_comments_del_tutor_info#:#A ‘Beállítások módosítása’ jogosultsággal rendelkező felhasználók törölhetik az objektumban lévő bármelyik hozzászólást. +note#:#note_enable_comments_del_user#:#A szerzők törlhetik a saját hozzászólásaikat +note#:#note_enable_comments_del_user_info#:#A hozzászólásokat azok törölhetik, akik létrehozták. +note#:#note_enable_comments_export_info#:#Ez a lehetőséggel tartalomobjektumoknál (portfólió, blog és wiki) a hozzászólások is exportálódnak. note#:#note_enable_notes#:#Jegyzetek bekapcsolása -note#:#note_html_export_include_comments#:#Should comments be included in the export? +note#:#note_html_export_include_comments#:#A hozzászólásokat is exportálja? notes#:#comments_feature_currently_not_activated_for_object#:#Ehhez az objektumhoz jelenleg nincsenek engedélyezve nyilvános megjegyzések. notes#:#note_add_comment#:#Megjegyzés létrehozása -notes#:#note_add_message#:#Add Message###26 08 2024 new variable +notes#:#note_add_message#:#Üzenet létrehozása notes#:#note_add_note#:#Jegyzet létrehozása -notes#:#note_content_removed#:#Tartalom eltávolítva. -notes#:#note_text#:#Text###29 07 2022 new variable +notes#:#note_content_removed#:#Ezt a tartalmat eltávolították. +notes#:#note_text#:#Szöveg notes#:#note_update_comment#:#Megjegyzés módosítása -notes#:#note_update_message#:#Update Message###26 08 2024 new variable +notes#:#note_update_message#:#Üzenet módosítása notes#:#note_update_note#:#Jegyzetet frissítette -notes#:#note_without_object#:#Hivatkozás nélkü +notes#:#note_without_object#:#Hivatkozás nélkül notes#:#notes_activate_comments#:#Nyilvános megjegyzések engedélyezése notes#:#notes_add_comment#:#Megjegyzés létrehozása notes#:#notes_add_edit_comment#:#Hozzászólás létrehozása/módosítása -notes#:#notes_add_edit_message#:#Add/Edit Message###26 08 2024 new variable -notes#:#notes_add_edit_note#:#Add/Edit Note###26 08 2024 new variable +notes#:#notes_add_edit_message#:#Üzenet hozzáadása/módosítása +notes#:#notes_add_edit_note#:#Megjegyzés létrehozása/módosítása notes#:#notes_all_comments#:#Összes megjegyzés notes#:#notes_comment#:#Megjegyzés -notes#:#notes_comment_deleted#:#A hozzászólást törölték. +notes#:#notes_comment_deleted#:#A megjegyzést törölték. notes#:#notes_comments#:#Nyilvános megjegyzések notes#:#notes_comments_deleted#:#A hozzászólásokat törölték. notes#:#notes_deactivate_comments#:#Nyilvános megjegyzések tiltása -notes#:#notes_delete_comment#:#Do you really want to delete this comment?###29 07 2022 new variable -notes#:#notes_delete_message#:#Do you really want to delete this message?###26 08 2024 new variable -notes#:#notes_delete_note#:#Do you really want to delete this note?###29 07 2022 new variable +notes#:#notes_delete_comment#:#Biztos, hog törli ezt a megjegyzést? +notes#:#notes_delete_message#:#Biztos, hog törli ezt az üzenetet? +notes#:#notes_delete_note#:#Biztos, hog törli ezt a jegyzetet? notes#:#notes_hide_comments#:#Megjegyzések elrejtése -notes#:#notes_html_export#:#HTML Export###29 07 2022 new variable +notes#:#notes_html_export#:#HTML export notes#:#notes_latest_comment#:#Utolsó hozzászólás -notes#:#notes_latest_message#:#Latest Message###26 08 2024 new variable -notes#:#notes_message_author_counterpart#:#Respondent###26 08 2024 new variable -notes#:#notes_message_author_you#:#You###26 08 2024 new variable -notes#:#notes_messages#:#Messages###26 08 2024 new variable +notes#:#notes_latest_message#:#Utolsó üzenet +notes#:#notes_message_author_counterpart#:#Válaszadó +notes#:#notes_message_author_you#:#Én +notes#:#notes_message_deleted#:#Az üzenetet sikeresen törölte. +notes#:#notes_messages#:#Uzenetek notes#:#notes_my_comments#:#Az én megjegyzéseim notes#:#notes_no_comments#:#Még egy megjegyzés sem érkezett. -notes#:#notes_no_comments_found#:#No comments found that match your seach criteria.###29 07 2022 new variable -notes#:#notes_no_messages#:#No messages have been attached yet.###26 08 2024 new variable -notes#:#notes_no_messages_found#:#No messages found that match your seach criteria.###26 08 2024 new variable -notes#:#notes_no_notes#:#No notes have been attached yet.###29 07 2022 new variable -notes#:#notes_no_notes_found#:#No notes found that match your seach criteria.###29 07 2022 new variable +notes#:#notes_no_comments_found#:#Nincs a keresési feltételnek megfelelő megjegyzés. +notes#:#notes_no_messages#:#Még egy üzenet sincs csatolva +notes#:#notes_no_messages_found#:#Egy üzenet sem felel meg a keresési feltételnek. +notes#:#notes_no_notes#:#Még egy jegyzetet sem csatoltak. +notes#:#notes_no_notes_found#:#Nincs a keresési feltételnek megfelelő jegyzet. notes#:#notes_note_deleted#:#A jegyzetet sikeresen törölte. notes#:#notes_notes_deleted#:#A jegyzeteket sikeresen törölte. -notes#:#notes_origin#:#Origin###29 07 2022 new variable +notes#:#notes_origin#:#Eredeti notes#:#notes_public_comments#:#Nyilvános megjegyzések notes#:#notes_show_comments#:#Megjegyzések megjelenítése notes#:#notes_sort_asc#:#Növekvő sorrend notes#:#notes_sort_desc#:#Csökkenő sorrend -notes#:#notes_text#:#Text###29 07 2022 new variable +notes#:#notes_text#:#Szöveg noti#:#noti_activate_notification#:#Értesítés bekapcsolása noti#:#noti_deactivate_notification#:#Értesítés kikapcsolása noti#:#noti_notification_activated#:#Az értesítőt sikeresen bekapcsolta noti#:#noti_notification_deactivated#:#Az értesítőt sikeresen kikapcsolta -notifications#:#push_notification#:#Push Notifications###29 10 2025 new variable -notifications_adm#:#enable_osd#:#Enable Toasts###26 08 2024 new variable -notifications_adm#:#enable_osd_desc#:#If enabled, users are notified by a pop-up about new notifications.###26 08 2024 new variable -notifications_adm#:#enable_push#:#Enable Push Notifications###29 10 2025 new variable -notifications_adm#:#enable_push_desc#:#If enabled, users are notified by push notifications. User can change this behaviour within their user settings.###29 10 2025 new variable -notifications_adm#:#notification_settings#:#Notification Settings###26 08 2024 new variable -notifications_adm#:#osd_error_refresh_interval_too_small#:#The Refresh Interval has to be at least than 3000 miliseconds.###26 08 2024 new variable -notifications_adm#:#osd_interval#:#Refreshinterval###26 08 2024 new variable -notifications_adm#:#osd_interval_desc#:#Polling interval for checking of new notifications in miliseconds. A lower number will notify the user more quickly but increases the number of requests the web server must handle.###26 08 2024 new variable -notifications_adm#:#osd_play_sound#:#Play a Sound###26 08 2024 new variable -notifications_adm#:#osd_play_sound_desc#:#Play a sound when receiving a new notficiation.###26 08 2024 new variable -notifications_adm#:#osd_settings#:#Toasts###26 08 2024 new variable -notifications_adm#:#push_client_already_used#:#Push notifications are already used by another user for this client.###29 10 2025 new variable -notifications_adm#:#push_client_edge_case#:#The Edge Browser might have deactivated notifications without your consent. Enter your browser settings to reactivate them.###29 10 2025 new variable -notifications_adm#:#push_client_inactive#:#Push notifications are disabled for this website. Open your browser settings to activate them.###29 10 2025 new variable -notifications_adm#:#push_client_ios_case#:#If you are using IOS (Iphone, Ipad, Ipod) push notifications for websites are not supported. Create an access via web app to enable them.###29 10 2025 new variable -notifications_adm#:#push_settings#:#Push Notifications###29 10 2025 new variable -notifications_adm#:#push_subscription_successfull#:#Push Notifications activation successful###29 10 2025 new variable -notifications_adm#:#push_subscription_successfull_desc#:#This is a dummy notification to verify the successful activation of push notifications.###29 10 2025 new variable +notifications#:#push_notification#:#Push értesítések +notifications_adm#:#available_providers#:#Elérhető szolgáltatók +notifications_adm#:#client_settings#:#Kliens beállításai +notifications_adm#:#enable_osd#:#Képernyő-értesítések bekapcsolása +notifications_adm#:#enable_osd_desc#:#A felhasználók értesítése felugró ablakban. +notifications_adm#:#enable_push#:#Push értesítések bekapcsolása +notifications_adm#:#enable_push_desc#:#Ha be van kapcsolva, a felhasználók push értesítéseket kapnak. A felhasználó ezt a saját felhasználói beállításaiban módosíthatja. +notifications_adm#:#notification_settings#:#Értesítés beállításai +notifications_adm#:#osd_error_refresh_interval_too_small#:#A frissítési időköz legalább 3000 ezredmásodperc lehet. +notifications_adm#:#osd_interval#:#Frissítési időköz +notifications_adm#:#osd_interval_desc#:#Új értesítések ellenőrzési ideje másodpercekben. Az alacsonyabb értéke gyorsabb értesítést jelent, de növeli a kérések számát és az adatforgalmat. +notifications_adm#:#osd_play_sound#:#Hang lejátszása +notifications_adm#:#osd_play_sound_desc#:#Új értesítéskor hangot játszunk le. +notifications_adm#:#osd_settings#:#Képernyőértesítések +notifications_adm#:#push_client_already_used#:#Push értesítéseket már egy másik felhasználó használja ehhez a klienshez. +notifications_adm#:#push_client_edge_case#:#Lehetséges, hogy az Edge böngésző az Ön beleegyezése nélkül kikapcsolta az értesítéseket. A böngésző beállításaiban aktiválhatja őket újra. +notifications_adm#:#push_client_inactive#:#Push értesítések ki vannak kapcsolva ezen a weboldalon. Nyissa meg a böngésző beállításait az aktiváláshoz. +notifications_adm#:#push_client_ios_case#:#A push értesítéseket az IOS (Iphone, Ipad, Ipod) nem támogatja. Hozzon létre egy hozzáférést webes alkalmazáson keresztül. +notifications_adm#:#push_settings#:#Push értesítések +notifications_adm#:#push_subscription_successfull#:#A push értesítéseket sikeresen bekapcsolta. +notifications_adm#:#push_subscription_successfull_desc#:#Ez egy próbaértesítés, hogy ellenőrizze a push értesítések bekapcsolását. +notifications_adm#:#user_settings#:#Felhasználó beállítások obj#:#activation_visible_when_disabled#:#Láthatóság -obj#:#activation_visible_when_disabled_info#:#Ha bejelöli, az elérhetőségi időszakon kívüli is látható, de ekkor a tartalma nem érhető el. -obj#:#availability_period_changed#:#The availability period for the selected objects has been changed successfully.###26 08 2024 new variable -obj#:#available_languages#:#Available Languages###29 10 2025 new variable +obj#:#activation_visible_when_disabled_info#:#Az objektum a megadott időszakon kívül is látható, de nem nyitható meg. +obj#:#availability_period_changed#:#A kiválasztott objektumok elérhetőségi időszakát sikeresen módosította. +obj#:#available_languages#:#Elérhető nyelvek obj#:#cont_filter_empty#:#Az objektumok megtekintéséhez használja a szűrőt. obj#:#cont_skll_published#:#Az összes hozzárendelést sikeresen közzétette. obj#:#cont_skll_published_some_not#:#Az összes megadott hozzárendelést sikeresen közzétette. Néhány felhasználóhoz nincs kompetencia rendelve, náluk nincs mit közzétenni. -obj#:#copy_container_page_no_label#:#Don't Copy Content Page###26 08 2024 new variable -obj#:#copy_container_page_yes_byline#:#The content page and corresponding style settings of the source object will be copied to this object. Pre-existing page elements will be overwritten.###26 08 2024 new variable -obj#:#copy_container_page_yes_label#:#Copy Content Page###26 08 2024 new variable +obj#:#copy_container_page_no_label#:#A tartalomoldalt nem másolja +obj#:#copy_container_page_yes_byline#:#A tartalomoldal és a forrásobjektum megfelelő stílusbeállításai átmásolódnak ebbe az objektumba. A már meglévő oldalelemek felülíródnak. +obj#:#copy_container_page_yes_label#:#Tartalomoldal másolása obj#:#custom_icon#:#Egyéni ikon -obj#:#default_base_lang_not_deletable#:#Neither the base language nor the default language can be deleted.###29 10 2025 new variable -obj#:#edit_availability_period#:#Availability Period###26 08 2024 new variable -obj#:#edit_language#:#Edit Language###29 10 2025 new variable +obj#:#default_base_lang_not_deletable#:#Sem az alapnyelv, sem az alapértelmezett nyelv nem törölhető. +obj#:#edit_availability_period#:#Elérhetőségi időszak +obj#:#edit_language#:#Nyelv módosítása obj#:#edit_questions#:#Kérdések módosítása -obj#:#make_default_language#:#Make Default Language###29 10 2025 new variable -obj#:#missing_migration#:#You cannot edit information on this page until all migrations have been run. Please contact your system administrator.###29 10 2025 new variable -obj#:#multiple_reference_deletion_info#:#Further references exist for the following objects.###29 10 2025 new variable +obj#:#make_default_language#:#Beállítás alapértelmezett nyelvként +obj#:#missing_migration#:#Az ezen az oldalon található információkat csak az összes migráció futtatása után szerkesztheti. Kérjük, vegye fel a kapcsolatot a rendszergazdával. +obj#:#multiple_reference_deletion_info#:#További hivatkozások léteznek a következő objektumokhoz. obj#:#multiple_selection#:#Többszörös kiválasztás -obj#:#no_objects_selected#:#At least one object needs to be selected.###26 08 2024 new variable +obj#:#no_objects_selected#:#Legalább egy objektumot ki kell választania obj#:#obj_activate_content_lang#:#Lapszerkesztés fordításának bekapcsolása obj#:#obj_activate_multilang#:#Többnyelvűség bekapcsolása obj#:#obj_activation#:#Aktiválás obj#:#obj_activation_list_gui#:#Elérhetőség -obj#:#obj_add_language#:#Add Language###29 10 2025 new variable +obj#:#obj_add_language#:#Nyelv hozzáadása obj#:#obj_additional_langs#:#További nyelvek obj#:#obj_base_lang#:#Elsődleges nyelv -obj#:#obj_conf_delete_lang#:#Do you really want to stop the presentation of title and description in these languages?###26 08 2024 new variable +obj#:#obj_conf_delete_lang#:#Biztos, hogy megszünteti, hogy a cím és a leírás ezeken a nyelveken jelenljen meg? obj#:#obj_cont_transl_deactivated#:#Lapszerkesztés fordítása ki van kapcsolva van. obj#:#obj_copy_progress#:#Másolási folyamat -obj#:#obj_copy_progress_estimate#:#Estimating duration...###29 10 2025 new variable -obj#:#obj_copy_progress_failure#:#Copying failed.###29 10 2025 new variable -obj#:#obj_copy_progress_success#:#Copied successfully.###29 10 2025 new variable -obj#:#obj_copy_progress_to#:#Copying to %s###29 10 2025 new variable +obj#:#obj_copy_progress_estimate#:#Becsült időtartam… +obj#:#obj_copy_progress_failure#:#A másolás sikertelen. +obj#:#obj_copy_progress_success#:#A másolást sikeresen végrehajtotta. +obj#:#obj_copy_progress_to#:#Másolás ide: %s obj#:#obj_deactivate_content_lang#:#Többnyelvűség kikapcsolása obj#:#obj_deactivate_content_transl_conf#:#Biztos, hogy kikapcsolja a többnyelvűséget? Csak a fő nyelv tartalma marad meg. obj#:#obj_deactivate_multilang#:#Többnyelvűség kikapcsolása @@ -13104,14 +13177,14 @@ obj#:#obj_fallback_lang#:#Alapértelmezett nyelv obj#:#obj_features#:#További tulajdonságok obj#:#obj_import_file_error#:#Ez a fájl nem importálható. Ellenőrizze, hogy ez tényleg egy ugyanolyan objektum ILIAS exportfájlja (XML export). A fájl nevét exportálás után nem szabad módosítani. Hibaüzenet: obj#:#obj_insert_into_clipboard#:#Tegyük a vágólapra -obj#:#obj_inserted_clipboard#:#Objektumok a vágólapra mozgatva. -obj#:#obj_master_lang#:#Master Language###29 10 2025 new variable +obj#:#obj_inserted_clipboard#:#Az objektumo(ka)t sikeresen a vágólapra tette. +obj#:#obj_master_lang#:#Elsődleges nyelv obj#:#obj_more_translations#:#További fordítások obj#:#obj_multilang_deactivated#:#Többnyelvűség kikapcsolva. -obj#:#obj_multilang_title_descr_only#:#A fordítás csak a címre és a leírásra van bekapcsolva. A lapszerkesztés ('Tartalom/Oldal testreszabása') fordításához további aktiválásokra van szükség. +obj#:#obj_multilang_title_descr_only#:#A fordítás csak a címre és a leírásra van bekapcsolva. A lapszerkesztés (‘Tartalom/Oldal testreszabása’) fordításához további aktiválásokra van szükség. obj#:#obj_multilinguality#:#Többnyelvűség -obj#:#obj_orgunit_positions#:#Hozzáférés-szabályozás a szervezeti egység pozíciói alapján -obj#:#obj_orgunit_positions_info#:#Ha be van kapcsolva, további hozzáférési szabályok hozhatóak létre a szervezeti egységek pozíciói alapján. +obj#:#obj_orgunit_positions#:#Jogosultságkezelés a szervezeti egység pozíciói alapján +obj#:#obj_orgunit_positions_info#:#További hozzáférési szabályok hozhatók létre a szervezeti egységek pozíciói alapján. obj#:#obj_permission_settings#:#Jogosultságok beállítása obj#:#obj_presentation#:#Megjelenítés obj#:#obj_select_base_lang#:#Válasszon elsődleges nyelvet. A jelenlegi tartalom a elsődleges nyelvhez lesz hozzárendelve. @@ -13122,37 +13195,37 @@ obj#:#obj_show_header_actions#:#Fejlécműveletek megjelenítése obj#:#obj_show_title_and_icon#:#A cím és az ikon is jelenjen meg obj#:#obj_target_location#:#Célhely obj#:#obj_tile_image#:#Csempekép -obj#:#obj_tile_image_info#:#A csempeképeket akkor használjuk, amikor a tároló (kurzus, mappa, csoport, ...) megjelenítési módja csempékre van állítva. +obj#:#obj_tile_image_info#:#Ez a kép az objektum miniatűr-stílusú képe (csempeképe), az objektumot abban a tárolóban ábrázolja (például kategória, mappacsoport stb.), amelyben az megtalálható, és a tároló tartalmának megjelenítése nem felsorolásra, hanem csempére van állítva. (A teljesítménnyel kapcsolatos problémák elkerülése érdekében csak 72 dpi felbontású és 1000 px-nél kisebb szélességű fájlokat töltsön fel.) obj#:#obj_tool_booking#:#Erőforrásfoglalás obj#:#obj_tool_booking_info#:#Foglalásgyűjtemények használata (például termek foglalásához). obj#:#obj_tool_ext_mail_subject_prefix#:#E-mail tárgyának előtagja obj#:#obj_tool_ext_mail_subject_prefix_info#:#Ez a rövid szöveg jelenik meg az e-mail tárgyának elején a könnyebb beazonosíthatóság kedvéért. obj#:#obj_tool_setting_badges#:#Érdemérmek -obj#:#obj_tool_setting_badges_info#:#Ha be van kapcsolva, az érdemérmek kezelése és használata elérhető. +obj#:#obj_tool_setting_badges_info#:#Az érdemérmek kezelésének, valamint megszerzésének vagy odaítélésének engedélyezése ezen az objektumon belül. obj#:#obj_tool_setting_booking#:#Erőforrásfoglalás obj#:#obj_tool_setting_filter#:#Szűrés obj#:#obj_tool_setting_filter_empty#:#Üres szűrő obj#:#obj_tool_setting_filter_empty_info#:#Az összes elem jelenjen meg, amikor a szűrő üres. -obj#:#obj_tool_setting_filter_info#:#A szűrés a tartalom fülön fog megjelenni. -obj#:#obj_tool_setting_info_tab#:#Információ fül -obj#:#obj_tool_setting_info_tab_info#:#Az 'Információ' fül látszódjon. +obj#:#obj_tool_setting_filter_info#:#A szűrés a tartalom lapon fog megjelenni. +obj#:#obj_tool_setting_info_tab#:#Információ lap +obj#:#obj_tool_setting_info_tab_info#:#Az ‘Információ’ lap látszódjon. obj#:#obj_tool_setting_skills#:#Kompetenciák obj#:#obj_tool_setting_skills_info#:#Aktiválja a kompetenciamenedzsmentet és a kompetenciák tagokhoz rendelését. obj#:#obj_tool_setting_tag_cloud#:#Címkefelhő -obj#:#obj_tool_setting_tag_cloud_info#:#'Címkefelhő' blokk megjelenik a 'Tartalom' fül alatt. +obj#:#obj_tool_setting_tag_cloud_info#:#‘Címkefelhő’ blokk megjelenik a ‘Tartalom’ lapon. obj#:#obj_tool_setting_taxonomies#:#Taxonómiák -obj#:#obj_tool_setting_taxonomies_info#:#Taxonomies allow the filtering of objects. They are created in the "Taxonomy" sub-tab in the "Settings" tab.###29 10 2025 new variable +obj#:#obj_tool_setting_taxonomies_info#:#A taxonómiák objektumok szűrését teszik lehetővé. A ‘Beállítások’ lap ‘Taxonómia’ allapján találhatók. obj#:#obj_tool_setting_use_news#:#Hírek -obj#:#obj_tool_setting_use_news_info#:#Hírblokk, illetve idővonal nézet bekapcsolása. +obj#:#obj_tool_setting_use_news_info#:#Hírblokk, illetve idővonal nézet bekapcsolása. Amennyiben aktív, a felhasználók értesítést kérhetnek a módosulásról. obj#:#obj_tool_setting_use_news_open_settings#:#Beállítások megnyitása obj#:#obj_user_decides_notification#:#A tagoknak saját maguknak kell aktiválniuk az értesítéseket obj#:#obj_user_not_disable_not#:#A tagok nem kapcsolhatják ki az értesítéseket -obj#:#online_input_byline#:#The object has been published and can be accessed by anyone with read access. Other access prerequisites or time-based access restrictions may still apply. This settings applies to the object wherever it is used in the repository.###26 08 2024 new variable -obj#:#select_import_type_info#:#The type of the object in the file to be imported cannot be determined automatically. The file was probably renamed. Please select the type of object in the file.###29 10 2025 new variable -obj#:#select_object_type#:#Select Object Type###26 08 2024 new variable +obj#:#online_input_byline#:#Az objektumot közzétették, így akinek olvasási joga van hozzá, hozzáféhet. Más elérhetőségi feltételek vagy időalapú hozzáférési korlátozások továbbra is érvényesek. Ez a beállítás az objektumra vonatkozik, függetlenül attól, hogy hol található meg a Tartalomtáron belül +obj#:#select_import_type_info#:#A fájlból nem állapítható meg automatikusan az importálandó objektum típusa. Lehet, hogy a fájlt átnevezték. Kérem, válassza ki a megfelelő típust. +obj#:#select_object_type#:#Kiválasztott objektumtípusok obj#:#svy_results#:#Végeredmények -obj#:#unequal_items_for_availability_period_message#:#You have selected items with different availability periods. Overwrite existing settings below or cancel action to keep current availability periods.###26 08 2024 new variable -obj#:#user_owns_no_objects#:#No Repository Objects Available###26 08 2024 new variable +obj#:#unequal_items_for_availability_period_message#:#Különböző elérhetőségi időszakú elemeket választott ki. Vagy írja felül lejjebb a meglévő beállításokat, vagy törölje a műveletet a jelenlegi elérhetőségi időszakok megtartásához. +obj#:#user_owns_no_objects#:#Egy objektum sincs objref#:#objref_custom_title#:#Egyéni cím objref#:#objref_edit_ref#:#Forrás objref#:#objref_edit_title#:#Címbeállítások @@ -13181,30 +13254,28 @@ orgu#:#import_terminated_with_warnings#:#Az import figyelmeztetésekkel futott l orgu#:#import_xml_file#:#Importálás dátuma orgu#:#local_other_roles#:#%s egyéb szerepei orgu#:#local_staff#:#%s emberei -orgu#:#msg_assignment_to_employee_done#:#A 'Beosztott' szerephez a hozzárendelés sikeres -orgu#:#msg_confirm_d_ua#:#Biztos, hogy hozzárendeli ezeket a személyeket szervezeti egységeik 'Beosztott' pozíciójához? +orgu#:#msg_assignment_to_employee_done#:#A ‘Beosztott’ szerepkörhöz a hozzárendelés sikeres +orgu#:#msg_confirm_d_ua#:#Biztos, hogy hozzárendeli ezeket a személyeket szervezeti egységeik ‘Beosztott’ pozíciójához? orgu#:#msg_confirm_deletion#:#Biztos, hogy törli az alábbi pozíciókat? -orgu#:#msg_confirm_remove_user#:#Biztos, hogy eltávolítja az alábbi felhasználót a(z) '%s' pozíciójából? +orgu#:#msg_confirm_remove_user#:#Biztos, hogy eltávolítja az alábbi felhasználót a(z) ‘%s’ pozíciójából? orgu#:#msg_deleted#:#Törölt orgu#:#msg_position_created#:#A pozíciót sikeresen létrehozta. -orgu#:#msg_position_delete_fail#:#Position wurde nicht gefunden.###29 10 2025 new variable +orgu#:#msg_position_delete_fail#:#A pozíció nem található. orgu#:#msg_position_updated#:#A pozíciót sikeresen módosította. orgu#:#msg_success_permission_saved#:#A jogosultságokat sikeresen mentette. orgu#:#no_assignment#:#Ellenőrizze az XML-Fájlt. Egy Szolgáltatási feltétel sincs. orgu#:#no_orgunit#:#Ellenőrizze az XML-Fájlt. Nincs Szervezeti egység. -orgu#:#no_roles#:#Nincsenek további szerepek ezen a ponton. +orgu#:#no_roles#:#Nincsenek további szerepkörök ezen a ponton. orgu#:#not_movable_to_subtree#:#Szervezeti egység nem mozgatható saját részfájába, mert az hurkot hozna létre. -orgu#:#org_op_access_enrolments#:#Bejegyzések megtekintése +orgu#:#org_op_access_enrolments#:#Kurzustagságok megtekintése orgu#:#org_op_access_results#:#Hozzáférés az eredményekhez orgu#:#org_op_create_employee_talk#:#Create talk appointments / edit talk appointments that you have created yourself orgu#:#org_op_edit_employee_talk#:#Edit Talk appointments orgu#:#org_op_edit_individual_plan#:#Egyedi terv módosítása orgu#:#org_op_edit_submissions_grades#:#Más felhasználók beküldésének módosítása orgu#:#org_op_manage_members#:#Tagok kezelése -orgu#:#org_op_manage_participants#:#Résztvevők kezelése orgu#:#org_op_read_employee_talk#:#Read access talk appointments orgu#:#org_op_read_learning_progress#:#Más felhasználók tanulási haladásának megtekintése -orgu#:#org_op_score_participants#:#Résztvevők pontozása orgu#:#org_op_view_certificates#:#Más felhasználók tanúsítványainak megtekintése orgu#:#org_op_view_competences#:#Más felhasználók kompetenciáinak megtekintése orgu#:#org_op_view_individual_plan#:#Egyedi terv megtekintése @@ -13214,10 +13285,10 @@ orgu#:#org_unit_not_found#:#Szervezeti egység nem található. orgu#:#orgu_add#:#Szervezeti egység hozzáadása orgu#:#orgu_adv_settings#:#További beállítások orgu#:#orgu_already_deleted#:#Az objektumot már korábban törölték. -orgu#:#orgu_enable_my_staff#:#A 'Munkatársak' bekapcsolása -orgu#:#orgu_enable_my_staff_info#:#A 'Munkatársak' a saját beosztottak tanulási haladását jeleníti meg. +orgu#:#orgu_enable_my_staff#:#Főmenü-bejegyzés bekapcsolása +orgu#:#orgu_enable_my_staff_info#:#Megjelenik egy főmenübejegyzés, amely tartalmazhat személyzeti listát, kurzustagságokat, tanúsítványokat, kompetenciákat, megbeszélgetéseket. orgu#:#orgu_global_set_form#:#Globális szervezeti egység beállításai -orgu#:#orgu_global_set_positions#:#Felhasználói adatok megjelenítése a szervezeti egységben lévő pozíciók szerint +orgu#:#orgu_global_set_positions#:#Objektumtípusonkénti pozíciók bekapcsolása orgu#:#orgu_global_set_positions_type_active#:#Pozíciók ebben: orgu#:#orgu_global_set_type_changeable#:#Módosíthatóság orgu#:#orgu_global_set_type_changeable_no#:#Nem módosítható @@ -13232,8 +13303,8 @@ orgu#:#orgu_staff#:#Személyi állomány orgu#:#orgu_staff_deassign#:#Biztos, hogy eltávolítja a felhasználókat a mintából? orgu#:#orgu_type#:#Szervezeti egységtípus orgu#:#orgu_type_add#:#Szervezeti egységtípus létrehozása -orgu#:#orgu_type_assign_amd_sets#:#Bővített metaadata készletek hozzárendelése -orgu#:#orgu_type_available_amd_sets#:#Elérhető bővített metaadat készletek +orgu#:#orgu_type_assign_amd_sets#:#Egyénimetaadata-készletek hozzárendelése +orgu#:#orgu_type_available_amd_sets#:#Elérhető egyénimetaadat-készletek orgu#:#orgu_type_custom_icon#:#Szervezeti egységtípus egyéni ikonja orgu#:#orgu_type_custom_icon_info#:#Az összes olyan Szervezeti egységnél, melyhez ezt a típust rendeli, a fában és fejlécében ez az ikon jelenik meg. orgu#:#orgu_type_edit#:#Szervezeti egységtípus módosítása @@ -13244,8 +13315,8 @@ orgu#:#orgu_type_msg_deletion_prevented#:#Az objektum a következő bővítmény orgu#:#orgu_type_msg_error_custom_icon#:#Egyéni ikon beállítása sikertelen orgu#:#orgu_type_msg_missing_title#:#Alapértelmezett nyelven címének megadása kötelező orgu#:#orgu_type_msg_missing_title_default_language#:#Alapértelmezett nyelv és annak címének megadása kötelező -orgu#:#orgu_type_msg_setting_default_lang_prevented#:#'%s' alapértelmezett nyelvek történő beállítása a következő bővítmények miatt nem lehetséges: %s -orgu#:#orgu_type_msg_setting_member_prevented#:#'%s' beállításai a következő bővítmények miatt nem törölhető: %s +orgu#:#orgu_type_msg_setting_default_lang_prevented#:#‘%s’ alapértelmezett nyelvek történő beállítása a következő bővítmények miatt nem lehetséges: %s +orgu#:#orgu_type_msg_setting_member_prevented#:#‘%s’ beállításai a következő bővítmények miatt nem törölhető: %s orgu#:#orgu_type_msg_unable_delete#:#A típus nem törölhető, mert a következő szervezeti egységekhez hozzá van rendelve: %s orgu#:#orgu_type_msg_updating_prevented#:#Az objektum a következő bővítmények miatt nem frissíthető: %s orgu#:#orgu_types#:#Típusok @@ -13256,7 +13327,7 @@ orgu#:#ou_more_than_one_match_found#:#Több, mint egy egyezést találtunk. orgu#:#ou_parent_id_not_valid#:#Az ou_parent_id nem található. orgu#:#over#:#Felette orgu#:#over_-1#:#Mindenki -orgu#:#placeholder#:#... +orgu#:#placeholder#:#… orgu#:#positions#:#Pozíciók orgu#:#rec_staff#:#%s emberei rekurzívan orgu#:#remove_successful#:#A felhasználót sikeresen eltávolította. @@ -13266,10 +13337,10 @@ orgu#:#scope_1#:#Ugyanazon szervezeti egység orgu#:#scope_2#:#Ugyanazon és alárendelt szervezeti egységek orgu#:#scope_3#:#Összes szervezeti egység orgu#:#show_learning_progress#:#Tanulási haladás megjelenítése -orgu#:#simple_import#:#Egyszerű XML Import +orgu#:#simple_import#:#Egyszerű XML import orgu#:#simple_user_import#:#XML felhasználó hozzárendelés orgu#:#simple_xls#:#Egyszerű Excel export -orgu#:#simple_xml#:#Egyszerű XML Export +orgu#:#simple_xml#:#Egyszerű XML export orgu#:#superior#:#Felettes orgu#:#user_assignments#:#Felhasználó hozzárendelései orgu#:#user_assignments_recursive#:#Felhasználó hozzárendelési részfája @@ -13281,7 +13352,7 @@ orgu#:#view_learning_progress_rec#:#Tanulási haladás rekurzív megjelenítése pd#:#block_show_chatviewer#:#Csevegésnéző megjelenítése pd#:#block_show_pdbookm#:#Könyvjelzők megjelenítése pd#:#block_show_pdcal#:#Naptár megjelenítése -pd#:#block_show_pdfrmpostdraft#:#Hozzászólásvázlatok megjelenítése +pd#:#block_show_pdfrmpostdraft#:#Hozzászóláspiszkozatok megjelenítése pd#:#block_show_pdmail#:#E-mail megjelenítése pd#:#block_show_pdnews#:#Hírek megjelenítése pd#:#block_show_pdnotes#:#Jegyzetek megjelenítése @@ -13295,13 +13366,12 @@ pd#:#pd_download_last_export_file#:#Utolsó exportfájlt letöltése pd#:#pd_enable_comments#:#Nyilvános megjegyzések engedélyezése pd#:#pd_enable_prtf#:#Portfóliók engedélyezése pd#:#pd_enable_user_publish#:#Felhasználói tartalom-közzététel engedélyezése -pd#:#pd_enable_user_publish_info#:#Ha be van kapcsolva, a felhasználók közzé tehetik profiljukat, személyes erőforrásaikat és portfóliójukat a weben. +pd#:#pd_enable_user_publish_info#:#A felhasználók közzé tehetik profiljukat, személyes erőforrásaikat és portfóliójukat a weben. pd#:#pd_ended#:#Elmúlt pd#:#pd_export_profile#:#Személyes adatok exportálása pd#:#pd_import_personal_data#:#Személyes adatok importálása pd#:#pd_my_memberships_sort_default#:#Alapértelmezett rendezési szempont -pd#:#pd_no_items_to_manage#:#No items available for removal.###26 08 2024 new variable -pd#:#pd_not_dated#:#Not Dated###26 08 2024 new variable +pd#:#pd_not_dated#:#Nincs időpontja pd#:#pd_ongoing#:#Folyamatban lévő pd#:#pd_personal_items_default_view#:#Alapértelmezett nézet pd#:#pd_personal_items_default_view_info#:#Munkaasztal alapértelmezett nézete. @@ -13310,127 +13380,124 @@ pd#:#pd_presentation_mode_tile#:#Csempe pd#:#pd_private_calendars#:#Privát naptár pd#:#pd_profile_data#:#Profiladatok pd#:#pd_remove_multi_confirm#:#Az objektumokat eltávolítottuk. -pd#:#pd_remove_multiple#:#Több objektum eltávolítása -pd#:#pd_unsubscribe_memberships#:#Leiratkozás -pd#:#pd_unsubscribe_multiple_memberships#:#Többszörös leiratkozás pd#:#pd_upcoming#:#Jövőbeli -pd#:#pd_view_select_at_least_one#:#Legalább egy nézetet ki kell választania vagy a 'Kigyűjtött objektumok' és/vagy a 'Tagságaim' közül. +pd#:#pd_view_select_at_least_one#:#Legalább egy nézetet ki kell választania vagy a ‘Kigyűjtött objektumok’ és/vagy a ‘Tagságaim’ közül. pdesk#:#bookmark_moved_ok#:#A könyvjelző áthelyeződött. pdesk#:#bookmark_select_target#:#Válasszon célt poll#:#poll_absolute#:#Szavazatok száma -poll#:#poll_activation_online_info#:#Kapcsolja be ezt a beállítást, hogy a szavazást elérhessék a felhasználók. +poll#:#poll_activation_online_info#:#Kapcsolja be, hogy a szavazást elérhessék a felhasználók. poll#:#poll_add#:#Szavazás létrehozása -poll#:#poll_anonymous_warning#:#Ez a szavazás névtelen. +poll#:#poll_anonymous_warning#:#Ez egy névtelen szavazás. A szavazatát rögzítjük, de a neve nem fog megjelenni a szavazás eredményében. poll#:#poll_answer#:#Válasz -poll#:#poll_answer_selected_alt_text#:#Selected###26 08 2024 new variable +poll#:#poll_answer_selected_alt_text#:#Kiválasztott poll#:#poll_answers#:#Lehetséges válaszok poll#:#poll_barchart#:#Oszlopdiagram poll#:#poll_block_message_already_voted#:#Már szavazott ebben a szavazásban. poll#:#poll_block_message_no_answers#:#Ez a szavazás még nem készült el teljesen. poll#:#poll_block_results_available_on#:#Az eredmény elérhető ettől: %s. -poll#:#poll_cannot_set_online_no_answers#:#The status cannot be changed to "online" because this poll has no question!###26 08 2024 new variable -poll#:#poll_chart_votes#:#Votes###28 10 2024 new variable +poll#:#poll_cannot_set_online_no_answers#:#Az állapot nem módosítható "online"-ra, mert egy kérdés sincs még a szavazásban! +poll#:#poll_chart_votes#:#Szavazatok poll#:#poll_comments#:#Nyilvános megjegyzések poll#:#poll_copy#:#Szavazás másolása -poll#:#poll_delete_votes#:#Összes szavazat törlése +poll#:#poll_delete_votes#:#Összes leadott szavazat törlése poll#:#poll_delete_votes_sure#:#Biztos, hogy törli az összes szavazatot? poll#:#poll_edit#:#Szavazás módosítása -poll#:#poll_edit_question#:#Edit Question###26 08 2024 new variable +poll#:#poll_edit_question#:#Kérdés módosítása poll#:#poll_image#:#Kép poll#:#poll_import#:#Szavazás importálása -poll#:#poll_limit_not_below_answer_count#:#The answer limit must be below the number of possible answers.###26 08 2024 new variable -poll#:#poll_limit_number_of_answers#:#Limit Number of Answers per Participant###26 08 2024 new variable +poll#:#poll_limit_not_below_answer_count#:#A válaszok megengedett maximális száma kevesebb kell, hogy legyen, mint a válaszlehetősége száma. +poll#:#poll_limit_number_of_answers#:#Résztvevőkénti válaszok számának korlátozása poll#:#poll_max_number_of_answers#:#Részvevőnkénti válaszok maximális száma -poll#:#poll_max_number_of_answers_info#:#You may choose up to %s answers.###26 08 2024 new variable +poll#:#poll_max_number_of_answers_info#:#Maximálisan %s választ adhat. poll#:#poll_mode#:#Mód poll#:#poll_mode_anonymous#:#Névtelen -poll#:#poll_mode_anonymous_info#:#A rendszer nem tárolja a szavazók nevét, így azt később sem lehet kideríteni. +poll#:#poll_mode_anonymous_info#:#A szavazás résztvevőinek neve nem jelenik meg az ‘Eredmények’ lapon. Kérjük, vegye figyelembe: a résztvevők felhasználói azonosítóit azonban rögzítjük az adatbázisban. poll#:#poll_mode_personal#:#Nevesített -poll#:#poll_mode_personal_info#:#A résztvevők szavazatait tartalmazó lista csak megfelelő jogosultsággal érhető el. +poll#:#poll_mode_personal_info#:#A szavazás résztvevőinek nevei és válaszai az ‘Eredmények’ lapon szerepelnek. Az ehhez a laphoz hozzáféréssel rendelkező felhasználók ellenőrizhetik, hogy ki melyik választ adta. poll#:#poll_new#:#Új szavazás létrehozása poll#:#poll_non_anonymous_warning#:#A szavazás szerkesztői megtekintheti a szavazók neveit. -poll#:#poll_notification_activated#:#Notification Activated###26 08 2024 new variable -poll#:#poll_notification_deactivated#:#Notification Deactivated###26 08 2024 new variable +poll#:#poll_notification_activated#:#Értesítések bekapcsolva +poll#:#poll_notification_deactivated#:#Értesítések kikapcsolva poll#:#poll_notification_subscribe#:#Értesítés bekapcsolása poll#:#poll_notification_unsubscribe#:#Értesítés kikapcsolása poll#:#poll_percentage#:#Szavazatok aránya -poll#:#poll_population#:#%s résztvevő -poll#:#poll_population_singular#:#1 Participant###26 08 2024 new variable +poll#:#poll_population#:#%s leadott szavazat +poll#:#poll_population_singular#:#1 leadott szavazat poll#:#poll_question#:#Kérdés poll#:#poll_result#:#Végeredmények poll#:#poll_result_answers#:#Szavazatok poll#:#poll_result_sorting#:#Rendezés poll#:#poll_result_sorting_answers#:#Lehetséges válaszok sorrendjében -poll#:#poll_result_sorting_votes#:#Szavazatok száma szerint (csökkenő) +poll#:#poll_result_sorting_votes#:#Szavazatok száma szerint ↓ poll#:#poll_result_users#:#Résztvevők -poll#:#poll_show_results_as#:#Eredmények megjelenítése, mint +poll#:#poll_show_results_as#:#Eredmények formátuma poll#:#poll_sortorder#:#Sorrend -poll#:#poll_stacked_chart#:#Stacked Chart###28 10 2024 new variable +poll#:#poll_stacked_chart#:#Halmozott diagram poll#:#poll_view_results#:#Eredmények megjelenítése poll#:#poll_view_results_after_period#:#Szavazási időszak után -poll#:#poll_view_results_after_period_impossible#:#A szavazás időtartama nincs korlátozva. +poll#:#poll_view_results_after_period_impossible#:#Ahhoz, hogy az eredmények csak a szavazási időszak végén jelenjenek meg, a fenti dátumok megadásával a szavazási időszakot korlátoznia kell. poll#:#poll_view_results_after_vote#:#Szavazás után poll#:#poll_view_results_always#:#Mindig poll#:#poll_view_results_never#:#Soha poll#:#poll_vote#:#Szavazás poll#:#poll_vote_error_multi#:#Ne válasszon többet, mint %s. -poll#:#poll_vote_error_multi_no_answer#:#Please select at least 1 answer.###26 08 2024 new variable +poll#:#poll_vote_error_multi_no_answer#:#Legalább 1 választ jelöljön meg. poll#:#poll_vote_error_single#:#Egyet válassz. poll#:#poll_vote_notification_body#:#ezúton tájékoztatjuk, hogy új szavazat érkezett. poll#:#poll_vote_notification_link#:#Link a Szavazásra poll#:#poll_vote_notification_reason#:#Ezt a levelet azért kapta, mert fent említett szavazásnál beállította, hogy kér értesítést. -poll#:#poll_vote_notification_subject#:#'%s' szavazás: új szavazat -poll#:#poll_votes_no_edit#:#Ez a szavazás már tartalmaz szavazatokat. A szavazás nem szerkeszthető, míg nem törli a szavazatokat. +poll#:#poll_vote_notification_subject#:#‘%s’ szavazás: új szavazat +poll#:#poll_votes_no_edit#:#Ez a szavazás már tartalmaz szavazatokat. A szavazás nem módosítható, míg nem törli a szavazatokat. poll#:#poll_voting_period_and_results#:#Szavazási időszak és eredmények -poll#:#poll_voting_period_ended_info#:#The voting period ended %s.###26 08 2024 new variable -poll#:#poll_voting_period_full_info#:#Szavazási időköz: %s → %s +poll#:#poll_voting_period_ended_info#:#A szavazási időszak véget ért %s. +poll#:#poll_voting_period_full_info#:#Szavazási időszak: %s → %s poll#:#poll_voting_period_info#:#Szavazás határideje: %s poll#:#poll_voting_period_limited#:#Korlátozott prg#:#access_ctr_by_orgu_position#:#Hozzáférés-kezelés szervezeti egység pozíciói alapján -prg#:#active_only#:#active users only###26 08 2024 new variable +prg#:#active_only#:#csak aktív felhasználók prg#:#add_automembership_source#:#Forrása hozzáadása prg#:#add_category#:#Kategória hozzáadása prg#:#assignment_date#:#Hozzárendelés időpontja -prg#:#assignments#:#Assignments###29 07 2022 new variable -prg#:#auto_add_success#:#Add automatism successfully.###29 07 2022 new variable -prg#:#auto_membership_description#:#Rules are only executed when a criterion gets fulfilled after activation of the rule. Deleting rules will not remove assignments if any other active criterion is fulfilled by that time.###29 07 2022 new variable +prg#:#assignments#:#Hozzárendelések +prg#:#auto_add_success#:#Az automatizmust sikeresen hozzáadta. +prg#:#auto_membership_description#:#Szabály csak akkor fut le, amikor annak aktiválása után teljesülnek annak feltételei. Szabály törlése nem távolít el hozzárendelést, ha bámely más aktiválási feltétel teljesül. prg#:#auto_membership_src_type#:#Típus prg#:#auto_membership_title#:#Automatizált tagság forrásai prg#:#auto_memberships#:#Tagság automatizálása prg#:#category#:#Kategória -prg#:#cert_relevance#:#Certificate###29 10 2025 new variable +prg#:#cert_relevance#:#Tanúsítvány prg#:#completion_date#:#Befejezés időpontja -prg#:#confirm_to_remove_selected_assignments#:#Do you really want to remove the user assignment(s)?###29 07 2022 new variable -prg#:#cont_ed_insert_prgactionnote#:#Insert Study Programme Action Note###26 08 2024 new variable -prg#:#cont_ed_insert_prgstatusinfo#:#Insert Study Programme Status Information###26 08 2024 new variable +prg#:#confirm_to_remove_selected_assignments#:#Biztos, hogy eltávolítja a felhasználó hozzárendeléseit? +prg#:#cont_ed_insert_prgactionnote#:#Képzési program teendőhez megjegyzés beillesztése +prg#:#cont_ed_insert_prgstatusinfo#:#Képzési program állapotinformációjának beillesztése prg#:#content_automation#:#Tartalomautomatizmus prg#:#content_automation_title#:#Automatikusan hozzáadja, illetve eltávolítja a kategóriákban lévő kurzusokat. -prg#:#could_not_add_users_no_permissons#:#%d felhasználót nem sikerült hozzárendelni jogosultság hiánya miatt.. -prg#:#crs_affiliation_to_prg#:#Affiliation to study programmes###26 08 2024 new variable -prg#:#deadline#:#Deadline###26 08 2024 new variable +prg#:#could_not_add_users_no_permissons#:#%d felhasználót nem sikerült hozzárendelni jogosultság hiánya miatt. +prg#:#crs_affiliation_to_prg#:#Képzési programokhoz való tartozás +prg#:#deadline#:#Határidő prg#:#deadline_information#:#A feldolgozási időszakra vonatkozó információk -prg#:#deadline_updated#:#Updated deadline###29 07 2022 new variable +prg#:#deadline_updated#:#A határidőt sikeresen módosította prg#:#edit_participants#:#Tagok módosítása prg#:#error_updating_deadline#:#Hiba a határidő módosításakor. prg#:#error_updating_expire_date#:#Hiba a lejárati idő módosításakor. -prg#:#export_memberships#:#Export Assignments###26 08 2024 new variable -prg#:#foreign_assignment#:#not top node###26 08 2024 new variable +prg#:#export_memberships#:#Hozzárendelések exportálása +prg#:#foreign_assignment#:#nem a legfelső csomópont prg#:#form_msg_file_wrong_file_type#:#Rossz fájltípus. -prg#:#header_remove_certificate#:#Do you really want to remove the certificate for the selected Users?###26 08 2024 new variable -prg#:#header_update_certificate#:#Do you really want to update the certificate?###26 08 2024 new variable -prg#:#header_update_current_plan#:#Do you really want to reset all individual settings for the selected assignments?###26 08 2024 new variable -prg#:#inactive_only#:#inactive users only###26 08 2024 new variable -prg#:#info_to_re_assign_mail_body#:#%s %s,

    ezúton értesítjük, hogy '%s' Képzési programban tagságának érvényessége hamarosan lejár. Kérjük, jelentkezzen be újra. +prg#:#header_remove_certificate#:#Biztos, hogy eltávolítja a kiválasztott felhasználók tanúsítványát? +prg#:#header_update_certificate#:#Biztos, hogy módosítja a tanúsítványt? +prg#:#header_update_current_plan#:#Biztos, hogy alapértemezettre állítja az összes egyéni beállítást a megjelölt hozzárendeléseknél? +prg#:#inactive_only#:#csak inaktív felhasználók +prg#:#info_to_re_assign_mail_body#:#%s %s,

    ezúton értesítjük, hogy ‘%s’ Képzési programban tagságának érvényessége hamarosan lejár. Kérjük, jelentkezzen be újra. prg#:#info_to_re_assign_mail_subject#:#Emlékeztető részvétel megújításáról Képzési programban -prg#:#invalidated#:#validity###26 08 2024 new variable +prg#:#invalidated#:#érvényesség prg#:#label_crs#:#Kurzus neve prg#:#label_grp#:#Csoport neve -prg#:#label_role#:#Szerep neve +prg#:#label_role#:#Szerepkör neve prg#:#last_edited#:#Utoljára módosítva prg#:#last_edited_by#:#Utoljára módosította -prg#:#mail_assignments#:#Mail to assigned Users###29 07 2022 new variable -prg#:#mails_foreign_assignment_failed#:#Selected assignments are not in current context. Mails should be sent from Study Programme's top node.###26 08 2024 new variable -prg#:#manage_assignments#:#Manage Assignments###29 07 2022 new variable +prg#:#mail_assignments#:#Levél küldése a hozzárendelt felhasználóknak +prg#:#mails_foreign_assignment_failed#:#A kiválasztott hozzárendelések nincsenek a jelenlegi kontextusban. Leveleket a tanulmányi program legfelső csomópontjából lehet csak küldeni. +prg#:#manage_assignments#:#Hozzárendelések kezelése prg#:#membership_source_id#:#Id prg#:#membership_source_id_byline_objid#:#Kérem, az object-id-t használja prg#:#membership_source_id_byline_refid#:#Kérem, a reference-id-t használja @@ -13438,52 +13505,52 @@ prg#:#membership_source_type#:#Forrás prg#:#modal_automembership_title#:#Automatikus hozzárendelés prg#:#modal_categories_title#:#Monitorozandó kategória prg#:#modal_member_auto_select_title#:#Válassza ki az automatikus összerendelés forrását -prg#:#msg_acknowledge_courses#:#Completed Courses have been acknowledged.###26 08 2024 new variable -prg#:#msg_change_deadline_date#:#Updated deadline for %s users.###29 07 2022 new variable -prg#:#msg_change_deadline_date_failed#:#Deadline not updated for:###29 07 2022 new variable -prg#:#msg_change_expire_date#:#Updated expire date for %s users.###29 07 2022 new variable -prg#:#msg_change_expire_date_failed#:#Expire date not updated for:###29 07 2022 new variable +prg#:#msg_acknowledge_courses#:#Az elvégzett kurzusokat elismerték. +prg#:#msg_change_deadline_date#:#%s felhasználónál a határidőt sikeresen módosította. +prg#:#msg_change_deadline_date_failed#:#A határidő nem módosult: +prg#:#msg_change_expire_date#:#%s felhasználónál a lejárati időt sikeresen módosította +prg#:#msg_change_expire_date_failed#:#A lejárati idő nem módosult prg#:#msg_fill_required#:#Az összes kötelező mezőt töltse ki. -prg#:#msg_impossible_target_status#:#Impossible target status###29 07 2022 new variable -prg#:#msg_mark_accredited#:#%s users successfully marked accredited###29 07 2022 new variable -prg#:#msg_mark_accredited_failed#:#Not marked accredited:###29 07 2022 new variable -prg#:#msg_mark_not_relevant#:#%s users successfully unmarked relevant###29 07 2022 new variable -prg#:#msg_mark_not_relevant_failed#:#Not unmarked relevant:###29 07 2022 new variable -prg#:#msg_mark_relevant#:#%s users successfully marked relevant###29 07 2022 new variable -prg#:#msg_mark_relevant_failed#:#Not marked marked relevant:###29 07 2022 new variable -prg#:#msg_points_must_be_positive#:#Only positive numbers are allowed.###29 07 2022 new variable -prg#:#msg_unmark_accredited#:#Unmarked %s users accredited.###29 07 2022 new variable -prg#:#msg_unmark_accredited_failed#:#Unmarking accredited not successful for:###29 07 2022 new variable -prg#:#msg_update_certificate#:#%s Certificate(s) updated.###26 08 2024 new variable -prg#:#msg_update_certificate_failed#:#Certificate(s) not updated:###26 08 2024 new variable -prg#:#msg_update_from_settings#:#Updated %s users from settings:###29 07 2022 new variable -prg#:#msg_update_from_settings_failed#:#Updated from settings failed:###29 07 2022 new variable -prg#:#msg_update_individual_plan#:#Individual plan: %s successfully updated.###29 07 2022 new variable -prg#:#msg_update_individual_plan_failed#:#Update of individual plan failed###29 07 2022 new variable -prg#:#no_permission_to_update_certificate#:#You have no permission to update certificates.###26 08 2024 new variable -prg#:#no_srctype_or_id#:#Id and type may not be empty.###29 07 2022 new variable +prg#:#msg_impossible_target_status#:#Lehetetlen célállapot +prg#:#msg_mark_accredited#:#%s felhasználót sikeresen megjelölt abszolvált állapotúra +prg#:#msg_mark_accredited_failed#:#Nincs megjelölve abszolváltként: +prg#:#msg_mark_not_relevant#:#%s felhasználó releváns állapotát sikeresen eltávolította +prg#:#msg_mark_not_relevant_failed#:#A releváns el nem távolítva: +prg#:#msg_mark_relevant#:#%s felhasználót sikeresen módosította irrelevánsra +prg#:#msg_mark_relevant_failed#:#Nem releváns: +prg#:#msg_points_must_be_positive#:#Csak pozitív szám lehetséges. +prg#:#msg_unmark_accredited#:#%s felhasználó abszolvált állapotát sikeresen eltávolította +prg#:#msg_unmark_accredited_failed#:#Abszolvált állapot eltávolítása sikertelen: +prg#:#msg_update_certificate#:#%s tanúsítvány(oka)t sikeresen módosította. +prg#:#msg_update_certificate_failed#:#A tanúsítványt nem sikerült frissíteni +prg#:#msg_update_from_settings#:#%s felhasználót sikeresen módosított a beállításokból +prg#:#msg_update_from_settings_failed#:#A módosítás a beállításokból sikertelen: +prg#:#msg_update_individual_plan#:#Az egyéni tervet sikeresen módosította(%) +prg#:#msg_update_individual_plan_failed#:#Az egyéni terv módosítása sikertelen +prg#:#no_permission_to_update_certificate#:#Nincs jogosultsága a tanúsítvány módosításához. +prg#:#no_srctype_or_id#:#Az ID vagy a típus üres. prg#:#not_a_valid_cat_id#:#%s nem érvényes ref-id-je egy kategóriának sem. -prg#:#obj_prg_select#:#-- Please select a study programme --###26 08 2024 new variable -prg#:#optgrp_label_restart#:#Restart###26 08 2024 new variable -prg#:#optgrp_label_validity#:#Expiry###26 08 2024 new variable +prg#:#obj_prg_select#:#-- Válasszon képzési programot -- +prg#:#optgrp_label_restart#:#Újrakezdés +prg#:#optgrp_label_validity#:#Lejárat prg#:#orgu#:#Szervezeti egység -prg#:#pc_prg_action_note_label#:#Required Actions Study Programme###26 08 2024 new variable -prg#:#pc_prg_statusinfo_label#:#Statusinformation Study Programme###26 08 2024 new variable -prg#:#pc_prgactionnote_complete_content#:#You are assigned to the Study Programme, but have not completed its content. Please complete the content.###26 08 2024 new variable -prg#:#pc_prgactionnote_complete_content_with_deadline#:#You are assigned to the Study Programme, but have not completed its content. Please complete the content until###26 08 2024 new variable -prg#:#pc_prgactionnote_headline#:#Required actions###26 08 2024 new variable -prg#:#pc_prgactionnote_no_actions_required#:#No actions required.###26 08 2024 new variable -prg#:#pc_prgstatus_edit_qualification#:#Re-processing required from###26 08 2024 new variable -prg#:#pc_prgstatus_expiration_date#:#Expiry date###26 08 2024 new variable -prg#:#pc_prgstatus_qualification_headline#:#Status of your qualification###26 08 2024 new variable -prg#:#pc_prgstatus_status_no_qualification#:#No qualification###26 08 2024 new variable -prg#:#pc_prgstatus_status_valid_qualification#:#Valid###26 08 2024 new variable -prg#:#pc_prgstatus_text_no_qualification#:#Your qualification is not valid###26 08 2024 new variable -prg#:#pc_prgstatus_unlimited_validation#:#Unlimited validity###26 08 2024 new variable +prg#:#pc_prg_action_note_label#:#Képzési program kötelező teendői +prg#:#pc_prg_statusinfo_label#:#Képzési program állapotinformációi +prg#:#pc_prgactionnote_complete_content#:#Kérem, fejezze be a Képézis program tartalmát. +prg#:#pc_prgactionnote_complete_content_with_deadline#:#Kérem, fejezze be a Képzési program tartalmát eddig: +prg#:#pc_prgactionnote_headline#:#Kötelező teendő +prg#:#pc_prgactionnote_no_actions_required#:#Nincs kötelező teendő +prg#:#pc_prgstatus_edit_qualification#:#Újrafeldolgozás szükséges innen: +prg#:#pc_prgstatus_expiration_date#:#Lejárat dátuma +prg#:#pc_prgstatus_qualification_headline#:#Képesítésének állapota +prg#:#pc_prgstatus_status_no_qualification#:#Nincs képesítése +prg#:#pc_prgstatus_status_valid_qualification#:#Érvényes +prg#:#pc_prgstatus_text_no_qualification#:#Képesítésem érvényességének kezdete: +prg#:#pc_prgstatus_unlimited_validation#:#Nincs lejárata prg#:#percentage#:#% prg#:#prg_access_by_orgu#:#Hozzáférés-vezérlés a szervezeti egység pozíciói alapján -prg#:#prg_access_by_orgu_byline#:#Ha be van kapcsolva, további hozzáférés-vezérlési szabályok adhatóak meg a szervezeti egységekben elfoglalt pozíciók alapján. -prg#:#prg_acknowledge_all_completed_courses#:#Acknowledge All Completed Courses###29 10 2025 new variable +prg#:#prg_access_by_orgu_byline#:#További hozzáférés-vezérlési szabályok adhatók meg a szervezeti egységekben elfoglalt pozíciók alapján. +prg#:#prg_acknowledge_all_completed_courses#:#Az összes teljesített kurzus e prg#:#prg_acknowledge_completed_courses#:#Teljesített kurzusok elismerése prg#:#prg_add#:#Képzési program hozzáadása prg#:#prg_added_course_ref_successful#:#Új kurzuslinket sikeresen hozzáadta. @@ -13497,45 +13564,45 @@ prg#:#prg_async_create#:#Új gyermekfa hozzáadása prg#:#prg_async_settings#:#Beállítások prg#:#prg_auto_member_select_crs#:#Kurzusok prg#:#prg_auto_member_select_grp#:#Csoportok -prg#:#prg_auto_member_select_role#:#Szerepek +prg#:#prg_auto_member_select_role#:#Szerepkörök prg#:#prg_autoassignment#:#(automatikus) -prg#:#prg_availability_action_not_allowed#:#Cannot set Availability Period on Study Programmes.###28 10 2024 new variable +prg#:#prg_availability_action_not_allowed#:#Nem állíthat be elérhetőségi időszakot Képzési programhoz prg#:#prg_belongs_to#:#Kiindulópontja prg#:#prg_can_not_manage_in_repo#:#Nincs jogosultsága ennek a Képzési programnak a kezeléséhez. prg#:#prg_cancel#:#Mégsem -prg#:#prg_cancel_acknowledge_completed_courses#:#Don't acknowledge any Courses###26 08 2024 new variable +prg#:#prg_cancel_acknowledge_completed_courses#:#Ne ismerjen el semmilyen kurzust prg#:#prg_cancel_tree_order#:#Faszerkezet eldobása -prg#:#prg_change_deadline#:#Change deadline###26 08 2024 new variable -prg#:#prg_change_expire_date#:#Change expire date###26 08 2024 new variable +prg#:#prg_change_deadline#:#Határidő módosítása +prg#:#prg_change_expire_date#:#Lejárati idő módosítása prg#:#prg_changed_by#:#Módosította prg#:#prg_completion_by#:#Véglegesítette prg#:#prg_completion_date#:#Befejezés dátuma -prg#:#prg_confirm_delete#:#Törlése -prg#:#prg_copy_threads_info#:#Please decide which Study Programme elements are to be copied, linked or omitted.###26 08 2024 new variable +prg#:#prg_confirm_delete#:#Törlés +prg#:#prg_copy_threads_info#:#Kérem, válassza ki a Képzési program mely elemeit másolja, linkeli, illetve hagyja ki. prg#:#prg_create_new_leaf#:#Új levél létrehozása prg#:#prg_create_new_node#:#Új csomópont létrehozása prg#:#prg_cron_job_configuration#:#Automatikus e-mailek beállításai -prg#:#prg_custom_plan#:#Teljesítette-e -prg#:#prg_cut_action_not_allowed#:#Cannot move Study Programmes###28 10 2024 new variable +prg#:#prg_custom_plan#:#Egyéni tanterv +prg#:#prg_cut_action_not_allowed#:#Nem helyezhet át Képzési programokat prg#:#prg_dash_label_finish_until#:#Befejezés eddig prg#:#prg_dash_label_gain#:#Jelenlegi teljesítettség prg#:#prg_dash_label_minimum#:#Minimális teljesítettség prg#:#prg_dash_label_restart_from#:#Megújítás ekkortól prg#:#prg_dash_label_status#:#Állapot -prg#:#prg_dash_label_unreachable#:#- cannot be achieved###26 08 2024 new variable +prg#:#prg_dash_label_unreachable#:#- nem valósítható meg prg#:#prg_dash_label_valid#:#Érvényes prg#:#prg_deadline#:#Határidő prg#:#prg_deadline_date#:#A feldolgozási idő egy megadott időpontban jár le prg#:#prg_deadline_date_desc#:#A programot a megadott időpontig kell teljesíteni. -prg#:#prg_deadline_date_label#:#Process until###26 08 2024 new variable +prg#:#prg_deadline_date_label#:#Feldolgozás eddig prg#:#prg_deadline_period#:#A feldolgozási időszak személyre szabott prg#:#prg_deadline_period_desc#:#A programot a megadott időtartam alatt kell teljesíteni. -prg#:#prg_deadline_period_label#:#Days after assignment###26 08 2024 new variable +prg#:#prg_deadline_period_label#:#Hozzárendelés után X nap prg#:#prg_deadline_settings#:#Feldolgozási időszak prg#:#prg_delete_confirmation#:#Biztos, hogy törli a kiválasztott bejegyzéseket? prg#:#prg_delete_failure#:#A törlés nem sikerült. prg#:#prg_delete_nothing_selected#:#Legalább egy sort válasszon ki. -prg#:#prg_delete_single_confirmation#:##Biztos, hogy törli a kiválasztott bejegyzést? +prg#:#prg_delete_single_confirmation#:#Biztos, hogy törli a kiválasztott bejegyzést? prg#:#prg_delete_single_success#:#A bejegyzést sikeresen törölte. prg#:#prg_delete_success#:#A bejegyzéseket sikeresen törölte. prg#:#prg_deleted_safely#:#Csomópontot biztonságosan törölte. @@ -13543,39 +13610,39 @@ prg#:#prg_description#:#Leírás prg#:#prg_edit#:#Képzési program módosítása prg#:#prg_expiry_date#:#Lejárat dátuma prg#:#prg_formatted_period#:#%d nap -prg#:#prg_import_action_not_allowed#:#Cannot import into Study Programmes.###28 10 2024 new variable -prg#:#prg_invalidate_expired_progresses_desc#:#A lejárt képesítésű Képzési programok megjelölése 'nem teljesített'-ként +prg#:#prg_import_action_not_allowed#:#Nem importálhat Képzési programba +prg#:#prg_invalidate_expired_progresses_desc#:#A lejárt képesítésű Képzési programok megjelölése ‘nem teljesített’-ként prg#:#prg_invalidate_expired_progresses_title#:#A Képzési program képesítésének korlátozott érvényessége prg#:#prg_link#:#Link prg#:#prg_mail_context_info#:#Képzési program tagsága, illetve tanulási haladási állapotai alapján levél küldés a résztvevőknek prg#:#prg_mail_context_title#:#Képzési program: levél a tagoknak prg#:#prg_mail_permanent_link#:#A Képzési programmal kapcsolatos összes információért kattintson a linkre: prg#:#prg_manage#:#Kezelés -prg#:#prg_manage_members#:#Manage Enrolments of Study Programme###26 08 2024 new variable -prg#:#prg_manage_members_short#:#Manage Assignments###29 07 2022 new variable +prg#:#prg_manage_members#:#Képzési program beiratkozásainak kezelése +prg#:#prg_manage_members_short#:#Hozzárendelések kezelése prg#:#prg_manual_status#:#Kézi állapot prg#:#prg_mark_accredited#:#Abszolváltként megjelölése prg#:#prg_mark_accredited_multi_success#:#Kijelölt felhasználók megjelölés akkreditáltként prg#:#prg_mark_accredited_success#:#A felhasználó programcsomópont teljesítettségét sikeresen beállította. prg#:#prg_mark_not_relevant_multi_success#:#Kijelölt felhasználók releváns jelölésének eltávolítása -prg#:#prg_mark_relevant#:#Mark Relevant###26 08 2024 new variable +prg#:#prg_mark_relevant#:#Megjelölés relevánsként prg#:#prg_mark_relevant_multi_success#:#Kijelölt felhasználók megjelölés relevánsként prg#:#prg_more_objects_without_read_permission#:#Képzési program több olyan objektumot is tartalmaz, melyek megtekintéséhez nem rendelkezik megfelelő jogosultsággal. prg#:#prg_multi_change_deadline#:#Határidő módosítása prg#:#prg_multi_change_expire_date#:#Lejárati idő módosítása -prg#:#prg_multi_mail_user#:#Send Mail###26 08 2024 new variable +prg#:#prg_multi_mail_user#:#Levél küldése prg#:#prg_multi_mark_accredited#:#Akkreditált prg#:#prg_multi_mark_relevant#:#Megjelölés relevánsként -prg#:#prg_multi_remove_certificate#:#Remove Certificates###26 08 2024 new variable +prg#:#prg_multi_remove_certificate#:#Tanúsítványok eltávolítása prg#:#prg_multi_remove_user#:#Felhasználó eltávolítása prg#:#prg_multi_unmark_accredited#:#Akkreditált jelölés eltávolítása prg#:#prg_multi_unmark_relevant#:#Releváns jelölés eltávolítása -prg#:#prg_multi_update_certificate#:#Update Certificates###26 08 2024 new variable +prg#:#prg_multi_update_certificate#:#Tanúsítványok frissítése prg#:#prg_multi_update_from_current_plan#:#Frissítés a jelenlegi tervből prg#:#prg_new#:#Új Képzési program prg#:#prg_no_deadline#:#Nincs rögzített feldolgozási időszak prg#:#prg_no_members_not_active#:#Nem adhat hozzá felhasználókat, mert a program nem aktív. -prg#:#prg_no_permission_to_remove_certificate#:#You do not have permission to remove certificates###26 08 2024 new variable +prg#:#prg_no_permission_to_remove_certificate#:#Nincs jogosultsága eltávolítani a tanúsítványt prg#:#prg_no_restart#:#Nem igényel megújítást prg#:#prg_no_user_selected#:#Egy felhasználót sem választott ki prg#:#prg_no_validity_qualification#:#Le nem járó képesítés @@ -13599,11 +13666,11 @@ prg#:#prg_progress_status#:#%1$d pont %2$d pontból prg#:#prg_progress_status_with_child_sp#:#%1$d pont a lehetséges %2$d pontból prg#:#prg_quali_not_valid#:#A képesítés már nem érvényes prg#:#prg_quali_still_valid#:#A képesítés még érvényes -prg#:#prg_remove_certificate#:#Remove Certificate###26 08 2024 new variable +prg#:#prg_remove_certificate#:#Tanúsítvány eltávolítása prg#:#prg_remove_user#:#Felhasználó eltávolítása prg#:#prg_remove_user_success#:#A felhasználót sikeresen törölte. prg#:#prg_remove_users_not_possible#:#Nem sikerült eltávolítani a kijelölt felhasználókat -prg#:#prg_remove_users_partial_success#:#Assignments (partially) removed.###26 08 2024 new variable +prg#:#prg_remove_users_partial_success#:#A hozzárendeseket (részlegesen) eltávolította. prg#:#prg_remove_users_success#:#Sikeresen eltávolította a kijelölt felhasználókat prg#:#prg_restart_assignments_temporal_progress_desc#:#A hamarosan lejáró Képzési programok újraindítása prg#:#prg_restart_assignments_temporal_progress_title#:#A hozzárendelések újraindítása @@ -13629,19 +13696,19 @@ prg#:#prg_status_byline#:#Az állapot segítségével ellenőrizheti, hogy ez a prg#:#prg_status_completed#:#Befejezve prg#:#prg_status_draft#:#Tervezet prg#:#prg_status_failed#:#sikertelen -prg#:#prg_status_hide_irrelevant#:#hide irrelevant###26 08 2024 new variable +prg#:#prg_status_hide_irrelevant#:#Nem relevánsak elrejtése prg#:#prg_status_in_progress#:#Folyamatban prg#:#prg_status_not_relevant#:#Nem releváns prg#:#prg_status_outdated#:#Elavult prg#:#prg_still_valid#:#még érvényes prg#:#prg_subtype_add#:#Új típus hozzáadása -prg#:#prg_subtypes#:#Képzésiprogram-típusok -prg#:#prg_successfully_removed_certificate#:#Successfully removed certificate of selected Users###26 08 2024 new variable +prg#:#prg_subtypes#:#Képzésiprogram-altípusok +prg#:#prg_successfully_removed_certificate#:#Sikeresen eltávolította a kiválasztott felhasználók tanúsítványát. prg#:#prg_title#:#Cím prg#:#prg_type#:#Képzésiprogram-típus prg#:#prg_type_add#:#Képzésiprogram-típus -prg#:#prg_type_assign_amd_sets#:#Bővített metaadat készletek hozzárendelés -prg#:#prg_type_available_amd_sets#:#Elérhető bővített metaadat készletek +prg#:#prg_type_assign_amd_sets#:#Egyénimetaadat-készletek hozzárendelés +prg#:#prg_type_available_amd_sets#:#Elérhető egyénimetaadat-készletek prg#:#prg_type_byline#:#Állítson be egy típust bizonyos egyedi metaadatkészletek vagy ikonok használatához. prg#:#prg_type_custom_icon#:#Egyéni ikonok prg#:#prg_type_custom_icon_info#:#Egyéni ikoninformáció @@ -13654,15 +13721,15 @@ prg#:#prg_type_msg_unable_delete#:#Nem törölhető ez a típus, mert az alábbi prg#:#prg_unmark_accredited#:#Abszolvált jelölés eltávolítása prg#:#prg_unmark_accredited_multi_success#:#Kijelölt felhasználók akkreditált jelölésének eltávolítása prg#:#prg_unmark_accredited_success#:#A felhasználó programcsomópont teljesítettségét sikeresen eltávolította. -prg#:#prg_unmark_relevant#:#Unmark Relevant###26 08 2024 new variable -prg#:#prg_update_certificate#:#Update Certificate###26 08 2024 new variable +prg#:#prg_unmark_relevant#:#Releváns jelölés eltávolítása +prg#:#prg_update_certificate#:#Tanúsítvány frissítése prg#:#prg_update_from_current_plan#:#Frissítés a jelenlegi terv alapján prg#:#prg_update_from_current_plan_not_possible#:#Nem sikerült frissíteni a jelenlegi tervből prg#:#prg_update_from_current_plan_partitial_success#:#Részben sikeresen frissített a jelenlegi tervből prg#:#prg_update_from_current_plan_success#:#Sikeresen frissített a jelenlegi tervből prg#:#prg_update_from_plan_successful#:#Sikeresen frissítette a jelenlegi terv alapján. -prg#:#prg_update_progress_description#:#A 'Folyamatban' állapotok módosítása 'Nem teljesítette' állapotra a határidő után. -prg#:#prg_update_progress_title#:#Határidő után a 'Folyamatban' legyen 'Nem teljesítette' +prg#:#prg_update_progress_description#:#A ‘Folyamatban’ állapotok módosítása ‘Nem teljesítette’ állapotra a határidő után. +prg#:#prg_update_progress_title#:#Határidő után a ‘Folyamatban’ legyen ‘Nem teljesítette’ prg#:#prg_update_successful#:#Módosításokat sikeresen mentette. prg#:#prg_user_not_restarted_desc#:#Értesítő e-mail küldése, amikor a képzési program képesítése lejár és meg nem újították meg a képesítést. prg#:#prg_user_not_restarted_time_input#:#Emlékeztető e-mail megújításról @@ -13675,27 +13742,27 @@ prg#:#prg_validity_of_qualification#:#A megszerzett képesítés érvényessége prg#:#prg_validity_of_qualification_limit#:#Képesítés lejárata prg#:#prg_validity_of_qualification_restart#:#Megújítás prg#:#prg_view#:#Megtekintés -prg#:#prgr_may_not_create_circular_reference#:#Erre a Képzési programra mutató link nem hozható létre, mert a szülőobjektumának linkje már szerepel itt. -prg#:#re_assigned_mail_body#:#%s %s,

    ezúton értesítjük, hogy '%s' Képzési programhoz újra hozzárendelték. +prg#:#prgr_may_not_create_circular_reference#:#Erre a képzési programra mutató link nem hozható létre, mert a szülőobjektumának linkje már szerepel itt. +prg#:#re_assigned_mail_body#:#%s %s,

    ezúton értesítjük, hogy ‘%s’ Képzési programhoz újra hozzárendelték. prg#:#re_assigned_mail_subject#:#Részvétel megújítása Képzési programban prg#:#restart_information#:#Információk a függőben lévő lejáró képesítések automatikus megújításról prg#:#restart_period#:#Megújítást igényel -prg#:#restart_period_desc#:#nappal a lejárat előtt +prg#:#restart_period_desc#:#hozzárendelés automatikus eltávolítása a lejárat előtt prg#:#restart_period_info#:#A képesítés megújításához a képesítés lejárta előtti napok száma -prg#:#restart_period_label#:#Days before expiry###26 08 2024 new variable -prg#:#restart_recheck_desc#:#For assignments made via an automatism, the system rechecks whether criteria for the assignment still exist.###26 08 2024 new variable -prg#:#restart_recheck_label#:#Check prerequisites again###26 08 2024 new variable -prg#:#restarted#:#restarted###26 08 2024 new variable -prg#:#risky_to_fail_mail_body#:#%s %s,

    ezúton értesítjük, hogy '%s' a képzési program teljesítésének határideje hamarosan lejár. +prg#:#restart_period_label#:#Lejárt előtt hány nappal +prg#:#restart_recheck_desc#:#Az automatizmussal végrehajtott hozzárendeléseknél a rendszer újra ellenőrzi, hogy a hozzárendelés feltételei még léteznek-e. +prg#:#restart_recheck_label#:#Előfeltételek ismételt ellenőrzése +prg#:#restarted#:#újraindított +prg#:#risky_to_fail_mail_body#:#%s %s,

    ezúton értesítjük, hogy ‘%s’ a képzési program teljesítésének határideje hamarosan lejár. prg#:#risky_to_fail_mail_subject#:#Emlékeztető, hogy a képzési program teljesítésének határideje hamarosan lejár -prg#:#rol#:#Szerep +prg#:#rol#:#Szerepkör prg#:#select_crs#:#Kurzusok keresése prg#:#select_grp#:#Csoportok keresése prg#:#select_org#:#Szervezeti egységek keresése -prg#:#select_role#:#Szerepek keresése +prg#:#select_role#:#Szerepkörök keresése prg#:#send_info_to_re_assign_mail#:#Emlékeztető e-mail megújításról prg#:#send_info_to_re_assign_mail_info#:#E-mail küldése a tanulóknak, ami emlékezteti őket, hogy újítsák meg a képesítésüket. -prg#:#send_re_assigned_mail#:#E-mail megújított résztvételről +prg#:#send_re_assigned_mail#:#E-mail megújított részvételről prg#:#send_re_assigned_mail_info#:#E-mail küldése a Képzési programhoz automatikus újracsatlakozásról. prg#:#send_risky_to_fail_mail#:#E-mail kudarcról prg#:#send_risky_to_fail_mail_info#:#E-mail küldése, amikor valószínű, hogy egy tanulónak nem sikerül teljesíteni a képzési programot. @@ -13705,49 +13772,49 @@ prg#:#sp_certificate_points#:#Megszerzett pontok mennyisége prg#:#sp_certificate_progress_expires_at#:#Képesítés lejáratának dátuma prg#:#sp_certificate_title#:#Képzési program címe prg#:#sp_certificate_type#:#Képzési program típusa -prg#:#status_changed#:#Updated status###29 07 2022 new variable -prg#:#status_changed_due_to_deadline#:#Status changed according to deadline.###26 08 2024 new variable -prg#:#status_transition_not_allowed#:#Status change not allowed###29 07 2022 new variable -prg#:#status_unchanged#:#Status unchanged###29 07 2022 new variable -prg#:#study_programme_icon#:#Page Editor Study Programme Icon###26 08 2024 new variable +prg#:#status_changed#:#Az állapotot sikeresen módosította +prg#:#status_changed_due_to_deadline#:#Az állapot módosult a határidőnek megfelelően. +prg#:#status_transition_not_allowed#:#Az állapot módosítása nem engedélyezett +prg#:#status_unchanged#:#Az állapot nem változott +prg#:#study_programme_icon#:#A Képzési program oldalszerkesztőjének ikonja prg#:#update_deadline#:#A határidőt sikeresen módosította. prg#:#update_expire_date#:#A lejárati időt sikeresen módosította. -prg#:#updated_from_settings#:#Updated from settings###29 07 2022 new variable -prg#:#usr_active#:#User###26 08 2024 new variable +prg#:#updated_from_settings#:#A beállításokból sikeresen módosította +prg#:#usr_active#:#Felhasználó prg#:#validity_qualification_date#:#A képesítés megadott időpontban jár le prg#:#validity_qualification_date_desc#:#lejárat időpontja prg#:#validity_qualification_period#:#A képesítés személyre szabottan jár le -prg#:#validity_qualification_period_desc#:#nappal a befejezés után -prg#:#validity_updated#:#Updated validity###29 07 2022 new variable -prg#:#vq_date#:#Expiration###26 08 2024 new variable +prg#:#validity_qualification_period_desc#:#A képesítés ennyi napig érvényes, utána lejár +prg#:#validity_updated#:#Az érvényességet sikeresen módosította +prg#:#vq_date#:#Lejárat prg#:#vq_date_info#:#A képesítés megadott időpontban jár le -prg#:#vq_date_label#:#Expiry date###26 08 2024 new variable +prg#:#vq_date_label#:#Lejárat dátuma prg#:#vq_information#:#Információk a megszerzett képesítésekről prg#:#vq_period_info#:#A megszerzése után ennyi nappal jár le a képesítés -prg#:#vq_period_label#:#Days after completion###26 08 2024 new variable +prg#:#vq_period_label#:#Befejezés után ennyi nappal prg#:#warning#:#Figyelem! -prg#:#will_not_modify_deadline_on_successful_progress#:#No change because already completed or marked accredited###29 07 2022 new variable -prg#:#will_not_modify_irrelevant_progress#:#No change because not relevant###29 07 2022 new variable -prg#:#will_not_modify_relevant_progress#:#already relevant###29 07 2022 new variable -prg#:#will_not_modify_validity_on_non_successful_progress#:#Can change only when successful###29 07 2022 new variable -prg#:#will_not_set_top_progress_to_irrelevant#:#Cannot change top node to irrelevant.###29 07 2022 new variable -prg#:#will_not_update_cert_for_unsuccessful_progress#:#No certificate for unsuccessful programme###26 08 2024 new variable +prg#:#will_not_modify_deadline_on_successful_progress#:#Nem módosult, mert már teljesített vagy abszolvált az állapota +prg#:#will_not_modify_irrelevant_progress#:#Nem módosult, mert nem releváns +prg#:#will_not_modify_relevant_progress#:#már releváns +prg#:#will_not_modify_validity_on_non_successful_progress#:#Csak teljesített esetén módosítható +prg#:#will_not_set_top_progress_to_irrelevant#:#A legfelső csomópont nem lehet irreleváns. +prg#:#will_not_update_cert_for_unsuccessful_progress#:#Nem jár tanúsítvány a nem teljesített programért prtf#:#pdf_export#:#PDF export -prtf#:#prtf_add_assignment#:#Add Assignment###29 07 2022 new variable +prtf#:#prtf_add_assignment#:#Hozzárendelés hozzáadása prtf#:#prtf_add_page#:#Lap létrehozása prtf#:#prtf_add_portfolio#:#Portfólió hozzáadása -prtf#:#prtf_add_portfolio_from_template#:#Add Portfolio From Template###26 08 2024 new variable +prtf#:#prtf_add_portfolio_from_template#:#Portfólió létrehozása sablonból prtf#:#prtf_all_pages#:#Összes oldal prtf#:#prtf_allow_html#:#HTML/JavaScript engedélyezése prtf#:#prtf_allow_html_info#:#HTML és JavaScript tartalmak engedélyezése a felhasználók portfólió oldalain. Ez biztonsági problémákhoz vezethet. -prtf#:#prtf_allow_my_courses#:#'Kurzusaim' oldalelemei -prtf#:#prtf_allow_my_courses_info#:#A jelenlegi kurzustagságok felsorolásának engedélyezése a portfólióban +prtf#:#prtf_allow_my_courses#:#‘Kurzusaim’ oldalelemei +prtf#:#prtf_allow_my_courses_info#:#A felhasználók pillanatnyi kurzustagságainak felsorolása a portfóliókban. prtf#:#prtf_author#:#Szerző prtf#:#prtf_back_to_portfolio_owner#:#Portfólió módosítása prtf#:#prtf_blog_page_created#:#Sikeresen létrehozott egy blogot. -prtf#:#prtf_copy_blog_pg#:#Copy Blog Page###29 07 2022 new variable +prtf#:#prtf_copy_blog_pg#:#Blogoldal másolása prtf#:#prtf_copy_page#:#Lap(ok) másolása -prtf#:#prtf_copy_pg#:#Copy Page###29 07 2022 new variable +prtf#:#prtf_copy_pg#:#Lap másolása prtf#:#prtf_copy_tab#:#Fül másolása prtf#:#prtf_create_portfolio#:#Portfólió létrehozása prtf#:#prtf_create_template_from_portfolio#:#Portfólió @@ -13758,14 +13825,14 @@ prtf#:#prtf_creation_mode_template#:#Létrehozás sablonból prtf#:#prtf_date_of_print#:#Nyomtatás dátuma prtf#:#prtf_decl_authorship#:#Szerzői nyilatkozat prtf#:#prtf_default_portfolio#:#Személyes adataim -prtf#:#prtf_delete_assignment#:#Delete Assignments###29 07 2022 new variable -prtf#:#prtf_delete_assignment_sure#:#Do you really want to delete the following assignment(s)?###29 07 2022 new variable +prtf#:#prtf_delete_assignment#:#Hozzárendelések törlése +prtf#:#prtf_delete_assignment_sure#:#Biztos, hogy törli az alábbi hozzárendekelés(eke)t? prtf#:#prtf_download_submission#:#A kézbesítés egy példányának letöltése prtf#:#prtf_edit_content#:#Tartalom módosítása -prtf#:#prtf_edit_data#:#Edit Data###29 07 2022 new variable -prtf#:#prtf_edit_embedded_blog#:#'%s' blog módosítása +prtf#:#prtf_edit_data#:#Adat szerkesztése +prtf#:#prtf_edit_embedded_blog#:#‘%s’ blog módosítása prtf#:#prtf_edit_portfolio#:#Portfólió módosítása -prtf#:#prtf_exercise_info#:#Ez a portfólió a(z) '%s' értékelés része, amely a(z) '%s' beadandó feladathoz tartozik. +prtf#:#prtf_exercise_info#:#Ez a portfólió a(z) ‘%s’ értékelés része, amely a(z) ‘%s’ beadandó feladathoz tartozik. prtf#:#prtf_exercise_submitted_info#:#Portfóliója beadásának időpontja: %s. Másolatot készíthet saját fájljairól. prtf#:#prtf_existing_portfolio#:#Meglévő portfólió prtf#:#prtf_finalize_portfolio#:#Portfólió véglegesítése és elküldése @@ -13775,7 +13842,7 @@ prtf#:#prtf_has_been_set_online#:#A portfóliónak online-nak kell lennie. prtf#:#prtf_link#:#Link prtf#:#prtf_manage_portfolios#:#Portfóliók kezelése prtf#:#prtf_new_portfolio#:#Új portfólió -prtf#:#prtf_no_blogs_info#:#'%s' egy blogot sem tartalmaz. Hozzon létre blogokat, hogy portfóliója részeként használhassa azokat. +prtf#:#prtf_no_blogs_info#:#‘%s’ egy blogot sem tartalmaz. Hozzon létre blogokat, hogy portfóliója részeként használhassa azokat. prtf#:#prtf_no_offline_share_info#:#A portfóliónak online-nak kell lennie, hogy megoszthassa másokkal. prtf#:#prtf_no_submission#:#Nincs beküldve prtf#:#prtf_page_created#:#Sikeresen létrehozott egy lapot @@ -13790,9 +13857,9 @@ prtf#:#prtf_page_type_prtf#:#Portfólióoldal prtf#:#prtf_page_type_prtt#:#Portfólió-sablonoldal prtf#:#prtf_pages_copied#:#A lapokat sikeresen másolta. prtf#:#prtf_pdf#:#Exportálás PDF-ként -prtf#:#prtf_permanent_link#:#Link to Portfolio:###26 08 2024 new variable +prtf#:#prtf_permanent_link#:#A portfólióra mutató link: prtf#:#prtf_portfolio_created#:#Sikeresen létrehozott egy portfóliót -prtf#:#prtf_portfolio_created_from_template#:#Ez portfóliójának új előnézete. Új oldal hozzáadásához és a portfólió tartalmának kezeléséhez kattintson ennek az oldalnak a tetején lévő 'Portfólió módosítása' lehetőségre. +prtf#:#prtf_portfolio_created_from_template#:#Ez portfóliójának új előnézete. Új oldal hozzáadásához és a portfólió tartalmának kezeléséhez kattintson ennek az oldalnak a tetején lévő ‘Portfólió módosítása’ lehetőségre. prtf#:#prtf_portfolio_deleted#:#Portfóliót sikeresen törölte. prtf#:#prtf_portfolio_page_deleted#:#Portfólió-/bloglapot sikeresen törölte. prtf#:#prtf_portfolios#:#Portfóliók @@ -13800,11 +13867,11 @@ prtf#:#prtf_print_options#:#Lehetőségek prtf#:#prtf_print_selection#:#Oldalak kijelölése prtf#:#prtf_profile_picture#:#Profilkép megjelenítése prtf#:#prtf_properties#:#Portfólió tulajdonságai -prtf#:#prtf_public_comments#:#Nyilvános megjegyzések -prtf#:#prtf_role_assignment#:#Role Assignment###29 07 2022 new variable -prtf#:#prtf_role_title#:#Role###29 07 2022 new variable +prtf#:#prtf_public_comments#:#Nyilvános megjegyzése +prtf#:#prtf_role_assignment#:#Szerepkör hozzárendelés +prtf#:#prtf_role_title#:#Szerepkör prtf#:#prtf_save_status_and_titles#:#Állapot és címek mentése -prtf#:#prtf_sec_protected_info#:#Protected sections cannot be edited by portfolio owners.###29 07 2022 new variable +prtf#:#prtf_sec_protected_info#:#A védett fejezeteket nem módosíthatják a portfólió tulajdonosai. prtf#:#prtf_selected_pages#:#Kijelölt oldalak prtf#:#prtf_set_default_publish_global#:#Nem csak regisztrált felhasználókkal legyen megosztva prtf#:#prtf_set_default_publish_registered#:#Csak regisztrált felhasználókkal legyen megosztva @@ -13817,23 +13884,23 @@ prtf#:#prtf_signature_date#:#Dátum, aláírása prtf#:#prtf_signature_info#:#Egy mezőt ad a nyomtatáshoz, ahol a szerző aláírhatja a portfólióját. prtf#:#prtf_style#:#Portfólió stílus prtf#:#prtf_submission_on#:#Beküldve: $1 -prtf#:#prtf_successfully_shared_prtf#:#Confirmation Shared Portfolio '%s'###26 08 2024 new variable -prtf#:#prtf_successfully_shared_prtf_body#:#You have shared your portfolio '%s' with:###26 08 2024 new variable +prtf#:#prtf_successfully_shared_prtf#:#‘%s’ portfólió megosztásának megerősítése +prtf#:#prtf_successfully_shared_prtf_body#:#Megosztotta ‘%s’ protfólióját vele: prtf#:#prtf_sure_delete_portfolio_pages#:#Biztos, hogy törli az alábbi portfólió-/bloglapot? prtf#:#prtf_sure_delete_portfolios#:#Biztos, hogy törli az alábbi portfóliót? prtf#:#prtf_tab_other_users#:#Felhasználók portfóliói prtf#:#prtf_tab_portfolios#:#Portfólióim -prtf#:#prtf_table_of_contents#:#Table of Contents###29 10 2025 new variable +prtf#:#prtf_table_of_contents#:#Tartalomjegyzék prtf#:#prtf_template_editor_placeholder_info#:#A portfólióban ezt a helyőrzőt majd lecseréljük. prtf#:#prtf_template_import_blog_create#:#Új blog létrehozása prtf#:#prtf_template_import_blog_ignore#:#Blogoldal eltávolítása prtf#:#prtf_template_import_blog_reuse#:#Létező blog használata -prtf#:#prtf_template_import_new_skills#:#Ha be van kapcsolva, a személyes kompetenciáidhoz hozzáadódnak ezek az elemek. -prtf#:#prtf_template_title#:#Portfolio Template###29 07 2022 new variable +prtf#:#prtf_template_import_new_skills#:#A személyes kompetenciáidhoz hozzáadódnak ezek az elemek. +prtf#:#prtf_template_title#:#Portfólió sablon prtf#:#prtf_unset_as_default#:#Profilomként megszüntetés prtf#:#prtf_unset_default_share_info#:#A módosításokat sikeresen mentette. Ellenőrizze a portfóliómegosztás jelenlegi beállításait! prtf#:#prtf_use_page_layout#:#Lapelrendezés használata -prtf#:#prtf_visible_for_tutor#:#Visible For Tutor###26 08 2024 new variable +prtf#:#prtf_visible_for_tutor#:#A tutorok láthatják prtf#:#prtt_title_info#:#Ez lesz a címe az összes, evvel a sablonnal létrehozott portfóliónak. prtt#:#prtt_activation_limited_visibility_info#:#Amennyiben ezt választja, a portfólió sablon a megadott elérhetőségen kívül is láthatóvá válik. prtt#:#prtt_activation_online_info#:#Ezen beállítás bekapcsolása elérhetővé teszi a felhasználók számára a portfóliósablont. @@ -13842,10 +13909,10 @@ prtt#:#prtt_copy#:#Portfólió sablon másolása prtt#:#prtt_edit#:#Portfólió sablon módosítása prtt#:#prtt_import#:#Portfólió sablon importálása prtt#:#prtt_new#:#Új portfólió sablon -prtt#:#prtt_pfpg#:#Portfolio Page###29 07 2022 new variable +prtt#:#prtt_pfpg#:#Portfólió oldal prtt#:#prtt_portfolio_created#:#Sikeresen létrehozott egy portfóliómintát prtt#:#prtt_properties#:#Portfóliósablon tulajdonságai -prtt#:#prtt_select_datasets#:#Select Datasets###29 07 2022 new variable +prtt#:#prtt_select_datasets#:#Adathalmaz választása prtt#:#prtt_style#:#Portfóliósablon stílus ps#:#cdf_edited_by_self#:#a felhasználó ps#:#crs_ps_cdf_info#:#További kurzusspecifikus adatok: @@ -13854,7 +13921,7 @@ ps#:#grp_ps_cdf_info#:#További csoportspecifikus adatok: ps#:#grp_ps_required_info#:#További csoport-specifikus mezők szükségesek a csoporttartalom eléréséhez. ps#:#ps_agreement_accepted#:#Felhasználói megállapodást elfogadta ps#:#ps_auto_https#:#Automatikus HTTPS felismerés -ps#:#ps_auto_https_description#:#Ha be van kapcsolva, az ILIAS megpróbálja felismerni a HTTP állapotát az alább megadott fejlécérték elemzésével. +ps#:#ps_auto_https_description#:#Az ILIAS megpróbálja felismerni a HTTP állapotát az alább megadott fejlécérték elemzésével. ps#:#ps_auto_https_header_name#:#Fejlécnév ps#:#ps_auto_https_header_value#:#Fejlécérték ps#:#ps_btn_add_value#:#Új érték @@ -13886,15 +13953,15 @@ ps#:#ps_error_message_password_min3_because_chars_numbers_sc#:#A maximális jels ps#:#ps_export_admin#:#Vezetők ps#:#ps_export_confirm#:#Felhasználói megerősítés, amikor kurzusba lép be ps#:#ps_export_confirm_group#:#Felhasználói megerősítés, amikor csoportba lép be -ps#:#ps_export_confirm_group_info#:#When joining a group, users are required to accept that their personal data can be viewed by the group admins.###29 10 2025 new variable -ps#:#ps_export_confirm_info#:#When joining a course, users are required to accept that their personal data can be viewed by the course admins.###29 10 2025 new variable -ps#:#ps_export_course#:#Felhasználó személyes adatainak láthatósága kurzusokban +ps#:#ps_export_confirm_group_info#:#Amikor valaki egy csporthoz csatlakozik, el kell fogadnia, hogy a csoportvezetők láthatják a személyes adatait. +ps#:#ps_export_confirm_info#:#Amikor valaki egy kurzushoz csatlakozik, el kell fogadnia, hogy a kurzusvezetők láthatják a személyes adatait. +ps#:#ps_export_course#:#Felhasználó profiladatainak exportálásának engedélyezése kurzusokban ps#:#ps_export_data#:#Felhasználói adatok adattípusai ps#:#ps_export_excel#:#Excel-export indítása ps#:#ps_export_files#:#Exportfájlok -ps#:#ps_export_groups#:#Felhasználó személyes adatainak láthatósága csoportokban +ps#:#ps_export_groups#:#Felhasználó profiladatainak exportálásának engedélyezése csoportokban ps#:#ps_export_member#:#Tagok -ps#:#ps_export_prgs#:#Allow export of user profile data in Study Programmes###26 08 2024 new variable +ps#:#ps_export_prgs#:#A Képzési programban a felhasználó profiladatok exportálásának engedélyezése ps#:#ps_export_settings#:#Exportbeállítások ps#:#ps_export_sub#:#Feliratkozottak ps#:#ps_export_tutor#:#Tutorok @@ -13910,10 +13977,10 @@ ps#:#ps_participants_list_courses#:#Résztvevők felsorolásának bekapcsolása ps#:#ps_passwd_policy_change_force_user_reset_succ#:#A módosításokat sikeresen alkalmazta. ps#:#ps_passwd_policy_changed_force_user_reset#:#A módosításokat sikeresen mentette. Az egyik jelszószabályt módosította. Kényszerítsük az összes felhasználót jelszava cseréjére a következő bejelentkezéskor? ps#:#ps_password_change_on_first_login_enabled#:#Jelszó cseréje első bejelentkezéskor -ps#:#ps_password_change_on_first_login_enabled_info#:#Ha be van kapcsolva, a felhasználóknak le kell cserélniük jelszavukat első bejelentkezéskor (kivéve azoknak a felhasználóknak, akik magukat regisztrálták). +ps#:#ps_password_change_on_first_login_enabled_info#:#A felhasználóknak le kell cserélniük jelszavukat első bejelentkezéskor (kivéve azoknak a felhasználóknak, akik magukat regisztrálták). ps#:#ps_password_chars_and_numbers_enabled#:#Karakterek és számok -ps#:#ps_password_chars_and_numbers_enabled_info#:#Ha be van kapcsolva, a jelszavaknak karaktereket és számokat is kell tartalmaznia. -ps#:#ps_password_force_user_reset#:#Force Password Reset###29 10 2025 new variable +ps#:#ps_password_chars_and_numbers_enabled_info#:#A jelszavaknak karaktereket és számokat is kell tartalmaznia. +ps#:#ps_password_force_user_reset#:#Jelszó-visszaállítás kényszerítése ps#:#ps_password_max_age#:#Maximális jelszóélettartam ps#:#ps_password_max_age_info#:#Jelszavak napokban kifejezett érvényességének beállítása. Állítsa 0-ra az opció letiltásához. ps#:#ps_password_max_length#:#Maximális jelszóhossz @@ -13922,17 +13989,17 @@ ps#:#ps_password_min_length#:#Minimális jelszóméret ps#:#ps_password_min_length_info#:#ILIAS-fiók jelszavak minimális hosszának beállítása. Ha 0-ra állítja, a jelszavaknak minimálisan 1 karakter hosszúnak kell lenniük. ps#:#ps_password_settings#:#Jelszóbeállítások ps#:#ps_password_special_chars_enabled#:#Speciális karakterek -ps#:#ps_password_special_chars_enabled_info#:#Ha be van kapcsolva, a jelszavaknak speciális karaktereket kell tartalmaznia. +ps#:#ps_password_special_chars_enabled_info#:#A jelszavaknak speciális karaktereket kell tartalmaznia. ps#:#ps_perform_export#:#CSV-export indítása ps#:#ps_prevent_simultaneous_logins#:#Párhuzamos bejelentkezések megakadályozása -ps#:#ps_prevent_simultaneous_logins_info#:#Ha be van kapcsolva, bejelentkezés ugyanazon felhasználónévvel különböző számítógépekről egy időben nem lehetséges. +ps#:#ps_prevent_simultaneous_logins_info#:#Bejelentkezés ugyanazon felhasználónévvel különböző számítógépekről egy időben nem lehetséges. ps#:#ps_privacy_protection#:#Adatvédelmi beállítások ps#:#ps_profile_export#:#Felhasználói adatok védelme ps#:#ps_security_protection#:#Biztonsági beállítások ps#:#ps_select_one#:#Válasszon egy exportfájlt ps#:#ps_show_crs_access#:#Kurzustagok utolsó látogatási idejének megjelenítése ps#:#ps_show_grp_access#:#Csoporttagok utolsó látogatási idejének megjelenítése -ps#:#ps_show_lso_access#:#Show last access time of learning sequence participants###26 08 2024 new variable +ps#:#ps_show_lso_access#:#A tanulási sor résztvevőinél az utolsó elérési idő megjelenítése ps#:#ps_size#:#Fájlméret ps#:#ps_type_select#:#Mező kiválasztása ps#:#ps_type_select_long#:#Kiválasztódoboz (megadott értékek) @@ -13941,43 +14008,72 @@ ps#:#ps_type_txt_long#:#Szövegmező (opcionális értékek) ps#:#ps_user_selection#:#Résztvevők kiválasztása ps#:#ps_warning_modify#:#Figyelmeztetés: Legalább egy felhasználó elfogadta a felhasználói megállapodást. Ezeknek a kurzusspecifikus mezőknek a módosítása visszaállítja alapértékre az összes felhasználói elfogadást. ps#:#rbac_log#:#Naplózási jogosultság -ps#:#rbac_log_age#:#Logbejegyzések megtartása -ps#:#rbac_log_age_info#:#Logbejegyzések maximális száma a hónapban -ps#:#rbac_log_info#:#Az összes objektum-jogosultságbeli módosítás logolásának engedélyezése +ps#:#rbac_log_age#:#Naplóbejegyzések megtartása +ps#:#rbac_log_age_info#:#Naplóbejegyzések maximális élettartama hónapokban +ps#:#rbac_log_info#:#Az összes objektum-jogosultságbeli módosítás naplózása ps#:#show_privacy#:#Adatvédelem ps#:#show_security#:#Biztonság pwassist#:#password_assistance#:#Jelszósegédlet pwassist#:#pwassist_disabled_no_access#:#A jelszósegédlet nincs bekapcsolva. További információért keresse a üzemeltetőt: %s -pwassist#:#pwassist_enter_email#:#Adjon meg egy e-mail címet. Az ILIAS egy e-mailt küld erre a címre, amely tartalmazza az összes felhasználónevet, amely ezt az e-mail címet adta meg. Válassza ki a kívánt felhasználónevet, és használja a jelszósegédletet új jelszó megadásához. Ha rövid időn belül nem kapja meg az e-mailt, vegye fel a kapcsolatot egy rendszergazdával vagy küldjön e-mailt a következő címre: %1$s -pwassist#:#pwassist_enter_username_and_email#:#Adjon meg egy felhasználónevet és a hozzá tartozó e-mail címet. Az ILIAS üzenetet küld az e-mail címre, amely azon weblap címét tartalmazza, ahol új jelszót adhat meg ILIAS-fiókjához. Ha ezután sem sikerül bejelentkeznie, vegye fel a kapcsolatot egy rendszergazdával, vagy küldjön e-mailt a következő címre: %1$s +pwassist#:#pwassist_enter_email#:#Adjon meg egy e-mail címet. Az ILIAS egy e-mailt küld erre a címre, amely tartalmazza az összes felhasználónevet, amely ezt az e-mail címet adta meg. Válassza ki a kívánt felhasználónevet, és használja a jelszósegédletet új jelszó megadásához. Ha rövid időn belül nem kapja meg az e-mailt, vegye fel a kapcsolatot egy rendszergazdával vagy küldjön e-mailt a következő címre: %1$s +pwassist#:#pwassist_enter_username_and_email#:#Adjon meg egy felhasználónevet és a hozzá tartozó e-mail címet. Az ILIAS üzenetet küld az e-mail címre, amely azon weblap címét tartalmazza, ahol új jelszót adhat meg ILIAS-fiókjához. Ha ezután sem sikerül bejelentkeznie, vegye fel a kapcsolatot egy rendszergazdával, vagy küldjön e-mailt a következő címre: %1$s pwassist#:#pwassist_enter_username_and_new_password#:#Adja meg a felhasználónevet és az új jelszót! pwassist#:#pwassist_login_not_match#:#Másik felhasználónevet adjon meg! A megadott felhasználónév nem egyezik meg azzal, amelyet a jelszósegédlettől kért. -pwassist#:#pwassist_mail_body#:#Adjon meg új jelszót az ILIAS-fiókjához: %1$s Ezt az üzenetet automatikusan generálta az alábbi ILIAS-szerver %2$s Ön (vagy valaki %3$s) jelszósegédletet kért a '%4$s' ILIAS-fiókhoz. Gondosan ellenőrizze az alább felsorolt lehetőségeket, és azok szerint járjon el: - Ha esetleg az ILIAS szerveren levő jelszósegédlet-űrlapot használta volna: Törölje ezt a levelet. - Ha biztos benne, hogy soha nem kért jelszósegédletet ettől az ILIAS-szervertől: Vegye fel a kapcsolatot: %5$s. - Ha kért jelszósegédletet, járjon el az alábbiak szerint: 1. Nyissa meg böngészőjét. 2. Adja meg a következő címet böngészőjében: %6$s Fontos: a cím egysoros. Ha azt látja, hogy a cím több részből tevődik össze, levelezőprogramja szúrta be a sortöréseket az útvonalba. 3. A böngészője által megjelenített weboldalon adjon meg egy új jelszót bejelentkezéséhez. Vegye figyelembe, hogy biztonsági okokból a fent leírt három lépést csak egyszer hajthatja végre, és csak időkorláton belül. Azután a cím érvénytelenné válik, és Önnek az ILIAS szerveren levő jelszósegédletet kell újra használnia. -pwassist#:#pwassist_mail_sent#:#Üzenetet küldtünk a következő címre: %1$s Ellenőrizze postaládáját! +pwassist#:#pwassist_mail_body#:#Adjon meg új jelszót az ILIAS-fiókjához: %1$s

    Ezt az üzenetet automatikusan generálta az alábbi ILIAS-szerver %2$s

    Ön (vagy valaki %3$s) jelszósegédletet kért a ‘%4$s’ ILIAS-fiókhoz. Gondosan ellenőrizze az alább felsorolt lehetőségeket, és azok szerint járjon el:

    • Ha esetleg az ILIAS szerveren levő jelszósegédlet-űrlapot használta volna: Törölje ezt a levelet.

    • Ha biztos benne, hogy soha nem kért jelszósegédletet ettől az ILIAS-szervertől: Vegye fel a kapcsolatot: %5$s.

    • Ha kért jelszósegédletet, járjon el az alábbiak szerint:
    1. Nyissa meg böngészőjét.
    2. Adja meg a következő címet böngészőjében: %6$s
    Fontos: a cím egysoros. Ha azt látja, hogy a cím több részből tevődik össze, levelezőprogramja szúrta be a sortöréseket az útvonalba.
    3. A böngészője által megjelenített weboldalon adjon meg egy új jelszót bejelentkezéséhez.

    Vegye figyelembe, hogy biztonsági okokból a fent leírt három lépést csak egyszer hajthatja végre, és csak időkorláton belül. Azután a cím érvénytelenné válik, és Önnek az ILIAS szerveren levő jelszósegédletet kell újra használnia. +pwassist#:#pwassist_mail_sent#:#Üzenetet küldtünk a következő címre: %1$s Ellenőrizze postaládáját! pwassist#:#pwassist_mail_sent_generic#:#Üzenetet küldtünk az ILIAS-ban megadott e-mail címére. Ellenőrizze postaládáját! pwassist#:#pwassist_mail_subject#:#ILIAS-jelszósegédlet -pwassist#:#pwassist_password_assigned#:#'%1$s' felhasználó jelszavát sikeresen cseréltük. +pwassist#:#pwassist_password_assigned#:#‘%1$s’ felhasználó jelszavát sikeresen cseréltük. pwassist#:#pwassist_session_expired#:#Töltse ki újra ezt az űrlapot! Jelszósegédlet-munkamenete lejárt. Ez azért történhetett, mert megpróbálta többször használni az e-mailben elküldött linket, vagy mert túl sok idő telt el azóta, hogy elküldték önnek a linket. -pwassist#:#pwassist_username_mail_body#:#Ehhez az e-mail címhez az alábbi felhasználónevek tartoznak: %s Ezt az üzenetet automatikusan küldte a következő ILIAS-szerver: %s %s IP-címről e-mail kértek %s e-mailhez tartozó felhasználónév elfelejtett jelszava miatt. Gondosan ellenőrizze az alább felsorolt lehetőségeket, és azok szerint járjon el: -Ha véletlenül kérte ezt a levelet, törölje. -Ha biztos, hogy nem kérte ezt a levelet, vegye fel a kapcsolatot a rendszergazdával: %s. Ha Ön kérte ezt a levelet, járjon el a jelszósegédlet oldalán leírtak szerint: 1. Nyissa meg böngészőjét. 2. Adja meg a következő címet böngészőjében: %s Fontos: a cím egysoros. Ha azt látja, hogy a cím több részből tevődik össze, levelezőprogramja szúrta be a sortöréseket az útvonalba. 3. A böngészője által megjelenített weboldalon adja meg az egyik fiók e-mail címét, melynek vissza kívánja szerzi jelszavát. +pwassist#:#pwassist_username_mail_body#:#Ehhez az e-mail címhez az alábbi felhasználónevek tartoznak: %s

    Ezt az üzenetet automatikusan küldte a következő ILIAS-szerver: %s

    %s IP-címről e-mail kértek %s e-mailhez tartozó felhasználónév elfelejtett jelszava miatt. Gondosan ellenőrizze az alább felsorolt lehetőségeket, és azok szerint járjon el:

    • Ha véletlenül kérte ezt a levelet, törölje.

    • Ha biztos, hogy nem kérte ezt a levelet, vegye fel a kapcsolatot a rendszergazdával: %s.

    • Ha Ön kérte ezt a levelet, járjon el a jelszósegédlet oldalán leírtak szerint:
    1. Nyissa meg böngészőjét.
    2. Adja meg a következő címet böngészőjében: %s
    Fontos: a cím egysoros. Ha azt látja, hogy a cím több részből tevődik össze, levelezőprogramja szúrta be a sortöréseket az útvonalba.
    3. A böngészője által megjelenített weboldalon adja meg az egyik fiók e-mail címét, melynek vissza kívánja szerzi jelszavát. pwassist#:#unassist_disabled_no_access#:#A felhasználónév-segédlet nincs bekapcsolva. További információért keresse az üzemeltetőt: %s pwsp#:#pwsp_enable_personal_resources#:#Személyes erőforrások bekapcsolása pwsp#:#pwsp_enable_wsp_blogs#:#Blogok bekapcsolása pwsp#:#pwsp_enable_wsp_files#:#Fájlok bekapcsolása pwsp#:#pwsp_enable_wsp_links#:#Linkek bekapcsolása -pwsp#:#pwsp_type_cannot_be_copied#:#Objects of type '%s' cannot be copied.###29 10 2025 new variable -qpl#:#qpl_filter_commented_exclude#:#Questions without comments###26 08 2024 new variable -qpl#:#qpl_filter_commented_only#:#Questions with comments###26 08 2024 new variable +pwsp#:#pwsp_type_cannot_be_copied#:#‘%s’ típusú objektumok nem másolhatók. +qpl#:#qpl_filter_commented_exclude#:#Megjegyzések nélküli kérdések +qpl#:#qpl_filter_commented_only#:#Megjegyzéssel ellátott kérdések qpl#:#qpl_page_type_qfbg#:#Általános visszajelzés qpl#:#qpl_page_type_qfbs#:#Speciális visszajelzés qpl#:#qpl_page_type_qht#:#Tipp qpl#:#qpl_page_type_qpl#:#Kérdésoldala +qsts#:#answer_options#:#Válaszlehetőségek +qsts#:#cloze_text#:#Kiegészítendő szöveg +qsts#:#cloze_textgapcase_insensitive#:#Kis-/nagybetűre nem érzékeny +qsts#:#cloze_textgapcase_sensitive#:#Kis-/nagybetűre érzékeny +qsts#:#cloze_textgaplevenshtein_of#:#'%s' Levenshtein-távolsága +qsts#:#confirm_delete_questions#:#Biztos, hogy eltávolítja az alábbi kérdés(eke)t? +qsts#:#create_question#:#Kérdés létrehozása +qsts#:#gap#:#Kitöltendő hely +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Kitöltendő hely beszúrása +qsts#:#min_auto_complete#:#Automatikus kiegészítés +qsts#:#msg_no_questions_selected#:#Egy kérdés sincs kiválasztva. +qsts#:#out_of_range#:#Tartományon kívül esik +qsts#:#qst_lifecycle#:#Életciklus +qsts#:#qst_lifecycle_draft#:#Piszkozat +qsts#:#qst_lifecycle_filter_all#:#Összes életciklus +qsts#:#qst_lifecycle_final#:#Végső +qsts#:#qst_lifecycle_outdated#:#Elavult +qsts#:#qst_lifecycle_rejected#:#Elutasított +qsts#:#qst_lifecycle_review#:#Átnézendő +qsts#:#qst_lifecycle_sharable#:#Megosztható +qsts#:#questionlist#:#Kérdéslista +qsts#:#questions#:#Kérdések +qsts#:#range_lower_limit#:#Alsó határ +qsts#:#range_upper_limit#:#Felső határ +qsts#:#reset_preview#:#Előnézet alaphelyzetbe állítása +qsts#:#select_gap#:#Szöveghely választása +qsts#:#shuffle_answers#:#Kevert válaszok +qsts#:#suggested_learning_content#:#Ismétlő összefoglaláshoz tartalom hozzáadása rating#:#rat_not_rated_yet#:#Még nincs értékelve rating#:#rat_nr_ratings#:#%s értékelés rating#:#rat_one_rating#:#Egy értékelés rating#:#rating_activate_rating#:#Értékelések engedélyezése -rating#:#rating_activate_rating_info#:#Ha be van kapcsolva, a felhasználók értékelhetik ezt az objektumot. +rating#:#rating_activate_rating_info#:#A felhasználók értékelhetik ezt az objektumot. rating#:#rating_add_category#:#Kategória létrehozása -rating#:#rating_avg_rating#:#Average Rating###29 07 2022 new variable +rating#:#rating_avg_rating#:#Értékelések átlaga rating#:#rating_categories#:#Értékelési kategóriák rating#:#rating_category_add#:#Hozzáadás rating#:#rating_category_create#:#Kategória létrehozása @@ -13993,10 +14089,10 @@ rating#:#rating_export_rating#:#Értékelés rating#:#rating_new_objects_auto#:#Alapértelmezett objektum-értékelhetőség rating#:#rating_new_objects_auto_info#:#Alapértelmezetten az értékelhetőség aktív új fájlokra, tananyagokra és wikikre. rating#:#rating_number_votes#:#%s értékelés -rating#:#rating_open_dialog#:#Open rating dialog###29 07 2022 new variable +rating#:#rating_open_dialog#:#Értékelő dialógus megnyitása rating#:#rating_overlay_submit#:#Értékelés elküldése -rating#:#rating_personal_rating#:#Your Rating###29 07 2022 new variable -rating#:#rating_rate_x_of_5#:#Rate with %s of 5 stars###29 07 2022 new variable +rating#:#rating_personal_rating#:#Az Ön értékelése +rating#:#rating_rate_x_of_5#:#5-ből %s csillagos értékelés rating#:#rating_remove#:#Értékelés eltávolítása rating#:#rating_update_positions#:#Kategória mentése rating#:#rating_your_rating#:#Az Ön értékelése @@ -14008,18 +14104,18 @@ rbac#:#activate_wiki_protection#:#Írásvédett rbac#:#active_preconditions#:#Előfeltételek rbac#:#add_consultation_hours#:#Konzultációs időpontok létrehozása rbac#:#add_consume_provider#:#Saját LTI-Kiszolgáló beállításai -rbac#:#add_pages#:#Add Pages###26 08 2024 new variable +rbac#:#add_pages#:#Oldalak hozzáadása rbac#:#add_reply#:#Válasz létrehozása rbac#:#add_thread#:#Téma létrehozása rbac#:#adm_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Általános beállítások jogosultsági beállításait rbac#:#adm_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Általános beállítások beállításaihoz rbac#:#adm_visible#:#A felhasználó láthatja a Rendszerbeállítások » Általános beállítások menüpontot rbac#:#adm_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Általános beállítások beállításait -rbac#:#adn_edit_permission#:#User can change permissions of Administrative Notifications' administration.###29 07 2022 new variable -rbac#:#adn_read#:#User has read access to administration of Administrative Notifications.###29 07 2022 new variable -rbac#:#adn_visible#:#Administration of Administrative Notifications is visible.###29 07 2022 new variable -rbac#:#adn_write#:#User can add and edit Administrative Notifications.###29 07 2022 new variable -rbac#:#adopt_perm_from_template#:#Jogosultsági beállítások másolása +rbac#:#adn_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Rendszerértesítések jogosultsági beállításait +rbac#:#adn_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Rendszerértesítések beállításaihoz +rbac#:#adn_visible#:#A felhasználó láthatja a Rendszerbeállítások » Rendszerértesítések menüpontot +rbac#:#adn_write#:#A felhasználó hozzáadhat és módosíthat rendszerértesítést +rbac#:#adopt_perm_from_template#:#Jogosultsági beállítások másolása ide másik szerepkörből rbac#:#adve_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Szerkesztés jogosultsági beállításait rbac#:#adve_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Szerkesztés beállításaihoz rbac#:#adve_visible#:#A felhasználó láthatja a Rendszerbeállítások » Szerkesztés menüpontot @@ -14033,14 +14129,14 @@ rbac#:#auth_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállít rbac#:#auth_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Hitelesítése és regisztráció beállításaihoz rbac#:#auth_visible#:#A felhasználó láthatja a Rendszerbeállítások » Hitelesítés és regisztráció menüpontot rbac#:#auth_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Hitelesítés és regisztráció beállításait -rbac#:#awra_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Ki van online' jogosultsági beállításait -rbac#:#awra_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » 'Ki van online' beállításaihoz -rbac#:#awra_visible#:#A felhasználó láthatja a Rendszerbeállítások » 'Ki van online' menüpontot -rbac#:#awra_write#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Ki van online' beállításait -rbac#:#bdga_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Érdemérmek' jogosultsági beállításait -rbac#:#bdga_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » 'Érdemérmek' beállításaihoz -rbac#:#bdga_visible#:#A felhasználó láthatja a Rendszerbeállítások » 'Érdemérmek' menüpontot -rbac#:#bdga_write#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Érdemérmek' beállításait +rbac#:#awra_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » ‘Ki van online’ jogosultsági beállításait +rbac#:#awra_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » ‘Ki van online’ beállításaihoz +rbac#:#awra_visible#:#A felhasználó láthatja a Rendszerbeállítások » ‘Ki van online’ menüpontot +rbac#:#awra_write#:#A felhasználó módosíthatja a Rendszerbeállítások » ‘Ki van online’ beállításait +rbac#:#bdga_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Érdemérmek jogosultsági beállításait +rbac#:#bdga_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Érdemérmek beállításaihoz +rbac#:#bdga_visible#:#A felhasználó láthatja a Rendszerbeállítások » Érdemérmek menüpontot +rbac#:#bdga_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Érdemérmek beállításait rbac#:#bibl_copy#:#A felhasználó másolhatja a bibliográfiát rbac#:#bibl_delete#:#A felhasználó mozgathatja és törölheti a bibliográfiát rbac#:#bibl_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat @@ -14055,7 +14151,7 @@ rbac#:#bibs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Bibl rbac#:#bibs_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Bibliográfia beállításait rbac#:#blga_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Blog jogosultsági beállításait rbac#:#blga_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Blog beállításaihoz -rbac#:#blga_visible#:#A felhasználó láthatja a Rendszerbeállítások » Blogo menüpontot +rbac#:#blga_visible#:#A felhasználó láthatja a Rendszerbeállítások » Blog menüpontot rbac#:#blga_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Blog beállításait rbac#:#blog_contribute#:#A felhasználó blogbejegyzést írhat és tehet közzé rbac#:#blog_copy#:#A felhasználó másolhat blogot @@ -14068,8 +14164,8 @@ rbac#:#blog_write#:#A felhasználó szerkeszthet blogbeállításokat rbac#:#book_copy#:#A felhasználó másolhat foglalásgyűjteményt. rbac#:#book_delete#:#A felhasználó áthelyezhet vagy törölhet foglalásgyűjteményt rbac#:#book_edit_permission#:#A felhasználó megváltoztathatja a foglalásgyűjteményt jogosultságait -rbac#:#book_manage_all_reservations#:#User can manage all reservations###28 10 2024 new variable -rbac#:#book_manage_own_reservations#:#User can manage own reservations###28 10 2024 new variable +rbac#:#book_manage_all_reservations#:#A felhasználó kezelheti az összes foglalást +rbac#:#book_manage_own_reservations#:#A felhasználó kezelheti a saját foglalásait rbac#:#book_read#:#A felhasználó foglalhat a foglalásgyűjtemény erőforrásaiból/objektumaiból rbac#:#book_visible#:#A foglalásgyűjtemény látható rbac#:#book_write#:#A felhasználó megváltoztathatja a foglalásgyűjteményt beállításait és tartalmát @@ -14097,10 +14193,10 @@ rbac#:#catr_delete#:#A felhasználó áthelyezhet vagy törölhet kategórialink rbac#:#catr_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#catr_visible#:#A kategórialink látható rbac#:#catr_write#:#A felhasználó szerkeszthet kategórialinket beállításokat -rbac#:#cert_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Igazolás jogosultsági beállításait -rbac#:#cert_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Igazolás beállításaihoz -rbac#:#cert_visible#:#A felhasználó láthatja a Rendszerbeállítások » Igazolás menüpontot -rbac#:#cert_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Igazolás beállításait +rbac#:#cert_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanúsítvány jogosultsági beállításait +rbac#:#cert_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Tanúsítvány beállításaihoz +rbac#:#cert_visible#:#A felhasználó láthatja a Rendszerbeállítások » Tanúsítvány menüpontot +rbac#:#cert_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanúsítvány beállításait rbac#:#change_existing_object_type_desc#:#Ez meg fogja változtatni a típus már létező objektumainak jogosultság-beállításait is rbac#:#change_existing_objects#:#A fastruktúra jelen pontjától örökítés rbac#:#change_existing_objects_desc#:#Ennek a szerepnek a jogosultsági beállításait alkalmazzuk az összes, már létező objektumra. Ha csak bizonyos objektumtípusokra szeretné a változtatást, kattintson a jelölőnégyzetekre a kiválasztandó objektumtípus jobb oldalán. @@ -14115,30 +14211,30 @@ rbac#:#chtr_moderate#:#A felhasználó moderálhat beszélgetést csevegőszobá rbac#:#chtr_read#:#A felhasználó csatlakozhat és részt vehet a csevegőszobában rbac#:#chtr_visible#:#A csevegőszoba látható rbac#:#chtr_write#:#A felhasználó szerkesztheti a csevegőszoba beállításait, és kitilthat felhasználókat -rbac#:#cmis_edit_permission#:#User can change permission settings of xAPI/cmi5 administration.###29 10 2025 new variable -rbac#:#cmis_read#:#User has read access to xAPI/cmi5 administration.###29 07 2022 new variable -rbac#:#cmis_visible#:#Administration of xAPI/cmi5 is visible.###29 07 2022 new variable -rbac#:#cmis_write#:#User can edit settings of xAPI/cmi5 administration.###29 07 2022 new variable -rbac#:#cmix_copy#:#A felhasználó másolhat xAPI/cmi5 objektumot -rbac#:#cmix_delete#:#User can move or delete xAPI/cmi5 Object -rbac#:#cmix_edit_learning_progress#:#User can edit learning progress settings -rbac#:#cmix_edit_permission#:#User can change permission settings -rbac#:#cmix_read#:#A felhasználó láthatja xAPI/cmi5 Object -rbac#:#cmix_read_learning_progress#:#User can view learning progress of other users -rbac#:#cmix_read_outcomes#:#A felhasználó láthatja learning experiences and ranking of other users -rbac#:#cmix_visible#:#xAPI/cmi5 Object is visible -rbac#:#cmix_write#:#User can edit settings of xAPI/cmi5 Object +rbac#:#cmis_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » xAPI/cmi5 jogosultsági beállításait +rbac#:#cmis_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » xAPI/cmi5 beállításaihoz +rbac#:#cmis_visible#:#A felhasználó láthatja a Rendszerbeállítások » xAPI/cmi5 menüpontot +rbac#:#cmis_write#:#A felhasználó módosíthatja a Rendszerbeállítások » xAPI/cmi5 beállításait +rbac#:#cmix_copy#:#A felhasználó másolhat xAPI/cmi5-objektumot +rbac#:#cmix_delete#:#A felhasználó áthelyezhet vagy törölhet xAPI/cmi5-objektumot +rbac#:#cmix_edit_learning_progress#:#A felhasználó szerkesztheti tanulási haladás beállításait +rbac#:#cmix_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat +rbac#:#cmix_read#:#A felhasználó láthatja a xAPI/cmi5-objektumot +rbac#:#cmix_read_learning_progress#:#A felhasználó láthatja más felhasználók tanulási haladását +rbac#:#cmix_read_outcomes#:#A felhasználó láthatja más felhasználók tanulási tapasztalatait és rangsorolásait +rbac#:#cmix_visible#:#Az xAPI/cmi5-objektum látható +rbac#:#cmix_write#:#A felhasználó szerkesztheti xAPI/cmi5-objektum beállításait rbac#:#cmps_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Bővítmények jogosultsági beállításait rbac#:#cmps_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Bővítmények beállításaihoz rbac#:#cmps_visible#:#A felhasználó láthatja a Rendszerbeállítások » Bővítmények menüpontot rbac#:#cmps_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Bővítmények beállításait -rbac#:#coms_edit_permissions#:#User can change permission settings of administration of Comments.###29 07 2022 new variable -rbac#:#coms_read#:#User has read access to administration of Comments.###29 07 2022 new variable -rbac#:#coms_visible#:#Administration of Comments is visible.###29 07 2022 new variable -rbac#:#coms_write#:#User can edit settings of administration of Comments.###29 07 2022 new variable +rbac#:#coms_edit_permissions#:#A felhasználó módosíthatja a Rendszerbeállítások » Hozzászólások jogosultsági beállításait +rbac#:#coms_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Hozzászólások beállításaihoz +rbac#:#coms_visible#:#A felhasználó láthatja a Rendszerbeállítások » Hozzászólások menüpontot +rbac#:#coms_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Hozzászólások beállításait rbac#:#condition_failed#:#Sikertelen rbac#:#condition_learning_progress#:#Tanulási haladásból származik -rbac#:#condition_result_range_percentage#:#Result Range###28 10 2024 new variable +rbac#:#condition_result_range_percentage#:#Eredménytartomány rbac#:#contribute#:#Közreműködés rbac#:#copa_copy#:#Tartalomlap másolása rbac#:#copa_delete#:#A felhasználó mozgathatja, illetve törölheti a tartalomlapot @@ -14146,12 +14242,12 @@ rbac#:#copa_edit_learning_progress#:#A felhasználó módosíthatja a tanulási rbac#:#copa_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#copa_read#:#A felhasználó olvashatja a tartalomlapot rbac#:#copa_read_learning_progress#:#A felhasználó megnézheti mások tanulási haladását -rbac#:#copa_visible#:#A tartalomlapok láthatóak +rbac#:#copa_visible#:#A tartalomlapok láthatók rbac#:#copa_write#:#A felhasználó módosíthatja a tartalomlapot -rbac#:#cpad_edit_permissions#:#User can change permission settings of administration of Content Pages.###29 07 2022 new variable -rbac#:#cpad_read#:#User has read access to administration of Content Pages.###29 07 2022 new variable -rbac#:#cpad_visible#:#Administration of Content Pages is visible.###29 07 2022 new variable -rbac#:#cpad_write#:#User can edit settings of administration of Content Pages.###29 07 2022 new variable +rbac#:#cpad_edit_permissions#:#A felhasználó módosíthatja a Rendszerbeállítások » Tartalomlap jogosultsági beállításait +rbac#:#cpad_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Tartalomlap beállításaihoz +rbac#:#cpad_visible#:#A felhasználó láthatja a Rendszerbeállítások » Tartalomlap menüpontot +rbac#:#cpad_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Tartalomlap beállításait rbac#:#crs_copy#:#A felhasználó másolhat kurzust rbac#:#crs_delete#:#A felhasználó áthelyezhet vagy törölhet kurzust rbac#:#crs_edit_event#:#Naptáresemények módosítása @@ -14168,9 +14264,9 @@ rbac#:#crs_visible#:#A kurzus látható rbac#:#crs_write#:#A felhasználó módosíthatja a kurzus beállításait és kezelheti a tartalmát rbac#:#crsr_copy#:#A felhasználó másolhat kurzuslinket rbac#:#crsr_delete#:#A felhasználó áthelyezhet vagy törölhet kurzuslinket -rbac#:#crsr_edit_learning_progress#:#User can edit learning progress settings###26 08 2024 new variable +rbac#:#crsr_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait rbac#:#crsr_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat -rbac#:#crsr_read_learning_progress#:#User can view learning progress of other users###26 08 2024 new variable +rbac#:#crsr_read_learning_progress#:#A felhasználó megtekintheti a többi felhasználó tanulási haladását rbac#:#crsr_visible#:#A kurzuslink látható rbac#:#crsr_write#:#A felhasználó szerkesztheti kurzuslinket rbac#:#crss_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Kurzus jogosultsági beállításait @@ -14188,10 +14284,10 @@ rbac#:#dcl_write#:#A felhasználó szerkesztheti az adatgyűjtés beállításai rbac#:#delete_files#:#Fájlok törlése rbac#:#delete_folders#:#Mappák törlése rbac#:#delete_wiki_pages#:#Oldalak törlése -rbac#:#dpro_edit_permission#:#User can change permission settings in the Declaration of Data Protected administration###29 10 2025 new variable -rbac#:#dpro_read#:#User has read access to the Declaration of Data Protection administration###29 10 2025 new variable -rbac#:#dpro_visible#:#Declaration of Data Protection administration is visible###29 10 2025 new variable -rbac#:#dpro_write#:#Edit settings in the Declaration of Data Protection###29 10 2025 new variable +rbac#:#dpro_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Adatvédelem Nyilatkozat jogosultsági beállításait +rbac#:#dpro_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Adatvédelem Nyilatkozat beállításaihoz +rbac#:#dpro_visible#:#A felhasználó láthatja a Rendszerbeállítások » Adatvédelem Nyilatkozat menüpontot +rbac#:#dpro_write#:#A felhasználó szerkesztheti az Adatvédelem Nyilatkozatot rbac#:#dshs_change_presentation#:#Műszerfal megjelenítésének módosítása rbac#:#dshs_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Műszerfal jogosultsági beállításait rbac#:#dshs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Műszerfal beállításaihoz @@ -14202,9 +14298,9 @@ rbac#:#ecss_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbe rbac#:#ecss_visible#:#A felhasználó láthatja a Rendszerbeállítások » ECS menüpontot rbac#:#ecss_write#:#A felhasználó módosíthatja a Rendszerbeállítások » ECS beállításait rbac#:#edit_event#:#Naptár módosítása -rbac#:#edit_file#:#Edit File###26 08 2024 new variable -rbac#:#edit_in_online_editor#:#Open in online editor###29 07 2022 new variable -rbac#:#edit_learning_progress#:#Tanulási haladás módosítása +rbac#:#edit_file#:#Fájl módosítása +rbac#:#edit_in_online_editor#:#Megnyitás online szerkesztővel +rbac#:#edit_learning_progress#:#Tanulási haladás beállításainak módosítása rbac#:#edit_members#:#Tagok kezelése rbac#:#edit_permission#:#Jogosultságok módosítása rbac#:#edit_roleassignment#:#Szerep-hozzárendelés módosítása @@ -14225,10 +14321,6 @@ rbac#:#excs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbe rbac#:#excs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Beadandó feladat menüpontot rbac#:#excs_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Beadandó feladat beállításait rbac#:#export_member_data#:#Felhasználói adatokhoz hozzáférés -rbac#:#extt_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Harmadik fél szoftvere' jogosultsági beállításait -rbac#:#extt_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » 'Harmadik fél szoftvere' beállításaihoz -rbac#:#extt_visible#:#A felhasználó láthatja a Rendszerbeállítások » 'Harmadik fél szoftvere' menüpontot -rbac#:#extt_write#:#A felhasználó módosíthatja a Rendszerbeállítások » 'Harmadik fél szoftvere' beállításait rbac#:#facs_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Fájlok és mappák jogosultsági beállításait rbac#:#facs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Fájlok és mappák beállításaihoz rbac#:#facs_upload_blacklisted_files#:#Az indexelt fájlok feltltése a tiltólista megkerülésével @@ -14239,27 +14331,27 @@ rbac#:#feed_delete#:#A felhasználó áthelyezhet vagy törölhet webhírforrás rbac#:#feed_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#feed_read#:#A felhasználó olvashat webhírforrást rbac#:#feed_write#:#A felhasználó módosíthat webhírforrás-beállításokat -rbac#:#file_content#:#Show Content###29 10 2025 new variable +rbac#:#file_content#:#Tartalom megjelentése rbac#:#file_copy#:#A felhasználó másolhat fájlt rbac#:#file_delete#:#A felhasználó áthelyezhet vagy törölhet fájlt -rbac#:#file_edit_file#:#Allow to edit the file in an external editor, if available###26 08 2024 new variable +rbac#:#file_edit_file#:#Fájl módosításának engedélyezése külső szerkesztővel (ha van) rbac#:#file_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait rbac#:#file_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#file_read#:#A felhasználó tölthet fel fájlt rbac#:#file_read_learning_progress#:#A felhasználó megnézheti mások tanulási haladását -rbac#:#file_view_content#:#File content presented in browser (if WOPI is active)###29 10 2025 new variable +rbac#:#file_view_content#:#A fájl tartalma a böngészőben jelenik meg (ha a WOPI aktív) rbac#:#file_visible#:#A fájl látható. rbac#:#file_write#:#A felhasználó módosíthatja a fájlbeállításokat, és tölthet fel új fájlverziót -rbac#:#files_visible#:#Fájlok láthatóak -rbac#:#fils_edit_permissions#:#User can change permission settings of File Services administration.###29 07 2022 new variable -rbac#:#fils_read#:#User has read access to File Services administration.###29 07 2022 new variable -rbac#:#fils_visible#:#Administration of File Services is visible.###29 07 2022 new variable -rbac#:#fils_write#:#User can edit and configure File Services.###29 07 2022 new variable -rbac#:#filter_all_roles#:#Az itt érvényben lévő összes szerep megjelenítése -rbac#:#filter_global_roles#:#A globális szerepek megjelenítése -rbac#:#filter_local_roles#:#Az itt érvényben lévő helyi szerepek megjelenítése -rbac#:#filter_local_roles_object#:#Az itt létrehozott helyi szerepek megjelenítése -rbac#:#filter_roles_local_policy#:#Az itt helyi hozzáférés-szabályozást használó szerepek megjelenítése +rbac#:#files_visible#:#Fájlok láthatók +rbac#:#fils_edit_permissions#:#A felhasználó módosíthatja a Rendszerbeállítások » Fájlszolgáltatás jogosultsági beállításait +rbac#:#fils_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Fájlszolgáltatás beállításaihoz +rbac#:#fils_visible#:#A felhasználó láthatja a Rendszerbeállítások » Fájlszolgáltatás menüpontot +rbac#:#fils_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Fájlszolgáltatás beállításait +rbac#:#filter_all_roles#:#Az itt érvényben lévő összes szerepkör megjelenítése +rbac#:#filter_global_roles#:#A globális szerepkörök megjelenítése +rbac#:#filter_local_roles#:#Az itt érvényben lévő helyi szerepkörök megjelenítése +rbac#:#filter_local_roles_object#:#Az itt létrehozott helyi szerepkörök megjelenítése +rbac#:#filter_roles_local_policy#:#Az itt helyi jogosultságokat használó szerepkörök megjelenítése rbac#:#fld_create_poll#:#Szavazás létrehozása rbac#:#fold_copy#:#A felhasználó másolhat mappát rbac#:#fold_delete#:#A felhasználó áthelyezhet vagy törölhet mappát @@ -14270,16 +14362,16 @@ rbac#:#fold_read_learning_progress#:#A felhasználó megnézheti mások tanulás rbac#:#fold_visible#:#A mappa látható rbac#:#fold_write#:#A felhasználó módosíthatja a mappák beállításait és kezelheti a tartalmukat rbac#:#folders_create#:#Mappák létrehozása -rbac#:#folders_visible#:#Mappák láthatóak +rbac#:#folders_visible#:#Mappák láthatók rbac#:#frm_add_reply#:#A felhasználó válaszolhat a hozzászólásra rbac#:#frm_add_thread#:#A felhasználó vehet fel új témát rbac#:#frm_copy#:#A felhasználó másolhat fórumot rbac#:#frm_delete#:#A felhasználó áthelyezhet vagy törölhet fórumot -rbac#:#frm_edit_learning_progress#:#User can edit learning progress settings###29 10 2025 new variable +rbac#:#frm_edit_learning_progress#:#A felhasználó módosíthatja a tanulás haladás beállításait rbac#:#frm_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#frm_moderate_frm#:#A felhasználó módosíthatja, cenzúrázhatja és törölheti a hozzászólásokat rbac#:#frm_read#:#A felhasználónak olvasási hozzáférése van a fórumhoz -rbac#:#frm_read_learning_progress#:#User can view learning progress of other users###29 10 2025 new variable +rbac#:#frm_read_learning_progress#:#A felhasználó megnézheti a többi felhasználó tanulási haladását rbac#:#frm_visible#:#A fórum látható rbac#:#frm_write#:#A felhasználó módosíthatja a fórum beállításait és moderátorait rbac#:#frma_edit_permission#:#Jogosultsági beállítások változtatása @@ -14338,14 +14430,14 @@ rbac#:#iass_read#:#Személyes értékelés tartalmának olvasása rbac#:#iass_read_learning_progress#:#Személyes értékelés tanulási haladási információjának megjelenítése rbac#:#iass_visible#:#Személyes értékelés látható rbac#:#iass_write#:#Személyes értékelés módosítása -rbac#:#il_lti_global_role#:#LTI User###29 07 2022 new variable +rbac#:#il_lti_global_role#:#LTI-Felhasználó rbac#:#il_sess_participant#:#Munkamenet résztvevők rbac#:#il_sess_status_closed#:#Résztvevő nélküli zárt esemény rbac#:#ilias_id#:#ILIAS-ID -rbac#:#impr_edit_permission#:#User can change permission settings of Legal Notice administration###29 10 2025 new variable -rbac#:#impr_read#:#User can read in Legal Notice administration###29 10 2025 new variable -rbac#:#impr_visible#:#Administration of Legal Notice is visible###29 10 2025 new variable -rbac#:#impr_write#:#User can edit content and settings of Legal Notice###29 10 2025 new variable +rbac#:#impr_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Jogi nyilatkozat jogosultsági beállításait +rbac#:#impr_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Jogi nyilatkozat beállításaihoz +rbac#:#impr_visible#:#A felhasználó láthatja a Rendszerbeállítások » Jogi nyilatkozat menüpontot +rbac#:#impr_write#:#UA felhasználó módosíthatja a Rendszerbeállítások » Jogi nyilatkozat beállításait rbac#:#info_user_view_changed#:#A felhasználói nézet megváltozott rbac#:#internal_mail#:#Belső levelezés rbac#:#invite#:#Meghívás kérdőívhez @@ -14356,10 +14448,10 @@ rbac#:#itgr_read#:#A felhasználó olvashat objektumcsoportot rbac#:#itgr_visible#:#Elem csoport látható rbac#:#itgr_write#:#A felhasználó szerkesztheti objektumcsoport tartalmát és beállításait rbac#:#leave#:#Kilépés -rbac#:#lhts_edit_permissions#:#User can change permission settings of Learning History administration.###29 07 2022 new variable -rbac#:#lhts_read#:#User has read access to Learning History administration.###29 07 2022 new variable -rbac#:#lhts_visible#:#Administration of Learning History is visible.###29 07 2022 new variable -rbac#:#lhts_write#:#User can edit settings of Learning History administration.###29 07 2022 new variable +rbac#:#lhts_edit_permissions#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanulási történelem jogosultsági beállításait +rbac#:#lhts_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Tanulási történelem beállításaihoz +rbac#:#lhts_visible#:#A felhasználó láthatja a Rendszerbeállítások » Tanulási történelem menüpontot +rbac#:#lhts_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanulási történelem beállításait rbac#:#lm_copy#:#A felhasználó másolhat ILIAS-tananyagot rbac#:#lm_delete#:#A felhasználó áthelyezhet vagy törölhet ILIAS-tananyagot rbac#:#lm_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait @@ -14385,7 +14477,7 @@ rbac#:#lso_copy#:#A felhasználó másolhat a tanulási sort rbac#:#lso_delete#:#A felhasználó törölhet tanulási sort rbac#:#lso_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait rbac#:#lso_edit_permission#:#A felhasználó módosíthatja a tanulási sor jogosultsági beállításait -rbac#:#lso_lp_other_users#:#A felhasználó megtekintheti a többi felhasználó tanulási haladását. +rbac#:#lso_lp_other_users#:#A felhasználó megtekintheti a többi felhasználó tanulási haladását rbac#:#lso_manage_members#:#Tanulási sor tagjainak kezelése rbac#:#lso_participate#:#A felhasználó feliratkozhat a tanulási sorra rbac#:#lso_read#:#A felhasználónak olvasási hozzáférése van a tanulási sorhoz @@ -14393,38 +14485,38 @@ rbac#:#lso_read_learning_progress#:#A felhasználó megnézheti mások tanulási rbac#:#lso_unparticipate#:#A felhasználó leiratkozhat a tanulási sorról rbac#:#lso_visible#:#A tanulási sor látható rbac#:#lso_write#:#A felhasználó módosíthatja a tanulási sor beállításait -rbac#:#lsos_edit_permission#:#User can change permission settings of Learning Sequences administration.###29 10 2025 new variable -rbac#:#lsos_read#:#User has read access to Learning Sequences administration.###29 07 2022 new variable -rbac#:#lsos_visible#:#Administration of Learning Sequences is visible.###29 07 2022 new variable -rbac#:#lsos_write#:#User can edit settings of Learning Sequences administration.###29 07 2022 new variable +rbac#:#lsos_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanulási sor jogosultsági beállításait +rbac#:#lsos_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Tanulási sor beállításaihoz +rbac#:#lsos_visible#:#A felhasználó láthatja a Rendszerbeállítások » Tanulási sor menüpontot +rbac#:#lsos_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Tanulási sor beállításait rbac#:#lti_copy#:#A felhasználó másolhat LTI-Fogyasztót -rbac#:#lti_delete#:#User can move or delete LTI Fogyasztó -rbac#:#lti_edit_learning_progress#:#User can edit learning progress settings -rbac#:#lti_edit_permission#:#User can change permission settings +rbac#:#lti_delete#:#A felhasználó áthelyezhet vagy törölhet LTI-Fogyasztót +rbac#:#lti_edit_learning_progress#:#A felhasználó szerkesztheti tanulási folyamat beállításait +rbac#:#lti_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#lti_read#:#A felhasználó láthatja az LTI-Fogyasztót -rbac#:#lti_read_learning_progress#:#User can view learning progress of other users -rbac#:#lti_read_outcomes#:#A felhasználó láthatja experiences and ranking of other users###XXX +rbac#:#lti_read_learning_progress#:#A felhasználó láthatja más felhasználók tanulási folyamatát +rbac#:#lti_read_outcomes#:#A felhasználó láthatja más felhasználók tanulási tapasztalatait és rangsorolásait rbac#:#lti_visible#:#Az LTI-Fogyasztó látható -rbac#:#lti_write#:#User can edit settings of LTI Fogyasztó -rbac#:#ltis_add_consume_provider#:#User can add own provider settings for LTI Fogyasztók +rbac#:#lti_write#:#A felhasználó módosíthaja az LTI-Fogyasztó beállításait +rbac#:#ltis_add_consume_provider#:#A felhasználó hozzáadhat saját kiszolgálóbeállításokat az LTI-Fogyasztóknak rbac#:#ltis_edit_permission#:#A felhasználó módosíthatja az LTI-kezelés jogosultsági beállításait rbac#:#ltis_read#:#A felhasználónak olvasási hozzáférése van az LTI-kezelés beállításaihoz rbac#:#ltis_release_objects#:#A felhasználó kiadhat objektumokat az LTI-fogyasztóknak rbac#:#ltis_visible#:#LTI-kezelés látható rbac#:#ltis_write#:#A felhasználónak módosíthatja az LTI-kezelés beállításaihoz rbac#:#mail_internal_mail#:#A felhasználó használhatja a belső levelezőrendszert (ILIAS) -rbac#:#mail_mail_to_global_roles#:#A felhasználó küldhet levelet a globális szerepeknek +rbac#:#mail_mail_to_global_roles#:#A felhasználó küldhet levelet a globális szerepköröknek rbac#:#mail_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Levelezés beállításaihoz rbac#:#mail_smtp_mail#:#A felhasználó SMTP-n keresztül küldhet e-mailt külső címekre -rbac#:#mail_to_global_roles#:#Globális szerepeknek levél +rbac#:#mail_to_global_roles#:#Globális szerepköröknek levél rbac#:#mail_visible#:#A felhasználó láthatja a Rendszerbeállítások » Levelezés menüpontot rbac#:#mail_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Levelezés beállításait -rbac#:#manage_all_reservations#:#Manage All Reservations###28 10 2024 new variable -rbac#:#manage_comp#:#User can edit Competences###29 07 2022 new variable -rbac#:#manage_comp_temp#:#User can edit Competence Templates###29 07 2022 new variable +rbac#:#manage_all_reservations#:#Az összes foglalás kezelése +rbac#:#manage_comp#:#A felhasználó módosíthatja a kompetenciákat +rbac#:#manage_comp_temp#:#A felhasználó módosíthatja a kompetenciasablonokat rbac#:#manage_materials#:#Segédanyagok kezelése -rbac#:#manage_own_reservations#:#Manage Own Reservations###28 10 2024 new variable -rbac#:#manage_profiles#:#User can edit Competence Profiles###29 07 2022 new variable +rbac#:#manage_own_reservations#:#Saját foglalások kezelése +rbac#:#manage_profiles#:#A felhasználó módosíthatja a kompetenciaprofilokat rbac#:#mcst_copy#:#A felhasználó másolhat médiasugárzást rbac#:#mcst_delete#:#A felhasználó áthelyezhet vagy törölhet médiasugárzást rbac#:#mcst_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait @@ -14457,19 +14549,19 @@ rbac#:#mobs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Méd rbac#:#mobs_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Médiaobjektumok és -gyűjtemények beállításait rbac#:#moderate#:#Moderálás rbac#:#moderate_frm#:#Moderálás -rbac#:#msg_anonymous_cannot_be_assigned#:#Anonymous cannot be assigned to a role.###26 08 2024 new variable -rbac#:#msg_no_roles_of_type#:#Nincsenek elérhetők szerepek a kiválasztott szűrőbeállítással. +rbac#:#msg_anonymous_cannot_be_assigned#:#Az Névtelen felhasználót nem lehet szerepkörhöz rendelni. +rbac#:#msg_no_roles_of_type#:#Nincsenek elérhetők szerepkörök a kiválasztott szűrőbeállítással. rbac#:#news_add_news#:#Hír létrehozása -rbac#:#no_corresponding_roles#:#No corresponding roles could be found.###29 10 2025 new variable -rbac#:#nots_edit_permission#:#User can change permission settings of Notes administration.###29 10 2025 new variable -rbac#:#nots_read#:#User has read access to Notes administration.###29 07 2022 new variable -rbac#:#nots_visible#:#Administration of Notes is visible.###29 07 2022 new variable -rbac#:#nots_write#:#User can edit settings of Notes administration.###29 07 2022 new variable +rbac#:#no_corresponding_roles#:#Nem található megfelelő szerepkör. +rbac#:#nots_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Jegyzetek jogosultsági beállításait +rbac#:#nots_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Jegyzetek beállításaihoz +rbac#:#nots_visible#:#A felhasználó láthatja a Rendszerbeállítások » Jegyzetek menüpontot +rbac#:#nots_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Jegyzetek beállításait rbac#:#nwss_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Hírek és webhírforrások jogosultsági beállításait rbac#:#nwss_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Hírek és webhírforrások beállításaihoz rbac#:#nwss_visible#:#A felhasználó láthatja a Rendszerbeállítások » Hírek és webhírforrások menüpontot rbac#:#nwss_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Hírek és webhírforrások beállításait -rbac#:#obj_skee#:#Competence Tree###29 07 2022 new variable +rbac#:#obj_skee#:#Kompetencia-fa rbac#:#org_op_access_results#:#Hozzáférés az alárendelt felhasználók eredményeihez rbac#:#org_op_edit_submissions_grades#:#Más felhasználók beküldésének módosítása rbac#:#org_op_manage_participants#:#Az alárendelt résztvevők kezelése @@ -14495,15 +14587,15 @@ rbac#:#perm_class_create#:#Új objektumok létrehozása rbac#:#perm_class_create_desc#:#Itt állíthatja be, hogy milyen objektumtípusokat lehessen létrehozni közvetlenül az objektum alá. rbac#:#perm_class_object#:#Speciális műveletek rbac#:#perm_class_object_desc#:#Objektumspecifikus műveletek. -rbac#:#perm_global_role#:#Globális szerep -rbac#:#perm_local_role#:#Helyi szerep -rbac#:#perm_local_role_desc#:#Ez a szerep helyi ebben az objektumban, ami egyenértékű egy helyi hozzáférés-szabályozással. -rbac#:#perm_protected_global_role#:#Védett globális szerep -rbac#:#perm_protected_local_role#:#Védett helyi szerep -rbac#:#perm_role_path_info_created#:#Létrehozva ebben: %1$s '%2$s' -rbac#:#perm_role_path_info_inheritance#:#helyi szabályok használata innen: %1$s '%2$s' -rbac#:#perm_use_local_policy#:#Helyi hozzáférés-szabályozás használata -rbac#:#perm_use_local_policy_desc#:#Ha a helyi hozzáférés-szabályozás be van kapcsolva, eltérő alapértelmezett jogosultsági beállításokat definiálhat ehhez az objektumhoz. +rbac#:#perm_global_role#:#Globális szerepkör +rbac#:#perm_local_role#:#Helyi szerepkör +rbac#:#perm_local_role_desc#:#Ez a szerepkör helyi ebben az objektumban, ami egyenértékű egy helyi jogosultságkezeléssel. +rbac#:#perm_protected_global_role#:#Védett globális szerepkör +rbac#:#perm_protected_local_role#:#Védett helyi szerepkör +rbac#:#perm_role_path_info_created#:#Létrehozva ebben: %1$s ‘%2$s’ +rbac#:#perm_role_path_info_inheritance#:#helyi szabályok használata innen: %1$s ‘%2$s’ +rbac#:#perm_use_local_policy#:#Helyi jogosultságkezelés használata +rbac#:#perm_use_local_policy_desc#:#Ha a helyi jogosultságkezelés be van kapcsolva, az alapértelmezettől eltérő jogosultsági beállításokat adhat meg ehhez az objektumhoz. rbac#:#poll_copy#:#A felhasználó másolhat szavazást rbac#:#poll_delete#:#A felhasználó áthelyezhet és törölhet szavazást rbac#:#poll_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat @@ -14514,13 +14606,16 @@ rbac#:#positions_override_operations#:#Globális beállítások felülírása rbac#:#precondition_not_obligatory_alt#:#Az előfeltétel opcionális rbac#:#precondition_num_obligatory#:#Kötelező anyagok száma rbac#:#precondition_num_optional_info#:#Adja meg az anyagok minimumszámát az előfeltételek teljesítettségéhez! +rbac#:#precondition_number_of_required_materials_bigger_preconditions_number#:#A szükséges segédanyagok számának kevesebbnek kell lennie, mint az összes előfeltétel számának. +rbac#:#precondition_number_of_required_materials_lower_compulsory_items#:#A szükséges segédanyagok számának nagyobbnak kell lennie, mint a kötelező előfeltételek számának. +rbac#:#precondition_number_of_required_materials_lower_than_one#:#A szükséges segédanyagok számának legalább 1-nek kell lennie. rbac#:#precondition_obligatory#:#Kötelező rbac#:#precondition_obligatory_alt#:#Az előfeltételeket teljesíteni kell rbac#:#precondition_obligatory_info#:#A kötelező előfeltételeket teljesíteni kell a hozzáféréshez. rbac#:#precondition_obligatory_settings#:#Előfeltételek beállításai -rbac#:#precondition_operator_range_err_min_max#:#The minimum value must be less than the maximum value.###28 10 2024 new variable -rbac#:#precondition_operator_range_max#:#Maximum Percentage###28 10 2024 new variable -rbac#:#precondition_operator_range_min#:#Minimum Percentage###28 10 2024 new variable +rbac#:#precondition_operator_range_err_min_max#:#A minimális értéknek kisebbnek kell lennie, mint a maximális értéknek. +rbac#:#precondition_operator_range_max#:#Maximumális % +rbac#:#precondition_operator_range_min#:#Minimális % rbac#:#prfa_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Portfólió jogosultsági beállításait rbac#:#prfa_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Portfólió beállításaihoz rbac#:#prfa_visible#:#A felhasználó láthatja a Rendszerbeállítások » Portfólió menüpontot @@ -14532,19 +14627,19 @@ rbac#:#prg_manage_members#:#Képzési programok tagjainak kezelése rbac#:#prg_read#:#A felhasználónak olvasási hozzáférése van a Képzési programhoz rbac#:#prg_visible#:#A Képzési program látható rbac#:#prg_write#:#A felhasználó módosíthatja Képzési programok beállításait -rbac#:#prgr_copy#:#User can copy links to study programmes.###29 07 2022 new variable -rbac#:#prgr_delete#:#User can move or delete links to study programmes.###29 07 2022 new variable -rbac#:#prgr_edit_permission#:#User can change permission settings.###29 07 2022 new variable -rbac#:#prgr_visible#:#Links to study programmes are visible and can be used###29 07 2022 new variable -rbac#:#prgr_write#:#User can edit settings of links to study programmes.###29 07 2022 new variable +rbac#:#prgr_copy#:#A felhasználó másolhat képzésiprogram-linket +rbac#:#prgr_delete#:#A felhasználó áthelyezhet vagy törölhet képzésiprogram-linket +rbac#:#prgr_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat +rbac#:#prgr_visible#:#A képzésiprogram-linkek láthatók és használhatók +rbac#:#prgr_write#:#A felhasználó módosíthatja a képzésiprogram-link beállításait rbac#:#prgs_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Képzési programok jogosultsági beállításait rbac#:#prgs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Képzési programok beállításaihoz rbac#:#prgs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Képzési programok menüpontot rbac#:#prgs_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Képzési programok beállításait -rbac#:#prss_edit_permission#:#User can change permission settings of Personal Resources administration.###29 10 2025 new variable -rbac#:#prss_read#:#User has read access to Personal Resources administration.###29 07 2022 new variable -rbac#:#prss_visible#:#Administration of Personal Resources is visible.###29 07 2022 new variable -rbac#:#prss_write#:#User can edit settings of Personal Resources administration.###29 07 2022 new variable +rbac#:#prss_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » ‘Személyes erőforrások kezelése’ jogosultsági beállításait +rbac#:#prss_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » ‘Személyes erőforrások kezelése’ beállításaihoz +rbac#:#prss_visible#:#A felhasználó láthatja a Rendszerbeállítások » ‘Személyes erőforrások kezelése’ menüpontot +rbac#:#prss_write#:#A felhasználó módosíthatja a Rendszerbeállítások » ‘Személyes erőforrások kezelése’ beállításait rbac#:#prtt_copy#:#Felhasználó másolhat portfóliósablont rbac#:#prtt_delete#:#Felhasználó áthelyezhet és törölhet portfóliósablont rbac#:#prtt_edit_permission#:#A felhasználó megváltoztathatja a portfóliósablon jogosultsági beállításait @@ -14556,36 +14651,36 @@ rbac#:#ps_export_member_data#:#A felhasználó tagadatokat exportálhat kurzusok rbac#:#ps_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Adatvédelem és biztonság beállításaihoz rbac#:#ps_visible#:#A felhasználó láthatja a Rendszerbeállítások » Adatvédelem és biztonságot rbac#:#ps_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Adatvédelem és biztonság beállításait -rbac#:#push_desktop_items#:#Recommend Content###29 07 2022 new variable +rbac#:#push_desktop_items#:#Ajánlott tartalom rbac#:#qpl_copy#:#A felhasználó másolhat tesztkérdésgyűjteményt tesztekhez rbac#:#qpl_delete#:#A felhasználó áthelyezhet vagy törölhet tesztkérdésgyűjteményt rbac#:#qpl_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#qpl_read#:#A felhasználó olvashat gyűjteményben lévő tesztkérdéseket, és beszúrhatja azokat tesztekbe rbac#:#qpl_visible#:#Kérdésgyűjtemény látható rbac#:#qpl_write#:#A felhasználó szerkesztheti a kérdésgyűjtemény tesztkérdéseit és beállításait -rbac#:#rbac_add_new_local_role#:#Új helyi szerep létrehozása +rbac#:#rbac_add_new_local_role#:#Új helyi szerepkör létrehozása rbac#:#rbac_add_recommended_content#:#Ajánlott tartalom -rbac#:#rbac_add_recommended_content_info#:#'%1' objektumot hozzáadja ajánlott tartalomként a szerep összes tagjának. +rbac#:#rbac_add_recommended_content_info#:#‘%1’ objektumot hozzáadja ajánlott tartalomként a szerepkör összes tagjának. rbac#:#rbac_admin_permissions#:#Rendszerbeállítási jogosultságok -rbac#:#rbac_auto_global#:#Automatikusan létrejött globális szerep -rbac#:#rbac_auto_local#:#Automatikusan létrejött helyi szerep +rbac#:#rbac_auto_global#:#Automatikusan létrejött globális szerepkör +rbac#:#rbac_auto_local#:#Automatikusan létrejött helyi szerepkör rbac#:#rbac_auto_rolt#:#Automatikusan létrejött szerepsablon rbac#:#rbac_back_to_overview#:#Vissza a szereplistához -rbac#:#rbac_cant_import_role_wrong_type#:#'%s' elemből '%s' elembe szabály nem importálható. -rbac#:#rbac_change_existing_confirm_tbl#:#Beállítások a 'Már létező objektumokra is' opcióhoz +rbac#:#rbac_cant_import_role_wrong_type#:#‘%s’ elemből ‘%s’ elembe szabály nem importálható. +rbac#:#rbac_change_existing_confirm_tbl#:#Beállítások a ‘Már létező objektumokra is’ opcióhoz rbac#:#rbac_change_existing_objects_desc_new_role#:#Ennek a szerepnek a jogosultsági beállításait a már összes létező objektumra alkalmazzunk. rbac#:#rbac_changes#:#Változtatások -rbac#:#rbac_choose_copy_targets#:#Adjon meg egy lekérdezést a célszerep kiválasztásához. +rbac#:#rbac_choose_copy_targets#:#Adjon meg egy kifejezést, mellyel megtalálható az a célszerepkör, amelyekre másolni kívánja %s jogosultságait. rbac#:#rbac_condition_delete_sure#:#Biztos, hogy törli az alábbi előfeltételeket? rbac#:#rbac_context_global#:#Globális rbac#:#rbac_copy_behaviour#:#Szerepmásolási beállítások -rbac#:#rbac_copy_behaviour_info#:#Transfer Permissions from: %s to: %s###29 10 2025 new variable +rbac#:#rbac_copy_behaviour_info#:#Jogosultságok másolása innen: %s ide: %s rbac#:#rbac_copy_finished#:#A másolás befejeződött. -rbac#:#rbac_copy_multi_targets#:#%s, %s and %s further Roles selected%s###29 10 2025 new variable -rbac#:#rbac_copy_no_targets#:#At least one Role must be selected as Target###29 10 2025 new variable -rbac#:#rbac_copy_role#:#Szerep másolása +rbac#:#rbac_copy_multi_targets#:#%s, %s és %s további szerepkört választott ki %s +rbac#:#rbac_copy_no_targets#:#Legalább egy szerepkört ki kell válsztania célnak +rbac#:#rbac_copy_role#:#Szerepkör másolása rbac#:#rbac_copy_role_add_perm#:#Hozzáadási engedélyek -rbac#:#rbac_copy_role_copy#:#Másolási engedélyek +rbac#:#rbac_copy_role_copy#:#Másik szerepkörből másolási engedélyek rbac#:#rbac_copy_role_remove_perm#:#Törlései engedélyek rbac#:#rbac_create_bibl#:#Bibliográfia létrehozása rbac#:#rbac_create_blog#:#Blog létrehozása @@ -14593,7 +14688,7 @@ rbac#:#rbac_create_book#:#Foglalásgyűjtemény létrehozása rbac#:#rbac_create_cat#:#Kategóriák létrehozása rbac#:#rbac_create_catr#:#Kategórialink létrehozása rbac#:#rbac_create_chtr#:#Csevegőszoba létrehozása -rbac#:#rbac_create_cmix#:#Create xAPI/cmi5 Object +rbac#:#rbac_create_cmix#:#xAPI/cmi5-objektum létrehozása rbac#:#rbac_create_copa#:#Tartalomlap létrehozása rbac#:#rbac_create_crs#:#Kurzus létrehozása rbac#:#rbac_create_crsr#:#Kurzuslink létrehozása @@ -14616,7 +14711,7 @@ rbac#:#rbac_create_mep#:#Médiagyűjtemény létrehozása rbac#:#rbac_create_orgu#:#Szervezeti egységek létrehozása rbac#:#rbac_create_poll#:#Szavazás létrehozása rbac#:#rbac_create_prg#:#Képzési program létrehozása -rbac#:#rbac_create_prgr#:#Create link to study programme###29 07 2022 new variable +rbac#:#rbac_create_prgr#:#Képzésiprogram-link létrehozása rbac#:#rbac_create_prtt#:#Portfólió sablon létrehozása rbac#:#rbac_create_qpl#:#Tesztkérdésgyűjtemény létrehozása rbac#:#rbac_create_rcrs#:#ECS-kurzus létrehozása @@ -14624,7 +14719,7 @@ rbac#:#rbac_create_role#:#Új szabály létrehozása rbac#:#rbac_create_rolt#:#Új szabály sablon létrehozása rbac#:#rbac_create_sahs#:#SCORM-tananyag létrehozása rbac#:#rbac_create_sess#:#Esemény létrehozása -rbac#:#rbac_create_skee#:#Create Competence Tree###26 08 2024 new variable +rbac#:#rbac_create_skee#:#Kompetencia-fa létrehozása rbac#:#rbac_create_spl#:#Kérdőívkérdés-gyűjtemény létrehozása rbac#:#rbac_create_svy#:#Kérdőív létrehozása rbac#:#rbac_create_tst#:#Teszt létrehozása @@ -14632,17 +14727,17 @@ rbac#:#rbac_create_usr#:#A felhasználó létrehozhat ILIAS-fiókokat rbac#:#rbac_create_webr#:#Weblink létrehozása rbac#:#rbac_create_wiki#:#Wiki létrehozása rbac#:#rbac_delete_local_policies#:#Helyi szabályok törlése -rbac#:#rbac_delete_local_policies_info#:#Ha be van kapcsolva, a helyi szabályok törlődnek. Az objektumjogosultságok újraíródnak és védettek lesznek. -rbac#:#rbac_delete_role#:#Szerep törlése +rbac#:#rbac_delete_local_policies_info#:#A helyi szabályok törlődnek. Az objektumjogosultságok újraíródnak és védettek lesznek. +rbac#:#rbac_delete_role#:#Szerepkör törlése rbac#:#rbac_edit_condition#:#Előfeltételek módosítása rbac#:#rbac_form_copy_roles_adjust_button#:#Jogosultság beállítása -rbac#:#rbac_form_copy_roles_adjust_type#:#A jogosultságok típusának beállítása###XXX +rbac#:#rbac_form_copy_roles_adjust_type#:#A jogosultságok típusának beállítása rbac#:#rbac_form_copy_roles_adjust_type_add#:#Jogosultságok hozzáadása -rbac#:#rbac_form_copy_roles_adjust_type_add_info#:#Hozzáadja a kiválasztott globális szerepminta KIVÁLASZTOTT jogait a helyi jogosultságokhoz. A ki nem választott jogosultságokat figyelmen kívül hagyjuk. +rbac#:#rbac_form_copy_roles_adjust_type_add_info#:#Hozzáadja a kiválasztott globális szerepkörminta KIVÁLASZTOTT jogait a helyi jogosultságokhoz. A ki nem választott jogosultságokat figyelmen kívül hagyjuk. rbac#:#rbac_form_copy_roles_adjust_type_clone#:#Másolási jogosultságok -rbac#:#rbac_form_copy_roles_adjust_type_clone_info#:#A kiválasztott globális szerepminta minden jogosultsága felülírja a helyi jogosultságokat. +rbac#:#rbac_form_copy_roles_adjust_type_clone_info#:#A kiválasztott globális szerepkörminta minden jogosultsága felülírja a helyi jogosultságokat. rbac#:#rbac_form_copy_roles_adjust_type_remove#:#Jogosultságok eltávolítása -rbac#:#rbac_form_copy_roles_adjust_type_remove_info#:#Eltávolítja a kiválasztott globális szerepminta KIVÁLASZTOTT jogosultságát a helyi jogosultságokból. +rbac#:#rbac_form_copy_roles_adjust_type_remove_info#:#Eltávolítja a kiválasztott globális szerepkörminta KIVÁLASZTOTT jogosultságát a helyi jogosultságokból. rbac#:#rbac_form_copy_roles_ce_add_no#:#NE módosítsa a meglévő objektumokat rbac#:#rbac_form_copy_roles_ce_add_no_info#:#A meglévő helyi engedélyek ennek megfelelően hozzáadódnak, a meglévő objektumok jogosultságai nem módosulnak. rbac#:#rbac_form_copy_roles_ce_add_yes#:#Csak a kiválasztott jogosultságokat adja hozzá a meglévő objektumokhoz @@ -14656,31 +14751,31 @@ rbac#:#rbac_form_copy_roles_ce_remove_no_info#:#A kiválasztott jogosultságokat rbac#:#rbac_form_copy_roles_ce_remove_yes#:#Csak a kiválasztott jogosultságokkal csökkentse a meglévő objektumokat rbac#:#rbac_form_copy_roles_ce_remove_yes_info#:#A meglévő helyi jogosultságok és a meglévő objektumok jogosultságainak beállításai ennek megfelelően csökkennek. rbac#:#rbac_global_rolt#:#Globális szerepsablon -rbac#:#rbac_import_role#:#Szerep importálása +rbac#:#rbac_import_role#:#Szerepkör importálása rbac#:#rbac_info_only_position_access#:#Csak az Ön szervezeti egységében egy pozícióban lévő alábbi kurzustagokat látja. Kurzustagok lehetnek még más szervezeti pozícióban lévők is, de őket nem látja. rbac#:#rbac_keep_local_policies#:#Helyi szabályok megtartása rbac#:#rbac_keep_local_policies_info#:#Válassza ezt a módot a helyi szabályok megtartásához. Ezekhez a szabályokhoz lesznek adaptálva az objektumjogosultságok, valamint a továbbiakban védettek lesznek. rbac#:#rbac_local_policies#:#Helyi szabályok -rbac#:#rbac_local_policy#:#Helyi hozzáférés-szabályozás +rbac#:#rbac_local_policy#:#Helyi jogosultságkezelés rbac#:#rbac_log#:#Naplózás rbac#:#rbac_log_change_owner#:#Objektum tulajdonosának cseréje rbac#:#rbac_log_changed_owner#:#Objektum tulajdonosának cseréje erre: rbac#:#rbac_log_copy_object#:#Objektum másolása rbac#:#rbac_log_create_object#:#Objektum létrehozása rbac#:#rbac_log_edit_permissions#:#Jogosultságok módosítása -rbac#:#rbac_log_edit_template#:#Szerepminta módosítása -rbac#:#rbac_log_edit_template_existing#:#Szerepminta használata meglévő objektumokhoz -rbac#:#rbac_log_inheritance_add#:#Megállított öröklődés ennél: '%s' -rbac#:#rbac_log_inheritance_rmv#:#Engedélyezett öröklődés ennél: '%s' +rbac#:#rbac_log_edit_template#:#Szerepkörminta módosítása +rbac#:#rbac_log_edit_template_existing#:#Szerepkörminta használata meglévő objektumokhoz +rbac#:#rbac_log_inheritance_add#:#Megállított öröklődés ennél: ‘%s’ +rbac#:#rbac_log_inheritance_rmv#:#Engedélyezett öröklődés ennél: ‘%s’ rbac#:#rbac_log_link_object#:#Objektum linkelése rbac#:#rbac_log_move_object#:#Objektum eltávolítása -rbac#:#rbac_log_operation_add#:#Felvett műveletek ehhez: '%s' -rbac#:#rbac_log_operation_rmv#:#Eltávolított műveletek innen: '%s' +rbac#:#rbac_log_operation_add#:#Felvett műveletek ehhez: ‘%s’ +rbac#:#rbac_log_operation_rmv#:#Eltávolított műveletek innen: ‘%s’ rbac#:#rbac_log_source_object#:#Forrásobjektum -rbac#:#rbac_msg_user_already_assigned#:#A kiválasztott felhasználók már hozzá vannak rendelve ehhez a szerephez. +rbac#:#rbac_msg_user_already_assigned#:#A kiválasztott felhasználók már hozzá vannak rendelve ehhez a szerepkörhöz. rbac#:#rbac_not_change_existing_objects#:#Ne változtasson létező objektumokat rbac#:#rbac_permissions#:#Jogosultságok -rbac#:#rbac_precondition_condition#:#Access requires having this status###29 10 2025 new variable +rbac#:#rbac_precondition_condition#:#Az állapot eléréséhez hozzáférés szükséges rbac#:#rbac_precondition_hide#:#Objektum elrejtése rbac#:#rbac_precondition_hide_info#:#Ez az opció lehetővé teszi, hogy az objektum rejtve maradjon az előfeltételeit nem teljesített felhasználók elől, vagyis az összes el nem elérhető tartalom nem látható a felhasználó számára. rbac#:#rbac_precondition_minimum_optional#:#Legalább két előfeltétel választhatóként kell maradjon. @@ -14688,28 +14783,28 @@ rbac#:#rbac_precondition_mode#:#Mód rbac#:#rbac_precondition_mode_all#:#Összes előfeltétel rbac#:#rbac_precondition_mode_all_info#:#Az összes előfeltételt teljesíteni kell a hozzáférés megszerzéséhez. rbac#:#rbac_precondition_mode_subset#:#Előfeltételek alhalmaza -rbac#:#rbac_precondition_mode_subset_info#:#Az előfeltételek egy részét elég teljesíteni a hozzáférés megszerzéséhez. Egyes előfeltételek kötelezőnek állíthatóak be. +rbac#:#rbac_precondition_mode_subset_info#:#Az előfeltételek egy részét elég teljesíteni a hozzáférés megszerzéséhez. Egyes előfeltételek kötelezőnek állíthatók be. rbac#:#rbac_precondition_save_obligatory#:#Kötelezőként mentés rbac#:#rbac_precondition_source#:#Előfeltétel rbac#:#rbac_precondition_target#:#Előfeltétel ennek az eléréséhez rbac#:#rbac_repository_permissions#:#Tartalomtárbeli jogosultságok -rbac#:#rbac_role_delete_qst#:#Biztos, hogy törli az alábbi szerepeket?
    Ezzel véglegesen törli az összes szereptagságon keresztül kiosztott jogosultságot is! +rbac#:#rbac_role_delete_qst#:#Biztos, hogy törli az alábbi szerepköröket?
    Ezzel véglegesen törli az összes szerepkörtagságon keresztül kiosztott jogosultságot is! rbac#:#rbac_role_delete_self#:#Figyelmeztetés: Ön is tagja ennek a szerepnek! Ha folytatja a törlést, elveszítheti a hozzáférést néhány ILIAS-anyaghoz! -rbac#:#rbac_role_exists_alert#:#Már van ilyen nevű szerep ebben a tartalomban. Válasszon másik nevet. -rbac#:#rbac_role_imported#:#A szerepet importáltuk. +rbac#:#rbac_role_exists_alert#:#Már van ilyen nevű szerepkör ebben a tartalomban. Válasszon másik nevet. +rbac#:#rbac_role_imported#:#A szerepkört sikeresen importálta és az alapértelmezett jogosultságait is sikeren beállította. Most adja meg, hogy az importált szerepkör milyen jogosultságokkal rendelkezzen ehhez az objektumhoz. rbac#:#rbac_role_rights_copy#:#Jogosultságok másolása rbac#:#rbac_role_rights_copy_change_existing#:#Már létező objektumokra is rbac#:#rbac_role_rights_copy_empty#:#Semmi rbac#:#rbac_role_selection#:#Szereptípus rbac#:#rbac_role_title#:#Szerepcím -rbac#:#rbac_select_copy_targets#:#Válassza ki a célszerepeket. -rbac#:#rbac_select_roles#:#Szerep kiválasztása -rbac#:#rbac_ud_global#:#Felhasználó által létrehozott globális szerep -rbac#:#rbac_ud_local#:#Felhasználó által létrehozott helyi szerep +rbac#:#rbac_select_copy_targets#:#Válassza ki a célszerepköröket, amelybe innen másol: %s. +rbac#:#rbac_select_roles#:#Szerepkör kiválasztása +rbac#:#rbac_ud_global#:#Felhasználó által létrehozott globális szerepkör +rbac#:#rbac_ud_local#:#Felhasználó által létrehozott helyi szerepkör rbac#:#rbac_ud_rolt#:#Felhasználó által létrehozott szerepsablon -rbac#:#rbac_unprotected_delete_local_policies_info#:#Ha be van kapcsolva, a helyi szabályokat is törli. A jogosultságok újrainicializálódnak a kurzusokban és a csoportokban. +rbac#:#rbac_unprotected_delete_local_policies_info#:#A helyi szabályokat is törli. A jogosultságok újrainicializálódnak a kurzusokban és a csoportokban. rbac#:#rbac_unprotected_keep_local_policies_info#:#A helyi szabályok megtartásához ezt a módot válassza. -rbac#:#rbac_view_content#:#View Content###29 10 2025 new variable +rbac#:#rbac_view_content#:#Tartalom megtekintése rbac#:#rcat_delete#:#A felhasználó áthelyezhet vagy törölhet ECS kategóriát rbac#:#rcat_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#rcat_read#:#A felhasználó használhat ECS kategóriát @@ -14720,11 +14815,11 @@ rbac#:#rcrs_edit_permission#:#A felhasználó módosíthatja a jogosultsági be rbac#:#rcrs_read#:#A felhasználó használhat ECS-kurzust rbac#:#rcrs_visible#:#ECS-kurzus látható rbac#:#rcrs_write#:#A felhasználó szerkesztheti ECS-kurzus beállításait -rbac#:#read_all_accounts#:#Read All Accounts###29 10 2025 new variable -rbac#:#read_comp#:#User has read access to Competences and Competence Templates###29 07 2022 new variable +rbac#:#read_all_accounts#:#Az összes ILIAS-fiók olvasása +rbac#:#read_comp#:#A felhasználónak olvasási hozzáférése van a Kompetenciákhoz és a Kompetencia sablonokhoz rbac#:#read_learning_progress#:#Mások tanulási haladásának megtekintése rbac#:#read_outcomes#:#A többi felhasználó tanulási tapasztalatának megtekintése -rbac#:#read_profiles#:#User has read access to Competence Profiles###29 07 2022 new variable +rbac#:#read_profiles#:#A felhasználónak olvasási hozzáférése van a Kompetenciaprofilokhoz rbac#:#read_results#:#Kérdőívre adott válaszok rbac#:#read_users#:#Olvasási elérés a helyi ILIAS-fiókokhoz rbac#:#recf_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Helyreállított objektumok jogosultsági beállításait @@ -14757,14 +14852,14 @@ rbac#:#rlm_edit_permission#:#A felhasználó módosíthatja a jogosultsági beá rbac#:#rlm_read#:#A felhasználó használhat ECS tananyagot rbac#:#rlm_visible#:#Az ECS tananyag látható rbac#:#rlm_write#:#A felhasználó szerkeszthet ECS tananyag beállításokat -rbac#:#role_block_role#:#Szerep kizárása +rbac#:#role_block_role#:#Szerepkör kizárása rbac#:#role_block_role_desc#:#Ehhez az objektumhoz és az összes alárendeltjéhez a hozzáférést visszavonjuk. -rbac#:#role_blocked#:#: Szerepet ki fogja zárni -rbac#:#role_confirm_block_role#:#Szerep állapotának módosítása -rbac#:#role_confirm_block_role_header#:#Biztos, hogy megváltoztatja a kiválasztott szerep zárolási állapotát? -rbac#:#role_confirm_block_role_info#:#A 'Szerep kizárása' művelettel a következő lépéseket hajtja végre:

    - a szerep jogosultságait ehhez az objektumhoz és az összes alárendeltjéhez letiltja.
    - új jogosultság beállítását meggátolja. -rbac#:#role_confirm_unblock_role_info#:#A 'Szerep kizárásának feloldása' művelettel a következő lépéseket hajtja végre:

    - a helyi irányelveket töröli. -rbac#:#role_unblocked#:#: Szerep kizárását fel fogja oldani +rbac#:#role_blocked#:#: Szerepkört ki fogja zárni +rbac#:#role_confirm_block_role#:#Szerepkör állapotának módosítása +rbac#:#role_confirm_block_role_header#:#Biztos, hogy megváltoztatja a kiválasztott szerepkör zárolási állapotát? +rbac#:#role_confirm_block_role_info#:#A ‘Szerepkör kizárása’ művelettel a következő lépéseket hajtja végre:

    - a szerepkör jogosultságait ehhez az objektumhoz és az összes alárendeltjéhez letiltja.
    - új jogosultság beállítását meggátolja. +rbac#:#role_confirm_unblock_role_info#:#A ‘Szerepkör kizárásának feloldása’ művelettel a következő lépéseket hajtja végre:

    - a helyi irányelveket töröli. +rbac#:#role_unblocked#:#: Szerepkör kizárását fel fogja oldani rbac#:#root_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#root_read#:#A felhasználónak olvasási elérése van a Tartalomtár - Kezdőlap-hoz rbac#:#root_visible#:#Tartalomtár - Kezdőlap látható @@ -14804,17 +14899,17 @@ rbac#:#sess_read#:#A felhasználónak olvasási elérése van munkamenetekhez rbac#:#sess_read_learning_progress#:#A felhasználó megnézheti mások tanulási haladását rbac#:#sess_visible#:#Az események láthatók rbac#:#sess_write#:#A felhasználó eseménytartalmakat és -beállításokat szerkeszthet -rbac#:#skee_copy#:#User can copy Competence Tree (currently not available)###26 08 2024 new variable -rbac#:#skee_delete#:#User can delete Competence Tree###26 08 2024 new variable -rbac#:#skee_edit_permission#:#User can change permission settings of Competence Tree administration###26 08 2024 new variable -rbac#:#skee_manage_comp#:#User can edit Competences in Competence Tree###26 08 2024 new variable -rbac#:#skee_manage_comp_temp#:#User can edit Competence Templates in Competence Tree###26 08 2024 new variable -rbac#:#skee_manage_profiles#:#User can edit Competence Profiles in Competence Tree###26 08 2024 new variable -rbac#:#skee_read#:#User has read access to administration of Competence Tree###26 08 2024 new variable -rbac#:#skee_read_comp#:#User has read access to Competences and Competence Templates in Competence Tree###26 08 2024 new variable -rbac#:#skee_read_profiles#:#User has read access to Competence Profiles in Competence Tree###26 08 2024 new variable -rbac#:#skee_visible#:#Competence Tree is visible###26 08 2024 new variable -rbac#:#skee_write#:#User can edit settings of Competence Tree###26 08 2024 new variable +rbac#:#skee_copy#:#A felhasználó másolhat kompetencia-fát +rbac#:#skee_delete#:#A felhasználó törölhet kompetencia-fát +rbac#:#skee_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Kompetencia-fa jogosultsági beállításait +rbac#:#skee_manage_comp#:#A felhasználó módosíthat kompetenciákat a kompetencia-fában +rbac#:#skee_manage_comp_temp#:#A felhasználó módosíthat kompetenciasablonokat a kompetencia-fában +rbac#:#skee_manage_profiles#:#A felhasználó módosíthat kompetenciaprofilokat a kompetencia-fában +rbac#:#skee_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Kompetencia-fa beállításaihoz +rbac#:#skee_read_comp#:#A felhasználónak olvasási hozzáférése van a kompetenciasablonokhoz a kompetencia-fában +rbac#:#skee_read_profiles#:#A felhasználónak olvasási hozzáférése van a kompetenciaprofilokhoz a kompetencia-fában +rbac#:#skee_visible#:#A kompetencia-fa látható +rbac#:#skee_write#:#A felhasználó módosíthat kompetencia-fa beállításait rbac#:#skmg_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Kompetenciamenedzsment jogosultsági beállításait rbac#:#skmg_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Kompetenciamenedzsment beállításaihoz rbac#:#skmg_visible#:#A felhasználó láthatja a Rendszerbeállítások » Kompetenciamenedzsment menüpontot @@ -14825,11 +14920,11 @@ rbac#:#spl_delete#:#A felhasználó áthelyezhet vagy törölhet kérdőívkérd rbac#:#spl_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat rbac#:#spl_read#:#A felhasználó kérdőívkérdéseket olvashat kérdőívkérdés-gyűjteményben, és beszúrhatja azokat kérdőívbe rbac#:#spl_visible#:#Kérdőívkérdés-gyűjtemény látható -rbac#:#spl_write#:#A felhasználó szerkesztheti kérdésgyűjtemény kérdőívkérdéseit beállításait +rbac#:#spl_write#:#A felhasználó módosíthatja kérdésgyűjtemény kérdőívkérdéseit beállításait rbac#:#statistics_read#:#Statisztikák megtekintése -rbac#:#stus_edit_permission#:#User can change permission settings in Shortlink administration###29 10 2025 new variable -rbac#:#stus_read#:#User can see the Shortlink Administration###29 10 2025 new variable -rbac#:#stus_write#:#User can edit Shortlinks###29 10 2025 new variable +rbac#:#stus_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Gyorslinkek jogosultsági beállításait +rbac#:#stus_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Gyorslinkek beállításaihoz +rbac#:#stus_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Gyorslinkek beállításait rbac#:#sty_write_content#:#Tartalomstílusok módosítása rbac#:#sty_write_page_layout#:#Lapelrendezések módosítása rbac#:#sty_write_system#:#Rendszerstílusok módosítása @@ -14844,7 +14939,7 @@ rbac#:#svy_copy#:#A felhasználó másolhat kérdőívet rbac#:#svy_delete#:#A felhasználó áthelyezhet vagy törölhet kérdőívet rbac#:#svy_edit_learning_progress#:#A felhasználó módosíthatja a tanulási haladás beállításait rbac#:#svy_edit_permission#:#A felhasználó módosíthatja a jogosultsági beállításokat -rbac#:#svy_invite#:#A felhasználó meghívhat másokat kérdőívhez +rbac#:#svy_invite#:#A felhasználó meghívhat másokat kérdőívbe rbac#:#svy_read#:#A felhasználó részt vehet kérdőívben rbac#:#svy_read_learning_progress#:#A felhasználó megnézheti mások tanulási haladását rbac#:#svy_read_results#:#A felhasználó hozzáférhet mások válaszaihoz @@ -14862,10 +14957,10 @@ rbac#:#tags_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállít rbac#:#tags_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Címkézés beállításaihoz rbac#:#tags_visible#:#A felhasználó láthatja a Rendszerbeállítások » Címkézés menüpontot rbac#:#tags_write#:#A felhasználó módosíthatja a Rendszerbeállítások » Címkézés beállításait -rbac#:#tala_edit_permission#:#User can change permission settings in Talk Templates administration###26 08 2024 new variable -rbac#:#tala_read#:#User has read access to Talk Templates administration###26 08 2024 new variable -rbac#:#tala_visible#:#Talk Templates administration is visible###26 08 2024 new variable -rbac#:#tala_write#:#User can create and edit Talk Templates###26 08 2024 new variable +rbac#:#tala_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Általános beállítások » Megbeszéléssablonok jogosultsági beállításait +rbac#:#tala_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Taxonómia menüpontot +rbac#:#tala_visible#:#A felhasználó láthatja a Rendszerbeállítások » Megbeszéléssablonok menüpontot +rbac#:#tala_write#:#A felhasználó létrehozhat és módosíthat Megbeszéléssablonokat rbac#:#taxs_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Taxonómia jogosultsági beállításait rbac#:#taxs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Taxonómia beállításaihoz rbac#:#taxs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Taxonómia menüpontot @@ -14886,24 +14981,24 @@ rbac#:#tst_edit_learning_progress#:#A felhasználó módosíthatja a tanulási h rbac#:#tst_edit_permission#:#Jogosultsági beállítások változtatása rbac#:#tst_read#:#A felhasználó tesztet tölthet ki rbac#:#tst_read_learning_progress#:#A felhasználó megnézheti mások tanulási haladását -rbac#:#tst_tst_history_read#:#View History###29 10 2025 new variable +rbac#:#tst_tst_history_read#:#Előzmények megtekintése rbac#:#tst_tst_results#:#A felhasználó hozzáférhet mások teszteredményeihez rbac#:#tst_visible#:#A teszt látható rbac#:#tst_write#:#A felhasználó szerkesztheti teszt tartalmát és beállításait rbac#:#upload_blacklisted_files#:#A tiltólista megkerülése rbac#:#usrf_delete#:#A felhasználó törölhet ILIAS-fiókokat rbac#:#usrf_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » ILIAS-fiókok jogosultsági beállításait -rbac#:#usrf_edit_roleassignment#:#A felhasználó ajánlott tartalmat adhat a szerepek tagjainak. +rbac#:#usrf_edit_roleassignment#:#A felhasználó ajánlott tartalmat adhat a szerepkörök tagjainak. rbac#:#usrf_push_desktop_items#:#A felhasználó objektumokat tehet ki a szereppel rendelkezők munkaasztalára rbac#:#usrf_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » ILIAS-fiókok beállításaihoz -rbac#:#usrf_read_all_accounts#:#User can list all accounts in User administration###29 10 2025 new variable +rbac#:#usrf_read_all_accounts#:#A felhasználó listázhatja az összes fiókot a Rendszerbeállítások » ILIAS-fiókok részben rbac#:#usrf_read_users#:#A felhasználónak olvasási elérése van a helyi ILIAS-fiókokhoz (helyi rendszergazda) rbac#:#usrf_visible#:#A felhasználó láthatja a Rendszerbeállítások » ILIAS-fiókok menüpontot rbac#:#usrf_write#:#A felhasználó módosíthatja a Rendszerbeállítások » ILIAS-fiókok beállításait -rbac#:#wbdv_edit_permission#:#User can change permission settings of WebDAV administration.###29 10 2025 new variable -rbac#:#wbdv_read#:#User has read access to WebDAV administration.###29 07 2022 new variable -rbac#:#wbdv_visible#:#Administration of WebDAV is visible.###29 07 2022 new variable -rbac#:#wbdv_write#:#User can edit settings of WebDAV administration.###29 07 2022 new variable +rbac#:#wbdv_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » WebDAV jogosultsági beállításait +rbac#:#wbdv_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » WebDAV beállításaihoz +rbac#:#wbdv_visible#:#A felhasználó láthatja a Rendszerbeállítások » WebDAV menüpontot +rbac#:#wbdv_write#:#A felhasználó módosíthatja a Rendszerbeállítások » WebDAV beállításait rbac#:#wbrs_edit_permission#:#A felhasználó módosíthatja a Rendszerbeállítások » Weblink jogosultsági beállításait rbac#:#wbrs_read#:#A felhasználónak olvasási hozzáférése van a Rendszerbeállítások » Weblink beállításaihoz rbac#:#wbrs_visible#:#A felhasználó láthatja a Rendszerbeállítások » Weblink menüpontot @@ -14915,7 +15010,7 @@ rbac#:#webr_read#:#A felhasználó olvashat és használhat weblinket rbac#:#webr_visible#:#A weblink látható rbac#:#webr_write#:#A felhasználó szerkeszthet weblink-beállításokat rbac#:#wiki_activate_wiki_protection#:#Wiki oldalak írásvédetté tétele -rbac#:#wiki_add_pages#:#User can create wiki pages###26 08 2024 new variable +rbac#:#wiki_add_pages#:#A felhasználó létrehozhat wikioldalakat rbac#:#wiki_copy#:#A felhasználó másolhat wikit rbac#:#wiki_delete#:#A felhasználó áthelyezhet vagy törölhet wikit. rbac#:#wiki_delete_wiki_pages#:#Wiki oldalak törlése @@ -14937,48 +15032,48 @@ rbac#:#write#:#Beállítások módosítása rcat#:#rcat_call#:#ECS kategória hívása rcrs#:#rcrs_call#:#ECS-kurzus hívása registration#:#reg_access_limitation_limited_time#:#Regisztráció után elérés ehhez: -registration#:#reg_access_limitation_limited_until#:#Az elérés korlátozott eddig: -registration#:#reg_access_limitation_missing_mode#:#Válasszon minden szerephez elérési korlátozás módot! -registration#:#reg_access_limitation_mode#:#Elérési korlátozás módja -registration#:#reg_access_limitation_mode_absolute#:#Megadott dátumig korlátozott elérés. +registration#:#reg_access_limitation_limited_until#:#A hozzáférés korlátozása eddig: +registration#:#reg_access_limitation_missing_mode#:#Válasszon minden szerepkörhöz hozzáférési korlátozás módot! +registration#:#reg_access_limitation_mode#:#Hozzáférés-korlátozás módja +registration#:#reg_access_limitation_mode_absolute#:#Hozzáférés korlátozása megadott dátumig registration#:#reg_access_limitation_mode_absolute_target#:#Érvényes eddig: -registration#:#reg_access_limitation_mode_relative#:#Határozott időre korlátozott elérés (regisztrációtól) +registration#:#reg_access_limitation_mode_relative#:#Korlátozott hozzáférés meghatározott időre (regisztrációtól) registration#:#reg_access_limitation_mode_relative_target#:#Érvényes -registration#:#reg_access_limitation_mode_unlimited#:#Nincs elérési korlátozás +registration#:#reg_access_limitation_mode_unlimited#:#Nincs a hozzáférésnek lejárati dátuma registration#:#reg_access_limitation_none#:#Korlátlan elérés -registration#:#reg_access_limitation_out_of_date#:#Egy vagy több szerepnek lejárt az elérési korlátozása! -registration#:#reg_access_limitations#:#Elérési korlátozás +registration#:#reg_access_limitation_out_of_date#:#Egy vagy több szerepnek lejárt a hozzáférési korlátozása! +registration#:#reg_access_limitations#:#Hozzáférés lejárati dátuma registration#:#reg_add_assignment#:#Új összerendelés registration#:#reg_added_assignment#:#Új összerendelés létrehozása registration#:#reg_allow_codes#:#Kódok engedélyezése registration#:#reg_allow_codes_info#:#A felhasználók kód segítségével is regisztrálhatják magukat. registration#:#reg_allowed_domains#:#Engedélyezett e-mail cím domain-ek -registration#:#reg_allowed_domains_info#:#Használjon helyettesítőnek *-ot, elválasztónak ;-t, például '*@cegem.hu;*@egyetem.hu'. A regisztrációs kódok felülírják ezt a szabályt. +registration#:#reg_allowed_domains_info#:#Használjon helyettesítőnek *-ot, elválasztónak ;-t, például ‘*@cegem.hu;*@egyetem.hu’. A regisztrációs kódok felülírják ezt a szabályt. registration#:#reg_approve#:#Regisztráció jóváhagyással -registration#:#reg_approve_info#:#Ha bejelölt, új felhasználói regisztráció rendszergazdai jóváhagyást kíván. -registration#:#reg_approve_needs_recipient#:#Legalább egy felhasználót meg kell adnia, aki értesítve lesz azokról az új regisztrációkról, amelyek típusa 'Regisztráció jóváhagyással'. -registration#:#reg_available_roles#:#Elérhető szerepek: -registration#:#reg_confirmation_already_confirmed#:#The registration is no longer pending, it has already been confirmed.###29 10 2025 new variable +registration#:#reg_approve_info#:#Az új felhasználói regisztrációhoz üzemeltetői jóváhagyás szükséges. +registration#:#reg_approve_needs_recipient#:#Legalább egy felhasználót meg kell adnia, aki értesítve lesz azokról az új regisztrációkról, amelyek típusa ‘Regisztráció jóváhagyással’. +registration#:#reg_available_roles#:#Elérhető szerepkörök: +registration#:#reg_confirmation_already_confirmed#:#A regisztráció már nincs függőben, azt már visszaigazolták. registration#:#reg_confirmation_hash_life_time#:#Élettartam registration#:#reg_confirmation_hash_life_time_expired#:#A visszaigazoló link nem érvényes a továbbiakban. Regisztráljon újra! registration#:#reg_confirmation_hash_life_time_info#:#Visszaigazoló linkek élettartamának megadása (másodpercben). Az ajánlott érték 1800 másodperc. registration#:#reg_confirmation_hash_not_found#:#Ehhez a visszaigazoló linkhez nem tartozik ILIAS-fiók. -registration#:#reg_confirmation_hash_not_passed#:#The confirmation link is incomplete.###26 08 2024 new variable -registration#:#reg_confirmation_link_successful#:#Sikeresen elküldött egy ILIAS-fiók igényt az ILIAS-hoz. A következő néhány percben kap egy visszaigazoló e-mailt.
    20 másodperc múlva átirányításra kerül a bejelentkező képernyőre. +registration#:#reg_confirmation_hash_not_passed#:#A visszaigazoló link nem teljes. +registration#:#reg_confirmation_link_successful#:#Sikeresen elküldött egy ILIAS-fiók igényt az ILIAS-hoz. A következő néhány percben kap egy visszaigazoló e-mailt. registration#:#reg_default#:#Alapértelmezett registration#:#reg_deleted_assignment#:#Törölt összerendelés(ek) registration#:#reg_direct#:#Közvetlen regisztráció registration#:#reg_direct_info#:#Új felhasználó regisztrációkérése automatikusan jóváhagyásra kerül. registration#:#reg_disabled#:#Regisztráció nem lehetséges registration#:#reg_domain#:#Tartomány -registration#:#reg_domain_already_assigned_p#:#The domains '%s' were already entered for another role.###26 08 2024 new variable -registration#:#reg_domain_already_assigned_s#:#The domain '%s' was already entered for another role. ###26 08 2024 new variable +registration#:#reg_domain_already_assigned_p#:#‘%s’ domainek már másik szerepkörhöz hozzá vannak rendelve. +registration#:#reg_domain_already_assigned_s#:#‘%s’ domain már másik szerepkörhöz hozzá van rendelve. registration#:#reg_email#:#Automatikus szerep-összerendelés registration#:#reg_email_domains#:#Az alábbi e-mail cím domain-ek érvényesek: %s registration#:#reg_email_domains_code#:#Regisztrációs kóddal bármely e-mail cím érvényes. registration#:#reg_email_role_assignment#:#Szerep-összerendelés tartománnyal -registration#:#reg_fixed#:#Megadott listából kiválasztás -registration#:#reg_info_pwd#:#A jelszavak e-mailben automatikusan elküldésre kerülnek az új felhasználóknak. +registration#:#reg_fixed#:#Megadott listából szabad választás +registration#:#reg_info_pwd#:#A véletlengenerált jelszót e-mailben automatikusan elküldjük az újonan regisztrált felhasználónak. registration#:#reg_mail_body_activation#:#ILIAS-fiókja aktiváláshoz és e-mail címének igazolásához kattintson ide: registration#:#reg_mail_body_approve#:#Regisztrált az ILIAS e-learning keretrendszerbe és kapott egy levelet felhasználói adataival. Most ILIAS-fiókját bekapcsolta egy rendszergazda. registration#:#reg_mail_body_confirmation#:#A regisztráció jóváhagyásához lépjen be az ILIAS-rendszerbeállításaiba, és aktiválja az ILIAS-fiókot. @@ -14993,12 +15088,12 @@ registration#:#reg_mail_new_user_confirmation#:#Hozzáférési kérelem jóváha registration#:#reg_missing_domain#:#Töltsön ki minden mezőt. registration#:#reg_missing_role#:#Töltsön ki minden mezőt. registration#:#reg_notification#:#Értesítések -registration#:#reg_notification_info#:#Adja meg egy vagy több felhasználó bejelentkezési azonosítóját (vesszővel elválasztva), akik e-mailben értesítésre kerülnek az új felhasználói regisztrációkról. -registration#:#reg_role_access_limitations#:#Definiálja a szerepek elérési korlátozásait az újonnan regisztrált felhasználókhoz. +registration#:#reg_notification_info#:#Adjon meg egy vagy több felhasználónevet (vesszővel elválasztva), akik e-mailben értesítést kapnak új felhasználó regisztrációjáról. +registration#:#reg_role_access_limitations#:#Definiálja a szerepkörök elérési korlátozásait az újonnan regisztrált felhasználókhoz. registration#:#reg_role_assignment#:#Szerep-összerendelés -registration#:#reg_role_info#:#Hozzárendelt szerepek +registration#:#reg_role_info#:#Hozzárendelt szerepkörök registration#:#reg_select_one#:#Válasszon ki egy bejegyzést. -registration#:#reg_selectable_roles#:#Kiválasztható szerepek +registration#:#reg_selectable_roles#:#Kiválasztható szerepkörök registration#:#reg_settings_header#:#Új regisztrációs beállítások registration#:#reg_type#:#Regisztrációtípus registration#:#reg_type_confirmation#:#Regisztráció e-mail visszaigazolással @@ -15013,14 +15108,14 @@ registration#:#registration_codes_access_limitation_all#:#Összes registration#:#registration_codes_add#:#Kódok létrehozása registration#:#registration_codes_edit_header#:#Kódok létrehozása registration#:#registration_codes_export#:#Kódok exportálása -registration#:#registration_codes_no_assigned_role#:#Nincs előredefiniált hozzárendelendő szerep +registration#:#registration_codes_no_assigned_role#:#Nincs előredefiniált hozzárendelendő szerepkör registration#:#registration_codes_number#:#Kódok száma -registration#:#registration_codes_override_global_info#:#Ezek a beállítások regisztrációs kódokkal felülírhatóak. -registration#:#registration_codes_override_info#:#Ez a beállítás felülírja a 'Regisztráció beállítások' alatt lévő bármely értékét. -registration#:#registration_codes_roles#:#Szerepek új bejelentkezésekhez +registration#:#registration_codes_override_global_info#:#Ezek a beállítások regisztrációs kódokkal felülírhatók. +registration#:#registration_codes_override_info#:#Ez a beállítás felülírja a ‘Regisztráció beállítások’ alatt lévő bármely értékét. +registration#:#registration_codes_roles#:#Szerepkörök új bejelentkezésekhez registration#:#registration_codes_roles_limitation_none#:#Nincs előredefiniált hozzáférési korlátozás registration#:#registration_codes_roles_local#:#Helyi szabály(ok) -registration#:#registration_codes_roles_title#:#Új ILIAS-fiókokhoz rendelt szerep +registration#:#registration_codes_roles_title#:#Új ILIAS-fiókokhoz rendelt szerepkör registration#:#registration_codes_type#:#Kód típusa registration#:#registration_codes_type_ext#:#Korlátozott felhasználói fiókok kiterjesztése registration#:#registration_codes_type_ext_info#:#A kódot korlátozott felhasználói fiókok kiterjesztésére lehet felhasználni @@ -15030,10 +15125,10 @@ registration#:#registration_disabled_no_access#:#A regisztrációs lehetőség n registration#:#registration_export_codes_no_data#:#Nincs kiválasztott kód az exportáláshoz. registration#:#registration_generated#:#Generálás dátuma registration#:#registration_generated_all#:#Összes dátum -registration#:#registration_no_valid_role#:#Jelenleg nincs érvényes szerep új ILIAS-fiókhoz. Vegye fel a kapcsolatot egy rendszergazdával! +registration#:#registration_no_valid_role#:#Jelenleg nincs érvényes szerepkör új ILIAS-fiókhoz. Vegye fel a kapcsolatot egy rendszergazdával! registration#:#registration_reg_type_codes#:#Regisztráció kódokkal -registration#:#registration_reg_type_codes_info#:#Lehetséges a felhasználók önregisztrációja, de érvényes kódra van hozzá szükség. -registration#:#registration_roles_all#:#Összes szerep +registration#:#registration_reg_type_codes_info#:#A felhasználók regisztrálhatják saját magukat, de ehhez érvényes kód szükséges. +registration#:#registration_roles_all#:#Összes szerepkör registration#:#registration_settings#:#ILIAS-hitelesítés / Regisztráció registration#:#registration_tab_codes#:#Regisztrációs kódok registration#:#registration_tab_settings#:#Regisztrációs beállítások @@ -15055,37 +15150,35 @@ rep#:#rep_add_new_def_grp_content#:#Tartalom rep#:#rep_add_new_def_grp_feedback#:#Visszajelzés és felmérés rep#:#rep_add_new_def_grp_organisation#:#Szervezet rep#:#rep_add_new_def_grp_templates#:#Sablonok -rep#:#rep_add_to_favourites#:#Hozzáadás a kedvencekhez rep#:#rep_added_rec_content#:#Az ajánlott tartalmat sikeresen hozzáadta. -rep#:#rep_added_to_favourites#:#Az objektumot felvette a kedvencei közé. -rep#:#rep_allowed_types#:#Allowed Types###26 08 2024 new variable +rep#:#rep_allowed_types#:#Engedélyezett típusok rep#:#rep_breadcr_crs#:#A navigációs sor a kurzustól indul -rep#:#rep_breadcr_crs_config#:#Configuration###26 08 2024 new variable +rep#:#rep_breadcr_crs_config#:#Beállítások rep#:#rep_breadcr_crs_overwrite#:#A beállítás kurzusszinten módosítható rep#:#rep_breadcr_crs_overwrite_not#:#A beállítás nem módosítható kurzusszinten -rep#:#rep_breadcr_crs_overwrite_settings#:#Allow Exceptions###26 08 2024 new variable -rep#:#rep_breadcr_crs_overwrite_with_default#:#Setting is changeable on course level, with this as default###26 08 2024 new variable +rep#:#rep_breadcr_crs_overwrite_settings#:#Kivételek engedélyezése +rep#:#rep_breadcr_crs_overwrite_with_default#:#Ez az alapértelmezett értek, de a beállítás kurzuszinten módosítható. rep#:#rep_configure#:#Beállítások -rep#:#rep_crs_default_shortened#:#Default: Breadcrumbs Shortened###26 08 2024 new variable +rep#:#rep_crs_default_shortened#:#Alapértelmezett: Rövidített navigációs sor rep#:#rep_custom_icons#:#Egyéni ikonok rep#:#rep_default#:#Alapértelmezett -rep#:#rep_deleted_account#:#Deleted Account###26 08 2024 new variable +rep#:#rep_deleted_account#:#Törölt fiók rep#:#rep_dependencies#:#Függőségek rep#:#rep_dependency#:#Függőség rep#:#rep_dependent_object#:#Források függőséggel rep#:#rep_export_limit_number#:#Objektumok száma rep#:#rep_export_limitation#:#Tároló típusú objektumok exportálásának korlátozása rep#:#rep_export_limitation_disabled#:#Tároló típusú objetumok exportálásának tiltása -rep#:#rep_export_limitation_info#:#A Tartalomtárban lévő tároló objektum (kurzusok, kategóriák, ...) exportálásának korlátozása elemeinek száma alapján. +rep#:#rep_export_limitation_info#:#A Tartalomtárban lévő tároló objektum (kurzusok, kategóriák, …) exportálásának korlátozása elemeinek száma alapján. rep#:#rep_export_limitation_limited#:#Exportálás korlátja -rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable -rep#:#rep_failure_trashed_trash#:#Olyan elemeket választott ki, melyek eredeti helyére nem állíthatóak vissza, mert a szülőobjektumát törölték. Kérem, nem válasszon ki ilyen objektumot vagy válassza az új helyre visszaállítást. +rep#:#rep_export_limitation_unlimited#:#Korlátlan exportálás +rep#:#rep_failure_trashed_trash#:#Olyan elemeket választott ki, melyek eredeti helyére nem állíthatók vissza, mert a szülőobjektumát törölték. Kérem, nem válasszon ki ilyen objektumot vagy válassza az új helyre visszaállítást. rep#:#rep_fav_intro1#:#Még nem választott ki egy kedvencet sem. Ehhez két lépést kell tennie: -rep#:#rep_fav_intro2#:#Kattintson '%s' elemre és válasszon egy tanulási objektumot a rendelkezésre álló ajánlatból, például egy tananyagot vagy egy fórumot. -rep#:#rep_fav_intro3#:#Amikor olyasmire bukkan, ami felkeltette az érdeklődését, adja hozzá a kedvenceihez: válassza a kívánt objektum Műveletek menüjéből a 'Hozzáadás a kedvencekhez' lehetőséget. -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable -rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable -rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable +rep#:#rep_fav_intro2#:#Kattintson ‘%s’ elemre és válasszon egy tanulási objektumot a rendelkezésre álló ajánlatból, például egy tananyagot vagy egy fórumot. +rep#:#rep_fav_intro3#:#Amikor olyasmire bukkan, ami felkeltette az érdeklődését, adja hozzá a kedvenceihez: válassza a kívánt objektum Műveletek menüjéből a ‘Hozzáadás a kedvencekhez’ lehetőséget. +rep#:#rep_favourites#:#Kedvencek +rep#:#rep_favourites_info#:#Kedvencként jelölhet meg Tartalomtárban lévő elemeket. A kedvencek listája az irányítópult és a menü beállításaiban kapcsolható be és konfigurálható. +rep#:#rep_input_not_empty#:#Ez a mező nem lehet üres, kérem, adjon meg egy értéket. rep#:#rep_intro#:#Üdvözöljük a Tartalomtárban! rep#:#rep_intro1#:#Ezen a területen tanulási és munkaforrásokat hozhat létre felhasználói számára. Minden forrás kategóriákba van szervezve. A kategóriák utalhatnak az Ön szervezetének struktúrájára (például osztályok), tudományágak hierarchiájára vagy iskolai osztályokra. rep#:#rep_intro2#:#Három lépés szükséges a kezdeti struktúra elkészítéséhez: @@ -15104,21 +15197,19 @@ rep#:#rep_new_item_group_other#:#Egyebek rep#:#rep_new_item_group_unassigned#:#Nincs hozzárendelve rep#:#rep_new_item_group_unassigned_subitems#:#Hozzá nem rendelt objektumok száma: %s rep#:#rep_new_item_groups#:#Csoportosítás -rep#:#rep_new_item_menu#:#'Új objektum létrehozása'-Menü -rep#:#rep_no_last_visited_mess#:#You did not visited any resources yet.###29 07 2022 new variable +rep#:#rep_new_item_menu#:#‘Új objektum létrehozása’-Menü +rep#:#rep_no_last_visited_mess#:#Még a Tartalmotár egy objektumát sem látogatta meg. rep#:#rep_no_permission_to_delete#:#Nincs törlési jogosultság rep#:#rep_object_lists#:#Objektum listák rep#:#rep_object_references_cannot_be_read#:#Nincs több hivatkozásra engedélye ehhez: %s. rep#:#rep_object_to_delete#:#Törölni rep#:#rep_rec_content_removed#:#Az ajánlott tartalmat sikeresen eltávolította. rep#:#rep_recommended_content#:#Ajánlott tartalom -rep#:#rep_remove_from_favourites#:#Eltávolítás a kedvencek közül rep#:#rep_remove_rec_content#:#Biztos, hogy eltávolítja az alábbi ajánlott tartalmat? -rep#:#rep_removed_from_favourites#:#Az objektumot sikeresen eltávolította a kedvencei közül. rep#:#rep_target_location#:#Célhely rep#:#rep_target_location_info#:#Kérem, válassza ki a helyet, ahová a kiválasztott objektumokat visszaállítja. rep#:#rep_time_based_availability#:#Elérhetőség időbeli korlátozása -rep#:#rep_time_based_availability_info#:#The selected items will only be visible between the start and end date.###26 08 2024 new variable +rep#:#rep_time_based_availability_info#:#A kiválasztott elemek csak a kezdő és a záró dátum között lesznek láthatók. rep#:#rep_time_period#:#Időszak rep#:#rep_trash_deleted_by_unknown#:#Ismeretlen rep#:#rep_trash_table_col_deleted_by#:#Törölte @@ -15138,8 +15229,6 @@ rtst#:#rtst_call#:#ECS teszt hívása rwik#:#rwik_call#:#ECS wiki hívása sahs#:#cont_insert_after_chap#:#Elemek beszúrása a fejezet után sahs#:#cont_insert_into_chap#:#Elemek beszúrása a fejezetbe -sahs#:#sahs_activate_expert_mode#:#Sorrend szakértő mód aktiválása -sahs#:#sahs_activate_expert_mode_info#:#A sorrend szakértői mód lehetővé teszi a csomagfa sorrend-információinak közvetlen szerkesztését. Ha bizonytalan abban, hogy ez mit jelent, azt ajánljuk, hogy használja az alapértelmezett sorrendi viselkedést. sahs#:#sahs_add#:#SCORM-tananyag létrehozása sahs#:#sahs_authoring_mode#:#Szerzői mód sahs#:#sahs_authoring_mode_info#:#A SCORM zip csomagot az ILIAS SCORM szerkesztővel kell létrehozni, és SCORM 1.2/2004 csomagként kell exportálni. @@ -15328,7 +15417,7 @@ scormdebug#:#return_value#:#visszatérési érték scormdebug#:#scormdebug_disable_cache#:#SCORM 2004 böngésző-gyorsítótárazás letiltása scormdebug#:#scormdebug_disable_cache_info#:#Ez megakadályozza a SCORM 2004 JavaScript fájlok tárolását a böngésző gyorsítótárában. Ezt a funkciót új közzététel előtt használja. scormdebug#:#scormdebug_global_activate#:#SCORM teszteszköz engedélyezése -scormdebug#:#scormdebug_global_activate_info#:#Ha be van kapcsolva, a SCORM-teszteszköz aktiválható a kívánt tananyagokhoz. Ha le van tiltva, a teszteszköz egyik tananyaghoz sem aktív. +scormdebug#:#scormdebug_global_activate_info#:#A SCORM-teszteszköz aktiválható a kívánt tananyagokhoz. Ha le van tiltva, a teszteszköz egyik tananyaghoz sem aktív. scormdebug#:#sent_values_not_checked#:#kiválasztott tulajdonság: az SCO által elküldött értékek nem ellenőrzöttek teljes mértékben scormdebug#:#show_all_API-calls#:#API-hívások megjelenítése. scormdebug#:#show_only_important_API-calls#:#Csak a fontos API-hívások megjelenítése. @@ -15337,7 +15426,7 @@ scormdebug#:#strange_API-Call#:#szokatlan API-hívás scormdebug#:#strange_error#:#szokatlan hiba scormdebug#:#success_status_by_score_scaled#:#Mivel van érték a cmi.scaled_passing_score-hoz, a cmi.success_status-hoz levő értéket az LMS értékeli ki! Ez a cmi.scaled_passing_score-hoz és a cmi.score.scaled-hez tartozó értékek összehasonlításával történik. A cmi.success_status-hoz tartozó érték jelenleg: scormdebug#:#summary_csv#:#Az összefoglaló CVS-fájlként van generálva például Excelbe importáláshoz -scormdebug#:#summary_download#:#A 'Logokra' kattinthat, és amikor legközelebb elindítja ezt az eszközt, letöltheti. +scormdebug#:#summary_download#:#A ‘Logokra’ kattinthat, és amikor legközelebb elindítja ezt az eszközt, letöltheti. scormdebug#:#summary_for_SCO_with_test#:#Összefoglaló SCO-hoz teszttel scormdebug#:#summary_for_SCO_without_test#:#Összefoglaló SCO-hoz teszt nélkül scormdebug#:#undefined_color#:#nem definiált szín @@ -15424,12 +15513,12 @@ scormtrac#:#total_time_seconds#:#total_time: összes idő másodpercben scormtrac#:#tracinteractionitem#:#Interakciónkénti értékelés scormtrac#:#tracinteractionuser#:#Felhasználónkénti értékelés scormtrac#:#tracinteractionuseranswers#:#Felhasználók válaszai -scormtrac#:#user_id#:#User-ID +scormtrac#:#user_id#:#User_id scormtrac#:#weighting#:#weighting -scov#:#crsv_create#:#SCORM-igazolás létrehozása -scov#:#crsv_create_info#:#Válasszon egy tananyagot, hogy igazolást generálhassunk hozzá -scov#:#scov_create#:#SCORM-igazolás létrehozása -scov#:#scov_create_info#:#Válasszon egy teljes SCORM-tananyag, amelyikhez igazolást hozzunk létre. +scov#:#crsv_create#:#SCORM-tanúsítvány létrehozása +scov#:#crsv_create_info#:#Válasszon egy tananyagot, hogy tanúsítványt generálhassunk hozzá +scov#:#scov_create#:#SCORM-tanúsítvány létrehozása +scov#:#scov_create_info#:#Válasszon egy teljes SCORM-tananyag, amelyikhez tanúsítványt hozzunk létre. search#:#add_members_header#:#Tagok hozzáadása search#:#append_results#:#Eredmények hozzáfűzése search#:#btn_search#:#Keresés @@ -15438,7 +15527,7 @@ search#:#lucene_and#:#ÉS search#:#lucene_cpu#:#Szálak maximális száma search#:#lucene_create_ini#:#Konfigurációs fájl létrehozása search#:#lucene_default_operator#:#Alapértelmezett beállítások -search#:#lucene_default_operator_info#:#Válassza ki az alapműveletet a logikai lekérdezésekhez. Alapértelmezett módban ('ÉS') az kifejezések együtt, 'VAGY' módban a kifejezések lehetőségként vannak figyelembe véve. +search#:#lucene_default_operator_info#:#Válassza ki az alapműveletet a logikai lekérdezésekhez. Alapértelmezett módban (‘ÉS’) az kifejezések együtt, ‘VAGY’ módban a kifejezések lehetőségként vannak figyelembe véve. search#:#lucene_download_ini#:#Konfigurációs fájl letöltése search#:#lucene_err_ampersand#:#Az && speciális karaktereket tartalmazó kérdéseknek a következő formája kell legyen: kifejezés1 && kifejezés2. search#:#lucene_err_and_or_not#:#Az ÉS/VAGY/NEM-et tartalmazó kérdéseknek a következő formában kell lenniük: kifejezés1 ÉS|VAGY|NEM|ÉS NEM kifejezés2. @@ -15470,40 +15559,44 @@ search#:#lucene_offline_filter#:#Online állapot search#:#lucene_or#:#VAGY search#:#lucene_port#:#Port search#:#lucene_prefix_wildcard#:#Helyettesítő jellel keresés -search#:#lucene_prefix_wildcard_info#:#Helyettesítő jellel végzett keresések támogatása: '*LIAS' találata 'ILIAS' +search#:#lucene_prefix_wildcard_info#:#Helyettesítő jellel végzett keresések támogatása: ‘*LIAS’ találata ‘ILIAS’ +search#:#lucene_settings_index_section#:#Index Backup search#:#lucene_settings_tab#:#Lucene +search#:#lucene_settings_text_section#:#A keresési eredmények megjelenítése search#:#lucene_settings_title#:#Lucene beállítások -search#:#lucene_size_frag_info#:#Válassza ki a kiemelt szövegtöredékek maximális hosszát. +search#:#lucene_size_frag_info#:#Válassza ki a kiemelt szövegtöredékek maximális hosszát. Ehhez adja meg a karakterek számát szóközökkel. search#:#lucene_size_fragments#:#Szövegtöredékek mérete search#:#lucene_tbl_create_ini#:#Java-szerver ini-fájljának létrehozása search#:#search_add_members_from_container_crs#:#Felhasználók jelen kurzushoz rendelése search#:#search_add_members_from_container_grp#:#Felhasználók jelen csoporthoz rendelése search#:#search_any#:#-- Bármi -- -search#:#search_area#:#Terület +search#:#search_area#:#Keresési terület search#:#search_area_info#:#Válassza ki azt a területet, ahol a keresés kezdődjön. search#:#search_auto_complete_length#:#Automatikus kiegészítéseket tartalmazó lista bejegyzéseinek száma +search#:#search_auto_complete_length_info#:#Válassza a ‘0’ lehetőséget az automatikus kiegészítési lista kikapcsolásához. search#:#search_cdate_filter#:#Szűrés létrehozás dátum alapján -search#:#search_cdate_filter_info#:#Ha be van kapcsolva, az objektumok keresése szűrhető létrehozásuk dátuma alapján. +search#:#search_cdate_filter_info#:#Az objektumok keresése szűrhető létrehozásuk dátuma alapján. search#:#search_content#:#Laptartalom -search#:#search_copyright#:#Copyright###29 10 2025 new variable +search#:#search_copyright#:#Copyright search#:#search_created_after#:#Később jött létre, mint search#:#search_created_before#:#Korábban jött létre, mint search#:#search_created_on#:#Ezen a napon jött létre search#:#search_crs_title#:#Kurzusnév -search#:#search_detailed_results_title#:#Detailed results in %s###29 10 2025 new variable +search#:#search_detailed_results_title#:#Részletes eredmények %s-ban search#:#search_details_info#:#Részletezett keresés. Válasszon ki egy vagy több forrástípust. search#:#search_direct#:#Direkt keresés search#:#search_err_user_not_exist#:#Nincs azzal a bejelentkező névvel felhasználó. search#:#search_fast_info#:#Címek, leírások és kulcsszavak keresése minden objektumtípusban -search#:#search_field#:#Search Input Field###29 07 2022 new variable -search#:#search_field_perform#:#Perform Search###26 08 2024 new variable +search#:#search_field#:#Kereső bemeneti mező +search#:#search_field_perform#:#Keresés végrehajtása search#:#search_filter_by_type#:#Típus szerinti szűrő search#:#search_filter_cd#:#Szűrés létrehozás dátuma alapján +search#:#search_filter_settings_section#:#Szűrők a keresési eredményekhez search#:#search_for_crs_members#:#Kurzusok keresése search#:#search_for_grp_members#:#Csoportok keresése search#:#search_for_orgu_members#:#Szervezeti egységek keresése -search#:#search_for_orgu_members_recursive#:#Include Subunits?###26 08 2024 new variable -search#:#search_for_role_members#:#Szerepek keresése +search#:#search_for_orgu_members_recursive#:#Az alegységekben is? +search#:#search_for_role_members#:#Szerepkörök keresése search#:#search_for_users#:#Felhasználók keresése search#:#search_grp_title#:#Csoportnév search#:#search_item_filter_form#:#Keresés típus szerint @@ -15522,79 +15615,79 @@ search#:#search_minimum_info#:#Keresési feltétele legalább %s karakter hossz search#:#search_minimum_three#:#A keresésnek legalább három karakter hosszúnak kell lennie. search#:#search_newer_than#:#Újabb, mint search#:#search_no_connection_lucene#:#Nem sikerült kapcsolódni a Lucene-szerverhez. -search#:#search_no_match#:#Keresés eredménytelen. +search#:#search_no_match#:#A keresése nem adott eredményt. search#:#search_no_match_hint#:#%s keresése egyetlen dokumentumra sem ad találatot.

    Javasoljuk, hogy:
    • Ellenőrizze, hogy minden szót helyesen írt-e.
    • Próbálkozzon más kulcsszavakkal.
    • Próbálkozzon általánosabb kulcsszavakkal.
    • Próbálkozzon kevesebb kulcsszóval. search#:#search_no_selection#:#Nem választott. search#:#search_off#:#Kikapcsolás -search#:#search_readme_file#:#Readme File###29 10 2025 new variable -search#:#search_results_show_subitems#:#See detailed results###29 10 2025 new variable -search#:#search_results_too_many_subitems#:#More results are available, please make your search terms more precise.###29 10 2025 new variable +search#:#search_readme_file#:#Readme fájl +search#:#search_results_show_subitems#:#Részletes eredmények megtekintése +search#:#search_results_too_many_subitems#:#További találatok érhetők el, kérjük, pontosítsa a keresési kifejezéseket. search#:#search_role_title#:#Szerepnév search#:#search_select_search_area#:#Keresési terület kiválasztása -search#:#search_server_further_information#:#You can find further information about the Lucene server configuration in the readme file.###29 10 2025 new variable +search#:#search_server_further_information#:#A Lucene szerver konfigurációjáról további információkat a readme fájlban talál. search#:#search_show_inactive_user#:#Inaktív felhasználók megjelenítése -search#:#search_show_inactive_user_info#:#Ha be van kapcsolva, a felhasználói keresés az inaktív felhasználókat is visszaadja. +search#:#search_show_inactive_user_info#:#A felhasználói keresés az inaktív felhasználókat is visszaadja. search#:#search_show_limited_user#:#Korlátozott hozzáférésű felhasználók megjelenítése -search#:#search_show_limited_user_info#:#Ha be van kapcsolva, a felhasználókeresés visszaadja az engedélyezett időszakán kívül lévő, korlátozott hozzáférésű felhasználókat is. -search#:#search_sort_by#:#Sortation: %s###28 10 2024 new variable -search#:#search_sort_creation_date_asc#:#Oldest###28 10 2024 new variable -search#:#search_sort_creation_date_desc#:#Latest###28 10 2024 new variable -search#:#search_sort_generic_asc#:#%s, asc.###28 10 2024 new variable -search#:#search_sort_generic_desc#:#%s, desc.###28 10 2024 new variable -search#:#search_sort_relevance#:#By Relevance###28 10 2024 new variable -search#:#search_sort_title_asc#:#Alphabetically: A-Z###28 10 2024 new variable -search#:#search_sort_title_desc#:#Alphabetically: Z-A###28 10 2024 new variable +search#:#search_show_limited_user_info#:#A felhasználókeresés visszaadja az engedélyezett időszakán kívül lévő, korlátozott hozzáférésű felhasználókat is. +search#:#search_sort_by#:#Rendezés: +search#:#search_sort_creation_date_asc#:#Legidősebb +search#:#search_sort_creation_date_desc#:#Legutolsó +search#:#search_sort_generic_asc#:#%s ↑ +search#:#search_sort_generic_desc#:#%s ↓ +search#:#search_sort_relevance#:#Relevanca szerint +search#:#search_sort_title_asc#:#Betűrendben: A-Z +search#:#search_sort_title_desc#:#Betűrendben: Z-A search#:#search_term_combination#:#Kombináció search#:#search_title_description#:#Cím / Leírás search#:#search_tst_svy#:#Tesztek/Kérdőívek search#:#search_type#:#Keresési típus search#:#search_user#:#Felhasználók search#:#search_user_extended#:#Részletes felhasználókeresés -search#:#search_user_search_form#:#Felhasználói profilokban keresés -search#:#search_user_search_info_form#:#A felhasználói profilok adatai indexeltek és a felhasználók számára kereshetőek. +search#:#search_user_search_form#:#Globális felhasználókeresés +search#:#search_user_search_info_form#:#Felhasználókat találhat meg evvel a keresésssel. Amennyiben a Lucene fulltext keresést bekapcsolták, a felhasználói profilok adatai indexeltek és a felhasználók számára kereshetők. search#:#seas_search_type#:#Keresési típus search#:#select_orgu#:#Válasszon szervezeti egységeket search#:#until#:#eddig -search#:#user_search_settings_section#:#User Search in 'Member'-tabs###29 10 2025 new variable +search#:#user_search_settings_section#:#Felhasználók keresése a ‘Tagok’ lapon sess#:#il_sess_participant#:#Esemény résztvevői -sess#:#il_sess_status_open#:#Open Session###29 07 2022 new variable +sess#:#il_sess_status_open#:#Esemény megnyitása sess#:#mail_sess_roles#:#Levél küldése az esemény szerepeinek sess#:#notification#:#Értesítés sess#:#objs_crs_role#:#Kurzusszabályok sess#:#objs_grp_role#:#Csoportszabályok sess#:#send_mail_participants#:#Az esemény összes résztvevője -sess#:#sess_accept_request#:#Résztvétel elfogadása +sess#:#sess_accept_request#:#Részvétel elfogadása sess#:#sess_assign#:#Hozzárendelés -sess#:#sess_bt_refuse#:#Nem vehet részt -sess#:#sess_change_type#:#Change Session Type###29 07 2022 new variable +sess#:#sess_bt_refuse#:#Részvétel lemondása +sess#:#sess_change_type#:#Munkamenettípus módosítása sess#:#sess_contact#:#Kapcsolat sess#:#sess_copy#:#Esemény másolása sess#:#sess_filter_all_types#:#Összes típus sess#:#sess_filter_not_assigned#:#Nincs hozzárendelve sess#:#sess_import#:#Esemény importálása -sess#:#sess_info_new_sess_type#:#New Session Type###29 07 2022 new variable +sess#:#sess_info_new_sess_type#:#Új munkamenettípus sess#:#sess_is_assigned#:#hozzá van rendelve sess#:#sess_list_reg_limit_places#:#Szabad helyek sess#:#sess_lp_preset#:#Tanulási haladás bekapcsolása sess#:#sess_lp_preset_info#:#Tanulási haladás bekapcsolása az összes létrehozandó eseményre. sess#:#sess_mail_admins_only#:#Csak a vezetők -sess#:#sess_mail_admins_only_info#:#Csak a vezetők használhatják a ‘Résztvevők’ fül alatt lévő ‘Levél a résztvevőknek’ funkciót. +sess#:#sess_mail_admins_only_info#:#Csak a vezetők használhatják a ‘Résztvevők’ lapon lévő ‘Levél a résztvevőknek’ funkciót. sess#:#sess_mail_all#:#Az összes résztvevő -sess#:#sess_mail_all_info#:#Az összes résztvevő használhatja a ‘Résztvevők’ fül alatt lévő ‘Levél a résztvevőknek’ funkciót. +sess#:#sess_mail_all_info#:#Az összes résztvevő használhatja a ‘Résztvevők’ lapon lévő ‘Levél a résztvevőknek’ funkciót. sess#:#sess_mail_context_participant_info#:#Levél a résztvevőknek az esemény résztvevőiről és a tanulási haladásuk állásáról sess#:#sess_mail_context_participant_title#:#Esemény: levél a résztvevőknek sess#:#sess_mail_permanent_link#:#Az alábbi linkre kattintva talál információkat az eseményről: sess#:#sess_mail_permanent_link_participants#:#Az alábbi linkre kattintva módosíthatja az esemény résztvevőit: -sess#:#sess_mail_sub_acc_bod#:#'%s' eseményre sikerrel regisztrált. -sess#:#sess_mail_sub_acc_sub#:#'%s' eseményre regisztráció -sess#:#sess_mail_sub_dec_bod#:#'%s' eseményre regisztrációját elutasították. -sess#:#sess_mail_sub_dec_sub#:#'%s' eseményre sikertelen regisztráció +sess#:#sess_mail_sub_acc_bod#:#‘%s’ eseményre sikerrel regisztrált. +sess#:#sess_mail_sub_acc_sub#:#‘%s’ eseményre regisztráció +sess#:#sess_mail_sub_dec_bod#:#‘%s’ eseményre regisztrációját elutasították. +sess#:#sess_mail_sub_dec_sub#:#‘%s’ eseményre sikertelen regisztráció sess#:#sess_mail_type#:#Levél a résztvevőknek sess#:#sess_material_assigned#:#Hozzárendelve sess#:#sess_material_not_assigned#:#Nincs hozzárendelve sess#:#sess_max_members_needed#:#A várólista bekapcsolásához maximális tagszám beállítása szükséges. sess#:#sess_mem_contacts#:#Tutori támogatás -sess#:#sess_mem_send_mail#:#Send Mail###26 08 2024 new variable +sess#:#sess_mem_send_mail#:#E-mail küldése sess#:#sess_mem_tbl_header#:#Esemény résztvevői sess#:#sess_member_administration#:#Résztvevők módosítása sess#:#sess_members#:#Résztvevők @@ -15608,7 +15701,7 @@ sess#:#sess_notification_option#:#Lehetőség sess#:#sess_notification_option_inherit#:#Öröklés a szülőtől sess#:#sess_notification_option_inherit_info#:#Az esemény tagjainál a szülőobjektum értesítési beállításainak használata (például kurzus vagy csoport értesítési beállításai) sess#:#sess_notification_option_manual#:#Kézi beállítás -sess#:#sess_notification_option_manual_info#:#A 'Résztvevők' fül alatt a résztvevők értesítései beállításait kézzel kell megadni +sess#:#sess_notification_option_manual_info#:#A ‘Résztvevők’ lapon a résztvevők értesítései beállításait kézzel kell megadni sess#:#sess_open#:#Időpont megnyitása sess#:#sess_part_filter_participated#:#Csak résztvettek sess#:#sess_part_filter_registered#:#Csak regisztráltak @@ -15616,78 +15709,78 @@ sess#:#sess_part_table_excused#:#Elutasítva sess#:#sess_participation_refused_info#:#A jelentkezését elutasították erre az eseményre. sess#:#sess_print_list#:#Lista létrehozása sess#:#sess_reg_added_to_wl#:#Várólistára került. -sess#:#sess_reg_cannot_participate#:#Résztvétel lemondása +sess#:#sess_reg_cannot_participate#:#Részvétel lemondása sess#:#sess_reg_cannot_participate_info#:#A felhasználók lemondhatják részvételüket. sess#:#sess_reg_direct#:#Közvetlen jelentkezés -sess#:#sess_reg_direct_info#:#A felhasználó a 'Feljelentkezés' gombra kattintva jelentkezhet az eseményre +sess#:#sess_reg_direct_info#:#A felhasználó a ‘Feljelentkezés’ gombra kattintva jelentkezhet az eseményre sess#:#sess_reg_disabled#:#Regisztráció nélküli -sess#:#sess_reg_disabled_info#:#A résztvétel regisztrációmentes ezen az eseményen. +sess#:#sess_reg_disabled_info#:#A részvétel regisztrációmentes ezen az eseményen. sess#:#sess_reg_max_members#:#Tagok számának korlátozása sess#:#sess_reg_max_members_info#:#Ezen az eseményen résztvevők maximális számnak meghatározása. sess#:#sess_reg_max_members_short#:#Tagok száma sess#:#sess_reg_max_users_exceeded#:#Regisztráció nem lehetséges, mert elérte a maximális felhasználószámot. sess#:#sess_reg_max_users_exceeded_wl#:#A találkozó elérte a maximálisan megengedett létszámot. sess#:#sess_reg_request#:#Jelentkezés jóváhagyása -sess#:#sess_reg_request_info#:#A résztvételhez egy vezetőnek jóvá kell hagynia minden érdeklődő felhasználó jelentkezését. +sess#:#sess_reg_request_info#:#A részvételhez egy vezetőnek jóvá kell hagynia minden érdeklődő felhasználó jelentkezését. sess#:#sess_reg_tutor#:#Nincs felhasználói regisztráció sess#:#sess_reg_tutor_info#:#Csak vezetők regisztálhatják a felhasználókat erre az eseményre, a felhasználók saját magukat nem. sess#:#sess_reg_type#:#Regisztráció módja sess#:#sess_reg_waiting_list#:#Várólista sess#:#sess_reg_waiting_list_autofill#:#Automatikus feltöltéssel -sess#:#sess_reg_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról lemondás esetén. Ez nem alkalmazható együtt a 'Jelentkezés jóváhagyása' regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. +sess#:#sess_reg_waiting_list_autofill_info#:#A résztvevőket automatikusan felvesszük a várólistáról lemondás esetén. Ez nem alkalmazható együtt a ‘Jelentkezés jóváhagyása’ regisztrációs eljárással, mert az automatikus felvétel kizárja a jóváhagyást. sess#:#sess_reg_waiting_list_no_autofill#:#Automatikus feltöltés nélkül sess#:#sess_reg_waiting_list_no_autofill_info#:#A maximális szám elérése után a jelentkezők várólistára kerülnek. sess#:#sess_reg_waiting_list_none#:#Egyik sem sess#:#sess_registered_confirm#:#A regisztrációhoz vezetői jóváhagyás szükséges. A regisztrációs folyamat eredményéről értesítést fog kapni. sess#:#sess_registration_notification#:#Értesítés -sess#:#sess_registration_notification_info#:#Egy oszlop megjelenítése a 'Résztvevők' fül alatt, ahol az új vagy távozó résztvevőkről értesítendő személyeket ki lehet választani +sess#:#sess_registration_notification_info#:#Egy oszlop megjelenítése a ‘Résztvevők’ lap alatt, ahol az új vagy távozó résztvevőkről értesítendő személyeket ki lehet választani sess#:#sess_section_reg#:#Regisztrációs beállítások sess#:#sess_setting_header_presentation#:#Megjelenítés sess#:#sess_show_members#:#Résztvevők megjelenítése -sess#:#sess_show_participants_info#:#Ha be van kapcsolva, az esemény résztvevői megtekinthetik a résztvevők képgalériáját +sess#:#sess_show_participants_info#:#Az esemény résztvevői megtekinthetik a résztvevők képgalériáját sess#:#sess_title#:#Esemény címe sess#:#sess_users_added#:#Az eseményre a kiválasztott felhasználót regisztrálta. sess#:#sess_users_already_assigned#:#A felhasználó már regisztrált erre az eseményre. sess#:#sess_users_removed_from_list#:#A kiválasztott jelentkező(ke)t sikeresen eltávolított a várólistáról. -sess#:#sess_warn_sess_type_changed#:#Do you really want to change the session type? All permission settings will be reset.###29 07 2022 new variable -shib#:#shib_account_creation#:#Account Creation###28 10 2024 new variable -shib#:#shib_account_creation_disabled#:#Disabled###28 10 2024 new variable -shib#:#shib_account_creation_disabled_info#:#No new account is created.###28 10 2024 new variable -shib#:#shib_account_creation_enabled#:#Enabled###28 10 2024 new variable -shib#:#shib_account_creation_enabled_info#:#An active new account is created.###28 10 2024 new variable -shib#:#shib_account_creation_info#:#Account creation is triggered, when a user without a pre-existing ILIAS Account tries to log in via Shibboleth.###28 10 2024 new variable -shib#:#shib_account_creation_with_approval#:#With approval###28 10 2024 new variable -shib#:#shib_account_creation_with_approval_info#:#An inactive new account is created. The account remains inactive until activated by an administrator.###28 10 2024 new variable -shib#:#shib_add_missing#:#Hiányzó szerepek összerendelése -shib#:#shib_add_remove#:#Szerepek létrehozása/eltávolítása +sess#:#sess_warn_sess_type_changed#:#Biztos, hogy megváltoztatja a munkamenet típusát? Az összes jogosultságot alapértelmezettre állítjuk. +shib#:#shib_account_creation#:#ILIAS-fiók létrehozása +shib#:#shib_account_creation_disabled#:#Kikapcsolva +shib#:#shib_account_creation_disabled_info#:#Egy új ILIAS-fiókot sem hoztunk létre +shib#:#shib_account_creation_enabled#:#Bekapcsolva +shib#:#shib_account_creation_enabled_info#:#Egy új ILIAS-fiókot hoztunk létre. +shib#:#shib_account_creation_info#:#Az ILIAS-fiók akkor jön létre, amikor egy felhasználó még nem létező ILIAS-fiókba próbál bejelentkezni Shibboleth-en keresztül. +shib#:#shib_account_creation_with_approval#:#Jóváhagyással +shib#:#shib_account_creation_with_approval_info#:#Egy új, inkatív ILIAS-fiókot hoztunk létre. A felhasználót megfelelő jogosultsággal lehet aktiválni. +shib#:#shib_add_missing#:#Hiányzó szerepkörök összerendelése +shib#:#shib_add_remove#:#Szerepkörök létrehozása/eltávolítása shib#:#shib_assignment_type#:#Összerendelés fajtája shib#:#shib_attr_info#:#A Shibboleth felhasználói profilban egy adott tulajdonsággal összerendelve. shib#:#shib_attribute#:#Felhasználói tulajdonság shib#:#shib_attribute_name#:#Tulajdonságnév shib#:#shib_attribute_value#:#Tulajdonságérték -shib#:#shib_check_role_assignment#:#Későbbi bejelentkezések utáni szerepek összerendelése -shib#:#shib_choose_role#:#Szerep választása +shib#:#shib_check_role_assignment#:#Későbbi bejelentkezések utáni szerepkörök összerendelése +shib#:#shib_choose_role#:#Szerepkör választása shib#:#shib_confirm_del_role_ass#:#Biztos, hogy törli az alábbi szabályokat? shib#:#shib_deleted_rule#:#Szerep-összerendeléseket sikeresen törölte. -shib#:#shib_global_role#:#Globális szerep +shib#:#shib_global_role#:#Globális szerepkör shib#:#shib_ilias_role#:#ILIAS-szerepnév -shib#:#shib_local_role#:#Lokális szerep +shib#:#shib_local_role#:#Lokális szerepkör shib#:#shib_missing_attr_name#:#Adja meg a tulajdonság nevét! shib#:#shib_missing_attr_value#:#Adja meg a tulajdonság értékét! shib#:#shib_missing_plugin_id#:#Érvényes bővítmény-azonosítót adjon meg! -shib#:#shib_missing_role#:#Válasszon egy szerepet! +shib#:#shib_missing_role#:#Válasszon egy szerepkört! shib#:#shib_new_rule#:#Új szabály létrehozása shib#:#shib_plugin#:#Összerendelés bővítménnyel shib#:#shib_plugin_id#:#Bővítmény-azonosító shib#:#shib_plugin_info#:#Szerep-összerendelés érvényesítése bővítménnyel. Adjon meg egy valós bővítmény-azonosítót. -shib#:#shib_remove_deprecated#:#Érvénytelen szerepek összerendelésének megszüntetése +shib#:#shib_remove_deprecated#:#Érvénytelen szerepkörök összerendelésének megszüntetése shib#:#shib_role_ass_table#:#Új szabály a szerep-összerendelésekhez shib#:#shib_role_assignment#:#Szerep-összerendelés shib#:#shib_role_by_attribute#:#Shibboleth-tulajdonság shib#:#shib_role_by_plugin#:#Bővítménnyel -shib#:#shib_role_name#:#ILIAS-szerepnév -shib#:#shib_role_name_info#:#Válasszon egy globális szerepet, vagy adja meg egy helyi szerep nevét! -shib#:#shib_role_selection#:#Szerepkiválasztás +shib#:#shib_role_name#:#ILIAS-szerepkör néve +shib#:#shib_role_name_info#:#Válasszon egy globális szerepkört, vagy adja meg egy helyi szerepkör nevét! +shib#:#shib_role_selection#:#Szerepkör kiválasztása shib#:#shib_rule_condition#:#Feltétel shib#:#shib_rule_type#:#Összerendelés típusa shib#:#shib_rules_tables#:#Aktív szerep-összerendelés szabályai @@ -15697,57 +15790,57 @@ shib#:#shib_update_roles#:#Szerep-összerendelések skll#:#skll_competence_achievements#:#Új kompetenciaeredmények és -értékelések. skll#:#skll_intro_skill_notification_for#:#Ez az Ön utolsó kompetenciaeredményeinek áttekintése. skll#:#skll_lhist_skill_achieved#:#$4$ / $3$ állapot ért el $1$ alatt. -skll#:#skll_lhist_skill_profile_fulfilled#:#Competence Profile $3$ was fulfilled.###29 07 2022 new variable +skll#:#skll_lhist_skill_profile_fulfilled#:#$3$ kompetenciaprofil teljesült. skll#:#skll_lhist_skill_self_eval#:#$3$ önértékelés, összesen $4$. skll#:#skll_lhist_skill_self_eval_in#:#$3$ önértékelés, összesen $4$, itt: $1$. skll#:#skll_new_skill_achievements#:#Új kompetenciaszinteket ért el %1$s - %2$s időszakban: skll#:#skll_skill_notification#:#Kompetenciaértesítések skll#:#skll_skill_notification_desc#:#Felhasználó értesítése új kompetenciaszint beállításáról. skmg#:#scat#:#Kompetenciakategória -skmg#:#skll#:#Alapkompetencia +skmg#:#skll#:#Kompetencia skmg#:#skmg_360_survey#:#360°-os kérdőív -skmg#:#skmg_add_assignment#:#Szerepek / felhasználók hozzáadása +skmg#:#skmg_add_assignment#:#Szerepkörök / felhasználók hozzáadása skmg#:#skmg_add_level#:#Kompetenciaszint létrehozása skmg#:#skmg_add_local_profile#:#Helyi profil hozzáadása skmg#:#skmg_add_profile#:#Profil hozzáadása -skmg#:#skmg_add_resource#:#Erőforrás hozzáadása +skmg#:#skmg_add_resource#:#ILIAS-objektum hozzárendelés skmg#:#skmg_add_skill#:#Kompetencia létrehozása -skmg#:#skmg_add_skill_tree#:#Add Competence Tree###29 07 2022 new variable -skmg#:#skmg_add_user_to_profile#:#Szerepek vagy felhasználók hozzáadása a profilhoz +skmg#:#skmg_add_skill_tree#:#Kompetencia-fa hozzáadása +skmg#:#skmg_add_user_to_profile#:#Szerepkörök vagy felhasználók hozzáadása a profilhoz skmg#:#skmg_all#:#Összes skmg#:#skmg_allow_local_profiles#:#Helyi profilok létrehozásának engedélyezése -skmg#:#skmg_allow_local_profiles_info#:#A 'Beállítások módosítása' jogosultsággal rendelkezők kurzusokban és csoportokban létrehozhatnak helyi kompetenciaprofilokat globálisan létrehozott kompetenciák felhasználásával. +skmg#:#skmg_allow_local_profiles_info#:#A ‘Beállítások módosítása’ jogosultsággal rendelkezők kurzusokban és csoportokban létrehozhatnak helyi kompetenciaprofilokat globálisan létrehozott kompetenciák felhasználásával. skmg#:#skmg_ass_materials_from_workspace#:#Itt rendelhet hozzá anyagokat, például fájlokat a személyes erőforrásaiból a kompetenciaszintekhez. Ha most szeretne anyagokat hozzáadni a személyes erőforrásaihoz, kattintson az alábbi linkre. skmg#:#skmg_assign_level#:#Szint hozzárendelése -skmg#:#skmg_assign_materials#:#Anyagok hozzárendelése +skmg#:#skmg_assign_materials#:#Személyes erőforrások hozzárendelése skmg#:#skmg_assign_user#:#Felhasználó hozzárendelése skmg#:#skmg_assigned_objects#:#Hozzárendelt objektumok -skmg#:#skmg_assigned_profiles#:#Hozzárendelt profilok -skmg#:#skmg_assigned_skill_levels#:#Hozzárendelt kompetenciaszintek -skmg#:#skmg_assigned_users#:#Hozzárendelt szerepek és felhasználók -skmg#:#skmg_bar_charts#:#Bar Charts###26 08 2024 new variable +skmg#:#skmg_assigned_profiles#:#Hozzárendelt kompetenciaprofilok +skmg#:#skmg_assigned_skill_levels#:#Hozzárendelt célszintek +skmg#:#skmg_assigned_users#:#Hozzárendelt szerepkörök és felhasználók +skmg#:#skmg_bar_charts#:#Oszlopdiagramok skmg#:#skmg_cannot_delete_nodes_in_use#:#Néhány elem nem törölhető, mert használatban van. skmg#:#skmg_cert_skill_level_title#:#Kompetenciaszint címe skmg#:#skmg_cert_skill_title#:#Kompetencia címe skmg#:#skmg_cert_skill_trigger_title#:#Kompetenciatrigger címe -skmg#:#skmg_confirm_level_resources_removal#:#Biztos, hogy törli az alábbi erőforrásokat a kompetenciaszintből? +skmg#:#skmg_confirm_level_resources_removal#:#Biztos, hogy törli az alábbi objektumokat a kompetenciaszintből? skmg#:#skmg_confirm_remove_level_ass#:#Biztos, hogy törli az alábbi kompetenciaszinteket a profilból? skmg#:#skmg_confirm_user_removal#:#Biztos, hogy törli az alábbi felhasználókat ebből a profilból? -skmg#:#skmg_cont_profiles_info#:#In this view, you can select the competence profiles with competence entries, which are related to the currently open object (course/group). To get to the global view with all competence profiles you are assigned to and all competence entries, click on the link below.###26 08 2024 new variable -skmg#:#skmg_cont_profiles_info_empty#:#There are no competence profiles related to the currently open object.###26 08 2024 new variable -skmg#:#skmg_cont_records_info_empty#:#There are no competences related to the currently opened object.###26 08 2024 new variable -skmg#:#skmg_context_global#:#Global -skmg#:#skmg_context_local#:#Local -skmg#:#skmg_count_references#:#Number of referenced competences:###26 08 2024 new variable +skmg#:#skmg_cont_profiles_info#:#Ebben a nézetben kiválaszthatja azokat a kompetencia-bejegyzéseket tartalmazó kompetencia profilokat, amelyek az éppen nyitott objektumhoz (kurzushoz/csoporthoz) kapcsolódnak. Az alábbi linkre kattintva elérheti az összes hozzárendelt kompetenciaprofil és az összes kompetencia-bejegyzés globális nézetét. +skmg#:#skmg_cont_profiles_info_empty#:#A jelenleg megnyitott objektumhoz egy kompetenciaprofil sincs hozzárendelve. +skmg#:#skmg_cont_records_info_empty#:#A jelenleg megnyitott objektumhoz egy kompetencia sincs hozzárendelve. +skmg#:#skmg_context_global#:#Globális +skmg#:#skmg_context_local#:#Helyi +skmg#:#skmg_count_references#:#A hivatkozott kompetenciák száma: skmg#:#skmg_create_sctp#:#Sablonkategória létrehozása skmg#:#skmg_create_skill_category#:#Kompetenciakategória létrehozása skmg#:#skmg_create_skill_template#:#Kompetenciasablon létrehozása skmg#:#skmg_create_skill_template_category#:#Kompetenciasablon-kategória létrehozása skmg#:#skmg_create_skill_template_reference#:#Kompetenciasablon-hivatkozás létrehozása skmg#:#skmg_create_skll#:#Kompetencia létrehozása -skmg#:#skmg_custom_image_alt#:#Custom image for competence profile###29 07 2022 new variable +skmg#:#skmg_custom_image_alt#:#Kompetenciaprofilokhoz egyéni kép skmg#:#skmg_delete_profiles#:#Biztos, hogy törli a következő profilokat? -skmg#:#skmg_delete_warning#:#Are you sure that you want to delete the following item(s)? When you delete the items, you also delete all usages, assignments and achievements of it. To be on the safe side, you find a list of all usages below. If the item is used in a competence profile, it will be removed from the profile, too. This may cause the fulfilment of the competence profile for the assigned users. If your are not sure whether an item should really be deleted, please use the statuses in the settings of a single item.###26 08 2024 new variable +skmg#:#skmg_delete_warning#:#Biztos, hogy törli a következő kompetenciákat, kompetencia-kategóriákat vagy kompetenciafákat? Ezzel törli az objektumok és felhasználók összes rekordját is. Ha az elemet eltávolítja egy kompetenciaprofilból, az azt eredményezheti, hogy a hozzárendelt felhasználók kompetenciaprofilja teljesül. Az alábbi lista azt mutatja, hogy a törlendő elemet hányszor használják objektumokban és felhasználók. Kérjük, a tényleges törlés előtt figyelmesen ellenőrizze az alábbi listát. skmg#:#skmg_description_info#:#A leírás a sablonból jön. skmg#:#skmg_edit_level#:#Szint módosítása skmg#:#skmg_edit_profile#:#Profil módosítása @@ -15759,17 +15852,17 @@ skmg#:#skmg_enable_skmg#:#Kompetenciamenedzsment bekapcsolása skmg#:#skmg_eval_type_1#:#Értékelés skmg#:#skmg_eval_type_2#:#Mérés skmg#:#skmg_eval_type_3#:#Önértékelés -skmg#:#skmg_eval_type_latest_1#:#Latest Appraisal###29 07 2022 new variable -skmg#:#skmg_eval_type_latest_2#:#Latest Measurement###29 07 2022 new variable -skmg#:#skmg_eval_type_latest_3#:#Latest Self-Evaluation###29 07 2022 new variable +skmg#:#skmg_eval_type_latest_1#:#Legutolsó értékelés +skmg#:#skmg_eval_type_latest_2#:#Legutolsó mérés +skmg#:#skmg_eval_type_latest_3#:#Legutolsó önértékelés skmg#:#skmg_execute_self_evaluation#:#Indítás -skmg#:#skmg_form_presentation#:#Presentation###29 07 2022 new variable +skmg#:#skmg_form_presentation#:#Presentation skmg#:#skmg_from_lower_to_higher_levels#:#Úgy rendezze a szinteket, hogy a legalacsonyabb felül, a legmagasabb pedig alul helyezkedjen el. -skmg#:#skmg_hide_profile_self_eval#:#Önértékelés nélküli profilok elrejtése -skmg#:#skmg_hide_profile_self_eval_info#:#A profilcél-érték nem jelenik meg a felhasználónak, amíg nem értékelte önmagát ebből a képességből. +skmg#:#skmg_hide_profile_self_eval#:#Önértékelés nélküli profil célszintjének elrejtése +skmg#:#skmg_hide_profile_self_eval_info#:#A profil célszintje nem jelenik meg a felhasználónak, amíg nem értékelte önmagát ebből a kompetenciából. skmg#:#skmg_import_skills#:#Importálás skmg#:#skmg_input_file#:#Importfájl -skmg#:#skmg_insert_basic_skill_from_clip#:#Alapkompetenciákat beillesztette a vágólapról +skmg#:#skmg_insert_basic_skill_from_clip#:#Kompetenciák beillesztése a vágólapról skmg#:#skmg_insert_please_choose_one_type_only#:#Csak azonos típusból objektumokat válasszon! skmg#:#skmg_insert_skill_category_from_clip#:#Kompetenciakategóriákat beillesztette a vágólapról skmg#:#skmg_insert_skill_template_from_clip#:#Kompetenciasablon-kategória beszúrása vágólapról @@ -15780,19 +15873,19 @@ skmg#:#skmg_level#:#Szint skmg#:#skmg_list_skills#:#Kompetenciák listája skmg#:#skmg_local_assignment_profiles#:#Globális profilok helyi hozzárendelésének engedélyzése skmg#:#skmg_lp_triggers_level#:#A befejezés hatására -skmg#:#skmg_materials#:#Segédanyagok -skmg#:#skmg_materials_resources#:#Learning Materials###26 08 2024 new variable +skmg#:#skmg_materials#:#Személyes erőforrások +skmg#:#skmg_materials_resources#:#Tanulási anyagok/segédanyagok skmg#:#skmg_new_level#:#Új szint skmg#:#skmg_new_sktr#:#Új kompetenciasablon-hivatkozás skmg#:#skmg_next_step#:#Következő lépés skmg#:#skmg_no_nodes_selectable#:#Jelenleg nincsenek választható kompetenciák. -skmg#:#skmg_no_skill_entries#:#You do not have any entries for this competence yet.###26 08 2024 new variable -skmg#:#skmg_no_skills_selected_info#:#You have not selected any competences yet. Click on the button "Add Competence" to select a competence and to see it here. You can add any number of competences.###29 07 2022 new variable +skmg#:#skmg_no_skill_entries#:#Ennek a kompetenciának még egy bejegyzése sincs. +skmg#:#skmg_no_skills_selected_info#:#Még nem választott ki és nem is teljesített egy kompetenciát sem. Egy kompetencia kiválasztásához kattintson a "Kompetencia hozzáadása" gombra. Tetszőlege számú kompetenciát hozzáadhat. Azokat a kompetenciákat automatikusan megjelenítjük, melyeket tanulási anyagokkal teljesített. skmg#:#skmg_no_trigger#:#Nincs trigger skmg#:#skmg_nr#:#Sorszám skmg#:#skmg_number#:#Szám -skmg#:#skmg_open#:#Open###26 08 2024 new variable -skmg#:#skmg_open_all_assigned_profiles#:#Open All Assigned Competence Profiles###26 08 2024 new variable +skmg#:#skmg_open#:#Megnyitás +skmg#:#skmg_open_all_assigned_profiles#:#Az összes hozzárendelt kompetenciaprofil megnyitása skmg#:#skmg_order#:#Sorrend skmg#:#skmg_order_nr#:#Sorszám skmg#:#skmg_order_nr_info#:#Kompetencia pozíciója a kompetenciák felsorolásában. @@ -15802,72 +15895,72 @@ skmg#:#skmg_previous_step#:#Előző lépés skmg#:#skmg_profile#:#Profil skmg#:#skmg_really_delete_levels#:#Biztos, hogy törli az alábbi kompetenciaszinteket? skmg#:#skmg_really_remove_skills#:#Biztos, hogy eltávolítja az alábbi kompetenciákat a listáról? -skmg#:#skmg_recommended_learning_material_crs#:#Achieve your targets in this course###26 08 2024 new variable -skmg#:#skmg_recommended_learning_material_global#:#Achieve your targets###26 08 2024 new variable -skmg#:#skmg_recommended_learning_material_grp#:#Achieve your targets in this group###26 08 2024 new variable -skmg#:#skmg_recommended_learning_material_info#:#Select exactly one of the following learning materials. Please work through it to achieve the competence target.###29 07 2022 new variable +skmg#:#skmg_recommended_learning_material_crs#:#Érje el céljait a kurzusban +skmg#:#skmg_recommended_learning_material_global#:#Érje el céljait +skmg#:#skmg_recommended_learning_material_grp#:#Érje el céljait a csoportban +skmg#:#skmg_recommended_learning_material_info#:#Pontosan egy tanulási (segéd)anyagot válasszon. Dolgozza fel annak tartalmát a célszint eléréséhez. skmg#:#skmg_refresh_view#:#Frissítés -skmg#:#skmg_remove#:#Remove###26 08 2024 new variable +skmg#:#skmg_remove#:#Eltávolítás skmg#:#skmg_remove_levels#:#Szintek eltávolítása skmg#:#skmg_remove_skill#:#Kompetencia eltávolítása skmg#:#skmg_remove_trigger#:#Trigger eltávolítása -skmg#:#skmg_resources#:#Erőforrások +skmg#:#skmg_resources#:#ILIAS-objektumok skmg#:#skmg_save_order#:#Sorrend mentése skmg#:#skmg_save_self_evaluation#:#Önértékelés befejezése skmg#:#skmg_save_settings#:#Beállítások mentése skmg#:#skmg_sctp#:#Kompetenciasablon-kategória -skmg#:#skmg_select_level#:#Select Competence Level###26 08 2024 new variable +skmg#:#skmg_select_level#:#Kompetenciaszint kiválasztása skmg#:#skmg_select_skill#:#Kattintson egy kompetenciára, hogy felvegye a személyes kompetenciái közé. -skmg#:#skmg_select_skill_level_assign#:#Válasszon egy szakismeret. +skmg#:#skmg_select_skill_level_assign#:#Válasszon egy kompetenciát. skmg#:#skmg_select_trigger#:#Trigger kiválasztása skmg#:#skmg_selectable#:#Kiválasztható skmg#:#skmg_selectable_info#:#Felhasználó személyes kompetenciaként választhatja ki ezt a kategóriát skmg#:#skmg_selected_items_have_been_copied#:#A kiválasztott objektumokat másolta. skmg#:#skmg_selected_items_have_been_cut#:#A kiválasztott objektumokat kivágta. -skmg#:#skmg_selected_skills#:#Kompetenciabejegyzések +skmg#:#skmg_selected_skills#:#Kiválasztott kompetenciák skmg#:#skmg_self_evaluation#:#Önértékelés -skmg#:#skmg_self_evaluation_byline#:#The self-evaluation will be excluded from target achievement. It is used for your guidance.###29 07 2022 new variable +skmg#:#skmg_self_evaluation_byline#:#Az önértékelést kizárjuk a cél eléréséből, az csak iránymutatásul szolgál. skmg#:#skmg_self_evaluations#:#Önértékelések -skmg#:#skmg_set_as_lp_trigger#:#Completion Should Trigger Competence Record###26 08 2024 new variable -skmg#:#skmg_set_as_no_lp_trigger#:#Completion Should Not Trigger Competence Record###26 08 2024 new variable -skmg#:#skmg_set_as_no_suggested#:#Do not Show as Learning Material###26 08 2024 new variable -skmg#:#skmg_set_as_suggested#:#Show as Learning Material###26 08 2024 new variable +skmg#:#skmg_set_as_lp_trigger#:#A teljesítés hozza létre a kompetenciabejegyzést +skmg#:#skmg_set_as_no_lp_trigger#:#A teljesítés nem hozza létre a kompetenciabejegyzést +skmg#:#skmg_set_as_no_suggested#:#Ne jelenjen meg mint tanulási segédanyag +skmg#:#skmg_set_as_suggested#:#Megjelenítés mint tanulási segédanyag skmg#:#skmg_settings#:#Kompetenciamenedzsment-beállítások -skmg#:#skmg_show_all#:#Show All###29 07 2022 new variable -skmg#:#skmg_show_latest_entries#:#Show Latest Entries###29 07 2022 new variable +skmg#:#skmg_show_all#:#Összes megjelenítése +skmg#:#skmg_show_latest_entries#:#Legújabb bejegyzések megjelenítése skmg#:#skmg_skill#:#Kompetencia skmg#:#skmg_skill_in_use#:#Ezt a kompetenciát másik felhasználó vagy tartalom használja, ezért nem minden művelet végezhető el rajta. Módosítása hatással lehet korábbi felhasználásaira. skmg#:#skmg_skill_level#:#Kompetenciaszint skmg#:#skmg_skill_level_trigger#:#Kompetenciaszint-trigger skmg#:#skmg_skill_levels#:#Kompetenciaszintek skmg#:#skmg_skill_management_deactivated#:#A kompetenciamenedzsment jelenleg ki van kapcsolva. -skmg#:#skmg_skill_needs_impr_no_res#:#Szükséges fejlesztenie ezt a kompetenciát. Sajnos jelenleg nincs olyan erőforrás, melyet tananyagként segítene a kívánt kompetenciaszint eléréséhez. -skmg#:#skmg_skill_needs_impr_res#:#Szükséges fejlesztenie ezt a kompetenciát. Az alábbi erőforrások biztosítanak tananyagot a kívánt kompetenciaszint eléréséhez. -skmg#:#skmg_skill_needs_self_eval#:#Please conduct a self-evaluation first to see your competence target. Please click on "Actions" for that.###29 07 2022 new variable -skmg#:#skmg_skill_needs_self_eval_box#:#Please note that you have not conducted a self-evaluation for at least one competence in this profile. You will not see the competence target for the affected competences until a self-evaluation is done.###29 07 2022 new variable -skmg#:#skmg_skill_no_needs_impr#:#A kompetencia szintje elegendő a kiválasztott profilhoz. -skmg#:#skmg_skill_no_needs_impr_info#:#You achieved the target for this competence.###29 07 2022 new variable -skmg#:#skmg_skill_overview#:#Overview###26 08 2024 new variable -skmg#:#skmg_skill_profile_records#:#Competence Records###26 08 2024 new variable -skmg#:#skmg_skill_profiles#:#Profilok +skmg#:#skmg_skill_needs_impr_no_res#:#Szükséges fejlesztenie ezt a kompetenciát. Sajnos jelenleg nem érhető el olyan (segéd)anyag, aminek feldogozásával a kívánt kompetenciaszintet elérhetné. +skmg#:#skmg_skill_needs_impr_res#:#Szükséges fejlesztenie ezt a kompetenciát. Az alábbi (segéd)anyagok feldolgozásával elérheti a kívánt kompetenciaszintet. +skmg#:#skmg_skill_needs_self_eval#:#Kérjük, először végezzen önértékelést, hogy lássa a célszintjét. +skmg#:#skmg_skill_needs_self_eval_box#:#Kérjük, vegye figyelembe, hogy ebben a profilban nem végzett önértékelést legalább egy kompetenciára vonatkozóan. Nem fogja látni az érintett kompetenciák célszintjét, amíg el nem készül az önértékelés. +skmg#:#skmg_skill_no_needs_impr#:#A célszintet elérte! +skmg#:#skmg_skill_no_needs_impr_info#:#Elérte a célt ebben a kompetenciában. +skmg#:#skmg_skill_overview#:#Áttekintés +skmg#:#skmg_skill_profile_records#:#Kompetencia-bejegyzések +skmg#:#skmg_skill_profiles#:#Kompetenciaprofilok skmg#:#skmg_skill_template#:#Kompetenciasablon skmg#:#skmg_skill_templates#:#Kompetenciasablonok -skmg#:#skmg_skill_tree#:#Competence Tree###29 07 2022 new variable -skmg#:#skmg_skill_trees#:#Competence Trees###29 07 2022 new variable +skmg#:#skmg_skill_tree#:#Kompetencia-fa +skmg#:#skmg_skill_trees#:#Kompetencia-fák skmg#:#skmg_skills#:#Kompetenciák skmg#:#skmg_sktr#:#Kompetenciasablon-hivatkozás skmg#:#skmg_status#:#Állapot skmg#:#skmg_status_draft#:#Tervezet (Offline) skmg#:#skmg_status_draft_info#:#Az elem rejtett lesz. skmg#:#skmg_status_outdated#:#Lejárt -skmg#:#skmg_status_outdated_info#:#A felhasználók nem választhatják újólag az elemet, mint személyes készség, vagy újólag nem rendelhetik ILIAS-objektumhoz vagy kompetenciaprofilokhoz. Azonban a meglévő hozzárendelések és adatok továbbra is jelen vannak. +skmg#:#skmg_status_outdated_info#:#A felhasználók nem választhatják újólag az elemet, mint személyes kompetencia, vagy újólag nem rendelhetik ILIAS-objektumhoz vagy kompetenciaprofilokhoz. Azonban a meglévő hozzárendelések és adatok továbbra is jelen vannak. skmg#:#skmg_status_publish#:#Közzétéve -skmg#:#skmg_status_publish_info#:#Az elemet nem lehet használni, ha az összes szülője is közzé van téve. Amennyiben az elemek használatban vannak, állapotuk nem állítható többé 'Vázlat'-ra, és nem is törölhetőek. -skmg#:#skmg_suggested#:#Javasolt erőforrások -skmg#:#skmg_suggested_resources#:#Ajánlott erőforrások +skmg#:#skmg_status_publish_info#:#Az elemet akkor is lehet használni, ha az összes szülője közzé van téve. +skmg#:#skmg_suggested#:#Megjelenítés tanulási (segéd)anyagként +skmg#:#skmg_suggested_resources#:#Hozzárendelt ILIAS-objektumok skmg#:#skmg_sure_delete_self_evaluation#:#Biztos, hogy törli az alábbi önértékeléseket? -skmg#:#skmg_target_level#:#Profil célszint -skmg#:#skmg_target_levels#:#Competence Targets###29 07 2022 new variable +skmg#:#skmg_target_level#:#Célszint +skmg#:#skmg_target_levels#:#Célszintek skmg#:#skmg_trigger#:#Trigger skmg#:#skmg_type#:#Típus skmg#:#skmg_type_of_formation#:#Típus @@ -15877,59 +15970,59 @@ skmg#:#skmg_usage_obj_objects#:#Objektum(ok) skmg#:#skmg_usage_obj_profiles#:#Profil(ok) skmg#:#skmg_usage_obj_users#:#Felhasználó(k) skmg#:#skmg_usage_type_info_gen#:#Általános használatra a ILIAS-objektumokban -skmg#:#skmg_usage_type_info_mat#:#A felhasználók segédanyagakat rendelhetnek a személyes erőforrásaiból -skmg#:#skmg_usage_type_info_pers#:#A felhasználók kiválaszthatják, mint személyes készség +skmg#:#skmg_usage_type_info_mat#:#A felhasználók (segéd)anyagakat rendeltek a személyes munkaterületükről +skmg#:#skmg_usage_type_info_pers#:#A felhasználók kiválaszthatják, mint személyes kompetencia skmg#:#skmg_usage_type_info_prof#:#Kompetenciaprofilokban felhasználásra -skmg#:#skmg_usage_type_info_res#:#ILIAS-objektumok hozzárendelése javasolt erőforrásként +skmg#:#skmg_usage_type_info_res#:#ILIAS-objektumok hozzárendelése tanulási (segéd)anyagként skmg#:#skmg_usage_type_info_user#:#Felhasználókhoz rendelve skmg#:#skmg_your_self_evaluation#:#Az Ön önértékelése -stus#:#stus_action_delete#:#Delete###29 10 2025 new variable -stus#:#stus_action_edit#:#Edit###29 10 2025 new variable -stus#:#stus_action_toggle#:#Activate/Deactivate###29 10 2025 new variable -stus#:#stus_active#:#Active###29 10 2025 new variable -stus#:#stus_alias#:#Shortlink###29 10 2025 new variable -stus#:#stus_alias_already_exists#:#The shortlink is already taken. Please choose another one.###29 10 2025 new variable -stus#:#stus_alias_invalid#:#The shortlink contains invalid characters. Permitted characters: A-Z, a-z, 0-9, - and _###29 10 2025 new variable -stus#:#stus_confirm_delete#:#Delete entries###29 10 2025 new variable -stus#:#stus_create_shortlink#:#Create shortlink###29 10 2025 new variable -stus#:#stus_delete#:#Delete###29 10 2025 new variable -stus#:#stus_delete_shortlink#:#Delete###29 10 2025 new variable -stus#:#stus_delete_shortlink_msg#:#Shortlink deleted###29 10 2025 new variable -stus#:#stus_index#:#Manage###29 10 2025 new variable -stus#:#stus_info#:#Information###29 10 2025 new variable -stus#:#stus_info_active#:#Inactive shortlinks are not redirected when called up.###29 10 2025 new variable -stus#:#stus_info_alias#:#May only contain the following characters: A-Z, a-z, 0-9, - und _###29 10 2025 new variable -stus#:#stus_info_target_ref_id#:#Target object###29 10 2025 new variable -stus#:#stus_order_saved#:#Order saved###29 10 2025 new variable -stus#:#stus_prefix#:#Prefix###29 10 2025 new variable -stus#:#stus_rbac_permissions#:#Permissions###29 10 2025 new variable -stus#:#stus_shortlink#:#Shortlink###29 10 2025 new variable -stus#:#stus_shortlinks#:#Shortlinks###29 10 2025 new variable -stus#:#stus_shortlinks_deleted#:#Shortlinks have been deleted###29 10 2025 new variable -stus#:#stus_shortlinks_toggled#:#Shortlinks have been deactivated/activated###29 10 2025 new variable -stus#:#stus_stus_stored_sucessfully#:#Shortlink successfully saved###29 10 2025 new variable -stus#:#stus_stus_toggle#:#Deactivate/Activate###29 10 2025 new variable -stus#:#stus_target_link#:#Target object###29 10 2025 new variable -stus#:#stus_target_ref_id#:#Target object###29 10 2025 new variable -stus#:#stus_target_ref_id_required#:#Select a target object.###29 10 2025 new variable -stus#:#stus_toggle#:#Deactivate/Activate###29 10 2025 new variable -stus#:#stus_toggle_shortlink#:#Change status###29 10 2025 new variable -stus#:#stus_toggle_shortlink_msg#:#Would you like to change the active status of the following entries?###29 10 2025 new variable +stus#:#stus_action_delete#:#Törlés +stus#:#stus_action_edit#:#Módosítás +stus#:#stus_action_toggle#:#Ki-/Bekapcsolás +stus#:#stus_active#:#Aktív +stus#:#stus_alias#:#Gyorslink +stus#:#stus_alias_already_exists#:#Ez a gyorslink már foglalt, válasszon másikat. +stus#:#stus_alias_invalid#:#A gyorslink érvénytelen karaktereket tartalmaz. Engedélyezett karakterek: A-Z, a-z, 0-9, - és _ +stus#:#stus_confirm_delete#:#Bejegyzések törlése +stus#:#stus_create_shortlink#:#Gyorslink létrehozása +stus#:#stus_delete#:#Törlés +stus#:#stus_delete_shortlink#:#Törlés +stus#:#stus_delete_shortlink_msg#:#A gyorslinkeket sikeresen törölte. +stus#:#stus_index#:#Kezelés +stus#:#stus_info#:#Információ +stus#:#stus_info_active#:#Az inaktív gyorslinkeket nem irányítjuk át meghíváskor +stus#:#stus_info_alias#:#Engedélyezett karakterek: A-Z, a-z, 0-9, - és _ +stus#:#stus_info_target_ref_id#:#Célobjektum +stus#:#stus_order_saved#:#A sorrendet sikeresen mentette. +stus#:#stus_prefix#:#Előtag +stus#:#stus_rbac_permissions#:#Jogosultságok +stus#:#stus_shortlink#:#Gyorslink +stus#:#stus_shortlinks#:#Gyorslinkek +stus#:#stus_shortlinks_deleted#:#A gyorslinkeket sikeresen törölte. +stus#:#stus_shortlinks_toggled#:#A gyorslinkeket sikeresen be-/kikapcsolta. +stus#:#stus_stus_stored_sucessfully#:#A gyorslinkeket sikeresen mentette. +stus#:#stus_stus_toggle#:#Ki-/Bekapcsolás +stus#:#stus_target_link#:#Célobjektum +stus#:#stus_target_ref_id#:#Célobjektum +stus#:#stus_target_ref_id_required#:#Válasszon egy célobjektumot. +stus#:#stus_toggle#:#Ki-/Bekapcsolás +stus#:#stus_toggle_shortlink#:#Állapot módosítása +stus#:#stus_toggle_shortlink_msg#:#Biztos, hogy módosítja a következő bejegyzések állapotát? style#:#Style#:#Stílus style#:#adapt_icon#:#Ikon átvétele style#:#adapt_icon_description#:#Ikonszínek átvétele vagy az ikon módosítása. style#:#adapt_icons#:#Ikonszínek átalakítása style#:#adapt_icons_description#:#A skin-ek képek mappájában lévő összes svg ikont felsoroljuk itt. Ha egy színt módosít, az az összes, azt a színt tartalmazó ikonban is módosul. -style#:#adapt_scss#:#Adapt scss###26 08 2024 new variable -style#:#adapt_scss_description#:#This is a direct representation of all scss variables from the settings files used in the selected skin. Variable names and descriptions are drawn directly from those files and are therefore only available in their original language. The selected style will be recompiled completely by updating/reseting the variables. Resetting variables will create a copy of the default delos style.###26 08 2024 new variable +style#:#adapt_scss#:#Az scss adaptálása +style#:#adapt_scss_description#:#Ez a kiválasztott skinen használt beállítások fájljaiból származó összes scss-változó közvetlen ábrázolása. A változók nevei és leírásai közvetlenül ezekből a fájlokból származnak, ezért csak az eredeti nyelvükön érhetők el. A kiválasztott stílust a rendszer a változók frissítésével/visszaállításával teljesen újrafordítja. A változók visszaállítása létrehozza az alapértelmezett delos stílus másolatát. style#:#add_substyle#:#Alstílus létrehozása style#:#add_system_style#:#Rendszerstílus létrehozása style#:#assignment#:#Hozzárendelés style#:#blue_color#:#Kék szín style#:#blue_colors#:#Kék színek style#:#blue_colors_description#:#Kék szín leírása -style#:#can_not_read_scss_file#:#Cannot read scss file. Path:###26 08 2024 new variable -style#:#cant_deactivate_default_style#:#Alapértelmezett stílusok nem kapcsolhatóak ki. +style#:#can_not_read_scss_file#:#Az scss fájl nem olvasható. Útvonala: +style#:#cant_deactivate_default_style#:#Alapértelmezett stílusok nem kapcsolhatók ki. style#:#cant_delete_activated_style#:#Aktív stílus nem törölhető. style#:#cant_delete_if_users_assigned#:#Azok a stílusok nem törölhetőek, melyekhez felhasználó van rendelve. style#:#cant_delete_style_with_substyles#:#Stílusok alstílusokkal nem törölhető. @@ -15940,11 +16033,11 @@ style#:#color_changed_to#:#erre: style#:#color_reset#:#Az ikonok színeit alapértelmezettre állította. Fontos: a gyorsítótárazás megakadályozhatja a változások megjelenítését, szükséges lehet a böngésző gyorsítótárának ürítése. style#:#color_update#:#Az ikonok színeit sikeresen frissítette. Fontos: a gyorsítótárazás megakadályozhatja a változások megjelenítését, szükséges lehet a böngésző gyorsítótárának ürítése. style#:#default_style_set_to#:#Az alapértelmezett rendszerstílusa mostantól: -style#:#dir_changed_to#:#The directory has been moved to:###26 08 2024 new variable +style#:#dir_changed_to#:#A mappát sikeresen áthelyezte: style#:#dir_copied_from#:#A mappát innen másolta: -style#:#dir_created#:#The following directory has been created:###26 08 2024 new variable +style#:#dir_created#:#A mappát sikeresen létrehozta: style#:#dir_deleted#:#Az alábbi mappát sikeresen törölte: -style#:#dir_preserved_backup#:#Preserved Backup folder:###26 08 2024 new variable +style#:#dir_preserved_backup#:#Lefoglalt Biztonsági mentés mappa: style#:#dir_preserved_linked#:#Lefoglalt link: style#:#directory_created#:#Mappa létrejött: style#:#documentation#:#Dokumentáció @@ -15954,7 +16047,7 @@ style#:#enable_system_styles_management_no_write_perm#:#Bár a Rendszerstílusok style#:#entries_reloaded#:#Az összes bejegyzést sikeresen újratöltötte. style#:#file_deleted#:#A következő fájlt töröltük: style#:#font_dir#:#Betűtípusok mappája -style#:#font_dir_description#:#A skin betűtípusait tároló mappa. Ez a mappa más skin-ek stílusainak és alstílusainak mappájával közössé tehető, megosztható. +style#:#font_dir_description#:#A skin betűtípusait tároló mappa. Ez a mappa más skin-ek stílusainak és alstílusainak mappájával közössé tehető, megosztható. Vigyázat, a mappa módosítását az ‘in-web-font-path’ SCSS-változóba is át kell vezetni. style#:#from_skin#:#skin-je a következőnek: style#:#green_color#:#Zöld szín style#:#green_colors#:#Zöld színek @@ -15966,23 +16059,23 @@ style#:#icons#:#Ikonok style#:#icons_gallery#:#Ikonok képtára style#:#image_dir#:#Képek mappája style#:#image_dir_description#:#A skin képeit (főleg ikonokat) tároló mappa. Ez a mappa más skin-ek stílusainak és alstílusainak mappájával közössé tehető, megosztható. -style#:#in_main_scss_file#:#is not imported inside the system styles main scss file:###26 08 2024 new variable -style#:#invalid_scss_path#:#The provided sass/scss path is either not valid or the webserver does not have the proper permission to read and execute sass/scss. Sass/scss (or the file linked to by the file pointed to by the scss path) has to be readable and executable by your webserver.###26 08 2024 new variable +style#:#in_main_scss_file#:#nincs importálva a rendszerstílusok fő scss fájljába: +style#:#invalid_scss_path#:#A megadott sass/scss elérési útvonala nem érvényes, vagy a webszervernek nincs megfelelő engedélye a sass/scss olvasásához és végrehajtásához. Az Sass/scss-t (vagy azt a fájlt, amelyre az scss elérési úton hivatkozott fájl hivatkozik) a webszerver futtatója olvasni és futtatni kell tudnia. style#:#ks_documentation_of_style#:#Kitchen Sink stílus dokumentációja style#:#ks_documentation_of_substyle#:#Kitchen Sink alstílus dokumentációja -style#:#main_scss_created#:#Main SCSS has been created:###26 08 2024 new variable +style#:#main_scss_created#:#A fő SCSS-t sikeresen létrehozta: style#:#manage_system_styles#:#Rendszerstílusok kezelése style#:#msg_sub_style_created#:#Az alstílust sikeresen létrehozta. style#:#msg_sys_style_created#:#Az új rendszerstílust sikeresen létrehozta. style#:#msg_sys_style_update#:#A rendszerstílusokat sikeresen frissítette -style#:#no_scss_path_set#:#No Scss Path set###26 08 2024 new variable +style#:#no_scss_path_set#:#Nincs Scss útvonal beállítva style#:#no_style_selected#:#Egy alstílust sem jelölt ki. style#:#of_parent#:#szülője a következőnek: style#:#open_documentation#:#Dokumentáció megnyitása style#:#parent#:#Szülőstílus style#:#personal#:#Személyes style#:#personal_style_set_to#:#Az Ön személyes rendszerstílusa mostantól: -style#:#provided_scss_path#:#Provided scss path:###26 08 2024 new variable +style#:#provided_scss_path#:#Megadott scss útvonal: style#:#red_color#:#Piros szín style#:#red_colors#:#Piros színek style#:#red_colors_description#:#Piros szín leírása @@ -15991,24 +16084,24 @@ style#:#remove_assignment#:#Hozzárendelés eltávolítása style#:#reset_icons#:#Ikonok alapértelmezettre állítása style#:#reset_variables#:#Változók alapértelmezettre állítása style#:#scope#:#Hatókör -style#:#scss#:#Scss###26 08 2024 new variable -style#:#scss_can_not_be_modified#:#Scss cannot be modified###26 08 2024 new variable -style#:#scss_compile_failed#:#Something in the compilation of the scss file went wrong. Is scss installed and the path set correctly in ILIAS setup? Original error:###26 08 2024 new variable -style#:#scss_file_reset#:#The scss variables have been reset. Important: Note that caching might prevent your changes from being shown. You might need to clear your browsers cache.###26 08 2024 new variable -style#:#scss_file_updated#:#The scss variables have been updated. Important: Note that caching might prevent your changes from being shown. You might need to clear your browsers cache.###26 08 2024 new variable -style#:#scss_folder_reset#:#Scss folder reset###26 08 2024 new variable -style#:#scss_folder_updated#:#Scss folder has been updated###26 08 2024 new variable -style#:#scss_scss_installation_detected#:#Scss/sass installation detected at:###26 08 2024 new variable -style#:#scss_variable_empty#:#This variable was empty. The default from your settings files has been set. Please check if this is correct before compiling.###26 08 2024 new variable -style#:#scss_variables_empty_might_have_changed#:#There are empty variables in your form. You might have changed your settings files since loading this form. The defaults from the settings files have been set for the empty fields. Please check those marked empty fields before compiling and saving the values to your settings files.###26 08 2024 new variable -style#:#scss_variables_file_not_included#:#The scss variables files:###26 08 2024 new variable +style#:#scss#:#Scss +style#:#scss_can_not_be_modified#:#Scss nem módosítható +style#:#scss_compile_failed#:#Valami hiba történt az scss fájl összeállításában. Az scss telepítve van, és az elérési út megfelelően van beállítva az ILIAS telepítőjében? Eredeti hiba: +style#:#scss_file_reset#:#A scss változókat sikeresen alaphelyzetve állította. Fontos: A gyorsítótárazás megakadályozhatja a módosítások megjelenését. Lehet, hogy törölnie kell a böngésző gyorsítótárát. +style#:#scss_file_updated#:#A scss változókat sikeresen frissítette. Fontos: A gyorsítótárazás megakadályozhatja a módosítások megjelenését. Lehet, hogy törölnie kell a böngésző gyorsítótárát. +style#:#scss_folder_reset#:#Scss mappát alapértelmezettre állította +style#:#scss_folder_updated#:#Scss mappát sikeresen módosította +style#:#scss_scss_installation_detected#:#Scss/sass telepítést detektáltunk: +style#:#scss_variable_empty#:#Ez a változó üres volt. A beállítási fájlokból származó alapértelmezett értéket állítottuk be. Kérem, a fordítás előtt ellenőrizze, hogy ez helyes-e. +style#:#scss_variables_empty_might_have_changed#:#Üres változók vannak az űrlapon. Lehet, hogy megváltoztatta a beállítási fájlokat az űrlap betöltése óta. Az üres mezők alapértelmezett értékei a beállítási fájlokból lettek beállítva. Kérem, ellenőrizze a megjelölt üres mezőket, mielőtt összeállítja és elmenti az értékeket a beállítások fájljaiba. +style#:#scss_variables_file_not_included#:#A scss változók fájljai: style#:#select_icon#:#Ikon kiválasztása style#:#settings_of_style#:#Stílus kezelése style#:#settings_of_substyle#:#Alstílus kezelése style#:#skin#:#Skin style#:#skin_deleted#:#A következő skin-t töröltük style#:#skin_id#:#Skin ID -style#:#skin_id_description#:#A skin-ek stílusokat és alstílusokat tartalmaznak. A skin ID egyben azon mappa neve is, ahol az összes, a stílusra és az alstílusokra vonatkozó információt tároljuk. A skin ID csak betűket, számokat, kötőjeleket és alulvonásokat tartalmazhat. +style#:#skin_id_description#:#A skin-ek stílusokat és alstílusokat tartalmaznak. A skin-ID egyben azon mappa neve is, ahol az összes, a stílusra és az alstílusokra vonatkozó információt tároljuk. A skin ID csak betűket, számokat, kötőjeleket és alulvonásokat tartalmazhat. style#:#skin_id_exists#:#Ilyen ID-jű skin már létezik. style#:#skin_name#:#Skin megnevezése style#:#skin_name_description#:#A skin neve alkalmazásának területét célszerű, hogy leírja, ember számára olvasható módon. Ez a név jelenik meg felhasználó felületen könnyítve a megfelelő skin kiválasztását. @@ -16023,7 +16116,7 @@ style#:#sty_add_color#:#Szín hozzáadása style#:#sty_add_content_style#:#Tartalomstílus létrehozása style#:#sty_add_image#:#Kép hozzáadása style#:#sty_add_media_query#:#Médialekérdezés létrehozása -style#:#sty_add_media_query_info#:#Például 'csak képernyő és (max-szélesség: 600px)' 600px-nél kisebb böngészőablakokhoz vagy 'nyomtatás' nyomtatókhoz. +style#:#sty_add_media_query_info#:#Például ‘csak képernyő és (max-szélesség: 600px)’ 600px-nél kisebb böngészőablakokhoz vagy ‘nyomtatás’ nyomtatókhoz. style#:#sty_add_pgl#:#Lapelrendezés hozzáadása style#:#sty_add_template#:#Sablon hozzáadása style#:#sty_added_characteristic#:#Stílusosztályok hozzáadva. @@ -16038,7 +16131,7 @@ style#:#sty_background_position#:#Háttérelhelyezkedés style#:#sty_background_repeat#:#Háttérismétlés style#:#sty_base_color#:#Alapszín style#:#sty_based_on#:#Ezen alapul -style#:#sty_bg_img_info#:#To add images to the dropdown selection please upload them in the "Images" section of the style first.###29 07 2022 new variable +style#:#sty_bg_img_info#:#Ha képeket szeretne hozzáadni a legördülő menühöz, kérjük, először töltse fel őket a stílus ‘Képek’ részébe. style#:#sty_border#:#Keret style#:#sty_border_color#:#Keretszín style#:#sty_border_style#:#Keretstílus @@ -16048,15 +16141,15 @@ style#:#sty_ca_cntr_class#:#Körhintatároló style#:#sty_ca_icntr_class#:#Körhintaelem-tároló style#:#sty_ca_icont_class#:#Körhintaelem-tartalom style#:#sty_ca_ihead_class#:#Körhintafejléc -style#:#sty_cannot_be_copied#:#The following style types cannot be copied###29 10 2025 new variable +style#:#sty_cannot_be_copied#:#A következő stílustípusok nem másolhatók: style#:#sty_caption#:#Felirat style#:#sty_caption_class#:#Felirat style#:#sty_carousel_templates#:#Körhinta-sablonok style#:#sty_cat_assignments#:#Stílus/kategória összerendelések -style#:#sty_change_user_assignment#:#Change User Assignment###29 10 2025 new variable +style#:#sty_change_user_assignment#:#Felhasználó összerendelés módosítása style#:#sty_characteristic_already_exists#:#Ilyen nevű stílusosztály már létezik ebben a stílusban. -style#:#sty_class#:#Style Class###29 07 2022 new variable -style#:#sty_class_name#:#Class Name###29 07 2022 new variable +style#:#sty_class#:#Stílusosztály +style#:#sty_class_name#:#Osztály neve style#:#sty_clear#:#Törlés (Clear) style#:#sty_col_foot_class#:#Oszloplábléc style#:#sty_col_head_class#:#Oszlopfejléc @@ -16064,21 +16157,21 @@ style#:#sty_color#:#Szín style#:#sty_color_already_exists#:#Ezzel a névvel már van szín a stílusban. style#:#sty_color_code#:#Színkód style#:#sty_color_flavors#:#Színárnyalat -style#:#sty_color_info#:#Az előredefiniált színek könnyűvé teszik egy szín különböző felhasználását. Az előredefiniált színekre a színek nevét megelőző '!' jellel hivatkozunk a stílusosztályban a színattribútumnál. Árnyalat használatához fűzzünk a színhez zárójelben világosságértéket, például !MyColor(20). +style#:#sty_color_info#:#Az előredefiniált színek könnyűvé teszik egy szín különböző felhasználását. Az előredefiniált színekre a színek nevét megelőző ‘!’ jellel hivatkozunk a stílusosztályban a színattribútumnál. Árnyalat használatához fűzzünk a színhez zárójelben világosságértéket, például !MyColor(20). style#:#sty_color_name#:#Színnév style#:#sty_colors#:#Színek style#:#sty_commands#:#Műveletek style#:#sty_confirm_char_deletion#:#Biztos, hogy törli az alábbi stílusosztályokat? style#:#sty_confirm_color_deletion#:#Színtörlés megerősítése style#:#sty_confirm_del_ind_styles#:#Egyedi tartalomstílus törlésének megerősítése -style#:#sty_confirm_del_ind_styles_desc#:#Az összes egyedi stílusú tananyag a(z) '%s' stílushoz lesz rendelve. Ezzel törlődik az összes egyedi tartalomstílus. Biztos, hogy folytatja? +style#:#sty_confirm_del_ind_styles_desc#:#Az összes egyedi stílusú tananyag a(z) ‘%s’ stílushoz lesz rendelve. Ezzel törlődik az összes egyedi tartalomstílus. Biztos, hogy folytatja? style#:#sty_confirm_template_deletion#:#Sablon törlésének megerősítése -style#:#sty_copied_please_select_target#:#A stílusosztályokat sikeresen másolta. Nyissa meg a célstílust, majd kattintson a 'Stílusosztályok beillesztése'-re. +style#:#sty_copied_please_select_target#:#A stílusosztályokat sikeresen másolta. Nyissa meg a célstílust, majd kattintson a ‘Stílusosztályok beillesztése’-re. style#:#sty_copy_other_stylesheet#:#Stílus másolása helyi forrásból style#:#sty_copy_other_system_style#:#Meglévő rendszerstílus klónozása. -style#:#sty_copy_to#:#to:###29 07 2022 new variable +style#:#sty_copy_to#:#ide: style#:#sty_create_ind_style#:#Egyedi stílus létrehozása -style#:#sty_create_new_class#:#Create new style class###29 07 2022 new variable +style#:#sty_create_new_class#:#Új stílusosztály létrehozása style#:#sty_create_new_stylesheet#:#Új stílus létrehozása style#:#sty_create_new_system_style#:#Új rendszerstílus létrehozása. style#:#sty_create_new_system_sub_style#:#Új rendszeralstílus létrehozása. @@ -16086,7 +16179,7 @@ style#:#sty_create_pgl#:#Lapelrendezés létrehozása style#:#sty_cursor#:#Kurzor style#:#sty_custom#:#Egyéni style#:#sty_custom_par#:#Egyéni paraméterek -style#:#sty_custom_par_info#:#Egyéni CSS paramétereket a következő formátumban tud hozzáadni: 'paraméter: érték'. +style#:#sty_custom_par_info#:#Egyéni CSS paramétereket a következő formátumban tud hozzáadni: ‘paraméter: érték’. style#:#sty_default#:#alapértelmezett style#:#sty_default_style#:#Alapértelmezett stílus style#:#sty_del_template#:#Sablonok és osztályok törlése @@ -16116,19 +16209,20 @@ style#:#sty_ha_ihead_class#:#Vízszintes harmonikaelem-fejléc (inaktív) style#:#sty_ha_iheada_class#:#Vízszintes harmonikafejléc (aktív) style#:#sty_haccordion_templates#:#Vízszintes harmonikasablonok style#:#sty_height#:#Magasság -style#:#sty_hide#:#Elrejtés +style#:#sty_hide#:#Rejtett style#:#sty_horizontal#:#Vízszintes -style#:#sty_if_style_class_already_exists#:#Ha a stílusosztály már létezik... +style#:#sty_if_style_class_already_exists#:#Ha a stílusosztály már létezik… style#:#sty_image_file#:#Képfájl style#:#sty_images#:#Képek style#:#sty_import_page_layout#:#Lapelrendezés importálása style#:#sty_import_stylesheet#:#Stílus importálása -style#:#sty_import_system_style#:#Meglévő rendszerstílus importálása ZIP-fájlként. -style#:#sty_imported_layout#:#Imported Page Layout###29 10 2025 new variable +style#:#sty_import_system_style#:#Rendszerstílus importálása +style#:#sty_imported_layout#:#Importált oldalstílus style#:#sty_individual_styles#:#Egyéni stílusok style#:#sty_keep_existing#:#Meglévők megtartása style#:#sty_left#:#Balra style#:#sty_left_right_padding#:#Cellaköz balra/jobbra +style#:#sty_legacy_image_directory_found#:#Van még egy régi képkönyvtár. A könyvtárat az ILIAS 9-ből a ‘Képek migrálása’ lehetőségre kattintva migrálhatja. style#:#sty_letter_spacing#:#Betűköz style#:#sty_lightness_border#:#Világosság szegély style#:#sty_lightness_cell1_bg#:#Világosság 1. cella háttér @@ -16140,8 +16234,8 @@ style#:#sty_lightness_header_text#:#Világosság fejlécszöveg style#:#sty_line_height#:#Sormagasság style#:#sty_link_char#:#Link style#:#sty_list_char#:#Felsorolás -style#:#sty_list_style_position#:#List Style Position###26 08 2024 new variable -style#:#sty_list_style_type#:#List Style Type###26 08 2024 new variable +style#:#sty_list_style_position#:#Felsorolás stílus pozíció +style#:#sty_list_style_type#:#Felsorolás stípus típus style#:#sty_make_global_default#:#Beállítás alapértelmezett stílusként style#:#sty_make_global_fixed#:#Ennek a stílusnak kényszerítése az összes objektumokra style#:#sty_margin#:#Margó @@ -16149,32 +16243,34 @@ style#:#sty_margin_and_padding#:#Margó és térköz style#:#sty_media_char#:#Média style#:#sty_media_queries#:#Médialekérdezés style#:#sty_media_query_info#:#Az alapértelmezett (nem speciális médialekérdezés) blokk után mindegyik médialekérdezéshez különálló CSS blokkot hozunk létre. +style#:#sty_migrate_images#:#Képek migrálása style#:#sty_min_height#:#Minimális magasság style#:#sty_move_lm_styles#:#Tananyag stílusának cseréje +style#:#sty_move_obj_styles#:#Objektumok stílusának a módosítása style#:#sty_move_style#:#Stílus cseréje style#:#sty_move_user_styles#:#Felhasználók stílusának cseréje -style#:#sty_move_user_styles_saved#:#The assignment of the users assigned to skind-id %s has been changed to skin-id %s.###29 10 2025 new variable -style#:#sty_msg_characteristic_must_only_include#:#A stílusosztályok címe betűvel kell, hogy kezdőjön, továbbá csak az alábbi karaktereket tartalmazhatja: +style#:#sty_move_user_styles_saved#:#A felhasználókhoz rendelt skin-id módosult: %s → %s. +style#:#sty_msg_characteristic_must_only_include#:#A stílusosztályok címe betűvel kell, hogy kezdőjön, nem tartalmazhat szóközt és továbbá csak az alábbi karaktereket tartalmazhatja: style#:#sty_msg_color_must_only_include#:#A színnév csak az alábbi karaktereket tartalmazhatja: style#:#sty_msg_input_must_be_numeric#:#A bemenetnek számnak kell lennie. style#:#sty_name#:#Név style#:#sty_nr_learning_modules#:#Tananyagok száma -style#:#sty_nr_objects#:#Number of Objects###29 10 2025 new variable +style#:#sty_nr_objects#:#Objektumok száma style#:#sty_odd_col_class#:#Páratlan oszlopok style#:#sty_odd_row_class#:#Páratlan sorok -style#:#sty_ol#:#Ordered List###26 08 2024 new variable +style#:#sty_ol#:#Számozott felsorolás style#:#sty_opacity#:#Átlátszatlanság style#:#sty_opt_saved#:#Az beállításokat sikeren mentette style#:#sty_order#:#Rendezés -style#:#sty_outdated#:#Outdated###29 07 2022 new variable +style#:#sty_outdated#:#Elavult style#:#sty_overflow#:#Túlcsordulás style#:#sty_overwrite#:#Felülírás -style#:#sty_overwrite_existing_class#:#Overwrite existing style class###29 07 2022 new variable +style#:#sty_overwrite_existing_class#:#Lézető stílusosztály felülírása style#:#sty_padding#:#Térköz style#:#sty_page_char#:#Lap -style#:#sty_parameters#:#Parameters###29 07 2022 new variable +style#:#sty_parameters#:#Paraméterek style#:#sty_paste_characteristics#:#Stílusosztályok beillesztése -style#:#sty_paste_chars#:#Paste Classes###29 07 2022 new variable +style#:#sty_paste_chars#:#Osztályok beillesztése style#:#sty_paste_style_classes#:#Stílusosztályok beillesztése style#:#sty_position#:#Pozíció style#:#sty_positioning#:#Pozicionálás @@ -16183,22 +16279,22 @@ style#:#sty_query#:#Lekérdezés style#:#sty_question_char#:#Kérdés style#:#sty_remove_global_default_state#:#Globálisan alapértelmezett állapot eltávolítása style#:#sty_remove_global_fixed_state#:#Globálisan rögzített állapot eltávolítása -style#:#sty_remove_outdated#:#Remove Outdated Status###29 07 2022 new variable -style#:#sty_resize#:#Resize###29 07 2022 new variable -style#:#sty_resize_image#:#Resize Image###29 07 2022 new variable +style#:#sty_remove_outdated#:#Elavult állapot eltávolítása +style#:#sty_resize#:#Méretezés +style#:#sty_resize_image#:#Kép méretezése style#:#sty_right#:#Jobbra style#:#sty_row_foot_class#:#Sorlábléc style#:#sty_row_head_class#:#Sorfejléc style#:#sty_rte_char#:#SCORM RTE style#:#sty_save_active_styles#:#Aktív stílus mentése -style#:#sty_save_hide_order_status#:#Save Order and Hidden Status###29 07 2022 new variable -style#:#sty_save_hide_status#:#Elrejtett állapot mentése -style#:#sty_save_order#:#Rendezés mentése -style#:#sty_save_order_status#:#Save Order###29 07 2022 new variable +style#:#sty_save_hide_order_status#:#Sorrend és rejtett állapot mentése +style#:#sty_save_hide_status#:#Mentés +style#:#sty_save_order#:#Sorrend mentése +style#:#sty_save_order_status#:#Sorrend mentése style#:#sty_sco_char#:#SCO és cél style#:#sty_scope#:#Hatókör style#:#sty_section_char#:#Blokk -style#:#sty_set_outdated#:#Set Outdated###29 07 2022 new variable +style#:#sty_set_outdated#:#Elavultnak megjelölés style#:#sty_set_scope#:#Hatókör beállítása style#:#sty_some_styles_obligatory_delete_rest#:#Az alábbi stílusosztályok kötelezőek és nem törölhetők. Folytatja, és törli a többi kiválasztott stílusosztályt? style#:#sty_source#:#Forrás @@ -16206,6 +16302,7 @@ style#:#sty_special#:#Speciális style#:#sty_style_chars#:#Stílusosztályok style#:#sty_style_class#:#Stílusosztályok style#:#sty_style_classes_copied#:#Stílusosztályokat sikeresen lemásolta. +style#:#sty_style_not_migrated#:#Ez a tartalomstílus még nem lett migrálva az ILIAS 10 adatstruktúrába. A változtatások nem lépnek érvénybe. style#:#sty_substyle#:#Alstílus style#:#sty_substyle_of#:#alstílusa a következőnek: style#:#sty_substyles#:#Alstílusok @@ -16230,7 +16327,7 @@ style#:#sty_text_decoration#:#Szövegdekoráció style#:#sty_text_indent#:#Szöveg behúzása style#:#sty_text_inline_char#:#Szöveg (karakter) style#:#sty_text_transform#:#Szövegtranszformáció -style#:#sty_titles#:#Titles###29 07 2022 new variable +style#:#sty_titles#:#Címek style#:#sty_to#:#erre style#:#sty_top#:#Fel style#:#sty_top_bottom_padding#:#Cellaköz felül/alul @@ -16243,7 +16340,7 @@ style#:#sty_type_ca_icont#:#Körhintaelem-tartalom style#:#sty_type_ca_ihead#:#Körhintaelem-fejléc style#:#sty_type_code_block#:#Kód (blokk) style#:#sty_type_code_inline#:#Kód (sorban) -style#:#sty_type_em#:#Emphasised###26 08 2024 new variable +style#:#sty_type_em#:#Dőlt style#:#sty_type_flist#:#Fájllista style#:#sty_type_flist_a#:#Fájllistaelem-hivatkozás style#:#sty_type_flist_cont#:#Fájllista-tároló @@ -16315,7 +16412,7 @@ style#:#sty_type_sco_keyw#:#SCO-kulcsszavak style#:#sty_type_sco_obj#:#SCO-cél style#:#sty_type_sco_title#:#SCO-cím style#:#sty_type_section#:#Rész -style#:#sty_type_strong#:#Strong###26 08 2024 new variable +style#:#sty_type_strong#:#Félkövér style#:#sty_type_sub#:#Alsó index style#:#sty_type_sup#:#Felső index style#:#sty_type_table#:#Táblázat @@ -16328,7 +16425,7 @@ style#:#sty_type_va_icont#:#Függőleges harmonikaelem-tartalom style#:#sty_type_va_ihcap#:#Függőleges harmonikaelem-fejlécfelirat style#:#sty_type_va_ihead#:#Függőleges harmonikaelem-fejléc (inaktív) style#:#sty_type_va_iheada#:#Függőleges harmonikaelem-fejléc (aktív) -style#:#sty_ul#:#Unordered List###26 08 2024 new variable +style#:#sty_ul#:#Listajeles felsorolás style#:#sty_va_cntr_class#:#Függőleges harmonikatároló style#:#sty_va_icntr_class#:#Függőleges harmonikaelem-tároló style#:#sty_va_icont_class#:#Függőleges harmonikaelem-tartalom @@ -16358,8 +16455,8 @@ style#:#style_not_deleted#:#A stílus az alábbi ok miatt nem törölhető: style#:#style_page_layout_module_learning_module#:#ILIAS-tananyag style#:#style_page_layout_module_portfolio#:#Portfólió style#:#style_page_layout_module_scorm#:#SCORM -style#:#style_support_reuse#:#Re-Use###29 07 2022 new variable -style#:#style_support_reuse_info#:#Allow sub-objects of the current container to re-use this content style.###29 07 2022 new variable +style#:#style_support_reuse#:#Újbóli felhasználás +style#:#style_support_reuse_info#:#Az aktuális tároló alobjektumai számára is lehetővé teszi ennek a tartalomstílusnak a használatát. style#:#styles_not_deleted#:#A stílus az alábbi okok miatt nem törölhető: style#:#sub_style#:#Alstílus style#:#sub_style_id#:#Alstílus ID @@ -16385,26 +16482,26 @@ survey#:#SurveyTextQuestion#:#Esszékérdés survey#:#add_heading#:#Címsor létrehozása survey#:#already_completed_survey#:#Már befejezte a kérdőív kitöltését. Nem léphet bele többször. survey#:#anonymization#:#Névtelenség -survey#:#anonymize_anonymous_introduction#:#Ez a kérdőív névtelenül kezel minden felhasználói adatot.
    A kérdőív eléréséhez 5 karakteres kérdőívkódot kell megadnia, amelyet ezen kérdőív létrehozójától/karbantartójától kaphat meg.
    Adja meg kódját a fenti szövegmezőben. +survey#:#anonymize_anonymous_introduction#:#A kérdőív eléréséhez 5 karakterből álló kódot kell megadnia, amelyet ezen kérdőív létrehozójától/karbantartójától kaphat meg.
    Adja meg kódját a kérdőív indítása után. survey#:#answer#:#Válasz survey#:#arithmetic_mean#:#Számtani átlag survey#:#browse_for_questions#:#Hozzáadás kérdésgyűjteményből survey#:#cancel_survey#:#Kérdőív kitöltésének felfüggesztése survey#:#cannot_read_survey#:#Nincs megfelelő jogosultsága a kérdőív adatainak olvasásához. -survey#:#cannot_switch_to_online_no_questions#:#Nem módosítható "online (aktív)"-ra az állapot, mert nincsenek kérdések a kérdőívben. -survey#:#cant_send_email_smtp_disabled#:#Külső e-mail küldése központilag le van tiltva. +survey#:#cannot_switch_to_online_no_questions#:#A kérdőív nem módosítható ‘online’-ra, mert nincsenek benne kérdések. +survey#:#cant_send_email_smtp_disabled#:#Külső e-mail küldésének lehetőségét központilag kikapcsolták. survey#:#category#:#Válasz survey#:#category_nr_selected#:#Kiválasztások száma survey#:#chart#:#Diagram survey#:#codes#:#Hozzáférési kód -survey#:#codes_created#:#Kódo(ok) jött(ek) létre -survey#:#codes_deleted#:#Kód(ok) törlése sikerült +survey#:#codes_created#:#Kódo(ok) jött(ek) létre. +survey#:#codes_deleted#:#Kód(ok) törlése sikerült. survey#:#combobox#:#Legördülő lista survey#:#concatenation#:#Összefűzés -survey#:#confirm_delete_all_user_data#:#Biztos, hogy törli a kérdőív összes felhasználói adatát? +survey#:#confirm_delete_all_user_data#:#Biztos, hogy törli a kérdőív összes felhasználói adatát? Ez kihat a válaszokra és a kitöltők listájára is. survey#:#confirm_delete_single_user_data#:#Biztos, hogy törli a résztvevőket? Evvel törli a kiválasztott felhasználók kérdőívadatait is. survey#:#confirm_remove_heading#:#Biztos, hogy eltávolítja a címsort? -survey#:#confirm_sync_questions#:#A kérdés amit módosított, egy kérdés aktuális kérdőívhez létrehozott másolata. A kérdés eredeti példányát is módosítani szeretné? +survey#:#confirm_sync_questions#:#A kérdés amit módosított, egy kérdés létrehozott másolata az aktuális kérdőívhez. A kérdés eredeti példányát is módosítani szeretné? survey#:#conjunction_and#:#ha minden feltétel teljesül survey#:#conjunction_and_title#:#Minden alábbi feltétel kitöltése survey#:#conjunction_or#:#ha egy feltétel teljesül @@ -16412,9 +16509,9 @@ survey#:#conjunction_or_title#:#Egy feltétel kitöltése az alábbiak közül survey#:#constraint_add#:#Elágazási szabály létrehozása survey#:#constraint_fulfilled#:#Lap megjelenítése survey#:#constraints#:#Elágazási szabályok -survey#:#constraints_first_question_description#:#Az első entitásnak nem lehet semmilyen elágazása, mert nincsenek megelőző kérdések. +survey#:#constraints_first_question_description#:#Az első kérdésnek és kérdésblokknak nem lehet semmilyen elágazása, mert nincsenek azt megelőző kérdések. survey#:#constraints_introduction#:#Egy kérdéshez vagy több kérdést tartalmazó kérdésblokkhoz elágazási szabály definiálható. A kitöltő a korábbi válaszától függően kapja vagy nem kapja a következő kérdést, azaz a kitöltő számára a válasza alapján nem relevánsnak ítélt következő kérdés nem jelenik meg, így rövidebb, személyre szabottabb lesz a kérdőív. Az első kérdéshez, illetve kérdésblokkhoz nem rendelhető elágazási szabály. -survey#:#constraints_list_of_entities#:#Elágazási szabályokhoz használható elemek +survey#:#constraints_list_of_entities#:#Kérdések survey#:#constraints_no_nonessay_available#:#Elágazási szabályok meghatározásához nincsenek korábbi kérdések. A következő típusok támogatottak: metrikus, egyválaszos, többválaszos. survey#:#constraints_no_questions_or_questionblocks_selected#:#Legalább egy kérdést vagy kérdésblokkot válasszon ki! survey#:#contains#:#Magában foglalja @@ -16456,29 +16553,27 @@ survey#:#dc_varying#:#változó survey#:#dc_verygood#:#nagyon jó survey#:#dc_yes#:#igen survey#:#default_codes_mail_message#:#Tisztelt [lastname] [firstname], az Ön kérdőívkódja: [code]. A kérdőívet az következő linken éri el: [url]. Üdvözlettel: -survey#:#default_codes_mail_subject#:#'%s' kérdőívhez hozzáférési kód +survey#:#default_codes_mail_subject#:#‘%s’ kérdőívhez hozzáférési kód survey#:#define_questionblock#:#Kérdésblokk definiálása survey#:#delete_saved_message#:#Üzenetszöveg törlése survey#:#display_all_available#:#Összes elérhető megjelenítése -survey#:#dont_use_questionpool#:#Ne szúrja be a kérdéseket kérdésgyűjteménybe (csak ebben a tesztben elérhetők). survey#:#duplicate#:#Másodpéldány létrehozása survey#:#edit_heading#:#Címsor módosítása survey#:#end_date#:#Záró időpont survey#:#end_date_reached#:#Már nem tudja elkezdeni a kérdőív kitöltését, mert elmúlt a záró időpont. survey#:#enter_anonymous_id#:#Kérdőív hozzáférési kódja survey#:#enter_valid_number_of_codes#:#Érvényes számot adjon meg a kérdőív hozzáférési kódjának generálásához! -survey#:#err_external_rcp_no_email#:#Az importadatoknak legalább egy 'e-mail' mezőt kell tartalmaznia. -survey#:#err_external_rcp_no_email_column#:#Az importadatoknak legalább egy 'e-mail' oszlopot kell tartalmaznia az 'email' felirattal az első sorban, és e-mail címeket a további sorokban. +survey#:#err_external_rcp_no_email#:#Az importadatoknak legalább egy ‘e-mail’ mezőt kell tartalmaznia. +survey#:#err_external_rcp_no_email_column#:#Az importadatoknak legalább egy ‘e-mail’ oszlopot kell tartalmaznia az ‘email’ felirattal az első sorban, és e-mail címeket a további sorokban. survey#:#err_maxvaluegeminvalue#:#A maximális érték nagyobb vagy egyenlő kell legyen, mint a minimumérték, és kisebb vagy egyenlő, mint a válaszok maximális száma. -survey#:#err_minvalueganswers#:#A minimumnak kisebbnek vagy egyenlőnek kell lennie, mint a válaszok maximális számának. +survey#:#err_minvalueganswers#:#A minimális érték kisebb vagy egyenlő kell legyen, mint a maximumérték, és kisebb vagy egyenlő, mint a válaszok maximális száma. survey#:#err_no_exact_answers#:#Pontosan %s választ jelöljön meg! survey#:#err_no_max_answers#:#Legfeljebb %s választ jelöljön meg! survey#:#err_no_min_answers#:#Legalább %s választ jelöljön meg! -survey#:#err_no_pool_name#:#Adja meg egy kérdőívkérdés-gyűjtemény nevét! survey#:#error_retrieving_anonymous_survey#:#Nem találja a rendszer a %s kódú kérdőívét. Ellenőrizze a megadott kérdőívkódot! -survey#:#error_save_code#:#Az értéket nem sikerült megfelelően menteni. '%s' e-mail cím nem valós. Családnév: '%s', utónév: '%s'.
    +survey#:#error_save_code#:#Az értéket nem sikerült megfelelően menteni. ‘%s’ e-mail cím nem valós. Családnév: ‘%s’, utónév: ‘%s’.
    survey#:#evaluation#:#Statisztika -survey#:#evaluation_access#:#Válaszadók hozzáférése a végeredményekhez +survey#:#evaluation_access#:#Hozzáférés a végeredményekhez survey#:#evaluation_access_all#:#Az összes felhasználó hozzáférhet ennek a kérdőívnek a végeredményeihez survey#:#evaluation_access_info#:#Ön hozzáférhet a kérdőív végeredményeihez survey#:#evaluation_access_off#:#A válaszadók nem férhetnek hozzá a végeredményekhez @@ -16492,12 +16587,12 @@ survey#:#export_title_label#:#Címek és címkék exportálása survey#:#export_title_only#:#Csak címek exportálása survey#:#external_recipients_imported#:#A külső címzetteket sikeresen importálta. survey#:#externalmails#:#Importfájl -survey#:#externalmails_info#:#Az importfájlnak CSV fájlnak kell lennie, az oszlopokat pontosvessző válassza el. Az első sor tartalmazza az oszlopcímeket. A fájlnak legalább 'e-mail' oszlopot kell tartalmaznia a címzett e-mail címével. +survey#:#externalmails_info#:#Az importfájlnak CSV fájlnak kell lennie, az oszlopokat pontosvessző válassza el. Az első sor tartalmazza az oszlopcímeket. A fájlnak legalább ‘e-mail’ oszlopot kell tartalmaznia a címzett e-mail címével. survey#:#externaltext#:#Szöveg importálása -survey#:#externaltext_info#:#Az importszöveget sorokba és oszlopokba kell rendezni, az oszlopokat pontosvesszővel kell elválasztani. Az első sor tartalmazza az oszlop címét. A szövegnek legalább egy 'email' oszlopot kell tartalmaznia a címzett e-mail címével. +survey#:#externaltext_info#:#Az importszöveget sorokba és oszlopokba kell rendezni, az oszlopokat pontosvesszővel kell elválasztani. Az első sor tartalmazza az oszlop címét. A szövegnek legalább egy ‘email’ oszlopot kell tartalmaznia a címzett e-mail címével. survey#:#filter_all_question_types#:#Összes kérdéstípus survey#:#filter_all_questionpools#:#Összes kérdésgyűjtemény -survey#:#finished_mail_subject#:#'%s' kérdőívet befejezte +survey#:#finished_mail_subject#:#‘%s’ kérdőívet egy válaszadó befejezte survey#:#freetext_answers#:#Szabadszöveges válaszok survey#:#geometric_mean#:#Geometriai átlag survey#:#given_answers#:#Adott válaszok @@ -16511,7 +16606,7 @@ survey#:#import_from_file#:#Felhasználói adatok importálása fájlból survey#:#import_from_text#:#Felhasználói adatok importálása szövegből survey#:#import_no_file_selected#:#Nincs kiválasztott fájl. survey#:#import_question#:#Kérdés(ek) importálása -survey#:#import_wrong_file_type#:#Hibás fájltípus. +survey#:#import_wrong_file_type#:#Érvénytelen fájltípus. survey#:#insert_after#:#Beszúrás utána survey#:#insert_before#:#Beszúrás előtte survey#:#insert_missing_question#:#Legalább egy kérdést válasszon ki a kérdőívbe való beszúráshoz! @@ -16521,20 +16616,20 @@ survey#:#internal_link#:#Belső link survey#:#introduction#:#Bevezető üzenet survey#:#invited_users#:#Kiválasztott felhasználók survey#:#label#:#Címke -survey#:#label_info#:#Alternatív azonosító további adatfeldolgozáshoz (például SPSS-ben) -survey#:#language_changed#:#Nyelv megváltoztatva +survey#:#label_info#:#Alternatív azonosító további adatfeldolgozáshoz (például SPSS-ben). +survey#:#language_changed#:#A nyelvet sikeresen megváltoztatta. survey#:#layout#:#Elrendezés survey#:#lower_limit#:#Alsó határ -survey#:#mail_import_example2#:#sandraowen@domain.tld;Sandra;Owen -survey#:#mail_import_example3#:#kennethbirt@domain.tld;Kenneth;Birt +survey#:#mail_import_example2#:#lucysnowe@villette.be;Lucy;Snowe +survey#:#mail_import_example3#:#holmes@bakerstreetconsulting.co.uk;Sherlock;Holmes survey#:#mail_sent_short#:#Elküldés -survey#:#mail_survey_codes#:#Hozzáférési kódok, üzenetek küldése +survey#:#mail_survey_codes#:#Emlékeztető / Hozzáférési kód üzenetek survey#:#mailaddresses#:#Címzettek -survey#:#mailaddresses_info#:#Adja meg a kérdőívek befejezéséről értesítést kapó címzettek listáját vesszővel elválasztva. +survey#:#mailaddresses_info#:#Adja meg azon felhasználónevek listáját vesszővel elválasztva, akikenek értesítést küldünk, amikor egy felhasználó befejezik a kérdőív kitöltését. survey#:#mailnotification#:#Minden befejezésről külön e-mail küldése -survey#:#mailparticipantdata#:#További válaszadói adatok +survey#:#mailparticipantdata#:#Információs szöveg survey#:#mailparticipantdata_info#:#Ez az információ az értesítő levélbe automatikusan beillesztett eredmények része elé kerül. -survey#:#mailparticipantdata_placeholder#:#Ezek a helyőrzők a felhasználó aktuális adatára cserélődnek, ha az 'Adatvédelem' értéke 'Nevekkel': +survey#:#mailparticipantdata_placeholder#:#Ezek a helyőrzők a felhasználó aktuális adatára cserélődnek, ha az ‘Adatvédelem’ értéke ‘Nevekkel’ (Lásd ‘Eredmények’ rész): survey#:#maintenance#:#Válaszadók survey#:#matrix_appearance#:#Megjelenés survey#:#matrix_bipolar_adjectives#:#Bipoláris melléknevek @@ -16544,7 +16639,7 @@ survey#:#matrix_column_separators_description#:#Vastag vonal az oszlopok közöt survey#:#matrix_column_settings#:#Mátrixoszlopok beállításai survey#:#matrix_columns#:#Mátrixoszlopok survey#:#matrix_left_pole#:#Bal pólus -survey#:#matrix_neutral_answer#:#Szöveg semleges oszlophoz ('Nem meghatározott', 'Nem tudom', stb.) +survey#:#matrix_neutral_answer#:#Szöveg semleges oszlophoz (‘Nem meghatározott’, ‘Nem tudom’ stb.) survey#:#matrix_neutral_column_separator#:#Semleges oszlopelválasztók survey#:#matrix_neutral_column_separator_description#:#Vastag vonal a semleges és a többi oszlop közé. survey#:#matrix_question_checkbox_not_checked#:#Jelöljön be legalább egy jelölőnégyzetet minden sorban! @@ -16566,7 +16661,7 @@ survey#:#message_content_info#:#Írjon üzenet a válaszadóknak, ami tartalmazz survey#:#metric_question_floating_point#:#A megadott érték lebegőpontos, amely nem megengedett ehhez a kérdéstípushoz. survey#:#metric_question_not_a_value#:#A megadott érték nem numerikus. survey#:#metric_question_out_of_bounds#:#A bevitt érték nincs a minimum és maximum érték között. -survey#:#metric_subtype_description_interval#:#Mérések esetén az ekvivalens intervallumok lehetővé teszik az önkényesen megadott méréshatárok közé eső adat jelentésének kiértékelését. A skálán a zérus pont bárhová tehető, így negatív értékek is használhatóak. Példák intervallumértékekre: naptárban lévő évek vagy a Celsius fokban mért hőmérséklet. +survey#:#metric_subtype_description_interval#:#Mérések esetén az ekvivalens intervallumok lehetővé teszik az önkényesen megadott méréshatárok közé eső adat jelentésének kiértékelését. A skálán a zérus pont bárhová tehető, így negatív értékek is használhatók. Példák intervallumértékekre: naptárban lévő évek vagy a Celsius fokban mért hőmérséklet. survey#:#metric_subtype_description_ratioabsolute#:#Az abszolút skálán mérés természetes számokat használ a nem önkényesen kijelölt zérusponthoz képest, például gyerekek száma egy családban vagy bekövetkezési valószínűség százalékban. survey#:#metric_subtype_description_rationonabsolute#:#Az intervallummérés mellett további jelentéssel bíró arányok is léteznek az önkényesen kijelölt számpárok között. A zérus érték egy arányskálán nem önkényes. A legtöbb fizikai mennyiséget, mint a hosszúságot centiméterben vagy az időtartamot másodpercben arányskálán mérjük. survey#:#minimum#:#Minimális érték @@ -16621,7 +16716,6 @@ survey#:#questionblock#:#Kérdésblokk survey#:#questionblock_inserted#:#Kérdésblokk beszúrva survey#:#questionblocks#:#Kérdésblokkok survey#:#questionblocks_inserted#:#Kérdésblokkok beszúrva -survey#:#questions#:#Kérdések survey#:#questions_inserted#:#Kérdés(ek) beszúrva. survey#:#questions_removed#:#Kérdés(ek)/kérdésblokk(ok) eltávolítva. survey#:#questiontype#:#Kérdéstípus @@ -16642,8 +16736,6 @@ survey#:#search_groups#:#Talált csoportok survey#:#search_term#:#Fogalom keresése survey#:#select_option#:#--- Válasszon egy beállítást --- survey#:#select_prior_question#:#Előzetes kérdés kiválasztása -survey#:#select_questionpool#:#Válasszon ki egy kérdésgyűjteményt a létrehozott kérdés mentéséhez. -survey#:#select_questionpool_short#:#Kérdőívkérdés-gyűjtemény survey#:#select_relation#:#Kapcsolat kiválasztása survey#:#select_target_position_for_move_question#:#Válasszon célhelyet a kérdés(ek) áthelyezéséhez és nyomja meg az egyik beszúrás gombot! survey#:#select_value#:#Érték megadása @@ -16652,7 +16744,7 @@ survey#:#send_to_all#:#Minden címzettnek survey#:#send_to_answered#:#Minden címzettnek, akik már befejezték a kérdőívet. survey#:#send_to_unanswered#:#Minden címzettnek, akik még nem fejezték be a kérdőívet (emlékeztető). survey#:#show_questiontext#:#Kérdésszöveg megjelenítése -survey#:#show_questiontext_description#:#Ha be van kapcsolva, a kérdésblokk egyes kérdéseinek kérdésszövege megjelenik. Ha nincs kiválasztva, a kérdésszövegek rejtve maradnak. +survey#:#show_questiontext_description#:#A kérdésblokk egyes kérdéseinek kérdésszövege megjelenik. Ha nincs kiválasztva, a kérdésszövegek rejtve maradnak. survey#:#skipped#:#kihagyott survey#:#spl_copy_insert_clipboard#:#A kiválasztott kérdés(ek)et a vágólapra másolta survey#:#spl_copy_select_none#:#Ellenőrizze, hogy legalább egy kérdést kiválasztott, hogy másolhassa @@ -16660,7 +16752,6 @@ survey#:#spl_move_insert_clipboard#:#A kiválasztott kérdés(eke)t kijelölte, survey#:#spl_move_same_pool#:#Ugyanazon kérdésgyűjteményen belül nem mozgathat kérdéseket. survey#:#spl_move_select_none#:#Ellenőrizze, hogy legalább egy kérdést kiválasztott a mozgatáshoz survey#:#spl_online_property#:#Online -survey#:#spl_online_property_description#:#Csak online kérdésgyűjtemény használható kérdőívekben. survey#:#spl_paste_no_objects#:#Egy kérdés sincs a vágólapon. Másoljon vagy helyezzen kérdést a vágólapra. survey#:#spl_paste_success#:#A kérdés(ek)et sikeresen beillesztette a kérdésgyűjteménybe. survey#:#spl_save_obligatory_state#:#Kötelező állapot mentése @@ -16678,16 +16769,13 @@ survey#:#survey_360_appraisee_close_action_status#:#Kérdőív lezárult: %s. survey#:#survey_360_appraisee_close_action_success#:#Lezárta saját 360°-os kérdőívét saját értékelői számára. survey#:#survey_360_appraisee_close_action_success_admin#:#Az értékelendő személyek 360°-os kérdőívei lezárultak az értékelők számára. survey#:#survey_360_appraisee_close_table#:#Lezárult -survey#:#survey_360_appraisee_info#:#Értékelendő személyről infó survey#:#survey_360_appraisee_is_closed#:#Az értékelendő személy lezárta a kérdőívét. survey#:#survey_360_appraisees#:#Értékelendő személyek survey#:#survey_360_edit_raters#:#Értékelők módosítása survey#:#survey_360_mode#:#360°-os értékelés survey#:#survey_360_mode_info#:#Személyek teljes körű vizsgálata survey#:#survey_360_no_appraisees#:#Jelenleg nincs olyan személy, akit értékelhetne. -survey#:#survey_360_no_closed_appraisees#:#Egy értékelendő személy kérdőíve sem zárult még le. -survey#:#survey_360_rate_other_appraisee#:#Rate Appraisee###28 10 2024 new variable -survey#:#survey_360_rate_other_appraisees#:#Értékelés +survey#:#survey_360_rate_other_appraisee#:#Értékelendő személyek értékelése survey#:#survey_360_rater_finished#:#Kérdőív befejezve survey#:#survey_360_rater_mail_sent#:#Levél elküldve survey#:#survey_360_rater_message_content_anonymous#:#Üzenet tartalma (Anonymous) @@ -16697,7 +16785,6 @@ survey#:#survey_360_rater_message_content_registered_default#:#A kérdőívet a survey#:#survey_360_rater_subject_default#:#Meghívás 360°-os kérdőívbe válaszadónak survey#:#survey_360_raters#:#Értékelések survey#:#survey_360_raters_finished#:#Befejezett értékelések -survey#:#survey_360_raters_status_info#:#Befejezett értékelések survey#:#survey_360_remove_appraisees#:#Értékelendő személy(ek) eltávolítása survey#:#survey_360_results#:#Hozzáférés az értékelt személyek végeredményeihez survey#:#survey_360_results_all#:#Az összes értékelt a másikéhoz is @@ -16707,8 +16794,8 @@ survey#:#survey_360_results_none_info#:#At értékeltek nem férhetnek hozzá az survey#:#survey_360_results_own#:#Mindenki a sajátjához survey#:#survey_360_results_own_info#:#Minden értékelendő csak a saját magára kapott értékelésekhez férhet hozzá. survey#:#survey_360_select_appraisee#:#Válassz -survey#:#survey_360_self_appraisee#:#Nyílt 360°-os visszajelzés -survey#:#survey_360_self_appraisee_info#:#Az összes felhasználó számára elérhető link jelenik meg az 'Információ' fülön. Erre kattintva önmagukat értékelendő személlyé tehetik, így visszajelzéseket kaphatnak. +survey#:#survey_360_self_appraisee#:#Nyílt visszajelzés +survey#:#survey_360_self_appraisee_info#:#Az összes felhasználó számára elérhető link jelenik meg az ‘Információ’ lapon. Erre kattintva önmagukat értékelendő személlyé tehetik, így visszajelzéseket kaphatnak. survey#:#survey_360_self_evaluation#:#Önértékelés survey#:#survey_360_self_evaluation_info#:#A válaszadók a kérdéseken keresztül értékelhetik saját magukat. survey#:#survey_360_self_raters#:#Az értékelendő személy kiválaszthatja értékelőit @@ -16718,23 +16805,23 @@ survey#:#survey_360_sure_appraisee_close_admin#:#Biztos, hogy lezárja a kérdő survey#:#survey_360_sure_delete_appraises#:#Biztos, hogy eltávolítja az alábbi értékelendő személyeket? survey#:#survey_360_sure_delete_raters#:#Biztos, hogy eltávolítja %s értékelőit? survey#:#survey_access_code#:#Hitelesítés kódokkal -survey#:#survey_access_codes_info#:#A felhasználók az 'Információ' fülön megadható kóddal férhet hozzá a teszthez. Kódokat generálni a 'Válaszadók' fül alatti 'Hozzáférési kódok' alfül alatt lehet. +survey#:#survey_access_codes_info#:#A felhasználók az ‘Információ’ lapon megadható kóddal férhet hozzá a teszthez. Kódokat generálni a ‘Válaszadók’ lap alatti ‘Hozzáférési kódok’ allap alatt lehet. survey#:#survey_activate_skill_service#:#Kompetenciaszolgáltatás bekapcsolása -survey#:#survey_activate_skill_service_info#:#Egy új, 'Kompetencia' nevű fül jelenik meg. Itt kompetenciákat rendelhet a kérdésekhez, majd küszöbértéket kompetenciaszintekhez. +survey#:#survey_activate_skill_service_info#:#Egy új, ‘Kompetencia’ nevű lap jelenik meg. Itt kompetenciákat rendelhet a kérdésekhez, majd küszöbértéket kompetenciaszintekhez. survey#:#survey_add_new_question#:#Új kérdés létrehozása survey#:#survey_assign_competence#:#Kompetencia hozzárendelése survey#:#survey_auto_block_title#:#Lapfejléc survey#:#survey_available_question_pools#:#Elérhető gyűjtemények survey#:#survey_calc_skills#:#Kompetenciaszintek megállapítása -survey#:#survey_calculate_sum_score#:#Calculate Sum Score###XXX -survey#:#survey_calculate_sum_score_info#:#Calculates the sum of all scale values for single choice, multiple choice and matrix questions for each participant. Caution: If participants skip these kind of questions, the whole sum score will not be calculated anymore. +survey#:#survey_calculate_sum_score#:#Összpontszám kiszámítása +survey#:#survey_calculate_sum_score_info#:#Kiszámolja az összes részvevő összes egyválaszos, többválaszos és mátrixkérdések értékének összegét. Vigyázzon: Ha a résztvevők kihagyják ezeket a kérdéseket, tovább a teljes szummát már nem számoljuk. survey#:#survey_cancel_preview#:#Előnézet kikapcsolása survey#:#survey_cannot_preview_survey#:#Az előnézet nem érhető el survey#:#survey_code#:#Kérdőív hozzáférési kódja -survey#:#survey_code_delete_sure#:#Biztos, hogy töröli az alábbi hozzáférési kódokat? +survey#:#survey_code_delete_sure#:#Biztos, hogy töröli az alábbi, fel nem használt hozzáférési kódokat? survey#:#survey_code_url#:#URL közvetlen eléréshez survey#:#survey_code_url_name#:#URL (használja a jobb egérgombot az URL másolásához) -survey#:#survey_code_used#:#A kód... +survey#:#survey_code_used#:#A kód… survey#:#survey_codes_lang#:#Előre kiválasztott kérdőívnyelv survey#:#survey_codes_no_anonymization#:#Névtelen kérdőívet kell létrehoznia hozzáférési kóddal új hozzáférési kódok létrehozásához! survey#:#survey_competences#:#Kompetenciák @@ -16747,24 +16834,22 @@ survey#:#survey_edit_heading#:#Címsor módosítása survey#:#survey_edit_settings#:#Beállítások módosítása survey#:#survey_error_insert_incomplete_question#:#Nem teljes kérdést próbált hozzáadni a kérdőívhez. A kérdés hozzáadása sikertelen. survey#:#survey_execution_exit#:#Vissza a Tartalomtárhoz -survey#:#survey_execution_exit_360#:#Back###26 08 2024 new variable +survey#:#survey_execution_exit_360#:#Vissza survey#:#survey_execution_sure_finish#:#Biztos, hogy befejezi a kérdőív kitöltését? Utána már nem tudja módosítani válaszait. -survey#:#survey_existing_pool#:#Már létező kérdésgyűjtemény használata survey#:#survey_finish#:#Kérdőív befejezése -survey#:#survey_finished#:#Befejezte a kérdőív kitöltését. Köszönjük résztvételét! +survey#:#survey_finished#:#Befejezte a kérdőív kitöltését. Köszönjük részvételét! +survey#:#survey_from_x_points#:#X ponttól survey#:#survey_has_datasets_warning#:#A kérdőív tartalmaz már adathalmazokat. Amíg nem távolítja el ezeket a válaszadók részben, nem tudja szerkeszteni a kérdőív kérdéseit. survey#:#survey_has_datasets_warning_page_view#:#A kérdőív már tartalmaz válaszokat. Nem szerkesztheti a kérdőív kérdéseit, amíg el nem távolítja azokat. survey#:#survey_has_datasets_warning_page_view_link#:#Résztvevő eredményei -survey#:#survey_introduction_info#:#Ez az üzenet az 'Információ' fülön jelenik meg. +survey#:#survey_introduction_info#:#Ez az üzenet az ‘Információ’ lapon jelenik meg. survey#:#survey_is_offline#:#Nem tudja elkezdeni a kérdőív kitöltését. A kérdőív jelenleg offline (nem aktív). -survey#:#survey_new_pool#:#Új kérdésgyűjtemény létrehozása survey#:#survey_next#:#Következő >>> -survey#:#survey_no_pool#:#Ne használjon kérdésgyűjteményt survey#:#survey_not_available#:#n.a. -survey#:#survey_notification_finished_introduction#:#Az alábbi válaszadók befejezték a kérdőívet. +survey#:#survey_notification_finished_introduction#:#Egy válaszadó befejezte a kérdőívet. survey#:#survey_notification_finished_reason#:#Ezt a levelet azért kapta, mert fent említett kérdőívnél beállította, hogy kér értesítést. survey#:#survey_notification_target_group#:#Célcsoport -survey#:#survey_notification_target_group_invited#:#All users who got the survey put on their Personal Desktop###29 07 2022 new variable +survey#:#survey_notification_target_group_invited#:#A kérdőív linkje megjelenik az összes felhasználó Műszerfalára. survey#:#survey_notification_target_group_invited_info#:#Jelenlegi felhasználók száma: %s survey#:#survey_notification_target_group_parent_course#:#Kurzustároló/csoporttároló összes tagja survey#:#survey_notification_target_group_parent_course_inactive#:#Nem adott meg kurzustárolót/csoporttárolót - emlékeztetőket nem küldünk! @@ -16774,45 +16859,39 @@ survey#:#survey_notification_tutor_recipients#:#Tutorok (felhasználónevek) survey#:#survey_notification_tutor_recipients_invalid#:#Kérem, adjon írási jogosultságot a felhasználók számára. survey#:#survey_notification_tutor_salutation#:#Tisztelt %s, survey#:#survey_notification_tutor_setting#:#E-mail küldése, miután az összes válaszadó befejezte a kérdőív kitöltését -survey#:#survey_notification_tutor_subject#:#Az összes válaszadó befejezte a(z) '%s' kérdőívet. +survey#:#survey_notification_tutor_subject#:#Az összes válaszadó befejezte a(z) ‘%s’ kérdőívet. survey#:#survey_order#:#Rendezési sorrend -survey#:#survey_pool_selection#:#Gyűjtemény kijelölése survey#:#survey_previous#:#<<< Előző survey#:#survey_question_editor#:#Listanézet survey#:#survey_question_obligatory#:#Ezt a kérdést kötelező megválaszolnia. survey#:#survey_question_pool#:#Kérdésgyűjtemény survey#:#survey_question_pool_title#:#Gyűjtemény címe -survey#:#survey_question_pool_usage#:#Kérdésgyűjtemény -survey#:#survey_question_pool_usage_active#:#Kérdésgyűjtemények használata -survey#:#survey_question_pool_usage_active_info#:#A kérdések felvehetőek kérdésgyűjteménybe, így a kérdések felhasználhatók más kérdőívekben is. -survey#:#survey_question_pool_usage_inactive#:#A kérdések közvetlenül a kérdőívben jönnek létre -survey#:#survey_question_pool_usage_inactive_info#:#A kérdések ehhez a kérdőívhez jönnek létre, de később kézileg kérdésgyűjteményhez adhatóak. survey#:#survey_question_title#:#Kérdéscím survey#:#survey_questions#:#Kérdések survey#:#survey_questions_to_clipboard_copy#:#Kérdés(ek) volt(ak) a vágólapra másolva. Válassza ki a célt, vagy ürítse a vágólapot. survey#:#survey_reached_level#:#Elért szint survey#:#survey_reminder_body#:#ezúton értesítjük, hogy a következő kérdőív kitöltését még nem fejezte be -survey#:#survey_reminder_cron#:#Remind users to participate###29 07 2022 new variable -survey#:#survey_reminder_cron_info#:#Ha be van kapcsolva, a felhasználóknak emlékeztetőt küldünk, hogy vegyenek részt a kérdőív kitöltésében. +survey#:#survey_reminder_cron#:#Felhasználók emlékeztetése a részvételre +survey#:#survey_reminder_cron_info#:#A felhasználóknak emlékeztetőt küldünk, hogy vegyenek részt a kérdőív kitöltésében. survey#:#survey_reminder_end#:#Záró időpont survey#:#survey_reminder_frequency#:#Gyakoriság survey#:#survey_reminder_frequency_days#:#Nap survey#:#survey_reminder_link#:#URL survey#:#survey_reminder_salutation#:#Tisztelt %s, -survey#:#survey_reminder_setting#:#Felhasználók emlékeztetése a résztvételre +survey#:#survey_reminder_setting#:#Felhasználók emlékeztetése a részvételre survey#:#survey_reminder_start#:#Kezdő időpont -survey#:#survey_reminder_subject#:#'%s' kérdőív még nem ért véget +survey#:#survey_reminder_subject#:#‘%s’ kérdőív még nem ért véget survey#:#survey_remove_competence#:#Kompetencia eltávolítása survey#:#survey_results_anonymization#:#Adatvédelem survey#:#survey_results_anonymized#:#Nevek nélküli / Anonimizált kérdőív -survey#:#survey_results_anonymized_info#:#A végeredmények megtekintésekor a válaszadók neve helyett egy kód jelenik meg, azaz a válaszadók személyei senki számára be nem azonosíthatóak. +survey#:#survey_results_anonymized_info#:#A végeredmények megtekintésekor a válaszadók neve helyett egy kód jelenik meg, azaz a válaszadók személyei senki számára be nem azonosíthatók. survey#:#survey_results_finished#:#Kérdőív befejezve survey#:#survey_results_not_started#:#A kérdőív nem indult el survey#:#survey_results_personalized#:#Nevekkel -survey#:#survey_results_personalized_info#:#A végeredmények megtekintésekor a válaszadók neve és válaszai megjelennek, azaz a válaszadók személyei a megfelelő jogosultsággal rendelkezők számára beazonosíthatóak. +survey#:#survey_results_personalized_info#:#A végeredmények megtekintésekor a válaszadók neve és válaszai megjelennek, azaz a válaszadók személyei a megfelelő jogosultsággal rendelkezők számára beazonosíthatók. Ez alacsony részvétel esetén a korlátozott hozzáféréssel rendelkezők is megtehetik. survey#:#survey_results_started#:#A kérdőív elindult survey#:#survey_show_blocktitle#:#Blokkcím megjelenítése -survey#:#survey_show_blocktitle_description#:#Ha be van kapcsolva, a blokkcím megjelenik a kérdőívben. +survey#:#survey_show_blocktitle_description#:#A blokkcím megjelenik a kérdőívben. survey#:#survey_skill#:#Kompetencia survey#:#survey_skill_assign#:#Kérdés/Kompetencia összerendelés survey#:#survey_skill_level#:#Kompetenciaszint @@ -16821,43 +16900,42 @@ survey#:#survey_skill_nr_q#:#Kérdések száma survey#:#survey_skill_thresholds#:#Kompetencia küszöbértékek survey#:#survey_start#:#Vissza a kezdőlapra survey#:#survey_sum_of_means#:#Számtani közepek összege -survey#:#survey_sure_delete_constraint#:#Biztos, hogy törli a(z) '%2$s' kérdés '%1$s' elágazási szabályát? +survey#:#survey_sure_delete_constraint#:#Biztos, hogy törli a(z) ‘%2$s’ kérdés ‘%1$s’ elágazási szabályát? survey#:#survey_sure_delete_questions#:#Biztos, hogy törli az alábbi kérdéseket vagy címsorokat? survey#:#survey_sync_insufficient_permissions#:#Nincs elegendő jogosultság survey#:#survey_sync_question_copies#:#Kérdésmásolatok szinkronizálása survey#:#survey_sync_question_copies_info#:#A kiválasztott kérdőívkérdések frissítése a gyűjteményben lévő jelenlegi változatra. survey#:#survey_sync_success#:#A kiválasztott kérdések frissültek. -survey#:#survey_up_to_x_points#:#x ponttól (alsó érték) survey#:#survey_use_start_button#:#A kérdőívbe lépéshez használja a kezdés gombot. survey#:#svy_activation_limited_visibility_info#:#Az adott időszakon kívül csak a kérdőív címe látható, kérdései nem érhetőek el. survey#:#svy_activation_online_info#:#Felhasználók csak akkor vehetnek részt a kérdőív kitöltésében, ha az online. -survey#:#svy_add_internal_user#:#Add User###29 07 2022 new variable -survey#:#svy_add_internal_user_info#:#The rater has a registered user on this platform.###29 07 2022 new variable -survey#:#svy_add_rater#:#Add Rater###29 07 2022 new variable -survey#:#svy_all_raters#:#All Raters###29 07 2022 new variable +survey#:#svy_add_internal_user#:#Felhasználó hozzáadása +survey#:#svy_add_internal_user_info#:#Az értékelőnek van ILIAS-fiókja. +survey#:#svy_add_rater#:#Értékelő hozzáadása +survey#:#svy_all_raters#:#Összes értékelő survey#:#svy_all_survey_competences#:#Összes kérdőív kompetencia survey#:#svy_all_user_data_deleted#:#Ehhez a kérdőívhez kapcsolódó összes felhasználói adatot sikeresen törölte. survey#:#svy_analysis#:#Analízis survey#:#svy_anonymous_participants#:#Válaszadók listája -survey#:#svy_anonymous_participants_info#:#Ha be van kapcsolva, a válaszadók listája bekapcsolható névtelen kérdőívekben. +survey#:#svy_anonymous_participants_info#:#A válaszadók listája bekapcsolható névtelen kérdőívekben. survey#:#svy_anonymous_participants_min#:#A válaszadók minimális száma survey#:#svy_anonymous_participants_min_info#:#A lista csak akkor lesz elérhető, ha a válaszadók száma meghaladja a minimálisat. survey#:#svy_anonymous_participants_svy#:#Válaszadók listája -survey#:#svy_anonymous_participants_svy_info#:#Ha be van kapcsolva, a válaszadók listája elérhető a záró időpont után. +survey#:#svy_anonymous_participants_svy_info#:#A válaszadók listája elérhető a záró időpont után. survey#:#svy_answer_too_long#:#Jelenlegi válasza túl hosszú (%s karakter), kérem, rövidítse válaszát. -survey#:#svy_app_see_rater_info#:#Appraisees can access rater information in the results screens, including names and e-mail addresses, if entered before when adding raters.###29 07 2022 new variable +survey#:#svy_app_see_rater_info#:#Az értékelők az eredményekkel együtt hozzáférhetnek az értékelői információkhoz, beleértve a neveket és az e-mail címeket, amennyiben azokat az értékelők megadták. survey#:#svy_appraisses_cannot_be_raters#:#A felhasználó nem adható hozzá értékelőnek. Használja inkább a kérdőív beállításaiban lévő önértékelés lehetőséget. survey#:#svy_back#:#Vissza survey#:#svy_categories#:#Válaszok survey#:#svy_check_evaluation_access_introduction#:#Mivel ez a kérdőíves kiértékelés csak a kérdőívben válaszadók számára elérhető, meg kell adnia kérdőív-hozzáférési kódját a kiértékelés megnyitásához. survey#:#svy_check_evaluation_authentication_needed#:#Azonosítás szükséges survey#:#svy_check_evaluation_wrong_key#:#Rossz kérdőív-hozzáférési kódot adott meg, vagy nem jogosult a kérdőív kitöltésére. Hozzáférését a kérdőív kiértékeléséhez elutasítottuk. -survey#:#svy_compress_view#:#Compressed View -survey#:#svy_compress_view_info#:#If activated, all single choice questions with similar scales will be presented matrix-like. +survey#:#svy_compress_view#:#Sűrített nézet +survey#:#svy_compress_view_info#:#Az összes, ugyanolyan válaszlehetőségekkel bíró egyszeres választásos kérdés matrixnézetben jelenik meg. survey#:#svy_copy#:#Kérdőív másolása survey#:#svy_create_question#:#Kérdés létrehozása survey#:#svy_delete_all_user_data#:#Összes felhasználói adat törlése -survey#:#svy_dont_send#:#Don't send a message###29 07 2022 new variable +survey#:#svy_dont_send#:#Ne küldjön üzenetet survey#:#svy_eval_captions#:#Ábrák survey#:#svy_eval_captions_abs#:#Abszolút survey#:#svy_eval_captions_abs_perc#:#Abszolút és százalék @@ -16865,12 +16943,12 @@ survey#:#svy_eval_captions_perc#:#Százalék survey#:#svy_eval_competences#:#Kompetencia végeredmények survey#:#svy_eval_cumulated#:#Áttekintés survey#:#svy_eval_detail#:#Részletek -survey#:#svy_eval_skipped_value#:#Végeredmények: 'kihagyott' +survey#:#svy_eval_skipped_value#:#Végeredmények: ‘kihagyott’ survey#:#svy_eval_skipped_value_custom#:#Egyéni érték használata survey#:#svy_eval_skipped_value_custom_info#:#A kihagyott válaszok esetére adjon meg bármilyen értéket vagy hagyja üresen survey#:#svy_eval_skipped_value_custom_value#:#Érték survey#:#svy_eval_skipped_value_lng#:#Alapértelmezett bejegyzés használata -survey#:#svy_eval_skipped_value_lng_info#:#Jelenlegi értéke: '%s' +survey#:#svy_eval_skipped_value_lng_info#:#Jelenlegi értéke: ‘%s’ survey#:#svy_eval_user#:#válaszadónként survey#:#svy_eval_view#:#Megjelenítés survey#:#svy_eval_view_charts#:#Diagram @@ -16882,48 +16960,46 @@ survey#:#svy_evaluation_access_participants_info#:#Az összes válaszadó a kér survey#:#svy_export_files#:#Exportfájlok survey#:#svy_export_format#:#Kérdőív adatainak exportálása mint survey#:#svy_export_pdf#:#Exportálás PDF-ként -survey#:#svy_ext_rater_firstname#:#First name of external rater###29 07 2022 new variable -survey#:#svy_ext_rater_lastname#:#Last name of external rater###29 07 2022 new variable -survey#:#svy_external_rater#:#Add External Rater###29 07 2022 new variable -survey#:#svy_external_rater_info#:#The rater is not registered on this platform.###29 07 2022 new variable +survey#:#svy_ext_rater_firstname#:#A külső értékelő családneve +survey#:#svy_ext_rater_lastname#:#A külső értékelő utóneve +survey#:#svy_external_rater#:#Külső értékelő hozzáadása +survey#:#svy_external_rater_info#:#Az értékelőnek nincs ILIAS-fiókja. survey#:#svy_fraction_of_selections#:#Kiválasztások aránya survey#:#svy_gap_analysis#:#Gap analízis (rés elemzés) survey#:#svy_general_properties#:#Általános tulajdonságok survey#:#svy_import_codes#:#Kódok importálása -survey#:#svy_import_codes_info#:#Az importáláshoz szükséges egy '%s' export fájl. -survey#:#svy_ind_feedb_info#:#Users get distinct evaluations by others.###29 07 2022 new variable -survey#:#svy_ind_feedb_mode#:#Individual Feedback###29 07 2022 new variable -survey#:#svy_mail_confirmation_subject#:#'%s' kérdőív kitöltéséről -survey#:#svy_mail_context_rater_invitation_info#:#Invite raters to participate in a survey.###29 07 2022 new variable -survey#:#svy_mail_context_rater_invitation_survey_title#:#Survey Title###29 07 2022 new variable -survey#:#svy_mail_context_rater_invitation_title#:#Survey: Rater Invitation###29 07 2022 new variable -survey#:#svy_mail_context_reminder_info#:#Emlékeztető felhasználóknak kérdőívben való résztvételre +survey#:#svy_import_codes_info#:#Az importáláshoz szükséges egy ‘%s’ export fájl. +survey#:#svy_ind_feedb_info#:#A felhasználók külön-külön kapnak visszajelzést a többiektől. +survey#:#svy_ind_feedb_mode#:#Egyéni visszajelzés +survey#:#svy_mail_confirmation_subject#:#‘%s’ kérdőív kitöltéséről +survey#:#svy_mail_context_rater_invitation_info#:#Értékelők meghívása a kérdőívbe. +survey#:#svy_mail_context_rater_invitation_survey_title#:#Kérdőív címe +survey#:#svy_mail_context_rater_invitation_title#:#Kérdőív: Értékelők meghívása +survey#:#svy_mail_context_reminder_info#:#Emlékeztető felhasználóknak kérdőívben való részvételre survey#:#svy_mail_context_reminder_survey_title#:#Kérdőív címe survey#:#svy_mail_context_reminder_title#:#Kérdőív: kérdőív-emlékeztető -survey#:#svy_mail_own_results#:#Válaszaim küldése levélben survey#:#svy_mail_own_results_body#:#a következő kérdőívben adott válaszokat: -survey#:#svy_mail_own_results_subject#:#'%s' kérdőívre adott válaszai +survey#:#svy_mail_own_results_subject#:#‘%s’ kérdőívre adott válaszai survey#:#svy_mail_send_confirmation#:#A kitöltésről e-mail küldése survey#:#svy_matrix_layout_percentages_sum_invalid#:#Az oszlopbeállítások összege nem 100%. -survey#:#svy_max_sum_score#:#Maximum Sum Score -survey#:#svy_neutral_answer#:#Szöveg semleges válaszhoz ('Nem meghatározott', 'Nem tudom' stb.) -survey#:#svy_no_appraisees_found#:#No appraisees with feedbacks found.###26 08 2024 new variable -survey#:#svy_notification_tutor_results#:#Egy e-Mail a kérdőív eredményeivel +survey#:#svy_max_sum_score#:#Összpontszám maximális értéke +survey#:#svy_neutral_answer#:#Szöveg semleges válaszhoz (‘Nem meghatározott’, ‘Nem tudom’ stb.) +survey#:#svy_no_appraisees_found#:#Egy értékelendő személy sem kapott még visszajelzést +survey#:#svy_notification_tutor_results#:#Egy e-mail a kérdőív eredményeivel survey#:#svy_notification_tutor_results_alert#:#Adjon meg záró dátumot. survey#:#svy_notification_tutor_results_info#:#A feladatütemező el fogja küldeni csatolmányként a kérdőív részletes eredményeit a záró dátumkor. -survey#:#svy_only_max_one_external_rater#:#Please select only one external rater.###29 07 2022 new variable -survey#:#svy_page_add_question#:#Új %s létrehozása +survey#:#svy_only_max_one_external_rater#:#Csak egy külső értékelőt válasszon. survey#:#svy_page_error#:#Egy kérdés megválaszolásakor egy hiba jelentkezett. További információért keresse meg a kérdést! survey#:#svy_page_errors#:#Kérdések megválaszolásakor hibák jelentkeztek. További információért keresse meg a kérdéseket! survey#:#svy_participant#:#Résztvevő -survey#:#svy_participants#:#Participants###26 08 2024 new variable -survey#:#svy_participation#:#Résztvétel -survey#:#svy_please_select_unused_codes#:#Please select at least one unused code.###26 08 2024 new variable +survey#:#svy_participants#:#Résztvevők +survey#:#svy_participation#:#Részvétel +survey#:#svy_please_select_unused_codes#:#Válasszon egy, még el nem használt kódot. survey#:#svy_print_hide_labels#:#Címkék elrejtése survey#:#svy_print_show_labels#:#Címkék megjelenítése -survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable -survey#:#svy_rater#:#Rater###29 07 2022 new variable -survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable +survey#:#svy_privacy_info#:#Adatvédelem +survey#:#svy_rater#:#Értékelő +survey#:#svy_rater_see_app_info#:#A válaszadók neveit megjelenítjük az értékelőknek, hogy ki tudják értékelni a kérdéseket. survey#:#svy_reminder_mail_template#:#Levélsablon survey#:#svy_reminder_mail_template_none#:#Ne használjon levélsablont survey#:#svy_result_mail_notification_info#:#A kérdőív befejezésekor mindegyik válaszadó válaszát elküldjük a megadott címekre. @@ -16932,41 +17008,39 @@ survey#:#svy_results_mail_confirm#:#A válaszadók e-mailt kérhetnek survey#:#svy_results_mail_confirm_info#:#A válaszadók e-mailt kérhetnek kitöltésükről a kérdőív végén. survey#:#svy_results_mail_own#:#A válaszok belefoglalása survey#:#svy_results_mail_own_info#:#A válaszok kerüljenek bele az e-mailbe. -survey#:#svy_results_view_own#:#Válaszadók megnézhetik saját válaszaikat -survey#:#svy_results_view_own_info#:#A válaszadók a kérdőívkitöltés végén saját válaszaikat megjeleníthetik, de nem módosíthatják. -survey#:#svy_save_and_continue#:#Save and Continue###29 07 2022 new variable +survey#:#svy_save_and_continue#:#Mentés és folytatás survey#:#svy_save_sync#:#Mentés és kérdésmásolatok szinkronizálása -survey#:#svy_search_user#:#Search User###29 07 2022 new variable -survey#:#svy_search_user_info#:#Search for users or roles and pick participants.###29 07 2022 new variable +survey#:#svy_search_user#:#Felhasználó keresése +survey#:#svy_search_user_info#:#Felhasználók, illetve szerepkörök keresése és résztvevők kiválasztása. survey#:#svy_search_users#:#Válaszadók keresése -survey#:#svy_select_rater#:#Select Rater###29 07 2022 new variable -survey#:#svy_selected_user_data_deleted#:#A kiválasztott felhasználó(k) kérdőívadatai sikeresen törlődtek. +survey#:#svy_select_rater#:#Értékelők keresése +survey#:#svy_selected_user_data_deleted#:#A kiválasztott felhasználó(k) kérdőívadatait sikeresen törlölte. survey#:#svy_self_ev_access_results_all#:#Összes résztvevő önértékeléseinek elérése survey#:#svy_self_ev_access_results_none#:#Nincs hozzáférés az eredményekhez survey#:#svy_self_ev_access_results_own#:#Saját önértékelések elérése -survey#:#svy_self_ev_info#:#Önértékelésre használva. +survey#:#svy_self_ev_info#:#Egy kérdőív, ami önértékelésre használható. survey#:#svy_self_ev_mode#:#Csak önértékelés survey#:#svy_settings_section_access#:#Kérdőív kezelése: Hozzáférés -survey#:#svy_settings_section_before_start#:#Kérdőív kezdése előtti információ +survey#:#svy_settings_section_before_start#:#Kérdőív kezdése előtt megjelenő információ survey#:#svy_settings_section_finishing#:#Kérdőív befejezése survey#:#svy_settings_section_question_behaviour#:#Kérdőív kezelése: A kérdés viselkedése survey#:#svy_settings_section_reminders#:#Emlékeztetők survey#:#svy_show_questiontitles#:#Kérdéscím megjelenítése survey#:#svy_skl_comp_assignm_not_supported#:#Kompetencia összerendelés nem támogatott ebben a kérdéstípusban. -survey#:#svy_sum_score#:#Sum Score -survey#:#svy_type_of_rater#:#Type of Rater###29 07 2022 new variable +survey#:#svy_sum_score#:#Összpontszám +survey#:#svy_type_of_rater#:#Értékelők típusa survey#:#svy_view_own_results#:#Válaszaim megtekintése -survey#:#svy_wrong_or_expired_code#:#Sorry, you entered an invalid or expired code.###26 08 2024 new variable -survey#:#text_maximum_chars_allowed#:#Ne adjon meg több mint %s karaktert! Az efölötti karakterek nem kerülnek tárolásra. +survey#:#svy_wrong_or_expired_code#:#Lejárt vagy érvénytelen kódot adott meg. +survey#:#text_maximum_chars_allowed#:#Ne adjon meg több, mint %s karaktert! Ha túllépi ezt a korlátot, a válaszát nem rögzítjük, a folytatáshoz le kell rövidítenie. survey#:#text_question_not_filled_out#:#Töltse ki a válaszmezőt! -survey#:#unfold#:#Szétbontás +survey#:#unfold#:#Kérdésblokk szétbontás survey#:#upper_limit#:#Felső határ survey#:#use_anonymous_id#:#Válaszadókód megjelenítése -survey#:#use_anonymous_id_desc#:#Anonimizált kérdőívekben a válaszadók 'Anonymous' helyett egy kódként jelenjenek meg. +survey#:#use_anonymous_id_desc#:#Anonimizált kérdőívben a résztvevők hozzáférési kódjait használjuk felhasználónevük helyett. Ha nincs bepipálva, a felhasználónevek helyett a ‘Névtelen’ felirat jelenik meg. survey#:#use_browser_print_function#:#Használja a böngészője nyomtatási funkcióját! -survey#:#use_min_answers#:#Válaszok száma -survey#:#use_min_answers_option#:#Kijelölendő válaszok számának beállítása -survey#:#use_other_answer#:#Egyéb válasz (szabadszöveges) +survey#:#use_min_answers#:#Válaszok elvárt száma +survey#:#use_min_answers_option#:#Kijelölendő válaszok számának (minimum, maximum) beállítása +survey#:#use_other_answer#:#Szabadszöveges válasz survey#:#used#:#használt survey#:#users_answered#:#Válaszoltak survey#:#users_invited#:#%s felhasználót meghívta @@ -16974,46 +17048,46 @@ survey#:#users_skipped#:#Kihagyták survey#:#values#:#Értékek survey#:#vertical#:#Függőleges survey#:#warning_question_not_complete#:#Nem teljes a kérdés. -survey#:#workingtime#:#Munkaidő -svy#:#survey_360_appraisees_remind_info#:#Ha az önértékelés be van kapcsolva, értesítjük a saját magukat nem értékelt személyeket. +survey#:#workingtime#:#Eltöltött idő +svy#:#survey_360_appraisees_remind_info#:#Ha az ‘Önértékelés’ be van kapcsolva, értesítjük a saját magukat nem értékelt személyeket, hogy tegyék meg. svy#:#survey_360_raters_remind_info#:#Emlékeztetni fogjuk azokat az értékelőket, akik még nem fejezeték be a kérdőívet. -svy#:#svy_0_open_appraisees#:#You cannot perform the survey for any appraisee anymore.###28 10 2024 new variable -svy#:#svy_all_pages#:#All Pages###29 07 2022 new variable -svy#:#svy_all_participants#:#All Participants###29 07 2022 new variable -svy#:#svy_all_questions#:#All Questions###29 07 2022 new variable -svy#:#svy_code#:#Access Code###28 10 2024 new variable +svy#:#svy_0_open_appraisees#:#Nincs több értékelendője, értékelést már nem adhat le ebben a kérdőívben. +svy#:#svy_all_pages#:#Összes oldal +svy#:#svy_all_participants#:#Összes résztvevő +svy#:#svy_all_questions#:#Összes kérdés +svy#:#svy_code#:#Hozzáférési kód svy#:#svy_codes#:#Hozzáférési kódok -svy#:#svy_current_page#:#Current Page###29 07 2022 new variable -svy#:#svy_finish_survey#:#'%1' kérdőív befejezése -svy#:#svy_finished_x_appraisees#:#You have finished the survey for %s appraisee(s).###28 10 2024 new variable -svy#:#svy_information#:#Information###28 10 2024 new variable -svy#:#svy_invite_participants#:#Résztvevők meghívása -svy#:#svy_link_to_svy#:#Link to Survey###26 08 2024 new variable +svy#:#svy_current_page#:#Jelenlegi oldal +svy#:#svy_finish_survey#:#‘%1’ kérdőívben részvétel +svy#:#svy_finished_x_appraisees#:#%s értékelendő esetében már befejezet a kérdőívet. +svy#:#svy_information#:#Információ +svy#:#svy_invite_participants#:#Résztvevők feladatához hozzáadás +svy#:#svy_link_to_svy#:#Kérdőívre mutató link svy#:#svy_part_overview#:#Áttekintés -svy#:#svy_placeholders_label#:#Available Placeholders###26 08 2024 new variable -svy#:#svy_print_selection#:#Print View Selection###29 07 2022 new variable +svy#:#svy_placeholders_label#:#Elérhető helyettesítő karakterek +svy#:#svy_print_selection#:#Nyomtatási nézet választása svy#:#svy_remove_all_participants#:#Összes résztvevő eltávolítása svy#:#svy_remove_participants#:#Résztvevő eltávolítása -svy#:#svy_selected_participants#:#Selected Participants###29 07 2022 new variable -svy#:#svy_selected_questions#:#Selected Questions###29 07 2022 new variable -svy#:#svy_selection#:#Selection###29 07 2022 new variable +svy#:#svy_selected_participants#:#Kiválasztott résztvevők +svy#:#svy_selected_questions#:#Kiválasztott kérdések +svy#:#svy_selection#:#Kiválasztás svy#:#svy_status#:#Állapot svy#:#svy_status_finished#:#Befejezve svy#:#svy_status_in_progress#:#Folyamatban -svy#:#svy_status_invited#:#Meghívva -svy#:#svy_user_added_appraisee#:#Survey '%1'###26 08 2024 new variable -svy#:#svy_user_added_appraisee_close_mail#:#The survey has been closed for your raters.###26 08 2024 new variable -svy#:#svy_user_added_appraisee_mail#:#You have been added to the survey as an appraisee.###26 08 2024 new variable -svy#:#svy_user_added_rater#:#Survey '%1'###26 08 2024 new variable -svy#:#svy_user_added_rater_mail#:#You have been added as a rater to the survey.###26 08 2024 new variable -svy#:#svy_user_added_rater_reminder_mail#:#Please finish to rate the following appraisees:###26 08 2024 new variable -svy#:#svy_user_not_found#:#User not found.###26 08 2024 new variable -svy#:#svy_users_invited#:#A felhasználókat sikeresen meghívta. -svy#:#svy_x_appraisees_closed_for_raters#:#%s appraisee(s) has/have closed the survey for raters.###28 10 2024 new variable -svy#:#svy_x_open_appraisees#:#%s appraisee(s) are open for you to rate.###28 10 2024 new variable -svy#:#svy_your_appraisees#:#Your Appraisees###28 10 2024 new variable -svy#:#svy_your_raters#:#Your Raters###28 10 2024 new variable -svy#:#svy_your_raters_finished#:#%s of your raters have finished the survey.###28 10 2024 new variable +svy#:#svy_status_invited#:#Sikeresen hozzáadta a feladatokhoz +svy#:#svy_user_added_appraisee#:#‘%1’ kérdőív +svy#:#svy_user_added_appraisee_close_mail#:#A kérdőív lezárult az értékelők számára. +svy#:#svy_user_added_appraisee_mail#:#ezúton értesítjük, hogy értékelendő személynek hozzáadták a kérdőívhez. +svy#:#svy_user_added_rater#:#‘%1’ kérdőív +svy#:#svy_user_added_rater_mail#:#ezúton értesítjük, hogy értékelő személynek hozzáadták a kérdőívhez. +svy#:#svy_user_added_rater_reminder_mail#:#Kérem, fejezze be a következő értékeléseket: +svy#:#svy_user_not_found#:#A felhasználó nem található. +svy#:#svy_users_invited#:#A felhasználók Műszerfaluk ‘Feladatok’ részéhez hozzáadtuk egy ‘teendő’ részt, amely értesíti őket arról, hogy részt vehetnek ebben a kérdőívben. +svy#:#svy_x_appraisees_closed_for_raters#:#%s értékelendő már lezárta a kérdőívet az értékelők előtt. +svy#:#svy_x_open_appraisees#:#%s értékelendője vár az Ön értékelésére. +svy#:#svy_your_appraisees#:#Értékelendőim +svy#:#svy_your_raters#:#Értékelőim +svy#:#svy_your_raters_finished#:#Az értékelőiből %s fejezte be a kérdőívet. sysc#:#sysc_action_list_tree#:#Tartalomtárfa-lenyomat létrehozása sysc#:#sysc_action_repair#:#Javítás sysc#:#sysc_action_show_tree#:#Tartalomtárfa-lenyomat megjelenítése @@ -17023,7 +17097,7 @@ sysc#:#sysc_btn_tree_missing#:#Hiányzók visszaállítása sysc#:#sysc_btn_tree_structure#:#Fastruktúra újralétrehozása sysc#:#sysc_completed_num#:#Elvégzett feladatok sysc#:#sysc_cron_empty_trash#:#Lomtár ürítése -sysc#:#sysc_cron_empty_trash_desc#:#Ha be van kapcsolva, a lomtárat ürítjük a megfelelő feltételek alapján (életkor, objektumtípus vagy objektumok maximális száma). +sysc#:#sysc_cron_empty_trash_desc#:#A lomtárat ürítjük a megfelelő feltételek alapján (életkor, objektumtípus vagy objektumok maximális száma). sysc#:#sysc_failed_num#:#El nem végzett feladatok sysc#:#sysc_groups#:#Rendszerellenőrzési csoportok sysc#:#sysc_grp_tree#:#Tartalomtár @@ -17057,32 +17131,32 @@ sysc#:#sysc_trash_limit_type#:#Típuskorlát sysc#:#sysc_trash_remove#:#Törölt objektumok végleges eltávolítása sysc#:#sysc_trash_remove_info#:#Törölt (lomtárban lévő) objektumok végleges eltávolítása a rendszerből sysc#:#sysc_trash_restore#:#Törölt objektumok visszaállítása -sysc#:#sysc_trash_restore_info#:#A lomtárban lévő törölt objektumok visszaállítása és 'Helyreállított objektumok'-ba helyezése +sysc#:#sysc_trash_restore_info#:#A lomtárban lévő törölt objektumok visszaállítása és ‘Helyreállított objektumok’-ba helyezése sysc#:#sysc_tree_duplicate_failures#:#Duplikált bejegyzéseket találtunk a Tartalomtár faszerkezetében. Duplikált bejegyzések száma: sysc#:#sysc_tree_list_failures#:#A Tartalomtár falenyomatát létrehoztuk. Hibák száma a Tartalomtár szerkezetében: sysc#:#sysc_tree_missing_failures#:#Hiányzó bejegyzéseket találtunk a Tartalomtár faszerkezetében. Hiányzó bejegyzések száma: sysc#:#sysc_tree_structure_failures#:#Fastruktúra hibáinak száma (szülőkapcsolat): -tagging#:#no_tag_text_1#:#You have not yet used any tags. To do this, you must take two steps:###29 07 2022 new variable -tagging#:#no_tag_text_2#:#Click on '%s' and select a learning object from the available offer, e.g. a learning module or a forum.###29 07 2022 new variable -tagging#:#no_tag_text_3#:#To attach any tags to the object select 'Set Tags' from the actions menu.###29 07 2022 new variable +tagging#:#no_tag_text_1#:#Eddig még egy címkét sem használt, ezért tegye a következőket: +tagging#:#no_tag_text_2#:#Kattintson %s kiindulópontra és válasszon egy tanulási objektumot a lehetségesek közül, például egy tananyagot vagy egy fórumot. +tagging#:#no_tag_text_3#:#Tetszőleges címke objektumhoz rendeléséhez válassza a ‘Címkék’ lehetőséget a műveletek menüből. tagging#:#tag_remove_tags_of_obj_without_access#:#Címke eltávolítása tagging#:#tag_some_obj_tagged_without_access#:#Nincs többé jogosultsága néhány címkével ellátott objektum eléréséhez. Eltávolítja ezekről objektumokról a címkéket? tagging#:#tag_tags_deleted#:#A címkét sikeresen eltávolította az elérhetetlen objektumokról. tagging#:#tagging_all_users#:#Az összes felhasználó címkéje tagging#:#tagging_edit_settings#:#Beállítások módosítása tagging#:#tagging_enable_all_users#:#Minden felhasználó címkéjének megjelenítése -tagging#:#tagging_enable_all_users_info#:#A Tartalomtár objektumainak 'Információ' lapján létrejön a 'Címkék' rész alatt egy 'Az összes felhasználó címkéje' alrész, ahol megjelenik az összes felhasználó objektumhoz létrehozott címkéi. +tagging#:#tagging_enable_all_users_info#:#A Tartalomtár objektumainak ‘Információ’ lapján létrejön a ‘Címkék’ rész alatt egy ‘Az összes felhasználó címkéje’ alrész, ahol megjelenik az összes felhasználó objektumhoz létrehozott címkéi. tagging#:#tagging_enable_tagging#:#Címkézés engedélyezése tagging#:#tagging_forbidden_tags#:#Tiltott címkék -tagging#:#tagging_no_obj_for_tag#:#No Resources tagged with %s.###29 07 2022 new variable -tagging#:#tagging_no_perm_write#:#You have no permission to change this data.###28 10 2024 new variable +tagging#:#tagging_no_obj_for_tag#:#Egy erőforrásnak sincs címkéjé: %s. +tagging#:#tagging_no_perm_write#:#Nincs jogosultsága az adatot módosítani. tagging#:#tagging_other_users#:#Más felhasználók címkéi tagging#:#tagging_resources_for_tag#:#Források ezzel a címkével: %s tagging#:#tagging_search_users#:#Felhasználók keresése tagging#:#tagging_set_tag#:#Címkék tagging#:#tagging_settings#:#Beállítások tagging#:#tagging_tag#:#Címke -tagging#:#tagging_tag_info#:#Címkék felvételéhez nyissa meg egy objektum 'Információ' lapját. +tagging#:#tagging_tag_info#:#Címkék felvételéhez nyissa meg egy objektum ‘Információ’ lapját. tagging#:#tagging_tags#:#Címkék tagging#:#tagging_users_using_tag#:#Felhasználók, akik a címkét használják task#:#task_deadline#:#Vége @@ -17119,40 +17193,46 @@ tax#:#tax_tax_settings#:#Taxonómia beállításai tax#:#tax_taxonomy#:#Taxonómia tbl#:#tbl_export_csv#:#Exportálás vesszővel tagolt (.csv) fájlba tbl#:#tbl_export_excel#:#Exportálás Excel (.xlsx) fájlba -tos#:#tos_accept_usr_agreement_anonymous#:#Terms of Service###26 08 2024 new variable -tos#:#tos_accept_usr_agreement_anonymous_intro#:#Before you proceed to ILIAS you accept the following Terms of Service.###26 08 2024 new variable -tos#:#tos_account_reg_not_possible#:#Nem regisztrálhatja saját magát, mert hiányzik a szolgáltatási feltételek. További információkért vegye fel a kapcsolatot a rendszerüzemeltetőkkel. -tos#:#tos_agree_date#:#ToS agreed on###26 08 2024 new variable +tbl#:#tbl_selection#:#Kiválasztás +tbl#:#tbl_template_create#:#Jelenlegi nézet mentése +tbl#:#tbl_template_created#:#Ezt a nézetet sikeresen mentette. +tbl#:#tbl_template_delete#:#Mentett nézet törlése +tbl#:#tbl_template_deleted#:#A mentett nézetet sikeresen törölte. +tbl#:#tbl_templates#:#Nézet +tos#:#tos_accept_usr_agreement_anonymous#:#Szolgáltatási feltételek +tos#:#tos_accept_usr_agreement_anonymous_intro#:#Mielőtt továbblép az ILIAS-hoz, elfogadja az alábbi Szolgáltatási feltételeket +tos#:#tos_account_reg_not_possible#:#Nem regisztrálhatja saját magát, mert hiányzik a Szolgáltatási feltételek. További információkért vegye fel a kapcsolatot a rendszerüzemeltetőkkel. +tos#:#tos_agree_date#:#Elfogadás időpontja tos#:#tos_agreement#:#Szolgáltatási feltételek tos#:#tos_disabled_no_docs_left#:#A felhasználási feltételeket kikapcsoltuk, mert az összes dokumentumot letörölték. Legalább egy dokumentumot hozzon létre a felhasználási feltételek újbóli bekapcsolása előtt. -tos#:#tos_last_reset_date#:#A szolgáltatási feltételek reszetelve: %s. -tos#:#tos_never_reset#:#A szolgáltatási feltételeket még sosem reszetelték. +tos#:#tos_last_reset_date#:#A szolgáltatási feltételek alapértékre állítva: %s. +tos#:#tos_never_reset#:#A Szolgáltatási feltételeket még sosem állították még alapértékre. tos#:#tos_no_documents_exist#:#Jelenleg egy telepített nyelvhez sincs szolgáltatási feltétel. tos#:#tos_no_documents_exist_cant_save#:#Jelenleg egy telepített nyelvhez sincs szolgáltatási feltétel. Kérem, legalább egy nyelvhez hozzon létre. -tos#:#tos_reset_for_all_users#:#Reset Terms of Service###26 08 2024 new variable -tos#:#tos_reset_successful#:#Szolgáltatási feltételeket sikeresen reszetelte. -tos#:#tos_status_desc#:#Ha be van kapcsolva, a felhasználóknak az ILAS-ba belépés előtt el kell fogadniuk a Szolgáltatási feltételeket. +tos#:#tos_reset_for_all_users#:#Szolgáltatási feltételek elfogadásainak törlése +tos#:#tos_reset_successful#:#Szolgáltatási feltételek elfogadásait sikeresen törölte. +tos#:#tos_status_desc#:#A felhasználóknak az ILAS-ba belépés előtt el kell fogadniuk a Szolgáltatási feltételeket. tos#:#tos_status_enable#:#Engedélyezés tos#:#tos_sure_reset_tos#:#Biztos, hogy törli az összes felhasználó Szolgáltatási feltételeit? Ez azokra a fiókokra is hatással van, melyeket SOAP webszolgáltatások, a csevegőszerver, vagy az ütemezett feladatok használnak. tos#:#tos_withdrawal_usr_deletion#:#ILIAS-fiók törlése a Szolgáltatási feltételek elutasítás esetén -tos#:#tos_withdrawal_usr_deletion_desc#:#If a user withdraws their acceptance from a previously accepted Terms of Service document, this will result in the deletion of the user’s account.###26 08 2024 new variable -trac#:#cmix_lp_mode_deactivated#:#Learning Progress is Deactivated -trac#:#cmix_lp_mode_deactivated_info#:#The learning progress status is not displayed and does not influence parent objects. -trac#:#cmix_lp_mode_when_completed#:#Completed when 'completed' -trac#:#cmix_lp_mode_when_completed_info#:#ILIAS status 'completed' is set when verb of last relevant xAPI-Statement is 'completed'. -trac#:#cmix_lp_mode_when_passed#:#Completed when 'passed' -trac#:#cmix_lp_mode_when_passed_info#:#ILIAS status 'completed' is set when verb of last relevant xAPI-Statement is 'passed' or 'satisfied'. -trac#:#cmix_lp_mode_when_passed_or_completed#:#Completed when passed or completed -trac#:#cmix_lp_mode_when_passed_or_completed_info#:#ILIAS status 'completed' is set when verb of last relevant xAPI-Statement is 'completed' or 'passed' or 'satisfied'. +tos#:#tos_withdrawal_usr_deletion_desc#:#Ha egy felhasználó visszavonja egy korábbi Szolgáltatási feltételek elfogadását, az ILIAS-fiókja törlését vonja maga után. +trac#:#cmix_lp_mode_deactivated#:#A tanulási haladás ki van kapcsolva +trac#:#cmix_lp_mode_deactivated_info#:#A tanulási haladás állapota nem jelenik meg és nincs hatással a szülőobjektumokra. +trac#:#cmix_lp_mode_when_completed#:#Sikeresen teljesített amikor ‘befejezte’ +trac#:#cmix_lp_mode_when_completed_info#:#A ‘befejezte’ ILIAS állapotot akkor állítjuk be, amikor az utolsó releváns xAPI-Nyilatkozat értéke ‘befejezte’. +trac#:#cmix_lp_mode_when_passed#:#Sikeresen teljesített amikor ‘sikeresen teljesítette’ +trac#:#cmix_lp_mode_when_passed_info#:#A ‘befejezte’ ILIAS állapotot akkor állítjuk be, amikor az utolsó releváns xAPI-Nyilatkozat értéke ‘sikeresen teljesítette’ vagy ‘elégedett’. +trac#:#cmix_lp_mode_when_passed_or_completed#:#Sikeresen teljesített amikor ‘sikeresen teljesítette’ vagy ‘befejezte’ +trac#:#cmix_lp_mode_when_passed_or_completed_info#:#A ‘befejezte’ ILIAS állapotot akkor állítjuk be, amikor az utolsó releváns xAPI-Nyilatkozat értéke ‘befejezte’ vagy ‘sikeresen teljesítette’ vagy ‘elégedett’. trac#:#cmix_lp_mode_with_failed#:#Also consider failed -trac#:#cmix_lp_mode_with_failed_info#:#The status could be 'failed' instead of 'in progress'. +trac#:#cmix_lp_mode_with_failed_info#:#Az állapot legyen ‘nem teljesítette’ a ‘folyamatban’ helyett. trac#:#create_date_max#:#Legkésőbbi regisztráció trac#:#create_date_min#:#Legkorábbi regisztráció trac#:#info_valid_request#:#A maximális érvényességi idő egy felhasználó két kérése között. trac#:#meta_typical_learning_time#:#Szokásos tanulási idő trac#:#obj_types#:#Objektumtípusok -trac#:#personal_learning_progress_view_description#:#Ongoing courses with membership###29 10 2025 new variable -trac#:#personal_learning_progress_view_title#:#Your Learning Progress###29 10 2025 new variable +trac#:#personal_learning_progress_view_description#:#Futó kurzusok tagsággal +trac#:#personal_learning_progress_view_title#:#Személyes tanulási haladásom trac#:#read_count_avg#:#Átlag lapmegtekintés trac#:#registration_filter#:#Regisztráció dátuma trac#:#search_area_info#:#Válasszon egy objektumot. @@ -17161,7 +17241,7 @@ trac#:#session_statistics#:#Munkamenet-statisztikák trac#:#trac_aggregation#:#Aggregálás trac#:#trac_all#:#Összes trac#:#trac_anonymized#:#Anonimizált -trac#:#trac_anonymized_info#:#Ha be van kapcsolva, az adatok nem köthetőek személyhez (így például az objektumteljesítés és a tanulási haladás állapota között nem lehet kapcsolat). +trac#:#trac_anonymized_info#:#Az adatok nem köthetőek személyhez (így például az objektumteljesítés és a tanulási haladás állapota között nem lehet kapcsolat). trac#:#trac_anonymized_info_short#:#(Anonimizált) trac#:#trac_assigned#:#Hozzárendelve trac#:#trac_average#:#Átlag @@ -17179,35 +17259,35 @@ trac#:#trac_collection_tlt_learner_info#:#Erre az objektumra a tanulási haladá trac#:#trac_collection_tlt_learner_subitem#:#Eltöltött / szükséges: %s / %s (%s%%). trac#:#trac_comment#:#Észrevétel trac#:#trac_completed#:#Teljesített -trac#:#trac_cron_info#:#Adatgyűjtéshez kapcsolja be az 'Objektumstatisztikák' ütemezett feladatot. +trac#:#trac_cron_info#:#Adatgyűjtéshez kapcsolja be az ‘Objektumstatisztikák’ ütemezett feladatot. trac#:#trac_crs_objects#:#Kurzusrésztvevők trac#:#trac_current#:#Jelenleg trac#:#trac_current_system_load#:#Jelenlegi rendszerterhelés trac#:#trac_data_deleted#:#Az adatokat sikeresen törölte. -trac#:#trac_defaults#:#Befejezési állapot +trac#:#trac_defaults#:#Teljesítettségi állapot trac#:#trac_defaults_inactive#:#Inaktív -trac#:#trac_defaults_info#:#Teljesítettségi állapot meghatározásának módja támogatott objektumtípusok esetén. Több érdemérem-típus, illetve tanúsítvány használja. +trac#:#trac_defaults_info#:#Meghatározza, hogy hogyan történjen a következő objektumtípusok teljesítési állapotának meghatározása, amikor egy kurzus vagy csoport elemeként használják őket. Több érdemérem-típus, illetve a tanúsítvány használja ezt. trac#:#trac_delete_data#:#Adatok törlése trac#:#trac_determines_learning_progress#:#Meghatározza-e a tanulási haladást -trac#:#trac_edit_collection#:#Itt találhatóak a tanulási haladást meghatározó objektumok. +trac#:#trac_edit_collection#:#Itt találhatók a tanulási haladást meghatározó objektumok. trac#:#trac_end_at#:#Záró dátum trac#:#trac_failed#:#Sikertelen trac#:#trac_figure#:#Mutatószám trac#:#trac_filter_area#:#Terület -trac#:#trac_filter_has_status#:#'Nem próbálkozott' állapotúak is +trac#:#trac_filter_has_status#:#‘Nem próbálkozott’ állapotúak is trac#:#trac_filter_hidden#:#Rejtett trac#:#trac_first_access#:#Első hozzáférés trac#:#trac_first_and_last_access#:#Első és utolsó hozzáférés -trac#:#trac_frm_contribution_num_postings#:#Minimum number of Postings###29 07 2022 new variable -trac#:#trac_frm_contribution_num_postings_info_p#:#%s: %s Posts###26 08 2024 new variable -trac#:#trac_frm_contribution_num_postings_info_s#:#%s: %s Post###26 08 2024 new variable +trac#:#trac_frm_contribution_num_postings#:#Hozzászólások minimális száma +trac#:#trac_frm_contribution_num_postings_info_p#:#%s: %s hozzászólás +trac#:#trac_frm_contribution_num_postings_info_s#:#%s: %s hozzászólás trac#:#trac_group_materials#:#Választható anyagok csoportosítása trac#:#trac_group_materials_save#:#Kötelező segédanyagok számának mentése trac#:#trac_grouped_material_obligatory_err#:#A teljesítendő segédanyagok száma, amelynek 0-nál nagyobbnak kell lenni, és kisebbnek, mint a csoportosítás anyagainak száma. trac#:#trac_hide#:#Elrejtés trac#:#trac_hide_selected#:#Kiválasztott objektumok elrejtése trac#:#trac_in_progress#:#Folyamatban -trac#:#trac_info_edited#:#Állítsa 'Teljesített'-re az állapotot, ha úgy gondolja, hogy a teljes tartalmat feldolgozta. +trac#:#trac_info_edited#:#Állítsa ‘Teljesített’-re az állapotot, ha úgy gondolja, hogy a teljes tartalmat feldolgozta. trac#:#trac_last_access#:#Utolsó hozzáférés trac#:#trac_last_aggregation#:#Utolsó aggregálás trac#:#trac_learning_progress#:#Tanulási haladás @@ -17227,9 +17307,9 @@ trac#:#trac_lp_determination_tutor#:#Objektumok megjelenítése a tanulási hala trac#:#trac_lp_learner_access#:#Saját tanulási haladás megtekintése trac#:#trac_lp_learner_access_info#:#Ha aktív, a felhasználók hozzáférnek saját tanulási haladási állapotukhoz. trac#:#trac_lp_list_gui#:#Műszerfal, Tartalomtár, Keresés -trac#:#trac_lp_list_gui_info#:#Ha be van kapcsolva, a tanulási haladás állapota megjelenik az objektumok felsorolásánál. -trac#:#trac_lp_settings_info_parent_container#:#Ős-tárolóobjektumok tanulási haladása -trac#:#trac_lp_settings_info_parent_legend#:#Tanulási haladási állapotát befolyásolja '%s'. +trac#:#trac_lp_list_gui_info#:#A tanulási haladás állapota megjelenik az objektumok felsorolásánál. +trac#:#trac_lp_settings_info_parent_container#:#Szülő-tárolóobjektumok tanulási haladása +trac#:#trac_lp_settings_info_parent_legend#:#Tanulási haladási állapotát befolyásolja ‘%s’. trac#:#trac_manual_display#:#Jelenjen meg a tanulási haladásban trac#:#trac_manual_is_displayed#:#Megjelenítve trac#:#trac_manual_no_display#:#Ne jelenjen meg a tanulási haladásban @@ -17239,68 +17319,68 @@ trac#:#trac_measure#:#Mutatószám trac#:#trac_members_short#:#Tagok trac#:#trac_min_passed#:#Teljesített anyagok minimális száma: trac#:#trac_mode#:#Állapotváltás módja -trac#:#trac_mode_cmix_compl_or_passed_with_failed#:#Completed when verb 'completed' or 'passed' or 'satisfied' was sent. Verb 'failed' sets status of ILIAS to 'Failed'.###26 08 2024 new variable -trac#:#trac_mode_cmix_compl_or_passed_with_failed_info#:# ###26 08 2024 new variable -trac#:#trac_mode_cmix_compl_with_failed#:#Completed when verb 'completed' was sent. Verb 'failed' sets status of ILIAS to 'Failed'.###26 08 2024 new variable -trac#:#trac_mode_cmix_compl_with_failed_info#:# ###26 08 2024 new variable -trac#:#trac_mode_cmix_completed#:#Completed when verb 'completed' was sent. Verb 'failed' sets status of ILIAS to 'In Progress'.###26 08 2024 new variable -trac#:#trac_mode_cmix_completed_info#:# ###26 08 2024 new variable -trac#:#trac_mode_cmix_completed_or_passed#:#Completed when verb 'completed' or 'passed' or 'satisfied' was sent. Verb 'failed' sets status of ILIAS to 'In Progress'.###26 08 2024 new variable -trac#:#trac_mode_cmix_completed_or_passed_info#:# ###26 08 2024 new variable -trac#:#trac_mode_cmix_passed#:#Completed when verb 'passed' or 'satisfied' was sent. Verb 'failed' sets status of ILIAS to 'In Progress'.###26 08 2024 new variable -trac#:#trac_mode_cmix_passed_info#:# ###26 08 2024 new variable -trac#:#trac_mode_cmix_passed_with_failed#:#Completed when verb 'passed' or 'satisfied' was sent. Verb 'failed' sets status of ILIAS to 'Failed'.###26 08 2024 new variable -trac#:#trac_mode_cmix_passed_with_failed_info#:# ###26 08 2024 new variable +trac#:#trac_mode_cmix_compl_or_passed_with_failed#:#Sikeresen teljesítette, amikor ‘befejezte’ vagy ‘sikeresen teljesítette’ vagy ‘elégedett’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘nem teljesítette’ értékűre állítja. +trac#:#trac_mode_cmix_compl_or_passed_with_failed_info#:#  +trac#:#trac_mode_cmix_compl_with_failed#:#Sikeresen teljesítette, amikor ‘befejezte’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘nem teljesítette’ értékűre állítja. +trac#:#trac_mode_cmix_compl_with_failed_info#:#  +trac#:#trac_mode_cmix_completed#:#Sikeresen teljesítette, amikor ‘befejezte’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘folyamatban’ értékűre állítja. +trac#:#trac_mode_cmix_completed_info#:#  +trac#:#trac_mode_cmix_completed_or_passed#:#Sikeresen teljesítette, amikor ‘befejezte’ vagy ‘sikeresen teljesítette’ vagy ‘elégedett’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘folyamatban’ értékűre állítja. +trac#:#trac_mode_cmix_completed_or_passed_info#:#  +trac#:#trac_mode_cmix_passed#:#Sikeresen teljesítette, amikor ‘sikeresen teljesítette’ vagy ‘elégedett’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘folyamatban’ értékűre állítja. +trac#:#trac_mode_cmix_passed_info#:#  +trac#:#trac_mode_cmix_passed_with_failed#:#Sikeresen teljesítette, amikor ‘sikeresen teljesítette’ vagy ‘elégedett’ értéket küld. A ‘nem teljesítette’ küldése az ILIAS-állapot ‘nem teljesítette’ értékűre állítja. +trac#:#trac_mode_cmix_passed_with_failed_info#:#  trac#:#trac_mode_collection#:#Az állapotot kiválasztott elemek határozzák meg -trac#:#trac_mode_collection_info#:#A felhasználó tanulási haladási állapotát a kiválasztott elemek tanulási haladási állapota határozza meg: amikor az összes kiválasztott elem tanulási haladási állapota 'Teljesített'-re vált, akkor lesz az összesítő állapot értéke 'Teljesített'.
    A beállítás mentése után lehet kiválasztani az elemeket. +trac#:#trac_mode_collection_info#:#A felhasználó tanulási haladási állapotát a kiválasztott elemek tanulási haladási állapota határozza meg: amikor az összes kiválasztott elem tanulási haladási állapota ‘Teljesített’-re vált, akkor lesz az összesítő állapot értéke ‘Teljesített’.
    A beállítás mentése után kibővül ez a lap, azaz a mentés után lehet kiválasztani az elemeket. trac#:#trac_mode_collection_manual#:#Felhasználók saját maguk fejezetenként vizsgálják és döntenek az állapotról -trac#:#trac_mode_collection_manual_info#:#A felhasználók maguk döntik el, mikor sajátították el a tananyag fejezetét. Amikor ezt megtették, állítsák be állapotukat 'Teljesített'-re az 'Információ' fülön.
    A beállítás mentése után határozhatja meg, mely fejezetek befolyásolják a tanulási haladást. +trac#:#trac_mode_collection_manual_info#:#A felhasználók maguk döntik el, mikor sajátították el a tananyag fejezetét. Amikor ezt megtették, állítsák be állapotukat ‘Teljesített’-re az ‘Információ’ lapon.
    A beállítás mentése után határozhatja meg, mely fejezetek befolyásolják a tanulási haladást. trac#:#trac_mode_collection_mobs#:#Médiaobjektumok gyűjteménye trac#:#trac_mode_collection_mobs_info#:#A tanulási haladás állapotát a kiválasztott médiaobjektumok megtekintési állapota határozza meg. trac#:#trac_mode_collection_tlt#:#Fejezetenként minimálisan elvárt tanulási idő -trac#:#trac_mode_collection_tlt_info#:#Az állapotot automatikusan a felhasználó fejezetenként eltöltött tanulási ideje alapján határozzuk meg. A felhasználó állapota akkor vált 'Teljesített'-re, amikor valamennyi releváns fejezet esetén elérte a minimálisan elvárt tanulási időt.
    A beállítások mentése után fejezetenként beállítható a szokásos tanulási idő. +trac#:#trac_mode_collection_tlt_info#:#Az állapotot automatikusan a felhasználó fejezetenként eltöltött tanulási ideje alapján határozzuk meg. A felhasználó állapota akkor vált ‘Teljesített’-re, amikor valamennyi releváns fejezet esetén elérte a minimálisan elvárt tanulási időt.
    A beállítások mentése után fejezetenként beállítható a szokásos tanulási idő. trac#:#trac_mode_content_visited#:#Megtekintés -trac#:#trac_mode_content_visited_info#:#A tanulási haladás állapota 'Teljesített' lesz, amikor az objektumot a felhasználó megtekinti. -trac#:#trac_mode_contribution_to_discussion#:#Contributions to Discussion###29 07 2022 new variable -trac#:#trac_mode_contribution_to_discussion_info#:#The learning progress status will be determined by the number of written postings.###29 07 2022 new variable +trac#:#trac_mode_content_visited_info#:#A tanulási haladás állapota ‘Teljesített’ lesz, amikor az objektumot a felhasználó megtekinti. +trac#:#trac_mode_contribution_to_discussion#:#Hozzászólások +trac#:#trac_mode_contribution_to_discussion_info#:#A tanulási haladás állapotát a hozzászólások száma határozza meg. trac#:#trac_mode_course_reference#:#A kurzusből örökítve trac#:#trac_mode_course_reference_info#:#A mód automatikusan öröklődik az erre a kurzusra mutató kurzusból. trac#:#trac_mode_deactivated#:#Tanulási haladás kikapcsolva trac#:#trac_mode_deactivated_info_new#:#A tanulási haladás állapota nem jelenik meg és nincs hatással a szülőobjektumra. -trac#:#trac_mode_event#:#Vezetők/Tutorok vizsgálják és rögzítik a jelenléteket -trac#:#trac_mode_event_info#:#Tutorok/Vezetők ellenőrzik, hogy ki vett részt az eseményen, és kézzel rögzítik azt a 'Résztvevők' fülön. +trac#:#trac_mode_event#:#Manuális jelenléti megerősítést igényel +trac#:#trac_mode_event_info#:#A felhasználó jelenlétét manuálisan kell megerősíteni a ‘Résztvevők’ lapon egy ‘Tagok kezelése’ jogosultsággal rendelkező személynek. Általában ez a személy az esemény felelőse. trac#:#trac_mode_exercise_returned#:#Vezetők/Tutorok vizsgálják és döntenek a teljesítettségéről -trac#:#trac_mode_exercise_returned_info#:#Vezetők/Tutorok döntik el, hogy a felhasználó teljesítette-e az elvárásokat, manuálisan állítják a felhasználók összesített állapotát (például 'Teljesített'-re vagy 'Nem teljesített'-re). +trac#:#trac_mode_exercise_returned_info#:#Vezetők/Tutorok döntik el, hogy a felhasználó teljesítette-e a feladatokat, manuálisan állítják a felhasználók összesített állapotát (például ‘Teljesített’-re vagy ‘Nem teljesített’-re). trac#:#trac_mode_individual_assessment#:#Tutor vagy trainer manuálisan értékelte trac#:#trac_mode_individual_assessment_info#:#A felhasználó bejegyzését véglegesített egy tutor, hogy teljesítse a személyes értékelést. -trac#:#trac_mode_lti_outcome#:#Mastery Score Must be reached -trac#:#trac_mode_lti_outcome_info#:#The Learning Progress will be evaluated from the LTI outcome and the mastery score threshold. +trac#:#trac_mode_lti_outcome#:#A kötelező pontszámot el kell érni +trac#:#trac_mode_lti_outcome_info#:#A tanulási haladást az LTI-eredmény és a kötelező pontszám küszöbértéke határozza meg. trac#:#trac_mode_manual#:#Felhasználók saját maguk vizsgálják és döntenek a teljesítettségéről trac#:#trac_mode_manual_by_tutor#:#Vezetők/Tutorok vizsgálják és döntenek a teljesítettségről -trac#:#trac_mode_manual_by_tutor_info#:#Vezetők/Tutorok döntik el, hogy a felhasználó teljesítette-e az objektum elvárásait, manuálisan állítják a felhasználók összesített állapotát (például 'Teljesített'-re vagy 'Nem teljesített'-re). -trac#:#trac_mode_manual_info#:#A felhasználók maguk döntik el, mikor sajátították el az objektumot. Amikor ezt megtették, állítsák be állapotukat 'Teljesített'-re az 'Információ' fülön. +trac#:#trac_mode_manual_by_tutor_info#:#Vezetők/Tutorok döntik el, hogy a felhasználó teljesítette-e az objektum elvárásait, manuálisan állítják a felhasználók összesített állapotát (például ‘Teljesített’-re vagy ‘Nem teljesített’-re). +trac#:#trac_mode_manual_info#:#A felhasználók maguk döntik el, mikor sajátították el az objektumot. Amikor ezt megtették, állítsák be állapotukat ‘Teljesített’-re az ‘Információ’ lapon. trac#:#trac_mode_objectives#:#Tanulási célok határozzák meg az állapotot trac#:#trac_mode_objectives_info#:#A tanulási haladást automatikusan értékeljük ki a teljesített tanulási objektumok száma alapján. trac#:#trac_mode_plugin#:#Plugin trac#:#trac_mode_questions#:#Összes kérdés helyes megválaszolása -trac#:#trac_mode_questions_info#:#Azon felhasználók, akik az összes kérdést hibátlanul megválaszolták, megkapják a 'Teljesített' állapotot. Csak akkor használja ezt az opciót, ha tényleg vannak kérdések a tananyagban. +trac#:#trac_mode_questions_info#:#Azon felhasználók, akik az összes kérdést hibátlanul megválaszolták, megkapják a ‘Teljesített’ állapotot. Csak akkor használja ezt az opciót, ha tényleg vannak kérdések a tananyagban. trac#:#trac_mode_scorm#:#Az állapotot a kiválasztott SCORM-elemek határozzák meg trac#:#trac_mode_scorm_info#:#A tanulási haladást a kiválasztott SCO-k állapota alapján automatikusan határozzuk meg.
    A felhasználók tanulási haladási állapotát a kiválasztott SCO-k tanulási haladási állapota automatikusan határozza meg: az SCO-kat a beállítás mentése után lehet kiválasztani. trac#:#trac_mode_scorm_package#:#Az állapotot a teljes SCORM-csomag határozza meg trac#:#trac_mode_scorm_package_info#:#A tanulási haladás állapotát a teljes SCORM-csomag állapota automatikusan határozza meg. Az összes SCO befolyásolja a tanulási haladást. trac#:#trac_mode_study_programme#:#Képzési program teljesítve trac#:#trac_mode_survey_finished#:#Kérdőív befejezése -trac#:#trac_mode_survey_finished_info#:#A kérdőívet a felhasználónak be kell fejeznie, hogy az állapota 'Teljesített' legyen. +trac#:#trac_mode_survey_finished_info#:#A kérdőívet a felhasználónak be kell fejeznie, hogy az állapota ‘Teljesített’ legyen. trac#:#trac_mode_test_finished#:#Teszt befejezése -trac#:#trac_mode_test_finished_info#:#A felhasználó tanulási haladási állapota akkor vált 'Teljesített'-re, amikor a felhasználó a 'Teszt befejezése' gombra kattint, függetlenül attól, hogy sikeresen teljesített-e a tesztet vagy sem. +trac#:#trac_mode_test_finished_info#:#A felhasználó tanulási haladási állapota akkor vált ‘Teljesített’-re, amikor a felhasználó a ‘Teszt befejezése’ gombra kattint, függetlenül attól, hogy sikeresen teljesített-e a tesztet vagy sem. trac#:#trac_mode_test_passed#:#Teszt sikeres teljesítése -trac#:#trac_mode_test_passed_info#:#A felhasználó tanulási haladási állapota a teszt sikeres teljesítésével vált 'Teljesített'-re. A teszt teljesítésének küszöbértéke a 'Beállítások' fül 'Értékelés' részén állítható be. +trac#:#trac_mode_test_passed_info#:#A felhasználó tanulási haladási állapota a teszt sikeres teljesítésével vált ‘Teljesített’-re. A teszt teljesítésének küszöbértéke a ‘Beállítások’ lap ‘Értékelés’ részén állítható be. trac#:#trac_mode_tlt#:#Tananyaggal töltött minimálisan elvárt idő -trac#:#trac_mode_tlt_info#:#Az állapotot a felhasználó tananyaggal töltött ideje alapján automatikusan határozzuk meg. Amikor a felhasználó feldolgozási ideje elérte a minimálisan elvárt Szokásos Tanulási Időt, állapota 'Teljesített'-re vált.
    A Szokásos Tanulási Idő a 'Metaadatok' fülön módosítható. +trac#:#trac_mode_tlt_info#:#Az állapotot a felhasználó tananyaggal töltött ideje alapján automatikusan határozzuk meg. Amikor a felhasználó feldolgozási ideje elérte a minimálisan elvárt Szokásos Tanulási Időt, állapota ‘Teljesített’-re vált.
    A Szokásos Tanulási Idő a ‘Metaadatok’ lapon módosítható. trac#:#trac_mode_visited_pages#:#Összes oldal meglátogatása -trac#:#trac_mode_visited_pages_info#:#Az állapot akkor vált 'Teljesített'-re, amikor a felhasználó meglátogatta a tananyag összes oldalát. +trac#:#trac_mode_visited_pages_info#:#Az állapot akkor vált ‘Teljesített’-re, amikor a felhasználó meglátogatta a tananyag összes oldalát. trac#:#trac_mode_visits#:#Az állapotot a látogatások szám határozza meg -trac#:#trac_mode_visits_info#:#A felhasználó állapota automatikusan 'Teljesített'-ra vált, amikor a felhasználó a megadott számán többször tekinti meg a tananyagot. A felhasználókat tájékoztatjuk a megtekintéseik számáról, és teljesítéshez szükséges állapot százalékáról. +trac#:#trac_mode_visits_info#:#A felhasználó állapota automatikusan ‘Teljesített’-ra vált, amikor a felhasználó a megadott számán többször tekinti meg a tananyagot. A felhasználókat tájékoztatjuk a megtekintéseik számáról, és teljesítéshez szükséges állapot százalékáról. trac#:#trac_name_of_installation#:#Installáció neve trac#:#trac_no_attempted#:#Nem próbálkozott trac#:#trac_not_accessed#:#Nem érhető el @@ -17320,20 +17400,21 @@ trac#:#trac_object_stat_lp_max#:#Max. trac#:#trac_object_stat_lp_min#:#Min. trac#:#trac_object_stat_types#:#Objektumok száma trac#:#trac_object_statistics#:#Objektumstatisztikák -trac#:#trac_object_statistics_info#:#Ha be van kapcsolva, a használati statisztika alapadatait összegyűjtjük és feldogozzuk. +trac#:#trac_object_statistics_info#:#A használati statisztika alapadatait összegyűjtjük és feldogozzuk. trac#:#trac_objects#:#Felhasználók trac#:#trac_others#:#Továbbiak trac#:#trac_participants#:#Résztvevők megjelenítése trac#:#trac_participated#:#Részt vett -trac#:#trac_paths#:#Paths###29 07 2022 new variable +trac#:#trac_paths#:#Útvonalak trac#:#trac_percentage#:#Százalék trac#:#trac_periodic_system_load#:#Időszakra rendszerterhelés trac#:#trac_progress#:#Személyes tanulási haladás -trac#:#trac_progress_block_title#:#Your Learning Progress###29 10 2025 new variable +trac#:#trac_progress_block_details#:#Részletek megjelenítése +trac#:#trac_progress_block_title#:#Tanulási haladásom trac#:#trac_read_count#:#Hozzáférésszám trac#:#trac_read_count_spent_seconds#:#Felhasznált idő/elérés trac#:#trac_reference#:#Linkek -trac#:#trac_reference_ids_column#:#Reference-Ids###29 07 2022 new variable +trac#:#trac_reference_ids_column#:#Reference-Id-k trac#:#trac_registered#:#Regisztrált trac#:#trac_release_materials#:#Választható anyagok csoportosításának megszüntetése trac#:#trac_report_date#:#Riport dátuma @@ -17360,7 +17441,7 @@ trac#:#trac_settings#:#Beállítások trac#:#trac_settings_saved#:#A beállításokat sikeresen mentette. trac#:#trac_short_system_load#:#Rövidtávú visszatekintés trac#:#trac_show_graph#:#Grafikon megjelenítése -trac#:#trac_show_progress_block#:#Show Personal Progress Chart in ‘Content’-Tab###29 10 2025 new variable +trac#:#trac_show_progress_block#:#Személyes haladási grafikon megjelenítése a ‘Tartalom’ fülön trac#:#trac_show_repository_views#:#Nyomkövetési információk megjelenítése trac#:#trac_show_repository_views_info#:#Tartalomtárbeli objektumok nyomkövetési információinak megjelenítése azok információs lapján. trac#:#trac_spent_seconds#:#Eltöltött idő @@ -17380,8 +17461,8 @@ trac#:#trac_title#:#Cím trac#:#trac_title_description#:#Cím/Leírás trac#:#trac_total_online#:#Teljes online eltöltött idő trac#:#trac_trash#:#Lomtárba helyezve -trac#:#trac_update_edit_user#:#Mentett beállítások -trac#:#trac_updated_status#:#Tanulási haladás állapotának mentése sikerült. +trac#:#trac_update_edit_user#:#A beállításokat sikeresen mentette +trac#:#trac_updated_status#:#A tanulási haladás állapotát sikeresen mentette. trac#:#trac_user_data#:#Felhasználói adatok trac#:#trac_valid_request#:#Kérések közötti maximális idő trac#:#trac_view_crs#:#Vissza a kurzushoz @@ -17391,106 +17472,108 @@ trac#:#trac_view_mode_all#:#Összes objektum trac#:#trac_view_mode_collection#:#Csak azok az objektumok, amelyek az átfogó állapotot határozzák meg trac#:#trac_visits#:#Elvárt látogatások száma trac#:#trac_visits_info#:#Csak a %s másodpercen túli kattintás számít új látogatásnak. +trac#:#trac_visits_nr#:#Látogatások száma trac#:#user_total#:#Felhasználók összesen trac#:#view_mode#:#Nézet -trac#:#view_mode_all#:#All###29 10 2025 new variable -trac#:#view_mode_current#:#Current###29 10 2025 new variable -trac#:#view_mode_future#:#Future###29 10 2025 new variable -trac#:#view_mode_past#:#Past###29 10 2025 new variable -tstv#:#tstv_create#:#Tesztigazolás létrehozása -tstv#:#tstv_create_info#:#Válasszon ki egy befejezett tesztet, hogy igazolást generáljon hozzá. -ui#:#1stars#:#one of five stars###26 08 2024 new variable -ui#:#2stars#:#two of five stars###26 08 2024 new variable -ui#:#3stars#:#three of five stars###26 08 2024 new variable -ui#:#4stars#:#four of five stars###26 08 2024 new variable -ui#:#5stars#:#five of five stars###26 08 2024 new variable -ui#:#datatable_close_warning#:#OK###29 10 2025 new variable -ui#:#datatable_multiaction_label#:#Bulk Actions###26 08 2024 new variable -ui#:#datatable_multiactionmodal_actionlabel#:#Action for All Entries###26 08 2024 new variable -ui#:#datatable_multiactionmodal_apply#:#Apply###26 08 2024 new variable -ui#:#datatable_multiactionmodal_listentry#:#Actions for Entire Table###26 08 2024 new variable -ui#:#datatable_multiactionmodal_msg#:#Selected action will affect all entries in this table.###26 08 2024 new variable -ui#:#datatable_multiactionmodal_title#:#Actions for Entire Table###26 08 2024 new variable -ui#:#drilldown_no_items#:#No Matching Elements###26 08 2024 new variable -ui#:#duration_default_label_end#:#end###29 07 2022 new variable -ui#:#duration_default_label_start#:#start###29 07 2022 new variable -ui#:#duration_end_must_not_be_earlier_than_start#:#Start must not be later than end.###29 07 2022 new variable -ui#:#filter_nodes_in#:#Filter Nodes in %s###26 08 2024 new variable -ui#:#footer_icons#:#Footer Icons###28 10 2024 new variable -ui#:#footer_link_groups#:#Footer Link-Groups###28 10 2024 new variable -ui#:#footer_links#:#Footer Links###28 10 2024 new variable -ui#:#footer_permanent_link#:#Footer Permanent Link###28 10 2024 new variable -ui#:#footer_texts#:#Footer Texts###28 10 2024 new variable -ui#:#image_alt_text#:#Alternate Text###29 10 2025 new variable -ui#:#image_purpose_decorative#:#Decorative Image###29 10 2025 new variable -ui#:#image_purpose_informative#:#Informative Image###29 10 2025 new variable -ui#:#image_purpose_user_defined#:#Image Purpose###29 10 2025 new variable -ui#:#label_fieldselection#:#Field Selection###26 08 2024 new variable -ui#:#label_fieldselection_refresh#:#Apply###26 08 2024 new variable -ui#:#label_modeviewcontrol#:#view mode###29 10 2025 new variable -ui#:#label_pagination_limit#:#Pagination Number of Rows###26 08 2024 new variable -ui#:#label_pagination_offset#:#Pagination Offset###26 08 2024 new variable -ui#:#label_sortation#:#Sortation###26 08 2024 new variable -ui#:#order_option_alphabetical_ascending#:#A to Z###26 08 2024 new variable -ui#:#order_option_alphabetical_descending#:#Z to A###26 08 2024 new variable -ui#:#order_option_chronological_ascending#:#Earliest first###26 08 2024 new variable -ui#:#order_option_chronological_descending#:#Most Recent first###26 08 2024 new variable -ui#:#order_option_first#:#first###26 08 2024 new variable -ui#:#order_option_generic_ascending#:#ascending###26 08 2024 new variable -ui#:#order_option_generic_descending#:#descending###26 08 2024 new variable -ui#:#order_option_numerical_ascending#:#0 to 9###26 08 2024 new variable -ui#:#order_option_numerical_descending#:#9 to 0###26 08 2024 new variable -ui#:#presentation_table_collapse#:#collapse all###26 08 2024 new variable -ui#:#presentation_table_expand#:#expand all###26 08 2024 new variable -ui#:#rating_average#:#others rated %s of 5###26 08 2024 new variable -ui#:#reset_stars#:#neutral###26 08 2024 new variable -ui#:#select_node#:#Add node %s to selection###29 10 2025 new variable -ui#:#table_posinput_col_title#:#Position###26 08 2024 new variable +trac#:#view_mode_all#:#Összes +trac#:#view_mode_current#:#Jelenlegi +trac#:#view_mode_future#:#Jövőbeli +trac#:#view_mode_past#:#Múltbeli +tstv#:#tstv_create#:#Teszttanúsítvány létrehozása +tstv#:#tstv_create_info#:#Válasszon ki egy befejezett tesztet, amelyhez tanúsítványt generál. +ui#:#1stars#:#öt csillagból egy +ui#:#2stars#:#öt csillagból kettő +ui#:#3stars#:#öt csillagból három +ui#:#4stars#:#öt csillagból négy +ui#:#5stars#:#öt csillagból öt +ui#:#datatable_close_warning#:#OK +ui#:#datatable_multiaction_label#:#Tömeges művelet +ui#:#datatable_multiactionmodal_actionlabel#:#művelet +ui#:#datatable_multiactionmodal_apply#:#Alkalmazás +ui#:#datatable_multiactionmodal_listentry#:#Művelet az egész táblázaton… +ui#:#datatable_multiactionmodal_msg#:#Vigyázat! Több objektumra van hatással. +ui#:#datatable_multiactionmodal_title#:#Művelet több objektumon. +ui#:#drilldown_no_items#:#Nincs találat +ui#:#duration_default_label_end#:#vége +ui#:#duration_default_label_start#:#kezdete +ui#:#duration_end_must_not_be_earlier_than_start#:#A kezdő időpont nem lehet későbbi, mint a záró. +ui#:#filter_nodes_in#:#%s szűrése +ui#:#footer_icons#:#Lábléc ikonok +ui#:#footer_link_groups#:#Lábléc linkcsoportok +ui#:#footer_links#:#Lábléc linkek +ui#:#footer_permanent_link#:#Lábléc állandó link +ui#:#footer_texts#:#Lábléc szövegek +ui#:#image_alt_text#:#Alternatív szöveg +ui#:#image_purpose_decorative#:#Dekoratív kép +ui#:#image_purpose_informative#:#Informatív kép +ui#:#image_purpose_user_defined#:#Kép célja +ui#:#label_fieldselection#:#Mezőválasztás +ui#:#label_fieldselection_refresh#:#Alkalmaz +ui#:#label_modeviewcontrol#:#nézet mód +ui#:#label_pagination_limit#:#Sorok számozása +ui#:#label_pagination_offset#:#Oldalszámozás kezdete +ui#:#label_sortation#:#Rendezés +ui#:#order_option_alphabetical_ascending#:#A → Z +ui#:#order_option_alphabetical_descending#:#Z → A +ui#:#order_option_chronological_ascending#:#Legkorábbi legelől +ui#:#order_option_chronological_descending#:#Leggyakoribb legelől +ui#:#order_option_first#:#első +ui#:#order_option_generic_ascending#:#növekvő +ui#:#order_option_generic_descending#:#csökkenő +ui#:#order_option_numerical_ascending#:#0 → 9 +ui#:#order_option_numerical_descending#:#9 → 0 +ui#:#presentation_table_collapse#:#becsukás +ui#:#presentation_table_expand#:#kinyitás +ui#:#rating_average#:#a többiek értékelése %s az 5-ből +ui#:#reset_stars#:#semleges +ui#:#select_node#:#%s csomópont hozzáadása a kiválasztáshoz +ui#:#table_posinput_col_title#:#Pozíció ui#:#ui_chars_max#:#Maximum: ui#:#ui_chars_min#:#Minimum: ui#:#ui_chars_remaining#:#Fennmaradó karakterek száma: -ui#:#ui_error#:#Error###28 10 2024 new variable +ui#:#ui_error#:#Hiba ui#:#ui_error_in_group#:#Ebben a részben van néhány hiba. -ui#:#ui_error_switchable_group_required#:#Please select an option.###29 07 2022 new variable -ui#:#ui_field_option_filter_clear_search#:#Clear search###29 10 2025 new variable -ui#:#ui_field_option_filter_filtered_results_aria_label#:#List of options - collapsible and filterable###29 10 2025 new variable -ui#:#ui_field_option_filter_no_match#:#There was no match for the search term you entered.###29 10 2025 new variable -ui#:#ui_field_option_filter_no_selection#:#Nothing selected.###29 10 2025 new variable -ui#:#ui_field_option_filter_options_shown#:#Currently showing %s options.###29 10 2025 new variable -ui#:#ui_field_option_filter_screen_reader_hint#:#Start typing and the field options below will be filtered accordingly.###29 10 2025 new variable -ui#:#ui_field_option_filter_search_in#:#Find###29 10 2025 new variable -ui#:#ui_field_option_filter_show_all_options#:#Show all options###29 10 2025 new variable -ui#:#ui_field_option_filter_show_less#:#Show less###29 10 2025 new variable -ui#:#ui_file_input_general_error#:#An error occurred! You can check the JavaScript console of your browser for more information and/or contact your ILIAS system administration about this incident.###29 07 2022 new variable -ui#:#ui_file_input_invalid_amount#:#You cannot upload this many files, please remove some in order to continue.###29 07 2022 new variable -ui#:#ui_file_input_invalid_mime#:#Files of type '%s' are not allowed###29 07 2022 new variable -ui#:#ui_file_input_invalid_size#:#File exceeds the maximum size of %s.###29 07 2022 new variable -ui#:#ui_file_upload_max_nr#:#Max Number of Files:###26 08 2024 new variable -ui#:#ui_invalid_url#:#Invalid URL-format###29 07 2022 new variable -ui#:#ui_link_label#:#Label###29 07 2022 new variable -ui#:#ui_link_url#:#URL###29 07 2022 new variable -ui#:#ui_md_input_edit#:#Edit###26 08 2024 new variable -ui#:#ui_md_input_view#:#View###26 08 2024 new variable -ui#:#ui_nav_sequence_control_label#:#Sequence control for contents below###29 10 2025 new variable -ui#:#ui_nav_sequence_description#:#Used to navigate through this content or trigger actions and filters on the entire sequence.###29 10 2025 new variable -ui#:#ui_pagination_unlimited#:#Unlimited###26 08 2024 new variable -ui#:#ui_select_dropdown_label#:#Please select###26 08 2024 new variable -ui#:#ui_table_no_records#:#No records###26 08 2024 new variable -ui#:#ui_table_order#:#Order###29 10 2025 new variable -ui#:#ui_transcription#:#Transcript###29 07 2022 new variable -ui#:#unselect_node#:#Remove node %s from selection###29 10 2025 new variable -ui#:#vc_sort#:#Sort by:###29 10 2025 new variable -ui#:#warning_url_too_long_msg#:#The amount of selected rows will result in a very large URL; the Server will probably block this request.
    Please select less rows or perform the action on all entries.###29 10 2025 new variable -user#:#activate_in_profile_fields#:#To change this setting, the user must first be allowed to change their login name under Profile > Profile Fields###29 10 2025 new variable -user#:#administrative_settings#:#Administrative Settings###29 10 2025 new variable +ui#:#ui_error_switchable_group_required#:#Válaszzon egy lehetőséget. +ui#:#ui_field_option_filter_clear_search#:#Keresés törlése +ui#:#ui_field_option_filter_filtered_results_aria_label#:#Lehetőségek listája - összecsukható és szűrhető +ui#:#ui_field_option_filter_no_match#:#Nincs találat a megadott keresési kifejezésre. +ui#:#ui_field_option_filter_no_selection#:#Semmit sem jelölt ki. +ui#:#ui_field_option_filter_options_shown#:#Jelenleg %s lehetőség látható. +ui#:#ui_field_option_filter_screen_reader_hint#:#Kezdjen el gépelni, és az alábbi mezőbeállításokat ennek megfelelően szűri. +ui#:#ui_field_option_filter_search_in#:#Keresés +ui#:#ui_field_option_filter_show_all_options#:#Összes lehetőség megjelenítése +ui#:#ui_field_option_filter_show_less#:#Kevesebb… +ui#:#ui_file_input_general_error#:#Hiba történt! Bővebb információért ellenőrizze böngészője JavaScript konzolát, illetve keresse az ILIAS üzemeltetőjét. +ui#:#ui_file_input_invalid_amount#:#Ennyi fájl nem tölthet fel, a folytatáshoz távolítson el néhányat. +ui#:#ui_file_input_invalid_mime#:#‘%s’ fájltípus nem engedélyzett +ui#:#ui_file_input_invalid_size#:#A fájl mérete meghaladja a maximálisan engedélyzettet (%s). +ui#:#ui_file_upload_max_nr#:#Fájlok maximális száma: +ui#:#ui_invalid_url#:#Érvénytelen URL-formátum +ui#:#ui_link_label#:#Címke +ui#:#ui_link_url#:#URL +ui#:#ui_md_input_edit#:#Szerkesztés +ui#:#ui_md_input_view#:#Megtekintés +ui#:#ui_nav_sequence_control_label#:#Az alábbi tartalmak sorrendjének vezérlése +ui#:#ui_nav_sequence_description#:#A tartalomban való navigálásra, illetve a teljes sorozaton műveletek és szűrők aktiválására szolgál. +ui#:#ui_pagination_unlimited#:#Korlátlan +ui#:#ui_select_dropdown_label#:#Kérem, válasszon +ui#:#ui_table_no_records#:#Egy bejegyzés sem található +ui#:#ui_table_order#:#Rendezés +ui#:#ui_transcription#:#Átirat +ui#:#unselect_node#:#%s csomópont eltávolítása a kijelölésből +ui#:#vc_sort#:#Rendezés alapja: +ui#:#warning_url_too_long_msg#:#A kiválasztott sorok száma nagyon nagy URL-t eredményez; a szerver valószínűleg blokkolja az ekkora kérést.
    Kérjük, válasszon kevesebb sort, vagy hajtsa végre a műveletet az összes bejegyzésen. +user#:#account_not_flagged_for_deletion#:#A fiók nincs megjelölve törlésre. +user#:#activate_in_profile_fields#:#A beállítás módosításához a felhasználónak először engedélyeznie kell a bejelentkezési nevének módosítását a Profil > Profilmezők menüpontban. +user#:#administrative_settings#:#Rendszerbeállítások user#:#all_roles_has_starting_point#:#Az összes szabálynak van kiindulási pontja user#:#back_to_starting_points_list#:#Vissza a kiindulási pontokhoz -user#:#change_email_email_confirmation_body#:#The email address for the account %s was changed. To confirm this change, please click on this link %s. The link is valid for %s minutes.###28 10 2024 new variable -user#:#change_email_email_confirmation_subject#:#Confirm Email Address###28 10 2024 new variable -user#:#change_email_email_information_body#:#The process to change the email address for the account %s to %s was started. An email with a link to confirm the change was sent to the new address. The link is valid for %s minutes.###28 10 2024 new variable -user#:#change_email_email_information_subject#:#Information about Change of Email Address###28 10 2024 new variable -user#:#change_email_email_sent#:#An email with a link to confirm your change has been sent. Please check your inbox and make sure to also look in the spam-folder if the email doesn't arrive within the next minutes.###28 10 2024 new variable -user#:#change_email_info_message#:#There is a pending request to change the email address for this account.###28 10 2024 new variable +user#:#change_email_email_confirmation_body#:#%s e-mail címe megváltozott. Ennek megerősítéséhez kattintson a linkre: %s. A link %s percig érvényes. +user#:#change_email_email_confirmation_subject#:#E-mail cím megerősítése +user#:#change_email_email_information_body#:#%s e-mail címének módosítása elkezdődött (%s). Egy megerősítő e-mail küldtünk az új címre. A link %s percig érvényes. +user#:#change_email_email_information_subject#:#Információ az e-mail cím módosításáról +user#:#change_email_email_sent#:#E-mail címe módosítása érdekében egy megerősítő linket tartalmazó e-mail küldtünk az új címre. Kérem, ellenőrizze postaládáját, illetve azt, is, hogy az üzenet ne kerüljön a levélszemetek közé. +user#:#change_email_info_message#:#Jelenleg van egy függőben lévő kérelem a fiók e-mail-címének módosítására. user#:#clipboard_add_btn#:#Hozzáadás a vágólaphoz user#:#clipboard_add_from_btn#:#Hozzáadás a vágólapról user#:#clipboard_empty_btn#:#Vágólap ürítése @@ -17498,47 +17581,47 @@ user#:#clipboard_remove_btn#:#Eltávolítás a vágólapról user#:#clipboard_table_title#:#Vágólap (ILIAS-fiókok) user#:#clipboard_user_added#:#Sikeresen hozzáadta a kiválasztott felhasználókat a vágólaphoz. user#:#confirm_delete_starting_point#:#Biztos, hogy törli ezt a szabályt? -user#:#confirm_logout_for_email_change#:#You changed your email. To finalize this change, you will need to provide your password. The system is thus going to log you out and you will have 5 minutes to log in again. All other changes will be saved before logging you out.###26 08 2024 new variable -user#:#confirm_logout_for_email_change_with_confirmation#:#Additionally, a confirmation that you control the new email address will be required. After you have logged in again, an email will be sent to you. Please click on the link in the email to confirm that you contoll the address. The change of the email address will only take effect once this second step is also finalized.###28 10 2024 new variable +user#:#confirm_logout_for_email_change#:#Az e-mail címet módosította. A módosítás véglegesítéséhez igazolni a kell önmagát. A rendszer kijelentkezteti, és 5 perce van az újbóli bejelentkezéshez. Minden egyéb módosítást a kijelentkezés előtt mentünk. +user#:#confirm_logout_for_email_change_with_confirmation#:#Meg kell erősítenie, hogy Ön használja az új e-mail címet. Miután újra bejelentkezik, e-mailt küldünk Önnek. Kérjük, kattintson az e-mailben található linkre, hogy megerősítse az új e-mail címét. Az e-mail cím módosítása csak ezután lép életbe. user#:#create_starting_point#:#Szabály létrehozása user#:#criteria#:#Feltétel -user#:#del_mail_body#:#Tisztelt %1$s, %2$s régóta nem jelentkezett be (%3$s). Ha %4$s napon belül nem jelentkezik be, ILIAS-fiókját töröljük. +user#:#del_mail_body#:#Tisztelt %1$s, %2$s régóta nem jelentkezett be (%3$s), ezért ‘%5$s’ fiókját hamarosan töröljük (%4$s nap). Amennyiben fiókját meg kívánja tartani, jelentkezzen be ennél korábban. user#:#del_mail_subject#:#[ILIAS] – ILIAS-fiókját hamarosan töröljük user#:#delete_inactive_user_accounts_frequency#:#Gyakoriság user#:#delete_inactive_user_accounts_frequency_desc#:#A törlés és az e-mail küldés gyakorisága. -user#:#edit_field#:#Edit Field###29 10 2025 new variable -user#:#edit_setting#:#Edit Setting###29 10 2025 new variable +user#:#edit_field#:#MEző módosítása +user#:#edit_setting#:#Beállítások módosítása user#:#editing_this_role#:#Szabályok -user#:#email_could_not_be_changed#:#The request to change your email could not be finalized.###26 08 2024 new variable +user#:#email_could_not_be_changed#:#Az e-mail címét nem sikerült megváltoztatni. user#:#enable_local_user_administration#:#Helyi ILIAS-fiókok kezelésének engedélyezése -user#:#enable_local_user_administration_info#:#Ha be van kapcsolva, a 'Helyi ILIAS-fiókok kezelése' fül megjelenik a kategóriáknál és a szervezeti egységeknél. +user#:#enable_local_user_administration_info#:#A ‘Helyi ILIAS-fiókok kezelése’ lap megjelenik a kategóriáknál és a szervezeti egységeknél. user#:#feedhash#:#Hírcsatorna-hash -user#:#field_type_custom#:#Custom###29 10 2025 new variable +user#:#field_type_custom#:#Egyéni user#:#has_role#:#Szabály -user#:#info_accessFree_sure#:#Are you sure you want to remove the valid until date from the following accounts?###26 08 2024 new variable -user#:#inform_user_mail_info#:#Ha be van kapcsolva, email-t küldünk a felhasználónak. Az e-mail tartalma megadható itt: Rendszerbeállítások » ILIAS-fiókok » Beállítások » Új felhasználónak levél. +user#:#info_accessFree_sure#:#Biztos, hogy eltávoltja az érvényesség korlátját az alábbi fiókokból? +user#:#inform_user_mail_info#:#Email-t küldünk a felhasználónak. Az e-mail tartalma megadható itt: Rendszerbeállítások » ILIAS-fiókok » Beállítások » Új felhasználónak levél. user#:#interests#:#Érdeklődési körök user#:#interests_general#:#Általános érdeklődési kör user#:#interests_help_looking#:#Segítséget várok ezekben user#:#interests_help_offered#:#Segíteni tudok ezekben -user#:#ldoc_accepted_content#:#Accepted Content###26 08 2024 new variable -user#:#ldoc_not_accepted_yet#:#Not accepted yet###26 08 2024 new variable +user#:#ldoc_accepted_content#:#Efogadott tartalom +user#:#ldoc_not_accepted_yet#:#Még nincs elfogadva user#:#msg_spoint_not_modified#:#A kiindulási pont nem változott -user#:#no_deactivate_yourself#:#You cannot deactivate your own user account.###26 08 2024 new variable +user#:#no_deactivate_yourself#:#A saját fiókját nem inaktiválhatja. user#:#obj_ref_id_not_exist#:#A megadott ref_id nem létezik -user#:#personalise_additional#:#Personalise Additional Settings###29 10 2025 new variable -user#:#personalise_communication#:#Personalise Communication Settings###29 10 2025 new variable -user#:#personalise_privacy#:#Personalise Privacy Settings###29 10 2025 new variable -user#:#profile_fields#:#Profile Fields###29 10 2025 new variable -user#:#profile_section#:#Section###29 10 2025 new variable -user#:#restrict_user_access#:#Korlátozott hozzáférés az ILIAS-fiókokhoz -user#:#restrict_user_access_info#:#Csak akkor engedélyezze, ha korlátozni szeretné a hozzáférést az ILIAS-fiókokhoz. 'Olvasási elérés a helyi ILIAS-fiókhoz' jogosultság szükséges a helyi és a globális ILIAS-fiókok hozzáféréséhez. +user#:#personalise_additional#:#További beállítások személyre szabása +user#:#personalise_communication#:#Kommunikációs beállítások személyre szabása +user#:#personalise_privacy#:#Adatvédelmi beállítások személyre szabása +user#:#profile_fields#:#Profilmezők +user#:#profile_section#:#Szakasz +user#:#restrict_user_access#:#Korlátozott keresés az ILIAS-fiókok között +user#:#restrict_user_access_info#:#A keresésben az ILIAS-fiókok automatikus kiegészítéséhez az ‘Olvasási elérés az ILIAS-fiókhoz’ jogosultság szükséges. user#:#roles_without_starting_point#:#Kiindulási pont nélküli szabályok: user#:#save_order#:#Rendezés mentése -user#:#send_mail_reminder_window_too_small#:#A 'Gyakoriság' értéke túl nagy. +user#:#send_mail_reminder_window_too_small#:#A ‘Gyakoriság’ értéke túl nagy. user#:#send_mail_to_inactive_users#:#Figyelmeztető levél -user#:#send_mail_to_inactive_users_desc#:#Ha be van kapcsolva, az ILIAS-fiók annak inaktivitása miatti törlése előtt figyelmeztető levelet küldünk a közelgő törlésről. Kérjük, ellenőrizze, hogy külső címre levél küldése lehetséges. Aktiválás utáni emlékeztető levelet küldő ütemezett feladatnál előfordulhat, hogy az emlékeztető levél és a törlés közötti időköz kisebb, mint a beállított időköz. -user#:#send_mail_to_inactive_users_must_be_smaller_than#:#Kisebb kell, hogy legyen, mint az 'Utolsó bejelentkezés óta eltelt napok száma'. +user#:#send_mail_to_inactive_users_desc#:#Az ILIAS-fiók annak inaktivitása miatti törlése előtt figyelmeztető levelet küldünk a közelgő törlésről. Kérjük, ellenőrizze, hogy külső címre levél küldése lehetséges. Aktiválás utáni emlékeztető levelet küldő ütemezett feladatnál előfordulhat, hogy az emlékeztető levél és a törlés közötti időköz kisebb, mint a beállított időköz. +user#:#send_mail_to_inactive_users_must_be_smaller_than#:#Kisebb kell, hogy legyen, mint az ‘Utolsó bejelentkezés óta eltelt napok száma’. user#:#send_mail_to_inactive_users_numbers_only#:#Csak pozitív egész szám lehet. user#:#send_mail_to_inactive_users_suffix#:#nap a törlés előtti. user#:#show_own_online_status#:#Online állapotom beállítása @@ -17546,7 +17629,7 @@ user#:#starting_page#:#Kiindulási pont user#:#starting_point#:#Kiindulási pont user#:#starting_point_settings#:#Kiindulási pont beállításai user#:#starting_points#:#Kiindulási pontok -user#:#udf_select_options#:#Options###29 10 2025 new variable +user#:#udf_select_options#:#Lehetőségek user#:#user_access_limited#:#Korlátozott user#:#user_access_unlimited#:#Korlátlan user#:#user_account_code#:#Kód @@ -17554,7 +17637,7 @@ user#:#user_account_code_generated#:#Generálás napja user#:#user_account_code_generated_all#:#Összes dátum user#:#user_account_code_not_valid#:#Az adott regisztrációs kód nem érvényes vagy már felhasználták. user#:#user_account_code_setting#:#ILIAS-fiók újraaktiválásának engedélyezése kóddal -user#:#user_account_code_setting_info#:#Az inaktív ILIAS-fiókokat újra aktiválhatják a felhasználók az előre definiált kódokkal. +user#:#user_account_code_setting_info#:#A lejárt ILIAS-fiókokat újra aktiválhatják a felhasználók egy előre megadott kódoddal. Ezek a kódok Rendszerbeállítások » ILIAS-fiókok kezelése » Hitelesítés és regisztráció » ILIAS hitelesítés / Regisztráció » Regisztrációs kódok alatt hozhatók létre. user#:#user_account_code_used#:#Felhasználás dátuma user#:#user_account_code_valid_until#:#Érvényességi idő user#:#user_account_code_valid_until_dynamic#:#Napok száma @@ -17568,17 +17651,17 @@ user#:#user_account_deleted_confirmation#:#ILIAS-fiókját törölte. E-mailt k user#:#user_activate_public_profile#:#Aktiválás user#:#user_activate_public_profile_info#:#Ha bekapcsolta, családi és utóneve mindig látható lesz a profiljában. user#:#user_activation#:#Aktiválás -user#:#user_admin_options#:#Options###29 10 2025 new variable +user#:#user_admin_options#:#Lehetőségek user#:#user_all#:#Összes user#:#user_allow_delete_own_account#:#Felhasználók törölhetik saját fiókjukat user#:#user_any#:#Bármi user#:#user_awrn_all_users#:#Összes felhasználó -user#:#user_awrn_all_users_info#:#A rendszer összes felhasználóját felsoroljuk. Az 'Online és offline' beállítás sok felhasználó esetén jelentősen lelassíthatja rendszert. +user#:#user_awrn_all_users_info#:#A rendszer összes felhasználóját felsoroljuk. Az ‘Online és offline’ beállítás sok felhasználó esetén jelentősen lelassíthatja rendszert. user#:#user_check_profile_data#:#A profiladatokat ellenőrzése user#:#user_chooses_starting_page#:#Felhasználók választják ki a kiindulási pontot user#:#user_delete_own_account#:#ILIAS-fiók törlése user#:#user_delete_own_account_aborted#:#Törlés megszakítva, a fiókon nem történt változás. -user#:#user_delete_own_account_email_body#:#ezúton értesítjük, hogy '%s' ILIAS-fiókját töröltük (%s, %s). +user#:#user_delete_own_account_email_body#:#ezúton értesítjük, hogy ‘%s’ ILIAS-fiókját töröltük (%s, %s). user#:#user_delete_own_account_email_subject#:#ILIAS-fiók törlése user#:#user_delete_own_account_final_confirmation#:#Utolsó alkalom, hogy meggondolhatja magát! Erősítse meg ILIAS-fiókjának végleges eltávolítását az ILIAS-ból! user#:#user_delete_own_account_info#:#Itt törölheti jelenlegi ILIAS-fiókját. Ne felejtse el, hogy ez a törlés visszafordíthatatlan! @@ -17586,10 +17669,10 @@ user#:#user_delete_own_account_logout_button#:#Hitelesítés menete user#:#user_delete_own_account_logout_confirmation#:#Fiókját törölni készül. Kérjük, hogy hitelesítse magát a folyamat folytatásához. user#:#user_delete_own_account_notification_email#:#Értesítő e-mail user#:#user_field#:#Mező -user#:#user_global_role#:#Globális szerep +user#:#user_global_role#:#Globális szerepkör user#:#user_last_login_before#:#Utolsó bejelentkezés ez előtt: user#:#user_limited_access#:#Korlátozott elérés -user#:#user_local_role#:#Local Role###29 07 2022 new variable +user#:#user_local_role#:#Helyi szerepkör user#:#user_lv_do_not_store#:#Soha ne jegyezze meg az utolsó megtekintéseimet user#:#user_lv_keep_entries#:#Utolsó megtekintéseim megjegyzése user#:#user_lv_keep_only_for_session#:#Munkamenet végén törölje az utolsó megtekintéseimet @@ -17608,10 +17691,10 @@ user#:#user_profile_data_checked#:#A profiladatokat ellenőriztük user#:#user_profile_info#:#Felhasználói profilinformáció user#:#user_profile_info_std#:#Alapértelmezett Felhasználói Profil Információ user#:#user_profile_info_text_info#:#Ez a szöveg a személyes adatok megadására szolgáló űrlap tetején jelenik meg. -user#:#user_profile_portfolio#:#Ha egy portfóliót a személyes profiljaként szeretne használni, a portfóliórészben jelölje ki 'Profilom'-nak. -user#:#user_profile_portfolio_selected#:#Jelenleg egy portfóliót használ profiljaként. Az aktiválás a 'Megosztás' fülön állítható be ott. -user#:#user_profile_preview#:#Előnézet -user#:#user_profile_prompt_text#:#Prompt Text###28 10 2024 new variable +user#:#user_profile_portfolio#:#Ha egy portfóliót a személyes profiljaként szeretne használni, a portfóliórészben jelölje ki ‘Profilom’-nak. +user#:#user_profile_portfolio_selected#:#Jelenleg egy portfóliót használ profiljaként. Az aktiválás a ‘Megosztás’ lapon állítható be ott. +user#:#user_profile_preview#:#Profil előnézete +user#:#user_profile_prompt_text#:#Prompt szöveg user#:#user_profile_prompt_text_info#:#Ez a szöveg jelenik meg az alapértelmezett információs szöveg helyett a felhasználó profiljának megjelenítésekor. user#:#user_prompt_incomplete#:#Csak ha a profil nem teljes user#:#user_prompt_incomplete_info#:#A profil bejelentkezés után megjelenik, amennyiben a felhasználónak van ki nem töltött, kötelező mezője. @@ -17621,22 +17704,22 @@ user#:#user_prompt_repeat#:#Minden X-edik napon. user#:#user_prompt_repeat_info#:#Amíg a felhasználó nem publikálja profiját, rendszeresen felkérjük erre. user#:#user_prompting_recurrence#:#Felkérés ismétlődése user#:#user_prompting_settings#:#Felkérés beállításai -user#:#user_public_profile_info#:#Válassza ki, mely személyes adatai legyenek láthatóak profiljában, és hogy mely felhasználók lássák profilját. +user#:#user_public_profile_info#:#Válassza ki, mely személyes adatai legyenek láthatók profiljában, és hogy mely felhasználók lássák profilját. user#:#user_publish_options#:#Profil közzététele -user#:#user_role_selection#:#Role Selection###26 08 2024 new variable +user#:#user_role_selection#:#Szerepkör kiválasztása user#:#user_role_starting_point#:#Felhasználó - Kiindulási pont user#:#user_save_continue#:#Mentés és folytatás user#:#user_save_ordering_and_titles#:#Sorrend és címek mentése user#:#user_select_course_group#:#Kurzus/csoport kiválasztása user#:#user_set_publishing_options#:#Közzététel beállítása user#:#user_set_visibilty_options#:#Láthatóság beállítása -user#:#user_settings#:#User Settings###29 10 2025 new variable +user#:#user_settings#:#Felhasználói beállítások user#:#user_store_last_visited#:#Utolsó megtekintéseim user#:#user_visibility_settings#:#Láthatóság -user#:#user_visible_in_profile#:#Látható a 'Felhasználói adatok és profil' alatt -user#:#usr_id#:#User-ID +user#:#user_visible_in_profile#:#Látható a ‘Felhasználói adatok és profil’ alatt +user#:#usr_id#:#User_id user#:#usr_letter_avatars#:#Betűavatárok -user#:#usr_letter_avatars_info#:#A név vagy a felhasználónév kezdetét használata profilképként, ha nincs nyilvános kép. +user#:#usr_letter_avatars_info#:#A név vagy a felhasználónév kezdete legyen a profilkép, ha nincs nyilvános kép. user#:#usr_public_profile_disabled#:#Profil letiltva user#:#usr_public_profile_disabled_info#:#Az információit csak az adminisztratív személyzet láthatja. user#:#usr_public_profile_global#:#WWW / Minden felhasználó elérheti az interneten @@ -17644,26 +17727,26 @@ user#:#usr_public_profile_logged_in#:#Bejelentkezett felhasználók számára l usr#:#user_action#:#Felhasználói művelet usr#:#user_actions#:#Felhasználói műveletek usr#:#user_actions_activation_info#:#A műveleteket csak akkor soroljuk fel a felhasználóknak, ha a kapcsolódó szolgáltatásokat bekapcsolták és az összes előfeltétel adott (például szükséges jogosultságok). -validation#:#datetime_required#:#Time/Date required###29 07 2022 new variable -validation#:#no_array#:#Given value is not an array###29 07 2022 new variable -validation#:#not_a_null#:#'%s' típus értéke nem üres. -validation#:#not_a_string#:#'%s' típus értéke nem sztring. -validation#:#not_an_array#:#'%s' nem egy halmaz. +validation#:#datetime_required#:#Idő/Dátum kötelező +validation#:#no_array#:#A megadott érték nem halmaz +validation#:#not_a_null#:#‘%s’ típus értéke nem üres. +validation#:#not_a_string#:#‘%s’ típus értéke nem sztring. +validation#:#not_an_array#:#‘%s’ nem egy halmaz. validation#:#not_an_array_of#:#A halmaza elemszáma nem %s. -validation#:#not_an_int#:#'%s' típus értéke nem egész szám. +validation#:#not_an_int#:#‘%s’ típus értéke nem egész szám. validation#:#not_generic#:#Ez nem ilyen: %s -validation#:#not_greater_than#:#'%s' nem nagyobb, mint '%s'. -validation#:#not_greater_than_or_equal#:#The value is not greater than or equal '%s'.###29 07 2022 new variable -validation#:#not_less_than#:#'%s' nem kisebb, mint '%s'. -validation#:#not_less_than_or_equal#:#The value is not less than or equal '%s'.###29 07 2022 new variable -validation#:#not_max_length#:#A megadott szöveg hossza több, mint '%s'. +validation#:#not_greater_than#:#‘%s’ nem nagyobb, mint ‘%s’. +validation#:#not_greater_than_or_equal#:#‘%s’ nem nagyobb vagy egyenlő, mint ‘%s’. +validation#:#not_less_than#:#‘%s’ nem kisebb, mint ‘%s’. +validation#:#not_less_than_or_equal#:#A megadott szöveg nem kisebb vagy egyenlő, mint ‘%s’. +validation#:#not_max_length#:#A megadott szöveg hossza több, mint ‘%s’. validation#:#not_min_length#:#A megadott érték hossza %d, ami a minimumnál (%d) kevesebb. -validation#:#not_numeric#:#'%s' nem szám. +validation#:#not_numeric#:#‘%s’ nem szám. validation#:#not_numeric_empty_string#:#A megadott adat nem szám. -validation#:#numeric_only#:#Please insert a whole number.###26 08 2024 new variable -validation#:#required#:#This input is required.###29 10 2025 new variable -validation#:#tag_required#:#Please insert at least one tag.###26 08 2024 new variable -violation#:#not_a_string#:#Given value is not a String###29 07 2022 new variable +validation#:#numeric_only#:#Egész számot adjon meg. +validation#:#required#:#Ezt kötelező megadni. +validation#:#tag_required#:#Legalább egy címkét adjon meg. +violation#:#not_a_string#:#A megadott érték nem szöveg webr#:#invalid_links_tbl#:#Érvénytelen linkek webr#:#webr_active#:#Aktív webr#:#webr_container_info#:#Adjon meg címet és esetleg leírást ennek a Tartalomtárban levő weblink-gyűjteményének a bemutatásához. @@ -17683,7 +17766,7 @@ webr#:#webr_list_added#:#Az új weblink-gyűjtemányt sikeresen létrehozta. webr#:#webr_list_desc#:#Weblink-gyűjtemény leírása webr#:#webr_list_set#:#A weblinket sikeresen weblink-gyűjteménnyé alakította. webr#:#webr_list_title#:#Weblink-gyűjtemény címe -webr#:#webr_new#:#Create Weblink###29 10 2025 new variable +webr#:#webr_new#:#Weblink létrehozása webr#:#webr_new_link#:#Új weblink létrehozása webr#:#webr_new_list#:#Új weblink-gyűjteménye létrehozása webr#:#webr_new_list_info#:#A weblink-gyűjtemény megjelenítéshez a Tartalomtárban, adjon meg címet és esetleg leírást. @@ -17692,10 +17775,10 @@ webr#:#webr_sort_manual#:#Kézi sorba rendezés webr#:#webr_sort_title#:#Cím szerinti rendezés webr#:#webr_sorting#:#Weblinkek sorba rendezése wfld#:#wfld_add#:#Mappa létrehozása -wfld#:#wfld_alphabetically_asc#:#Betűrend, növ. -wfld#:#wfld_alphabetically_desc#:#Betűrend csökk. -wfld#:#wfld_creation_asc#:#étrehozás dátuma, növ. -wfld#:#wfld_creation_desc#:#Létrehozás dátuma, csökk. +wfld#:#wfld_alphabetically_asc#:#Betűrend ↑ +wfld#:#wfld_alphabetically_desc#:#Betűrend ↓ +wfld#:#wfld_creation_asc#:#Létrehozás dátuma ↑ +wfld#:#wfld_creation_desc#:#Létrehozás dátuma ↓ wfld#:#wfld_derive#:#Szülőtől öröklődik wfld#:#wfld_edit#:#Mappa módosítása wfld#:#wfld_new#:#Új mappa létrehozása @@ -17706,7 +17789,7 @@ wiki#:#wiki_activate_page_rating#:#Értékelés bekapcsolása wiki#:#wiki_activate_rating#:#Oldalak értékelésének engedélyezése wiki#:#wiki_add_link#:#Link létrehozása wiki#:#wiki_add_template#:#Sablonként megjelöl -wiki#:#wiki_advmd_block_title#:#Oldal bővített metaadatai +wiki#:#wiki_advmd_block_title#:#Oldal egyéni metaadatai wiki#:#wiki_all_pages#:#Összes lap wiki#:#wiki_block_page#:#Beállítás írásvédetté wiki#:#wiki_change_notification_body_new#:#az alábbi wikioldal jött létre @@ -17716,7 +17799,7 @@ wiki#:#wiki_change_notification_page_body_delete#:#ezúton értesítjük, hogy a wiki#:#wiki_change_notification_page_body_update#:#ezúton értesítjük, hogy az alábbi wikilapokat sikeresen frissítette wiki#:#wiki_change_notification_page_link#:#URL wiki#:#wiki_change_notification_salutation#:#Tisztelt %s, -wiki#:#wiki_change_notification_subject#:#'%1$s' wiki megváltozott: %2$s +wiki#:#wiki_change_notification_subject#:#‘%1$s’ wiki megváltozott: %2$s wiki#:#wiki_changed_by#:#Módosította wiki#:#wiki_commented_by#:#A hozzászólást írta wiki#:#wiki_contributor#:#Közreműködő @@ -17731,7 +17814,7 @@ wiki#:#wiki_empty_page#:#Üres oldal wiki#:#wiki_empty_page_template#:#Oldal létrehozása üres sablonnal wiki#:#wiki_exc_template#:#Wikisablon wiki#:#wiki_exc_wiki_created#:#A wikit sikeresen létrehozta. -wiki#:#wiki_exercise_info#:#Ez a wiki része a következő feladatnak: '%s' / '%s'. +wiki#:#wiki_exercise_info#:#Ez a wiki része a következő feladatnak: ‘%s’ / ‘%s’. wiki#:#wiki_exercise_submitted_info#:#Utolsó beküldésének időpontja: %s. Ellenőrizze az exportfájlt. wiki#:#wiki_failed#:#Sikertelen wiki#:#wiki_feedback_from_tutor#:#Visszajelzés a tutortól @@ -17743,7 +17826,7 @@ wiki#:#wiki_grading#:#Értékelés wiki#:#wiki_html_export#:#Exportálás HTML-ként wiki#:#wiki_imp_page_added#:#Sikeresen létrehozott egy lapot. wiki#:#wiki_import#:#Wiki importálása -wiki#:#wiki_incl_comments#:#including comments +wiki#:#wiki_incl_comments#:#hozzászólásokkal együtt wiki#:#wiki_indentation#:#Behúzás wiki#:#wiki_introduction#:#Bevezetés wiki#:#wiki_last_changed#:#Utolsó módosítás @@ -17754,8 +17837,8 @@ wiki#:#wiki_link_md_values#:#Automatikus linkelés wiki#:#wiki_link_md_values_info#:#Az automatikusan linkelt tulajdonságok a wiki oldal oldalsávjában jelenik meg ugyanazon a néven. wiki#:#wiki_link_text#:#Link szövege wiki#:#wiki_mark#:#Osztályzat -wiki#:#wiki_master_existing#:#Page Exists in Master Language###26 08 2024 new variable -wiki#:#wiki_master_title#:#Title of Page in Master Language###26 08 2024 new variable +wiki#:#wiki_master_existing#:#Az oldal létezik a főnyelven +wiki#:#wiki_master_title#:#Az oldal címe főnyelven wiki#:#wiki_navigation#:#Wikinavigáció wiki#:#wiki_navigation_info#:#Itt adhatja hozzá wikilapok linkjeit a wiki navigációs blokkjához, illetve távolíthat el linkeket a blokkból. wiki#:#wiki_new_page#:#Új oldal @@ -17763,11 +17846,11 @@ wiki#:#wiki_new_page_name#:#Új cím wiki#:#wiki_new_pages#:#Új lapok wiki#:#wiki_news_page_changed#:#A wikilap frissült wiki#:#wiki_news_page_created#:#Sikeresen létrehozott egy új wikilapot. -wiki#:#wiki_no_master#:#Page Does Not Exist in Master Language###26 08 2024 new variable -wiki#:#wiki_no_page_found#:#Nincs wikioldal a kifejezéshez: '$1'. +wiki#:#wiki_no_master#:#Az oldal még nem létezik a főnyelven. +wiki#:#wiki_no_page_found#:#Nincs wikioldal a kifejezéshez: ‘$1’. wiki#:#wiki_no_search_term#:#Nem adott meg keresési feltételt. Az összes wikioldalt felsoroljuk. wiki#:#wiki_no_start_page#:#A wikiből hiányzik az érvényes kezdőlap. -wiki#:#wiki_not_existing#:#not existing yet###26 08 2024 new variable +wiki#:#wiki_not_existing#:#még nem létezik wiki#:#wiki_notgraded#:#Nincs értékelve wiki#:#wiki_notification_activate_page#:#Értesítés bekapcsolása lapra wiki#:#wiki_notification_activate_wiki#:#Értesítés bekapcsolása wikire @@ -17785,18 +17868,18 @@ wiki#:#wiki_other_pages_linking#:#Erre a lapra linkelő más lapok wiki#:#wiki_page#:#Lap wiki#:#wiki_page_actions#:#Laptevékenységek wiki#:#wiki_page_already_exists#:#Már van ilyen című lap. -wiki#:#wiki_page_blocked#:#A wikilap írásvédett. Csak a «Beállítások módosítása» joggal rendelkezőknek van írási joguk hozzá. +wiki#:#wiki_page_blocked#:#A wikilap írásvédett. Csak a ‘Beállítások módosítása’ joggal rendelkezők tudják módosítani. wiki#:#wiki_page_changes#:#Lapmódosítások wiki#:#wiki_page_deleted#:#A wikilapot sikeresen törölte. wiki#:#wiki_page_deletion_confirmation#:#Biztos, hogy törli ezt a wikilapot? wiki#:#wiki_page_exists#:#Létező oldal wiki#:#wiki_page_hits#:#Laplátogatások -wiki#:#wiki_page_in_master_language#:#Page in Master Language###26 08 2024 new variable +wiki#:#wiki_page_in_master_language#:#Az oldal főnyelven. wiki#:#wiki_page_list_form_info#:#Az alábbi kiválasztott metaadathoz rendelt wikioldalakat sorolja fel. Csak a kereshető metaadat-mezőket soroljuk fel. wiki#:#wiki_page_list_mode#:#Felsorolás típusa wiki#:#wiki_page_list_mode_ordered#:#Számozott wiki#:#wiki_page_list_mode_unordered#:#Listajeles -wiki#:#wiki_page_lists#:#Lapok +wiki#:#wiki_page_lists#:#Lapok áttekintése wiki#:#wiki_page_not_exist_select_templ#:#Ez az oldal még nem létezik. Válasszon egy sablont az új oldalnak. wiki#:#wiki_page_notification_activated#:#Értesítés bekapcsolva (egy oldalra) wiki#:#wiki_page_status_blocked#:#A lap írásvédett. @@ -17808,7 +17891,7 @@ wiki#:#wiki_page_toc_info#:#Ennek a listának minden címe az egyes lapok tartal wiki#:#wiki_page_type_wpg#:#Wikioldal wiki#:#wiki_page_unblocked#:#A felhasználók írási jogosultságot kaptak. wiki#:#wiki_pages#:#Lapok -wiki#:#wiki_pages_found#:#A következő wikioldalakat találtuk a kifejezéshez: '$1'. +wiki#:#wiki_pages_found#:#A következő wikioldalakat találtuk a kifejezéshez: ‘$1’. wiki#:#wiki_passed#:#Sikeres wiki#:#wiki_pg_list_no_search_fields#:#A wiki metaadata gyűjteményében egy kereshető metaadat sem található. wiki#:#wiki_please_enter_search_term#:#Adjon meg keresési időt. @@ -17827,7 +17910,7 @@ wiki#:#wiki_rename_page#:#Lap átnevezése wiki#:#wiki_save_ordering_and_indent#:#Rendezés és behúzás mentése wiki#:#wiki_search#:#Keresés wiki#:#wiki_search_results#:#Keresési találatok -wiki#:#wiki_sec_protect_info#:#Protected sections can only be edited by users having "Edit Settings" permission.###29 07 2022 new variable +wiki#:#wiki_sec_protect_info#:#A védett fejezeteket csak a ‘Beállítások módosítása’ jogosultsággal rendelkezők szerkeszthetik. wiki#:#wiki_select_one_item#:#Egy elemet válasszon ki. wiki#:#wiki_selected_pages#:#Kiválasztott lapok wiki#:#wiki_set_as_start_page#:#Beállítás kezdőoldalnak @@ -17879,54 +17962,53 @@ wiki#:#wiki_templ_add_to_page#:#Meglévő oldalhoz használható wiki#:#wiki_templ_new_pages#:#Új oldalhoz használható wiki#:#wiki_template_added#:#Sikeresen létrehozott egy sablont. wiki#:#wiki_template_status_removed#:#A sablont sikeresen eltávolította. -wiki#:#wiki_translate_page_master_info#:#You are creating a new wiki page translation. Please specify, if this translation belongs to an existing master version of the page, or if a completely new page is being created. In the second case you need to specify a page title for the master version.###26 08 2024 new variable -wiki#:#wiki_translation_page#:#Translation Page###26 08 2024 new variable -wiki#:#wiki_translations#:#Translations###26 08 2024 new variable +wiki#:#wiki_translate_page_master_info#:#Új wikioldal fordítást hoz létre. Kérjük, adja meg, hogy ez a fordítás az oldal egy meglévő főverziójához tartozik-e, vagy egy teljesen új oldal készül. A második esetben meg kell adnia a főverzió oldalcímét. +wiki#:#wiki_translation_page#:#Fordítási oldal +wiki#:#wiki_translations#:#Fordítások wiki#:#wiki_type_wiki_team#:#Csapatwiki wiki#:#wiki_unblock_page#:#Írási jog megadása wiki#:#wiki_unhide_meta_adv_records#:#További tulajdonságok megjelenítése wiki#:#wiki_what_links_here#:#Ide mutató linkek -wiki#:#wiki_what_links_to_page#:#Mi hivatkozik a(z) '%s' lapra? +wiki#:#wiki_what_links_to_page#:#Mi hivatkozik a(z) ‘%s’ lapra? wiki#:#wiki_whole_wiki#:#Teljes wiki wiki#:#wiki_wiki_page#:#Wikilap wiki#:#wiki_wiki_search#:#Wikikeresés wiki#:#wiki_wpg#:#Wiki oldal -wopi#:#action_edit#:#Edit###28 10 2024 new variable -wopi#:#action_view#:#View###28 10 2024 new variable -wopi#:#activate_saving_interval#:#Activate Saving Interval###28 10 2024 new variable -wopi#:#activate_wopi#:#Activate WOPI###26 08 2024 new variable -wopi#:#close_wopi_editor#:#Close Editor###26 08 2024 new variable -wopi#:#close_wopi_editor_info#:#It can take up to several minutes for the external editor to transfer the changes to ILIAS. Visit this page again at a later time if the changes you have made are not yet visible.###26 08 2024 new variable -wopi#:#currently_supported#:#Currently supported Suffixes: %s###26 08 2024 new variable -wopi#:#msg_error_wopi_invalid_discorvery_url#:#The Discovery URL entered is invalid or cannot be accessed.###26 08 2024 new variable -wopi#:#msg_wopi_settings_modified#:#Settings stored###26 08 2024 new variable -wopi#:#open_external_editor#:#Open in external Editor###26 08 2024 new variable -wopi#:#open_external_viewer#:#Show Content###28 10 2024 new variable -wopi#:#saving_interval#:#Interval###28 10 2024 new variable -wopi#:#saving_interval_byline#:#By default, ILIAS adds all changes made by an external editor to a draft version until this version is published manually. Activating the save interval causes a new version to be published after the specified number of seconds, if possible. Please note that a low value can lead to a large number of file versions, which in turn takes up a multiple of the hard disk space.###28 10 2024 new variable -wopi#:#wopi_crawler_cronjob_description#:#Updates the information of the connected WOPI service.###26 08 2024 new variable -wopi#:#wopi_crawler_cronjob_no_apps#:#No WOPI apps were found in the discovery.###26 08 2024 new variable -wopi#:#wopi_crawler_cronjob_not_activated#:#WOPI is not activated.###26 08 2024 new variable -wopi#:#wopi_crawler_cronjob_success#:#WOPI information updated successfully.###26 08 2024 new variable -wopi#:#wopi_crawler_cronjob_title#:#Update WOPI Discovery###26 08 2024 new variable -wopi#:#wopi_settings#:#WOPI###26 08 2024 new variable -wopi#:#wopi_url#:#WOPI Discovery URL###26 08 2024 new variable -wopi#:#wopi_url_byline#:#Complete URL of the WOPI-Discovery, this must be accessible through the ILIAS server. The XML data of the Discover is read in and stored by ILIAS, the information is regularly updated by the cronjob "Update WOPI Discovery". Example: https://example.org/hosting/discovery###26 08 2024 new variable +wopi#:#action_edit#:#Szerkesztés +wopi#:#action_view#:#Megjelenítése +wopi#:#activate_saving_interval#:#Automatikus mentés +wopi#:#activate_wopi#:#WOPI bekapcsolása +wopi#:#close_wopi_editor#:#Szerkesztő bezárása +wopi#:#close_wopi_editor_info#:#Több percig is eltarthat, amíg a külső szerkesztő átviszi a változtatásokat az ILIAS-ba. Látogassa meg újra ezt az oldalt egy későbbi időpontban, ha a végrehajtott módosítások még nem láthatók. +wopi#:#currently_supported#:#Jelenleg támogatott utótagok: %s +wopi#:#msg_error_wopi_invalid_discorvery_url#:#A Discovery URL nem valós vagy nem érhető el. +wopi#:#msg_wopi_settings_modified#:#A beállításokat sikeresen mentette +wopi#:#open_external_editor#:#Megnyitás külső szerkesztőben +wopi#:#open_external_viewer#:#Tartalom megjelenítése +wopi#:#saving_interval#:#Mentési időköz +wopi#:#saving_interval_byline#:#Az ILIAS alapértelmezetten az összes külső szerkesztő módosítását hozzáadja a piszkozathoz, amíg azt manuálisan közzé nem teszik. A mentési időközben megadott másodperc után új verzió jelenik meg. Kérjük, vegye figyelembe, hogy az alacsony érték sok verziót jelent, aminek nagy lehet a tárhelyigénye. +wopi#:#wopi_crawler_cronjob_description#:#A csatlakoztatott WOPI szolgáltatás információinak frissítése. +wopi#:#wopi_crawler_cronjob_no_apps#:#Egy WOPI app-ot sem találtunk a discovery-ben. +wopi#:#wopi_crawler_cronjob_not_activated#:#WOPI nincs bekapcsolva. +wopi#:#wopi_crawler_cronjob_success#:#A WOPI információt sikeresen módosította. +wopi#:#wopi_crawler_cronjob_title#:#WOPI Discovery frissítése +wopi#:#wopi_settings#:#WOPI +wopi#:#wopi_url#:#WOPI Discovery URL +wopi#:#wopi_url_byline#:#A WOPI Discovery teljes URL-je, ennek elérhetőnek kell lennie az ILIAS szerveren keresztül. A Discover XML-adatait az ILIAS olvassa be és tárolja, az információkat rendszeresen frissíti a ‘WOPI Discovery frissítése’ ütemezett feladat. Például: https://example.org/hosting/discovery wsp#:#element_already_shared#:#Ezt az objektumot már megosztotta evvel a felhasználóval. wsp#:#element_shared#:#Az objektumot sikeresen megosztotta. -wsp#:#error_creating_certificate_pdf#:#Az igazolást nem sikerült létrehozni. Kérem, keresse a szerver üzemeltetőjét. -wsp#:#search_no_match#:#A keresése nem adott eredményt. +wsp#:#error_creating_certificate_pdf#:#A tanúsítványt nem sikerült létrehozni. Kérem, keresse a szerver üzemeltetőjét. wsp#:#share#:#Megosztás wsp#:#share_content#:#Megosztott objektum wsp#:#share_with#:#Felhasználónév wsp#:#wsp_copy_to_repository#:#Tartalomtárba másolás wsp#:#wsp_invalid_password#:#A megadott jelszó érvénytelen. -wsp#:#wsp_list_cmxv#:#xAPI/cmi5 Objektum tanúsítványa -wsp#:#wsp_list_crsv#:#Kurzusigazolás -wsp#:#wsp_list_excv#:#Beadandó feladatról igazolás +wsp#:#wsp_list_cmxv#:#xAPI/cmi5-objektum tanúsítványa +wsp#:#wsp_list_crsv#:#Kurzustanúsítvány +wsp#:#wsp_list_excv#:#Beadandó feladatról tanúsítvány wsp#:#wsp_list_ltiv#:#LTI-Fogyasztóobjektum tanúsítványa -wsp#:#wsp_list_scov#:#SCORM-igazolás -wsp#:#wsp_list_tstv#:#Tesztről igazolás +wsp#:#wsp_list_scov#:#SCORM-tanúsítvány +wsp#:#wsp_list_tstv#:#Tesztről tanúsítvány wsp#:#wsp_move_to_repository#:#Tartalomtárba mozgatás wsp#:#wsp_password_for#:#Jelszó ehhez: wsp#:#wsp_password_protected_resource#:#Jelszóvédett forrás @@ -17937,7 +18019,8 @@ wsp#:#wsp_permission_registered_info#:#Az objektumot megosztotta az összes regi wsp#:#wsp_permission_removed#:#A bejegyzést sikeresen törölte. wsp#:#wsp_permissions#:#Megosztás wsp#:#wsp_personal_resources_description#:#Itt kezelheti személyes fájljait, blogjait és alkotásait. -wsp#:#wsp_send_mail#:#Send Mail###26 08 2024 new variable +wsp#:#wsp_search_no_match#:#Nincs találat a keresésére. +wsp#:#wsp_send_mail#:#Levél küldése wsp#:#wsp_set_permission_all#:#World Wide Web wsp#:#wsp_set_permission_all_password#:#World Wide Web (jelszóval) wsp#:#wsp_set_permission_course#:#Kurzus @@ -17969,11 +18052,11 @@ wsp#:#wsp_tab_personal#:#Forrásaim wsp#:#wsp_tab_shared#:#Más felhasználók forrásai wsp#:#wsp_type_blog#:#Blog wsp#:#wsp_type_cmxv#:#Tanúsítvány: xAPI/cmi5 -wsp#:#wsp_type_crsv#:#Igazolás: Kurzus -wsp#:#wsp_type_excv#:#Igazolás: beadandó feladat +wsp#:#wsp_type_crsv#:#Tanúsítvány: Kurzus +wsp#:#wsp_type_excv#:#Tanúsítvány: beadandó feladat wsp#:#wsp_type_file#:#Fájl wsp#:#wsp_type_ltiv#:#Tanúsítvány: LTI-Fogyasztók -wsp#:#wsp_type_scov#:#Igazolás: SCORM -wsp#:#wsp_type_tstv#:#Igazolás: teszt +wsp#:#wsp_type_scov#:#Tanúsítvány: SCORM +wsp#:#wsp_type_tstv#:#Tanúsítvány: teszt wsp#:#wsp_type_webr#:#Weblink wsp#:#wsp_type_wfld#:#Mappa \ No newline at end of file diff --git a/lang/ilias_it.lang b/lang/ilias_it.lang index ee903ef4af9d..c33704cedc67 100644 --- a/lang/ilias_it.lang +++ b/lang/ilias_it.lang @@ -421,7 +421,6 @@ adve#:#adve_use_tiny_mce#:#Abilita TinyMCE come Editor WYSIWYG (What You See Is assessment#:#activate_logging#:#Activate Test and Assessment Logging###28 11 2025 new variable assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 11 2025 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 11 2025 new variable -assessment#:#addSuggestedSolution#:#Contenuti per il ripasso assessment#:#add_answers#:#Aggiungi risposte assessment#:#add_circle#:#Aggiungi cerchio assessment#:#add_gap#:#Aggiungi lacuna di testo @@ -446,7 +445,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Hai ricevuto dei punti per la assessment#:#answer_is_right#:#La soluzione è corretta. assessment#:#answer_is_wrong#:#La soluzione è sbagliata. assessment#:#answer_of#:#Risposta di -assessment#:#answer_options#:#Opzioni di risposte: assessment#:#answer_question#:#Risposta domanda assessment#:#answer_text#:#Testo della risposta assessment#:#answer_types#:#Tipi di risposta @@ -500,7 +498,6 @@ assessment#:#ass_completion_by_submission#:#Completato da presentazione assessment#:#ass_completion_by_submission_info#:#Se abilitato, la presentazione di almeno un file causa il completamento di questa domanda garantendo il punteggio massimo per questa domanda. Il punteggio può essere modificato manualmente in seguito. In cambiamento di questa impostazione non effetto sulle domande già presentate. assessment#:#ass_create_export_file_with_results#:#Crea file di esportazione dei test (inclusi i risultati dei partecipanti) assessment#:#ass_create_export_test_archive#:#Crea file archivio dei test -assessment#:#ass_create_question#:#Crea domanda assessment#:#ass_imap_hint#:#Il suggerimento deve essere mostrato come Descrizione comando assessment#:#ass_imap_map_file_not_readable#:#L’immagine caricata della mappa non può essere letta. assessment#:#ass_imap_no_map_found#:#Non è possibile trovare alcun modello nell’immagine della mappa caricata. @@ -570,10 +567,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Lunghezza del campo di testo assessment#:#cloze_fixed_textlength_description#:#Se si inserisce un valore maggiore di 0 tutte le mancanze di testo e di numero avranno quella lunghezza. assessment#:#cloze_gap_size_info#:#Se si immette un valore maggiore di 0, questo campo di testo spazio verrà creato con la lunghezza fissa di questo valore. Se non si immette un valore, il campo di testo del gap verrà creato con il valore della lunghezza fissa globale. -assessment#:#cloze_text#:#Testo corrispondente -assessment#:#cloze_textgap_case_insensitive#:#No Maiuscole/minuscole -assessment#:#cloze_textgap_case_sensitive#:#Maiuscole/minuscole -assessment#:#cloze_textgap_levenshtein_of#:#Distanza di Levenshtein del %s assessment#:#code#:#Codice assessment#:#codebase#:#Base dei codici assessment#:#concatenation#:#Concatenazione @@ -756,9 +749,7 @@ assessment#:#fq_formula_desc#:#È possibile inserire variabili predefinite (da $ assessment#:#fq_no_restriction_info#:#Entrambi i decimali e le frazioni sono accettati come input. assessment#:#fq_precision_info#:#Digita il numero delle posizioni decimali desiderate. assessment#:#fq_question_desc#:#È possibile definire le variabili inserendo $ v1, $ v2 ... $ vn, i risultati inserendo $ r1, $ r2 .... $ rn nella posizione desiderata nel testo della domanda. Fare clic sul pulsante "Analizza domanda" per creare moduli di modifica per variabili e risultati. -assessment#:#gap#:#Spazio vuoto assessment#:#gap_combination#:#Combinazione di Gap -assessment#:#gaps#:#Gaps###28 11 2025 new variable assessment#:#glossary_term#:#Voce del glossario assessment#:#goto_first_question#:#Show first question###28 11 2025 new variable assessment#:#grading_mark_msg#:#Il tuo punteggio risultante è: "[mark]" @@ -776,7 +767,6 @@ assessment#:#info_answer_type_change#:#La domanda contiene già delle immagini. assessment#:#info_text_upload#:#Scegli un file di risposte da caricare assessment#:#insert_after#:#Inserisci dopo assessment#:#insert_before#:#Inserisci prima -assessment#:#insert_gap#:#Inserisci Gap assessment#:#interaction_type#:#Interaction Type###28 11 2025 new variable assessment#:#internal_links#:#Link interni assessment#:#intprecision#:#Divisibile per @@ -888,7 +878,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Menù esteso assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###28 07 2023 new variable assessment#:#longmenu_text#:#Testo menu esteso -assessment#:#mainbar_button_label_questionlist#:#Questionlist###30 04 2024 new variable assessment#:#maintenance#:#Manutenzione assessment#:#manscoring#:#Punteggio manuale assessment#:#manscoring_done#:#Partecipanti Valutati @@ -915,7 +904,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Hai raggiunto il numero massimo di pa assessment#:#maximum_points#:#Punteggio massimo disponibile assessment#:#maxsize#:#massima dimensione file di upload assessment#:#maxsize_info#:#Inserire la massima dimensione in, bytes, dei files da caricare. Se il campo è lasciato in bianco, la dimensione sarà definita dal sistema. -assessment#:#min_auto_complete#:#Completamento automatico assessment#:#min_ip_label#:#Lowest IP With Access###28 11 2025 new variable assessment#:#min_percentage_ne_0#:#Devi raggiungere la percentuale minima dello 0 percento! Lo schema voti non e' stato salvato. assessment#:#misc#:#Opzioni varie @@ -924,7 +912,6 @@ assessment#:#mode_onebyone#:#One by One###28 11 2025 new variable assessment#:#mode_question#:#Question oriented###28 11 2025 new variable assessment#:#mode_user#:#Participant oriented###28 11 2025 new variable assessment#:#msg_circle_added#:#Circonferenza aggiunta -assessment#:#msg_no_questions_selected#:#No questions were selected.###30 04 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Il numero dei termini deve essere maggiore o uguale al numero delle definizioni assessment#:#msg_poly_added#:#Aggiunto poligono assessment#:#msg_questions_moved#:#Domanda(e) spostata(e) @@ -983,7 +970,6 @@ assessment#:#order#:#Order###09 11 2022 new variable assessment#:#ordering_answer_sequence_info#:#La sequenza di risposte che definisci qui sara' presa come sequenza di risposte corrette. assessment#:#ordertext#:#Ordinando il testo assessment#:#ordertext_info#:#Per favore, inserisci il testo che dovrebbe essere ordinato orizzontalmente. Il testo ordinato sarà separato da spazi vuoti. Se c'e' bisogno di una differente spaziatura, si può usare il separatore %s per separare il testo.
    -assessment#:#out_of_range#:#Fuori portata assessment#:#output#:#Uscita assessment#:#output_mode#:#Modalità di output assessment#:#parseQuestion#:#Analizza domanda @@ -1052,7 +1038,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 11 2025 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 11 2025 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 11 2025 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Annulla -assessment#:#qpl_confirm_delete_questions#:#Sei sicuro di voler eliminare le seguenti domande? Se cancelli le domande bloccate, anche i risultati dei test che le contengono verranno cancellati. assessment#:#qpl_copy_insert_clipboard#:#Le domande selezionate sono state copiate negli appunti assessment#:#qpl_copy_select_none#:#Seleziona almeno una domanda da copiare negli appunti assessment#:#qpl_delete_rbac_error#:#Non hai l'autorizzazione per eliminare questa raccolta di domande! @@ -1105,7 +1090,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#competenze assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Somma totale di punti di competenze per competenze assessment#:#qpl_question_is_in_use#:#La domanda che stai per modificare è inserita in un %s dei test. Se modifichi la domanda, NON verranno modificate le domande nei test, perchè il sistema crea una copia delle domande quando queste vengono inserite in un test! assessment#:#qpl_questions_deleted#:#Domande eliminate -assessment#:#qpl_reset_preview#:#Ripristina anteprima assessment#:#qpl_save_skill_assigns_update#:#Salva assegnazioni della competenze assessment#:#qpl_settings_availability#:#Availability###30 04 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Se abilitato, le tassonomie eventualmente create vengono mostrate per il filtro. @@ -1135,14 +1119,6 @@ assessment#:#qst_essay_chars_remaining#:#Caratteri rimanenti: assessment#:#qst_essay_wordcounter_enabled#:#Conta parole assessment#:#qst_essay_wordcounter_enabled_info#:#Le parole inserite vengono contate. Il numero di parole scritte viene mostrato ai partecipanti sotto il campo di immissione del testo. assessment#:#qst_essay_written_words#:#Numero di parole inserite: -assessment#:#qst_lifecycle#:#Ciclo vitale -assessment#:#qst_lifecycle_draft#:#Bozza -assessment#:#qst_lifecycle_filter_all#:#Tutti i cicli di vita -assessment#:#qst_lifecycle_final#:#Finale -assessment#:#qst_lifecycle_outdated#:#Obsoleto -assessment#:#qst_lifecycle_rejected#:#Respinto -assessment#:#qst_lifecycle_review#:#Da rivedere -assessment#:#qst_lifecycle_sharable#:#Condivisibile assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Numero di tentativi @@ -1166,17 +1142,14 @@ assessment#:#question_title#:#Titolo della domanda assessment#:#question_type#:#Tipo di domanda assessment#:#questionpool_not_entered#:#Per favore inserisci il nome della raccolta di domande! assessment#:#questionpool_not_selected#:#Please select a question pool! -assessment#:#questions#:#Questions###30 04 2024 new variable assessment#:#questions_from#:#domande da assessment#:#questions_per_page_view#:#Visualizza pagina assessment#:#random_accept_sample#:#Accetta esempio assessment#:#random_another_sample#:#Prendi un altro esempio assessment#:#random_selection#:#Scegli casualmente assessment#:#range#:#Intervallo -assessment#:#range_lower_limit#:#Limite inferiore assessment#:#range_max#:#Portata (Massima) assessment#:#range_min#:#Portata (Minima) -assessment#:#range_upper_limit#:#Limite superiore assessment#:#rated_sign#:#Segno assessment#:#rated_unit#:#Unità assessment#:#rated_value#:#Valore @@ -1252,7 +1225,6 @@ assessment#:#search_roles#:#Ricerca ruoli assessment#:#search_term#:#Ricerca termini assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###30 04 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###28 11 2025 new variable -assessment#:#select_gap#:#Seleziona spazio assessment#:#select_max_one_item#:#Per favore scegli un solo elemento assessment#:#select_one_user#:#Seleziona almeno un utente assessment#:#select_question#:#Select a Question###28 11 2025 new variable @@ -1279,7 +1251,6 @@ assessment#:#show_old_introduction#:#Show old introduction###30 04 2024 new vari assessment#:#show_pass_overview#:#Mostra il sommario dei voti assessment#:#show_results#:#Show Results###28 11 2025 new variable assessment#:#show_user_answers#:#Mostra le risposte valutate degli utenti -assessment#:#shuffle_answers#:#Mescola le risposte assessment#:#skip_question#:#Non rispondere e Avanti assessment#:#solution#:#Solution###28 11 2025 new variable assessment#:#solutionText#:#testo @@ -1400,7 +1371,7 @@ assessment#:#tst_answered_questions_of_total#:#%s di %s assessment#:#tst_answered_questions_test#:#Domande risposte in questo test assessment#:#tst_attached_xls_file#:#Puoi trovare il risultato del test per questo partecipante nel file Excel allegato. assessment#:#tst_attempt#:#Tentativo -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###30 04 2024 new variable +assessment#:#tst_attempt_limit_message#:#Numero totale di volte in cui puoi sostenere questo test: %s.###Tentative translation of new English entry. Please check. assessment#:#tst_attempt_started#:#Attempt Started###28 11 2025 new variable assessment#:#tst_back_to_pass_details#:#Torna ai dettagli del passaggio assessment#:#tst_back_to_question_list#:#Torna all’elenco domande @@ -1483,7 +1454,7 @@ assessment#:#tst_exam_password_invalid_message#:#The given password is not valid assessment#:#tst_exam_password_label#:#Password###30 04 2024 new variable assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###30 04 2024 new variable assessment#:#tst_exam_start#:#Start Test###30 04 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###30 04 2024 new variable +assessment#:#tst_exam_use_previous_answers#:#Usa le risposte precedenti###translation of new English entry #Use Previous Answers' assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###30 04 2024 new variable assessment#:#tst_extratime_added#:#L'orario di lavoro del partecipante è stato aumentato di %s minuti. assessment#:#tst_extratime_info#:#Se il tempo di elaborazione di un partecipante al test viene prolungato più volte, inserire qui il totale di tutte le sue estensioni di tempo. @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Non hai i diritti per incollare i seguenti oggetti: common#:#msg_no_perm_paste_object_in_folder#:#Non ha il permesso di incollare l’oggetto %s nella cartella %s. common#:#msg_no_perm_perm#:#Non hai i diritti per modificare le impostazioni dei permessi common#:#msg_no_perm_read#:#Non hai i diritti per accedere a questo oggetto. -common#:#msg_no_perm_read_item#:#Non sei autorizzato ad accedere all'elemento '%s'. +common#:#msg_no_perm_read_item#:#Non sei autorizzato ad accedere all'elemento. common#:#msg_no_perm_read_lm#:#Non hai i diritti per accedere a questo modulo. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###26 08 2025 new variable common#:#msg_no_perm_write#:#Non hai i diritti di scrittura @@ -13977,6 +13948,35 @@ qpl#:#qpl_page_type_qfbg#:#Feedback generale qpl#:#qpl_page_type_qfbs#:#Feedback speciali qpl#:#qpl_page_type_qht#:#Suggerimento qpl#:#qpl_page_type_qpl#:#Pagina delle domande +qsts#:#answer_options#:#Opzioni di risposte +qsts#:#cloze_text#:#Testo corrispondente +qsts#:#cloze_textgapcase_insensitive#:#No Maiuscole/minuscole +qsts#:#cloze_textgapcase_sensitive#:#Maiuscole/minuscole +qsts#:#cloze_textgaplevenshtein_of#:#Distanza di Levenshtein del %s +qsts#:#confirm_delete_questions#:#Sei sicuro di voler eliminare le seguenti domande? Se cancelli le domande bloccate, anche i risultati dei test che le contengono verranno cancellati. +qsts#:#create_question#:#Crea domanda +qsts#:#gap#:#Spazio vuoto +qsts#:#gaps#:#Gaps###28 11 2025 new variable +qsts#:#insert_gap#:#Inserisci Gap +qsts#:#min_auto_complete#:#Completamento automatico +qsts#:#msg_no_questions_selected#:#No questions were selected.###30 04 2024 new variable +qsts#:#out_of_range#:#Fuori portata +qsts#:#qst_lifecycle#:#Ciclo vitale +qsts#:#qst_lifecycle_draft#:#Bozza +qsts#:#qst_lifecycle_filter_all#:#Tutti i cicli di vita +qsts#:#qst_lifecycle_final#:#Finale +qsts#:#qst_lifecycle_outdated#:#Obsoleto +qsts#:#qst_lifecycle_rejected#:#Respinto +qsts#:#qst_lifecycle_review#:#Da rivedere +qsts#:#qst_lifecycle_sharable#:#Condivisibile +qsts#:#questionlist#:#Questionlist###30 04 2024 new variable +qsts#:#questions#:#Questions###30 04 2024 new variable +qsts#:#range_lower_limit#:#Limite inferiore +qsts#:#range_upper_limit#:#Limite superiore +qsts#:#reset_preview#:#Ripristina anteprima +qsts#:#select_gap#:#Seleziona spazio +qsts#:#shuffle_answers#:#Mescola le risposte +qsts#:#suggested_learning_content#:#Contenuti per il ripasso rating#:#rat_not_rated_yet#:#Non valutato rating#:#rat_nr_ratings#:#%s Valutazioni rating#:#rat_one_rating#:#Una valutazione @@ -16627,7 +16627,6 @@ survey#:#questionblock#:#Blocco di domande survey#:#questionblock_inserted#:#Blocco di domande inserito survey#:#questionblocks#:#Blocchi di domande survey#:#questionblocks_inserted#:#Blocchi di domande inseriti -survey#:#questions#:#Domande survey#:#questions_inserted#:#Domande inserite! survey#:#questions_removed#:#Domande e/o blocco di domande cancellate! survey#:#questiontype#:#Tipo di domanda @@ -16928,6 +16927,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Nascondi etichette survey#:#svy_print_show_labels#:#Mostra etichette survey#:#svy_privacy_info#:#Privacy###31 03 2023 new variable +survey#:#svy_questions#:#Domande survey#:#svy_rater#:#Rater###31 03 2023 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###31 03 2023 new variable survey#:#svy_reminder_mail_template#:#Modello di mail diff --git a/lang/ilias_ja.lang b/lang/ilias_ja.lang index cac05820e23c..f34ee727d1c8 100644 --- a/lang/ilias_ja.lang +++ b/lang/ilias_ja.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#WYSIWYG編集用にTinyMCEを有効にする assessment#:#activate_logging#:#テストとログをアクティブにする assessment#:#activate_manual_scoring#:#手動並び替えを有効にする assessment#:#activate_manual_scoring_desc#:#全ての問題タイプの手動並び替えを有効にする -assessment#:#addSuggestedSolution#:#要約用のコンテンツを追加 assessment#:#add_answers#:#解答を追加 assessment#:#add_circle#:#円形エリアを追加 assessment#:#add_gap#:#穴埋めテキストを追加 @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#ベストな正解ではあり assessment#:#answer_is_right#:#解答は正解 assessment#:#answer_is_wrong#:#解答は誤り assessment#:#answer_of#:#回答者 -assessment#:#answer_options#:#解答オプション: assessment#:#answer_question#:#問題回答 assessment#:#answer_text#:#答案テキスト assessment#:#answer_types#:#答案タイプ @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#提出すると完了 assessment#:#ass_completion_by_submission_info#:#有効にすると提出ファイルの一つはこの問題の最高点で承認して完了した事になります。点数は後で手動にて修正可能です。この設定の変更は既に提出済みの解答には影響しません。 assessment#:#ass_create_export_file_with_results#:#テストエクスポートファイル(受験者結果を含む)を作成 assessment#:#ass_create_export_test_archive#:#テストアーカイブファイルを作成 -assessment#:#ass_create_question#:#問題を作成 assessment#:#ass_imap_hint#:#ツールチップとしてヒントを表示 assessment#:#ass_imap_map_file_not_readable#:#アップロードされたイメージマップを読み込む事ができませんでした。 assessment#:#ass_imap_no_map_found#:#アップロードされたイメージマップ内に書式が見つかりませんでした。 @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#フォームが保存されると回答テ assessment#:#cloze_fixed_textlength#:#テキスト欄の長さ assessment#:#cloze_fixed_textlength_description#:#0以上の値を入力すると全てのテキストと数値穴埋めテキストフィールドがこの値の固定長で作成されます。 assessment#:#cloze_gap_size_info#:#0以上を入力するとこのギャップテキストフィールドはこの値の固定長で作成されます。値を入力しない場合はギャップテキストフィールドはグローバル固定長で作成されます。 -assessment#:#cloze_text#:#穴埋め問題のテキスト -assessment#:#cloze_textgap_case_insensitive#:#大文字・小文字を非区分 -assessment#:#cloze_textgap_case_sensitive#:#大文字・小文字を区分 -assessment#:#cloze_textgap_levenshtein_of#:#%sのレーベンシュタイン距離 assessment#:#code#:#コード assessment#:#codebase#:#コードベース assessment#:#concatenation#:#結び付け @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#事前定義変数($v1を$vnへ)を(例 $r1)の assessment#:#fq_no_restriction_info#:#10進と分母両方共に入力として承認されます。 assessment#:#fq_precision_info#:#希望する10進位置を入力してください。 assessment#:#fq_question_desc#:#問題文章中の必要な位置で$r1, $r2 .... $rnを挿入する事により$v1, $v2 ... $vnの挿入による変数を定義できます。変数と結果のフォーム編集を作成するには"問題解析"ボタンをクリックします。 -assessment#:#gap#:#穴埋め assessment#:#gap_combination#:#ギャップ連結 -assessment#:#gaps#:#Gaps assessment#:#glossary_term#:#用語集 assessment#:#goto_first_question#:#第1問を表示 assessment#:#grading_mark_msg#:#結果: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#問題にはイメージが既に含ま assessment#:#info_text_upload#:#アップロードする回答テキスト(UTF-8)を選択 assessment#:#insert_after#:#後に挿入 assessment#:#insert_before#:#前に挿入 -assessment#:#insert_gap#:#ギャップを挿入 assessment#:#interaction_type#:#インタラクションタイプ assessment#:#internal_links#:#内部リンク assessment#:#intprecision#:#非表示者 @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#受験者が間違ったテス assessment#:#longmenu#:#ロングメニュー assessment#:#longmenu_answeroptions_differ#:#訂正オプションのテキスト内ギャップ数が同じではないので問題は正しく動作しません。 assessment#:#longmenu_text#:#長いメニューテキスト -assessment#:#mainbar_button_label_questionlist#:#問題リスト assessment#:#maintenance#:#メンテナンス assessment#:#manscoring#:#手動採点 assessment#:#manscoring_done#:#採点済み受講者 @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#このテストの最大受験回数 assessment#:#maximum_points#:#最高得点 assessment#:#maxsize#:#最大アップロードファイルサイズ assessment#:#maxsize_info#:#ファイル アップロードを許可するバイト単位の最大サイズを入力します。このフィールドを空白のままにする場合は、このインストールの最大サイズが代わりに選択されます。 -assessment#:#min_auto_complete#:#オートコンプリート assessment#:#min_ip_label#:#アクセス可能な最低IP assessment#:#min_percentage_ne_0#:#最小0のパーセントを定義する必要があります! 評価尺度は保存されませんでした。 assessment#:#misc#:#その他オプション @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#一つずつ assessment#:#mode_question#:#問題指向 assessment#:#mode_user#:#受験者志向 assessment#:#msg_circle_added#:#円の追加 -assessment#:#msg_no_questions_selected#:#問題が選択されませんでした。 assessment#:#msg_number_of_terms_too_low#:#用語数は定義数と等しいかそれ以上である必要があります。 assessment#:#msg_poly_added#:#多角形の追加 assessment#:#msg_questions_moved#:#問題の移動 @@ -984,7 +971,6 @@ assessment#:#order#:#順番 assessment#:#ordering_answer_sequence_info#:#ここで定義する解答順序は正解として使用されます。 assessment#:#ordertext#:#整列するテキスト assessment#:#ordertext_info#:#水平方向にそろえるテキストを入力してください。整列するテキストはテキストの空白記号で区切られます。別の区切りが必要な場合は、%s の区切り記号を使用してテキストの単位を区切る事ができます。 -assessment#:#out_of_range#:#範囲外 assessment#:#output#:#出力 assessment#:#output_mode#:#出力モード assessment#:#parseQuestion#:#問題解析 @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#追加 assessment#:#qpl_bulk_save_overwrite#:#上書き assessment#:#qpl_bulkedit_success#:#変更を保存しました。 assessment#:#qpl_cancel_skill_assigns_update#:#キャンセル -assessment#:#qpl_confirm_delete_questions#:#本当に次の問題を削除しますか? assessment#:#qpl_copy_insert_clipboard#:#選択した問題をクリップボードへコピーします assessment#:#qpl_copy_select_none#:#クリップボードへコピーする問題を最低1個チェックしてください assessment#:#qpl_delete_rbac_error#:#この問題の削除権がありません! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#能力 assessment#:#qpl_qst_skl_usg_sklpnt_col#:#能力当たりの能力-ポイントの総合計 assessment#:#qpl_question_is_in_use#:#テスト%s 内にある修正しようとしている問題です。 この問題を修正しても、テストへ挿入の時点でシステムが問題のコピーを作成するためテストの問題は修正されません! assessment#:#qpl_questions_deleted#:#問題は削除されました。 -assessment#:#qpl_reset_preview#:#プレビューをリセット assessment#:#qpl_save_skill_assigns_update#:#能力割り当てを保存 assessment#:#qpl_settings_availability#:#Availability(空き状況) assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#有効にすると作成可能性のある分類基準がフィルタ用として表示されます。 @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#残り文字数: assessment#:#qst_essay_wordcounter_enabled#:#カウント文字数 assessment#:#qst_essay_wordcounter_enabled_info#:#入力の文字数をカウントします。受験者は以下のテキスト入力欄へ書きこんだ文字数が表示されます。 assessment#:#qst_essay_written_words#:#入力した文字数: -assessment#:#qst_lifecycle#:#ライフサイクル -assessment#:#qst_lifecycle_draft#:#ドラフト -assessment#:#qst_lifecycle_filter_all#:#全てのライフサイクル -assessment#:#qst_lifecycle_final#:#最終 -assessment#:#qst_lifecycle_outdated#:#旧 -assessment#:#qst_lifecycle_rejected#:#拒否されました -assessment#:#qst_lifecycle_review#:#要レビュー -assessment#:#qst_lifecycle_sharable#:#共有化 assessment#:#qst_nested_nested_answers_off#:#インデントなし、順番のみ assessment#:#qst_nested_nested_answers_on#:#回答にインデントを使用 assessment#:#qst_nr_of_tries#:#実行回数 @@ -1168,17 +1144,14 @@ assessment#:#question_type#:#問題のタイプ assessment#:#questionlist_cannot_be_altered#:#テストにはすでに参加者のデータセットが含まれているため、質問リストを変更することはできません。 assessment#:#questionpool_not_entered#:#問題集の名前を入力してください! assessment#:#questionpool_not_selected#:#問題集を選択して下さい! -assessment#:#questions#:#問題 assessment#:#questions_from#:#質問者 assessment#:#questions_per_page_view#:#ページ表示 assessment#:#random_accept_sample#:#サンプルを承諾 assessment#:#random_another_sample#:#他のサンプルを入手 assessment#:#random_selection#:#ランダム選択 assessment#:#range#:#範囲 -assessment#:#range_lower_limit#:#下限 assessment#:#range_max#:#範囲(最大) assessment#:#range_min#:#範囲(最小) -assessment#:#range_upper_limit#:#上限 assessment#:#rated_sign#:#サイン assessment#:#rated_unit#:#ユニット assessment#:#rated_value#:#値 @@ -1254,7 +1227,6 @@ assessment#:#search_roles#:#役割を検索 assessment#:#search_term#:#用語を検索 assessment#:#select_at_least_one_feedback_type_and_trigger#:#ファイードバックとトリガーの一つは選択してください。 assessment#:#select_at_least_one_lock_answer_type#:#ロックされた回答の一つは選択してください。 -assessment#:#select_gap#:#穴埋めを選択 assessment#:#select_max_one_item#:#一アイテムのみ選択してください assessment#:#select_one_user#:#最低ユーザ1名を選択してください。 assessment#:#select_question#:#問題を選択 @@ -1281,7 +1253,6 @@ assessment#:#show_old_introduction#:#過去の序論を表示 assessment#:#show_pass_overview#:#マークした試験状況を表示 assessment#:#show_results#:#結果を表示 assessment#:#show_user_answers#:#マークしたユーザの解答を表示 -assessment#:#shuffle_answers#:#解答をシャッフル assessment#:#skip_question#:#回答しないで次へ assessment#:#solution#:#解答 assessment#:#solutionText#:#テキスト @@ -4687,7 +4658,7 @@ common#:#mm_private_chats#:#プライベートチャット common#:#mm_repo_tree_view#:#ツリー表示 common#:#mm_repo_tree_view_act#:#ツリー表示をアクティブ化 common#:#mm_repo_tree_view_deact#:#ツリー表示を解除 -common#:#mm_repository#:#Repository +common#:#mm_repository#:#リポジトリ common#:#mm_skills#:#能力 common#:#mm_staff_list#:#スタッフリスト common#:#mm_tags#:#タグ @@ -4776,7 +4747,7 @@ common#:#msg_no_perm_paste#:#次のオブジェクトを貼り付けるアクセ common#:#msg_no_perm_paste_object_in_folder#:#フォルダ %sの中のオブジェクト%sを貼り付けるアクセス権限がありません。 common#:#msg_no_perm_perm#:#アクセス権限設定の編集アクセス権限がありません common#:#msg_no_perm_read#:#このアイテムアクセスへのアクセス権限がありません。 -common#:#msg_no_perm_read_item#:#アイテム '%s'へのアクセス権限がありません。 +common#:#msg_no_perm_read_item#:#アイテム へのアクセス権限がありません。 common#:#msg_no_perm_read_lm#:#このラーニングモジュールを読み込むアクセス権限がありません。 common#:#msg_no_perm_view_roles_of_user#:#このユーザの役割割当を見る権限がありません。 common#:#msg_no_perm_write#:#書込みアクセス権限がありません @@ -5067,7 +5038,7 @@ common#:#obj_rcat#:#ECSカテゴリ common#:#obj_rcrs#:#コースリンク common#:#obj_recf#:#リストアされたオブジェクト common#:#obj_recf_desc#:#リストアされたシステムチェックのオブジェクトが含まれます。 -common#:#obj_rep#:#Repository +common#:#obj_rep#:#リポジトリ common#:#obj_reps#:#リポジトリ common#:#obj_reps_desc#:#リポジトリの全般設定 common#:#obj_rfil#:#ECSファイル @@ -14049,6 +14020,35 @@ qpl#:#qpl_page_type_qfbg#:#全般フィードバック qpl#:#qpl_page_type_qfbs#:#特別フィードバック qpl#:#qpl_page_type_qht#:#ヒント qpl#:#qpl_page_type_qpl#:#質問ページ +qsts#:#answer_options#:#解答オプション +qsts#:#cloze_text#:#穴埋め問題のテキスト +qsts#:#cloze_textgapcase_insensitive#:#大文字・小文字を非区分 +qsts#:#cloze_textgapcase_sensitive#:#大文字・小文字を区分 +qsts#:#cloze_textgaplevenshtein_of#:#%sのレーベンシュタイン距離 +qsts#:#confirm_delete_questions#:#本当に次の問題を削除しますか? +qsts#:#create_question#:#問題を作成 +qsts#:#gap#:#穴埋め +qsts#:#gaps#:#Gaps +qsts#:#insert_gap#:#ギャップを挿入 +qsts#:#min_auto_complete#:#オートコンプリート +qsts#:#msg_no_questions_selected#:#問題が選択されませんでした。 +qsts#:#out_of_range#:#範囲外 +qsts#:#qst_lifecycle#:#ライフサイクル +qsts#:#qst_lifecycle_draft#:#ドラフト +qsts#:#qst_lifecycle_filter_all#:#全てのライフサイクル +qsts#:#qst_lifecycle_final#:#最終 +qsts#:#qst_lifecycle_outdated#:#旧 +qsts#:#qst_lifecycle_rejected#:#拒否されました +qsts#:#qst_lifecycle_review#:#要レビュー +qsts#:#qst_lifecycle_sharable#:#共有化 +qsts#:#questionlist#:#問題リスト +qsts#:#questions#:#問題 +qsts#:#range_lower_limit#:#下限 +qsts#:#range_upper_limit#:#上限 +qsts#:#reset_preview#:#プレビューをリセット +qsts#:#select_gap#:#穴埋めを選択 +qsts#:#shuffle_answers#:#解答をシャッフル +qsts#:#suggested_learning_content#:#要約用のコンテンツを追加 rating#:#rat_not_rated_yet#:#星評価なし rating#:#rat_nr_ratings#:#%s星評価 rating#:#rat_one_rating#:#1つ星評価 @@ -16698,7 +16698,6 @@ survey#:#questionblock#:#質問ブロック survey#:#questionblock_inserted#:#質問ブロックの挿入 survey#:#questionblocks#:#質問ブロック survey#:#questionblocks_inserted#:#質問ブロックの挿入 -survey#:#questions#:#質問 survey#:#questions_inserted#:#質問を挿入しました! survey#:#questions_removed#:#質問や質問ブロックを削除しました! survey#:#questiontype#:#質問タイプ @@ -16981,6 +16980,7 @@ survey#:#svy_please_select_unused_codes#:#未使用のコードを一つは選 survey#:#svy_print_hide_labels#:#ラベルを非表示 survey#:#svy_print_show_labels#:#ラベルを表示 survey#:#svy_privacy_info#:#プライバシー +survey#:#svy_questions#:#質問 survey#:#svy_rater#:#評価者 survey#:#svy_rater_see_app_info#:#評価対象者名は問題評価を可能にする評価者へ表示されます。 survey#:#svy_reminder_mail_template#:#メールテンプレート diff --git a/lang/ilias_ka.lang b/lang/ilias_ka.lang index c1ebbd302731..cf5bcfe0e4e1 100644 --- a/lang/ilias_ka.lang +++ b/lang/ilias_ka.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#ტესტისა და შეფასების ჩატვირთვის გააქტიურება assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#დაამატეთ შემოთავაზებული ამოხსნა assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#დაამატეთ წრის სივრცე assessment#:#add_gap#:#დაამტეთ ნაპრალის ტექსტი @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#თქვენ მიიღ assessment#:#answer_is_right#:#თქვენი პასუხი სწორია assessment#:#answer_is_wrong#:#თქვენი პასუხი არასწორია assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#პასუხის ტექსტი assessment#:#answer_types#:#პასუხის სახეობები @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#დასრულებულია assessment#:#ass_completion_by_submission_info#:#თუ გააქტიურებულია, ერთი ფაილის ჩაბარებაც იწვევს დავალების დასრულებას. ნიშნის ხელით შეცვლა შესაძლებელია მოგვიანებით. Aმ პარამეტრების ჩართვა არ იწვევს ცვლიბებს უკვე ჩაბარებულ პასუხებში assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#ტექსტის ველის სიგრძე assessment#:#cloze_fixed_textlength_description#:#თუ თქვენ შეიყვანთ 0-ზე მეტ ღირებულებას მთლიანი ტექსტი და რიცხვითი "ნაპრალები" ამ ღირებულებით განისაზღვრება assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#ტექსტის დახურვა -assessment#:#cloze_textgap_case_insensitive#:#შემთხვევა აუთვისებადია -assessment#:#cloze_textgap_case_sensitive#:#შემთხვევა ათვისებულია -assessment#:#cloze_textgap_levenshtein_of#:# assessment#:#code#:#კოდი assessment#:#codebase#:#კოდების ბაზა assessment#:#concatenation#:#ურთიერთაკვშირი, დამთხვევა @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#ნაპრალი assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#ლექსიკონის პერიოდი assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#კითხვა უკვე შეი assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#ჩავსვათ შემდეგ assessment#:#insert_before#:#წინასწარ ჩავსვათ -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#შიდა ლინკები assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#შენარჩუნება assessment#:#manscoring#:#ხელით შეფასება assessment#:#manscoring_done#:#შეფასებული მონაწილეები @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#თქვენ მიაღწეთ assessment#:#maximum_points#:#ქულების მაქსიმალური რაოდენობა assessment#:#maxsize#:#ატვირთული ფაილის მაქსიმალური ზომა assessment#:#maxsize_info#:#შეიყვანეთ მაქსიმალური ზომა ბაიტებში რის ატვირთვაც იქნება შესაძლებელი. თუ თქვენ ამ ველს ცარიელს დატოვებთ, ინსტალაციისთვის მაქსიმალური ზომა იქნება დაშვებული. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#თქვენ უნდა განსაზღვროთ 0ის მინიმალური %s. Qქულის სქემა არ არის შენახული assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#წრე დაემატა -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#დასახელებების რიცხვი მეტი ან ტოლი უნდა იყოს განსაზღვრებების რიცხვისა assessment#:#msg_poly_added#:#პოლიგონი დაემატა assessment#:#msg_questions_moved#:#კითხვა გადაადგილდა @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#პასუხების თანმიმდევრობა რომელიც თქვენ აქ განსაზღვრეთ გამოიყენება როგორც სწორი პასუხების თანმიმდევრობა assessment#:#ordertext#:#თანმიმდევრობითი ტექსტი assessment#:#ordertext_info#:#გთხოვთ შეიყვანოთ ტექსტი რომელიც ჰორიზონტალურად უნდა დალაგდეს. თანმიმდევრობითი ტექსტი გამოიყოფა თეთრი თავისუფალი სივრცის ნიშნებით. თუ გსურთ სხვა სახის გამოყოფა, თქვენ შეგიძლიათ გამოიყენოთ სხვა გამომყოფი %s. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#შედეგი assessment#:#output_mode#:#შედეგის სახეობა assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#დარწმუნებული ხართ რომ ნამდვილად გსურთ შემდეგი კითხვების წაშლა? assessment#:#qpl_copy_insert_clipboard#:#მონიშნული კითხვების ასლი გადავიდა დაფაზე assessment#:#qpl_copy_select_none#:#გთხოვთ შეამოწმოთ სულ მცირე ერთი კითხვა რომ გადაიტანოთ ის დაფაზე assessment#:#qpl_delete_rbac_error#:#თქვენ არ გაქვთ უფლება წაშალოთ ეს კითხვა! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#კითხვები რომლის რედაქტირებასაც თქვენ ცდილობთ არსებობს %s ტესტში. თუ თქვენ შეცვლით ამ ტესტს, თქვენ ვეღარ შეცვლით კითხვებს ტესტებში, რადგან სისტემა ქმნის კითხვების ასლს როცა მას ტესტში სვავთ assessment#:#qpl_questions_deleted#:#კითხვები წაიშალა -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#მცდელობების რაოდენობა @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#კითხვის დასახელებ assessment#:#question_type#:#კითხვის სახეობა assessment#:#questionpool_not_entered#:#გთხოვთ შეიყვანოთ სახელი კითხვების ნაკადისთვის assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#კითხვების ფორმა assessment#:#questions_per_page_view#:#გვერდის ხედვა assessment#:#random_accept_sample#:#ნიმუშის მიღება assessment#:#random_another_sample#:#სხვა ნიმუშის მიღება assessment#:#random_selection#:#შემთხვევითი მონიშვნა assessment#:#range#:#რიგი -assessment#:#range_lower_limit#:#ქვედა ზღვარი assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#ზედა ზღვარი assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#პასუხისმგებლობეის assessment#:#search_term#:#დასახელების ძიება assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#აირჩიეთ ნაპრალი assessment#:#select_max_one_item#:#გთხოვთ აირჩიოთ მხოლოდ ერთი პუნქტი assessment#:#select_one_user#:#გთხოვთ აირჩიოთ სულ მცირე ერთი მომხმარებელი assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#აჩვენე შეფასებული ჩაბარების მიმოხილვა assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#აჩვენე მომხმარებელთა შეფასებული პასუხები -assessment#:#shuffle_answers#:#პასუხების არევა assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#ტექსტი @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#თქვენ არ გაქვთ შემდ common#:#msg_no_perm_paste_object_in_folder#:#თქვენ არ გაქვთ ობიექტის %s ფოლდერში %s ჩასმის უფლება common#:#msg_no_perm_perm#:#თქვენ არ გაქვთ დაშვების პარამეტრების რედაქტირების უფლება common#:#msg_no_perm_read#:#თქვენ არ გაქვთ ამ ნივთზე უფლება -common#:#msg_no_perm_read_item#:#თქვენ არ გაქვთ ნივთზე უფლება %s +common#:#msg_no_perm_read_item#:#თქვენ არ გაქვთ ნივთზე უფლება common#:#msg_no_perm_read_lm#:#თქვენ არ გაქვთ ამ სასწავლო მოდულში კითხვის უფლება common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#თქვენ არ გაქვთ წერის უფლება @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#ტექსტის დახურვა +qsts#:#cloze_textgapcase_insensitive#:#შემთხვევა აუთვისებადია +qsts#:#cloze_textgapcase_sensitive#:#შემთხვევა ათვისებულია +qsts#:#cloze_textgaplevenshtein_of#:# +qsts#:#confirm_delete_questions#:#დარწმუნებული ხართ რომ ნამდვილად გსურთ შემდეგი კითხვების წაშლა? +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#ნაპრალი +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#ქვედა ზღვარი +qsts#:#range_upper_limit#:#ზედა ზღვარი +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#აირჩიეთ ნაპრალი +qsts#:#shuffle_answers#:#პასუხების არევა +qsts#:#suggested_learning_content#:#დაამატეთ შემოთავაზებული ამოხსნა rating#:#rat_not_rated_yet#:#არ არის შეფასებული ჯერ rating#:#rat_nr_ratings#:#%s რეიტინგები rating#:#rat_one_rating#:#ერთი რეიტინგი @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#კითხვის ბლოკი survey#:#questionblock_inserted#:#კითხვის ბლოკი ჩასმულია survey#:#questionblocks#:#კითხვის ბლოკები survey#:#questionblocks_inserted#:#კითხვების ბლოკები ჩასმულია -survey#:#questions#:#კითხვები survey#:#questions_inserted#:#კითხვები ჩასმულია survey#:#questions_removed#:#კითხვები და/ან კითხვების ბლოკები ამოშლილია! survey#:#questiontype#:#კითხვის სახეობა @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#კითხვები survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_lt.lang b/lang/ilias_lt.lang index 23cdb510600d..48a64650b3f0 100644 --- a/lang/ilias_lt.lang +++ b/lang/ilias_lt.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Aktyvuoti Testavimo ir Vertinimo registravimą assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Pridėti Tarpo (Gap) Tekstą @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Jūs gavote taškų už savo s assessment#:#answer_is_right#:#Jūsų sprendimas yra teisingas assessment#:#answer_is_wrong#:#Jūsų sprendimas yra klaidingas assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Atsakymo tekstas assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Sąlygos tekstas -assessment#:#cloze_textgap_case_insensitive#:#ABC/abc nesvarbu -assessment#:#cloze_textgap_case_sensitive#:#ABC/abc svarbu -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein atstumas iš %s assessment#:#code#:#Kodas assessment#:#codebase#:#Kodo bazė assessment#:#concatenation#:#Tarpusavio ryšis @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Tarpas (Gap) assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Glosarijaus terminas assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Įterpti po assessment#:#insert_before#:#Įterpti prieš -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Vidinės Nuorodos assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Priežiūra assessment#:#manscoring#:#Individualus Vertinimas assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Jūs pasiekėte maksimalų testo band assessment#:#maximum_points#:#Maksimalus galimas balų skaičius assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Jūs privalote nustatyti minimalų procentų skaičių lygų 0 procentų! Vertinimo sistema neišsaugota. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Išvestis assessment#:#output_mode#:#Išvesties būdas assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Ar jūs tikrai norite ištrinti šį(-iuos) klausimą(-us)? Jei ištrinsite užrakintus klausimus, visų testų, kuriuose yra užrakintas klausimas rezultatai bus ištrinti taip pat. assessment#:#qpl_copy_insert_clipboard#:#Pasirinktas(-i) klausimas(-ai) nukopijuoti į atminties krepšelį assessment#:#qpl_copy_select_none#:#Norėdami perkelti į atminties krepšelį pasirinkite bent vieną klausimą assessment#:#qpl_delete_rbac_error#:#Jūs neturite teisių ištrinti šį klausimą! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Klausimas, kurį ruošiatės redaguoti įtrauktas į %s testą(-us). Jei pakeisite šį klausimą, klausimas(-ai) teste(-uose) NEpasikeis, kadangi sistema sukuria įterpiamo į testą klausimo kopiją! assessment#:#qpl_questions_deleted#:#Klausimas(-ai) ištrintas(-i). -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Klausimo pavadinimas assessment#:#question_type#:#Klausimo Tipas assessment#:#questionpool_not_entered#:#Prašome įrašyti apklausos pavadinimą! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#klausimai iš assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Priimti pavyzdį assessment#:#random_another_sample#:#Pasirinkite kitą pavyzdį assessment#:#random_selection#:#Atsitiktinis pasirinkimas assessment#:#range#:#Ribos -assessment#:#range_lower_limit#:#Žemutinė riba assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Viršutinė riba assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Ieškoti Rolių assessment#:#search_term#:#Ieškoti Žodžio assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Pasirinkite tarpą assessment#:#select_max_one_item#:#Pasirinkite tik vieną elementą assessment#:#select_one_user#:#Pasirinkite bent vieną vartotoją assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Išmaišyti atsakymus assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Jūs neturite teisės įterpti šį(-iuos) objektą common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Jūs neturite teisės redaguoti leidimo nustatymus common#:#msg_no_perm_read#:#Jūs neturite teisės pasiekti šį objektą. -common#:#msg_no_perm_read_item#:#Jūs neturite teisės į objekto '%s' prieigą. +common#:#msg_no_perm_read_item#:#Jūs neturite teisės į objekto prieigą. common#:#msg_no_perm_read_lm#:#Jūs neturite teisės skaityti šį mokymo modulį. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Jūs neturite teisės įrašyti @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Sąlygos tekstas +qsts#:#cloze_textgapcase_insensitive#:#ABC/abc nesvarbu +qsts#:#cloze_textgapcase_sensitive#:#ABC/abc svarbu +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein atstumas iš %s +qsts#:#confirm_delete_questions#:#Ar jūs tikrai norite ištrinti šį(-iuos) klausimą(-us)? Jei ištrinsite užrakintus klausimus, visų testų, kuriuose yra užrakintas klausimas rezultatai bus ištrinti taip pat. +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Tarpas (Gap) +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Žemutinė riba +qsts#:#range_upper_limit#:#Viršutinė riba +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Pasirinkite tarpą +qsts#:#shuffle_answers#:#Išmaišyti atsakymus +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Klausimo blokas survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Klausimo blokai survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Klausimai survey#:#questions_inserted#:#Klausimas(-ai) įterpti! survey#:#questions_removed#:#Klausimas(-ai) ir/ar klausimo blokas(-ai) pašalinti! survey#:#questiontype#:#Klausimo tipas @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Klausimai survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_nl.lang b/lang/ilias_nl.lang index 10383e62b332..bc523874dc80 100644 --- a/lang/ilias_nl.lang +++ b/lang/ilias_nl.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Inschakelen TinyMCE voor WYSIWYG Editen assessment#:#activate_logging#:#Inschakelen Toets&Beoordeling logging assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Voeg voorgestelde oplossing toe assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Voeg cirkel gebied toe assessment#:#add_gap#:#Voeg spatie toe @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Je hebt punten gekregen voor d assessment#:#answer_is_right#:#Je oplossing is goed assessment#:#answer_is_wrong#:#Je oplossing is fout assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Tekst assessment#:#answer_types#:#Antwoord type @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions. assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Aanmaken van een Test Archive bestand -assessment#:#ass_create_question#:#Vraag aanmaken assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Tekst veldlengte assessment#:#cloze_fixed_textlength_description#:#Als je een waarde hoger dan 0 ingeeft, dan zullen alle tekst en numerieke velden een lengte krijgen van deze waarde. assessment#:#cloze_gap_size_info#:#Als je een waarde groter dan 0 ingeeft, zal dit gap tekstveld worden aangemaakt met deze lengte. Als je geen waarde ingeeft, zal het gap tekstveld worden aangemaakt met de waarde van het globale vaste lengte. -assessment#:#cloze_text#:#Verhaspelde zin -assessment#:#cloze_textgap_case_insensitive#:#Hoofdletter ongevoelig -assessment#:#cloze_textgap_case_sensitive#:#Hoofdletter gevoelig -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein afstand van %s assessment#:#code#:#Code assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Aaneenschakeling @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Zowel decimalen als breuken worden geaccepteerd als input assessment#:#fq_precision_info#:#Gewenste aantal decimale plaatsen assessment#:#fq_question_desc#:#Je kunt variabelen definieren met $v1, $v2 ... $vn, resultaten door het gebruik van $r1, $r2 .... $rn op de gewenste positie in de vraagtekst. Klik op de knop "Ontleed vraag" om editforms voor variabelen en resultaten te openen. -assessment#:#gap#:#Gat assessment#:#gap_combination#:#Gap Combinatie -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Verklarende term assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Je resultaat is: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#De vraag bevat reeds plaatjes.U kunt het assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Voeg in na assessment#:#insert_before#:#Voeg in voor -assessment#:#insert_gap#:#Insert Gap assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Interne links assessment#:#intprecision#:#Deelbaar door @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Onderhoud assessment#:#manscoring#:#Handmatige score assessment#:#manscoring_done#:#Scorende Deelnemers @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Je hebt het maximum aantal pogingen v assessment#:#maximum_points#:#Maximum behaalbare punten assessment#:#maxsize#:#Maximum file upload size assessment#:#maxsize_info#:#Vul in de maximale hoeveelheid bytes die wordt toegestaan voor bestand-uploads. Als je dit vak blanco laat, wordt de maximale grootte van deze installatie gekozen. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Je moet een minimum percentage opgeven van ministens 0 procent! Het punten schema is niet opgeslaan assessment#:#misc#:#Misc Options @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Cirkel toegevoegd -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Het aantal termen moet groter of gelijk zijn aan het aantal definities. assessment#:#msg_poly_added#:#Polygon toegevoegd assessment#:#msg_questions_moved#:#Vragen verplaatst @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#De volgorde van de antwoorden die je hebt bepaald, wordt beschouwd als de juiste volgorde. assessment#:#ordertext#:#Tekstvolgorde assessment#:#ordertext_info#:#Voer de tekst in die horizontaal komt te staan. De tekst wordt gescheiden door spaties. Als je daarvoor iets anders wenst gebruik dan %s om je tekstonderdelen te scheiden. -assessment#:#out_of_range#:#Out of range###06 02 2015 new variable assessment#:#output#:#Output assessment#:#output_mode#:#Output modus assessment#:#parseQuestion#:#Vraag ontleden @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Weet je zeker dat je de volgende vraag(vragen) wilt verwijderen Als je een geblokkeerde vraag verwijderd, dan worden de resultaten van alle toetsen die deze geblokkeerde vraag bevatten, ook verwijderd. assessment#:#qpl_copy_insert_clipboard#:#De geselecteerde vragen zijn gekopieerd naar het klembord assessment#:#qpl_copy_select_none#:#Selecteer minstens één vraag om te kopiëren naar het klembord assessment#:#qpl_delete_rbac_error#:#Je hebt geen toegang om deze vraag te verwijderen! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#De vraag, die je nu gaat wijzigen, bestaat al in %s toets(en). Als je deze vraag nu wijzigt, wijzig je niet de vraag/vragen in de toets(en), omdat het systeem een kopie van de vraag maakt als de vraag in een toets wordt opgenomen! assessment#:#qpl_questions_deleted#:#Vraag/vragen verwijderd. -assessment#:#qpl_reset_preview#:#Herstel beeld assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Aantal pogingen @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Vraag titel assessment#:#question_type#:#Vraag type assessment#:#questionpool_not_entered#:#Geef een naam voor de vragenpool! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#vragen van assessment#:#questions_per_page_view#:#Paginabeeld assessment#:#random_accept_sample#:#Accepteer voorbeeld assessment#:#random_another_sample#:#Kies een ander voorbeeld assessment#:#random_selection#:#Willekeurige selectie assessment#:#range#:#Limiet -assessment#:#range_lower_limit#:#Verlaag limit assessment#:#range_max#:#Bereik (Maximum) assessment#:#range_min#:#Bereik (Minimum) -assessment#:#range_upper_limit#:#Verhoog limit assessment#:#rated_sign#:#Teken assessment#:#rated_unit#:#Eenheid assessment#:#rated_value#:#Beoordeling @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Zoek rollen assessment#:#search_term#:#Zoek begrippen assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Selecteer gaten assessment#:#select_max_one_item#:#Selecteer minstens 1 item assessment#:#select_one_user#:#Selecteer minstens 1 gebruiker assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Toon gemarkeerde afgelopen toetsen assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Toon gebruikers gemarkeerde antwoorden. -assessment#:#shuffle_answers#:#Antwoorden mixen assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Tekst @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#U hebt geen toestemming voor het plakken van het/de common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s. common#:#msg_no_perm_perm#:#U hebt geen toestemming voor het wijzigen van de instellingen van rechten common#:#msg_no_perm_read#:#U hebt geen toestemming om het item te bekijken -common#:#msg_no_perm_read_item#:#U hebt geen toestemming om het item '%s' te bekijken. +common#:#msg_no_perm_read_item#:#U hebt geen toestemming om het item te bekijken. common#:#msg_no_perm_read_lm#:#U hebt geen rechten om deze lesmodule te lezen. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#U hebt geen toestemming voor schrijven @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Verhaspelde zin +qsts#:#cloze_textgapcase_insensitive#:#Hoofdletter ongevoelig +qsts#:#cloze_textgapcase_sensitive#:#Hoofdletter gevoelig +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein afstand van %s +qsts#:#confirm_delete_questions#:#Weet je zeker dat je de volgende vraag(vragen) wilt verwijderen Als je een geblokkeerde vraag verwijderd, dan worden de resultaten van alle toetsen die deze geblokkeerde vraag bevatten, ook verwijderd. +qsts#:#create_question#:#Vraag aanmaken +qsts#:#gap#:#Gat +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###06 02 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Verlaag limit +qsts#:#range_upper_limit#:#Verhoog limit +qsts#:#reset_preview#:#Herstel beeld +qsts#:#select_gap#:#Selecteer gaten +qsts#:#shuffle_answers#:#Antwoorden mixen +qsts#:#suggested_learning_content#:#Voeg voorgestelde oplossing toe rating#:#rat_not_rated_yet#:#Nog geen beoordelingen rating#:#rat_nr_ratings#:#%s Beoordelingen rating#:#rat_one_rating#:#Eén beoordeling @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Vragenblok survey#:#questionblock_inserted#:#Vraagblok ingevoegd survey#:#questionblocks#:#Vraagblokken survey#:#questionblocks_inserted#:#Vraakblokken ingevoegd -survey#:#questions#:#Vragen survey#:#questions_inserted#:#Vraag(vragen) ingevoegd! survey#:#questions_removed#:#Vraag(vragen) en/of vraag-blok(ken)verwijderd! survey#:#questiontype#:#Vraagtype @@ -16922,6 +16921,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Vragen survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_pl.lang b/lang/ilias_pl.lang index 31cfeefd861d..a95e1c7f8b70 100644 --- a/lang/ilias_pl.lang +++ b/lang/ilias_pl.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Aktywuj TinyMCE do edytowania WYSIWYG assessment#:#activate_logging#:#Aktywuj śledzenie testów i oceniania assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Pokaż sugerowane rozwiązanie assessment#:#add_answers#:#Dodaj odpowiedzi assessment#:#add_circle#:#Dodaj krąg assessment#:#add_gap#:#Dodaj tekst odstępu @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Otrzymałeś punkty za swoją assessment#:#answer_is_right#:#Twoja odpowiedź jest prawidłowa. assessment#:#answer_is_wrong#:#Twoja odpowiedź jest błędna. assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Opcje z odpowiedziami: assessment#:#answer_question#:#Odpowiedz na pytanie assessment#:#answer_text#:#Tekst odpowiedzi assessment#:#answer_types#:#Edytor odpowiedzi @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Zaliczenie przez oddanie assessment#:#ass_completion_by_submission_info#:#Jeśli ta opcja jest aktywna, oddanie pliku z odpowiedziami skutkuje naliczeniem maksymalnej liczny punktów dla danego pytania. Ocenę można w każdej chwili dopasować ręcznie. Zmiana tego ustawienia nie ma żadnego wpływu na już oddane rozwiązania. assessment#:#ass_create_export_file_with_results#:#Utwórz plik eksportowy (łącznie z wynikami uczestników) assessment#:#ass_create_export_test_archive#:#Utwórz plik archiwalny dla testu -assessment#:#ass_create_question#:#Utwórz pytanie assessment#:#ass_imap_hint#:#Wskazówka (wyświetlona jako porada) assessment#:#ass_imap_map_file_not_readable#:#Nie udało się wczytać wysłanej mapy bitowej. assessment#:#ass_imap_no_map_found#:#W wysłanej mapie bitowej nie udało się znaleźć obsługiwanego formatu. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Długość pola tekstowego assessment#:#cloze_fixed_textlength_description#:#Jeśli wpiszesz tutaj wartość, zostaną utworzone luki w tekście, które nie mają określonej maksymalnej długości, oraz luki numeryczne o tej długości, dzięki czemu nie będzie możliwości wprowadzić większej liczby znaków. W przypadku luk numerycznych należy również pamiętać, że przy liczeniu uwzględniany jest separator dziesiętny. assessment#:#cloze_gap_size_info#:#Jeśli wpisana wartość jest większa niż 0, ta przerwa generowane jest o tutaj wpisanej długości. Jeśli nie podano żadnej wartości, ta przerwa zostanie wygenerowana o długości pola tekstowego podanej globalnie. -assessment#:#cloze_text#:#Uzupełnij tekst -assessment#:#cloze_textgap_case_insensitive#:#Nie uwzględniaj wielkości liter -assessment#:#cloze_textgap_case_sensitive#:#Uwzględniaj wielkość liter -assessment#:#cloze_textgap_levenshtein_of#:#Odległość Levenshtein %s assessment#:#code#:#Kod assessment#:#codebase#:#Baza kodu assessment#:#concatenation#:#Złączenie @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Dozwolone jest użycie już zdefiniowanych zmienn assessment#:#fq_no_restriction_info#:#Dozwolone są zarówno liczby dziesiętne jak i ułamki. assessment#:#fq_precision_info#:#Wpisz tutaj wymaganą liczbę miejsc po przecinku. assessment#:#fq_question_desc#:#Zmienne definiujesz przez podanie w wybranych pozycjach w tekście $v1, $v2 ... $vn, pól z wynikami z $r1, $r2 .... $rn. Następnie kliknij na przycisk "Analizuj pytanie", aby wygenerować formularze edycji dla wszystkich zmiennych i wyników. -assessment#:#gap#:#Luka assessment#:#gap_combination#:#Kombinacji tekstu do uzupełnienia -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Hasło słownika assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Otrzymałeś/otrzymałaś ocenę Note "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Pytanie zawiera już obrazy. Dlatego nie assessment#:#info_text_upload#:#Wybierz plik tekstowy (UTF-8) z odpowiedziami do załadowania. assessment#:#insert_after#:#Wstaw po assessment#:#insert_before#:#Wstaw przed -assessment#:#insert_gap#:#Wypełnij lukę assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Linki wewnętrzne assessment#:#intprecision#:#Dzielone przez @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Uczestnik wprowadził nieprawid assessment#:#longmenu#:#Longmenu assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Tekst ‘Long Menu’ -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Konserwacja assessment#:#manscoring#:#Ręczna punktacja assessment#:#manscoring_done#:#Już ocenieni uczestnicy @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Przekroczyłeś maksymalną ilość p assessment#:#maximum_points#:#Maksymalna liczba dostępnych punktów assessment#:#maxsize#:#Maksymalny rozmiar pliku assessment#:#maxsize_info#:#Podaj maksymalny rozmiar pliku w bytach, którego ładowany plik nie może przekroczyć. Jeśli to pole będzie puste, zastosowane zostanie ustawienie podstawowego systemu. -assessment#:#min_auto_complete#:#Automatyczne uzupełnianie assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Musisz określić minimum na 0 procent! Schemat zaznaczeń nie został zapisany. Schemat zaznaczeń nie został zapisany. assessment#:#misc#:#Różne opcje @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Dodano krąg. -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Liczba pojęć musi być większa lub równa liczbie definicji. assessment#:#msg_poly_added#:#Dodano wielobok. assessment#:#msg_questions_moved#:#Przesunięto pytanie(a). @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Ustalona tutaj kolejność odpowiedzi używana jest jako prawidłowa kolejność rozwiązań. assessment#:#ordertext#:#Tekst, który trzeba umieścić assessment#:#ordertext_info#:#Proszę podaj tekst w takiej kolejności, w jakiej ma zostać umieszczony w układzie poziomym. Poszczególne elementy składowe oddzielone są znakiem pustym. Jeśli konieczny jest inny sposób oddzielenia, należy zamiast znaku pustego użyć separatora %s. -assessment#:#out_of_range#:#Poza obszarem assessment#:#output#:#Wyjście assessment#:#output_mode#:#Tryb wyjścia assessment#:#parseQuestion#:#Analizuj pytanie @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Przerwij -assessment#:#qpl_confirm_delete_questions#:#Czy jesteś pewien, że chcesz usunąć następujące pytania? Jeśli usuniesz zaznaczone pytania, to rezultaty wszystkich testów zawierających zaznaczone pytania będą również usunięte. assessment#:#qpl_copy_insert_clipboard#:#Wybrane pytania zostały skopiowane do schowka assessment#:#qpl_copy_select_none#:#Wybierz co najmniej jedno pytanie do skopiowania do schowka assessment#:#qpl_delete_rbac_error#:#Nie masz uprawnień do usunięcia tego pytania! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetencje assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Suma wszystkich punktów kompetencyjnych dla każdej kompetencji assessment#:#qpl_question_is_in_use#:#Pytanie, które modyfikujesz, jest w %s testach. Jeśli zmieniasz to pytanie, to NIE będziesz mógł zmienić pytań w testach, ponieważ system tworzy kopie pytań po wstawieniu ich do testu! assessment#:#qpl_questions_deleted#:#Usunięte pytania. -assessment#:#qpl_reset_preview#:#Przywróć podgląd assessment#:#qpl_save_skill_assigns_update#:#Zapisz przyporządkowane kompetencje assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Istniejące klasyfikacje można użyć do filtrowania pytań. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Ilość prób @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Tytuł pytania assessment#:#question_type#:#Typ pytania assessment#:#questionpool_not_entered#:#Podaj nazwę puli pytań! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#pytania z assessment#:#questions_per_page_view#:#Podgląd strony assessment#:#random_accept_sample#:#Akceptuj próbkę assessment#:#random_another_sample#:#Pobierz inną próbkę assessment#:#random_selection#:#Wybór przypadkowy assessment#:#range#:#Zakres -assessment#:#range_lower_limit#:#Limit dolny assessment#:#range_max#:#Zakres (maksimum) assessment#:#range_min#:#Zakres (minimum) -assessment#:#range_upper_limit#:#Limit górny assessment#:#rated_sign#:#Znak liczby assessment#:#rated_unit#:#Jednostka assessment#:#rated_value#:#Wartość @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Szukaj ról assessment#:#search_term#:#Szukaj frazy assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Wybierz odstęp assessment#:#select_max_one_item#:#Wybierz tylko jedną pozycję. assessment#:#select_one_user#:#Wybierz co najmniej jednego użytkownika. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Pokaż podgląd zaznaczonych wykonań assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Pokaż zaznaczone przez użytkownika odpowiedzi -assessment#:#shuffle_answers#:#Mieszaj odpowiedzi assessment#:#skip_question#:#Nie udzielaj odpowiedzi i przejdź do następnego pytania assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Tekst @@ -1401,7 +1372,7 @@ assessment#:#tst_answered_questions_of_total#:#%s of %s###07 02 2020 new variabl assessment#:#tst_answered_questions_test#:#Pytania, na które udzielono odpowiedzi w tym teście assessment#:#tst_attached_xls_file#:#Wyniki testu tego uczestnika znajdziesz w załączonym pliku Excel. assessment#:#tst_attempt#:#Próba -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#Łączna liczba podejść do tego testu: %s. assessment#:#tst_attempt_started#:#Test rozpoczęty assessment#:#tst_back_to_pass_details#:#Powrót do widoku ogólnego przebiegu assessment#:#tst_back_to_question_list#:#Powrót do listy pytań @@ -1452,7 +1423,7 @@ assessment#:#tst_derive_new_pools#:#Utwórz nowe pule pytań assessment#:#tst_dont_show_msg_again_in_current_session#:#Don't show this message again in my current session. assessment#:#tst_edit_competence_assign#:#Przetwarzaj właściwości przydziału assessment#:#tst_edit_scoring#:#Edytuj punktację -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#Pokaż „Listę pytań” assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#Czas ukończenia assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1477,14 +1448,14 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#Aby rozpocząć test, wprowadź hasło. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#Hasło testowe assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password_label#:#Hasło assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable +assessment#:#tst_exam_start#:#Rozpocznij test +assessment#:#tst_exam_use_previous_answers#:#Użyj poprzednich odpowiedzi assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#Czas, w którym uczestnik przetwarza zadanie, został przedłużony o %s minut. assessment#:#tst_extratime_info#:#Jeśli czas, w którym uczestnik przetwarza zadanie, zostanie kilka razy przedłużony, tutaj należy wpisać sumę wszystkich czasów. @@ -1504,7 +1475,7 @@ assessment#:#tst_final_information#:#Zakończ test assessment#:#tst_finish_confirm_button#:#Tak, chcę skończyć test assessment#:#tst_finish_confirm_cancel_button#:#Nie, powrót do poprzedniej odpowiedzi assessment#:#tst_finish_confirmation_question#:#Kończysz test i wyczerpałeś wszystkie próby. Już nie będziesz mógł powtórzyć tego testu aby zmienić odpowiedzi. Na pewno chcesz skończyć test? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Zakończysz ten test i osiągniesz maksymalną liczbę dozwolonych prób. Nie będziesz mieć możliwości ponownego wejścia do testu, aby zmienić swoje odpowiedzi. Czy na pewno chcesz ukończyć test? assessment#:#tst_finished#:#Ukończone assessment#:#tst_form_dynamic_question_set_config#:#Bieżący wybór pytań assessment#:#tst_gap_analysis#:#Analiza GAP @@ -1591,7 +1562,7 @@ assessment#:#tst_invited_selected_users#:#Wybrani użytkownicy zostali dodani ja assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_launcher_status_message_password#:#Na początku testu zostaniesz poproszony o podanie hasła. assessment#:#tst_level#:#Poziom kompetencji assessment#:#tst_limit_nr_of_tries#:#Ogranicz liczbę przebiegów testu assessment#:#tst_link_only_unassigned#:#Wybrałeś co najmniej jedno pytanie, które zostało już przyporządkowane do puli pytań. Do puli pytań można dodać tylko te pytania, które jeszcze nie zostały przyporządkowane do żadnej puli. Wybierz jedną opcję. @@ -1696,7 +1667,7 @@ assessment#:#tst_objective_progress_header#:#Postęp w celu dydaktycznym assessment#:#tst_objectives_progress_header#:#Postęp w celach dydaktycznych assessment#:#tst_old_style_rnd_quest_set_broken#:#Ten test jest w stanie nieodwracalnym, ponieważ usunięto przyporządkowaną pulę pytań. Dlatego uczestnicy nie mogą już przeprowadzić. assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Pytania dotyczące z powodzeniem przetworzonych celów dydaktycznych są opcjonalne.

    Chcesz przejść do innego pytania, które należy do już zaliczonego celu dydaktycznego.
    Masz następujący wybór:

    Jeśli będziesz kontynuował, możesz przetworzyć pytania dotyczące tych celów dydaktycznych. Ponieważ dla tej próby wybrano nowe pytania, nie pobrano Twoich odpowiedzi z wcześniejszych prób. W przypadku ponownego przetwarzania pytań Twoje wyniki związane z celami dydaktycznymi mogą ulec pogorszeniu.

    Jeśli nie chcesz ponownie przetworzyć pytań, możesz się cofnąć. W takiej sytuacji pytania te nie będą uwzględnione przy ocenie. -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#Przewidziany czas na wykonanie tego testu upłynął. assessment#:#tst_participant#:#Uczestnicy assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s assessment#:#tst_participant_status#:#Status uczestnika @@ -1952,7 +1923,7 @@ assessment#:#tst_text_count_system#:#System punktacji assessment#:#tst_threshold#:#Wartość progowa (w %) assessment#:#tst_time_already_spent#:#Rozpocząłeś test: %s. Czas spędzony na pracy: %s assessment#:#tst_time_already_spent_left#:#Do końca testu pozostało %s -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#Będziesz mieć %s minut na udzielenie odpowiedzi na wszystkie pytania. assessment#:#tst_title_output#:#Pokaż tytuł testu assessment#:#tst_title_output_full#:#Pokaż tytuł testu i dostępne punkty assessment#:#tst_title_output_hide_points#:#Pokaż tylko tytuł testu @@ -4660,7 +4631,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#Ulubione common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4671,10 +4642,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#Widok drzewa +common#:#mm_repo_tree_view_act#:#Aktywuj widok drzewa +common#:#mm_repo_tree_view_deact#:#Deaktywuj widok drzewa +common#:#mm_repository#:#Magazyn common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nie masz uprawnień do wklejania następujących ob common#:#msg_no_perm_paste_object_in_folder#:#Nie masz uprawnień do dodawania obiektu %s do folderu %s. common#:#msg_no_perm_perm#:#Nie możesz modyfikować uprawnień. common#:#msg_no_perm_read#:#Nie masz uprawnień do dostępu do tej pozycji. -common#:#msg_no_perm_read_item#:#Nie masz uprawnień do dostępu do pozycji '%s'. +common#:#msg_no_perm_read_item#:#Nie masz uprawnień do dostępu do pozycji. common#:#msg_no_perm_read_lm#:#Nie masz uprawnień do czytania tego modułu nauczania. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nie masz uprawnień do pisania. @@ -5057,7 +5028,7 @@ common#:#obj_rcat#:#Kategoria ECS common#:#obj_rcrs#:#Kurs ECS common#:#obj_recf#:#Odtworzone obiekty common#:#obj_recf_desc#:#Zawiera odtworzone obiekty powstałe przy sprawdzeniu systemu -common#:#obj_rep#:#Repository###07 02 2020 new variable +common#:#obj_rep#:#Dostępne zasoby common#:#obj_reps#:#Dostępne zasoby common#:#obj_reps_desc#:#Właściwości ogólne dla dostępnych zasobów common#:#obj_rfil#:#Plik ECS @@ -8090,15 +8061,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#Ulubione dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#Moje kursy i grupy dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#Ulubione dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8110,7 +8081,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#Moje kursy i grupy dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Opcje z odpowiedziami +qsts#:#cloze_text#:#Uzupełnij tekst +qsts#:#cloze_textgapcase_insensitive#:#Nie uwzględniaj wielkości liter +qsts#:#cloze_textgapcase_sensitive#:#Uwzględniaj wielkość liter +qsts#:#cloze_textgaplevenshtein_of#:#Odległość Levenshtein %s +qsts#:#confirm_delete_questions#:#Czy jesteś pewien, że chcesz usunąć następujące pytania? Jeśli usuniesz zaznaczone pytania, to rezultaty wszystkich testów zawierających zaznaczone pytania będą również usunięte. +qsts#:#create_question#:#Utwórz pytanie +qsts#:#gap#:#Luka +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Wypełnij lukę +qsts#:#min_auto_complete#:#Automatyczne uzupełnianie +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Poza obszarem +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Lista pytań +qsts#:#questions#:#Pytania +qsts#:#range_lower_limit#:#Limit dolny +qsts#:#range_upper_limit#:#Limit górny +qsts#:#reset_preview#:#Przywróć podgląd +qsts#:#select_gap#:#Wybierz odstęp +qsts#:#shuffle_answers#:#Mieszaj odpowiedzi +qsts#:#suggested_learning_content#:#Pokaż sugerowane rozwiązanie rating#:#rat_not_rated_yet#:#Jeszcze nie oceniono rating#:#rat_nr_ratings#:#%s oceny rating#:#rat_one_rating#:#Ocena @@ -15080,10 +15080,10 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable +rep#:#rep_fav_intro1#:#Nie wybrałeś jeszcze żadnych ulubionych. Aby to zrobić, musisz wykonać dwa kroki: +rep#:#rep_fav_intro2#:#Kliknij '%s' i wybierz obiekt edukacyjny z dostępnych opcji, np. moduł edukacyjny lub forum. +rep#:#rep_fav_intro3#:#Jeśli znajdziesz coś, co Cię interesuje, możesz łatwo dodać to do ulubionych. Aby dodać interesujący Cię element, wybierz opcję „Dodaj do ulubionych” z menu „Akcje”. +rep#:#rep_favourites#:#Ulubione rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Witamy w dostępnych zasobach! @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok pytań survey#:#questionblock_inserted#:#Wstawiono blok pytań survey#:#questionblocks#:#Bloki pytań survey#:#questionblocks_inserted#:#Wstawiono bloki pytań -survey#:#questions#:#Pytania survey#:#questions_inserted#:#Pytania wstawione! survey#:#questions_removed#:#Pytania i/lub bloki pytań usunięte! survey#:#questiontype#:#Typ pytania @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Ukryj etykiety survey#:#svy_print_show_labels#:#Pokaż etykiety survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Pytania survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Szablon wiadomości mailowej diff --git a/lang/ilias_pt.lang b/lang/ilias_pt.lang index 275e0811abf8..d0182418dd55 100644 --- a/lang/ilias_pt.lang +++ b/lang/ilias_pt.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Ativar TinyMCE para a edição WYSIWYG assessment#:#activate_logging#:#Novas notificações de correio assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Adicionar conteúdo para recapitulação assessment#:#add_answers#:#Adicionar respostas assessment#:#add_circle#:#Adicionar área de círculo assessment#:#add_gap#:#Adicionar texto do intervalo @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Tem pontos para a sua soluçã assessment#:#answer_is_right#:#A sua solução é correta assessment#:#answer_is_wrong#:#A sua solução está errada assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Opções de resposta: assessment#:#answer_question#:#Responder a pergunta assessment#:#answer_text#:#Texto de resposta assessment#:#answer_types#:#Editor para respostas @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completado por submissão assessment#:#ass_completion_by_submission_info#:#Se estiver ativado, a submissão de pelo menos um ficheiro leva à conclusão desta pergunta, concedendo a pontuação máxima para esta pergunta. A pontuação pode ser alterada mais tarde manualmente. Mudar esta definição não afeta as soluções já submetidas. assessment#:#ass_create_export_file_with_results#:#Criar ficheiro de exportação de texto (incl. resultados do participante) assessment#:#ass_create_export_test_archive#:#Criar ficheiro de arquivo de teste -assessment#:#ass_create_question#:#Criar pergunta assessment#:#ass_imap_hint#:#Sugestão para ser apresentado como dica de contexto. assessment#:#ass_imap_map_file_not_readable#:#Não foi possível ler o mapa de imagem carregada. assessment#:#ass_imap_no_map_found#:#Não foi possível encontrar qualquer forma na mapa de imagem carregada. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Comprimento do campo de texto assessment#:#cloze_fixed_textlength_description#:#Se introduzir um novo valor, todos os campos de espaços do texto que não impõem uma limitação máxima própria de caracteres, assim como todos os campos de espaços numéricos, serão criados com um comprimento fixo deste valor, não sendo assim possível introduzir mais do que os caracteres permitidos. Repare que para os espaços numéricos, o separador decimal conta como um caracter regular. assessment#:#cloze_gap_size_info#:#Se introduzir um valor superior a 0, este campo de texto de espaços será criado com o comprimento fixo deste valor. Se não introduzir um valor, o campo de texto de espaços será criado com o valor do comprimento global fixo. -assessment#:#cloze_text#:#Fechar texto -assessment#:#cloze_textgap_case_insensitive#:#Caso insensível -assessment#:#cloze_textgap_case_sensitive#:#Caso sensível -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distância de %s assessment#:#code#:#Código assessment#:#codebase#:#Base do código assessment#:#concatenation#:#Concatenação @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Pode introduzir variáveis predefinidas ($v1 até assessment#:#fq_no_restriction_info#:#São aceites entradas decimais e também frações. assessment#:#fq_precision_info#:#Introduza o número de casas decimais pretendido. assessment#:#fq_question_desc#:#Pode definir variáveis ao inserir $v1, $v2 ... $vn, resultados ao inserir $r1, $r2 .... $rn na posição pretendida no texto de perguntas. Clique no botão ‘Analisar pergunta’ para criar formas de edição para variáveis e resultados. -assessment#:#gap#:#Intervalo assessment#:#gap_combination#:#Combinação de intervalo -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Termo do glossário assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#A sua marca é: "[mark]" @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#A pergunta já contém imagens. Não pode assessment#:#info_text_upload#:#Escolha um ficheiro de texto de resposta (UTF-8) para carregar. assessment#:#insert_after#:#Inserir depois assessment#:#insert_before#:#Inserir antes -assessment#:#insert_gap#:#Inserir intervalo assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Links internos assessment#:#intprecision#:#Divisível por @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#O participante introduziu uma p assessment#:#longmenu#:#Menu comprido assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Texto de menu comprido -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Manutenção assessment#:#manscoring#:#Pontuação manual assessment#:#manscoring_done#:#Participantes pontuados @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Chegou ao número máximo de tentativ assessment#:#maximum_points#:#Pontos máximos disponíveis assessment#:#maxsize#:#Tamanho máximo para carregar ficheiro: assessment#:#maxsize_info#:#Introduzir o tamanho máximo em bytes que deve ser permitido para carregar ficheiros. Se deixar este campo vazio, será em vez disso escolhido o tamanho máximo desta instalação. -assessment#:#min_auto_complete#:#Autocompletado assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Tem e definir uma percentagem mínima de 0 por cento! O esquema de anotações não foi guardado. assessment#:#misc#:#Opções combinadas @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Círculo adicionado -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#O número de termos tem de ser superior ou igual ao número de definições. assessment#:#msg_poly_added#:#Polígono adicionado assessment#:#msg_questions_moved#:#Pergunta(s) movida(s) @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#A sequência de respostas que define aqui será assumida como a sequência de solução correta. assessment#:#ordertext#:#Ordenação texto assessment#:#ordertext_info#:#Introduza o texto que deve ser ordenado na horizontal. O texto de ordenação será separado pelos sinais de espaço em branco no texto. Se precisar de uma separação diferente, pode usar o separador %s para separar as suas unidades de texto. -assessment#:#out_of_range#:#Fora de alcance assessment#:#output#:#Saída assessment#:#output_mode#:#Modo saída assessment#:#parseQuestion#:#Analisar pergunta @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancelar -assessment#:#qpl_confirm_delete_questions#:#Tem a certeza que quer remover as seguintes perguntas? assessment#:#qpl_copy_insert_clipboard#:#A(s) pergunta(s) selecionada(s) são copiada(s) para a área de transferência assessment#:#qpl_copy_select_none#:#Selecione pelo menos uma pergunta para copiar para a área de transferência! assessment#:#qpl_delete_rbac_error#:#Não tem permissão para remover esta pergunta! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competência assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total dos pontos de competência por competência assessment#:#qpl_question_is_in_use#:#A pergunta que está prestes a editar existe em %s teste(s). Se mudar esta pergunta, NÃO muda a(s) pergunta(s) no teste(s), porque o sistema cria uma cópia de uma pergunta quando é inserida num teste! assessment#:#qpl_questions_deleted#:#Pergunta(s) removida(s). -assessment#:#qpl_reset_preview#:#Repor pré-visualização assessment#:#qpl_save_skill_assigns_update#:#Guardar atribuições de competência assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#São propostas taxonomias existentes neste banco para filtrar as perguntas. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Número de tentativas @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Título da pergunta assessment#:#question_type#:#Tipo de pergunta assessment#:#questionpool_not_entered#:#Introduza um nome para um banco de perguntas! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#perguntas de assessment#:#questions_per_page_view#:#Vista de página assessment#:#random_accept_sample#:#Aceitar amostra assessment#:#random_another_sample#:#Obter outra amostra assessment#:#random_selection#:#Seleção aleatória assessment#:#range#:#Faixa -assessment#:#range_lower_limit#:#Limite inferior assessment#:#range_max#:#Faixa (máxima) assessment#:#range_min#:#Faixa (mínima) -assessment#:#range_upper_limit#:#Limite superior assessment#:#rated_sign#:#Sinal assessment#:#rated_unit#:#Unidade assessment#:#rated_value#:#Valor @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Pesquisar funções assessment#:#search_term#:#Pesquisar termo assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Selecionar espaço assessment#:#select_max_one_item#:#Selecione apenas um item assessment#:#select_one_user#:#Selecione pelo menos um utilizador. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Mostrar vista geral de tentativas marcadas assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Mostrar respostas marcadas do utilizador -assessment#:#shuffle_answers#:#Misturar respostas assessment#:#skip_question#:#Não responder e próximo assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Texto @@ -1401,7 +1372,7 @@ assessment#:#tst_answered_questions_of_total#:#%s de %s assessment#:#tst_answered_questions_test#:#Perguntas respondidas neste teste assessment#:#tst_attached_xls_file#:#Encontrará o resultado do teste deste participante no ficheiro Excel anexado. assessment#:#tst_attempt#:#Tentativa -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#Número total de vezes que pode realizar este teste: %s. assessment#:#tst_attempt_started#:#Teste iniciado assessment#:#tst_back_to_pass_details#:#Regressar aos detalhes da tentativa assessment#:#tst_back_to_question_list#:#Regressar à lista de perguntas @@ -1452,7 +1423,7 @@ assessment#:#tst_derive_new_pools#:#Derivar novo banco de perguntas assessment#:#tst_dont_show_msg_again_in_current_session#:#Não mostrar esta mensagem novamente durante a minha sessão atual. assessment#:#tst_edit_competence_assign#:#Editar propriedades de atribuição assessment#:#tst_edit_scoring#:#Editar pontuação -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#Exibir 'Lista de perguntas' assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#Tempo para acabar assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1477,14 +1448,14 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#Por favor, insira a senha para iniciar o teste. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#Senha de teste assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password_label#:#Senha assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable +assessment#:#tst_exam_start#:#Iniciar teste +assessment#:#tst_exam_use_previous_answers#:#Usar respostas anteriores assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#O tempo de trabalho do participante aumentou em %s minutos. assessment#:#tst_extratime_info#:#Se quiser adicionar o tempo de trabalho várias vezes para o mesmo participante, insira o tempo total que quer adicionar. @@ -1504,7 +1475,7 @@ assessment#:#tst_final_information#:#Vai acabar este teste e chegar ao número m assessment#:#tst_finish_confirm_button#:#Sim, quero terminar o teste assessment#:#tst_finish_confirm_cancel_button#:#Notificação assessment#:#tst_finish_confirmation_question#:#Não, voltar à resposta anterior -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Você vai concluir este teste e atingir o número máximo de tentativas permitidas. Você não poderá acessar este teste novamente para alterar suas respostas. Você realmente deseja concluir o teste? assessment#:#tst_finished#:#Terminado assessment#:#tst_form_dynamic_question_set_config#:#Continuar seleção de perguntas assessment#:#tst_gap_analysis#:#Análise de intervalo @@ -1696,7 +1667,7 @@ assessment#:#tst_objective_progress_header#:#Progresso dos objetivos de aprendiz assessment#:#tst_objectives_progress_header#:#Progresso dos objetivos de aprendizagem assessment#:#tst_old_style_rnd_quest_set_broken#:#Este teste aleatório está num estado irreparável porque foram eliminados um ou mais bancos de perguntas conectados. Por isso, os participantes já não podem fazer este teste. assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Administrar o teste: comportamento da pergunta -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#O tempo previsto para realizar este teste expirou. assessment#:#tst_participant#:#Participante assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s assessment#:#tst_participant_status#:#Estado do participante @@ -1952,7 +1923,7 @@ assessment#:#tst_text_count_system#:#Se estiver ativada, a sincronização das c assessment#:#tst_threshold#:#Criação automática de contas de utilizador assessment#:#tst_time_already_spent#:#Cria automaticamente contas de utilizador ILIAS, para utilizadores autenticados com sucesso contra Radius, sem ter ainda uma conta ILIAS. assessment#:#tst_time_already_spent_left#:#Saiu %s. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#Você terá %s minutos para responder a todas as perguntas. assessment#:#tst_title_output#:#Migração de conta: assessment#:#tst_title_output_full#:#Ative esta opção para permitir aos utilizadores migrar as suas contas ILIAS existentes para a autenticação Radius. assessment#:#tst_title_output_hide_points#:#Verifique e edite a configuração SimpleSAMLphp em '%s' e '%s' (diretório externo de dados). Não se esqueça de adicionar os caminhos à sua chave privada e certificado no ficheiro authsources.php. Leia o manual para mais explicações %s.
    Federação metadados URL: %s @@ -4660,7 +4631,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#Favoritos common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4671,10 +4642,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#Visualização em árvore +common#:#mm_repo_tree_view_act#:#Ativar visualização em árvore +common#:#mm_repo_tree_view_deact#:#Desativar visualização em árvore +common#:#mm_repository#:#Repositório common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Analisar common#:#msg_no_perm_paste_object_in_folder#:#Não tem permissão para colar o objeto %s para a pasta %s. common#:#msg_no_perm_perm#:#Palavra-passe common#:#msg_no_perm_read#:#Não tem permissão para aceder a este item. -common#:#msg_no_perm_read_item#:#A nova palavra-passe é inválida! Apenas são permitidos os seguintes caracteres (mínimo de 6 caracteres): A-Z a-z 0-9 _.-+? +common#:#msg_no_perm_read_item#:#Não tem permissão para aceder ao objeto. common#:#msg_no_perm_read_lm#:#Não tem permissão para ler este módulo de aprendizagem. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#As suas entradas para a nova palavra-passe não correspondem! Volte a inserir a sua nova palavra-passe. @@ -5057,7 +5028,7 @@ common#:#obj_rcat#:#Linhas common#:#obj_rcrs#:#Fontes adicionais para a criação de ficheiros PDF. Outras fontes diferentes de ‘Helvetica’ e ‘unifont’ devem ser instaladas no servidor ILIAS. common#:#obj_recf#:#Módulo de aprendizagem SCORM common#:#obj_recf_desc#:#Módulo de aprendizagem SCORM adicionado -common#:#obj_rep#:#Repository###07 02 2020 new variable +common#:#obj_rep#:#Repositório common#:#obj_reps#:#Repositório common#:#obj_reps_desc#:#Definições gerais para o repositório common#:#obj_rfil#:#Ficheiro ECS @@ -5792,7 +5763,7 @@ common#:#trash#:#Editar sequência parágrafo common#:#tree#:#Editar propriedades common#:#tree_frame#:#Ir common#:#treeview#:#(Des)ativar elementos -common#:#tst#:#A largura da coluna pode abranger múltiplas unidades 1/12 da linha e depende do tamanho geral do ecrã. Os dispositivos são dados como exemplos. O tamanho do seu ecrã determina o comportamento concreto. 12/12 igual a 100% da largura. +common#:#tst#:#Teste common#:#tst_add#:#Inserir tabela avançada common#:#tst_edit_questions#:#Editar perguntas common#:#tst_history_read#:#View History###26 08 2024 new variable @@ -7708,7 +7679,7 @@ crs#:#crs_members_map#:#Mapa dos membros do curso crs#:#crs_members_print_title#:#Membros do curso crs#:#crs_min_one_admin#:#Tem de haver pelo menos um administrador atribuído a este curso. crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable +crs#:#crs_my_courses_groups_enabled#:#Meus cursos e grupos crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable crs#:#crs_new_status#:#O seu novo estado é: crs#:#crs_new_subscription#:#Campo para opções de referência guardados num campo diferente de uma tabela. @@ -8090,15 +8061,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#Favoritos dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#Meus cursos e grupos dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#Favoritos dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8110,7 +8081,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#Meus cursos e grupos dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Opções de resposta +qsts#:#cloze_text#:#Fechar texto +qsts#:#cloze_textgapcase_insensitive#:#Caso insensível +qsts#:#cloze_textgapcase_sensitive#:#Caso sensível +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distância de %s +qsts#:#confirm_delete_questions#:#Tem a certeza que quer remover as seguintes perguntas? +qsts#:#create_question#:#Criar pergunta +qsts#:#gap#:#Intervalo +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Inserir intervalo +qsts#:#min_auto_complete#:#Autocompletado +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Fora de alcance +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Lista de perguntas +qsts#:#questions#:#Questões +qsts#:#range_lower_limit#:#Limite inferior +qsts#:#range_upper_limit#:#Limite superior +qsts#:#reset_preview#:#Repor pré-visualização +qsts#:#select_gap#:#Selecionar espaço +qsts#:#shuffle_answers#:#Misturar respostas +qsts#:#suggested_learning_content#:#Adicionar conteúdo para recapitulação rating#:#rat_not_rated_yet#:#Não classificado ainda rating#:#rat_nr_ratings#:#%s Classificações rating#:#rat_one_rating#:#Uma classificação @@ -15080,10 +15080,10 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable +rep#:#rep_fav_intro1#:#Você ainda não selecionou nenhum favorito. Para fazer isso, você precisa concluir duas etapas: +rep#:#rep_fav_intro2#:#Clique em '%s' e selecione um objeto de aprendizagem dentre as opções disponíveis, por exemplo, um módulo de aprendizagem ou um fórum. +rep#:#rep_fav_intro3#:#Se encontrar algo que lhe interesse, pode adicioná-lo facilmente aos seus favoritos. Para o item desejado, selecione "Adicionar aos favoritos" no menu Ações. +rep#:#rep_favourites#:#Favoritos rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Bem-vindo ao repositório! @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Bloco de perguntas survey#:#questionblock_inserted#:#Bloco de perguntas inserido survey#:#questionblocks#:#Questionblocks survey#:#questionblocks_inserted#:#Blocos de perguntas inseridos -survey#:#questions#:#Perguntas survey#:#questions_inserted#:#Pergunta(s) inserida(s)! survey#:#questions_removed#:#Pergunta(s) e/ou bloco(s) de perguntas removidos! survey#:#questiontype#:#Tipo de pergunta @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Ocultar etiquetas survey#:#svy_print_show_labels#:#Mostrar etiquetas survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Perguntas survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Modelo mail diff --git a/lang/ilias_ro.lang b/lang/ilias_ro.lang index 02aca9fa8d8b..32b54d94a1d5 100644 --- a/lang/ilias_ro.lang +++ b/lang/ilias_ro.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Activati log-ul de Testare si Evaluare assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Adaugati text cu spatii goale @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Solutia dumneavoastra este corecta###28 Jul 2006 content changed assessment#:#answer_is_wrong#:# Solutia dumneavoastra este gresita assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Raspuns la text assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Text cu spatii se completat -assessment#:#cloze_textgap_case_insensitive#:#Case insensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_case_sensitive#:#Case sensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable assessment#:#code#:#Cod assessment#:#codebase#:#Codebase###10 Jul 2006 new variable assessment#:#concatenation#:#Concatenare @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Spatiu assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Termen de glosar assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Inserati dupa assessment#:#insert_before#:#Inserati inainte -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Legaturi Interne assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Intretinere assessment#:#manscoring#:#Manual Scoring###12 11 2006 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Ati ajuns la numarul maxim de incerca assessment#:#maximum_points#:#Maxium available points###10 Jul 2006 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Trebuie sa definiti un procentaj minim de 0 la suta! Schema de notare nu a fost salvata.###10 Jul 2006 content changed assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 10 2006 new variable assessment#:#output_mode#:#Output mode###10 Jul 2006 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Sunteti sigur/a ca doriti sa stergeti urmatoarele intrebari)? Daca stergeti intrebarile blocate rezultatele tuturor testelor continand intrebari blocate vor fi sterse de asemenea.###10 Jul 2006 content changed assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard###03 Nov 2005 new variable assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard###03 Nov 2005 new variable assessment#:#qpl_delete_rbac_error#:#Nu aveti dreptul sa stergeti aceasta intrebare! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Intrebarea pe care doriti sa o editati axista in %s test(e). Daca schimbati aceasta intrebare, NU veti putea schimba intrebarea din alte teste pentru ca sistemul creaza o copie a intrebarii atunci cand este introdusa in test! assessment#:#qpl_questions_deleted#:#Intrebare stearsa. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Titlul intrebarii assessment#:#question_type#:#Tipul intrebarii assessment#:#questionpool_not_entered#:#Va rugam introduceti un nume pentru baza de intrebari! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#Forma intrebarii assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Acceptati mostra assessment#:#random_another_sample#:#Alta mostra assessment#:#random_selection#:#Selectie la intamplare assessment#:#range#:#Range###22 Feb 2006 new variable -assessment#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Cauta roluri assessment#:#search_term#:#Cauta termeni assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Selectati un spatiu assessment#:#select_max_one_item#:#Selectati un singur obiect assessment#:#select_one_user#:#Please select at least one user###23 Dec 2005 new variable assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Amestecati raspunsurile assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nu aveti permisiunea de a lipi urmatoarele obiecte: common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Nu aveti permisiunea de a edita setarile de permisiune common#:#msg_no_perm_read#:#You have no permission to access this item. ### 2006-8-11 --- Add new translation here. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###10 Jul 2006 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#Nu aveti permisiunea de a citi acest modul de invatare. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nu aveti permisiunea de a scrie @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Text cu spatii se completat +qsts#:#cloze_textgapcase_insensitive#:#Case insensitive###03 Nov 2005 new variable +qsts#:#cloze_textgapcase_sensitive#:#Case sensitive###03 Nov 2005 new variable +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable +qsts#:#confirm_delete_questions#:#Sunteti sigur/a ca doriti sa stergeti urmatoarele intrebari)? Daca stergeti intrebarile blocate rezultatele tuturor testelor continand intrebari blocate vor fi sterse de asemenea.###10 Jul 2006 content changed +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Spatiu +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable +qsts#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Selectati un spatiu +qsts#:#shuffle_answers#:#Amestecati raspunsurile +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Baraj de intrebari survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Baraje de intrebari survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Intrebari survey#:#questions_inserted#:#Intrebari inserate! survey#:#questions_removed#:#Intrebarile sau barajele de intrebari eliminate! survey#:#questiontype#:#Tipul intrebarii @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Intrebari survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_ru.lang b/lang/ilias_ru.lang index 8156d786d99e..b607acc3ddb2 100644 --- a/lang/ilias_ru.lang +++ b/lang/ilias_ru.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#Активировать тестирование assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Добавить предполагаемое решение assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Добавить зону в виде круга assessment#:#add_gap#:#Добавить пропущенный текст @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Вы получили балл assessment#:#answer_is_right#:#Ваше решение верно assessment#:#answer_is_wrong#:#Ваше решение ошибочно assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Текст ответа assessment#:#answer_types#:#Типы ответа @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions. assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Создать файл архива теста -assessment#:#ass_create_question#:#Создать вопрос assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Длинна текстового поля assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Текст с пропусками -assessment#:#cloze_textgap_case_insensitive#:#Нечувствительный к регистру -assessment#:#cloze_textgap_case_sensitive#:#Чувствительный к регистру -assessment#:#cloze_textgap_levenshtein_of#:#Расстояние Левинштейна %s assessment#:#code#:#Код assessment#:#codebase#:#Кодовая база assessment#:#concatenation#:#Конкатенация @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input. assessment#:#fq_precision_info#:#Enter the number of desired decimal places. assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results. -assessment#:#gap#:#Пропуск assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Термин глоссария assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Вставить после assessment#:#insert_before#:#Вставить перед -assessment#:#insert_gap#:#Вставить пропуск assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Внутренние связи assessment#:#intprecision#:#Divisible By @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Обслуживание assessment#:#manscoring#:#Ручная проверка assessment#:#manscoring_done#:#Оцененые участники @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Вы достигли максима assessment#:#maximum_points#:#Максимальное число баллов assessment#:#maxsize#:#Максимальный размер загружаемого файла assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Вы должны определить минимальное значение как 0 процентов. Схема оценки не сохранена. assessment#:#misc#:#Прочие опции @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Круг добавлен -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Число терминов должно быть больше или равно числу определений. assessment#:#msg_poly_added#:#Многогранник добавлен assessment#:#msg_questions_moved#:#Вопрос(ы) перемещены @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence. assessment#:#ordertext#:#Упорядоченный текст assessment#:#ordertext_info#:#Пожалуйста введите текст который был бы упорядочен горизонтально. Упорядоченный текст должен быть разделен пробелами. Если вам нужен другой разделитель, вы можете использовать %s для отделение ваших блоков текста. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Вывод assessment#:#output_mode#:#Режим вывода assessment#:#parseQuestion#:#Разобрать вопрос @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Вы действительно желаете удалить следующие вопрос(ы)? assessment#:#qpl_copy_insert_clipboard#:#Выбранные вопросы скопированы в буфер обмена assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard assessment#:#qpl_delete_rbac_error#:#У вас нет прав удаления этого вопроса! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Вопрос, который вы выбрали на редактирование существует в %s тесте(ах). Если вы измените этот вопрос, то вы не сможете изменить вопрос(ы) в тесте(ах), потому, что система создает копию этого вопроса, когда добавляет его в тест! assessment#:#qpl_questions_deleted#:#Вопрос(ы) удален(ы). -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Число попыток @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Название вопроса assessment#:#question_type#:#Тип вопроса assessment#:#questionpool_not_entered#:#Пожалуйста, задайте имя для набора вопросов! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#форма вопросов assessment#:#questions_per_page_view#:#Page View assessment#:#random_accept_sample#:#Взять пример assessment#:#random_another_sample#:#Взять другой пример assessment#:#random_selection#:#Случайный выбор assessment#:#range#:#Диапазон -assessment#:#range_lower_limit#:#Нижняя граница assessment#:#range_max#:#Range (Maximum) assessment#:#range_min#:#Range (Minimum) -assessment#:#range_upper_limit#:#Верхняя граница assessment#:#rated_sign#:#Sign assessment#:#rated_unit#:#Unit assessment#:#rated_value#:#Value @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Поиск ролей assessment#:#search_term#:#Поиск терминов assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Выберите пропуск assessment#:#select_max_one_item#:#Пожалуйста, выберите только один пункт assessment#:#select_one_user#:#Please select at least one user. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Показать обзор отмеченных верных ответов assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Показать отмеченные пользователем ответы -assessment#:#shuffle_answers#:#Перемешать ответы assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Текст @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#У вас нет прав вставить след common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s. common#:#msg_no_perm_perm#:#У вас нет прав редактирования установки прав common#:#msg_no_perm_read#:#У вас нет права доступа к этому пункту. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'. +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#У вас нет права доступа для чтения этого обучающего модуля. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#У вас нет права записи @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Текст с пропусками +qsts#:#cloze_textgapcase_insensitive#:#Нечувствительный к регистру +qsts#:#cloze_textgapcase_sensitive#:#Чувствительный к регистру +qsts#:#cloze_textgaplevenshtein_of#:#Расстояние Левинштейна %s +qsts#:#confirm_delete_questions#:#Вы действительно желаете удалить следующие вопрос(ы)? +qsts#:#create_question#:#Создать вопрос +qsts#:#gap#:#Пропуск +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Вставить пропуск +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Нижняя граница +qsts#:#range_upper_limit#:#Верхняя граница +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Выберите пропуск +qsts#:#shuffle_answers#:#Перемешать ответы +qsts#:#suggested_learning_content#:#Добавить предполагаемое решение rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Блок вопроса survey#:#questionblock_inserted#:#Question Block inserted survey#:#questionblocks#:#Блоки вопроса survey#:#questionblocks_inserted#:#Question Blocks inserted -survey#:#questions#:#Вопросы survey#:#questions_inserted#:#Вопрос(ы) вставлен(ы)! survey#:#questions_removed#:#Вопрос(ы) и/или удаленный блок(и) вопроса! survey#:#questiontype#:#Тип вопроса @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Вопросы survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_sk.lang b/lang/ilias_sk.lang index 675ccc20e0fe..a587b6331912 100644 --- a/lang/ilias_sk.lang +++ b/lang/ilias_sk.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Aktivovat záznam Test a Hodnocení assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Přidat doporučené řešení assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Přidat kruhovou plochu assessment#:#add_gap#:#Přidat textovou mezeru @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Obdržel(a) jste body za Vaše assessment#:#answer_is_right#:#Vaše řešení je správné assessment#:#answer_is_wrong#:#Vaše řešení je chybné assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Text odpovědi assessment#:#answer_types#:#Typy odpovědi @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Délka textového pole assessment#:#cloze_fixed_textlength_description#:#Pokud vložíte hodnotu větší než 0, všechna textová pole textových i numerických mezer budou vytvářeny s pevnou délkou rovnou této hodnotě. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Doplňovaný text -assessment#:#cloze_textgap_case_insensitive#:#Nerozlišuje velká/malá písmena -assessment#:#cloze_textgap_case_sensitive#:#Rozlišuje velká/malá písmena -assessment#:#cloze_textgap_levenshtein_of#:#Vzdálenost Levenshtein %s assessment#:#code#:#Kód assessment#:#codebase#:#Databáze kódu assessment#:#concatenation#:#Sřetězení @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Mezera assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Pojem glosáře assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Tato otázka již obsahuje obrázky. Nem assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Vložit za assessment#:#insert_before#:#Vložit před -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Interní odkazy assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Údržba assessment#:#manscoring#:#Manuální hodnocení assessment#:#manscoring_done#:#Vyhodnocení účastníci @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Dosáhl(a) jste maximální počet po assessment#:#maximum_points#:#Maxium dostupných bodů assessment#:#maxsize#:#Maximální velkost ukládaného souboru assessment#:#maxsize_info#:#Vložit maximální velikost v bytech, která je povolena pro ukládané soubory. Pokud necháte toto pole prázdné, bude namísto něj nastavena maximální velikost této instalace. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Musíte definovat minimální procento od specifikace 0 procent! Schéma známkování nebylo uloženo. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Kruh přidán -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Počet výrazů musí být větší, nebo roven počtu definicí. assessment#:#msg_poly_added#:#Polygon přidán assessment#:#msg_questions_moved#:#Otázky přesunuty @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###28 10 2010 new variable assessment#:#ordertext#:#Řazení textu assessment#:#ordertext_info#:#Vložte prosím text, který má být řazen horizontálně. Řazený text bude oddělen pomocí značek mezer v textu. Pokud potřebujete jiné oddělení, můžete použít separátor %s k oddělení Vašich textových jednotek. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Výstup assessment#:#output_mode#:#Výstupní mód assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Jste si jist(a), že chcete smazat následující otázky? assessment#:#qpl_copy_insert_clipboard#:#Vybrané otázky jsou zkopírovány do schránky assessment#:#qpl_copy_select_none#:#Označte alespoň jednu otázku ke zkopírování do schránky assessment#:#qpl_delete_rbac_error#:#Nemáte oprávnění smazat tuto otázku! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Otázka, kterou upravujete, existuje v %s testech. Pokud tuto otázku změníte, NEZMĚNÍTE otázku(y) v testu(ech), protože systém vytváří kopii otázky, která je vložena do testu! assessment#:#qpl_questions_deleted#:#Otázky smazány. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Počet pokusů @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Název otázky assessment#:#question_type#:#Typ otázky assessment#:#questionpool_not_entered#:#Vložte prosím název zásobníku otázek! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#otázky z assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Akceptovat příklad assessment#:#random_another_sample#:#Vybrat jiný příklad assessment#:#random_selection#:#Náhodný výběr assessment#:#range#:#Rozmezí -assessment#:#range_lower_limit#:#Spodní hranice assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Horní hranice assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Vyhledat role assessment#:#search_term#:#Vyhledat termín assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Vybírací mezera assessment#:#select_max_one_item#:#Vyberte prosím pouze jednu položku assessment#:#select_one_user#:#Vyberte prosím alespoň jednoho uživatele assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Zobrazit přehled označených průchodů assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Zobrazit označené odpovědi uživatelů -assessment#:#shuffle_answers#:#Zamíchat odpovědi assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nemáte oprávnění vložit následující objekty common#:#msg_no_perm_paste_object_in_folder#:#Nemáte oprávnění vkládat objekt %s do složky %s. common#:#msg_no_perm_perm#:#Nemáte oprávnění měnit nastavení přístupových práv common#:#msg_no_perm_read#:#Nemáte oprávnění přístupu k této položce. -common#:#msg_no_perm_read_item#:#Nemáte oprávnění přístupu k položce '%s'. +common#:#msg_no_perm_read_item#:#Nemáte oprávnění přístupu k položce. common#:#msg_no_perm_read_lm#:#Nemáte oprávnění číst tento výukový modul. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nemáte oprávnění k zápisu @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Doplňovaný text +qsts#:#cloze_textgapcase_insensitive#:#Nerozlišuje velká/malá písmena +qsts#:#cloze_textgapcase_sensitive#:#Rozlišuje velká/malá písmena +qsts#:#cloze_textgaplevenshtein_of#:#Vzdálenost Levenshtein %s +qsts#:#confirm_delete_questions#:#Jste si jist(a), že chcete smazat následující otázky? +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Mezera +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Spodní hranice +qsts#:#range_upper_limit#:#Horní hranice +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Vybírací mezera +qsts#:#shuffle_answers#:#Zamíchat odpovědi +qsts#:#suggested_learning_content#:#Přidat doporučené řešení rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok otázek survey#:#questionblock_inserted#:#Blok otázek vložen survey#:#questionblocks#:#Bloky otázek survey#:#questionblocks_inserted#:#Bloky otázek vloženy -survey#:#questions#:#Otázky survey#:#questions_inserted#:#Otázky vloženy survey#:#questions_removed#:#Otázky a/nebo bloky otázek odstraněny! survey#:#questiontype#:#Typ otázky @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Otázky survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_sl.lang b/lang/ilias_sl.lang index f28ff5c9c8e3..11708ada4f72 100644 --- a/lang/ilias_sl.lang +++ b/lang/ilias_sl.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing assessment#:#activate_logging#:#Aktiviraj protokol testov in ocen assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Vsebine za ponavljanje assessment#:#add_answers#:#Dodaj odgovore assessment#:#add_circle#:#Dodaj krog assessment#:#add_gap#:#Dodaj besedilo s prazninami @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Dobili ste točke za svojo re assessment#:#answer_is_right#:#Vaša rešitev je pravilna. assessment#:#answer_is_wrong#:#Vaša rešitev je napačna. assessment#:#answer_of#:#Answer of -assessment#:#answer_options#:#Možnosti odgovora: assessment#:#answer_question#:#Odgovori na vprašanje assessment#:#answer_text#:#Besedilo odgovora assessment#:#answer_types#:#Urednik odgovorov @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Obstoj z oddajo assessment#:#ass_completion_by_submission_info#:#Če je to aktivirano, oddaja datoteke z rešitvijo povzroči največjo oceno za to vprašanje. Oceno lahko kadar koli ročno prilagodite. Sprememba te nastavitve naknadno ne vpliva na že oddane rešitve. assessment#:#ass_create_export_file_with_results#:#Ustvari datoteko za izvoz (vključno z rezultati udeležencev) assessment#:#ass_create_export_test_archive#:#Ustvari arhivsko datoteko za test -assessment#:#ass_create_question#:#Ustvari vprašanje assessment#:#ass_imap_hint#:#Opomba (prikaže se kot opis orodja) assessment#:#ass_imap_map_file_not_readable#:#Naloženega slikovnega zemljevida ni mogoče prebrati. assessment#:#ass_imap_no_map_found#:#V naloženem Imapemap ni bila najdena nobena podprta oblika. @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Dolžina besedilnega polja assessment#:#cloze_fixed_textlength_description#:#Če tukaj vnesete vrednost, se v besedilu ustvarijo praznine, ki ne določajo lastne vrednosti za maksimalno dolžino, kot tudi praznine za številčni odgovor s to dolžino, zato ni mogoče vnesti več znakov, kot je dovoljeno. Pri prazninah za številčni odgovor je poleg tega treba upoštevati, da se pri štetju upoštevajo tudi decimalna ločila. assessment#:#cloze_gap_size_info#:#Če je vnesena vrednost večja od 0, se ta praznina ustvari z dolžino, ki je tukaj navedena. Če ni vnesena nobena vrednost, se ta praznina ustvari z globalno določeno dolžino besedilnega polja. -assessment#:#cloze_text#:#Vprašanje s praznino v besedilu -assessment#:#cloze_textgap_case_insensitive#:#Ni razlikovanja med velikimi in malimi črkami -assessment#:#cloze_textgap_case_sensitive#:#Upoštevaj razlikovanje velikih in malih črk -assessment#:#cloze_textgap_levenshtein_of#:#Levenshteinov razmik v %s assessment#:#code#:#Koda assessment#:#codebase#:#Osnova kode assessment#:#concatenation#:#Povezava @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#Dovoljena je uporaba že definiranih spremenljivk assessment#:#fq_no_restriction_info#:#Kot vnos se sprejmejo tako decimalne številke kot ulomki. assessment#:#fq_precision_info#:#Tukaj vnesite želeno število decimalnih mest. assessment#:#fq_question_desc#:#Spremenljivke lahko definirate tako, da vstavite $ v1, $ v2 ... $vn, rezultate pa tako, da vstavite $ r1, $ r2 .... $ rn na želeno mesto v besedilu. Nato kliknite na gumb "Analiziraj vprašanje", da ustvarite obrazce za obdelavo spremenljivk in rezultatov. -assessment#:#gap#:#Praznina assessment#:#gap_combination#:#Kombinacija besedila s prazninami -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Pojem iz glosarja assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Vaša ocena je "[mark]""; @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Vprašanje že vsebuje slike. Tipa odgovo assessment#:#info_text_upload#:#Izberite besedilno datoteko (UTF-8) z odgovori, ki jih želite naložiti. assessment#:#insert_after#:#Vstavi za assessment#:#insert_before#:#Vstavi pred -assessment#:#insert_gap#:#Vstavi praznino assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Notranje opombe assessment#:#intprecision#:#Deljivo z @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Udeleženec je vnesel napačno assessment#:#longmenu#:#Longmenu assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Besedilo ‘Long Menu’ -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Vzdrževanje assessment#:#manscoring#:#Ročno ocenjevanje assessment#:#manscoring_done#:#Udeleženci, ki so že bili ocenjeni @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Dosegli ste maksimalno dovoljeno šte assessment#:#maximum_points#:#Maksimalno možno število točk assessment#:#maxsize#:#Maksimalna velikost datoteke assessment#:#maxsize_info#:#Navedite maksimalno velikost v bitih, ki jo lahko ima datoteka, ki se nalaga. Če pustite to polje prazno, bo uporabljena nastavitev osnovnega sistema. -assessment#:#min_auto_complete#:#Samodejno dopolnjevanje assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Določiti morate minimalni odstotek v vrednosti 0, da se lahko upoštevajo vse dosežene točke. Shema ocenjevanja ni shranjena! assessment#:#misc#:#Različne možnosti @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Dodan je krog -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Število izrazov mora biti večje ali enako številu definicij. assessment#:#msg_poly_added#:#Dodan je poligon assessment#:#msg_questions_moved#:#Vprašanje/-a je/so premaknjeno/-a. @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Na tem mestu definirano zaporedje odgovorov se uporabi kot pravilen vrstni red rešitev. assessment#:#ordertext#:#Besedilo za razporeditev assessment#:#ordertext_info#:#Vnesite besedilo v takšnem zaporedju, kot naj bo razvrščeno horizontalno. Posamezne sestavine so ločene s presledki. Če potrebujete drugačno ločitev, namesto presledkov uporabite ločilo %s. -assessment#:#out_of_range#:#Izven področja assessment#:#output#:#Izdaja assessment#:#output_mode#:#Način izdaje assessment#:#parseQuestion#:#Analiziraj vprašanje @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Prekini -assessment#:#qpl_confirm_delete_questions#:#Ali ste prepričani, da želite odstraniti naslednja vprašanja? assessment#:#qpl_copy_insert_clipboard#:#Izbrano/-a vprašanje/-a se kopira/-jo v odložišče assessment#:#qpl_copy_select_none#:#Izberite vsaj eno vprašanje za kopiranje v odložišče assessment#:#qpl_delete_rbac_error#:#Nimate pravice za odstranitev tega vprašanja! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetenca assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Skupno število kompetenčnih točk na kompetenco assessment#:#qpl_question_is_in_use#:#Vprašanje, ki ga zdaj želite obdelati, že obstaja v %st testu/-ih. Če zdaj spremenite to vprašanje, to NE bo vplivalo na vprašanja, ki so že vključena v testih, ker sistem samodejno naredi kopijo vprašanja, ko je vključeno v test! assessment#:#qpl_questions_deleted#:#Vprašanje/-a izbrisano/-a -assessment#:#qpl_reset_preview#:#Ponastavite predogled assessment#:#qpl_save_skill_assigns_update#:#Shranite dodelitev kompetenc assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Obstoječe taksonomije se lahko uporabijo za filtriranje vprašanj. @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters assessment#:#qst_essay_wordcounter_enabled#:#Count Words assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field. assessment#:#qst_essay_written_words#:#Number of entered words -assessment#:#qst_lifecycle#:#Lifecycle -assessment#:#qst_lifecycle_draft#:#Draft -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles -assessment#:#qst_lifecycle_final#:#Final -assessment#:#qst_lifecycle_outdated#:#Outdated -assessment#:#qst_lifecycle_rejected#:#Rejected -assessment#:#qst_lifecycle_review#:#To be Reviewed -assessment#:#qst_lifecycle_sharable#:#Sharable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###19 08 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###19 08 2022 new variable assessment#:#qst_nr_of_tries#:#Število poskusov @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Naslov vprašanja assessment#:#question_type#:#Tip vprašanja assessment#:#questionpool_not_entered#:#Vnesite ime za skupino vprašanj! assessment#:#questionpool_not_selected#:#Please select a question pool! -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#Vprašanja iz assessment#:#questions_per_page_view#:#Prikaz strani assessment#:#random_accept_sample#:#Sprejmite seznam assessment#:#random_another_sample#:#Nov seznam assessment#:#random_selection#:#Naključna izbira assessment#:#range#:#Področje -assessment#:#range_lower_limit#:#Spodnja meja assessment#:#range_max#:#Področje (maksimalno) assessment#:#range_min#:#Področje (minimalno) -assessment#:#range_upper_limit#:#Zgornja meja assessment#:#rated_sign#:#Predznak assessment#:#rated_unit#:#Enota assessment#:#rated_value#:#Vrednost @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#po vlogah assessment#:#search_term#:#Iskani pojem assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Izbrana praznina assessment#:#select_max_one_item#:#Izberite samo en objekt assessment#:#select_one_user#:#Izberite vsaj enega uporabnika. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Pregled rezultatov (ocenjeno opravljanje testa) assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Odgovori (ocenjeno opravljanje testa) -assessment#:#shuffle_answers#:#Pomešaj odgovore assessment#:#skip_question#:#Ne odgovarjaj in naprej assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Besedilo @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nimate ustreznih pravic za vstavljanje naslednjih o common#:#msg_no_perm_paste_object_in_folder#:#Nimate ustreznih pravic za vstavljanje objekta %s v mapo %s. common#:#msg_no_perm_perm#:#Nimate ustreznih pravic za dostop do nastavitev pravic! common#:#msg_no_perm_read#:#Nimate ustreznih pravic za dostop do tega objekta. -common#:#msg_no_perm_read_item#:#Nimate pravic za dostop do objekta '%s'. +common#:#msg_no_perm_read_item#:#Nimate pravic za dostop do objekta. common#:#msg_no_perm_read_lm#:#Nimate ustreznih pravic za prikaz tega učnega modula. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nimate pravic za pisanje! @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback qpl#:#qpl_page_type_qfbs#:#Special Feedback qpl#:#qpl_page_type_qht#:#Hint qpl#:#qpl_page_type_qpl#:#Question Page +qsts#:#answer_options#:#Možnosti odgovora +qsts#:#cloze_text#:#Vprašanje s praznino v besedilu +qsts#:#cloze_textgapcase_insensitive#:#Ni razlikovanja med velikimi in malimi črkami +qsts#:#cloze_textgapcase_sensitive#:#Upoštevaj razlikovanje velikih in malih črk +qsts#:#cloze_textgaplevenshtein_of#:#Levenshteinov razmik v %s +qsts#:#confirm_delete_questions#:#Ali ste prepričani, da želite odstraniti naslednja vprašanja? +qsts#:#create_question#:#Ustvari vprašanje +qsts#:#gap#:#Praznina +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Vstavi praznino +qsts#:#min_auto_complete#:#Samodejno dopolnjevanje +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Izven področja +qsts#:#qst_lifecycle#:#Lifecycle +qsts#:#qst_lifecycle_draft#:#Draft +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles +qsts#:#qst_lifecycle_final#:#Final +qsts#:#qst_lifecycle_outdated#:#Outdated +qsts#:#qst_lifecycle_rejected#:#Rejected +qsts#:#qst_lifecycle_review#:#To be Reviewed +qsts#:#qst_lifecycle_sharable#:#Sharable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Spodnja meja +qsts#:#range_upper_limit#:#Zgornja meja +qsts#:#reset_preview#:#Ponastavite predogled +qsts#:#select_gap#:#Izbrana praznina +qsts#:#shuffle_answers#:#Pomešaj odgovore +qsts#:#suggested_learning_content#:#Vsebine za ponavljanje rating#:#rat_not_rated_yet#:#Not Rated Yet rating#:#rat_nr_ratings#:#%s Ratings rating#:#rat_one_rating#:#One Rating @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok vprašanj survey#:#questionblock_inserted#:#Blok vprašanj je vstavljen survey#:#questionblocks#:#Bloki vprašanj survey#:#questionblocks_inserted#:#Bloki vprašanj so vstavljeni -survey#:#questions#:#Vprašanja survey#:#questions_inserted#:#Vstavljeno/-a vprašanje/-a! survey#:#questions_removed#:#Vprašanje/-a in/ali bloki vprašanj je bilo/so bili odstranjeno/-i! survey#:#questiontype#:#Tip vprašanja @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Skrij oznake survey#:#svy_print_show_labels#:#Prikaži oznake survey#:#svy_privacy_info#:#Privacy###19 08 2022 new variable +survey#:#svy_questions#:#Vprašanja survey#:#svy_rater#:#Rater###19 08 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###19 08 2022 new variable survey#:#svy_reminder_mail_template#:#Predloga za e-pošto diff --git a/lang/ilias_sq.lang b/lang/ilias_sq.lang index 4ac3b6b07264..4f4bb4588bda 100644 --- a/lang/ilias_sq.lang +++ b/lang/ilias_sq.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Aktivizo testin&Ruaj aktivitetin e vlerësimit assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Shto zbrazëtirë për tekst @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Zgjidhja juaj është e drejtë###28 Jul 2006 content changed assessment#:#answer_is_wrong#:#Zgjidhja juaj është e padrejtë assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Përgjigju tekstit assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Mbyll tekstin###20 Jun 2005 content changed -assessment#:#cloze_textgap_case_insensitive#:#Case insensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_case_sensitive#:#Case sensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable assessment#:#code#:#Kod assessment#:#codebase#:#Codebase###10 Jul 2006 new variable assessment#:#concatenation#:#Concatenation ### 2006-8-11 --- Add new translation here. @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Zbrazëtirë assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Term nga fjalorthi assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Vendos pas assessment#:#insert_before#:#Vendos para -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Vendos linqe assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Mirëmbajtje assessment#:#manscoring#:#Manual Scoring###12 11 2006 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Keni arritur numrin maksimal të tent assessment#:#maximum_points#:#Maxium available points###10 Jul 2006 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Duhet të definoni minimumin e përqindjes të 0 përqind! Skema e markuar nuk është ruajtur.###10 Jul 2006 content changed assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 10 2006 new variable assessment#:#output_mode#:#Output mode###10 Jul 2006 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#A jeni të sigurt për të fshirë pyetjen/pyetjet ? Nëse i fshini pyetjet e mbyllura po ashtu do të fshihen edhe rezultatet e testeve që i përmbajn ato pyetje.###10 Jul 2006 content changed assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard###03 Nov 2005 new variable assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard###03 Nov 2005 new variable assessment#:#qpl_delete_rbac_error#:#Nuk keni të drejta për të fshirë këtë pyetje! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Pyetjen që jeni duke e edituar ekziston në %s test(e). Nëse e ndërroni këtë pyetje, nuk do të ndërroni pyetjen/pyetjet në testin/testet, për shkak se sistemi krijon një kopje të pyetjes kur ajo futet në test! assessment#:#qpl_questions_deleted#:#Pyetja/pyetjet janë fshirë -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Titulli i pyetjes assessment#:#question_type#:#Lloji i pyetjes assessment#:#questionpool_not_entered#:#Ju lutem të emërtoni fondin e pyetjeve! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#formë e pyetjeve assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Prano shembullin assessment#:#random_another_sample#:#Merr një shembull tjetër assessment#:#random_selection#:#Përzgjedhje sipas rastit assessment#:#range#:#Range###22 Feb 2006 new variable -assessment#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Search Roles ### 2006-8-11 --- Add new translation h assessment#:#search_term#:#Search Term ### 2006-8-11 --- Add new translation here. assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Zgjedh zbrazëtirë assessment#:#select_max_one_item#:#Ju lutem të zgjedhni vetëm një artikull assessment#:#select_one_user#:#Please select at least one user###23 Dec 2005 new variable assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Përziej përgjigjet assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nuk keni të drejta të vendosur objektet vijuese: common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Nuk keni të drejta t'i editoni konfigurimet për të drejtat common#:#msg_no_perm_read#:#Nuk keni të drejta për qasje në këtë artikull. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###10 Jul 2006 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#Nuk keni të drejta të lexoni këtë modul mësimor. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nuk keni të drejta për të shkruar @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Mbyll tekstin###20 Jun 2005 content changed +qsts#:#cloze_textgapcase_insensitive#:#Case insensitive###03 Nov 2005 new variable +qsts#:#cloze_textgapcase_sensitive#:#Case sensitive###03 Nov 2005 new variable +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable +qsts#:#confirm_delete_questions#:#A jeni të sigurt për të fshirë pyetjen/pyetjet ? Nëse i fshini pyetjet e mbyllura po ashtu do të fshihen edhe rezultatet e testeve që i përmbajn ato pyetje.###10 Jul 2006 content changed +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Zbrazëtirë +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable +qsts#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Zgjedh zbrazëtirë +qsts#:#shuffle_answers#:#Përziej përgjigjet +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Grupi i pyetjeve survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Grupet e pyetjeve survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Pyetjet survey#:#questions_inserted#:#Pyetjet janë vendosur! survey#:#questions_removed#:#Pyetjet dhe/ose grupet e pyetjeve janë fshirë! survey#:#questiontype#:#Tipi i pyetjes @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Pyetjet survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_sr.lang b/lang/ilias_sr.lang index 07aba9eaa1af..a055e5163488 100644 --- a/lang/ilias_sr.lang +++ b/lang/ilias_sr.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Aktiviraj test i proveru prijave assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#dodajte razmak u tekstu @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Vaše rešenje je ispravno###28 Jul 2006 content changed assessment#:#answer_is_wrong#:#Vaše rešenje je pogrešno assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Tekst odgovora assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Zatvori tekst###20 Jun 2005 content changed -assessment#:#cloze_textgap_case_insensitive#:#Case insensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_case_sensitive#:#Case sensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable assessment#:#code#:#Kod assessment#:#codebase#:#Codebase###10 Jul 2006 new variable assessment#:#concatenation#:#Concatenation ### 2006-8-11 --- Add new translation here. @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Razmak assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Recnik termina assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Ubacite posle assessment#:#insert_before#:#Ubacite pre -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Unutrašnje veze assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Održavanje assessment#:#manscoring#:#Manual Scoring###12 11 2006 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Dostigli ste maksimalan broj pokušaj assessment#:#maximum_points#:#Maxium available points###10 Jul 2006 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Morate definisati minimalan procenat od 0 procenata! Šema ocena nije sacuvana.###10 Jul 2006 content changed assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 10 2006 new variable assessment#:#output_mode#:#Output mode###10 Jul 2006 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Da li ste sigurni da želite da obrišete sledece(a) pitanje(a)? Ukoliko obrišete zakljucana pitanja, rezultati svih testova koji sadrže zakljucana pitanja bice takode obrisani.###10 Jul 2006 content changed assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard###03 Nov 2005 new variable assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard###03 Nov 2005 new variable assessment#:#qpl_delete_rbac_error#:#Nemate prava da obrišete ovo pitanje! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Pitanje koje nameravate da izmenite nalazi se u %s testova. Ukoliko promenite ovo pitanje, NECETE promeniti pitanje(a) u testu/testovima, zato što sistem pravi kopije pitanja kada su una ubacena u test! assessment#:#qpl_questions_deleted#:#Pitanje(a) obrisano(a). -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Naziv pitanja assessment#:#question_type#:#Vrsta pitanja assessment#:#questionpool_not_entered#:#Molimo unesite naziv bazu pitanja! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#pitanje iz assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Prihvati primer assessment#:#random_another_sample#:#Uzmi drugi primer assessment#:#random_selection#:#Slucajni izbor assessment#:#range#:#Range###22 Feb 2006 new variable -assessment#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Search Roles ### 2006-8-11 --- Add new translation h assessment#:#search_term#:#Search Term ### 2006-8-11 --- Add new translation here. assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Odaberite razmak assessment#:#select_max_one_item#:#Molimo odaberite samo jedno polje assessment#:#select_one_user#:#Please select at least one user###23 Dec 2005 new variable assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Izbegni odgovore assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Nemate dozvolu da zalepite sledece objekte common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Nemate dozvolu da uredujete podešavanja za dozvolu common#:#msg_no_perm_read#:#Nemate dozvolu da pristupite ovoj poziciji. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###10 Jul 2006 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#Nemate dozvolu da citate ovaj metod ucenja. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Nemate dozvolu za beleženje @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Zatvori tekst###20 Jun 2005 content changed +qsts#:#cloze_textgapcase_insensitive#:#Case insensitive###03 Nov 2005 new variable +qsts#:#cloze_textgapcase_sensitive#:#Case sensitive###03 Nov 2005 new variable +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable +qsts#:#confirm_delete_questions#:#Da li ste sigurni da želite da obrišete sledece(a) pitanje(a)? Ukoliko obrišete zakljucana pitanja, rezultati svih testova koji sadrže zakljucana pitanja bice takode obrisani.###10 Jul 2006 content changed +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Razmak +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower limit###22 Feb 2006 new variable +qsts#:#range_upper_limit#:#Upper limit###22 Feb 2006 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Odaberite razmak +qsts#:#shuffle_answers#:#Izbegni odgovore +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Blok pitanja survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Blokovi pitanja survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Pitanja survey#:#questions_inserted#:#Pitanja ubacena! survey#:#questions_removed#:#Pitanja i/ili blok pitanja je uklonjen! survey#:#questiontype#:#Vrsta pitanja @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Pitanja survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_sv.lang b/lang/ilias_sv.lang index 552360765072..173e0180d12f 100644 --- a/lang/ilias_sv.lang +++ b/lang/ilias_sv.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Aktivera TinyMCE för WYSIWYG-redigering assessment#:#activate_logging#:#Aktivera loggning av test och bedömning assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Innehåll för repetition assessment#:#add_answers#:#Lägg till svar assessment#:#add_circle#:#Lägg till cirkel assessment#:#add_gap#:#Lägg till cloze @@ -501,7 +500,6 @@ assessment#:#ass_completion_by_submission#:#Passera genom att lämna in assessment#:#ass_completion_by_submission_info#:#Om den är aktiverad leder inlämnandet av en lösningsfil till att maximalt antal poäng tilldelas för denna fråga. Poängen kan justeras manuellt när som helst. Ändring av denna inställning har ingen efterföljande effekt på redan inlämnade lösningar. assessment#:#ass_create_export_file_with_results#:#Skapa exportfil (inkl. deltagarresultat) assessment#:#ass_create_export_test_archive#:#Skapa arkivfil för test -assessment#:#ass_create_question#:#Skapa fråga assessment#:#ass_imap_hint#:#Note (visas som verktygstips) assessment#:#ass_imap_map_file_not_readable#:#Den uppladdade bildkartan kan inte läsas. assessment#:#ass_imap_no_map_found#:#Ingen stödd form kunde hittas i den uppladdade bildkartan. @@ -571,10 +569,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Längd på textfältet assessment#:#cloze_fixed_textlength_description#:#Om du anger ett värde här skapas textgap som inte definierar ett eget värde för en maximal längd, samt numeriska gap med denna längd, så att det inte är möjligt att ange ett större antal tecken. För numeriska luckor, observera att decimalavgränsaren ocks assessment#:#cloze_gap_size_info#:#Om ett värde större än 0 anges skapas detta mellanrum med den längd som anges här. Om inget värde anges skapas detta mellanrum med den globalt angivna textfältslängden. -assessment#:#cloze_text#:#Cloze fråga -assessment#:#cloze_textgap_case_insensitive#:#Ingen skillnad görs mellan stora och små bokstäver -assessment#:#cloze_textgap_case_sensitive#:#Känsliga gemener -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein avstånd från %s assessment#:#code#:#Kod assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Länk @@ -757,9 +751,7 @@ assessment#:#fq_formula_desc#:#Tillåtet är användning av redan definierade va assessment#:#fq_no_restriction_info#:#Både decimaltal och bråktal accepteras som indata. assessment#:#fq_precision_info#:#Ange det antal decimaler du vill ha här. assessment#:#fq_question_desc#:#Du definierar variabler genom att ange $v1, $v2 ... $vn, resultatfält med $r1, $r2 .... $rn på önskade positioner i texten. Klicka sedan på knappen "Analysera fråga" för att generera redigeringsformulär för alla variabler och resultat. -assessment#:#gap#:#Gap assessment#:#gap_combination#:#Cloze kombination -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Glossarisk term assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Du har uppnått märket "[märke]". @@ -777,7 +769,6 @@ assessment#:#info_answer_type_change#:#Frågan innehåller redan bilder. Fråget assessment#:#info_text_upload#:#Välj en textfil (UTF-8) med svar som ska laddas upp. assessment#:#insert_after#:#Insätt bakom assessment#:#insert_before#:#Infoga före -assessment#:#insert_gap#:#Insert gap assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Interna referenser assessment#:#intprecision#:#Kan delas av @@ -889,7 +880,6 @@ assessment#:#logs_wrong_test_password_provided#:#Deltagaren har angett fel testl assessment#:#longmenu#:#Lång meny assessment#:#longmenu_answeroptions_differ#:#Den här frågan fungerar inte korrekt eftersom den inte har samma antal luckor i texten som i svarsalternativen. assessment#:#longmenu_text#:#"Lång meny" text -assessment#:#mainbar_button_label_questionlist#:#Questionlist###21 11 2023 new variable assessment#:#maintenance#:#Underhåll assessment#:#manscoring#:#Manuell bedömning assessment#:#manscoring_done#:#Redan betygsatta deltagare @@ -916,7 +906,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Du har förbrukat det maximala antale assessment#:#maximum_points#:#Maximalt uppnåelig poäng assessment#:#maxsize#:#Maximal filstorlek assessment#:#maxsize_info#:#Anger den maximala storleken i bytes som en uppladdad fil får ha. Om du lämnar fältet tomt används inställningen för det underliggande systemet. -assessment#:#min_auto_complete#:#Autokomplett assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Du måste ange en lägsta procentsats på 0 procent. Betygsschemat har inte sparats. assessment#:#misc#:#Olika alternativ @@ -925,7 +914,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle tillagd -assessment#:#msg_no_questions_selected#:#No questions were selected.###21 11 2023 new variable assessment#:#msg_number_of_terms_too_low#:#Antalet termer måste vara större än eller lika med antalet definitioner. assessment#:#msg_poly_added#:#Polygon tillagd assessment#:#msg_questions_moved#:#Frågeställningar uppskjutna @@ -984,7 +972,6 @@ assessment#:#order#:#Sortering assessment#:#ordering_answer_sequence_info#:#Den svarsordning som anges här används som korrekt lösningsordning. assessment#:#ordertext#:#Texten ska ordnas assessment#:#ordertext_info#:#Var vänlig ange texten i den ordning som den ska placeras horisontellt. De enskilda komponenterna separeras med mellanslag. Om du vill ha en annan avgränsning kan du använda avgränsaren %s istället för mellanslag. -assessment#:#out_of_range#:#Utanför intervall assessment#:#output#:#Utmatning assessment#:#output_mode#:#Utmatningsläge assessment#:#parseQuestion#:#Analysera frågan @@ -1053,7 +1040,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Avbryt -assessment#:#qpl_confirm_delete_questions#:#Är du säker på att du vill ta bort följande frågor? assessment#:#qpl_copy_insert_clipboard#:#De valda frågorna har kopierats till Urklipp assessment#:#qpl_copy_select_none#:#Välj minst en fråga för att kopiera den till urklipp! assessment#:#qpl_delete_rbac_error#:#Du har inte tillstånd att ta bort denna fråga! @@ -1106,7 +1092,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Kompetens assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Summa av alla kompetenspoäng per kompetens assessment#:#qpl_question_is_in_use#:#Frågan du vill redigera nu finns redan i %s test(s). Om du ändrar den här frågan nu kommer det INTE att påverka frågor som redan ingår i test, eftersom systemet automatiskt skapar en kopia av frågan när den ingår i ett test! assessment#:#qpl_questions_deleted#:#Frågor borttagna -assessment#:#qpl_reset_preview#:#Återställ förhandsgranskning assessment#:#qpl_save_skill_assigns_update#:#Spara kompetensuppdrag assessment#:#qpl_settings_availability#:#Availability###21 11 2023 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#Existerande taxonomier kan användas för att filtrera frågorna. @@ -1136,14 +1121,6 @@ assessment#:#qst_essay_chars_remaining#:#Andra tecken assessment#:#qst_essay_wordcounter_enabled#:#Räkna ord assessment#:#qst_essay_wordcounter_enabled_info#:#De inmatade orden räknas. Antalet ord visas för deltagarna under textinmatningsfältet. assessment#:#qst_essay_written_words#:#Antal inmatade ord -assessment#:#qst_lifecycle#:#Livscykel -assessment#:#qst_lifecycle_draft#:#Draft -assessment#:#qst_lifecycle_filter_all#:#Alla livscykler -assessment#:#qst_lifecycle_final#:#Final -assessment#:#qst_lifecycle_outdated#:#Veraltet -assessment#:#qst_lifecycle_rejected#:#Avvisad -assessment#:#qst_lifecycle_review#:#Revision nödvändig -assessment#:#qst_lifecycle_sharable#:#Distribuerbar assessment#:#qst_nested_nested_answers_off#:# Utan indragning assessment#:#qst_nested_nested_answers_on#:#Med indrag assessment#:#qst_nr_of_tries#:#Antal försök @@ -1167,17 +1144,14 @@ assessment#:#question_title#:#Frågans titel assessment#:#question_type#:#Typ av fråga assessment#:#questionpool_not_entered#:#Var vänlig ange ett namn för frågepoolen! assessment#:#questionpool_not_selected#:#Välkomna att välja en frågepool! -assessment#:#questions#:#Questions###21 11 2023 new variable assessment#:#questions_from#:#Frågor från assessment#:#questions_per_page_view#:#Sidvisning assessment#:#random_accept_sample#:#Acceptera sammanställning assessment#:#random_another_sample#:#Ny sammanställning assessment#:#random_selection#:#Slumpmässigt urval assessment#:#range#:#Område -assessment#:#range_lower_limit#:#Lägre barriär assessment#:#range_max#:#Range (maximalt) assessment#:#range_min#:#Range (Minimum) -assessment#:#range_upper_limit#:#Övre barriär assessment#:#rated_sign#:#Omens assessment#:#rated_unit#:#Enhet assessment#:#rated_value#:#Värde @@ -1253,7 +1227,6 @@ assessment#:#search_roles#:#Efter rullar assessment#:#search_term#:#Sökord assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Selektionsgap assessment#:#select_max_one_item#:#Välj endast ett objekt! assessment#:#select_one_user#:#Välj minst en användare! assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1253,6 @@ assessment#:#show_old_introduction#:#Show old introduction###21 11 2023 new vari assessment#:#show_pass_overview#:#Resultatöversikt (poängsatt provkörning) assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Answers (poängsatt testkörning) -assessment#:#shuffle_answers#:#Svar från Shuffle assessment#:#skip_question#:#Svara inte och fortsätt assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text @@ -13971,6 +13943,34 @@ qpl#:#qpl_page_type_qfbg#:#Allmän feedback qpl#:#qpl_page_type_qfbs#:#Särskild feedback qpl#:#qpl_page_type_qht#:#Note qpl#:#qpl_page_type_qpl#:#Frågesida +qsts#:#cloze_text#:#Cloze fråga +qsts#:#cloze_textgapcase_insensitive#:#Ingen skillnad görs mellan stora och små bokstäver +qsts#:#cloze_textgapcase_sensitive#:#Känsliga gemener +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein avstånd från %s +qsts#:#confirm_delete_questions#:#Är du säker på att du vill ta bort följande frågor? +qsts#:#create_question#:#Skapa fråga +qsts#:#gap#:#Gap +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert gap +qsts#:#min_auto_complete#:#Autokomplett +qsts#:#msg_no_questions_selected#:#No questions were selected.###21 11 2023 new variable +qsts#:#out_of_range#:#Utanför intervall +qsts#:#qst_lifecycle#:#Livscykel +qsts#:#qst_lifecycle_draft#:#Draft +qsts#:#qst_lifecycle_filter_all#:#Alla livscykler +qsts#:#qst_lifecycle_final#:#Final +qsts#:#qst_lifecycle_outdated#:#Veraltet +qsts#:#qst_lifecycle_rejected#:#Avvisad +qsts#:#qst_lifecycle_review#:#Revision nödvändig +qsts#:#qst_lifecycle_sharable#:#Distribuerbar +qsts#:#questionlist#:#Questionlist###21 11 2023 new variable +qsts#:#questions#:#Questions###21 11 2023 new variable +qsts#:#range_lower_limit#:#Lägre barriär +qsts#:#range_upper_limit#:#Övre barriär +qsts#:#reset_preview#:#Återställ förhandsgranskning +qsts#:#select_gap#:#Selektionsgap +qsts#:#shuffle_answers#:#Svar från Shuffle +qsts#:#suggested_learning_content#:#Innehåll för repetition rating#:#rat_not_rated_yet#:#Not yet rated rating#:#rat_nr_ratings#:#%s betyg rating#:#rat_one_rating#:#En bedömning @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Frågeställning block survey#:#questionblock_inserted#:#Frågeblock infört survey#:#questionblocks#:#Frågeblock survey#:#questionblocks_inserted#:#Frågeblock infogade -survey#:#questions#:#Frågor och svar survey#:#questions_inserted#:#Frågor tillagda survey#:#questions_removed#:#Frågor och/eller frågeblock borttagna! survey#:#questiontype#:#Typ av fråga @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Välj minst en oanvänd åtkomstnyckel survey#:#svy_print_hide_labels#:#Dölj Etiketter survey#:#svy_print_show_labels#:#Visa Märkningar survey#:#svy_privacy_info#:#Personuppgifter +survey#:#svy_questions#:#Frågor och svar survey#:#svy_rater#:#Feedback givare survey#:#svy_rater_see_app_info#:#feedbackgivare, namnen på de som tar emot feedback visas så att de kan svara på frågorna i förhållande till den som tar emot feedback. survey#:#svy_reminder_mail_template#:#Mall för e-post diff --git a/lang/ilias_tr.lang b/lang/ilias_tr.lang index c630f5961f1a..2d9e2ce3da34 100644 --- a/lang/ilias_tr.lang +++ b/lang/ilias_tr.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#WYSIWYG düzenleme için TinyMCE kullan assessment#:#activate_logging#:#Test ve Değerlendirme Günlüğünü Aktif Yap assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Önerilen çözüm ekle assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Daire alanı ekle assessment#:#add_gap#:#Boşluk Metni Ekle @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#Çözümünüz için puan ald assessment#:#answer_is_right#:#Çözümünüz doğru assessment#:#answer_is_wrong#:#Çözümünüz yanlış assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Yanıt Metin assessment#:#answer_types#:#Yanıt Türleri @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Başvuru ile Tamamlandı assessment#:#ass_completion_by_submission_info#:#Etkinse, bu soru için en az bir dosya gönderme maksimum puan alma için yeterlidir. Puan daha sonra elle değiştirilebilir. Bu ayarı değiştirme önceden gönderilen sorulara etki etmez assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Metin Alanı Uzunluğu assessment#:#cloze_fixed_textlength_description#:#Eğer 0'dan büyük bir değer girerseniz , tüm metin ve sayısal alan boşluklarının karakter uzunluğu bu değer olacaktır. assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Boşluklu Metin -assessment#:#cloze_textgap_case_insensitive#:#Büyük/Küçük Harf Duyarsız -assessment#:#cloze_textgap_case_sensitive#:#Büyük/Küçük Harf Duyarlı -assessment#:#cloze_textgap_levenshtein_of#:#%S in Levenshtein Uzaklığı assessment#:#code#:#Kod assessment#:#codebase#:#Codebase assessment#:#concatenation#:#Birleştirme @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Boşluk assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Sözlük Terim assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#Soru zaten resimler içeriyor. Cevap tür assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Sonrasına Ekle assessment#:#insert_before#:#Öncesine Ekle -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Dahili Linkler assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Bakım assessment#:#manscoring#:#Manuel Puanlama assessment#:#manscoring_done#:#Puanlanan Katılımcılar @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Bu testi tamamladınız. assessment#:#maximum_points#:#Maksimum Kullanılabilir Puanlar assessment#:#maxsize#:#Maksimum dosya yükleme boyutu assessment#:#maxsize_info#:#Dosya yüklemeleri için izin verilen en büyük boyutu bayt cinsinden girin. Bu alanı boş bırakırsanız, bu yükleme maksimum boyut yerine geçicek. -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#%0 yerine minimum yüzde tanımlamalısınız. Not şeması kayıt edilmedi. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Daire eklendi -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#Terimler sayısı tanımlar sayısından büyük veya eşit olmalı assessment#:#msg_poly_added#:#Poligon eklendi assessment#:#msg_questions_moved#:#Soru(lar) taşındı @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#Burada tanımladığınız cevap sırası doğru çözüm sırası olarak alınacak assessment#:#ordertext#:#Metin Sıralama assessment#:#ordertext_info#:#Yatay sıralanabilen metni giriniz. Sıralama metni, metin içinde boşluk(whitespace) ile ayrılacaktır.. Eğer farklı bir ayraç kullanmak isterseniz, text birimlerini ayırmak için %s ayracını kullanabilirsiniz. -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Çıktı assessment#:#output_mode#:#Çıkış Modu assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Aşağıdaki soruları silmek istediğinizden emin misiniz? assessment#:#qpl_copy_insert_clipboard#:#Seçilen soru(lar) panoya kopyalandı assessment#:#qpl_copy_select_none#:#Panoya kopyalamak için en az bir soruyu seçiniz assessment#:#qpl_delete_rbac_error#:#Bu soruyu silmek için yetkiniz yok ! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Düzenlemek üzere olduğunuz soru test %s içinde var Eğer bu soruyu değiştirirseniz, test(ler) içindeki soruyu değiştiremezsiniz, çünkü sistem soru teste eklendiğinde bir kopyasını alır. assessment#:#qpl_questions_deleted#:#Soru(lar) silindi. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Deneme Sayısı @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Soru Başlığı assessment#:#question_type#:#Soru Türü assessment#:#questionpool_not_entered#:#Soru havuzu için bir ad girin! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#sorular assessment#:#questions_per_page_view#:#Sayfa Görünümü assessment#:#random_accept_sample#:#Örnek Kabul assessment#:#random_another_sample#:#Başka bir örnek alın assessment#:#random_selection#:#Rasgele Seçim assessment#:#range#:#Aralık -assessment#:#range_lower_limit#:#Alt Sınır assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Üst Sınır assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Rolleri Ara assessment#:#search_term#:#Terim Ara assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Boşluk Seç assessment#:#select_max_one_item#:#Yalnızca bir öğe seçiniz assessment#:#select_one_user#:#En az bir kullanıcı seçiniz. assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Geçti İşaretlilere Genel Bakışı Göster assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Kullanıcının işaretli cevaplarını göster -assessment#:#shuffle_answers#:#Cevapları Karıştır assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Metin @@ -1401,7 +1372,7 @@ assessment#:#tst_answered_questions_of_total#:#%s of %s###07 02 2020 new variabl assessment#:#tst_answered_questions_test#:#Bu testteki cevaplanan sorular assessment#:#tst_attached_xls_file#:#You find the test result for this participant in the attached Excel file.###27 01 2015 new variable assessment#:#tst_attempt#:#Attempt###30 08 2015 new variable -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#Bu sınavı alabileceğiniz toplam sayı: %s. assessment#:#tst_attempt_started#:#Test Başladı assessment#:#tst_back_to_pass_details#:#Back to Pass Details###26 09 2014 new variable assessment#:#tst_back_to_question_list#:#Back to Question List###26 09 2014 new variable @@ -1452,7 +1423,7 @@ assessment#:#tst_derive_new_pools#:#Derive New Question Pools###25 10 2016 new v assessment#:#tst_dont_show_msg_again_in_current_session#:#Don't show this message again in my current session.###10 11 2018 new variable assessment#:#tst_edit_competence_assign#:#Edit Assignment Properties###30 08 2015 new variable assessment#:#tst_edit_scoring#:#Puanlama Düzenle -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:'Sorular Listesi'ni göster assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#Bitiş Zamanı assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1477,14 +1448,14 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#Lütfen testi başlatmak için şifreyi girin. assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#Test şifresi assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password_label#:#Şifre assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable -assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable +assessment#:#tst_exam_start#:#Teste Başla +assessment#:#tst_exam_use_previous_answers#:#Önceki cevapları kullanın assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#The working time of the participant has been increased by %s minutes.###24 10 2013 new variable assessment#:#tst_extratime_info#:#If you want to add the working time multiple times for the same participant, please insert the total amount of time you want to add.###14 05 2014 new variable @@ -1504,7 +1475,7 @@ assessment#:#tst_final_information#:#Finishing the Test: Information Before Subm assessment#:#tst_finish_confirm_button#:#Evet, testi bitirmek istiyorum assessment#:#tst_finish_confirm_cancel_button#:#Hayır, önceki soruya geri dön assessment#:#tst_finish_confirmation_question#:#Testi sonlandırmak üzeresiniz. Cevaplarınızı değiştirmek için bu teste tekrar giremeyeceksiniz. Gerçekten testi bitirmek istiyor musunuz? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#Bu testi bitireceksiniz ve izin verilen maksimum test deneme sayısına ulaşacaksınız. Cevaplarınızı değiştirmek için bu teste tekrar giremeyeceksiniz. Gerçekten testi bitirmek istiyor musunuz? assessment#:#tst_finished#:#Bitti assessment#:#tst_form_dynamic_question_set_config#:#Continues Question Selection###24 10 2013 new variable assessment#:#tst_gap_analysis#:#Gap Analysis###26 09 2014 new variable @@ -1591,7 +1562,7 @@ assessment#:#tst_invited_selected_users#:#Seçilen kullanıcıların sabit test assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_launcher_status_message_password#:#Testi başlattığınızda sizden şifre istenecektir. assessment#:#tst_level#:#Competence Level###26 09 2014 new variable assessment#:#tst_limit_nr_of_tries#:#Maximum Number of Test Passes###07 11 2014 new variable assessment#:#tst_link_only_unassigned#:#Zaten bir soru havuzu ile bağlantılı en az bir soru seçtiniz. Sadece atanmamış soru ettiği havuz için ilave edilebilir. @@ -1696,7 +1667,7 @@ assessment#:#tst_objective_progress_header#:#Learning Objective Progress###25 10 assessment#:#tst_objectives_progress_header#:#Learning Objectives Progress###25 10 2016 new variable assessment#:#tst_old_style_rnd_quest_set_broken#:#This random test is in a irreparable state, because one or more connected question pools have been deleted. Therefor participants cannot take the test any longer.###30 08 2015 new variable assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Question related to allready passed learning objectives are optional.

    You want to navigate to a question, that relates to an allready passed learning objective.
    You can choose:

    I you proceed, you can work on these questions. Your answers from previous attempts were not adopted, since new random questions were selected for this attempt. With working on this questions you can also degrade your learning objective result.

    If you decide to not work on these questions, you can go back. In this case these questions won't be considered in the evaluation.###30 08 2015 new variable -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#Bu sınav için ayrılan süre doldu. assessment#:#tst_participant#:#Katılımcı assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s###26 09 2014 new variable assessment#:#tst_participant_status#:#Katılımcı Durumu @@ -1952,7 +1923,7 @@ assessment#:#tst_text_count_system#:#Puanlama Sistemi assessment#:#tst_threshold#:#Thresholds###26 09 2014 new variable assessment#:#tst_time_already_spent#:#%s de test başladı. Maksimum işlem süresi %s. assessment#:#tst_time_already_spent_left#:#%s kaldı. -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#Tüm soruları yanıtlamak için %s dakikanız olacak. assessment#:#tst_title_output#:#Soru Başlığı assessment#:#tst_title_output_full#:#Soru Başlığı ve Puanları Göster assessment#:#tst_title_output_hide_points#:#Sadece Soru Başlıklarını Göster @@ -4660,7 +4631,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#Favoriler common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4671,10 +4642,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#Ağaç görünümü +common#:#mm_repo_tree_view_act#:#Aktywuj widok drzewa +common#:#mm_repo_tree_view_deact#:#Deaktywuj widok drzewa +common#:#mm_repository#:#Depo common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Aşağıdaki nesne (ler) yapıştırın izniniz yok common#:#msg_no_perm_paste_object_in_folder#:#Klasördeki% s nesnesini% s yapıştırmak için izniniz yoktur. common#:#msg_no_perm_perm#:#İzin ayarlarını düzenlemek için izniniz yoktur common#:#msg_no_perm_read#:#Bu öğeye erişmek için izniniz yoktur. -common#:#msg_no_perm_read_item#:#Her öğe '% s' erişim izniniz yok. +common#:#msg_no_perm_read_item#:#Her öğe erişim izniniz yok. common#:#msg_no_perm_read_lm#:#Bu öğrenme modülü okumak için izniniz yoktur. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Yazma yetkiniz yok @@ -5057,8 +5028,8 @@ common#:#obj_rcat#:#ECS Kategori common#:#obj_rcrs#:#ECS Kursu common#:#obj_recf#:#Restored Nesneler common#:#obj_recf_desc#:#Sistem Kontrolü dan restore Nesneler içerir. -common#:#obj_rep#:#Repository###07 02 2020 new variable -common#:#obj_reps#:#Repository###24 10 2013 new variable +common#:#obj_rep#:#Depo +common#:#obj_reps#:#Depo common#:#obj_reps_desc#:#General settings for the Repository###24 10 2013 new variable common#:#obj_rfil#:#ECS Dosya common#:#obj_rglo#:#ECS Sözlüğü @@ -7708,7 +7679,7 @@ crs#:#crs_members_map#:#Ders Üyeler Harita crs#:#crs_members_print_title#:#Ders üyeleri crs#:#crs_min_one_admin#:#Bunun ders atanmış en az bir yönetici olmalıdır. crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable +crs#:#crs_my_courses_groups_enabled#:#Kurslarım ve Gruplarım crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable crs#:#crs_new_status#:#Yeni durumu: crs#:#crs_new_subscription#:#Kullanıcı kursu "% s" için tescil @@ -8090,15 +8061,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#Favoriler dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#Kurslarım ve Gruplarım dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#Favoriler dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8110,7 +8081,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#Kurslarım ve Gruplarım dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Boşluklu Metin +qsts#:#cloze_textgapcase_insensitive#:#Büyük/Küçük Harf Duyarsız +qsts#:#cloze_textgapcase_sensitive#:#Büyük/Küçük Harf Duyarlı +qsts#:#cloze_textgaplevenshtein_of#:#%S in Levenshtein Uzaklığı +qsts#:#confirm_delete_questions#:#Aşağıdaki soruları silmek istediğinizden emin misiniz? +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Boşluk +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Soru listesi +qsts#:#questions#:#Sorular +qsts#:#range_lower_limit#:#Alt Sınır +qsts#:#range_upper_limit#:#Üst Sınır +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Boşluk Seç +qsts#:#shuffle_answers#:#Cevapları Karıştır +qsts#:#suggested_learning_content#:#Önerilen çözüm ekle rating#:#rat_not_rated_yet#:#Henüz Oylanmadı rating#:#rat_nr_ratings#:#%s Puan rating#:#rat_one_rating#:#Bir Değerlendirme @@ -15080,10 +15080,10 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable -rep#:#rep_favourites#:#Favourites###29 07 2022 new variable +rep#:#rep_fav_intro1#:#Henüz hiçbir favori seçmediniz. Bunu yapmak için iki adımı tamamlamanız gerekiyor: +rep#:#rep_fav_intro2#:#'%s' üzerine tıklayın ve mevcut seçeneklerden bir öğrenme nesnesi seçin, örneğin bir öğrenme modülü veya bir forum. +rep#:#rep_fav_intro3#:#İlginizi çeken bir şey bulursanız, onu kolayca favorilerinize ekleyebilirsiniz. İstediğiniz öğe için, İşlemler menüsünden "Favorilere Ekle" seçeneğini belirleyin. +rep#:#rep_favourites#:#Favoriler rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#Repository hoş geldiniz! @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Soru Blok survey#:#questionblock_inserted#:#Soru Blok takılı survey#:#questionblocks#:#Soru Blokları survey#:#questionblocks_inserted#:#Takılı Soru Blokları -survey#:#questions#:#Sorular survey#:#questions_inserted#:#Soru (ler) eklenir! survey#:#questions_removed#:#Soru (ler) ve / veya söz konusu bloğun (ler) kaldırıldı! survey#:#questiontype#:#Soru Türü @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Sorular survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_uk.lang b/lang/ilias_uk.lang index ed5334ea9912..143841d64e26 100644 --- a/lang/ilias_uk.lang +++ b/lang/ilias_uk.lang @@ -422,7 +422,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Активувати логування Тестів & Оцінок assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Додати текст з проміжком @@ -447,7 +446,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Ваша відповідь вірна assessment#:#answer_is_wrong#:#Вага відповідь невірна assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Текст з відповідю assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -501,7 +499,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -571,10 +568,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Закрити текст###20 Jun 2005 content changed -assessment#:#cloze_textgap_case_insensitive#:#Case insensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_case_sensitive#:#Case sensitive###03 Nov 2005 new variable -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable assessment#:#code#:#Код assessment#:#codebase#:#Codebase###25 02 2007 new variable assessment#:#concatenation#:#Об'єднання @@ -757,9 +750,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Проміжок assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Термін глосарію assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -777,7 +768,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Вставити після assessment#:#insert_before#:#Вставити перед -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Внутрішні Посилання assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -889,7 +879,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Підтримка assessment#:#manscoring#:#Manual Scoring###25 02 2007 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -916,7 +905,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Ви досялги максимал assessment#:#maximum_points#:#Maxium Available Points###25 02 2007 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Ви маєете вказати мінімальне процентне співвідношення до нуля процентів! Схема оцінок не збережена. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -925,7 +913,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -984,7 +971,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 02 2007 new variable assessment#:#output_mode#:#Output Mode###25 02 2007 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1053,7 +1039,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Ви впевнені що бажаєте видалити наступні питання ? Якщо ви видалите заблоковані питання то результати усіх тестів що містять залоковані питання буде також видалено. assessment#:#qpl_copy_insert_clipboard#:#The selected question(s) are copied to the clipboard###03 Nov 2005 new variable assessment#:#qpl_copy_select_none#:#Please check at least one question to copy it to the clipboard###03 Nov 2005 new variable assessment#:#qpl_delete_rbac_error#:#У вас немає прав видалити це питання! @@ -1106,7 +1091,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Питання що ви збираєтесь редагувати існує в %s тесті(ах). Якщо ви зміните це питання, ви НЕ зміните питання в тесті(ах), тому що система створює копію питання коли воно вставляється в тест! assessment#:#qpl_questions_deleted#:#Питання виделено(і). -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1136,14 +1120,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1167,17 +1143,14 @@ assessment#:#question_title#:#Назва питання assessment#:#question_type#:#Тип Питання assessment#:#questionpool_not_entered#:#Будб ласка введіть ім'я для пула з питаннями! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#питання з assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Прийняти приклад assessment#:#random_another_sample#:#Взяти інший приклад assessment#:#random_selection#:#Випадковий вибір assessment#:#range#:#Range###25 02 2007 new variable -assessment#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1253,7 +1226,6 @@ assessment#:#search_roles#:#Пошук Ролей assessment#:#search_term#:#Пошук Термінів assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Вибрати проміжок assessment#:#select_max_one_item#:#Будь ласка виберіть тільки один пункт assessment#:#select_one_user#:#Please select at least one user###23 Dec 2005 new variable assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1280,7 +1252,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Перерозташувати відповіді assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4763,7 +4734,7 @@ common#:#msg_no_perm_paste#:#Ви не маєте права вставляти common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Ви не маєте права редагувати настройки прав common#:#msg_no_perm_read#:#Ви не маєте прав для доступу в цей розділ. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###25 02 2007 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#Ви не маєте прав читати цей учбовий модуль. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Ви не маєте права записувати @@ -13971,6 +13942,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Закрити текст###20 Jun 2005 content changed +qsts#:#cloze_textgapcase_insensitive#:#Case insensitive###03 Nov 2005 new variable +qsts#:#cloze_textgapcase_sensitive#:#Case sensitive###03 Nov 2005 new variable +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s###03 Nov 2005 new variable +qsts#:#confirm_delete_questions#:#Ви впевнені що бажаєте видалити наступні питання ? Якщо ви видалите заблоковані питання то результати усіх тестів що містять залоковані питання буде також видалено. +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Проміжок +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable +qsts#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Вибрати проміжок +qsts#:#shuffle_answers#:#Перерозташувати відповіді +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16620,7 +16620,6 @@ survey#:#questionblock#:#Блок питань survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Блоки питань survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Питання survey#:#questions_inserted#:#Питання вставлені! survey#:#questions_removed#:#Питання та/або блоки питань видалені! survey#:#questiontype#:#Тип питання @@ -16921,6 +16920,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Питання survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_vi.lang b/lang/ilias_vi.lang index 333e15b4fa3c..37cffd20960d 100644 --- a/lang/ilias_vi.lang +++ b/lang/ilias_vi.lang @@ -424,7 +424,6 @@ adve#:#adve_use_tiny_mce#:#Enable TinyMCE for WYSIWYG Editing###01 10 2011 new v assessment#:#activate_logging#:#Kích hoạt ghi nhật ký Kiểm tra và Đánh giá assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#Add suggested solution###24 02 2009 new variable assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#Add circle area###24 07 2009 new variable assessment#:#add_gap#:#Thêm từ @@ -449,7 +448,6 @@ assessment#:#answer_is_not_correct_but_positive#:#You've got points for your sol assessment#:#answer_is_right#:#Giải pháp của bạn đúng assessment#:#answer_is_wrong#:#Giải pháp của bạn sai assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#Phương án trả lời assessment#:#answer_types#:#Answer Types###24 07 2009 new variable @@ -503,7 +501,6 @@ assessment#:#ass_completion_by_submission#:#Completed by Submission###12 06 2011 assessment#:#ass_completion_by_submission_info#:#If enabled, the submission of at least one file causes the completion of this question by granting the maximum score for this question. The score could be manually changed later. Switching this setting does not effect already submitted solutions.###12 06 2011 new variable assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -573,10 +570,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#Text Field Length###02 04 2007 new variable assessment#:#cloze_fixed_textlength_description#:#If you enter a value greater than 0, all text and numeric gap text fields will be created with the fixed length of this value.###02 04 2007 new variable assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#Đoạn văn điền chỗ trống -assessment#:#cloze_textgap_case_insensitive#:#Không phân biệt chữ hoa chữ thường -assessment#:#cloze_textgap_case_sensitive#:#Phân biệt chữ hoa chữ thường -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s/// assessment#:#code#:#Mã assessment#:#codebase#:#Codebase###25 02 2007 new variable assessment#:#concatenation#:#Kết hợp @@ -759,9 +752,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#Chỗ trống assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#Bảng chú giải thuật ngữ assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -779,7 +770,6 @@ assessment#:#info_answer_type_change#:#The question already contains images. You assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#Chèn vào sau assessment#:#insert_before#:#Chèn vào trước -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#Liên kết nội bộ assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -891,7 +881,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Bảo quản - bảo trì assessment#:#manscoring#:#Manual Scoring###25 02 2007 new variable assessment#:#manscoring_done#:#Scored Participants###24 02 2009 new variable @@ -918,7 +907,6 @@ assessment#:#maximum_nr_of_tries_reached#:#Bạn đã hết số lần có thể assessment#:#maximum_points#:#Maxium Available Points###25 02 2007 new variable assessment#:#maxsize#:#Maximum file upload size ###24 02 2009 new variable assessment#:#maxsize_info#:#Enter the maximum size in bytes that should be allowed for file uploads. If you leave this field empty, the maximum size of this installation will be chosen instead.###24 02 2009 new variable -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#Bạn phải định nghĩa phần trăm tối thiếu là 0 phần trăm! Giản đồ điểm không được ghi. assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -927,7 +915,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#Circle added###24 07 2009 new variable -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#The number of terms must be greater or equal to the number of definitions.###12 08 2009 new variable assessment#:#msg_poly_added#:#Polygon added###24 07 2009 new variable assessment#:#msg_questions_moved#:#Question(s) moved###06 08 2009 new variable @@ -986,7 +973,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#The answer sequence you define here will be taken as the correct solution sequence.###10 09 2010 new variable assessment#:#ordertext#:#Ordering Text###24 02 2009 new variable assessment#:#ordertext_info#:#Please enter the text that should be ordered horizontally. The ordering text will be separated by the whitespace signs in the text. If you need a different separation, you may use the separator %s to separate your text units.###24 02 2009 new variable -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#Output###25 02 2007 new variable assessment#:#output_mode#:#Output Mode###25 02 2007 new variable assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1055,7 +1041,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#Bạn có chắc chắn muốn xóa (các) câu hỏi sau không? Nếu bạn xóa các câu hỏi đã khóa kết quả của tất cả bài kiểm tra chứa câu hỏi đã khóa sẽ bị xóa theo. assessment#:#qpl_copy_insert_clipboard#:#(Những) câu hỏi bạn chọn đã được sao chép vào bộ nhớ đệm assessment#:#qpl_copy_select_none#:#Hãy chọn ít nhất một câu hỏi để sao chép vào bộ nhớ đệm assessment#:#qpl_delete_rbac_error#:#Bạn không có quyền xóa câu hỏi này! @@ -1108,7 +1093,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#Câu hỏi bạn muốn sửa đang tồn tại trong %s bài kiểm tra. Nếu bạn thay đổi câu hỏi này, bạn sẽ không thay đổi những câu hỏi trong các bài kiểm tra, vì hệ thống tạo ra bản sao của câu hỏi khi chèn câu hỏi vào bài kiểm tra! assessment#:#qpl_questions_deleted#:#Đã xóa (các) câu hỏi. -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1138,14 +1122,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#Number of tries###15 05 2009 new variable @@ -1169,17 +1145,14 @@ assessment#:#question_title#:#Tiêu đề câu hỏi assessment#:#question_type#:#Kiểu câu hỏi assessment#:#questionpool_not_entered#:#Hãy nhập vào tên thư viện câu hỏi! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#câu hỏi từ assessment#:#questions_per_page_view#:#Page View###12 06 2011 new variable assessment#:#random_accept_sample#:#Chấp nhận mẫu assessment#:#random_another_sample#:#Lấy mẫu khác assessment#:#random_selection#:#Lựa chọn ngẫu nhiên assessment#:#range#:#Range###25 02 2007 new variable -assessment#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1255,7 +1228,6 @@ assessment#:#search_roles#:#Tìm kiếm vai trò assessment#:#search_term#:#Tìm kiếm thuật ngữ assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#Lựa chọn từ điền assessment#:#select_max_one_item#:#Hãy chọn chỉ một mục assessment#:#select_one_user#:#Hãy chọn ít nhất một người sử dụng assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1282,7 +1254,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#Show Marked Pass Overview###31 05 2007 new variable assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#Show User's Marked Anwers###31 05 2007 new variable -assessment#:#shuffle_answers#:#Xáo trộn các lựa chọn assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text###24 02 2009 new variable @@ -4765,7 +4736,7 @@ common#:#msg_no_perm_paste#:#Bạn không có quyền dán những đối tượ common#:#msg_no_perm_paste_object_in_folder#:#You have no permission to paste the object %s in the folder %s.###24 02 2009 new variable common#:#msg_no_perm_perm#:#Bạn không có quyền sửa thiết lập quyền hạn common#:#msg_no_perm_read#:#Bạn không có quyền truy cập mục này. -common#:#msg_no_perm_read_item#:#You have no permission to access item '%s'.###25 02 2007 new variable +common#:#msg_no_perm_read_item#:#You have no permission to access this object. common#:#msg_no_perm_read_lm#:#Bạn không có quyền đọc học phần này. common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#Bạn không có quyền viết @@ -13973,6 +13944,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#Đoạn văn điền chỗ trống +qsts#:#cloze_textgapcase_insensitive#:#Không phân biệt chữ hoa chữ thường +qsts#:#cloze_textgapcase_sensitive#:#Phân biệt chữ hoa chữ thường +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s/// +qsts#:#confirm_delete_questions#:#Bạn có chắc chắn muốn xóa (các) câu hỏi sau không? Nếu bạn xóa các câu hỏi đã khóa kết quả của tất cả bài kiểm tra chứa câu hỏi đã khóa sẽ bị xóa theo. +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#Chỗ trống +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#Questionlist###26 08 2024 new variable +qsts#:#questions#:#Questions###26 08 2024 new variable +qsts#:#range_lower_limit#:#Lower Bound###25 02 2007 new variable +qsts#:#range_upper_limit#:#Upper Bound###25 02 2007 new variable +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#Lựa chọn từ điền +qsts#:#shuffle_answers#:#Xáo trộn các lựa chọn +qsts#:#suggested_learning_content#:#Add suggested solution###24 02 2009 new variable rating#:#rat_not_rated_yet#:#Not Rated Yet###12 06 2011 new variable rating#:#rat_nr_ratings#:#%s Ratings###12 06 2011 new variable rating#:#rat_one_rating#:#One Rating###12 06 2011 new variable @@ -16622,7 +16622,6 @@ survey#:#questionblock#:#Khối câu hỏi survey#:#questionblock_inserted#:#Question Block inserted###06 08 2009 new variable survey#:#questionblocks#:#Khối câu hỏi survey#:#questionblocks_inserted#:#Question Blocks inserted###06 08 2009 new variable -survey#:#questions#:#Câu hỏi survey#:#questions_inserted#:#Đã thêm (các) câu hỏi! survey#:#questions_removed#:#Câu hỏi và/hoặc khối câu hỏi đã xóa! survey#:#questiontype#:#Kiểu câu hỏi @@ -16923,6 +16922,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#Câu hỏi survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/lang/ilias_zh.lang b/lang/ilias_zh.lang index dbdeaeaf4282..f2cab7f66e29 100644 --- a/lang/ilias_zh.lang +++ b/lang/ilias_zh.lang @@ -421,7 +421,6 @@ adve#:#adve_use_tiny_mce#:#为所见即所得编辑启用TinyMCE。 assessment#:#activate_logging#:#激测试 & 评估日志 assessment#:#activate_manual_scoring#:#Enable Manual Scoring###28 10 2024 new variable assessment#:#activate_manual_scoring_desc#:#Enables manual Scoring for all question types.###28 10 2024 new variable -assessment#:#addSuggestedSolution#:#添加建议解决方案 assessment#:#add_answers#:#Add Antworten ###23 12 2015 new variable assessment#:#add_circle#:#添加圆区域 assessment#:#add_gap#:#添加填空文字 @@ -446,11 +445,10 @@ assessment#:#answer_is_not_correct_but_positive#:#您已经获取了解决方案 assessment#:#answer_is_right#:#回答正确 assessment#:#answer_is_wrong#:#回答错误 assessment#:#answer_of#:#Answer of###07 02 2020 new variable -assessment#:#answer_options#:#Answer Options: ###23 12 2015 new variable assessment#:#answer_question#:#Answer Question###30 08 2015 new variable assessment#:#answer_text#:#答案文本 assessment#:#answer_types#:#答案类型 -assessment#:#answered#:#Answered###07 11 2014 new variable +assessment#:#answered#:#已回答 assessment#:#answers_multiline#:#多行答案 assessment#:#answers_of#:#Answers of:###24 10 2013 new variable assessment#:#answers_select#:#Select###30 08 2015 new variable @@ -500,7 +498,6 @@ assessment#:#ass_completion_by_submission#:#提交已完成 assessment#:#ass_completion_by_submission_info#:#如果启用,至少一个文件因为通过为这个题目授予最高分完成这个题目而提交。这个分数以后可以手工修改。切换这个设置不影响已提交的方案。 assessment#:#ass_create_export_file_with_results#:#Create Test Export File (incl. Participant Results)###25 10 2016 new variable assessment#:#ass_create_export_test_archive#:#Create Test Archive File###24 10 2013 new variable -assessment#:#ass_create_question#:#Create Question###24 10 2013 new variable assessment#:#ass_imap_hint#:#Hint to be shown as Tooltip###25 10 2016 new variable assessment#:#ass_imap_map_file_not_readable#:#The uploaded image map could not be read.###25 10 2016 new variable assessment#:#ass_imap_no_map_found#:#Could not find any form in the uploaded image map.###25 10 2016 new variable @@ -570,10 +567,6 @@ assessment#:#cloze_answer_text_info#:#Spaces preceding or following the answer t assessment#:#cloze_fixed_textlength#:#文本域长度 assessment#:#cloze_fixed_textlength_description#:#如果输入一个大于0的值,所有文本和数字的文本域将以这个值的固定长度被创建。 assessment#:#cloze_gap_size_info#:#If you enter a value greater than 0, this gap text field will be created with the fixed length of this value. If you do not enter a value the gap text fiel will be created with the value of the global fixed length.###26 09 2014 new variable -assessment#:#cloze_text#:#填充测验文本 -assessment#:#cloze_textgap_case_insensitive#:#不区分大小写 -assessment#:#cloze_textgap_case_sensitive#:#区分大小定 -assessment#:#cloze_textgap_levenshtein_of#:#Levenshtein distance of %s assessment#:#code#:#代码 assessment#:#codebase#:#代码库 assessment#:#concatenation#:#级联 @@ -756,9 +749,7 @@ assessment#:#fq_formula_desc#:#You may enter predefined variables ($v1 to $vn), assessment#:#fq_no_restriction_info#:#Both decimals and fractions are accepted as input.###26 03 2014 new variable assessment#:#fq_precision_info#:#Enter the number of desired decimal places.###26 03 2014 new variable assessment#:#fq_question_desc#:#You can define variables by inserting $v1, $v2 ... $vn, results by inserting $r1, $r2 .... $rn at the desired position in the question text. Click on the button "Parse Question" to create editing forms for variables and results.###06 11 2013 new variable -assessment#:#gap#:#间隔 assessment#:#gap_combination#:#Gap Combination###26 09 2014 new variable -assessment#:#gaps#:#Gaps###29 10 2025 new variable assessment#:#glossary_term#:#术语表 assessment#:#goto_first_question#:#Show First Question###29 10 2025 new variable assessment#:#grading_mark_msg#:#Your resulting mark is: "[mark]"###26 09 2014 new variable @@ -776,7 +767,6 @@ assessment#:#info_answer_type_change#:#这道题已经包含图片。您不能 assessment#:#info_text_upload#:#Choose an answer file to upload###30 08 2015 new variable assessment#:#insert_after#:#后插 assessment#:#insert_before#:#前插 -assessment#:#insert_gap#:#Insert Gap###24 10 2013 new variable assessment#:#interaction_type#:#Interaction Type###26 08 2024 new variable assessment#:#internal_links#:#内部链接 assessment#:#intprecision#:#Divisible By###24 10 2013 new variable @@ -888,7 +878,6 @@ assessment#:#logs_wrong_test_password_provided#:#Participant entered wrong test assessment#:#longmenu#:#Longmenu###10 11 2018 new variable assessment#:#longmenu_answeroptions_differ#:#This question does not work correctly, as there are not the same amount of gaps in the text as in the correction options.###26 08 2024 new variable assessment#:#longmenu_text#:#Long Menu Text###30 08 2015 new variable -assessment#:#mainbar_button_label_questionlist#:#Questionlist###26 08 2024 new variable assessment#:#maintenance#:#Maintenance维护 assessment#:#manscoring#:#Manual Scoring手动评分 assessment#:#manscoring_done#:#Scored Participants评分参加者 @@ -915,7 +904,6 @@ assessment#:#maximum_nr_of_tries_reached#:#用户已经达到了每日所限制 assessment#:#maximum_points#:#最大有效分值 assessment#:#maxsize#:#文件上传的最大尺寸 assessment#:#maxsize_info#:#输入将被允许上传的文件的最大值(单位字节)。如果这个域留空,这次安装的最大尺寸将被选择替代。 -assessment#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable assessment#:#min_ip_label#:#Lowest IP With Access###26 08 2024 new variable assessment#:#min_percentage_ne_0#:#您必须定义一个最低百分比0%!这个标记模式没被保存。 assessment#:#misc#:#Misc Options###24 10 2013 new variable @@ -924,7 +912,6 @@ assessment#:#mode_onebyone#:#One by One###29 10 2025 new variable assessment#:#mode_question#:#Question oriented###29 10 2025 new variable assessment#:#mode_user#:#Participant oriented###29 10 2025 new variable assessment#:#msg_circle_added#:#加入圈子 -assessment#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable assessment#:#msg_number_of_terms_too_low#:#项目的数量必需大于或等于定义的数量。 assessment#:#msg_poly_added#:#添加多边形 assessment#:#msg_questions_moved#:#题目被移除 @@ -983,7 +970,6 @@ assessment#:#order#:#Order###26 08 2024 new variable assessment#:#ordering_answer_sequence_info#:#您定义在这里的答案序列将被视为正确的方案序列。 assessment#:#ordertext#:#文本排序 assessment#:#ordertext_info#:#请输入水平排序的文本。这个排序文本将被空白标志分隔开。如果您需要一个不同的分隔方式,您可以使用分隔器 %s 去分隔您的文本单元。 -assessment#:#out_of_range#:#Out of range###27 01 2015 new variable assessment#:#output#:#输出 assessment#:#output_mode#:#输出模式 assessment#:#parseQuestion#:#Parse Question###24 10 2013 new variable @@ -1052,7 +1038,6 @@ assessment#:#qpl_bulk_save_add#:#Add###28 10 2024 new variable assessment#:#qpl_bulk_save_overwrite#:#Overwrite###28 10 2024 new variable assessment#:#qpl_bulkedit_success#:#Modifications saved.###28 10 2024 new variable assessment#:#qpl_cancel_skill_assigns_update#:#Cancel###30 08 2015 new variable -assessment#:#qpl_confirm_delete_questions#:#您确认删除下面的题目?如果您删除已经锁定的题目,所有包含被锁定题目的测试结果也将被删除。 assessment#:#qpl_copy_insert_clipboard#:#被选择的题目已经复制到了剪贴板上 assessment#:#qpl_copy_select_none#:#请至少勾选一个题目,然后复制到剪贴板上 assessment#:#qpl_delete_rbac_error#:#您无权删除此题目! @@ -1105,7 +1090,6 @@ assessment#:#qpl_qst_skl_usg_skill_col#:#Competence###30 08 2015 new variable assessment#:#qpl_qst_skl_usg_sklpnt_col#:#Total Sum of Competence-Points per Competence###30 08 2015 new variable assessment#:#qpl_question_is_in_use#:#您即将编辑的题目已存在于 %s 测试中。如果您改变这个题目,您将不能改变这个测试中的题目,因为当一个题目插入到一个测试中时,系统会创建一个它的复本。 assessment#:#qpl_questions_deleted#:#题目已删除 -assessment#:#qpl_reset_preview#:#Reset Preview###26 09 2014 new variable assessment#:#qpl_save_skill_assigns_update#:#Save Competence Assignments###30 08 2015 new variable assessment#:#qpl_settings_availability#:#Availability###26 08 2024 new variable assessment#:#qpl_settings_general_form_prop_show_tax_desc#:#When enabled, possibly created taxonomies are shown for filtering.###24 10 2013 new variable @@ -1135,14 +1119,6 @@ assessment#:#qst_essay_chars_remaining#:#Remaining characters:###07 02 2020 new assessment#:#qst_essay_wordcounter_enabled#:#Count Words###07 02 2020 new variable assessment#:#qst_essay_wordcounter_enabled_info#:#The entered words are counted. The number of written words is shown to the participants below the text input field.###07 02 2020 new variable assessment#:#qst_essay_written_words#:#Number of entered words:###07 02 2020 new variable -assessment#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable -assessment#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable -assessment#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable -assessment#:#qst_lifecycle_final#:#Final###07 02 2020 new variable -assessment#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable -assessment#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable -assessment#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable -assessment#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable assessment#:#qst_nested_nested_answers_off#:#No indents, just order###29 07 2022 new variable assessment#:#qst_nested_nested_answers_on#:#Use indents in anwers###29 07 2022 new variable assessment#:#qst_nr_of_tries#:#尝试次数。 @@ -1166,17 +1142,14 @@ assessment#:#question_title#:#题目标题 assessment#:#question_type#:#题目类型 assessment#:#questionpool_not_entered#:#请为题目池输入一个名字! assessment#:#questionpool_not_selected#:#Please select a question pool!###07 02 2020 new variable -assessment#:#questions#:#Questions###26 08 2024 new variable assessment#:#questions_from#:#题目表单 assessment#:#questions_per_page_view#:#页面视图 assessment#:#random_accept_sample#:#Accept sample assessment#:#random_another_sample#:#获取其它示例 assessment#:#random_selection#:#随机选择 assessment#:#range#:#范围 -assessment#:#range_lower_limit#:#下限 assessment#:#range_max#:#Range (Maximum)###24 10 2013 new variable assessment#:#range_min#:#Range (Minimum)###24 10 2013 new variable -assessment#:#range_upper_limit#:#上限 assessment#:#rated_sign#:#Sign###24 10 2013 new variable assessment#:#rated_unit#:#Unit###24 10 2013 new variable assessment#:#rated_value#:#Value###24 10 2013 new variable @@ -1252,7 +1225,6 @@ assessment#:#search_roles#:#搜索角色 assessment#:#search_term#:#搜索条目 assessment#:#select_at_least_one_feedback_type_and_trigger#:#Please Select at least one type of feedback and a trigger.###26 08 2024 new variable assessment#:#select_at_least_one_lock_answer_type#:#Please select at least one type of answer lock.###29 10 2025 new variable -assessment#:#select_gap#:#选择间隔 assessment#:#select_max_one_item#:#请仅选择一个条目 assessment#:#select_one_user#:#请至少选择一个用户 assessment#:#select_question#:#Select a Question###28 10 2024 new variable @@ -1279,7 +1251,6 @@ assessment#:#show_old_introduction#:#Show old introduction###26 08 2024 new vari assessment#:#show_pass_overview#:#展示已标注通过的概况 assessment#:#show_results#:#Show Results###28 10 2024 new variable assessment#:#show_user_answers#:#展示用户的已标注答案 -assessment#:#shuffle_answers#:#简答题 assessment#:#skip_question#:#Do not Answer and Next###08 10 2015 new variable assessment#:#solution#:#Solution###28 10 2024 new variable assessment#:#solutionText#:#Text文档 @@ -1392,15 +1363,15 @@ assessment#:#tst_answer_fixation_on_instant_feedback#:#Lock Answers with the Pre assessment#:#tst_answer_fixation_on_instant_feedback_desc#:#After the feedback for a question is shown participant answers are locked, participants cannot change these answers any longer.###10 11 2018 new variable assessment#:#tst_answer_fixation_on_instantfb_or_followupqst#:#Lock Answers with the Presentation of Feedback or Follow-Up Questions###10 11 2018 new variable assessment#:#tst_answer_fixation_on_instantfb_or_followupqst_desc#:#Participant Answers for a question will be locked either with the presentation of the questions's feedback or when the follow-up question is shown.###10 11 2018 new variable -assessment#:#tst_answer_status_answered#:#Answered###fau: testNav -assessment#:#tst_answer_status_editing#:# (editing ... )###fau: testNav -assessment#:#tst_answer_status_not_answered#:#Not answered###fau: testNav +assessment#:#tst_answer_status_answered#:#已回答###fau: testNav +assessment#:#tst_answer_status_editing#:# (编辑...)###fau: testNav +assessment#:#tst_answer_status_not_answered#:#未回答###fau: testNav assessment#:#tst_answered_questions#:#已经回答题目 assessment#:#tst_answered_questions_of_total#:#%s of %s###07 02 2020 new variable assessment#:#tst_answered_questions_test#:#这个测试中已回答的题目 assessment#:#tst_attached_xls_file#:#You find the test result for this participant in the attached Excel file.###27 01 2015 new variable assessment#:#tst_attempt#:#Attempt###30 08 2015 new variable -assessment#:#tst_attempt_limit_message#:#Your limit of test attempts is %s.###26 08 2024 new variable +assessment#:#tst_attempt_limit_message#:#您可以参加此测试的总次数:%s。 assessment#:#tst_attempt_started#:#测试已经开始 assessment#:#tst_back_to_pass_details#:#Back to Pass Details###26 09 2014 new variable assessment#:#tst_back_to_question_list#:#Back to Question List###26 09 2014 new variable @@ -1451,7 +1422,7 @@ assessment#:#tst_derive_new_pools#:#Derive New Question Pools###25 10 2016 new v assessment#:#tst_dont_show_msg_again_in_current_session#:#Don't show this message again in my current session.###10 11 2018 new variable assessment#:#tst_edit_competence_assign#:#Edit Assignment Properties###30 08 2015 new variable assessment#:#tst_edit_scoring#:#编辑评分 -assessment#:#tst_enable_questionlist#:#Show 'List of Questions’###26 08 2024 new variable +assessment#:#tst_enable_questionlist#:#显示“问题列表” assessment#:#tst_enable_questionlist_description#:#Participants can switch on a list of the test questions on the left of the actual question.###26 08 2024 new variable assessment#:#tst_ending_time#:#结束时间 assessment#:#tst_ending_time_before_starting_time#:#Please enter a date for the end of the test that is after the start date.###26 08 2024 new variable @@ -1476,13 +1447,13 @@ assessment#:#tst_exam_conditions_not_checked_message#:#You need to accept the ex assessment#:#tst_exam_ending_time_message#:#The test cannot be started after %s.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions#:#Please confirm the conditions to start the test.###26 08 2024 new variable assessment#:#tst_exam_modal_message_conditions_and_password#:#Please confirm the conditions and enter the password to start the test.###26 08 2024 new variable -assessment#:#tst_exam_modal_message_password#:#Please enter the password to start the test.###26 08 2024 new variable +assessment#:#tst_exam_modal_message_password#:#请输入密码开始测试。 assessment#:#tst_exam_not_assigned_participant_disclaimer#:#You cannot start this test, as you are not an assigned participant.###26 08 2024 new variable -assessment#:#tst_exam_password#:#Test Password###26 08 2024 new variable +assessment#:#tst_exam_password#:#测试密码 assessment#:#tst_exam_password_invalid_message#:#The given password is not valid!###26 08 2024 new variable -assessment#:#tst_exam_password_label#:#Password###26 08 2024 new variable +assessment#:#tst_exam_password_label#:#密码 assessment#:#tst_exam_required_fields_not_filled_message#:#You need to fill out all required fields!###26 08 2024 new variable -assessment#:#tst_exam_start#:#Start Test###26 08 2024 new variable +assessment#:#tst_exam_start#:#开始测试 assessment#:#tst_exam_use_previous_answers#:#Previous Answers###26 08 2024 new variable assessment#:#tst_exam_use_previous_answers_label#:#If enabled answers from previous tests will be prefilled.###26 08 2024 new variable assessment#:#tst_extratime_added#:#The working time of the participant has been increased by %s minutes.###24 10 2013 new variable @@ -1503,13 +1474,13 @@ assessment#:#tst_final_information#:#Finishing the Test: Information Before Subm assessment#:#tst_finish_confirm_button#:#是的,我想完成这个测试 assessment#:#tst_finish_confirm_cancel_button#:#不,返回之前的答案 assessment#:#tst_finish_confirmation_question#:#您将要完成这次测试并且达到了测试所允许的最大次数。您将不能再次进入这次测试去修改您的答案。您真的想完成这次测试吗? -assessment#:#tst_finish_confirmation_question_no_attempts_left#:#You are going to finish this test and reach the maximum number of allowed test attempts. You won’t be able to enter this test again to change your answers. Do you really want to finish the test?###26 08 2024 new variable +assessment#:#tst_finish_confirmation_question_no_attempts_left#:#你即将完成本次测试,并达到允许的最大测试次数。你将无法再次进入测试来更改答案。你真的想完成测试吗? assessment#:#tst_finished#:#已完成 assessment#:#tst_form_dynamic_question_set_config#:#Continues Question Selection###24 10 2013 new variable assessment#:#tst_gap_analysis#:#Gap Analysis###26 09 2014 new variable assessment#:#tst_general_properties#:#常规属性 assessment#:#tst_header_participant#:#Result:###24 10 2013 new variable -assessment#:#tst_header_participant_no_answer#:#Question - not answered###26 08 2024 new variable +assessment#:#tst_header_participant_no_answer#:#问题 - 未回答 assessment#:#tst_header_solution#:#Correct solution:###24 10 2013 new variable assessment#:#tst_hide_info_tab#:#Hide Info Tab###26 08 2024 new variable assessment#:#tst_hide_info_tab_desc#:#Hides the tab ‘Info’ of the test.###26 08 2024 new variable @@ -1590,7 +1561,7 @@ assessment#:#tst_invited_selected_users#:#所选择的用户已经做为既定 assessment#:#tst_launcher_button_label_passes_limit_reached#:#You have reached the limit of possible test passes###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions#:#You will be asked for your approval of the exam conditions when you start the test.###26 08 2024 new variable assessment#:#tst_launcher_status_message_conditions_and_password#:#You will be asked for the password and your approval of the exam conditions when you start the test.###26 08 2024 new variable -assessment#:#tst_launcher_status_message_password#:#You will be asked for the password when you start the test.###26 08 2024 new variable +assessment#:#tst_launcher_status_message_password#:#开始测试时,系统会要求您输入密码。 assessment#:#tst_level#:#Competence Level###26 09 2014 new variable assessment#:#tst_limit_nr_of_tries#:#Maximum Number of Test Passes###07 11 2014 new variable assessment#:#tst_link_only_unassigned#:#您至少选择了一个已链接到一个题目池的题目。仅未分配题目能添加到一个题目池中。 @@ -1695,7 +1666,7 @@ assessment#:#tst_objective_progress_header#:#Learning Objective Progress###25 10 assessment#:#tst_objectives_progress_header#:#Learning Objectives Progress###25 10 2016 new variable assessment#:#tst_old_style_rnd_quest_set_broken#:#This random test is in a irreparable state, because one or more connected question pools have been deleted. Therefor participants cannot take the test any longer.###30 08 2015 new variable assessment#:#tst_optional_questions_confirmation_non_fixed_test#:#Question related to allready passed learning objectives are optional.

    You want to navigate to a question, that relates to an allready passed learning objective.
    You can choose:

    I you proceed, you can work on these questions. Your answers from previous attempts were not adopted, since new random questions were selected for this attempt. With working on this questions you can also degrade your learning objective result.

    If you decide to not work on these questions, you can go back. In this case these questions won't be considered in the evaluation.###30 08 2015 new variable -assessment#:#tst_out_of_time_message#:#You have reached the maximum allowed processing time of the test!###26 08 2024 new variable +assessment#:#tst_out_of_time_message#:#进行此测试的时间已过。 assessment#:#tst_participant#:#参与者 assessment#:#tst_participant_fullname_pattern#:#%2$s, %1$s###26 09 2014 new variable assessment#:#tst_participant_status#:#参与者状态 @@ -1951,7 +1922,7 @@ assessment#:#tst_text_count_system#:#评分系统 assessment#:#tst_threshold#:#Thresholds###26 09 2014 new variable assessment#:#tst_time_already_spent#:#花在工作上的时间 assessment#:#tst_time_already_spent_left#:#您还剩余 %s 。 -assessment#:#tst_time_limit_message#:#You will have %s minutes to answer all questions.###26 08 2024 new variable +assessment#:#tst_time_limit_message#:#您将有%s分钟分钟来回答所有问题。 assessment#:#tst_title_output#:#测试标题输出 assessment#:#tst_title_output_full#:#显示测试标题和有效分值 assessment#:#tst_title_output_hide_points#:#仅显示测试标题 @@ -3412,7 +3383,7 @@ cmxv#:#cmxv_create_info#:#Select a completed xAPI/cmi5 object to generate a cert cntr#:#cntr_add_new_item#:#加入新条目 cntr#:#cntr_adopt_content#:#适用的内容 cntr#:#cntr_container_only_on_their_own#:#Categories, courses, groups, folders or study programmes can only be copied as single objects. Please select one item only. -cntr#:#cntr_copy_crs_grp#:#My Courses and Groups###30 08 2015 new variable +cntr#:#cntr_copy_crs_grp#:#我的课程和小组 cntr#:#cntr_copy_repo_tree#:#Repository Tree###30 08 2015 new variable cntr#:#cntr_hide_title_and_icon#:#隐藏标题和图标 cntr#:#cntr_manage#:#管理 @@ -4659,7 +4630,7 @@ common#:#mm_communication#:#Communication###07 02 2020 new variable common#:#mm_contacts#:#Contacts###07 02 2020 new variable common#:#mm_dashboard#:#Dashboard###07 02 2020 new variable common#:#mm_enrolments#:#Enrolments###07 02 2020 new variable -common#:#mm_favorites#:#Favourites###07 02 2020 new variable +common#:#mm_favorites#:#收藏夹 common#:#mm_learning_history#:#Learning History###07 02 2020 new variable common#:#mm_learning_progress#:#Learning Progress###07 02 2020 new variable common#:#mm_mail#:#Mail###07 02 2020 new variable @@ -4670,10 +4641,10 @@ common#:#mm_personal_and_shared_r#:#Personal and Shared Resources###07 02 2020 n common#:#mm_personal_workspace#:#Personal Workspace###07 02 2020 new variable common#:#mm_portfolio#:#Portfolio###07 02 2020 new variable common#:#mm_private_chats#:#Private Chats###29 07 2022 new variable -common#:#mm_repo_tree_view#:#Tree View###07 02 2020 new variable -common#:#mm_repo_tree_view_act#:#Activate Tree###07 02 2020 new variable -common#:#mm_repo_tree_view_deact#:#Deactivate Tree###07 02 2020 new variable -common#:#mm_repository#:#Repository###07 02 2020 new variable +common#:#mm_repo_tree_view#:#树形视图 +common#:#mm_repo_tree_view_act#:#激活树形视图 +common#:#mm_repo_tree_view_deact#:#停用树形视图 +common#:#mm_repository#:#存储库 common#:#mm_skills#:#Competences###07 02 2020 new variable common#:#mm_staff_list#:#Staff List###07 02 2020 new variable common#:#mm_tags#:#Tags###07 02 2020 new variable @@ -4762,7 +4733,7 @@ common#:#msg_no_perm_paste#:#您无权限粘贴下列对象 common#:#msg_no_perm_paste_object_in_folder#:#您没有权限粘贴对象 %s 到文件夹 %s。 common#:#msg_no_perm_perm#:#您无权限编辑权限设置 common#:#msg_no_perm_read#:#您没有权限访问这个项目。 -common#:#msg_no_perm_read_item#:#您没有权限访问条目 '%s'。 +common#:#msg_no_perm_read_item#:#您没有权限访问条目。 common#:#msg_no_perm_read_lm#:#您没有权限读取这个学习模块。 common#:#msg_no_perm_view_roles_of_user#:#You have no permission to view the role assignment of this user###29 10 2025 new variable common#:#msg_no_perm_write#:#您无写权限 @@ -5056,8 +5027,8 @@ common#:#obj_rcat#:#ECS 类目 common#:#obj_rcrs#:#课程链接 common#:#obj_recf#:#恢复对象 common#:#obj_recf_desc#:#包含来自系统检测的已恢复对象。 -common#:#obj_rep#:#Repository###07 02 2020 new variable -common#:#obj_reps#:#Repository###24 10 2013 new variable +common#:#obj_rep#:#存储库 +common#:#obj_reps#:#存储库 common#:#obj_reps_desc#:#General settings for the Repository###24 10 2013 new variable common#:#obj_rfil#:#ECS 文件 common#:#obj_rglo#:#ECS 词汇表 @@ -5769,7 +5740,7 @@ common#:#toggle_off#:#OFF### Don't translate this label to prevent rendering pro common#:#toggle_on#:#ON### Don't translate this label to prevent rendering problems of the related Toggle Button! common#:#tomorrow#:#明天 common#:#toolbar_more_actions#:#More Actions###26 08 2024 new variable -common#:#tools#:#Tools###29 07 2022 new variable +common#:#tools#:#工具 common#:#top_of_page#:#页面顶部 common#:#tos_accept_usr_agreement#:#Accept Terms of Service?###26 08 2024 new variable common#:#tos_accept_usr_agreement_intro#:#There are new terms of service. You need to accept them before proceeding with the use of ILIAS. Read the following document carefully and give your consent or dissent at the bottom of the page.###26 08 2024 new variable @@ -7707,7 +7678,7 @@ crs#:#crs_members_map#:#课程成员地图 crs#:#crs_members_print_title#:#课程成员 crs#:#crs_min_one_admin#:#必须至少有一个管理员分配给本课程 crs#:#crs_msg_no_self_registration_period_if_self_enrolment_disabled#:#The limited registration period can not be defined if the "No Self-enrolment" setting is active.###26 08 2024 new variable -crs#:#crs_my_courses_groups_enabled#:#My Courses and Groups###26 08 2024 new variable +crs#:#crs_my_courses_groups_enabled#:#我的课程和小组 crs#:#crs_my_courses_groups_enabled_info#:#If activated, the section 'My Courses and Groups' is visible.###26 08 2024 new variable crs#:#crs_new_status#:#您的新状态 crs#:#crs_new_subscription#:#新课程订阅 @@ -8089,15 +8060,15 @@ dash#:#dash_dashboard#:#Dashboard###07 02 2020 new variable dash#:#dash_default_presentation#:#Default Presentation###07 02 2020 new variable dash#:#dash_default_sortation#:#Default Sortation###07 02 2020 new variable dash#:#dash_enable_cal#:#Calendar###07 02 2020 new variable -dash#:#dash_enable_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_enable_favourites#:#收藏夹 dash#:#dash_enable_learning_sequences#:#Learning Sequences###26 08 2024 new variable dash#:#dash_enable_mail#:#Mail###07 02 2020 new variable -dash#:#dash_enable_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_enable_memberships#:#我的课程和小组 dash#:#dash_enable_news#:#News###07 02 2020 new variable dash#:#dash_enable_recommended_content#:#Recommended Content###26 08 2024 new variable dash#:#dash_enable_study_programmes#:#Study Programmes###26 08 2024 new variable dash#:#dash_enable_task#:#Tasks###07 02 2020 new variable -dash#:#dash_favourites#:#Favourites###07 02 2020 new variable +dash#:#dash_favourites#:#收藏夹 dash#:#dash_info_sure_remove_from_favs#:#Are you sure you want to remove the following objects from your Favourites?###07 02 2020 new variable dash#:#dash_item_removed#:#Recommendation has been removed from the list.###07 02 2020 new variable dash#:#dash_learning_sequences#:#My Learning Sequences###26 08 2024 new variable @@ -8109,7 +8080,7 @@ dash#:#dash_manual_new_item_pos_bot#:#Bottom###29 10 2025 new variable dash#:#dash_manual_new_item_pos_top#:#Top###29 10 2025 new variable dash#:#dash_manual_sorting_title#:#Manual Sorting of Favorites###29 10 2025 new variable dash#:#dash_member_main_alt#:#Courses and groups can also be configured as a separate main menu entry.###07 02 2020 new variable -dash#:#dash_memberships#:#My Courses and Groups###07 02 2020 new variable +dash#:#dash_memberships#:#我的课程和小组 dash#:#dash_page_edit_info#:#The content of this page is displayed to all users on their dashboard. The contents of the various blocks of the dashboard are presented below.###28 10 2024 new variable dash#:#dash_presentation#:#Presentation###07 02 2020 new variable dash#:#dash_recommended_content#:#Recommended Content###26 08 2024 new variable @@ -13970,6 +13941,35 @@ qpl#:#qpl_page_type_qfbg#:#General Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qfbs#:#Special Feedback###29 07 2022 new variable qpl#:#qpl_page_type_qht#:#Hint###29 07 2022 new variable qpl#:#qpl_page_type_qpl#:#Question Page###29 07 2022 new variable +qsts#:#answer_options#:#Answer Options ###23 12 2015 new variable +qsts#:#cloze_text#:#填充测验文本 +qsts#:#cloze_textgapcase_insensitive#:#不区分大小写 +qsts#:#cloze_textgapcase_sensitive#:#区分大小定 +qsts#:#cloze_textgaplevenshtein_of#:#Levenshtein distance of %s +qsts#:#confirm_delete_questions#:#您确认删除下面的题目?如果您删除已经锁定的题目,所有包含被锁定题目的测试结果也将被删除。 +qsts#:#create_question#:#Create Question###24 10 2013 new variable +qsts#:#gap#:#间隔 +qsts#:#gaps#:#Gaps###29 10 2025 new variable +qsts#:#insert_gap#:#Insert Gap###24 10 2013 new variable +qsts#:#min_auto_complete#:#Autocomplete###25 10 2016 new variable +qsts#:#msg_no_questions_selected#:#No questions were selected.###26 08 2024 new variable +qsts#:#out_of_range#:#Out of range###27 01 2015 new variable +qsts#:#qst_lifecycle#:#Lifecycle###07 02 2020 new variable +qsts#:#qst_lifecycle_draft#:#Draft###07 02 2020 new variable +qsts#:#qst_lifecycle_filter_all#:#All Lifecycles###07 02 2020 new variable +qsts#:#qst_lifecycle_final#:#Final###07 02 2020 new variable +qsts#:#qst_lifecycle_outdated#:#Outdated###07 02 2020 new variable +qsts#:#qst_lifecycle_rejected#:#Rejected###07 02 2020 new variable +qsts#:#qst_lifecycle_review#:#To be Reviewed###07 02 2020 new variable +qsts#:#qst_lifecycle_sharable#:#Sharable###07 02 2020 new variable +qsts#:#questionlist#:#问题清单 +qsts#:#questions#:#题目。 +qsts#:#range_lower_limit#:#下限 +qsts#:#range_upper_limit#:#上限 +qsts#:#reset_preview#:#Reset Preview###26 09 2014 new variable +qsts#:#select_gap#:#选择间隔 +qsts#:#shuffle_answers#:#简答题 +qsts#:#suggested_learning_content#:#添加建议解决方案 rating#:#rat_not_rated_yet#:#还没有评级 rating#:#rat_nr_ratings#:#%s 评级 rating#:#rat_one_rating#:#One 评级 @@ -15079,11 +15079,11 @@ rep#:#rep_export_limitation_info#:#Limits the number of objects for container ex rep#:#rep_export_limitation_limited#:#Limit Export###07 02 2020 new variable rep#:#rep_export_limitation_unlimited#:#Unlimited Export###26 08 2024 new variable rep#:#rep_failure_trashed_trash#:#You selected objects that cannot be restored to their original location, because their parent objects were deleted. Please uncheck the respective object in the table or select the Restore to New Location instead.###07 02 2020 new variable -rep#:#rep_fav_intro1#:#Sie haben aktuell noch keine Favoriten ausgewählt. Um dies zu tun, müssen Sie zwei Schritte machen:###07 02 2020 new variable -rep#:#rep_fav_intro2#:#Klicken Sie auf '%s' und wählen Sie aus dem verfügbaren Angebot ein Lernobjekt aus, z. B. ein Lernmodul oder ein Forum.###07 02 2020 new variable -rep#:#rep_fav_intro3#:#Wenn Sie etwas gefunden haben, das Sie interessiert, können Sie es ganz einfach zu Ihren Favoriten hinzufügen. Wählen Sie beim gewünschten Objekt im Aktionen-Menü die Option "Zu Favoriten hinzufügen".###07 02 2020 new variable +rep#:#rep_fav_intro1#:#您尚未选择任何收藏夹。要选择收藏夹,您需要完成以下两个步骤: +rep#:#rep_fav_intro2#:#点击“%s”,然后从可用选项中选择一个学习对象,例如学习模块或论坛。 +rep#:#rep_fav_intro3#:#如果您发现感兴趣的内容,可以轻松将其添加到收藏夹。在“操作”菜单中选择“添加到收藏夹”即可找到所需项目。 rep#:#rep_favourites#:#Favourites###29 07 2022 new variable -rep#:#rep_favourites_info#:#Users can mark single repository items as favourites. Favourites lists can be activated and configured in the dashboard and menu settings.###29 07 2022 new variable +rep#:#rep_favourites_info#:#用户可以将单个存储库项目标记为收藏。可以为仪表板和主菜单激活“收藏”列表。 rep#:#rep_input_not_empty#:#This field must not be empty, please provide a value.###29 10 2025 new variable rep#:#rep_intro#:#欢迎来到知识库! rep#:#rep_intro1#:#在这个区域,您能为所有用户创建学习和工作资源。所有资源都组织在类目中。类目能反映您的组织结构(例如,部门)、一个学科的层次结构,或一个学校的类别。 @@ -16619,7 +16619,6 @@ survey#:#questionblock#:#题目块 survey#:#questionblock_inserted#:#问题块已插入 survey#:#questionblocks#:#题目块 survey#:#questionblocks_inserted#:#题目块已插入 -survey#:#questions#:#题目。 survey#:#questions_inserted#:#题目已插入! survey#:#questions_removed#:#题目和/或题目块已删除! survey#:#questiontype#:#题目类型 @@ -16920,6 +16919,7 @@ survey#:#svy_please_select_unused_codes#:#Please select at least one unused code survey#:#svy_print_hide_labels#:#Hide labels###31 08 2017 new variable survey#:#svy_print_show_labels#:#Show labels###31 08 2017 new variable survey#:#svy_privacy_info#:#Privacy###29 07 2022 new variable +survey#:#svy_questions#:#题目。 survey#:#svy_rater#:#Rater###29 07 2022 new variable survey#:#svy_rater_see_app_info#:#The names of appraisees will be presented to raters to enable them evaluating the questions.###29 07 2022 new variable survey#:#svy_reminder_mail_template#:#Mail Template###25 10 2016 new variable diff --git a/scripts/PHP-CS-Fixer/code-format.php_cs b/scripts/PHP-CS-Fixer/code-format.php_cs index af1d341375cf..277457a725ba 100755 --- a/scripts/PHP-CS-Fixer/code-format.php_cs +++ b/scripts/PHP-CS-Fixer/code-format.php_cs @@ -2,7 +2,7 @@ $finder = PhpCsFixer\Finder::create() ->exclude(array( - __DIR__ . '/../../components/ILIAS/setup_/sql', + __DIR__ . '/../../components/ILIAS/Database/sql', __DIR__ . '/example' )) ->in(array( diff --git a/templates/default/030-tools/_index.scss b/templates/default/030-tools/_index.scss new file mode 100644 index 000000000000..b70d3f680d80 --- /dev/null +++ b/templates/default/030-tools/_index.scss @@ -0,0 +1,3 @@ +// Write the reason down, why these tools have to generate CSS utility classes +// Prefer using mixins and @extend instead whenever possible +@use "tool_text-more-less-toggle"; // many adjacent selectors; avoiding construct of 4+ mixins or 4+ parameters diff --git a/templates/default/030-tools/_tool_focus-outline.scss b/templates/default/030-tools/_tool_focus-outline.scss index 70fa7fea0e77..7a54799b6c56 100755 --- a/templates/default/030-tools/_tool_focus-outline.scss +++ b/templates/default/030-tools/_tool_focus-outline.scss @@ -6,14 +6,10 @@ $il-focus-outline-outer-width: 2px; // KEYBOARD FOCUS DEFAULT // This is the mixin you should be using if possible -@mixin il-focus($il-focus-outline-inner-width: $il-focus-outline-inner-width, $il-focus-outline-outer-width: $il-focus-outline-outer-width){ - $il-focus-outline-inner: $il-focus-outline-inner-width solid $il-focus-color; - $il-focus-outline-outer: $il-focus-outline-outer-width solid $il-focus-protection-color; - &:focus { - outline: none; - outline-offset: 0px; - } - &:focus-visible { +@mixin il-focus($il-focus-outline-inner-width: $il-focus-outline-inner-width, $il-focus-outline-outer-width: $il-focus-outline-outer-width, $apply-to-child: "") { + &:focus #{$apply-to-child}, &:focus-visible #{$apply-to-child} { + $il-focus-outline-inner: $il-focus-outline-inner-width solid $il-focus-color; + $il-focus-outline-outer: $il-focus-outline-outer-width solid $il-focus-protection-color; position: relative; // outermost protection color line outline: $il-focus-outline-outer; @@ -111,3 +107,5 @@ $il-focus-outline-outer-width: 2px; } } } + + diff --git a/templates/default/030-tools/_tool_text-more-less-toggle.scss b/templates/default/030-tools/_tool_text-more-less-toggle.scss new file mode 100644 index 000000000000..7ce3f6b470a7 --- /dev/null +++ b/templates/default/030-tools/_tool_text-more-less-toggle.scss @@ -0,0 +1,45 @@ +@use "../010-settings" as s; +@use "../030-tools/tool_multi-line-cap" as t-cap; +@use "../030-tools/tool_focus-outline" as t-focus; +@use "../030-tools/tool_screen-reader-only" as t-sr; +@use "../050-layout/basics" as l; +@use "../050-layout/layout_breakpoints" as l-brk; + +.t-text-more-less { + &__toggle { + &:checked + .t-text-more-less__label { + .t-text-more-less__label__more { + display: none; + } + } + &:not(:checked) + .t-text-more-less__label { + .t-text-more-less__label__less { + display: none; + } + } + } + &__label { + color: s.$il-link-color; + text-decoration: s.$il-link-decoration; + &:hover { + color: s.$il-link-hover-color; + text-decoration: s.$il-link-hover-decoration; + } + } + &:has(.t-text-more-less__toggle:not(:checked)) { + .t-text-more-less__text-body { + @include l-brk.on-screen-size(medium) { + @include t-cap.il-multi-line-cap-mixin(1); + } + @include l-brk.on-screen-size(small) { + @include t-cap.il-multi-line-cap-mixin(2); + } + } + } +} + +input[type="checkbox"].t-text-more-less__toggle { + @include t-sr.sr-only(); + @include t-focus.clear-focus-for-override(); + @include t-focus.il-focus($apply-to-child: "~ label"); +} diff --git a/templates/default/050-layout/_layout_element-bar.scss b/templates/default/050-layout/_layout_element-bar.scss index 0438deba55b1..d5286bb7797d 100755 --- a/templates/default/050-layout/_layout_element-bar.scss +++ b/templates/default/050-layout/_layout_element-bar.scss @@ -22,8 +22,15 @@ $l-bar__element__margin-bottom: $il-margin-xlarge-vertical; // this margin separ flex-direction: row; flex-wrap: wrap; align-items: center; + // avoid nested elements breaking off + .l-bar__group, + .l-bar__element { + flex-wrap: nowrap; + } } +// elements inside have a margin bottom to keep lines apart +// compensate this line gap so elementbar does not have a margin-bottom below .l-bar__space-keeper:not(:empty) { margin-bottom: calc(-1 * var(--l-bar__element__margin-bottom)); // counteract element margin-bottom, so outer edge doesn't have a visible margin-bottom &.l-bar__space-keeper--space-between { @@ -31,19 +38,22 @@ $l-bar__element__margin-bottom: $il-margin-xlarge-vertical; // this margin separ } } +// bottom margin to separate lines .l-bar__space-keeper > .l-bar__element, .l-bar__group > .l-bar__element { margin-bottom: var(--l-bar__element__margin-bottom); - &:last-of-type { - margin-right: 0; - } } +// gap between two elements .l-bar__group > .l-bar__element, .l-bar__space-keeper > .l-bar__element { margin-right: var(--l-bar__gap--elements); + &:last-child { + margin-right: 0; + } } +// gap between two groups .l-bar__space-keeper > .l-bar__group, .l-bar__group > .l-bar__group { margin-right: var(--l-bar__gap--groups); diff --git a/templates/default/050-layout/_layout_grid-auto-columns.scss b/templates/default/050-layout/_layout_grid-auto-columns.scss new file mode 100644 index 000000000000..bac5e66564b2 --- /dev/null +++ b/templates/default/050-layout/_layout_grid-auto-columns.scss @@ -0,0 +1,15 @@ +@use "sass:math"; +@use "sass:list"; +@use "../050-layout/basics" as l; + +$allowed-units: ("px", "ch", "rem", "em"); + +@mixin make-grid-with-auto-columns($column-min-width, $gap: l.$il-margin-xxxlarge-vertical) { + $unit: math.unit($column-min-width); + @if (list.index($allowed-units, $unit) == null) { + @error "Enter a width with one of these units: #{$allowed-units}"; + } + display: grid; + grid-template-columns: repeat(auto-fill, minmax($column-min-width, 1fr)); + gap: $gap; +} diff --git a/templates/default/060-elements/_elements_media.scss b/templates/default/060-elements/_elements_media.scss index cd46057a5285..60c61df57bb4 100755 --- a/templates/default/060-elements/_elements_media.scss +++ b/templates/default/060-elements/_elements_media.scss @@ -1,4 +1,5 @@ @use "../010-settings/" as *; +@use "../030-tools/tool_focus-outline" as focus; img { vertical-align: middle; @@ -6,4 +7,10 @@ img { /* height: auto; messes e.g. survey progress bar */ max-width: 100%; } -} \ No newline at end of file +} + +a:has(img) { + display: inline-block; + @include focus.clear-focus-for-override(); + @include focus.il-focus(); +} diff --git a/templates/default/070-components/UI-framework/Entity/_ui-component_entity.scss b/templates/default/070-components/UI-framework/Entity/_ui-component_entity.scss index ffe8ef22fe74..f089acabb44f 100755 --- a/templates/default/070-components/UI-framework/Entity/_ui-component_entity.scss +++ b/templates/default/070-components/UI-framework/Entity/_ui-component_entity.scss @@ -1,93 +1,125 @@ @use "sass:math"; @use "../../../010-settings/" as s; @use "../../../050-layout/basics/" as l; +@use "../../../050-layout/layout_breakpoints" as l-brk; + +$entity-padding-vertical: l.$il-padding-xlarge-vertical; +$entity-spacer-padding-vertical: l.$il-padding-xlarge-vertical * 2; +$entity-padding-horizontal: l.$il-padding-xlarge-horizontal; // counterstyling in use for padding-less images on mobile +$img-large-max-width: 360px; +$max-rows: 9; + +@mixin entity-limited-space-design() { + &__container { + display: flex; + flex-direction: column; + > * { + order: 2; + } + } + &__secondary-identifier { + order: 1; + &.--image { + img { + // break out of padding to reach from edge to edge + width: calc(100% + $entity-padding-horizontal * 2); + max-width: unset; + margin-left: -($entity-padding-horizontal); + margin-top: -($entity-padding-vertical); + } + } + } + &__reactionbar { + flex-grow: 1; + } +} .c-entity { - &.__container { + + &__container { display: grid; - grid-template-areas: - "f-blocking f-blocking f-blocking f-blocking actions" - "second-id f-prop f-prop f-prop actions" - "second-id prim-id prim-id prim-id actions" - "second-id status status status status" - "second-id f-details f-details f-details f-details" - "second-id availab availab availab availab" - "second-id details details details details" - "second-id reaction reaction f-reaction f-reaction"; - grid-template-columns: min-content auto auto min-content min-content; + grid-template-columns: max-content auto; + grid-template-rows: repeat($max-rows, minmax(min-content, auto)); + border: s.$il-main-border; background-color: s.$il-main-bg; - padding: math.div(l.$il-margin-xlarge-vertical, 2) math.div(l.$il-margin-xlarge-horizontal, 2); - > *:not(:empty) { - padding: math.div(l.$il-margin-xlarge-vertical, 2) math.div(l.$il-margin-xlarge-horizontal, 2); + padding: math.div($entity-padding-vertical, 2) math.div($entity-padding-horizontal, 2); + > * { + // half paddings edge to edge equal a full padding + padding: math.div($entity-padding-vertical, 2) math.div($entity-padding-horizontal, 2); + } + @include l-brk.on-screen-size(small) { + display: block; } } - &.__blocking-conditions { - grid-area: f-blocking; - font-size: s.$il-font-size-xlarge; - } - - &.__actions { - display: flex; - justify-content: end; - grid-area: actions; - .dropdown { - height: max-content; + &__featured-headerbar { + column-span: 2; + > .l-bar__space-keeper { + flex-wrap: nowrap; + .l-bar__group, + .l-bar__element { + align-self: flex-start; + } } } - &.__secondary-identifier { + &__secondary-identifier { + grid-column: 1; + grid-row: 1 / #{$max-rows + 1}; // number high enough so all others can fit on the right &.--string, &.--shy, &.--shylink { width: 10rem; } &.--symbol { - min-width: 3rem; + img { width: auto; } } &.--image { - width: 15rem; + img { max-width: $img-large-max-width; }; } - grid-area: second-id; } - &.__primary-identifier { - grid-area: prim-id; + &__primary-identifier { font-weight: s.$il-font-weight-bold; font-size: s.$il-font-size-xxlarge; } - &.__featured { - grid-area: f-prop; - font-size: s.$il-font-size-xlarge; + &__featured { + font-size: s.$il-font-size-large; } - &.__personal-status { - grid-area: status; + &__workflow-actions { + padding-top: $entity-spacer-padding-vertical; } - &.__main-details { - grid-area: f-details; + &__blocking-conditions { + padding-bottom: $entity-spacer-padding-vertical; + font-size: s.$il-font-size-large; } - - &.__availability { - grid-area: availab; + &__main-details { + padding-top: $entity-spacer-padding-vertical; + } + &__details { + font-size: s.$il-font-size-small; } - &.__details { - grid-area: details; + &__reactions { + padding-top: $entity-spacer-padding-vertical; } - &.__reactions { - // display: flex; - // flex-direction: row; - grid-area: reaction; + &__reactionbar { + align-self: stretch; + align-content: flex-end; + grid-column: 2; + grid-row: $max-rows; // always in last row } - &.__featured-reactions { - display: flex; - justify-content: end; - grid-area: f-reaction; + &__featured-reactions { + padding-top: $entity-spacer-padding-vertical; + text-align: end; min-width: max-content; } + @include l-brk.on-screen-size(small) { + @include entity-limited-space-design(); + } } diff --git a/templates/default/070-components/UI-framework/Listing/_ui-component_entitylisting.scss b/templates/default/070-components/UI-framework/Listing/_ui-component_entitylisting.scss index d04b2f0c9bf9..549919a3a6b7 100755 --- a/templates/default/070-components/UI-framework/Listing/_ui-component_entitylisting.scss +++ b/templates/default/070-components/UI-framework/Listing/_ui-component_entitylisting.scss @@ -1,4 +1,33 @@ -.c-listing-entity { +@use "../../../050-layout/basics" as l; +@use "../../../050-layout/layout_grid-auto-columns" as l-auto-grid; +@use "../../../030-tools/tool_multi-line-cap" as t-linecap; + +// so we can force entity small space design on large screens +@use "../../../070-components/UI-framework/Entity/ui-component_entity" as entity; + +$listing-column-min-width: 650px; +$grid-column-min-width: 400px; + +.c-listing-entity, +.c-listing-entity-grid { list-style: none; padding-left: 0; -} \ No newline at end of file +} + +.c-listing-entity { + @include l-auto-grid.make-grid-with-auto-columns($listing-column-min-width); +} + +.c-listing-entity-grid { + @include l-auto-grid.make-grid-with-auto-columns($grid-column-min-width); + .c-entity { + @include entity.entity-limited-space-design(); + &__container { + height: 100%; + .c-listing-property__propertyvalue:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + height: 2lh; + } + } + } +} + diff --git a/templates/default/070-components/UI-framework/Listing/_ui-component_inline.scss b/templates/default/070-components/UI-framework/Listing/_ui-component_inline.scss new file mode 100644 index 000000000000..9edc51348296 --- /dev/null +++ b/templates/default/070-components/UI-framework/Listing/_ui-component_inline.scss @@ -0,0 +1,19 @@ +@use "../../../010-settings" as s; +@use "../../../030-tools/tool_multi-line-cap" as t-cap; +@use "../../../030-tools/tool_focus-outline" as t-focus; +@use "../../../050-layout/basics/" as l; +@use "../../../050-layout/layout_breakpoints" as l-brk; + +.c-listing-inline { + padding: 0; + margin: 0; + list-style: none; + > .c-listing-inline__item { + &::after { + content: ", "; + } + &:last-child::after { + content: ""; + } + } +} diff --git a/templates/default/070-components/UI-framework/Listing/_ui-component_properties.scss b/templates/default/070-components/UI-framework/Listing/_ui-component_properties.scss index 6ab6876c386d..e499c128fbf8 100755 --- a/templates/default/070-components/UI-framework/Listing/_ui-component_properties.scss +++ b/templates/default/070-components/UI-framework/Listing/_ui-component_properties.scss @@ -1,9 +1,13 @@ +@use "../../../010-settings" as s; +@use "../../../030-tools/tool_multi-line-cap" as t-cap; +@use "../../../030-tools/tool_focus-outline" as t-focus; @use "../../../050-layout/basics/" as l; +@use "../../../050-layout/layout_breakpoints" as l-brk; -.c-listing-property__propertylabel:after { - content: ":" +.c-listing-property__propertylabel:not(:has(.glyphicon)):after { + content: ":"; } .c-listing-property + .c-listing-property { margin-top: l.$il-margin-large-vertical; -} \ No newline at end of file +} diff --git a/templates/default/070-components/UI-framework/MainControls/_ui-component_footer.scss b/templates/default/070-components/UI-framework/MainControls/_ui-component_footer.scss index 86fe62addf9d..8a236e5e7b0e 100755 --- a/templates/default/070-components/UI-framework/MainControls/_ui-component_footer.scss +++ b/templates/default/070-components/UI-framework/MainControls/_ui-component_footer.scss @@ -50,14 +50,15 @@ @include brk.on-screen-size(large) { font-size: $il-font-size-small; - &-grid { + &-grid--sm { grid-template-columns: repeat(4, 1fr); } } @include brk.on-screen-size(small) { font-size: $il-font-size-base; - &-grid { + &-grid--sm, + &-grid--md { grid-template-columns: repeat(1, 1fr); } & ul li { diff --git a/templates/default/070-components/UI-framework/Symbol/_ui-component_glyph.scss b/templates/default/070-components/UI-framework/Symbol/_ui-component_glyph.scss index 241b2fe03d78..43acfa46c87b 100644 --- a/templates/default/070-components/UI-framework/Symbol/_ui-component_glyph.scss +++ b/templates/default/070-components/UI-framework/Symbol/_ui-component_glyph.scss @@ -154,7 +154,6 @@ $icon-font-svg-id: "glyphicons_halflingsregular" !default; .glyphicon-eye-close { &:before { content: "\e106"; } } .glyphicon-warning-sign { &:before { content: "\e107"; } } .glyphicon-plane { &:before { content: "\e108"; } } - .glyphicon-calendar { &:before { content: "\e109"; } } .glyphicon-random { &:before { content: "\e110"; } } .glyphicon-comment { &:before { content: "\e111"; } } .glyphicon-magnet { &:before { content: "\e112"; } } @@ -548,3 +547,23 @@ $icon-font-svg-id: "glyphicons_halflingsregular" !default; font-family: il-icons; content: "\e914"; } +.glyphicon-presenter:before { + font-family: il-icons; + content: "\e90e"; +} +.glyphicon-owner:before { + font-family: il-icons; + content: "\e90f"; +} +.glyphicon-date:before { + font-family: il-icons; + content: "\e619"; +} +.glyphicon-calendar:before { + font-family: il-icons; + content: "\e075"; +} +.glyphicon-location:before { + font-family: il-icons; + content: "\e096"; +} diff --git a/templates/default/070-components/UI-framework/Table/_ui-component_table.scss b/templates/default/070-components/UI-framework/Table/_ui-component_table.scss index 7ffbab3c76d0..40fb23744475 100755 --- a/templates/default/070-components/UI-framework/Table/_ui-component_table.scss +++ b/templates/default/070-components/UI-framework/Table/_ui-component_table.scss @@ -308,7 +308,7 @@ th.c-table-data__cell:after { // Text .c-table-data__cell--link, -.c-table-data__cell--linklisting, +.c-table-data__cell--listing, .c-table-data__cell--text { .c-table-data__header__resize-wrapper { min-width: 140px; diff --git a/templates/default/070-components/_index.scss b/templates/default/070-components/_index.scss index fa625b1ab3aa..088c76f86a32 100755 --- a/templates/default/070-components/_index.scss +++ b/templates/default/070-components/_index.scss @@ -21,6 +21,7 @@ @use "./UI-framework/Dropdown/_ui-component_dropdown.scss"; @use "./UI-framework/Dropzone/_ui-component_dropzone.scss"; @use "./UI-framework/Entity/ui-component_entity"; +@use "./UI-framework/Listing/ui-component_inline"; @use "./UI-framework/Item/_ui-component_item.scss"; @use "./UI-framework/Launcher/ui-component_launcher"; @use "./UI-framework/Layout/_ui-component_layout.scss"; @@ -88,6 +89,7 @@ @use "./legacy/Modules/_component_orgunit.scss"; @use "./legacy/Modules/_component_poll.scss"; @use "./legacy/Modules/_component_portfolio.scss"; +@use "./legacy/Modules/_component_questions.scss"; @use "./legacy/Modules/_component_scormaicc.scss"; @use "./legacy/Modules/_component_survey.scss"; @use "./legacy/Modules/_component_test.scss"; diff --git a/templates/default/070-components/legacy/Modules/_component_questions.scss b/templates/default/070-components/legacy/Modules/_component_questions.scss new file mode 100755 index 000000000000..06791bee6405 --- /dev/null +++ b/templates/default/070-components/legacy/Modules/_component_questions.scss @@ -0,0 +1,19 @@ +@use "../../../010-settings/" as *; +@use "../../../050-layout/basics" as *; + +$il-questions-solution-value-background: $il-highlight-bg; +$il-questions-solution-value-padding: $il-padding-base-vertical; +$il-questions-async-answerform-padding: $il-padding-large-vertical; + +.c-questions__solution-value { + background: $il-questions-solution-value-background; + padding: $il-questions-solution-value-padding; +} + +.c-questions__async-answerform { + padding-bottom: $il-questions-async-answerform-padding; +} + +.c-questions_async-answerform-feedback { + padding-top: $il-questions-async-answerform-padding; +} diff --git a/templates/default/070-components/legacy/Modules/_component_test.scss b/templates/default/070-components/legacy/Modules/_component_test.scss index ddb96549b42e..8ca27135fdda 100755 --- a/templates/default/070-components/legacy/Modules/_component_test.scss +++ b/templates/default/070-components/legacy/Modules/_component_test.scss @@ -16,6 +16,8 @@ $il-test-margin-large-horizontal: $il-padding-large-horizontal; $il-test-working-time-font-size: $il-font-size-large; $il-test-working-time-font-weight: $il-font-weight-bold; +$il-test-solution-value-background: $il-highlight-bg; + // general layout #tst_output { display: flex; @@ -172,9 +174,15 @@ $cons-scoring-bottom-fade-height: $il-padding-xxxlarge-vertical * 2; display: none; } - // fix for ordering question - .ilc_qanswer_Answer.solutionbox { - width: auto; + .ilc_qanswer_Answer { + // fix for ordering question + .solutionbox { + width: auto; + } + + .ilc_answers.answers.ilAssClozeTest div input[type=text] { + width: 100%; + } } } @@ -390,4 +398,4 @@ $cons-scoring-bottom-fade-height: $il-padding-xxxlarge-vertical * 2; } } } -} +} \ No newline at end of file diff --git a/templates/default/070-components/legacy/Modules/_component_test_legacy.scss b/templates/default/070-components/legacy/Modules/_component_test_legacy.scss index fc89928f1838..5d0f70e7bd21 100755 --- a/templates/default/070-components/legacy/Modules/_component_test_legacy.scss +++ b/templates/default/070-components/legacy/Modules/_component_test_legacy.scss @@ -538,8 +538,8 @@ td.ilc_Page { } .ilTestMarkQuestionIcon { - width: 12px; - height: 12px; + width: 28px; + height: 28px; } .ilTestAnswerStatusIcon { diff --git a/templates/default/delos.css b/templates/default/delos.css index 0b838ddd9024..b17ebc537a42 100644 --- a/templates/default/delos.css +++ b/templates/default/delos.css @@ -715,6 +715,165 @@ table.mceToolbar tbody, table.mceToolbar tr, table.mceToolbar td { min-height: 23px; } +/* + These classes are used to limit the number of rows when displaying larger chunks of text. + The mixin receives $height-in-rows as an integer. The classes il-multi-line-cap-2,3,5,10 + can be used to limit the number of rows for text to 2,3,5 or 10 lines in any template, + e.g. the Standard Listing Panels limit the property values to 3 lines using il-multi-line-cap-3 + + Technical discussion can be found in https://mantis.ilias.de/view.php?id=21583 + The background/gradient fallback can be removed as soon as all browsers support line-clamp. + */ +.t-text-more-less__toggle:checked + .t-text-more-less__label .t-text-more-less__label__more { + display: none; +} +.t-text-more-less__toggle:not(:checked) + .t-text-more-less__label .t-text-more-less__label__less { + display: none; +} +.t-text-more-less__label { + color: #4c6586; + text-decoration: none; +} +.t-text-more-less__label:hover { + color: rgb(57.5428571429, 76.4714285714, 101.4571428571); + text-decoration: underline; +} +@media screen and (min-width: 769px) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + position: relative; + max-height: 1.5em; + overflow: hidden; + line-height: 1.5; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + content: ""; + text-align: right; + position: absolute; + bottom: 0; + right: 0; + width: 30%; + height: 1.5em; + background: linear-gradient(to right, rgba(255, 255, 255, 0), rgb(255, 255, 255) 80%); + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + /* edge, chrome, safari go here... */ + } + @supports (-webkit-line-clamp: 2) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + display: none; + } + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + /* may come with next firefox 68, https://caniuse.com/#search=clamp */ + } + @supports (-moz-line-clamp: 2) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + overflow: hidden; + text-overflow: ellipsis; + display: -moz-box; + -moz-line-clamp: 1; + -moz-box-orient: vertical; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + display: none; + } + } +} +@media screen and (max-width: 768px) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + position: relative; + max-height: 3em; + overflow: hidden; + line-height: 1.5; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + content: ""; + text-align: right; + position: absolute; + bottom: 0; + right: 0; + width: 30%; + height: 1.5em; + background: linear-gradient(to right, rgba(255, 255, 255, 0), rgb(255, 255, 255) 80%); + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + /* edge, chrome, safari go here... */ + } + @supports (-webkit-line-clamp: 2) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + display: none; + } + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + /* may come with next firefox 68, https://caniuse.com/#search=clamp */ + } + @supports (-moz-line-clamp: 2) { + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + overflow: hidden; + text-overflow: ellipsis; + display: -moz-box; + -moz-line-clamp: 2; + -moz-box-orient: vertical; + } + .t-text-more-less:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body:after { + display: none; + } + } +} + +input[type=checkbox].t-text-more-less__toggle { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + white-space: nowrap; + clip: rect(0, 0, 0, 0); + border: 0; +} +input[type=checkbox].t-text-more-less__toggle:focus { + border: inherit; + box-shadow: inherit; + outline: none; + outline-offset: 0px; +} +input[type=checkbox].t-text-more-less__toggle:focus-visible { + border: inherit; + box-shadow: inherit; + outline: none; + outline-offset: 0px; +} +input[type=checkbox].t-text-more-less__toggle:focus ~ label, input[type=checkbox].t-text-more-less__toggle:focus-visible ~ label { + position: relative; + outline: 2px solid #FFFFFF; + outline-offset: 5px; +} +input[type=checkbox].t-text-more-less__toggle:focus ~ label::after, input[type=checkbox].t-text-more-less__toggle:focus-visible ~ label::after { + content: " "; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: 2px solid #FFFFFF; + outline: 3px solid #0078D7; +} + /* * Normalize */ @@ -1767,6 +1926,12 @@ th { flex-wrap: wrap; align-items: center; } +.l-bar__space-keeper .l-bar__group, +.l-bar__space-keeper .l-bar__element, +.l-bar__group .l-bar__group, +.l-bar__group .l-bar__element { + flex-wrap: nowrap; +} .l-bar__space-keeper:not(:empty) { margin-bottom: calc(-1 * var(--l-bar__element__margin-bottom)); @@ -1779,15 +1944,15 @@ th { .l-bar__group > .l-bar__element { margin-bottom: var(--l-bar__element__margin-bottom); } -.l-bar__space-keeper > .l-bar__element:last-of-type, -.l-bar__group > .l-bar__element:last-of-type { - margin-right: 0; -} .l-bar__group > .l-bar__element, .l-bar__space-keeper > .l-bar__element { margin-right: var(--l-bar__gap--elements); } +.l-bar__group > .l-bar__element:last-child, +.l-bar__space-keeper > .l-bar__element:last-child { + margin-right: 0; +} .l-bar__space-keeper > .l-bar__group, .l-bar__group > .l-bar__group { @@ -2138,21 +2303,19 @@ fieldset[disabled] input[type=checkbox] { cursor: not-allowed; } -input[type=file]:focus, +input[type=file]:focus, input[type=file]:focus-visible, input[type=radio]:focus, -input[type=checkbox]:focus { - outline: none; - outline-offset: 0px; -} -input[type=file]:focus-visible, input[type=radio]:focus-visible, +input[type=checkbox]:focus, input[type=checkbox]:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -input[type=file]:focus-visible::after, +input[type=file]:focus::after, input[type=file]:focus-visible::after, +input[type=radio]:focus::after, input[type=radio]:focus-visible::after, +input[type=checkbox]:focus::after, input[type=checkbox]:focus-visible::after { content: " "; position: absolute; @@ -2212,6 +2375,37 @@ img { } } +a:has(img) { + display: inline-block; +} +a:has(img):focus { + border: inherit; + box-shadow: inherit; + outline: none; + outline-offset: 0px; +} +a:has(img):focus-visible { + border: inherit; + box-shadow: inherit; + outline: none; + outline-offset: 0px; +} +a:has(img):focus, a:has(img):focus-visible { + position: relative; + outline: 2px solid #FFFFFF; + outline-offset: 5px; +} +a:has(img):focus::after, a:has(img):focus-visible::after { + content: " "; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: 2px solid #FFFFFF; + outline: 3px solid #0078D7; +} + script { display: none !important; } @@ -4900,70 +5094,112 @@ hr.il-divider-with-label { width: 100%; } -.c-entity.__container { +.c-entity__container { display: grid; - grid-template-areas: "f-blocking f-blocking f-blocking f-blocking actions" "second-id f-prop f-prop f-prop actions" "second-id prim-id prim-id prim-id actions" "second-id status status status status" "second-id f-details f-details f-details f-details" "second-id availab availab availab availab" "second-id details details details details" "second-id reaction reaction f-reaction f-reaction"; - grid-template-columns: min-content auto auto min-content min-content; + grid-template-columns: max-content auto; + grid-template-rows: repeat(9, minmax(min-content, auto)); + border: 1px solid #dddddd; background-color: white; padding: 4.5px 7.5px; } -.c-entity.__container > *:not(:empty) { +.c-entity__container > * { padding: 4.5px 7.5px; } -.c-entity.__blocking-conditions { - grid-area: f-blocking; - font-size: 1.115rem; +@media screen and (max-width: 768px) { + .c-entity__container { + display: block; + } } -.c-entity.__actions { - display: flex; - justify-content: end; - grid-area: actions; +.c-entity__featured-headerbar { + column-span: 2; } -.c-entity.__actions .dropdown { - height: max-content; +.c-entity__featured-headerbar > .l-bar__space-keeper { + flex-wrap: nowrap; } -.c-entity.__secondary-identifier.--string, .c-entity.__secondary-identifier.--shy, .c-entity.__secondary-identifier.--shylink { - width: 10rem; +.c-entity__featured-headerbar > .l-bar__space-keeper .l-bar__group, +.c-entity__featured-headerbar > .l-bar__space-keeper .l-bar__element { + align-self: flex-start; } -.c-entity.__secondary-identifier.--symbol { - min-width: 3rem; +.c-entity__secondary-identifier { + grid-column: 1; + grid-row: 1/10; +} +.c-entity__secondary-identifier.--string, .c-entity__secondary-identifier.--shy, .c-entity__secondary-identifier.--shylink { + width: 10rem; } -.c-entity.__secondary-identifier.--image { - width: 15rem; +.c-entity__secondary-identifier.--symbol img { + width: auto; } -.c-entity.__secondary-identifier { - grid-area: second-id; +.c-entity__secondary-identifier.--image img { + max-width: 360px; } -.c-entity.__primary-identifier { - grid-area: prim-id; +.c-entity__primary-identifier { font-weight: 600; font-size: 1.5rem; } -.c-entity.__featured { - grid-area: f-prop; - font-size: 1.115rem; +.c-entity__featured { + font-size: 1rem; +} +.c-entity__workflow-actions { + padding-top: 18px; } -.c-entity.__personal-status { - grid-area: status; +.c-entity__blocking-conditions { + padding-bottom: 18px; + font-size: 1rem; } -.c-entity.__main-details { - grid-area: f-details; +.c-entity__main-details { + padding-top: 18px; } -.c-entity.__availability { - grid-area: availab; +.c-entity__details { + font-size: 0.75rem; } -.c-entity.__details { - grid-area: details; +.c-entity__reactions { + padding-top: 18px; } -.c-entity.__reactions { - grid-area: reaction; +.c-entity__reactionbar { + align-self: stretch; + align-content: flex-end; + grid-column: 2; + grid-row: 9; } -.c-entity.__featured-reactions { - display: flex; - justify-content: end; - grid-area: f-reaction; +.c-entity__featured-reactions { + padding-top: 18px; + text-align: end; min-width: max-content; } +@media screen and (max-width: 768px) { + .c-entity__container { + display: flex; + flex-direction: column; + } + .c-entity__container > * { + order: 2; + } + .c-entity__secondary-identifier { + order: 1; + } + .c-entity__secondary-identifier.--image img { + width: calc(100% + 30px); + max-width: unset; + margin-left: -15px; + margin-top: -9px; + } + .c-entity__reactionbar { + flex-grow: 1; + } +} + +.c-listing-inline { + padding: 0; + margin: 0; + list-style: none; +} +.c-listing-inline > .c-listing-inline__item::after { + content: ", "; +} +.c-listing-inline > .c-listing-inline__item:last-child::after { + content: ""; +} .il-std-item-container:not(:last-child) { border-bottom: 1px solid #dddddd; @@ -5819,7 +6055,7 @@ a[aria-disabled].il-link.link-bulky:hover { background-color: unset; } -.c-listing-property__propertylabel:after { +.c-listing-property__propertylabel:not(:has(.glyphicon)):after { content: ":"; } @@ -6033,11 +6269,49 @@ a[aria-disabled].il-link.link-bulky:hover { padding: 15px 15px; } -.c-listing-entity { +.c-listing-entity, +.c-listing-entity-grid { list-style: none; padding-left: 0; } +.c-listing-entity { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(650px, 1fr)); + gap: 15px; +} + +.c-listing-entity-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); + gap: 15px; +} +.c-listing-entity-grid .c-entity__container { + display: flex; + flex-direction: column; +} +.c-listing-entity-grid .c-entity__container > * { + order: 2; +} +.c-listing-entity-grid .c-entity__secondary-identifier { + order: 1; +} +.c-listing-entity-grid .c-entity__secondary-identifier.--image img { + width: calc(100% + 30px); + max-width: unset; + margin-left: -15px; + margin-top: -9px; +} +.c-listing-entity-grid .c-entity__reactionbar { + flex-grow: 1; +} +.c-listing-entity-grid .c-entity__container { + height: 100%; +} +.c-listing-entity-grid .c-entity__container .c-listing-property__propertyvalue:has(.t-text-more-less__toggle:not(:checked)) .t-text-more-less__text-body { + height: 2lh; +} + .il-maincontrols-slate.disengaged { display: none; } @@ -7129,7 +7403,7 @@ code { .c-maincontrols__footer { font-size: 0.75rem; } - .c-maincontrols__footer-grid { + .c-maincontrols__footer-grid--sm { grid-template-columns: repeat(4, 1fr); } } @@ -7137,7 +7411,7 @@ code { .c-maincontrols__footer { font-size: 0.875rem; } - .c-maincontrols__footer-grid { + .c-maincontrols__footer-grid--sm, .c-maincontrols__footer-grid--md { grid-template-columns: repeat(1, 1fr); } .c-maincontrols__footer ul li { @@ -11055,10 +11329,6 @@ div.alert ul { content: "\e108"; } -.glyphicon-calendar:before { - content: "\e109"; -} - .glyphicon-random:before { content: "\e110"; } @@ -11932,6 +12202,31 @@ div.alert ul { content: "\e914"; } +.glyphicon-presenter:before { + font-family: il-icons; + content: "\e90e"; +} + +.glyphicon-owner:before { + font-family: il-icons; + content: "\e90f"; +} + +.glyphicon-date:before { + font-family: il-icons; + content: "\e619"; +} + +.glyphicon-calendar:before { + font-family: il-icons; + content: "\e075"; +} + +.glyphicon-location:before { + font-family: il-icons; + content: "\e096"; +} + .il-avatar { height: 45px; width: 45px; @@ -12349,7 +12644,7 @@ th.c-table-data__cell { } .c-table-data__cell--link .c-table-data__header__resize-wrapper, -.c-table-data__cell--linklisting .c-table-data__header__resize-wrapper, +.c-table-data__cell--listing .c-table-data__header__resize-wrapper, .c-table-data__cell--text .c-table-data__header__resize-wrapper { min-width: 140px; resize: horizontal; @@ -15942,6 +16237,19 @@ body.ilPrtfPdfBody .ilPCMyCoursesToggle img { visibility: hidden; } +.c-questions__solution-value { + background: rgb(226.2857142857, 231.6428571429, 238.7142857143); + padding: 3px; +} + +.c-questions__async-answerform { + padding-bottom: 6px; +} + +.c-questions_async-answerform-feedback { + padding-top: 6px; +} + /* Modules/ScormAicc */ table.il_ScormTable { color: #161616; @@ -16623,8 +16931,8 @@ td.ilc_Page { } .ilTestMarkQuestionIcon { - width: 12px; - height: 12px; + width: 28px; + height: 28px; } .ilTestAnswerStatusIcon { @@ -16902,9 +17210,12 @@ div.ilc_Page.readonly textarea[disabled] { .c-consecutive-scoring__answer__body h1:empty { display: none; } -.c-consecutive-scoring__answer__body .ilc_qanswer_Answer.solutionbox { +.c-consecutive-scoring__answer__body .ilc_qanswer_Answer .solutionbox { width: auto; } +.c-consecutive-scoring__answer__body .ilc_qanswer_Answer .ilc_answers.answers.ilAssClozeTest div input[type=text] { + width: 100%; +} .c-consecutive-scoring__answer__grade-card { width: 40%; border-left: 1px solid #dddddd; @@ -17281,16 +17592,12 @@ div.ilc_va_icont_VAccordICont { border-bottom: 1px solid #dddddd; background-color: white; } -.ilAwarenessItem > div[role=button]:focus-visible:focus { - outline: none; - outline-offset: 0px; -} -.ilAwarenessItem > div[role=button]:focus-visible:focus-visible { +.ilAwarenessItem > div[role=button]:focus-visible:focus, .ilAwarenessItem > div[role=button]:focus-visible:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -.ilAwarenessItem > div[role=button]:focus-visible:focus-visible::after { +.ilAwarenessItem > div[role=button]:focus-visible:focus::after, .ilAwarenessItem > div[role=button]:focus-visible:focus-visible::after { content: " "; position: absolute; top: -2px; @@ -19127,16 +19434,12 @@ p#copg-auto-save { position: static; } -.ilPageVideo button:focus, .ilPageAudio button:focus { - outline: none; - outline-offset: 0px; -} -.ilPageVideo button:focus-visible, .ilPageAudio button:focus-visible { +.ilPageVideo button:focus, .ilPageVideo button:focus-visible, .ilPageAudio button:focus, .ilPageAudio button:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -.ilPageVideo button:focus-visible::after, .ilPageAudio button:focus-visible::after { +.ilPageVideo button:focus::after, .ilPageVideo button:focus-visible::after, .ilPageAudio button:focus::after, .ilPageAudio button:focus-visible::after { content: " "; position: absolute; top: -2px; @@ -20190,18 +20493,15 @@ a.mailunread, a.mailunread:visited { background-image: url("../images/media/bigplay.svg"); } -.mejs__overlay-button:focus, -.ilPlayerPreviewPlayButton:focus { - outline: none; - outline-offset: 0px; -} -.mejs__overlay-button:focus-visible, +.mejs__overlay-button:focus, .mejs__overlay-button:focus-visible, +.ilPlayerPreviewPlayButton:focus, .ilPlayerPreviewPlayButton:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -.mejs__overlay-button:focus-visible::after, +.mejs__overlay-button:focus::after, .mejs__overlay-button:focus-visible::after, +.ilPlayerPreviewPlayButton:focus::after, .ilPlayerPreviewPlayButton:focus-visible::after { content: " "; position: absolute; @@ -20213,16 +20513,12 @@ a.mailunread, a.mailunread:visited { outline: 3px solid #0078D7; } -.mejs__time-total:focus { - outline: none; - outline-offset: 0px; -} -.mejs__time-total:focus-visible { +.mejs__time-total:focus, .mejs__time-total:focus-visible { position: relative; outline: 1px solid #FFFFFF; outline-offset: 2px; } -.mejs__time-total:focus-visible::after { +.mejs__time-total:focus::after, .mejs__time-total:focus-visible::after { content: " "; position: absolute; top: -1px; @@ -22129,18 +22425,15 @@ a.ilMediaLightboxClose:hover { #ilTab > li > .c-tooltip__container > a:focus-visible::after { content: none; } -#ilTab > li > a:focus, -#ilTab > li > .c-tooltip__container > a:focus { - outline: none; - outline-offset: 0px; -} -#ilTab > li > a:focus-visible, +#ilTab > li > a:focus, #ilTab > li > a:focus-visible, +#ilTab > li > .c-tooltip__container > a:focus, #ilTab > li > .c-tooltip__container > a:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -#ilTab > li > a:focus-visible::after, +#ilTab > li > a:focus::after, #ilTab > li > a:focus-visible::after, +#ilTab > li > .c-tooltip__container > a:focus::after, #ilTab > li > .c-tooltip__container > a:focus-visible::after { content: " "; position: absolute; @@ -22211,18 +22504,15 @@ a.ilMediaLightboxClose:hover { #ilSubTab > li > .c-tooltip__container > a:focus-visible::after { content: none; } -#ilSubTab > li > a:focus, -#ilSubTab > li > .c-tooltip__container > a:focus { - outline: none; - outline-offset: 0px; -} -#ilSubTab > li > a:focus-visible, +#ilSubTab > li > a:focus, #ilSubTab > li > a:focus-visible, +#ilSubTab > li > .c-tooltip__container > a:focus, #ilSubTab > li > .c-tooltip__container > a:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -#ilSubTab > li > a:focus-visible::after, +#ilSubTab > li > a:focus::after, #ilSubTab > li > a:focus-visible::after, +#ilSubTab > li > .c-tooltip__container > a:focus::after, #ilSubTab > li > .c-tooltip__container > a:focus-visible::after { content: " "; position: absolute; @@ -22376,16 +22666,12 @@ img.ilUserXXSmall { .webdav-view-control { text-align: center; } -.webdav-view-control:focus { - outline: none; - outline-offset: 0px; -} -.webdav-view-control:focus-visible { +.webdav-view-control:focus, .webdav-view-control:focus-visible { position: relative; outline: 2px solid #FFFFFF; outline-offset: 5px; } -.webdav-view-control:focus-visible::after { +.webdav-view-control:focus::after, .webdav-view-control:focus-visible::after { content: " "; position: absolute; top: -2px; @@ -22396,15 +22682,6 @@ img.ilUserXXSmall { outline: 3px solid #0078D7; } -/* - These classes are used to limit the number of rows when displaying larger chunks of text. - The mixin receives $height-in-rows as an integer. The classes il-multi-line-cap-2,3,5,10 - can be used to limit the number of rows for text to 2,3,5 or 10 lines in any template, - e.g. the Standard Listing Panels limit the property values to 3 lines using il-multi-line-cap-3 - - Technical discussion can be found in https://mantis.ilias.de/view.php?id=21583 - The background/gradient fallback can be removed as soon as all browsers support line-clamp. - */ /* * Hacks & Tweaks */ diff --git a/templates/default/delos.scss b/templates/default/delos.scss index 45a1b2b15d31..c1ce11074878 100755 --- a/templates/default/delos.scss +++ b/templates/default/delos.scss @@ -11,6 +11,7 @@ // ## Tools // include patterns and tools with @use in component when needed +@forward "./030-tools"; // avoid creating new tools like these that generate CSS utility classes // ## Normalize @use "./040-normalize/" as *; @@ -30,4 +31,4 @@ // # Relative paths differences // SCSS paths are relativ to the SCSS file -// CSS paths (linked fonts) are relative to the compiled template CSS \ No newline at end of file +// CSS paths (linked fonts) are relative to the compiled template CSS diff --git a/templates/default/delos.scss.map b/templates/default/delos.scss.map new file mode 100644 index 000000000000..11f17f06e2dc --- /dev/null +++ b/templates/default/delos.scss.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["020-dependencies/_index.scss","020-dependencies/modifications/datetimepicker/bootstrap-datetimepicker.scss","030-tools/_tool_browser-prefixes.scss","010-settings/_settings_typography.scss","030-tools/_tool_screen-reader-only.scss","010-settings/_settings_borders.scss","010-settings/_settings_color-palette.scss","010-settings/_settings_button.scss","010-settings/legacy-settings/_legacy-settings_menu.scss","070-components/UI-framework/Dropdown/_ui-component_dropdown.scss","030-tools/legacy-bootstrap-mixins/_nav-divider.scss","050-layout/basics/_layout_spacing-variables.scss","010-settings/legacy-settings/_legacy-settings_form.scss","020-dependencies/modifications/_jquery-autocomplete.scss","020-dependencies/modifications/_additions_tinymce.scss","020-dependencies/modifications/_additions_yui2.scss","040-normalize/_index.scss","040-normalize/_normalize_print.scss","040-normalize/_normalize_typography.scss","040-normalize/_normalize_input.scss","040-normalize/_normalize_structure.scss","040-normalize/_normalize_table.scss","050-layout/_layout_grid.scss","050-layout/_layout_container.scss","050-layout/_layout_element-bar.scss","050-layout/_layout_visibility-utilities.scss","060-elements/_index.scss","060-elements/_elements_dialog.scss","060-elements/_elements_html-body.scss","060-elements/_elements_input.scss","030-tools/_tool_focus-outline.scss","060-elements/_elements_lists.scss","060-elements/_elements_media.scss","060-elements/_elements_objects.scss","060-elements/_elements_tables.scss","060-elements/_elements_typography.scss","060-elements/_elements_details-summary.scss","070-components/_index.scss","070-components/UI-framework/_ui-component_tooltip.scss","030-tools/_tool_typography-mixins.scss","070-components/UI-framework/Breadcrumbs/_ui-component_breadcrumbs.scss","050-layout/standardpage/_layout_standardpage.scss","070-components/UI-framework/Button/_ui-component_button.scss","030-tools/_tool_buttons.scss","070-components/UI-framework/Button/_ui-component_tag.scss","070-components/UI-framework/Button/_ui-component_toggle.scss","070-components/UI-framework/Card/_ui-component_card.scss","010-settings/legacy-settings/_legacy-settings_panel.scss","070-components/UI-framework/Chart/_ui-component_chart.scss","010-settings/legacy-settings/_legacy-settings_chart.scss","070-components/UI-framework/Counter/_ui-component_counter.scss","070-components/UI-framework/Deck/_ui-component_deck.scss","070-components/UI-framework/Divider/_ui-component_divider.scss","070-components/UI-framework/Dropzone/_ui-component_dropzone.scss","010-settings/legacy-settings/_legacy-settings_dropzone.scss","070-components/UI-framework/Entity/_ui-component_entity.scss","070-components/UI-framework/Item/_ui-component_item.scss","070-components/UI-framework/Launcher/_ui-component_launcher.scss","010-settings/legacy-settings/_legacy-settings_symbol.scss","070-components/UI-framework/MainControls/_ui-component_metabar.scss","050-layout/standardpage/_layout_standardpage-mobile.scss","070-components/UI-framework/Layout/_ui-component_standardpage.scss","050-layout/basics/_layout_z-index.scss","010-settings/_settings_header.scss","050-layout/_layout_container-query.scss","070-components/UI-framework/Layout/_ui-component_alignment.scss","070-components/UI-framework/Link/_ui-component_link.scss","070-components/UI-framework/Listing/_ui-component_properties.scss","030-tools/_tool_clearfix.scss","070-components/UI-framework/Listing/_ui-component_characteristic_value.scss","050-layout/basics/_layout_positioning.scss","070-components/UI-framework/Listing/_ui-component_workflow.scss","070-components/UI-framework/Listing/_ui-component_entitylisting.scss","070-components/UI-framework/MainControls/Slate/_ui-component_slate.scss","030-tools/_tool_multi-line-cap.scss","070-components/legacy/_component_screen-reader-only.scss","070-components/UI-framework/MainControls/_ui-component_mainbar.scss","010-settings/_settings_mainbar.scss","070-components/UI-framework/MainControls/_ui-component_footer.scss","010-settings/_settings_footer.scss","050-layout/_layout_breakpoints.scss","070-components/UI-framework/MainControls/_ui-component_mode_info.scss","010-settings/_settings_shadows.scss","070-components/UI-framework/MainControls/_ui-component_system_info.scss","070-components/UI-framework/Menu/_ui-component_drilldown.scss","070-components/UI-framework/Input/_ui-component_tag.scss","070-components/UI-framework/Input/_ui-component_password.scss","070-components/UI-framework/Input/_ui-component_radio.scss","070-components/UI-framework/Input/_ui-component_multiselect.scss","070-components/UI-framework/Input/_ui-component_filter.scss","070-components/UI-framework/Input/_ui-component_file.scss","010-settings/legacy-settings/_legacy-settings_ui-input-file.scss","070-components/UI-framework/Input/_ui-component_markdown.scss","050-layout/_layout_form.scss","070-components/UI-framework/Input/_ui-component_option-filter.scss","070-components/UI-framework/Input/_ui-component_rating.scss","070-components/UI-framework/Input/_ui-component_section.scss","070-components/UI-framework/Input/_ui-component_numeric.scss","070-components/UI-framework/Input/_ui-component_optionalgroups.scss","070-components/UI-framework/Input/_ui-component_tree_select.scss","070-components/UI-framework/Input/_ui-component_input.scss","070-components/UI-framework/MessageBox/_ui-component_messagebox.scss","070-components/UI-framework/Modal/_ui-component_modal.scss","030-tools/_tool_dialog-patterns.scss","070-components/UI-framework/Navigation/_ui-component_sequence.scss","070-components/UI-framework/Panel/_ui-component_panel.scss","030-tools/_tool_border-radius.scss","070-components/UI-framework/Player/_ui-component_player.scss","020-dependencies/modifications/webui-popover/jquery.webui-popover.scss","070-components/UI-framework/Popover/_ui-component_popover.scss","070-components/UI-framework/Progress/_ui-component_progress_bar.scss","070-components/UI-framework/Symbol/_ui-component_icon.scss","070-components/UI-framework/Symbol/_ui-component_glyph.scss","070-components/UI-framework/Symbol/_ui-component_avatar.scss","070-components/UI-framework/Table/_ui-component_table.scss","030-tools/_tool_highlighted-box.scss","070-components/UI-framework/Toast/_ui-component_toast.scss","070-components/UI-framework/Tree/_ui-component_tree.scss","010-settings/legacy-settings/_legacy-settings_tree.scss","070-components/UI-framework/ViewControl/_ui-component_viewcontrol.scss","070-components/legacy/_component_agreement.scss","070-components/legacy/_component_alert.scss","070-components/legacy/_component_bottom-center-area.scss","070-components/legacy/_component_headline.scss","070-components/legacy/_component_helpsidebar.scss","070-components/legacy/_component_icon.scss","070-components/legacy/_component_LeftNavSpace.scss","070-components/legacy/_component_link.scss","070-components/legacy/_component_map.scss","070-components/legacy/_component_media-object.scss","070-components/legacy/_component_rightPanel.scss","070-components/legacy/_component_delostable.scss","070-components/legacy/_component_well.scss","070-components/legacy/_component_php.scss","070-components/legacy/_component_animated-collapse-fade.scss","070-components/legacy/_component_btn-group.scss","050-layout/_layout_responsive-img.scss","070-components/legacy/_component_carousel.scss","070-components/legacy/_component_input-group.scss","070-components/legacy/Modules/_component_bibliographic.scss","070-components/legacy/Modules/_component_blog.scss","070-components/legacy/Modules/_component_bookingmanager.scss","070-components/legacy/Modules/_component_chatroom.scss","070-components/legacy/Modules/_component_course.scss","070-components/legacy/Modules/_component_datacollection.scss","070-components/legacy/Modules/_component_excercise.scss","070-components/legacy/Modules/_component_forum.scss","070-components/legacy/Modules/_component_learningmodule.scss","070-components/legacy/Modules/_component_learningsequence.scss","070-components/legacy/Modules/_component_lticonsumer.scss","070-components/legacy/Modules/_component_mediacast.scss","070-components/legacy/Modules/_component_mediapool.scss","070-components/legacy/Modules/_component_orgunit.scss","070-components/legacy/Modules/_component_poll.scss","070-components/legacy/Modules/_component_portfolio.scss","070-components/legacy/Modules/_component_questions.scss","070-components/legacy/Modules/_component_scormaicc.scss","070-components/legacy/Modules/_component_survey.scss","070-components/legacy/Modules/_component_test_legacy.scss","070-components/legacy/Modules/_component_test.scss","030-tools/_tool_fade-edge.scss","070-components/legacy/Modules/_component_wiki.scss","070-components/legacy/Modules/_component_workspacefolder.scss","070-components/legacy/Modules/_component_studyprogramme.scss","070-components/legacy/Services/_component_accesscontrol.scss","070-components/legacy/Services/_component_accordion.scss","070-components/legacy/Services/_component_awareness.scss","070-components/legacy/Services/_component_cron.scss","070-components/legacy/Services/_component_badge.scss","070-components/legacy/Services/_component_block.scss","070-components/legacy/Services/_component_bookmarks.scss","070-components/legacy/Services/_component_calendar.scss","070-components/legacy/Services/_component_chart.scss","070-components/legacy/Services/_component_container.scss","070-components/legacy/Services/_component_copage.scss","070-components/legacy/Services/_component_fileupload.scss","070-components/legacy/Services/_component_form.scss","070-components/legacy/Services/_component_help.scss","070-components/legacy/Services/_component_infoscreen.scss","070-components/legacy/Services/_component_init.scss","070-components/legacy/Services/_component_learninghistory.scss","070-components/legacy/Services/_component_like.scss","070-components/legacy/Services/_component_mail.scss","070-components/legacy/Services/_component_openlayers.scss","070-components/legacy/Services/_component_mediaobjects.scss","070-components/legacy/Services/_component_membership.scss","070-components/legacy/Services/_component_navigation.scss","070-components/legacy/Services/_component_news.scss","070-components/legacy/Services/_component_notes.scss","070-components/legacy/Services/_component_object.scss","070-components/legacy/Services/_component_onscreenchat.scss","070-components/legacy/Services/_component_rating.scss","070-components/legacy/Services/_component_search.scss","070-components/legacy/Services/_component_skill.scss","070-components/legacy/Services/_component_style.scss","070-components/legacy/Services/_component_table.scss","070-components/legacy/Services/_component_tags.scss","070-components/legacy/Services/_component_termsofservice.scss","070-components/legacy/Services/UIComponent/_component_checklist.scss","070-components/legacy/Services/UIComponent/_component_explorer2.scss","070-components/legacy/Services/UIComponent/_component_lightbox.scss","070-components/legacy/Services/UIComponent/_component_modal.scss","070-components/legacy/Services/UIComponent/_component_progressbar.scss","070-components/legacy/Services/UIComponent/_component_tabs.scss","070-components/legacy/Services/UIComponent/_component_toolbar.scss","070-components/legacy/Services/_component_user.scss","070-components/legacy/Services/_component_webdav.scss","080-hacks/_index.scss","050-layout/_layout_pull-float.scss"],"names":[],"mappings":";AAAA;AAAA;AAAA;ACKA;AAAA;AAAA;AAAA;AAAA;AAmBA;EACI;;AAEA;EACI;EACA;EACA;;AAGI;EADJ;IAEQ;;;AAGJ;EALJ;IAMQ;;;AAGJ;EATJ;IAUQ;;;AAIR;EACI;EACA;EACA;;AAIA;EACI;EACA;EACA;EACA,qBAtCiC;EAuCjC;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;EACA;EACA,kBAzDiC;EA0DjC;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAKJ;EACI;EACA;;AAGJ;EACI;EACA;;AAKZ;EACI;;AAGJ;EACI;;AAGJ;ECvCF,oBDwCM;ECvCE,YDuCF;;AAGJ;EACI;EACA,aE5EiB;EF6EjB,WEnGc;EFoGd;;AAGJ;EACI;;AAGJ;EGvHA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHiHI;;AAGJ;EG5HA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHsHI;;AAGJ;EGjIA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EH2HI;;AAGJ;EGtIA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHgII;;AAGJ;EG3IA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHqII;;AAGJ;EGhJA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EH0II;;AAGJ;EGrJA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EH+II;;AAGJ;EG1JA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHoJI;;AAGJ;EG/JA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHyJI;;AAGJ;EACI;;AAEA;EGvKJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHiKQ;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAKZ;EACI;EACA;;AAGA;EAEI;EACA,eIjMY;;AJoMhB;EACI;EACA;EACA;;AAEA;EACI;;AAGJ;EAEI;EACA,OKhMS;ELiMT;;AAGJ;EGtNR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHgNY;;AAGJ;EG3NR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EHqNY;;AAIR;EACI;;AAEA;EACI,YKtME;ELuMF,OK/LM;;ALmMd;EACI;EACA;EACA;;AAEA;EACI,WExOM;EFyON;EACA;EACA,OKjOS;;ALoOb;EACI;EACA;EACA;;AAGJ;EAII,YKjOE;ELkOF,OK1NM;EL2NN;;AAGJ;EAEI,OKrPS;;ALwPb;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA,qBMnQA;ENoQA,kBAvQ6B;EAwQ7B;EACA;EACA;;AAIR;EAEI,kBM7QI;EN8QJ,OMhRO;ENiRP,aAhRiB;;AAmRrB;EACI;;AAGJ;EAEI;EACA,OKtRS;ELuRT;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA,eIjTQ;;AJmTR;EACI,YKvRF;ELwRE,OKhRE;;ALmRN;EACI,kBM5SA;EN6SA,OM/SG;ENgTH,aA/Sa;;AAkTjB;EACI,OK/SK;;ALkTT;EAEI;EACA,OKrTK;ELsTL;;AAOZ;EACI;EACA;;AAIX;EACC;;AAGD;EACO;;;AAKJ;EACI;EACA;;AACA;EACI;;;AOxWZ;AC2CA;EACC;EACA;EACA;EACA;EACA;EACA;;;AAIC;AAAA;EAED;EACA;EACA;;;AAIC;EACC;EACF;EACA;EACA,SAtD0B;EAuD1B;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WN1DsB;EM2DtB;EACA;EACA,kBHlDY;EGmDZ;EACA;EACA,eJxEuB;EH+DtB,oBOUD;EPTS,YOST;;AAKA;EACE;EACA;;AAGF;EACE;EACA;;AAEF;EACE;EACA;;AAKF;EC/FC;EACA;EACA;EACA,kBDU+B;;AAqFhC;EACC;;AAID;EACE;EACA;EACA;EACA;;;AAMF;EAGE,OHhGU;EGiGV;EACA,kBHvHa;EGwHb;;;AASF;EAGE,OHlHsB;;AGsHxB;EAEE;EACA,QAzGe;EA0Gf;EACA;;;AAQF;EACE;;AAIF;EACE;;;AAQD;EACD;EACA;;;AAQC;EACD;EACA;;;AAIC;EACD;EACA;EACA;EACA;EACA;EACA;;;AAIC;EACD;EACA;;;AAWA;AAAA;EACE;EACA;EACA;EACA;;AAGF;AAAA;EACE;EACA;EACA;;;AAKH;EACC;EACA,OHzLe;EG0Lf,kBD7NoB;EC8NpB;EACA;;AACA;EACC;EACA,eE/MuB;EFgNvB,WNtNoB;;;AMyNtB;EACC,kBHjNY;EGkNZ,aNvMwB;EMwMxB;EPvKC,oBOwKD;EPvKS,YOuKT;;AAEA;EACC;;AACA;EACC;;AAKF;AAAA;EAEC;EACA;EACA;EACA;EACA,aNzNuB;EM0NvB,WNhPqB;EMiPrB,aNtOqB;EMuOrB,kBD9PiB;EC+PjB,OH3Nc;EG4Nd,YG3NoB;EH4NpB;EACA;EACA;EACA;;AACA;AAAA;AAAA;EAEC,OH9NmB;EG+NnB,kBHvOe;EGwOf;;AAED;AAAA;EACC,kBFvOkB;;AE0OpB;EACC;EACA;EACA;EACA;EACA,SD7Qa;;;ACkRf;EACC;EACA;;;AAGA;EACC;;;AAIF;EPhOE,oBOiOE;EPhOM,YOgON;;;AASJ;EACC;;;AAMA;EACC;EACA;;;AIrTF;AACA;EACC;EACA;EACA;EACA;EACA;EACA,kBPeY;EOdZ;EACA;EACA;EXwDC,oBWvDE;EXwDM,YWxDN;;AACH;EACC;EACA;EACA;EACA;EACA;EACA;;AACA;EACC;EACA;EACA;EACA;EACA,OPWa;EOVb,kBL1BgB;;AK2BhB;EACC,kBPKc;EOJd,OPOY;;AOJd;EACC,OPGa;;AOFb;EACC,OPMkB;;AOFrB;EACC;EACA;EACA;EACA;EACA;EACA;EACA,aVVuB;;AUYxB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACC;;AAED;EACC;;;AAKH;EACC;EACA;AACA;EACA;;AAEA;EACC;;;AC7EF;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;AACA;EACC;EACA;;;ACjCF;EACC,OTsCe;;;ASlCf;EACC;;AAED;EACC;EACA;;;ACZF;AAAA;AAAA;ACEA;AACA;EAEE;AACE;AACA;AAAA;AAAA;AAAA;;EAMF;AAAA;IAEE;;EAGF;IACE;;EAGF;IACE;;EAIF;AAAA;IAEE;;EAGF;AAAA;IAEE;IACA;;EAGF;IACE;;EAGF;AAAA;IAEE;;EAGF;IACE;;EAGF;AAAA;AAAA;IAGE;IACA;;EAGF;AAAA;IAEE;;EAKF;IACE;;EAIF;IACE;;EAGA;AAAA;IAEE;;EAKF;AAAA;IACE;;EAGJ;IACE;;EAGF;IACE;;EAGA;AAAA;IAEE;;EAKJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IAUE;;EAEF;IACE;;EAEF;IACE;;EAEF;IACE;;EAGF;IACE;;EAIF;IACE;;EAGF;IACE;;EAGF;IACE;IACA;;;ACvIJ;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAGD;EACC;EACA;EAEA;EACA;;AAKD;EACC;EACA;EAEA;;AAGD;EACC;EACA;EAGA;EACA;;ACjGD;AAAA;AAAA;AAAA;EAIE;EACA;EACA;;;ACNF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAQI;;;ACNJ;EACI;EACA;;;AAGJ;AAAA;EAEI;;;ACuQA;EAnJA;EACA;EACA;EACA;EAEA;EACA;EACA;;AA+II;EAtIJ;EACA;EACA;EACA;EACA;EACA;;;AAxCI;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AA9HZ;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AA9HZ;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AA9HZ;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AA9HZ;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AA9HZ;EAqFI;IACI;;EAGJ;IAhCR;IACA;;EASA;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAFJ;IACI;IACA;;EAgCI;IA5CR;IACA;;EAiDgB;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EA6DY;IA9DZ;IACA;;EAyEQ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;EAPJ;AAAA;IAEI;;EAGJ;AAAA;IAEI;;;AC/MhB;AAAA;EAZA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAWA;ACvBJ;EACI;EACA;EACA;;;AAOJ;AAAA;EAGI;EACA;EACA;EACA;;;AAGJ;EACI;;AACA;EACI;;;AAIR;AAAA;EAEI;;AACA;AAAA;EACI;;;AAIR;AAAA;EAEI;;;AAGJ;AAAA;EAEI;;AACA;AAAA;EACI;;;AC7BR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAaE;;;AAGF;EAzBE;IACE;;EAEF;IAAmB;;EACnB;IAAmB;;EACnB;AAAA;IACmB;;;AAuBnB;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIJ;EA5CE;IACE;;EAEF;IAAmB;;EACnB;IAAmB;;EACnB;AAAA;IACmB;;;AA0CnB;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIJ;EA/DE;IACE;;EAEF;IAAmB;;EACnB;IAAmB;;EACnB;AAAA;IACmB;;;AA6DnB;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIJ;EAlFE;IACE;;EAEF;IAAmB;;EACnB;IAAmB;;EACnB;AAAA;IACmB;;;AAgFnB;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAIF;EADF;IAEI;;;;AAWJ;EALE;IACE;;;AAQJ;EATE;IACE;;;AAYJ;EAbE;IACE;;;AAgBJ;EAjBE;IACE;;;AADF;EACE;;;AA6BJ;EArIE;IACE;;EAEF;IAAmB;;EACnB;IAAmB;;EACnB;AAAA;IACmB;;;AAkIrB;EACE;;AAEA;EAHF;IAII;;;;AAGJ;EACE;;AAEA;EAHF;IAII;;;;AAGJ;EACE;;AAEA;EAHF;IAII;;;;AAIJ;EAvDE;IACE;;;ACpHJ;AAAA;AAAA;ACEA;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;IAAO;;EACP;IAAK;;;AAGP;EACE;IAAO;IAA6B;IAAY;;EAChD;IAAK;IAA4B;IAAY;;;ACvB/C;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;AACA;EAFD;IAGE;;;;AAIF;EACC,azBZ2B;EyBa3B,WzBJsB;EyBKtB,azBMsB;EyBLtB,OtBkBe;EsBjBf,kBtBIY;;AsBHZ;EAND;IAOE;IACA;IACA;;;;AAIF;AACA;EACC;;;AC5BD;EACC;;ACmCA;EACC,SAHwB;EAIxB;;;ADhCD;EADD;IAEE;;;;AAKD;EADD;IAEE;;;;AAIF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOC,YjBYqB;;;AiBTtB;AAAA;EAEC;EACA;EACA;;AAGA;AAAA;AAAA;AAAA;EAGC,QjBJgB;;;AkB5BjB;AAAA;AAAA;EACC;EACG;;AAEJ;AAAA;AAAA;EACC;EAEA,SARwB;EASxB;;AAEA;AAAA;AAAA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;;AD6C1B;AAAA;AAAA;AAAA;AAAA;AAAA;EAMC;;AClBA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC,SAHwB;EAIxB;;;AC1CF;EACC;;;AAGD;EACC,cpBO8B;EoBN3B;;;AAGJ;AAAA;EAEC;EACA;;;AAGD;EACC;IACC;;;ACjBF;EACC;;AACA;EAFD;AAGE;IACA;;;;ACJF;EACC;;;AAGD;EACC;EACA;EACA;;;ACPD;EACC,W/BcsB;E+BbnB;;;AAGJ;EACC;;;AAGD;EACI;EACH;EACG;;;ACAJ;AAAA;EAEE,ahCR0B;EgCS1B,ahC4BwB;EgC3BxB,ahCcwB;EgCbxB,O7BwBkB;;A6BtBlB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;EACA,O7BkBgB;;;A6BdpB;AAAA;AAAA;EAGE,YhCHwB;EgCIxB;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAGJ;AAAA;AAAA;EAGE;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAIJ;EAAU,WhC3BW;;;AgC4BrB;EAAU,WhC9BgB;;;AgC+B1B;EAAU,WhCjCe;;;AgCkCzB;EAAU,WhCpCY;;;AgCqCtB;EAAU,WhCvCa;;;AgCwCvB;EAAU,WhC1CY;;;AgCgDtB;EACE;;;AAKF;EACE,O7B/Dc;E6BgEd;EACA;AACA;AAAA;AAAA;AAAA;EAID;AACA;;AACC;EAEE,O7B1BkB;E6B2BlB,iBhClCuB;;A2B6B1B;EACC;EACA,QAJwB;EAKxB;;;AKYF;AAAA;EAGE,WhClFqB;;;AgCsFvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AAGvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AAGvB;EACE,O7B5FiB;;;A6BqGjB;AAAA;AAAA;AAAA;EAEE;;;AAYJ;EAJE;EACA;;;AAQF;EACE;EACA,ehCjHwB;;;AgCmH1B;AAAA;EAEE,ahCtHqB;;;AgCwHvB;EACE;;;AAEF;EACE;;;AAOF;EACE;EACA;EACA,WhCjJqB;EgCkJrB;;AAKE;AAAA;AAAA;EACE;;;AAMN;EACE,ehCnJwB;EgCoJxB;EACA,ahCtJqB;;;AgCyJvB;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AACA;EACC;;;AAGD;EACC,ahClKwB;;;AgCqKzB;EACC;EACA,WhCjMqB;EgCkMrB,O7BjKqB;;;A6BoKtB;EACC;;;AAGD;EACC;;;AAGD;EACC;IACC;;;AC3NF;EACE,e/BGe;E+BFf,ezBc6B;;AyBb7B;EACE;EACA;;AACA;EACE,czBawB;EyBZxB;EACA;;AAGJ;EACE;;AAGA;EACE;;;ACpBN;AAAA;AAAA;AAQA;ACKA;EACC;;;AAGD;EACC;;;AAKD;EACC;EACA;EACA;EACA;EACA;EACA,qBhCtBe;EgCuBf,SAnBmB;;;AAuBpB;EACC;EACA;EACA;EACA;EACA;EACA;EACA,SA9BmB;;;AAkCpB;AAAA;EAEC;;;AAID;AAAA;AAAA;EAGC;EACA;;;AAID;EACC,kBhCrDe;EgCsDf;;;AAID;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OhCjCe;EgCkCf,YhC1CkB;EgC2ClB;EACA,WAzEqB;EA0ErB,YAzEsB;EA0EtB;EACA;EACA,SAtEmB;;ACTlB;EACC;;AAED;EACC;;;AD+EH;EACC;;;AAGD;AACA;EACC;;;AEtFD;EACC;EACA;EACA,YlCoBY;;AkClBZ;EACC;EACA;EACA;EACA;EACA;EACA;EACA,arCwBuB;EqCvBvB,WrCHoB;EqCIpB;EACA,cCNiC;;ADQjC;EACC,OlChBa;;AkCiBb;EACC,OlC8BkB;;AwBmCrB;EACC;EACA;EACA;EACG;;AAEF;EACC;;AAIH;EACC;EACA;EACA;EACG;;AAEF;EACC;;AAlEH;EACC,SAHwB;EAIxB;;AUbA;EACC,SCWsC;EDVtC,OlCRsB;EkCStB;EACA,arCIsB;EqCHtB;;;AA4BH;AAEA;EACC;EACA,WrCrDqB;;AqCuDrB;EACC;;AAGD;EARD;IASE;IACA;;;;AAIF;AACA;EACC;;AAEA;EACC;;AAED;EACC;EACA,OlChEuB;EkCiEvB,SC/CuC;EDgDvC;;;AEtDF;AAAA;ECmFY;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,aAfa;;ADzEzB;AAAA;EC4FQ;EACA;EACA,QA3BW;EA4BX;EACA;EAGA,axChIoB;EwCiIpB;EACA,aD3HQ;EC4HR;EACA,axCrGiB;EwCsGjB,iBDlIY;;AZ+BnB;AAAA;EACC,SAHwB;EAIxB;;AYPF;AAAA;EC+GQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;;A+BgB5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAKF;AAAA;AAAA;AAAA;EAEE;;;AAKJ;AAAA;EACE,W9BjB0B;;A8BmB1B;EAHF;AAAA;IAII;;;;AAIJ;ECuFQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBrC3JQ;EqC4JR,OpCtJgB;EoCuJhB,cDvJS;ECwJT;EACA,crC/JQ;EqCiKJ,etC/JY;;AsCmKhB;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OpCnKY;EoCoKZ,cDpKK;ECqKL;EACA,cA5GS;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OpC9KY;EoC+KZ,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;EACI,OpCtLY;EoCuLZ,iBDzLQ;;AC6LZ;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;AAqBJ;EACI,kBpC1MQ;EoC2MR,cD3Je;EC4Jf;EACA,crClOI;EqCmOJ,OrCjMI;;;AoC2ChB;ECgEQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBpC5IY;EoC6IZ,OpC/Ie;EoCgJf,cDvJS;ECwJT;EACA,cpC9IgB;EoCgJZ,etC/JY;;AsCmKhB;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OpC5JW;EoC6JX,cDpKK;ECqKL;EACA,cA5GS;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OpCvKW;EoCwKX,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;EACI,OpC/KW;EoCgLX,iBDzLQ;;AC6LZ;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;AAqBJ;EACI,kBpC1MQ;EoC2MR,cDpIe;ECqIf;EACA,cpCjNY;EoCkNZ,OrCjMI;;;AoC6DhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECkBY;EACA;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,aAfa;;ADRzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EC2BQ;EACA;EACA,QA3BW;EA4BX;EACA;EAGA,axChIoB;EwCiIpB;EACA,aD3HQ;EC4HR;EACA,axCrGiB;EwCsGjB,iBDlIY;;AZ+BnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC,SAHwB;EAIxB;;AY0DF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EC8CQ,YpC/GmB;EoCmHf,WpCnHe;EoCqHnB,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBrC5HU;EqC6HV,OrC5JQ;EqC6JR,cDvJS;ECwJT;EACA,crChIU;EqCkIN,etC1JuB;;AsC8J3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OrCzKI;EqC0KJ,cDpKK;ECqKL;EACA,crC5KI;;AqCgLR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OrCpLI;EqCqLJ,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,OrC5LI;EqC6LJ,iBDzLQ;;AC6LZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;AAqBJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,kBA/IW;EAgJX,cAvIe;EAwIf;EACA,crCnMM;EqCoMN,OAlJa;;ADyBvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA,kBpCxFS;;AoC0FX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;;;AAKF;AAAA;AAAA;EAGE,a/BrGuB;;;A+BoH3B;EACE;EACD;EACA;EACC;EACA;EACA,avC7GuB;EuC8GvB,OpC9Ic;;AoCgJd;EAKE;ExCpFF,oBwCqFE;ExCpFM,YwCoFN;;AAEF;EAGE;;AAEF;EACE,OpC9GkB;EoC+GlB,iBvCtHuB;EuCuHvB;;AAEF;EAEE,kBnCjIiB;EmCkIjB,OnCnIoB;EmCoIpB;EACA,Q9BvIc;;A8BwId;EACE;;AAGJ;EACE,OpC3IY;EoC4IZ,kBpC/Ic;;;AoCyJlB;AAAA;EC3CQ,YDtHiB;ECwHb;EAIJ,WxCzIe;EwC2If;EACA,KhCnJoB;EgCwJpB,kBrC/HY;EqCgIZ,OrC1HQ;EqC2HR,cDvJS;ECwJT;EACA,crCnIY;EqCqIR,etC/JY;;AsCmKhB;AAAA;EACI,iBDlKQ;ECoKR,kBrCzIM;EqC0IN,OrCvII;EqCwIJ,cDpKK;ECqKL;EACA,crC7IM;;AqCiJV;AAAA;EAGI,kBAvGU;EAwGV,OrClJI;EqCmJJ,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;AAAA;EACI,OrC1JI;EqC2JJ,iBDzLQ;;AC6LZ;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;;AAyHd;AAAA;EACI,kBrChMM;EqCiMN,cDhBe;ECiBf;EACA,crCtMQ;EqCuMR,ODrBa;;ACqCb;AAAA;EACI;EACA;EACA,KhCnPY;EgCoPZ;;AAGJ;AAAA;EACI;;AbrLf;AAAA;EACC;EACA,QAJwB;EAKxB;;;AYoJA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE,eD/LuB;;ACgMvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;;;AAQN;EC7FQ,YDtHiB;EC0Hb,WD1Ha;EC4HjB,WxCvIc;EwCyId;EACA,KhCtIsB;;;A+BkO9B;ECrGQ,YDyGe;ECrGX,WDqGW;ECnGf,WxC7Ie;EwC+If;EACA,KhCtIsB;;;A+B4O9B;EACE;;;AAGF;EACE;;;AAOF;EACC;EACC,kBnCvOmB;EmCwOnB,cnCvOuB;;AmCwOvB;EACE,kBnC1OiB;EmC2OjB,cnC1OqB;;AmCoOzB;EAQC;EACA;EACA;;;AAGD;EACE;EACA,avCrPuB;EuCsPvB;EACA,OpCvQuB;EoCwQvB;EACA;;AAEA;EAEE,OpClRe;EoCmRf;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;;AEzSF;EACI;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AArCR;ED0IQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBrC3JQ;EqC4JR,OrCvIK;EqCwIL,cDvJS;ECwJT;EACA,crC/JQ;EqCiKJ,etCzJuB;;AsC6J3B;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OrCpJC;EqCqJD,cDpKK;ECqKL;EACA,cA5GS;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OrC/JC;EqCgKD,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;EACI,OrCvKC;EqCwKD,iBDzLQ;;AC6LZ;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;AAqBJ;EACI,kBpC1MQ;EoC2MR,cC3KmB;ED4KnB;EACA,crClOI;EqCmOJ,OrCjMI;;;AuCehB;EACE;EACA;EACA,QA3CqB;EA4CrB,cA3CsB;EA4CtB,eA5CsB;EA6CtB,eA3C4B;EA4C1B;;;AAGJ;EACE;EACA,KA5CkC;EA6ClC,MAzC4C;EA0C5C,OA7C0B;EA8C1B,QA9C0B;EA+C1B,eArD4B;EAsD5B,oBA/CgC,uBA+CsB;EACtD,YAhDgC;;;AAoDhC;EACE,YAnEoC;EAoEpC;;AACA;EACE;EACA,KApD4B;EAqD5B,MApDiC;EAqDjC,a1C5CmB;E0C6CnB,W1CvEgB;E0CwEhB,OvC3DO;;AuC6DT;EACE,MA/DuC;EAgEvC,YvC/DO;EuCgEP;;AAGJ;EACE,YxC5FmB;EwC6FnB;;AACA;EACE;EACA,KArE4B;EAsE5B,MApEkC;EAqElC,a1C7DmB;E0C8DnB,W1CxFgB;;A0C0FlB;EACE,YvC9EO;EuC+EP;;AAGJ;EACE,YvCtFqB;EuCuFrB;;AACA;EACE,YvC9Fa;EuC+Fb;;;AAOJ;EACE,QlCpHuB;;AkCsHzB;EACE,W1C/GkB;;;A0CmHtB;EACE;;AAEA;EACE;EACA,elChH0B;;;AmCC9B;EACC;EACA;EACA;EACA;EACA,QCtBiB;EDuBjB,eARuB;EASvB,YCzBiB;;AD2BjB;EACC;EACA;;AAEA;EACC;;AAIF;EACC;EACA;EACA;;AArBF;AAwBC;;AACA;EACC;;AAGD;EACC,W3CrCqB;;A2CwCtB;EACC;EACA,W3C5CoB;E2C6CpB,ezC7CiC;;AyC+CjC;EACC;;AAGD;EACC;;AAGF;EACC,YxCxDiB;EwCyDjB,QnC9D0B;EmC+D1B;;AAED;EACC;EACA,QnCnE0B;EmCoE1B;;AAGD;EACC;EAGA;EACA;;AAEA;EACC;;AAKA;EACC,a3CxDqB;E2CyDrB,OxChDkB;EwCiDlB,anCvFwB;;AmC4F3B;EACC;EACA;;AAEA;EACC;EACA;;AAGK;EACI,OxCzGI;;AwC4Gd;EACC;EACA;;AAEA;EACC;;AAKF;EACC;EACA;;AAGC;EACC;EACA;EACA;EACA,QAvHgC;EAwHhC;EACA;;AAEA;EACC;EACA;EACA;;;AAQN;EACC,kBxCtHiB;;;AwCyHlB;EAEE;IACC;IACA;;EAEA;IACC;;;AAMJ;AACA;EACC;IACC,WAtJqB;IAuJrB;IACA;;;AEnKF;AACA;AACA;AACA;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE,W7CpBqB;E6CqBrB;EACA,O1CMc;E0CLd;EACA,kBC/B0B;EDgC1B;EACA;EACA;;;AAGF;EACE,OCvC2B;EDwC3B,kB1CtCc;;;A0CyChB;AACA;AACA;AACA;EACE;EACA;;AAEA;EACE,OCdgC;;ADiBlC;EACE;EACA,WClD+B;EDmD/B,WCjD+B;EDkD/B;EACA;;AAEA;EACE;EACA;EACA,WC1D6B;ED2D7B,YCzD6B;;AD2D7B;EACE,QClD0B;EDmD1B;EACA,cC5DiC;ED6DjC;;AAGF;EACE;EACA;;AAGA;EACE,cClEkC;;ADsEpC;EACE,cCrEiC;;ADyErC;EACE,QChE4B;;ADkE9B;EACE,QCrEyB;;ADuE3B;EACE,QCpE4B;;ADsE9B;EACE,QCrEwB;;ADwE1B;EACE;;AAGA;EACE,W7CnGa;E6CoGb,a7CxEe;E6C0Ef,MC9EgC;;ADgFlC;EACE;EACA,MClFgC;;ADoFlC;AAAA;EAEE;EACA,MCrF+B;;ADyFnC;EAEE;;AAEA;EACE,QC1GmC;ED2GnC;;AAEF;EACE,MChH4B;EDiH5B;;AAIJ;EACE;;AAOJ;EACE,WC1GkC;ED2GlC,WCzGkC;;AD2GlC;EACE,WC9GgC;ED+GhC,YC7GgC;;AD+GhC;EACE,QC1G6B;ED2G7B,cC/IoC;;ADkJtC;EACE,cCnJoC;;ADsJtC;EACE,QC/G+B;;ADiHjC;EACE,QChH4B;;ADmH9B;EACE,QCxHiC;EDyHjC;EACA,cC9HwC;ED+HxC;EAEA;;AAEF;EACE;;;AAQV;AACA;AACA;AACA;EACE,arCxL4B;EqCyL5B,gBrCzL4B;;;AqC4L9B;EACE,arC7L4B;EqC8L5B,gBrC9L4B;;;AuCa9B;EACE;EACA,W/CbqB;E+CcrB,aAjBuB;EAkBvB;EACA;EACA;EACA;EACA,O5CJW;E4CKX;EACA,e7CpBiC;;A6CqBjC;EACE;;;AAIJ;EACE;EACA,W/CzBqB;;;A+C4BvB;EACE,SAtCmB;EAuCnB;EACA,KA1BgC;EA2BhC,kB5ClCiB;;;A4CoCnB;EACE,SA5CmB;EA6CnB;EACA,QAtCkC;EAuClC,kB5C9BuB;;;A4CkCvB;EACA,aAlDuB;EAmDvB,W/ChDqB;E+CiDrB,SAtDmB;EAuDnB;;;AC3DA;EACE;EACA;EACA,exCS0B;;AwCP1B;EACE,cxCgBqB;EwCfrB,exCeqB;EwCdrB,exCFsB;;AwCMtB;EACE;;AAGF;EACE;;;AAMR;EAEE;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AC1BJ;EACC;EACA;;;AAGD;AAAA;EAEC;EACA;EACA;EACA;;;AAGD;EACC;;;AAED;EACC;;;AAGD;EACC;EACA;EACA,kB9CLY;E8CMZ;EACA,WjDpBqB;EiDqBrB,ajDHsB;EiDItB,O9CIe;;;A8CDhB;EACC;;;AAGD;EACC;EACA,czCvB6B;EyCwB7B,ezCxB6B;;;A0Cb9B;EACC;EACA,eCF2B;EDG3B,Y/CeY;E+CdZ;EACA,e1CW0B;E0CV1B;;AACA;EACC;EACA,ehDNgC;EgDOhC,kB/CYgB;E+CXhB;;;AAIF;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA,YChC0B;;;ADmC3B;EACC;EACA,kBCnCsB;;;ADsCvB;EACC,WlD/BsB;;;AkDkCvB;EACC;;;AAID;AAAA;EAEC;;;AErDG;EACI;EACA,qBACI;EAQJ;EACA,kBjDWK;EiDVL;;AACA;EACI;;AAIR;EACI;EACA,WpDLiB;;AoDQrB;EACI;EACA;EACA;;AACA;EACI;;AAKJ;EAGI;;AAEJ;EACI;;AAEJ;EACI;;AAVR;EAYI;;AAGJ;EACI;EACA,apDdiB;EoDejB,WpDjCkB;;AoDoCtB;EACI;EACA,WpDxCiB;;AoD2CrB;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EAGI;;AAGJ;EACI;EACA;EACA;EACA;;;ACnER;EACC,enDjBgB;;;AmDoBjB;EACC;EACA;EACA,S7ChB8B;;A6CkB9B;EACC,WrDhBqB;EqDiBrB;;AACA;EACC;EACA,arDToB;;AqDWpB;EACC;;AAKH;EACC;;AAGD;EACC;;AAGD;EACC;EACA,SA7CwB;EA8CxB,QA7CuB;EA8CvB;EACA;EACA,eA/C8B;;AAkD/B;EACC;EACA;;AAGD;EACC,SAvD4B;EAwD5B,WrDtDoB;EqDuDpB;;AAGD;EACC,WrD3DoB;EqD4DpB,OlD3BoB;EkD4BpB;;AACA;EACC;;AAIF;EACC,WrDpEoB;EqDqEpB;;AAGD;EACC,WP7EiC;EO8EjC;EACA;;AAIA;EADD;IAEE,a7CrFyB;;;A6CyF3B;EACC;;AAGD;EACC;;AAGD;EACC,SA9FsB;;;AAmGxB;EACC,aAlG4B;;;AAqG7B;EACC;EACA,kBlDvFiB;;AkDyFjB;EACC;EACA,OlDlFc;EkDmFd,WrDzGoB;EqD0GpB,arDtFuB;EqDuFvB,ST1HyB;ES2HzB;;AAGD;EACC;;;AAIF;EACC;;AAEA;EACC;EACA;EACA;;;AAID;EACC,Y7CxI0B;;;A6C4I5B;EAEC;;AAEA;EACC,WrDxIoB;EqDyIpB;EACA;;AAGD;EACC;;AAGD;EAEC;;AAGD;EACC;;;AAKF;EACC;EACA,KA9JmB;;AAgKnB;EACC;EACA;EACA,qBACC;EAID;;AAEA;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;EACA;EACA;EACA,KA3LgB;;;AAgMnB;AACA;EACC;;;AAGD;EAEE;IACC,SAhNuB;IAiNvB;IACA;;EAKD;IACC;;;AC5NC;Ed4JI,kBpC5IY;EoC6IZ,OpC/Ie;EoCgJf,cDvJS;ECwJT;EACA,cpChJY;EoCkJR,etC1JuB;;AsC8J3B;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OpC5JW;EoC6JX,cDpKK;ECqKL;EACA,cA5GS;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OpCvKW;EoCwKX,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;EACI,OpC/KW;EoCgLX,iBDzLQ;;AC6LZ;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;AAqBJ;EACI,kBA/IW;EAgJX,cAvIe;EAwIf;EACA,cpCnNQ;EoCoNR,OAlJa;;AclFrB;EAUI;EACA;;AACA;EACI;;AAEJ;EACI,OnDMC;;AmDJL;EAlBJ;IAmBQ;;;;AAKZ;EACI;EACA;EACA,e9CpByB;;;A8CuB7B;EACI;EACA;;AACA;EACI;;;AAIR;EACI,c9CtB0B;E8CuB1B;EACA;;AACA;EACI,QCxCa;EDyCb,OCzCa;;;ACarB;EACC;EACG;EACA;EAEH;;AAGA;EvDvBG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AuDmBH;EACC;EACA;EACA,WlBD0B;EkBE1B,chDf4B;EgDgB5B;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC,WApDsB;;A7BkEvB;EACC;EACA,QAJwB;EAKxB;;A6BdA;EAEA,QA5DwB;EA6DxB;EACA,QA7DwB;EA8DxB,WA7DuB;;AA+DvB;EAPA;IAQC,QCzEoC;ID0EpC,WC1EoC;;;AD4ErC;EAEC;;AAED;EACC,YlB9BuB;EkB+BvB,kBAtE0B;EAuE1B;EACA,QA7EuB;;A7BqEzB;EACC;EACA,QAJwB;EAKxB;;A6BQA;EACC,OrDhEsB;EqDiEtB,WA/EqB;;AAmFvB;EACC;IACC,ehD5E8B;;EgD6E9B;IACC;;EACA;IACC,chD7EyB;;EgD+E1B;IACC;IACA,chD9EsB;;EgD+EtB;IACC;;EAED;IACC,YhD7FwB;;;;AgDqG9B;EACC,YlBlEyB;EkBmEtB,kBA1GyB;EA2G5B;EAEA,WA9GyB;;AA+GzB;EACC,WAhHwB;;AAyG1B;EASC;EACA;EACA;EAEA,KAzHyB;;AA2HzB;EACC;EACA;;AAGD;EApBD;IAqBE;IACA,KC1IqC;ID2IrC;;EAEA;IACC,OrDtHsB;IqDuHtB,WA5H2B;;EA+H5B;IACC;;EAIA;IACC;IAEA;IACA;IACA,WlBzHwB;IkB0HxB,OhDnJ0B;IgDoJ1B,KhD5I2B;IgD6I3B,axDnIsB;;EwDuIxB;IACC;;EAIA;IACC;;;;AEhKJ;AAAA;AAAA;AAAA;AAAA;AAOA;EACC,YvDUY;EuDTZ;EACA;EACG;EACA;EACA;EACH;EACA;EACA;EACA;EACA;EACA;;AAEC;EACC;;AAKF;EACC;;AAEA;EACC;;AAGA;EACC;EACA;EACA,SCzCqC;;AD0CrC;EACC;EACA;EACA;;AAIF;EACC;;;AAOJ;EACC;EACA;EACA;EACA,SCjEgC;EDkEhC,YpBduC;;;AoBkBxC;EACC;EACA;EACA,YpBjCqC;EoBkCrC;EACA,kBvDjDY;EuDkDZ;EACA;EACA,SCzEqC;ED0ErC,YpB3BuC;;;AoB+BxC;EACC;EACA;EACA;EACA,SCtFoC;;;AD0FrC;EACI;EACA,YvDnES;EuDoET;EACA;EACA,QE7F6B;EF8F7B;EACA;EACA;EACA;;;AAIJ;EACC,QExG8B;EFyG9B;EACA;EACA;EACE;;AACF;EACC;;;AAIF;EACC,a1D7EwB;E0D8ExB;EACA,W1DrGqB;E0DsGrB;EACA;EACA;EACA,OvDnFe;;;AuDsFhB;EACC;;;AAGD;EACC;EACA;EACA,SClIsC;;;ADsIvC;EACC;EACA;EACA;EACA;EACA,OpBzHsB;;AoBgIvB;EACC;EACA;EACA,SCpJiC;;;ADwJlC;EACC;EACA;;;AAID;EACC;;;AAIA;EACC;;AAFF;EAIC;EACA;EACA;;AACA;EACI;EACA;;;AAIJ;EGtJO,gBHuJyC;EGtJzC;;AAuBA;EHiIL;IACC;;;;AAMJ;AAAA;AAAA;AAAA;AAAA;AAOA;EACC;AAAA;IAEC;IACA;;;AAIF;EAEC;IACC,YvDpLW;IuDqLX;IACA;IACA;;EACA;IACC;IACA;IACA,SCnNoC;IDoNpC;;EACA;IACC;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACC;;EAED;IACC;IACA;IACA;IACA;IACA,YpBrLmB;;EoBuLpB;IACC;IACA;IACA;IACA;;EAIH;IACC;IACA;;EACA;IACC;IACA;IACA;IACA;IACA;;EACA;IACC;IACG;IACH;IACA;IACA;IACA;;EACA;IACC,YpBhNkB;;EoBmNnB;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,SC5QmC;;ED6QnC;IACC;;EAIF;IAEC;;EAQL;IACC;IACA;IACA;IACA;;EAID;IACC;IACG,QD3SkC;IC4SlC;IACH,YpBxPsC;;EoB4PvC;IACC,ODhTkC;;ECoTnC;IACC;;EAID;IACC;;EAGD;IACC;;EAEA;IACC;IACA;IACA;IACA;;EAED;IACC;IACA;;EAGD;IACC;IACA;IACA;IACA;IACA,OvD/TgB;IuDgUhB,W1DjUmB;I0DkUnB;IACA;IACA;IACA;IACA;;EACA;IACI;IACA;IACA,W1D1Ue;I0D2Uf,clDzVW;;EkD6VhB;IACC;;EAED;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IAQC,YvDjVU;IuDkVV,cvDlVU;IuDmVV,OvD3VgB;IuD4VhB;;EAGD;IACC;;EAKF;IACC;IACA;;EAID;IACC;IACA;IACA;IACA,YDjYsC;ICkYtC,YA5XyD;IA6XzD;IACA,SCjYgC;;EDqYjC;IACC;IACG;IACH;IACG;;EAGJ;IACC,QD9Y4B;IC+Y5B,OD9Y2B;;ECkZ3B;IACC,QDpZ2B;ICqZ3B,ODpZ0B;;ECsZ3B;IACC;IACA;IACA;IACA;;EAGD;IACI,QD/ZwB;;EC0a7B;IACC;IACA;IACA;IACA;;EAQD;IACC;;EACA;IACC;;EAKF;IACC;;EAGD;IACC;IACA;IACA;IACA,gBDxcsC;;ECyctC;IACC;;EAIF;IACC,epBrcwB;;;AoByc1B;AAAA;AAAA;AAAA;AAAA;AAMA;EACC;IACC;IACA;;EAEA;IACC;IACA;IACA;;EAEA;AAAA;AAAA;AAAA;AAAA;IAKC;;EAGF;IACC;;;AI3eH;EACC;EACA;EACA;EACA,KtDI6B;;AsDD5B;EACC;;AACA;EAFD;IAGE;;;AAMF;EACC;;AAIF;EACC;EACA;;;ACvBF;EACC;;AAEA;EACC;;AAGD;EACC;;AAGD;EACC,O5D0Bc;;;A4DtBhB;AAAA;EAEC;EACA;EACA;EACA;;;ACtBD;EACI;;;AAGJ;EACI,YxDGwB;;;AyDT1B;EACE;EACA;EACA;;;ACKJ;ADRE;EACE;EACA;EACA;;ACMJ;AACqB;EACnB;EACA;;;AAEF;EACE;;;AAEF;ECjBI;EDmBF;EACA;;AACA;EAJF;IAKC;IACA;;;;AAGD;ECtBI;EDwBF,c1DlB4B;E0DmB5B;EACA;;AACA;EALF;IAMC;IACA;;;;AAGD;AACA;EACE;EACA;;;AAEF;EACE,c1DpB4B;E0DqB5B;EACA;;;AAEF;E9BlCC;E8BoCC;EACA;;;AEnCF;EACC;;AACA;EACC,oBxBZgB;EwBahB,YxBbgB;;;AwBmBjB;EACC,kBjEMgB;EiELhB,OjEcc;EiEbd,WpEPuB;EoEQvB,apEUuB;EoETvB,e5DpB0B;E4DqB1B;EACA;;;AAGF;EACC;EACA;;AAEC;EACC,kBA7B2B;EA8B3B;EACA;EACA,OAhC2B;EAiC3B;EACA;EACA;EACA,QArCqB;EAsCrB,aAtCqB;EAuCrB;EACA;EACA;EACA;EACA,OA3CqB;;AA6CtB;EACC;;AAGD;EACC,WpE3CoB;EoE4CpB,apExBuB;;AoE8BxB;AAAA;EACC;EACA,kBjEzCU;EiE0CV;;AAGA;AAAA;EACC,kBjEjDqB;;AiEmDtB;AAAA;EACC,OAhEiC;;AAoElC;AAAA;EACC,OArEiC;;AAwEnC;AAAA;EACC,OAzEkC;;AA6EnC;EACC;;AAMD;AAAA;EACC,kBjEzEsB;;AiE6EvB;EACC;;AAID;EACC;;AAMD;AAAA;AAAA;EACC,kBjE5Ga;;AiEiHd;EACC;EACA;EACA;EACA,WpEvGsB;;AoEyGvB;EAEI;EACH,kBjE1Ha;;AiE6Hb;AAAA;EAEC,OjE/HY;EiEgIZ,WpEpHkB;EoEqHlB,apEjGqB;;AoEsGxB;EACC;EACA;EACA;EACA;;AACA;EACC;;AAGF;AAAA;EAEC,OjE/Gc;EiEgHd,WpEtIoB;EoEuIpB,apEnHuB;EoEoHvB;;;AAIF;EAEC,QxB1JiB;EwB2JjB,elEnJkC;EkEoJlC,oBxB7JiB;EwB8JjB,YxB9JiB;;AwBgKjB;EACC,kBjEvIgB;EiEwIhB;EACA,SxBrKyB;;AwBuKzB;EACC;EACA;EACA,OjErIa;EiEsIb,WpE1JsB;EoE2JtB,apEjJqB;EoEkJrB,apExIsB;;AoE4IxB;EACC;;;ACtLF;EACI;EACA;;;ACSH;EACC;;AAMA;AAAA;AAAA;EAEE;EACA,WhCewB;;AgCb1B;AAAA;EACE;;AAEF;AAAA;EACE;;AAEF;AAAA;EACC;;AAGF;AAAA;EAEC;;AAGD;EACC,kBnEPgB;;AmEWhB;EACC,S9DjC2B;;A8DoCzB;EACC;EACA;EACA,WhCbqB;EgCcrB;;AANH;EASC;EACA;EACA;EACA,oBnEzBc;EmE0Bd,S9D/C0B;E8DiD1B;EAEA;;AAUA;EACC;EACA;EACA,WhCtCsB;;AgC8CzB;EACC;EACA;EACA;EACA;EACA;;;AAUD;AAAA;EAEC,kBnEpEe;;AmEwEhB;AAAA;EAEC;;AAID;AAAA;EAEC;;;AAMF;EACC;EACA;EACA;;AACA;EACC;;AAGF;EACC;;AAED;EACC;;AAED;EACC,SA7HsB;;AA+HvB;EACC;;AAGD;AAAA;EAEC;;;AAMD;AAAA;EACC;;;AAIF;EACC;;AACA;EACC;;AAED;EACC;EACA;EACA;;;AAKF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACC;;AAED;EACC,kBnErJW;EmEsJX;EACA;EACA;EACA;EACA;;AACA;EACC;;AAED;EACC,kBnE/JU;EmEgKV;;AAED;EAEC;;;AAQH;EAEE;IACC;IACA;;EAED;IACC;;EAED;IACC;;;Ad5LH;EACC;EACG;EACA;EAEH;;AAGA;EvDvBG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AuDmBH;EACC;EACA;EACA,WlBD0B;EkBE1B,chDf4B;EgDgB5B;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC,WApDsB;;A7BkEvB;EACC;EACA,QAJwB;EAKxB;;A6BdA;EAEA,QA5DwB;EA6DxB;EACA,QA7DwB;EA8DxB,WA7DuB;;AA+DvB;EAPA;IAQC,QCzEoC;ID0EpC,WC1EoC;;;AD4ErC;EAEC;;AAED;EACC,YlB9BuB;EkB+BvB,kBAtE0B;EAuE1B;EACA,QA7EuB;;A7BqEzB;EACC;EACA,QAJwB;EAKxB;;A6BQA;EACC,OrDhEsB;EqDiEtB,WA/EqB;;AAmFvB;EACC;IACC,ehD5E8B;;EgD6E9B;IACC;;EACA;IACC,chD7EyB;;EgD+E1B;IACC;IACA,chD9EsB;;EgD+EtB;IACC;;EAED;IACC,YhD7FwB;;;;AgDqG9B;EACC,YlBlEyB;EkBmEtB,kBA1GyB;EA2G5B;EAEA,WA9GyB;;AA+GzB;EACC,WAhHwB;;AAyG1B;EASC;EACA;EACA;EAEA,KAzHyB;;AA2HzB;EACC;EACA;;AAGD;EApBD;IAqBE;IACA,KC1IqC;ID2IrC;;EAEA;IACC,OrDtHsB;IqDuHtB,WA5H2B;;EA+H5B;IACC;;EAIA;IACC;IAEA;IACA;IACA,WlBzHwB;IkB0HxB,OhDnJ0B;IgDoJ1B,KhD5I2B;IgD6I3B,axDnIsB;;EwDuIxB;IACC;;EAIA;IACC;;;;AevKJ;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;ACKA;EvEDI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAQA;EAEE;EACA;EACA;EACA;EACA;EACA;;;AwEeN;EACC,YnCMyB;;;AmCKzB;AAAA;AAAA;AAAA;AAAA;AAAA;EAEC,QnCtCsB;EmCuCtB,OnCtCqB;;;AmC6CtB;AAAA;AAAA;AAAA;AAAA;AAAA;EAEC,SA3DuB;EA4DvB;EACA,eAxDsB;EAyDtB,evE/DsB;EuEgEtB;EACA;EACA,KjElDuB;EiEmDvB,WzE/DqB;EyEgErB;;A9CAD;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA,QAJwB;EAKxB;;A4CnED;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AEmDA;AAAA;AAAA;AAAA;AAAA;AAAA;AFhDD;;AACA;EACC;AAAA;AAAA;AAAA;AAAA;AAAA;IACC;IACA;IACA;IACA,oBE2C4C;IF1C5C;;EAGD;AAAA;AAAA;AAAA;AAAA;AAAA;IACC;;;AEqCD;AAAA;AAAA;AAAA;AAAA;AAAA;AFjCD;;AACA;EACC;AAAA;AAAA;AAAA;AAAA;AAAA;IACC;IACA;IACA;IACA,iBE4B4C;IF3B5C;;EAGD;AAAA;AAAA;AAAA;AAAA;AAAA;IACC;;;AEsBD;AAAA;AAAA;AAAA;AAAA;AAAA;EAEC;EACA;EACA;EACA;EACA;;;AAWF;EAEC;EACA;EACA;EACA;;AAKD;AAAA;EAEC,YtExFiB;;AsEyFjB;AAAA;EACC,OtElFU;EsEmFV;;AAED;AAAA;EACC,QCvG0B;;ADwG1B;AAAA;EACC,OAnG2B;EAoG3B,QApG2B;;AAyH7B;AAAA;EAbC;EACA;;AACA;AAAA;EACC;;AAED;AAAA;EACC;;AAED;AAAA;EACC;;AAOF;AAAA;EAhBC;EACA;;AACA;AAAA;EACC;;AAED;AAAA;EACC;;AAED;AAAA;EACC;;AAUF;AAAA;EACC;EApBA;EACA;;AACA;AAAA;EACC;;AAED;AAAA;EACC;;AAED;AAAA;EACC;;AAcF;AAAA;EACC,OtEzHU;;AsE4HZ;EACC,YtErIiB;;AsEwIlB;EAGE;AAAA;IACC,kBtE5Ie;IsE6If,OtE7Ie;;EsE8If;AAAA;IACC,QCxJwB;;ED0JzB;AAAA;IACC,OtE1IQ;;EsE6IV;AAAA;IACC,kBtE9IS;IsE+IT,OtEvJe;;EsEwJf;AAAA;IACC,QChKgC;;EDkKjC;AAAA;IACC,OtE5Jc;;;;AsEwKnB;EACC,YnCzIyB;EmC0IzB,YtElKY;EsEmKZ;EACA;;;AAGD;EACC,kBtEhLkB;;;AsEqLlB;AAAA;EACC,enCnKyB;;AmCoKzB;AAAA;EACC,YtE5Ke;;;AsEmLjB;AAAA;EACC;;;AAUF;EACC;;AACA;AAAA;EAEC,kBtEnNiB;EsEoNjB;;AACA;AAAA;EACC,QC1N0B;;AD6N5B;EACC,kBA9MgC;EA+MhC,OtEtNiB;;AsEuNjB;EACC;;;AAOH;EACC;;AACA;EACC;EACA,QnClOsB;EmCmOtB;;AAED;AAAA;EAEC,kBtErPc;EsEsPd,OtEjOW;;AsEkOX;AAAA;EACC,QCpP0B;;ADsP3B;AAAA;EACC;EACA;;AAED;AAAA;EACC,kBA1OmC;;AA2OnC;AAAA;EACC;;AAHF;AAAA;EAKC,OtEtPgB;;AsEuPhB;AAAA;EACC;;AAIH;EACC;EACA,cA5P0B;;AA6P1B;EACC;;;AAKH;EACC,kBA/PiC;EAgQjC;EACA,QnCvQuB;EmCwQvB;EAEA;EACA;;;AAKD;EACC;;AACA;AACC;EACA;EACG;EACA;;AAEJ;EACC,OtEvSc;EsEwSX;EACA,azE3QqB;EyE4QxB,QnC5RsB;EmC6RtB;EACA;;;AAMF;EACC;;AACA;EACC,YnC3RkC;EmC4RlC;EACA,YA/SsB;;AAgTtB;ExExTE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AwEoTD;EACC;EACA;EACA;EACA;;AAED;EACC;;;AAMJ;EACC;EACA;EACA;EACA;;;AAGC;EACC;;AAFF;EAIC;;AAEA;EACC;EACA;;;AAQH;EACC;IACI;IACA;IACA;IACA;;EAGJ;IACC,YnCzTsC;;EmC4TvC;IACG;IACA;;EAKF;AAAA;AAAA;AAAA;IAEM;IACH;IACA,QhBzXyB;IgB0XzB,OhBzXwB;;EgB0XxB;AAAA;AAAA;AAAA;IACC,QlB3Xe;IkB4Xf,OlB5Xe;;EkBkYnB;IACC,QhBpY2B;;EgBqY3B;IACC;;EACA;IACC;IACA,QhBzYyB;;;AgBoZ9B;EAOE;AAAA;AAAA;AAAA;AAAA;IACC;;;AzClZH;AAAA;EAEE,ahCR0B;EgCS1B,ahC4BwB;EgC3BxB,ahCcwB;EgCbxB,O7BwBkB;;;A6BtBlB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;EACA,O7BkBgB;;;A6BdpB;AAAA;AAAA;EAGE,YhCHwB;EgCIxB;;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAGJ;AAAA;AAAA;EAGE;EACA;;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAIJ;EAAU,WhC3BW;;;AgC4BrB;EAAU,WhC9BgB;;;AgC+B1B;EAAU,WhCjCe;;;AgCkCzB;EAAU,WhCpCY;;;AgCqCtB;EAAU,WhCvCa;;;AgCwCvB;EAAU,WhC1CY;;;AgCgDtB;EACE;;;AAKF;EACE,O7B/Dc;E6BgEd;EACA;AACA;AAAA;AAAA;AAAA;EAID;AACA;;;AACC;EAEE,O7B1BkB;E6B2BlB,iBhClCuB;;;A2B6B1B;EACC;EACA,QAJwB;EAKxB;;;AKYF;AAAA;EAGE,WhClFqB;;;AgCsFvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AAGvB;EAAuB;;;AACvB;EAAuB;;;AACvB;EAAuB;;;AAGvB;EACE,O7B5FiB;;;A6BqGjB;AAAA;AAAA;AAAA;EAEE;;;AAYJ;EAJE;EACA;;;AAQF;EACE;EACA,ehCjHwB;;;AgCmH1B;AAAA;EAEE,ahCtHqB;;;AgCwHvB;EACE;;;AAEF;EACE;;;AAOF;EACE;EACA;EACA,WhCjJqB;EgCkJrB;;;AAKE;AAAA;AAAA;EACE;;;AAMN;EACE,ehCnJwB;EgCoJxB;EACA,ahCtJqB;;;AgCyJvB;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AACA;EACC;;;AAGD;EACC,ahClKwB;;;AgCqKzB;EACC;EACA,WhCjMqB;EgCkMrB,O7BjKqB;;;A6BoKtB;EACC;;;AAGD;EACC;;;AAGD;EACC;IACC;;;A2CvNF;EACC,kBxEoBY;EwEnBZ,W3EQsB;E2EPtB,OxE+Be;EwE9Bf,YzEJgB;;AyEMhB;EAEC,OxERc;;AwESd;EAEC,OxEqCmB;;AwEjCrB;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA,YCxBmB;EDyBnB;;AAGD;EACC;EACA;EACA;;AAGD;E3C0FC;EACA;E2CzFA;;AAGD;EACC;;AEYE;EFpDJ;IA4CE,W3EpCoB;;E2EqCpB;IACC;;;AECC;EF/CJ;IAmDE,W3EzCqB;;E2E0CrB;IACC;;EAED;IACC;;;;AJ5DH;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AOYA;EACE;EACA;EACA,SANoB;EAOpB;EACA;EACA;EACA;;AAEA;EACE,QAhBkB;EAiBlB;EACA;EACA;EACA;EACA,SAlBkB;;AAqBpB;EACE;EACA;EACA;EACA,kB3EtBe;E2EuBf,2B5ExB+B;E4EyB/B,4B5EzB+B;E4E0B/B,oBCnCe;EDoCf,iBCpCe;EDqCf,YCrCe;EDsCf;EACA,KtExB6B;EsEyB7B,YAnCkB;EAoClB;EACA;;AAEA;EAhBF;IAiBI;IACA;IACA,YrBnDiC;IqBoDjC;;;AAIJ;EAEE,OAhDsB;EAiDtB,W9EzCkB;E8E0ClB;EACA;EACA;EACA;EACA;;AACA;AAAA;AAAA;EAEE,OAzDoB;;APEzB;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AO4CA;APzCD;;AACA;EACC;IACC;IACA;IACA;IACA,oBOoCkC;IPnClC;;EAGD;IACC;;;AO8BD;AP1BD;;AACA;EACC;IACC;IACA;IACA;IACA,iBOqBkC;IPpBlC;;EAGD;IACC;;;AOeD;EAEE;;AAIA;EADF;IAEM,QrB9E+B;;;;AuBIvC;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAoBA;AAGA;AAEA;AAIA;AAEA;AAEA;AAQI;EAEE,oBAnBgC;EAoBhC,iBApBgC;EAqBhC,YArBgC;EAsBhC,kBAZ+C;EAc/C;EACA;EACA;EACA;EAEA,OAbe;;AAef;EACE;;AAEF;EACE,OAnBa;;AACjB;EAEE,oBAnBgC;EAoBhC,iBApBgC;EAqBhC,YArBgC;EAsBhC,kBAXiD;EAajD;EACA;EACA;EACA;EAEA,OAbe;;AAef;EACE;;AAEF;EACE,OAnBa;;AACjB;EAEE,oBAnBgC;EAoBhC,iBApBgC;EAqBhC,YArBgC;EAsBhC,kBAVgD;EAYhD;EACA;EACA;EACA;EAEA,OAbe;;AAef;EACE;;AAEF;EACE,OAnBa;;AAFrB;EAgCE,ahF9CwB;EgF+CxB,axElE0B;EwEmE1B,gBxEnE0B;EwEoE1B;EAIA;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAIA;EACE;;AAGF;EACE,gBAhF4C;EAiF5C,ahFlEmB;EgFmEnB,cxEvGY;;AwE+GhB;EACE;;AAGF;EACE,WhFtGkB;EgFuGlB;EACA;EACA;EACA;;AAEA;EACE,exErHwB;;AwEwH1B;EACE;;AAIJ;EACE;;;AAIJ;AAAA;AAAA;AAAA;AAAA;AAMA;EACE;IACE;;;AAIJ;AAAA;AAAA;AAAA;AAAA;AAMA;EACE;IACE;;;AzC5HJ;AAAA;ECmFY;EACA;;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,aAfa;;;ADzEzB;AAAA;EC4FQ;EACA;EACA,QA3BW;EA4BX;EACA;EAGA,axChIoB;EwCiIpB;EACA,aD3HQ;EC4HR;EACA,axCrGiB;EwCsGjB,iBDlIY;;;AZ+BnB;AAAA;EACC,SAHwB;EAIxB;;;AYPF;AAAA;EC+GQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;;;A+BgB5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;;AAKF;AAAA;AAAA;AAAA;EAEE;;;AAKJ;AAAA;EACE,W9BjB0B;;;A8BmB1B;EAHF;AAAA;IAII;;;AAIJ;ECuFQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBrC3JQ;EqC4JR,OpCtJgB;EoCuJhB,cDvJS;ECwJT;EACA,crC/JQ;EqCiKJ,etC/JY;;;AsCmKhB;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OpCnKY;EoCoKZ,cDpKK;ECqKL;EACA,cA5GS;;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OpC9KY;EoC+KZ,cD/KK;ECgLL;EACA,cA3GU;;;AA+Gd;EACI,OpCtLY;EoCuLZ,iBDzLQ;;;AC6LZ;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;;AAqBJ;EACI,kBpC1MQ;EoC2MR,cD3Je;EC4Jf;EACA,crClOI;EqCmOJ,OrCjMI;;;AoC2ChB;ECgEQ,Y/B1Gc;E+B8GV,W/B9GU;E+BgHd,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBpC5IY;EoC6IZ,OpC/Ie;EoCgJf,cDvJS;ECwJT;EACA,cpC9IgB;EoCgJZ,etC/JY;;;AsCmKhB;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OpC5JW;EoC6JX,cDpKK;ECqKL;EACA,cA5GS;;;AAgHb;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OpCvKW;EoCwKX,cD/KK;ECgLL;EACA,cA3GU;;;AA+Gd;EACI,OpC/KW;EoCgLX,iBDzLQ;;;AC6LZ;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;;AAqBJ;EACI,kBpC1MQ;EoC2MR,cDpIe;ECqIf;EACA,cpCjNY;EoCkNZ,OrCjMI;;;AoC6DhB;AAAA;AAAA;AAAA;AAAA;ECkBY;EACA;;;AAGJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACI,aAfa;;;ADRzB;AAAA;AAAA;AAAA;AAAA;EC2BQ;EACA;EACA,QA3BW;EA4BX;EACA;EAGA,axChIoB;EwCiIpB;EACA,aD3HQ;EC4HR;EACA,axCrGiB;EwCsGjB,iBDlIY;;;AZ+BnB;AAAA;AAAA;AAAA;AAAA;EACC,SAHwB;EAIxB;;;AY0DF;AAAA;AAAA;AAAA;AAAA;EC8CQ,YpC/GmB;EoCmHf,WpCnHe;EoCqHnB,WxC3Ic;EwC6Id;EACA,KhCtIsB;EgC2ItB,kBrC5HU;EqC6HV,OrC5JQ;EqC6JR,cDvJS;ECwJT;EACA,crChIU;EqCkIN,etC1JuB;;;AsC8J3B;AAAA;AAAA;AAAA;AAAA;EACI,iBDlKQ;ECoKR,kBAxGS;EAyGT,OrCzKI;EqC0KJ,cDpKK;ECqKL;EACA,crC5KI;;;AqCgLR;AAAA;AAAA;AAAA;AAAA;EACI,WDjKgB;ECmKhB,kBAvGU;EAwGV,OrCpLI;EqCqLJ,cD/KK;ECgLL;EACA,cA3GU;;;AA+Gd;AAAA;AAAA;AAAA;AAAA;EACI,OrC5LI;EqC6LJ,iBDzLQ;;;AC6LZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;EAoGV;;;AAqBJ;AAAA;AAAA;AAAA;AAAA;EACI,kBA/IW;EAgJX,cAvIe;EAwIf;EACA,crCnMM;EqCoMN,OAlJa;;;ADyBvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA,kBpCxFS;;;AoC0FX;AAAA;AAAA;AAAA;AAAA;EACE;;;AAKF;AAAA;AAAA;EAGE,a/BrGuB;;;A+BoH3B;EACE;EACD;EACA;EACC;EACA;EACA,avC7GuB;EuC8GvB,OpC9Ic;;;AoCgJd;EAKE;ExCpFF,oBwCqFE;ExCpFM,YwCoFN;;;AAEF;EAGE;;;AAEF;EACE,OpC9GkB;EoC+GlB,iBvCtHuB;EuCuHvB;;;AAEF;EAEE,kBnCjIiB;EmCkIjB,OnCnIoB;EmCoIpB;EACA,Q9BvIc;;;A8BwId;EACE;;;AAGJ;EACE,OpC3IY;EoC4IZ,kBpC/Ic;;;AoCyJlB;AAAA;EC3CQ,YDtHiB;ECwHb;EAIJ,WxCzIe;EwC2If;EACA,KhCnJoB;EgCwJpB,kBrC/HY;EqCgIZ,OrC1HQ;EqC2HR,cDvJS;ECwJT;EACA,crCnIY;EqCqIR,etC/JY;;;AsCmKhB;AAAA;EACI,iBDlKQ;ECoKR,kBrCzIM;EqC0IN,OrCvII;EqCwIJ,cDpKK;ECqKL;EACA,crC7IM;;;AqCiJV;AAAA;EAGI,kBAvGU;EAwGV,OrClJI;EqCmJJ,cD/KK;ECgLL;EACA,cA3GU;;;AA+Gd;AAAA;EACI,OrC1JI;EqC2JJ,iBDzLQ;;;AC6LZ;AAAA;AAAA;AAAA;AAAA;AAAA;EAEI,kBpChKS;EoCiKT,cD9LK;EC+LL;EACA,cpClKa;EoCmKb,OpCrKY;EoCsKZ,QAnGU;;;AAyHd;AAAA;EACI,kBrChMM;EqCiMN,cDhBe;ECiBf;EACA,crCtMQ;EqCuMR,ODrBa;;;ACqCb;AAAA;EACI;EACA;EACA,KhCnPY;EgCoPZ;;;AAGJ;AAAA;EACI;;;AbrLf;AAAA;EACC;EACA,QAJwB;EAKxB;;;AYoJA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE,eD/LuB;;;ACgMvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;;;AAQN;EC7FQ,YDtHiB;EC0Hb,WD1Ha;EC4HjB,WxCvIc;EwCyId;EACA,KhCtIsB;;;A+BkO9B;ECrGQ,YDyGe;ECrGX,WDqGW;ECnGf,WxC7Ie;EwC+If;EACA,KhCtIsB;;;A+B4O9B;EACE;;;AAGF;EACE;;;AAOF;EACC;EACC,kBnCvOmB;EmCwOnB,cnCvOuB;;;AmCwOvB;EACE,kBnC1OiB;EmC2OjB,cnC1OqB;;;AmCoOzB;EAQC;EACA;EACA;;;AAGD;EACE;EACA,avCrPuB;EuCsPvB;EACA,OpCvQuB;EoCwQvB;EACA;;;AAEA;EAEE,OpClRe;EoCmRf;;;AAGF;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;;A0CtRF;EACI;EACA;EACA;;AAGA;EACI;EACA;EACA;;AAGJ;EACI,YA1BiB;EA2BjB;;AAGJ;EACI;EAEA;EACA;EACA,Y3C9BgB;E2CgChB,e3CdmB;E2CenB;EACA;EACA;;AAEA;EACI,WjFtCa;EiFuCb;EACA;;AAEJ;EACI;EACA;EACA;;AAGJ;EACI;;AAEJ;EACI;EACA;EAEA;EACA;EACA;EACA;;AACA;EACI;EACA;EACA;EACA;;AtDPf;EACC;EACA,QAJwB;EAKxB;;AsDQM;EACI,cAhEc;;AAiEd;EACI;;AAEJ;EACI;;AASR;EACI;;AAMJ;AAAA;AAAA;AAAA;AAAA;EAKI;;AAGJ;EACI;;AAKJ;AAAA;AAAA;AAAA;EAGI;;AAEJ;EACI;;AAIR;EACI;;AAIA;EACI;;AAKI;AAAA;AAAA;AAAA;AAAA;AAAA;EAGI;;AAIZ;EACI,Y9EnHM;;A8EoHN;EACI;;AAKZ;EAEQ;IACI;;EAEJ;IACI;;EAGA;IACI;;EAEJ;IACI;;EAGR;IACI,cAxJU;;EAyJV;IACI;;EAEJ;IACI;;EAMR;IACI;;EAGI;IACI,kBA7KC;;EA+KL;IACI;;EAGA;AAAA;AAAA;IAGI;IACA,kB9ErKV;I8EsKU;IACA;;EACA;AAAA;AAAA;IACI,kBA3LP;IA4LO,cA5LP;;EAiMD;IACI,kBA3LO;IA4LP,cA5LO;;EA6LP;IACI,kBArMP;IAsMO,cAtMP;;EA0MG;AAAA;AAAA;IAGI;;EAOhB;AAAA;AAAA;AAAA;IAGI;;EAEJ;IACI;;EAGR;IACI;IACA;IACA,Y1CtNS;I0CuNT;IACA;;EAEA;IACI;IACA;;EAIJ;AAAA;IAEI;;EAGR;IACI,YAhPS;;EAkPb;IACI;;EAEA;IACI,Y9EpOF;;E8EuOE;AAAA;AAAA;AAAA;IAGI,kB9E1ON;I8E2OM;IACA;;EACA;AAAA;AAAA;AAAA;IACI,kBAhQH;IAiQG,cAjQH;;;AA0QrB;EACI;;AAEJ;AAAA;AAAA;EAGI,kBAzQ2B;EA0Q3B,cA1Q2B;;AA2Q3B;AAAA;AAAA;EACI,kBAnRa;EAoRb,cApRa;EAsRb;;AAGR;AAAA;EAEI;EACA;EACA,cAxRkB;EA0RlB,e3C5QmB;;A2C+QvB;AAAA;EAEI;EACA;EACA,cAjSkB;EAmSlB,e3CrRmB;;A2CwRvB;EACI,azEtToB;EyEuTpB,gBzEvToB;;;A0EF5B;EACC;EACA,kB/EkBY;E+EhBZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,alFMsB;;;AmF3BrB;EACE;EACA;EACA;;AACA;EACE;;AAEF;EACE;;AAKF;EACE;;AAEF;EACE;;;ACfL;EACC;EACA;EAEA;EACA,Y5EE0B;;A4ED1B;EACC;;AAED;EACC;EACA,Y5EPwB;E4EQxB,c5EVe;E4EWf;EACA;EACA;EACA;;AAED;EACC;EACA;;AAED;EACC;EACA;;;ACzBH;EACC;EACA;EACA;;AACA;EACC;;AACA;EACC;;AAED;EACC;;AACA;EACC,c7ETc;E6EUd;;AAED;EACC;;;ACsBH;EACC;;AAED;EACC,a9ElC0B;E8EmC1B,gB9EnC0B;E8EoC1B;;AAID;EACC;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC,OA3CqC;EA4CrC,QA3CsC;EA4CtC;;AAEA;EACC,OAhDoC;EAiDpC,QAhDqC;EAiDrC,QAhDsC;EAiDtC,kBnF1CU;;AmF6CX;EACS;EACR,QAvDqC;;AA0DtC;EACC,QA3DqC;EA4DrC,SArD0C;;AAwD3C;EACC,kBnFjDiB;;AmFqDnB;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA,OA9E+B;;AAiFhC;EACC;EACA;EACA;EACA,OApFsC;;AAsFtC;EACC;;AAIF;EACC,c9E9GgB;;A8EiHjB;AAAA;EAEC;EACA,QAtFiD;EAuFjD,SAtFkD;;AA2FjD;EACC;;AAIF;EACC;EACA;EACA,OAlGsD;;AAsGxD;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;;AAIF;EACC;EACA;EACA,kBnFxIiB;;AmF0IjB;EACC;;AAEA;EACC,kBnF3IiB;;AmF8IlB;EACC;EACA,OAhKoC;EAiKpC;EACA;EACA;EACA,WtFtKoB;EsFuKpB;;AAEA;EACC,eAhLyC;;AAqL5C;EACC,cArL2C;;;AAyL7C;EACC,QA7KoC;EA8KpC,c9ElMiB;E8EmMjB,gBA7K4C;;AA+K5C;EACC;EACA;EACA;EACA,WtF7LqB;;AsF+LrB;EACC;EACA,kBnF/KiB;;;AmFqLnB;EACC,WtFxMqB;;;AsF6MvB;EACC,kBnF/LiB;EmFgMjB;;AAEA;EACC;EACA;EACA;EACA;EACA,kBnF3MW;EmF4MX,WtFzNoB;EsF0NpB;EACA;EACA;EACA;;;AAIF;EACC,YAlO6C;EAmO7C;EACA,e9E9OiB;E8E+OjB,QAnOyC;EAoOzC,YnFrNiB;;AmFuNjB;EACC,WtFzOoB;EsF0OpB;;AAGD;EACC,QA3OoD;;AA8OrD;EACC,Q9EjP4B;;;A8EqP9B;EACC;EACA;EACA;EACA;;;AAIA;EACC,OnF9NoB;;;AmFkOtB;EACE;EACA,WtFnQqB;EsFoQrB,atF9OuB;EsF+OvB;EACA,OnF9Oc;EmF+Od;EACA,kBnFzPgB;EmF0PhB;EACA;;;AClRF;EACC;EACA;;;AAGD;EACC,WvFEsB;EuFDtB,a/EXiB;;;A+EclB;EACC,WvFHsB;EuFItB,OpFJiB;;;AoFOlB;AAAA;EAEC,OnFgBoB;EmFfpB;EACA;;;AAGD;EACC;EACA,e/EvB2B;E+EwB3B,S/E7BiB;;;A+EgClB;EACC,WvFrBsB;;AuFsBtB;EACC;;AAED;EACC,a/EtCgB;E+EuChB;;AAED;EACC,c/E1CgB;;A+E4CjB;EACC,c/E7CgB;E+E8ChB;;;AAIF;EACC,QClD+B;EDmD/B,kBpFtBmB;EoFuBnB,Y/ErDiB;E+EsDjB;EACA;EACA;;AAEA;EACC,kBrF1D0B;EqF2D1B;EACA;EACA;EACA;EACA;EACA;;AACA;EACC,kBpF7DgB;;AoF+DjB;EACC,kBpF5DgB;;;AsFfnB;AAAA;AAAA;AASA;EACE;EACA;EACA;EACA,KjFNyB;EiFOzB,ejFPyB;;;AiFa3B;AAAA;EAEE,OtFMW;;;AsFHb;EACE,YCpBmB;EDqBnB,QvFpBe;EuFqBf;EACA;EACA,cjFnB4B;EiFoB5B,ejFpB4B;EiFqB5B;;;AAIF;EACE;;;AAGF;EACE;;AAEA;EACE;;;AErCF;AAAA;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACE;;AAEF;AAAA;EACE;;AAGF;AAAA;EACE,YnFZsB;EmFatB;;AAGF;AAAA;EACE;EACA;EACA;EACA;EACA;;AACA;AAAA;EACE;EACA;EACA;EACA,enF1BoB;EmF2BpB;;AACA;AAAA;EACE,cnF5BoB;;AmF8BtB;AAAA;EACE;;AAGJ;AAAA;EACE,anFnCsB;EmFoCtB;;AAIJ;AAAA;EACE,YnF1CsB;EmF2CtB;;AAIF;AAAA;EACE;EACA;;AAEA;AAAA;EACE;;AAEA;AAAA;EACE;EACA;;AAKN;AAAA;EACE;EACA;;AAEA;AAAA;EACE;;AAEA;AAAA;EACE;EACA;EACA,enFvEkB;;AmFgFxB;AAAA;EACE;;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAIE;;AAIF;AAAA;AAAA;AAAA;EAEE;;AAIF;AAAA;EACE;;AAMN;AAAA;EACE;EACA,QzF/Ga;;AyFiHb;AAAA;EACE;;AAGF;AAAA;EACE;;AAGF;AAAA;EACE,YnFvHsB;EmFwHtB;EACA,QzF5HW;EyF6HX;EACA,YAlIY;EAmIZ;;;AAMN;EACE;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;;AAKJ;EACE;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;EAEF;IACE;IACA;IACA;;;AAKJ;EACE;IACE;;EAEF;IACE,YA9Lc;;;ACChB;EACE;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA,OzFEc;;AyFAhB;EACE;EACA,OzFCY;EyFAZ;;AACA;EACE;;AAIF;EACE,OzFOgB;;AyFJlB;EACE;;AAIJ;AAAA;EAEE,OzFHkB;;AyFKpB;EACI;;AAIF;AAAA;AAAA;EAGE,QnF7BY;EmF8BZ,OzF5CmB;;AyF+CrB;EACE;;AAIJ;EACE;EACA;EACA,kBzF1Cc;;AyF4ChB;EACE;EACA,kBzF3DqB;EyF4DrB;;;AClFJ;EACE;EACA;EACA;;AAEA;EACE;EACA;;AACA;EACE;;AAEF;EACE;EACA,W7FKmB;E6FJnB,a7FwBmB;;A6FpBvB;EACE;EACA;;AAGF;EAEE;;AAGF;EACE,YrFrB0B;EqFsB1B;EACA;;;AClCJ;EACC;;;ACkBD;AAAA;EAEC;EACA;;AAEA;AAAA;EACC;EACA;EACA;;AACA;AAAA;EACC;;AACA;AAAA;EACC,YvFrBwB;;AuFkB1B;AAAA;EAKC;EACA,kB5FFe;;A4F1BjB;AAAA;AAAA;EAEE,YA2BiC;EA1BjC,kB5F0BiB;;A4FxBlB;AAAA;AAAA;AAAA;EAEC;EACA;;AAyBF;AAAA;EACC;;AAGD;AAAA;EACC;;AAzBF;AAAA;EA4BC;EACA;EACA;EACA;;AACA;AAAA;EACC;EACA;EACA;;;AAMD;EACC;;AAIA;EACC;;AA5DF;EAEE,YA4DgC;EA3DhC,kBA2DsC;;AAzDvC;AAAA;EAEC;EACA;;;AA0DH;EACC;;AAKA;EACC;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;;AAGD;EACC;EACA;;;AlBtCC;EkB4CH;AAAA;IAEC;IACA;;EAIA;AAAA;IACC;IACA;;;AAOH;AAAA;EAEC;;AACA;AAAA;EACC;;;AdzFF;EACI;EACA;EACA;;AAGA;EACI;EACA;EACA;;AAGJ;EACI,YA1BiB;EA2BjB;;AAGJ;EACI;EAEA;EACA;EACA,Y3C9BgB;E2CgChB,e3CdmB;E2CenB;EACA;EACA;;AAEA;EACI,WjFtCa;EiFuCb;EACA;;AAEJ;EACI;EACA;EACA;;AAGJ;EACI;;AAEJ;EACI;EACA;EAEA;EACA;EACA;EACA;;AACA;EACI;EACA;EACA;EACA;;AtDPf;EACC;EACA,QAJwB;EAKxB;;AsDQM;EACI,cAhEc;;AAiEd;EACI;;AAEJ;EACI;;AASR;EACI;;AAMJ;AAAA;AAAA;AAAA;AAAA;EAKI;;AAGJ;EACI;;AAKJ;AAAA;AAAA;AAAA;EAGI;;AAEJ;EACI;;AAIR;EACI;;AAIA;EACI;;AAKI;AAAA;AAAA;AAAA;AAAA;AAAA;EAGI;;AAIZ;EACI,Y9EnHM;;A8EoHN;EACI;;AAKZ;EAEQ;IACI;;EAEJ;IACI;;EAGA;IACI;;EAEJ;IACI;;EAGR;IACI,cAxJU;;EAyJV;IACI;;EAEJ;IACI;;EAMR;IACI;;EAGI;IACI,kBA7KC;;EA+KL;IACI;;EAGA;AAAA;AAAA;IAGI;IACA,kB9ErKV;I8EsKU;IACA;;EACA;AAAA;AAAA;IACI,kBA3LP;IA4LO,cA5LP;;EAiMD;IACI,kBA3LO;IA4LP,cA5LO;;EA6LP;IACI,kBArMP;IAsMO,cAtMP;;EA0MG;AAAA;AAAA;IAGI;;EAOhB;AAAA;AAAA;AAAA;IAGI;;EAEJ;IACI;;EAGR;IACI;IACA;IACA,Y1CtNS;I0CuNT;IACA;;EAEA;IACI;IACA;;EAIJ;AAAA;IAEI;;EAGR;IACI,YAhPS;;EAkPb;IACI;;EAEA;IACI,Y9EpOF;;E8EuOE;AAAA;AAAA;AAAA;IAGI,kB9E1ON;I8E2OM;IACA;;EACA;AAAA;AAAA;AAAA;IACI,kBAhQH;IAiQG,cAjQH;;;AA0QrB;EACI;;AAEJ;AAAA;AAAA;EAGI,kBAzQ2B;EA0Q3B,cA1Q2B;;AA2Q3B;AAAA;AAAA;EACI,kBAnRa;EAoRb,cApRa;EAsRb;;AAGR;AAAA;EAEI;EACA;EACA,cAxRkB;EA0RlB,e3C5QmB;;A2C+QvB;AAAA;EAEI;EACA;EACA,cAjSkB;EAmSlB,e3CrRmB;;A2CwRvB;EACI,azEtToB;EyEuTpB,gBzEvToB;;;AwFWtB;AAAA;EAEE;;AAON;EAME;EACA;EACA;EACA;EACA;EACA,KxF/BwB;EwFgCxB;EACA;EACA;EACA;;AAKA;EAIE;;AAEA;EACE,cfrCiB;;AeyCrB;EAEE;EACA;;ArEaL;EACC;EACA,QAJwB;EAKxB;;AqEbE;ExDiFI,YDtHiB;EC0Hb,WD1Ha;EC4HjB,WxCzIe;EwC2If;EACA,KhCnJoB;EgCwJpB,kByC/Ie;EzCgJf,OrC1HQ;EqC2HR,cDvJS;ECwJT;EACA,cyCnJe;EzCqJX,etC/JY;;AsCmKhB;EACI,iBDlKQ;ECoKR,kByC3Ja;EzC4Jb,OrCvII;EqCwIJ,cDpKK;ECqKL;EACA,cyC/Ja;;AzCmKjB;EAGI,kBAvGU;EAwGV,OrClJI;EqCmJJ,cD/KK;ECgLL;EACA,cA3GU;;AA+Gd;EACI,OrC1JI;EqC2JJ,iBDzLQ;;AC6LZ;AAAA;EAEI,kBA/HY;EAgIZ,cD9LK;EC+LL;EACA,cAhIgB;EAiIhB,OAlIc;EAmId,QAnGU;;AAyHd;EACI,kBA/IW;EAgJX,cAvIe;EAwIf;EACA,cyCtNW;EzCuNX,OAlJa;;AwDrBrB;EAmBE,e1D/CqB;E0DgDrB;EACA;EACA;;AAEA;EACE;;AAIJ;EACE;;AAGF;EACE;;AAGF;EAEE;IACE,YfvFiB;;Ee0FnB;IACE;;EAIA;IACE,YfhGe;;EemGf;IACE,kB7FlFM;I6FmFN;IACA;;EACA;IACE,kBfxGW;IeyGX,cfzGW;;EeiHf;IACE,kBflHa;;EeqHb;IACE;IACA,kB7FrGI;I6FsGJ;IACA;;EACA;IACE,kBf3HS;Ie4HT,cf5HS;;EeiIb;IACE,kBf3HqB;Ie4HrB,cf5HqB;;Ee6HrB;IACE,kBfrIS;IesIT,cftIS;;Ee8IjB;IACE;;EAMI;IACE;;EAKA;IACE;;;;ACnIlB;EACE,ezF9B4B;;AyFgC5B;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;EACE;;AAGF;AAAA;EACE;;AAGJ;EACE,YzF/C0B;;;AyFoD9B;EACE;EACA;EACA;EAIA,YzF3D4B;;AyF4D5B;EACE;;AAGF;EACE;EACA;EACA,ezFxE0B;;AyF0E1B;EACE,czF/EqB;;AyFmFzB;EACE;;AAGF;EACE;;AAGF;EACE;;ApB7CA;EoBcJ;IAmCI;IACA;;EAIA;IACE,YzFtGqB;;;;AyF+GzB;EACE;EACA,kB9FxFc;;A8F0FhB;EACE;EACA,kB9FtFc;;;A8F2FhB;EACE,YzFxHwB;EyFyHxB;;AAEF;EACE,kB9F5DiB;E8F6DjB;;AAEF;EACE,YzFpHwB;EyFqHxB,WjG5HkB;;AiG8HpB;EACE,YzFxHwB;;AyFyHxB;EACE;;AAHJ;EAKE;;AAEF;EACE;EACA,czFjJc;;AyFmJhB;AAAA;EAEA,QPpJmB;EOqJnB;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;EACA,WjGrJkB;;AiGuJpB;AAAA;EAEE;EACA,WjG1JkB;;AiG4JpB;EACE;;;AChKH;EACC,YANyB;;AAQ1B;EACC,YARmC;EASnC,kB/FegB;E+FdhB;EACA,WlGJoB;EkGKpB,O/F4BoB;;;AgGPtB;AAAA;EAEC;EACA;EpG4BC,oBoG3BD;EpG4BS,YoG5BT;;AAGC;AAAA;EACC,kBhG7BgB;EgG8BhB,OhGtBU;;AgGuBV;AAAA;EACC,qBhGxBS;;AgG0BV;AAAA;EACC;;AAED;AAAA;EACC;;AAED;AAAA;EACC,OhGjCS;EgGkCT;;AAGF;AAAA;EACC,OhGtCU;EgGuCV,kBhG/CgB;EgGgDhB;;;AAWH;EACC;;;AAIC;EACD;EACA;EACA;EACA;EACA;EACA,SA/E0B;EAgF1B;EACA;EACA;EAKA;;AAGA;EACC;EACA,qBAvE0B;EAwE1B;EACA;;AAED;EpGkCC;EACI;EACC;EACG;EAkER;EACG;EACE;EACG;;AoGtGT;EpG8BC;EACI;EACC;EACG;;AoG7BR;EACC,kBhGhGgB;EgGiGhB,OhGzFU;;AgG0FV;EACC,qBhG3FS;;AgG6FV;EACC;;AAED;EACC;;AAED;EACC,OhGpGS;EgGqGT;;AAGF;EACC,OhGzGU;EgG0GV,kBhGlHgB;EgGmHhB;;;AAID;EACD;EACA;;;AAIC;EACD;EACA;EACA;;;AAIC;EACD;EACA,kBA5I8C;EA6I9C;EACA;EACA;EACA,ejGpJwB;EiGuJxB;;;AAGC;EACC;;;AAID;EACD;EACA;EACA;EACA;EACA;EACA,SArK0B;EAsK1B,kBC/K6B;;ADiL7B;EpGqDC;EACA,SoGtDyB;;AAC1B;EpGoDC;EACA,SqGnO4B;;;ADiL5B;AAAA;AAAA;AAAA;AAAA;AAAA;EAMC,SAjKmB;;AlC1BpB;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;EACA;;;AkC8LF;EACD;;;AAGC;EACD;;;AAIC;EACD,WnGzLqB;EmG0LrB;EACA,anGlLsB;EmGmLtB;;;AAKC;EACD;;AAGG;EACC;;;AAMH;EACD;EACA;;AlChOC;EACE;EACA;EACA;;AkCiOH;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;;AAKD;EACD;EACA;EACA;EACA;EACA;;;AAOA;EAEC;IACC,OA3OkC;IA4OlC;;EAED;IpG9LA,oBoG+LC;IpG9LO,YoG8LP;;EAID;IAAmB,OAlPgB;;;AAqPpC;EACC;IAAmB,OAvPgB;;;AtB8BjC;EsB+NJ;IAEE;IACA;IACA;IACA;;;AAED;AAAA;AAAA;EAEC;EACA;;AACA;AAAA;AAAA;EACC;EACA;;AAED;AAAA;AAAA;EACC;EACA;;AtBhPC;EsBkPF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;IAEE;IACA;IACA;IACA;;;;AAUA;EACC;;AAED;EACC;;;AAOH;EACC,e3FhT4B;;A2FkT3B;EACC;EACA;EACA;;AAED;EACC;EACA;EACA;EACA;EACA,OhG/RiB;EgGgSjB,c3FzTyB;;;A6FhB9B;EACE;EACA,QnGFe;EmGGf,enGIiC;EmGHjC,kBlGiBW;EkGhBX;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA,K7FL4B;E6FM5B,a7FVyB;E6FWzB,kBlGIS;EkGHT,YApBuB;EAqBvB;;AAEA;EACE;EACA;EACA;EACA,K7FrBwB;E6FsBxB;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAEA;EACE;;AAIJ;EACE;;AxBIJ;EwB1BA;IA0BI;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;AAGF;EACE;;AAIN;EACE;;AxBpBA;EwBsBF;IAEI;;;;AAMJ;EACE,K/D3CkC;;;AgE5BtC;EACC,etGcyB;EsGbzB,Q1DTiB;E0DUjB,epGFkC;EoGGlC,oB1DZiB;E0DajB,Y1DbiB;;A0DejB;EACC,S1DlByB;E0DmBzB;EACA;ECrBA,wBDsB2B;ECrB3B,yBDqB2B;;AAE3B;EACC,OlGfqB;;AkGmBvB;AAAA;EAEC,kBnGFgB;EmGGhB;EACA;;AAEA;AAAA;AAAA;EACC;EACA,OnGCa;EmGAb,WtGpBsB;EsGqBtB,atGXqB;EsGYrB,atGFsB;;AsGKvB;AAAA;AAAA;EACC;EACA,OnGPa;EmGQb,WtGhCoB;;A6EqCnB;EyBDH;IAEE;IACA;IACA;;;AzBDC;EyBHH;IAOE;IACA;IACA;;;AzBHC;EyBNH;IAYE;IACA;IACA;IACA;;;AAIF;EACC;EACA,kBnG9CW;;A8D3BX;EACE;EACA;EACA;;;AqC2EJ;EACC,S1DvEyB;E0DwEzB,kBnGjDiB;EmGkDjB;ECvEC,4BDwE6B;ECvE7B,2BDuE6B;;;AAK9B;EACC;EACA;EACA;EACA,K9FvFgB;;A8FyFjB;EACC;;AAED;EACC;EACA,K9F9FgB;E8F+FhB;EACA;;AzB/CE;EyB2CH;IAME;;;AzB/CC;EyByCH;IASE;;;AzB/CC;EyBsCH;IAYE;;;AAGF;EACC;EACA;EACA;EACA;;AAED;EACC;EACA;EACA;;;AAMD;EACC,atGvFuB;;;AsG4FzB;EACC,oB1DhIiB;E0DiIjB,Y1DjIiB;;A0DmIhB;EACC,WtGvHmB;;AsG0HpB;EACC,WtG3HmB;;AsGgIpB;EACC;;AACA;EACC;;AAED;EACC;;AAKA;EACC;EACA;;AAIF;EACC;;AAGD;EACC;;AAGD;EACC,c9F/J2B;;A8FiK3B;EACC;;AAMJ;EACC;EACA;EACA,WtGxKqB;EsGyKrB,OnGjJc;EmGkJd;;AAGD;EACC,epGxLe;;;AoG6LjB;EACC;EACA;EACA;EAEA;;AAEA;EACC;;AAIA;EACC,S1D7MwB;;;A0DoN1B;EACC;;AAED;EACC,e9FlN0B;;A8FoN3B;EACC;;;AAMF;EACC,kBnGtMiB;EmGuMjB,ehEzNkC;;AgE2NlC;EACC,OnGjMc;EmGkMd,WtGtNuB;EsGuNvB,atGnMuB;EsGoMvB;EACA,S1D1OyB;E0D2OzB;EACA,atGjNsB;;AsGoNvB;EACC;;AAED;EACC,S1DnPyB;;A0DqPzB;EACC,gB9FpOyB;;;AgGd1B;EACE,OANoB;;;AASxB;EACE;EACA,QAVuB;EAWvB,OAZsB;;;AAetB;EACE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;;;AC4DJ;EACE;;;AAGF;EACG;EACA;;;AAGH;AACA;EACE;EACA;EACA;EACA,SArDgB;EAsDhB;EACA,WA7FoC;EA8FpC,YA5FoC;EA6FpC;EACA;EACA;EACA,kBAxGkC;EAyGlC;EACA;EACA;EACA,eA3EkC;EAelC,oBA6DoB;EA5DZ,YA4DY;;AAEpB;EAAmC;;AACnC;EAAuC,aA3FH;;AA4FpC;EAAwC,YA5FJ;;AA6FpC;EAAqC;;AAGrC;EAnDE,mBAoDmB;EAnDd,cAmDc;EAlDX,WAkDW;EA9CpB,oBA+CqB;EA9Cf,eA8Ce;EA7CZ,YA6CY;EAlEtB,SAmEmB;EAhEnB;;AAkEA;EA5CE,6BA6C6B;EA5CxB,wBA4CwB;EA3CrB,qBA2CqB;EAnD9B,oBAoDqB;EAnDf,eAmDe;EAlDZ,YAkDY;EAvEtB,SAwEmB;EArEnB;;AAwEA;EAxDC,oBAyDqB;EAxDf,eAwDe;EAvDZ,YAuDY;EA5EtB,SA6EmB;EA1EnB;;AA4EA;EA/EA,SAgFmB;EA7EnB;;AAgFA;EAtEE,mBAsEuB;EArElB,cAqEkB;EApEf,WAoEe;EAnFzB,SAmFiD;EAhFjD;;AAkFA;EACE;EACA;EACA;;AACA;EACE;;;AAON;EACE;EACA;EACA;EACA,WAjHkC;EAkHlC;EACA,aAnHkC;EAoHlC,OAnHkC;EAoHlC;EAzGA,SA0GiB;EAvGjB;EAwGA;;AACA;EA5GA,SA6GkB;EA1GlB;;AA4GA;EACE;EACA;EACA;EACA;EAEA;;;AAIJ;EACE;EACA;EACA,WA7IgC;EA8IhC;EACA;EACA,kBApLkC;EAqLlC;EACA;;;AAGF;EACE;EACA;EACA;;;AAIF;EACE,kBA/LsB;EAgMtB,OA9LyB;;AAgMzB;EACC,YAnMqB;EAoMrB;EACA,OAnMwB;;;AAwM1B;EACC;;AAED;EACC;EACE;;AACA;EACD;;AAEC;EACD;;;AAOD;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE,cA9MoC;;;AAgNtC;EACE,cAtNoC;EAuNpC;;;AAIA;EAIE;EACD;EACA;EACA,kBAzNmC;EA0NnC,kBA5NmC;EA6NnC;;AACA;EACG;EACA;EACF;EACA,kBAvOkC;EAwOlC;;AAGF;EAGE;EACA;EACA;EACA;EACA,oBA3OkC;EA4OlC,oBA9OkC;;AA+OlC;EACE;EACA;EACA;EACA;EACA,oBAzPgC;;AA4PpC;EAIE;EACD;EACA;EACA,qBA5PmC;EA6PnC,qBA/PmC;EAgQnC;;AACA;EACG;EACA;EACF;EACA,qBA1QkC;EA2QlC;;AAGF;EAGE;EACA;EACA;EACA;EACA,mBA9QkC;EA+QlC,mBAjRkC;;AAkRlC;EACE;EACA;EACA;EACA,mBA3RgC;EA4RhC;;;AASJ;EACC,kBA3TqB;;AAiUtB;EACC,oBAlUqB;;AAwUtB;EACC,qBAzUqB;;AA+UtB;EACC,mBAhVqB;;;AAqVxB;EACE;;;AAGF;EACG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIH;EACE;IAAM;;;AAGR;EACE;IAAM;;;AAGR;EACE;EACA;EACA;EACA;EACA;EACA;EACA,SA3UyB;;;AAgVvB;EACE;EACA;EACA;EACA;EACA;EACA;;;AC5VN;EACE,WA9BqB;;AA+BrB;EACD;;AAEC;EACD,YArBuB;EAsBvB;;AACA;EACE;;AACA;EACD;EACA;EACA;EACA;;AAIA;EACD;EACA;;AAGC;EACD,kBvGhCmB;;AuGiCnB;EACE,W1GlDmB;E0GmDnB,a1G/BsB;E0GgCtB;EACA;EACA;EACA,OvGjCa;;AuGqCd;EACD;;;AC1ED;EACE;EACA;;AAEA;EACE,W3GSkB;E2GRlB;;AAEA;ExCRA;;AwCaF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE,YxGKc;EwGJd,ezGrBmB;;AyGuBrB;EACE,YxG3BU;;AwG6BZ;EACE;EACA,YxGbmB;;AwGiBrB;EACE,YxGpCU;EwGqCV,ezGlCmB;;AyGoCrB;EACE;EACA,YxGvBmB;;AwG4BrB;EACE,OxG3Ca;;AwG4Cb;EACE,OxG7CW;;AwGkDf;EACE,YxGnDa;;AwGuDf;EACE,YxGxDa;;AwG6Df;EACE,OxGxDY;;AwGyDZ;EACE,OxG1DU;;AwG+Dd;EACE,YxGhEY;;AwGoEd;EACE,YxGrEY;;AwGyEhB;EACE,W3G5EkB;E2G6ElB;EACA;;AAEA;EACE;EACA;;;AClFN;EACC;EACA;;AAEA;EACC,QrDfmB;EqDgBnB,arDhBmB;;AqDkBpB;EACC,QrDjBoB;EqDkBpB,arDlBoB;;AqDoBrB;EACC,QrDnBmB;EqDoBnB,arDpBmB;;AqDsBpB;EACC;EACA,arD1BoB;;AqD6BrB;EACC,gBA1BiC,iBA0BkB;EACnD,QA3BiC;;AA8BlC;EACC;IACC;;;;ACvBF;EACE;EACA;EACA;;AASH;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIqC;EAAW;;;AACX;EAAW;;;AAEX;AAAA;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AASX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AACX;EAAW;;;AAMjD;EACC,O1G3Te;;A0G6Tf;EACC,OA9T2B;;AA+T3B;EACC,O1GxTgB;;A0G4TlB;EACC,O1GnTuB;E0GoTvB;;AAGD;EACC,O1G1RoB;E0G2RpB;;AAGE;EACE;;;AAKL;EACC;;;AAIF;AAAA;EAEC;;;AAGD;EACC;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;;;AAED;EACC;;;AAID;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACC;EACA;;;AAED;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAGF;EACC;EACA;;;AAED;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;ACjgBF;EACC,QvD3BoB;EuD4BpB,OvD5BoB;EuD8BpB;EAEA,eA5ByB;EA6BzB,cAxBwB;EAyBxB,cA5BuB;EA8BvB;EACA;EACA;EACA;;AAGA;EACC,c5GhDqB;;A4GkDrB;EACC,QvD9CkB;EuD+ClB,OvD/CkB;EuDgDlB;EACA,QA7CuB;EA8CvB;EACA;;AAKD;EACC,a9G7BuB;E8G8BvB,gBAxC4C;EAyC5C;EACA;EACA;EACA;;AAIA;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;AALD;EAGC,kBAFQ;EAGR,cAFW;EAGX;;;AAQJ;EACC;IACC,QxEjF4B;IwEkF5B,OxElF4B;IwEmF5B,cA5E4B;;EA+E3B;IACC,QxEvF0B;IwEwF1B,OxExF0B;;EwE6F3B;IACC;IACA;;;AClFJ;EACI,evGbwB;;AuGcxB;EAFJ;IAGQ;;;;AAIR;EACI,kB5GFS;E4GGT,YAnBkC;EAoBlC,avGhB0B;EuGiB1B,gBvGjB0B;EuGkB1B;EACA;;AAGI;EACI;;AAEJ;AAAA;EAEI;;AAEJ;AAAA;EAEI;;AAIJ;EACI;;AAEJ;AAAA;EAEI;;AAEJ;AAAA;EAEI;;AAIR;EACI;EACA;;AAGJ;EAEI;;AACA;EACI,W/GtDU;E+GuDV,a/GnCa;E+GoCb;EACA;EACA;;AlCvBR;EkCeA;IAYQ;;;AlC3BR;EkC+BA;IAEQ;IACA,YvGxEkB;;;AuG6E1B;AAAA;EAEI;;AAGJ;EACI;;AlC7CJ;EkC4CA;IAIQ;;;AAIA;EACI,evGjGY;;AuGoGhB;EC5FV,YAPW;EAQX,SxGC+B;EwGA/B,kB7GekB;E6GdlB,Q9Gde;E8Gef,e9GbsB;E8GctB,Y7GKW;EJ4CX,oBiHhDA;EjHiDQ,YiHjDR;;AACA;EACE,c9GtBmB;;A6G0GX;EAEI;EACA,W/GlGM;;A+GmGN;EACI,O5GnEE;;;A4GuFlB;AAAA;EACI,evG9HoB;;;AuGkI5B;EACI,kB5GjHS;;A4GkHT;EACI;;;AAIR;EACI,kB5GxHS;E4GyHT;EACA;;AACA;EACI,gBvG9IoB;;;AqE8CxB;EkCqGJ;AAAA;IAGQ,kB5G7HY;;;;A4GiIpB;EACI;;;AAOJ;EACI;;AlCrHA;EkCoHJ;IAIQ;IACA;IACA;IACA;;EACA;IACI;IACA;IAEA;IACA;IACA;IAEA;IACA;;EAEJ;IACI;;;;AlCrIR;EkC4IJ;IAEQ;;;;AlCjJJ;EkCuJJ;IAEQ;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;AAKR;EACI;EACA;EACA;EACA;EACA;EAEA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AASR;EACI;EACA;EACA;;AAEA;EACI;EACA,O7G5Pe;;;A2EoDnB;EkC6MJ;IAEQ;IACA;IACA;IACA;IACA;IACA;IACA;;;;AAQR;AAAA;EAEI;EACA;EACA;;;AAIA;EACI;;AACA;EACI;;AAEJ;EACI;;;AASZ;EACI;;;AAWA;AAAA;AAAA;EACI;EACA;;;AAMJ;EACI;EACA;;;AAGR;EACI;;;AAMA;AAAA;EACI;EACA;;;AAGR;EACI;;;AAKA;EAEI;EACA;;;AAOJ;AAAA;EAEI;EACA;;;AAKR;EACI,kB5G1Uc;;;A0EwBd;EkCqTJ;AAAA;IAGQ;;;;AAKR;EACI;;AACA;EACI;EACA;;;AASR;EACI;;;AlC7UA;EkCuVI;AAAA;AAAA;AAAA;AAAA;AAAA;IAGI;IACA;IACA;;EAEJ;AAAA;IAEI;IACA;;EAIJ;AAAA;IACI;IACA;;EAEJ;AAAA;IACI;;EASJ;AAAA;IACI;;EAGJ;AAAA;IACI;IACA;;EAOJ;AAAA;AAAA;AAAA;IAEI;;EAIJ;AAAA;IACI,W/Gtac;I+Guad;;EAIA;AAAA;IACI;IACA;;EACA;AAAA;IACI;IACA;;EAEJ;AAAA;IACI;;EAQZ;AAAA;AAAA;AAAA;IAEI;IACA;;EAEJ;AAAA;IACI;;;;AAOR;EAEI;EACA;EACA;EACA,kB5GxcK;E4GycL,YhCheW;;AgCkef;EACI;EACA,kB5GtcY;E4GucZ,YA3W4B;;AA4W5B;EACI;;AAGR;EACI,YAjX4B;EAkX5B;;AACA;EACI;;AAGR;EACI;EACA;;;AAIR;EACI;IACI;;EAEJ;IACI;;;AElfR;EACI;EACA,SANe;EAOf,KrDb6B;EqDc7B;EACA,OAVa;;;AAajB;EACI;;;AAGJ;EACI;;;AAGJ;EACI,azGT0B;EyGU1B,YzGXwB;EyGYxB,ejHLsB;EiHMtB,czGrB2B;EyGsB3B,SzG/Bc;EyGgCd;EACA;EACA,qBACA;EAGA,uBAnC2B;EAoC3B,UzGvCc;EyGwCd,YAhCc;EAiCd;EACA,YAtCkB;;AAwClB;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA,WjHpDc;;AiHuDlB;EACI;EACA;EACA;;;AClER;EACC;EACA;EACA;;AACA;EACC,clHKqB;EkHJrB;;AAED;EACC;;AAEA;EACC;EACA;EACA;EACA;EACA;;AACA;EACC,cClB8B;;ADmB9B;EACC;;AAGF;EACC,cCxB8B;ED0B9B;EACA;EACA;EACA;EAEA;EACA,WlHxBkB;EkHyBlB,O/GQkB;;A+GNnB;EACC,cCpC8B;EDqC9B;;AAGF;EACC,kB/GVe;;A+Gaf;EACC,O/G3BqB;E+G6BrB;EACA;EACA;EACA;;AAED;EAEC;EACA;;AAGF;EACC;;;AEnDH;AAAA;AAAA;AAAA;AAAA;EAKC;EACA;EACA,K5GI0B;;;A4GA3B;AAAA;AAAA;AAAA;EAIC;EACA,YhHM0B;EgHL1B,WhHK0B;EgHJ1B;EACA,S5GR0B;E4GS1B,kBjHGiB;EiHFjB,elHtBkC;;;AkHuClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC,YhHhB6B;EgHiB7B,WhHjB6B;EgHkB7B,elH1CiC;;AkH6ClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC;EACA;EACA;EACA,kBjHzBgB;;;AiHkCjB;AAAA;AAAA;EAEC,elH5DiC;;AkH8DlC;AAAA;AAAA;EACC;;AAGD;AAAA;AAAA;EACC;EACA,M5GvE4B;E4GwE5B;EACA,OjH7Ec;EiH8Ed;;;AAIF;EACC;;;AAID;AAAA;AAAA;EAGC;EACA;EACA;;;AAKA;EACC;;;AAID;EACC;EACA;EACA;;;AAID;EACC;EACA;EACA;;;AAMD;EACC;EACA;;;AAKF;EACC,elHvHkC;;AkHwHlC;EACC;;AAED;EACC;;AAGD;EACC;;;AAKF;EACC,SzD5IoB;;;AzBuCrB;AmF/CA;EACC;EACA;EACA;EACA;;;ACWD;EACC,SAbe;EAcf,etHYyB;EsHXzB;EACA,epHTwB;;AoHYxB;EACE;EACA;;AAIF;EACE,atHUsB;;AsHNxB;AAAA;EAEE;;AAGF;EACE;;;AASD;AAAA;EAED;;AAGA;AAAA;EACE;EACA;EACA;EACA;;;AAsBD;EAbD,OnHzBe;EmH0Bf,kBnHLqB;EmHMrB,cnHNqB;;AmHQrB;EACE;;AAGF;EACE;;;AAQD;EAjBD,OnHzBe;EmH0Bf,kBnHDkB;EmHElB,cnHFkB;;AmHIlB;EACE;;AAGF;EACE;;;AAYD;EArBD,OnHzBe;EmH0Bf,kBnHGqB;EmHFrB,cnHEqB;;AmHArB;EACE;;AAGF;EACE;;;AAgBD;EAzBD,OnHzBe;EmH0Bf,kBnHOoB;EmHNpB,cnHMoB;;AmHJpB;EACE;;AAGF;EACE;;;AAwBH;EACC,OnHrFkB;;;AmHwFnB;EACC,OnHzFkB;;;AmH4FnB;EACC,WtH7FqB;EsH8FrB;EACA,OnH/FkB;;;AmHmGlB;EACC;;;AAID;EACC;;;ACtHF;AACA;EACC;EACA;EACA;EACA;EACA,kBpHoBY;EoHnBZ;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;ACrCD;AACA;EACC,OrHekB;EqHdlB;EACA,WxHkBoB;EwHjBpB,axHiCwB;;AwHhCxB;EALD;IAMQ,WxHakB;;;;AwHT1B;EACC;;AACA;EAFD;IAGQ;;;;AAIR;EACI;EACA;;;AAGJ;EACC,axHcwB;EwHbxB;EACA;EACA;EACA,WxHVwB;EwHWxB,OrHZkB;;;AqHenB;EACC;EACA;EACA,YhH5B2B;EgH6B3B,chHhB6B;EgHiB7B,ehH9B2B;EgH+B3B;;AACA;EAPD;IAQQ;IACN;IACA;IACA;;;;AAIF;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAAA;EAEC;;;AAGD;EACC,WxHpDsB;EwHqDtB;EACA,OrH9Be;;;AqHiChB;EACC;EACA;EACA;;AACA;EAJD;IAKE,OrHtCc;;;AqHwCf;EACC;;;AAIF;EACC;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;AACA;AACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;AACA;EAHD;IAIE;IACA;IACA;;;;AAIF;EACC;;;AAGD;EACC;;;AChID;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC,WzHGqB;EyHFrB,OtHwBe;EsHvBf;EACA;;;AAGD;EACC;;;AAED;AACA;EACC,WzHZqB;EyHarB,azHWwB;;;A0HvCzB;AACA;EACC;EACA;;;AAGD;AACA;EACC;EACA;;;ACPD;AACC;EACA;;AACA;EAHD;IAIE;;;;ACNF;AACA;EACC;EACA;;;AAGD;EACC;;;ACJA;EADD;IAKE;;;;AAKD;EADD;IAEQ;;;;ACRR;EAEI,YtHGwB;;AsHDxB;EACI;;;AAIR;AAAA;EAEI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;AAAA;EAEI,ctHnB0B;;;AsHsB9B;AAAA;EAEI,etHxB0B;;;AsH2B9B;AAAA;AAAA;EAGI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAIJ;EACI;EACA,etHjC0B;;;AuHvB9B;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;ACTA;EADD;IAEE;IACA;;;;AAKD;EADD;IAEQ;;;;AAIR;AAEA;EACI;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACG,O7HYa;E6HXb,kB7HEe;E6HDf;EACA;EACA;;;AAIH;EACG,O7HGa;E6HFb,kB7HPe;E6HQf;EACA;;;AAGH;EACG,O7HJa;E6HKb;EACA;EACA;;;AAIH;EACC;EACA;EACA;AACA;;;AAGD;EACG;EACA;EACA;EACA;EACA;EACA;;;AAGH;EACG;;;AAGH;EACG;EACA,O7HjCa;E6HkCb;;;AAGH;EACG;EACA;EACA,ahI1CsB;;;AgI6CzB;EACG;EACA;;;AAGH;EACG;;;AAGH;EACG,kB7HlEU;E6HmEV,O7HtDa;E6HuDb;EACA,ahIxDsB;EgIyDtB;EACA;EACA;;;AAGH;EACG;EACA,O7HhEa;E6HiEb;EACA,ahIlEsB;EgImEtB;EACA;;;AAGH;EACG;EACA,O7HzEa;E6H0Eb;EACA;EACA;EACA;;;AAGH;EACG;EACA,O7HlFa;E6HmFb;EACA;EACA;EACA;;;AAGH;EACG;EACA,O7H3Fa;E6H4Fb;EACA;EACA,ahIhGsB;EgIiGtB;EACA;;;AAGH;EACG;;;AAGH;AACA;AAAA;EAEG,WhIpImB;EgIqInB;EACA;EACA;EACA,ahIhHsB;;;AgImHzB;AAAA;EAEG;;;AAGH;EACG;EACA;;;AAGH;EACG;;;AAGH;EACG;EACA;EACA,ahIpIsB;EgIqItB,WhI3JoB;EgI4JpB;;;AAGH;EACG;EACA;EACA;;;AAGH;EACG;EACA;EACA,ahIlJsB;EgImJtB,WhI3KmB;;;AgI8KtB;EACG;EACA;EACA,ahIzJsB;EgI0JtB,WhIlLmB;EgImLnB;;;AAGH;EACG;EACA,ahIhKsB;;;AgImKzB;EACG;EACA;;;AAKH;AACA;AACA;EACG;EACA,WhItMmB;EgIuMnB,ahI/KsB;EgIgLtB;;;AAGH;EACG,WhI5MmB;EgI6MnB;EACA;;;AAGH;EACG,WhIlNmB;EgImNnB;;;ACzNH;EjBSE,YAPW;EAQX,SxGC+B;EwGA/B,kB7GekB;E6GdlB,Q9Gde;E8Gef,e9GbsB;E8GctB,Y7GKW;EJ4CX,oBiHhDA;EjHiDQ,YiHjDR;;AACA;EACE,c9GtBmB;;;AgIMvB;ElBQE,YAPW;EAQX,SxGC+B;EwGA/B,kB7GYgB;E6GXhB,Q9Gde;E8Gef,e9GbsB;E8GctB,Y7GKW;EJ4CX,oBiHhDA;EjHiDQ,YiHjDR;;AACA;EACE,c9GtBmB;;;AgC4DvB;AiGpDA;EACE;EpIgLA,oBoI/KA;EpIgLK,eoIhLL;EpIiLQ,YoIjLR;;AAEA;EACE;;;AAIJ;EACE;;AAEA;EAAY;;;AAKd;EAAoB;;;AAEpB;EAAoB;;;AAEpB;EACE;EACA;EACA;EpI8JA,6BoI7JA;EpI8JQ,qBoI9JR;EpIqKA,6BoIpKA;EpIqKQ,qBoIrKR;EpIwKA,oCoIvKoC;EpIwK5B,4BoIxK4B;;;ACxBtC;AAAA;EAEE;EACA;EACA;;AACA;AAAA;EACE;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAIE;;;AAOJ;AAAA;AAAA;AAAA;EAIE;;;AAKJ;EACE;;AnE5CA;EACE;EACA;EACA;;AmE4CF;AAAA;AAAA;EAGE;;AAEF;AAAA;AAAA;EAGE;;;AAIJ;EACE;;;AAIF;EACE;;AACA;E7B5DA,yB6B6D+B;E7B5D/B,4B6B4D+B;;;AAIjC;AAAA;E7BzDE,wB6B2D4B;E7B1D5B,2B6B0D4B;;;AAI9B;EACE;;;AAEF;EACE;;;AAGA;AAAA;E7B9EA,yB6BgF+B;E7B/E/B,4B6B+E+B;;;AAGjC;E7B3EE,wB6B4E4B;E7B3E5B,2B6B2E4B;;;AAM5B;AAAA;EACE;;AzGrBH;AAAA;EACC;EACA,QAJwB;EAKxB;;;AyGsCF;EACE;EACA;;;AAEF;EACE;EACA;;;AAKF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAQA;AAAA;AAAA;EAGE;EACA;EACA;EACA;;AnExJF;EACE;EACA;EACA;;AmE2JA;EACE;;AAIJ;AAAA;AAAA;AAAA;EAIE;EACA;;;AAKF;EACE;;AAEF;E7B9KA,wBrGMsB;EqGLtB,yBrGKsB;EqGEtB,4B6BwKgC;E7BvKhC,2B6BuKgC;;AAEhC;E7BlLA,wB6BmL6B;E7BlL7B,yB6BkL6B;E7B3K7B,4BrGFsB;EqGGtB,2BrGHsB;;;AkIiLxB;EACE;;;AAGA;AAAA;E7BnLA,4B6BqLgC;E7BpLhC,2B6BoLgC;;;AAGlC;E7BhME,wB6BiM2B;E7BhM3B,yB6BgM2B;;;AAO7B;EACE;EACA;EACA;EACA;;AACA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;;AAGF;EACE;;;AAoBA;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;;AC5ON;EANI,SAD4B;EAE5B;EACA;EACA;;;ACoBJ;EACI;;;AAGF;EACE;EACA;EACA;EACA;EACA,SAd0C;;AAgB1C;EACI;EACA;;AAEI;EACJ;;AAGJ;EACE;EACA;EvIgJJ,oBuI/II;EvIgJC,euIhJD;EvIiJI,YuIjJJ;;AAGA;AAAA;AAAA;AAAA;EDhDF,SAD4B;EAE5B;EACA;EACA;ECkDI;;AAIF;EAfF;IvIuKF;IACG;IACE;IACG;IAxJR,6BuIDmC;IvIEhC,0BuIFgC;IvIG3B,qBuIH2B;IvI6GnC,qBuI5G2B;IvI6GxB,kBuI7GwB;IvI8GnB,auI9GmB;;EAErB;IvIoFN;IACQ;IuIlFA;;EAEF;IvI+EN;IACQ;IuI7EA;;EAEF;IvI0EN;IACQ;IuIvEA;;EACA;IACE;;;AAMR;AAAA;AAAA;EAGE;;AAGF;EACE;;AAGF;AAAA;EAEE;EACA;EACA;;AAGF;EACE;;AAEF;EACE;;AAEF;AAAA;EAEE;;AAGF;EACE;;AAEF;EACE;;;AAQJ;EACE;EACA;EACA;EACA;EACA,OAvH0C;EvI4N5C;EACA,SuI9N4C;EA0H1C,WAzH0C;EA0H1C,OnI9HY;EmI+HZ;EACA,aAhI0C;EAiI1C;;AAQA;EACE;EACA;;AAKF;EAEE;EACA,OnInJU;EmIoJV;EvI4EJ;EACA,SuI5EqB;;AAInB;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;EACA;;AAEF;AAAA;EAEE;EACA;;AAEF;AAAA;EAEE;EACA;;AAEF;AAAA;EAEE;EACA;EACA;EACA;;AAKA;EACE;;AAIF;EACE;;;AAUN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,kBnI3NU;;AmI6NZ;EACE;EACA;EACA;EACA,kBnIjLgB;;;AmIwLpB;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OnIhPY;EmIiPZ;EACA,aAlP0C;;AAmP1C;EACE;;;AAMJ;EAII;AAAA;AAAA;AAAA;IAIE;IACA;IACA;IACA;;EAEF;AAAA;IAEE;;EAEF;AAAA;IAEE;;EAKJ;IACE;IACA;IACA;;EAIF;IACE;;;AAKN;EAIM;AAAA;AAAA;AAAA;IAIE;IACA;IACA;IACA;;EAEF;AAAA;IAEE;;EAEF;AAAA;IAEE;;EAKJ;IACE;IACA;IACA;;EAIF;IACE;;;ACtTN;EACI;EACA;EACA;;AAGA;EACE;EACA;EACA;;AAGF;EAGE;EACA;EAKA;EAEA;EACA;;AAEA;EACE;;;AAQN;AAAA;AAAA;EAGE;;AAEA;AAAA;AAAA;EACE;;;AAIJ;AAAA;EAEE;EACA;EACA;;;AAKF;EACE;EACA,WvIvDmB;EuIwDnB;EACA;EACA,OpIlCY;EoImCZ;EACA,kBpI1CgB;EoI2ChB;EACA,erItEoB;;AqIyEpB;EACE;EACA,WvIrEgB;EuIsEhB,erI1EmB;;AqI4ErB;EACE;EACA,WvItEgB;EuIuEhB,erIhFmB;;AqIoFrB;AAAA;EAEE;;;AAKJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EhC9FA,yBgCqG+B;EhCpG/B,4BgCoG+B;;;AAE/B;EACE;;;AAEF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EhClGA,wBgCyG8B;EhCxG9B,2BgCwG8B;;;AAE9B;EACE;;;AAKF;EACE;EAGA;EACA;;AAIA;EACE;;AACA;EACE;;AAGF;EAGE;;AAMF;AAAA;EAEE;;AAIF;AAAA;EAEE;EACA;;;A/DzJR;EvEDI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAQA;EAEE;EACA;EACA;EACA;EACA;EACA;;;AiC0CN;AsGxEA;AAEA;EACC;;;ACAD;AAEA;EACC;EACA;EACA,kBtIoBY;;;AsIjBb;EACC;EACA;;AACA;EACC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA,OtImBqB;EsIlBrB,WzIfqB;EyIgBrB;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA,WzIpCqB;EyIqCrB;EACA;;;AAGD;EACC;;;AAGD;EACC,WzI9CqB;EyI+CrB,OtIdqB;EsIerB;EACA;EACA,kBtIjCiB;EsIkCjB;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC,OtIxEkB;EsIyElB;EACA,WzI1EqB;EyI2ErB;EACA;EACA,kBtIhEY;;;AsImEb;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;IACC;;;ACtHF;AAKA;EACC;;;AAGD;EACC;EACA;EACA;;AACA;EACC,clITgB;;;AkIkBlB;EAHC;;;AAMD;EANC;;;AASD;EATC;;;AAYD;EAZC;;;AAeD;EAfC;;;AAkBD;EAlBC;;;AAqBD;EArBC;;;AAwBD;EAxBC;;;AA2BD;EA3BC;;;AAsCD;EANC;EACA;EACA;EAlCA;;;AAyCD;EATC;EACA;EACA;EAlCA;;;AA4CD;EAZC;EACA;EACA;EAlCA;;;AA+CD;EAfC;EACA;EACA;EAlCA;;;AAkDD;EAlBC;EACA;EACA;EAlCA;;;AAqDD;EArBC;EACA;EACA;EAlCA;;;AAwDD;EAxBC;EACA;EACA;EAlCA;;;AA2DD;EA3BC;EACA;EACA;EAlCA;;;AA8DD;EA9BC;EACA;EACA;EAlCA;;;ACjBD;AAEA;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACC;;AAFF;EAIC;EACA;EACA;EACA;;;AAGD;EACC;IACC;;;AAIF;EACC;EACA;EACO;;;AAGR;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACI;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;;;AAGJ;AAAA;EAEI;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACI;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACC;;AAEA;EACC;;AAGD;EACC;;AAGM;EACI;;AAGX;EACC,OxI/GoB;EwIgHpB,W3IjJoB;E2IkJpB;EACA;EACA;;AAGD;EACC;EACA,OxIxHoB;EwIyHpB;EACA;EACA;;AAGM;EACI;;AAEA;EACI;;AAIf;EACC,OxI9Ic;;AwIiJf;EACC,OxI7IoB;;AwIgJrB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC,kBxInKgB;;AwIsKjB;EACI;;AAGJ;EACC;;AAGD;EACC;EACA;;AAGD;EACC;EACA;;AAGD;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;;AAIF;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;AAAA;EAEI;EACA;;;AAGJ;EACI;;;AAGJ;AAAA;EAEI;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;EACC;EACA;;;AAGD;EACC;EACA;;;AAOD;EACC;;;AClVD;AAEA;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA,OzIsBe;EyIrBf;EACA;EACA;;;AAED;EACC;EACA,OzIee;EyIdf;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAID;EACC;;;AAID;EACC,W5IxCqB;;;A4I2CtB;EACC,W5IxCqB;E4IyCrB;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAID;AAEA;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;E7IfE,oB6IgBD;E7IfS,Y6IeT;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC,kBzI3EwB;;;AyI8EzB;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AC7GD;AAEA;EACC;;;AAGD;EACC;EACA,W7IIqB;;;A6IDtB;EACC;EACA,W7ICsB;;;A6IEvB;EACE;;;AAGF;EACC,a7IewB;E6IdxB;EACA,W7IXqB;E6IYlB;EACA;;;AAGJ;EACE;;;AAGF;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AChDD;AAEA;EACC,ctIU+B;EsIT/B,etIS+B;;;AsINhC;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA,W9IbqB;;;A8IgBtB;EACC;EACA;EACA;;;AAED;EACC,kB3ILiB;E2IMjB;;;AAGD;EACC;;AACA;EACC;EACA;;AAED;EACC;;AAED;EACC;EACA;;;AAKF;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA,O3I7DwB;E2I8DxB;EACA;EACA;EACA;;;ACtFD;AAQA;EACC,a/I0BwB;;;A+IvBzB;EACC,a/IwBwB;;;A+IrBzB;EACC;EACA,a/ImBwB;;;A+IhBzB;EACC;EACA;EACA;EACA,W/IdqB;;;A+IiBtB;EACC,a/IQwB;E+IPxB,W/InBqB;E+IoBrB;;;AAGD;AACA;EACC;EACA;EACA;EACA,kB5IfY;;;A4IkBb;EACC;EACA;EACA;;AACA;EACC;EACA;EACA;EACA;;AACA;EALD;IAME;IACA;;;;AAKH;EACC;EACA;EACA;EACA;;;AAGD;EACC,YvInD8B;EuIoD9B,W/IpDqB;;A+IqDrB;EAHD;IAIE,YvI/D0B;IuIgE1B,W/IzDqB;;;;A+I6DvB;EACC,O5I/BqB;;;A4IkCtB;EACC;EACA;EACA;;AACA;EAJD;IAKE,cvIhE4B;IuIiE5B;;;AAGA;EADD;IAEE;IACA;;;;AAKH;EACC;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;;;AAIF;EACC,YvIrG8B;;;AuIwG/B;EACC;EACA,evI1G8B;EuI2G9B;;AAEA;EACC,kB5IrGW;E4IsGX;;AAGD;EACC;EACA;;AACA;EACC;;AAED;EACC;;AAGA;EADD;IAEE;;;AAKF;EADD;IAEE;IACA;;;;AAKH;EAEE;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;EAED;IACC;;;AAKH;EACC;EACA;EACA,a/ItJwB;E+IuJxB,O5IjLkB;;;A4IoLnB;EACC;EACA,a/I5JwB;;A+I6JxB;EACC,a/IhKuB;;A+IkKxB;EACC;;;AAIF;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC,YvIzM8B;;;AuI4M/B;EACC;;;AAGD;EACC,O5IrNkB;;;A4IwNnB;EACC,a/I/LwB;;;A+IkMzB;EACC;EACA;EACA;EACA;EACA;EACA;EACA,O5IzMe;E4I0Mf;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;ACrQD;AAEA;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;AACA;EACC;EACA;EACA;EACA;EACA;AACA;EACA,kB7IJiB;E6IKjB;AACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAID;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AC7GD;EACI,kB9IqBS;E8IpBT,oBrGFc;EqGGd,YrGHc;;AqGIjB;AAAA;EAEC;EACA;EACA;;;AAKD;EACC;;;AAGF;EACC;EACA,kB9IOiB;;A8INjB;EACC;;AAED;EACC;;;AAMA;EACC;;;AAKH;EACC,kB9IXiB;;A8IajB;EACC;;;AAGF;AAEA;EACC;;;AClDD;AAUA;EACE;EACA;;;AAEF;EACE;EACA,SARmB;EASnB,OAfiB;EAgBjB,QAfkB;;;AAiBpB;ACpBA;EACE;;AACA;EACE;;;AAKF;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAIA;EACE;EACA;EACA;;AAGF;EACE;;AACA;EACE;;AAHJ;EAKE;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAIA;EACE;;AAIJ;EACE;;;ACjEJ;AAEA;EACC;EACA;EACA;EACA;;;AAGD;EACC,kBjJoBiB;EiJnBjB;;;AAGD;EACC;;;AChBC;EACD;EACA;EACA;;AAGC;EACD;;AAGC;EACD;EACA;;AAGC;EACD;EACA;;AAGC;EACD;EACA;EACA;;;AAID;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;ACtDF;AAEA;EACC;EACA,WtJSqB;EsJRrB,OnJQkB;;;AmJLnB;EACC;EACA,WtJGqB;EsJFrB,OnJmCqB;;;AmJhCtB;EACC;EACA;EACA;EACA,WtJLqB;EsJMrB;;;AAGD;EACC;EACA;EACA;EACA,WtJbqB;EsJcrB,OnJmBqB;;;AmJhBtB;EACC;EACA;;;AAGD;EACC;EACA,WtJxBqB;;;AsJ2BtB;EACC;;;AAGD;EACC;;;AC7CD;AAEA;EACC;;AACA;EACC;EACA;;;AAIF;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA,WvJRqB;AuJSrB;;;AAGD;EAEC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAIA;EACC;EACA;;AAHF;EAKC;;;AAGD;EACC;;;AAGD;EACC;;;ACvDD;EACG,YrJ6Be;EqJ5Bf;;;AAGH;EACI,gBhJJwB;;;AiJR5B;AAEA;EACC,OtJoCe;EsJnCf,kBtJ0BiB;EsJzBjB;EACA;;;AAGD;EACC,kBtJoBiB;EsJnBjB,OtJ4Be;EsJ3Bf;EACA;EACA;;;AAGD;EACC;EACA,OtJoBe;EsJnBf;EACA;EACA;;;ACpBD;AAEA;EAEC;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAGD;IACC;IACA;IACA;IACA;;EAGD;IACC;IACA;IACA;IACA;;EAGD;IACC;IACA;;EAGD;IAEC;IACA;AACA;AAAA;AAAA;;EAKD;IAEC;IACA;IACA;;EAGD;IAEC;IACA,elJ9C4B;;EkJiD7B;IACC;;EAGD;IACC;IACA;;EAGD;IACC;IACA;IACA;IACA;IACA;;EAGD;IACC;IACA,a1JtCuB;I0JuCvB;IACA;IACA;;EAGD;IACC;IACA;;EAGD;IACC;IACA;IACA;IACA;IACA;IACA;IACA;;EAGD;IACC;;EAGD;IACC;;EAGD;IACC;;EAGD;IACC;IACA,a1JzEuB;I0J0EvB;;EAGD;IACC;;EAGD;IACC;;EAGD;IACC;;EAGD;IACC;;EAGD;IACC;IACA;IACA,a1JhGuB;I0JiGvB;IACA;;;AAIF;AAEA;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA,kBvJxIiB;EuJyIjB;;;AAGD;EACC;EACA;;;AAGD;EACC;;AACA;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAMA;EACC;;;AC/LH;AAcA;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAIA;EACC;EACA,W3JtBqB;E2JuBrB,a3JDuB;;A2JGxB;EACC,W3JtBuB;E2JuBvB,a3JHuB;;;A2JOzB;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EAEI;EACH;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;AAEA;EAHD;IAIE;;;;AAIF;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EAEI;EACA;EACA;;;AAGJ;EACC;EACA;EACA;EAEA,SnJtH+B;;AmJuH/B;EACC,cnJxH8B;EmJyH9B,enJzH8B;;;AmJ6HhC;EACI,W3J9HmB;E2J+HnB,Y3J/HmB;;;A2JkIvB;EACC;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;;AAGD;AAEA;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EAEC;EACA;EACA;;;AAGD;EAEC;EACA;EACA;;;AAGD;EAEC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAID;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOC;;;AAGD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASI;;;AAEJ;AAAA;EAGI;;;AAEJ;EAEI;EACA;;;AAEJ;EAEI;EACA;EACA;;;AAKJ;EAEI;;;AAEJ;EAEI;;;AAEJ;AAAA;EAGI;;;AAGJ;EAEC;;;AAED;EAEC;;;AAED;EAEC;;;AAED;AAAA;EAGC;;;AAED;EAEC;;;AAED;EAEC;;;AAED;EAEC;;;AAED;EAEC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;AAAA;EAEC;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAED;EACC;EACA;EACA;;;AAOD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAAA;EAGC;EACA;;;AAGD;EAEC;EACA;EACA;;;AAGD;EAEC;;;AAGD;AAAA;EAGC;;;AAGD;EAEC;EACA;;;AAGD;EAEI;EACA;EACA;;;AAGJ;EACC;;;AAGD;EAEI;;;AAGJ;EAEI;;;AAGJ;AAAA;EAGC;;;AAGD;AAAA;EAGI;EACA;;;AAEJ;EAEI;;;AAGJ;EACI;EACA;EACA;;;AAEJ;EACI;;;AAGJ;AAAA;EAGI;EACA;EACA;;;AAGJ;EAEC;;;AAGD;EACC;;;AAGD;AAEA;EACI;;;AAGJ;EACC;EACA;;;AAGD;EACI;EACA;EACA;EACA;;;AAGJ;EACI;;;AAEJ;AAEA;EAEC;;;AAED;EAEC;;;AAGD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASC;EACA;;;AAGD;EAEC;EACA;EACA,KnJzjB4B;EmJ0jB5B,OnJzjB8B;EmJ0jB9B,Y5EnkBkB;;A4EokBlB;EACC;;;AAIF;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAED;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;AACA;EACI;EACA;EACA;EACA,YxJ5kBc;EwJ6kBd,QzJtmBa;;AyJwmBb;EACI,YxJ1kBU;;AwJ6kBd;EACI;;;AAIR;EACI;;;AAGJ;EACI;;;AAGJ;EACI,QzJ1nBa;EyJ2nBb,kBxJ/lBgB;EwJgmBhB;EACA,SnJ1mBuB;;;AmJ6mB3B;EACI,QzJjoBa;EyJkoBb,kBxJnmBc;EwJomBd;EACA,SnJjnBuB;EmJknBvB;;;AAIA;EACI;;;AAIR;EACI,kBvJ5mBiB;;;AuJ+mBrB;EACI;EACA;;AACA;EACI;EACA,kBxJloBK;EwJmoBL,azJxpBS;EyJypBT,czJzpBS;EyJ0pBT,ezJ1pBS;EyJ2pBT;EACA;EACA,SnJ1oBmB;EmJ2oBnB;EACA;EACA;;AAEJ;EACI,kBxJpoBU;;;AyJjBlB;EACI;;AACH;EACC;;AAGE;EACI;EACA,WAtBsB;EAuBtB,cpJnBsB;;AoJoBtB;EACI;EACA;;AAEJ;EARJ;IASQ;IACA;;;AAGR;EACI;;AACA;EACI,kBzJfC;EyJgBD;;AAGR;EA1BJ;IA2BQ;;;;AAIR;EACC;IACC;;EACA;IACC;IACS;;;AAMZ;EACI;EACA;EACA;EACA,kBzJnCc;;;AyJwCd;EACI;EACA;;AACA;EACI;EACA;EACA;EACA;;AACA;EACI;;AAEJ;EACI;;AAEJ;EACI,a5J9CS;;;A4JsDxB;EACO;EACA;;AACA;EACI;EACA;;AAEJ;EACI,W5JpFU;E4JqFV,a5J/Da;;A4JkErB;EACI,epJlGoB;;;AoJwGxB;EACI,W5JlGe;;A4JqGnB;EACI;EACA;;;AAIR;EACE;;;AAWA;EACE;;AAEF;EACE;;;AAIF;EACE;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;;ACvJA;EACE;EACA;EACA;EACA;EACA;EACA;EACA,QD0H4B;ECzH5B;EACA;;ADsJJ;EACE;;AAGF;EACE;EACA;EACA,gBArC8B;;AAuC9B;EACE;;AAIF;EACE;;AAIJ;EACE;EACA,a1JjLa;E0JkLb;EACA;EAEA;EACA;EACA;EACA;;A/EzIA;E+EgIF;IAYI;IACA;IACA;;;AAGF;EACE;;AACA;EACE,W5JvLc;;A4J2LlB;EACE;;AAGF;EACE;EACA,YpJzMwB;EoJ0MxB;;ACjNF;EACE;EACA;EACA;EACA;EACA;EACA;EACA,QD0H4B;ECzH5B;EACA;;ADiNA;EACE,gBA1F0B;EA2F1B;EACA;;;A/E3KJ;E+EkLF;IACE;IACA;;EACA;IAEE;;;AAUN;EACE;EACA;EAEA;EACA;EACA;EACA,OA3HkB;;A/E7EhB;E+EiMJ;IAUI;;;AAGF;EACE;;AAGF;EACE;EACA;;AACA;EAEE;;AAGF;EACE;EACA;;AAGF;AAAA;AAAA;EAGE;;AAGF;EACE;EACA;EACA;;AACA;EACE;EACA;;AAEF;EACE;EACA;EACA,YpJnRuB;EoJoRvB,epJ1RqB;EoJ2RrB;EACA;;AAKN;EACE;EACA;;AAGF;EACE;EACA;;;AAQF;AAAA;EAEE;EACA,WA7LgB;EA8LhB;;AAIA;EACE,YpJlT2B;;;AoJuTjC;AAAA;EAEE,WA1MkB;EA2MlB;;;AAKE;EACE,epJ1UsB;;AoJ6U1B;EACE;;;AASA;EACE,epJxVsB;EoJyVtB,YpJnVwB;;AoJqV1B;EACE;;AAEF;EACE;;AACA;EACE;;AAEF;EACE;;;AAUJ;EACE;;;AASF;AAAA;EACE;;AAEA;AAAA;EACE;;;AEnYR;AAEA;EACC,O3JWiB;;;A2JRlB;EACC,O3JoCqB;;;A2JjCtB;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA,atJjB2B;EsJkB3B,gBtJlB2B;EsJmB3B,W9JdqB;;;A8JiBtB;AAEC;EACC;;;ACjCF;AAEA;EACC;;;AAGD;EACC,kB5JuBiB;E4JtBjB;EACA;;;ACPD;AAIE;AAAA;EACE;EACA;EACA;EACA,QpHLc;EoHMd,e9JE+B;E8JD/B,oBpHRc;EoHSd,YpHTc;;AoHYhB;AAAA;EACE,kB7Jac;E6JZd,SpHhBuB;EoHiBvB,ahKkBqB;EgKjBrB;EACA;;AACA;AAAA;EACE;EACA,O7JeU;;A6JXd;AAAA;EACE,e9JxBa;E8JyBb,kB7JJS;;A6JOX;AAAA;EACE,SpHhCuB;EoHiCvB;EACA;EACA;;AAGF;AAAA;EACE;EACA;EACA;EACA,cxJzCc;;AyJFlB;EACE,WjKWoB;;AiKTpB;EACE;EACA,czJe0B;;;A0JlB9B;AAEA;EACC;EACA;EACA;EACA,O/JJe;E+JKf,WlKOqB;EkKNrB;EACA;EACA,kB/JiBiB;E+JhBjB;EACA;EACA;;AACA;EACC,kB/JkBgB;;;A+JdlB;EACC;EACA;;;AAGD;EACC,QtHvBiB;EsHwBjB,e1Jf6B;E0JgB7B,ehKjBkC;;;AgKoBnC;EACC,a1JvB4B;;A0JwB5B;EACC;;;AAGF;EACC;EACA,kB/JLiB;;;A+JQlB;EACC;EACA;EACA;;;AAWD;EACI;;;ACzDJ;AAEA;EACC;EACA,OhKiCe;EgKhCf;;;AAGD;EACC;;AACA;EACC,kBhKiBgB;EgKhBhB;;;AAIF;EACC;;;AAGD;EACC;EACA;;;AAED;EACC;;;AAED;EACC;;;AAIA;EACC;;AAED;EACC,kBhKFgB;;AgKIjB;EACC;;;AAKF;EACC;EACA;EpKsBC,oBoKrBD;EpKsBS,YoKtBT;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA,kBhKrCY;;AwBjBZ;EACC;EACG;;AAEJ;EACC;EAEA,SARwB;EASxB;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;AwI8DzB;EACC;EACA;;AAEA;EACC;EACA;;;AAKH;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC,OhK5CqB;EgK6CrB,WnK9EqB;EmK+ErB;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC,kBhK5EiB;EgK6EjB;EACA,WnK/FqB;;;AmKkGtB;EACC,OhKzEe;;;AgK4EhB;EACC,OhKxEqB;;;AgK2EtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;AACC;EACA;EACA;EACA;AACA;AACA;AACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;AAIA;EACC;EACA;EACA;;;AAIF;EACC;EACA;;;AAGD;EACC,kBhK3JiB;EgK4JjB,OhKlJqB;;;AgKqJtB;EACC;;;AAGD;AACA;EACC;EACA;EACA;;;AAGD;EACC;;;ACjND;AAIA;EACC;;;ACLD;AAEA;EACC;EACA;;;AAKG;EACE;EACA;EACA;;;AAKN;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;AAEA;EACC;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAIF;EACC;EACA;EACA;;;AAKD;EACC;EACA;EACA;;;ACjDF;AAEA;EACC;EACA;EACA;EACA,etKoByB;EsKnBzB;EACA;EACA;EACA,kBnKmBiB;EmKlBjB;EACA;EACA,S9JXiB;;;A8JclB;EACC,kBnKYiB;;;AmKTlB;AAAA;AAEC;EACA,atKewB;EsKdxB;EACA;EACA;EACA,OnKVkB;EmKWlB;AACA;;;AAGD;EACC,WtKnBsB;;;AsKsBvB;EACC,atKCwB;EsKAxB;EACA;EACA,WtKxBqB;EsKyBrB;;;AAGD;EACC,atKPwB;EsKQxB;EACA;EACA,WtKlCsB;EsKmCtB;;;AAID;AACA;EACC,WtK3CqB;EsK4CrB,OnKXqB;;;AmKctB;AACA;EACC,WtKjDqB;EsKkDrB,OnKjBqB;EmKkBrB;EACA,kBnKnCiB;EmKoCjB;;;AAGD;EACC,StKvDsB;;;AsK0DvB;EACC,S9JlD0B;E8JmD1B;;;AAGD;EACC,OnKjCqB;;;AoKhDtB;AAEA;EACC;EACA;;;AAGD;EACC;EACA;;;ACND;AAIA;EACC,OrKiCe;EqKhCf,kBrKuBiB;EqKtBjB;;;AAGD;EACC,OrK2Be;EqK1Bf,kBrKoBmB;EqKnBnB;;;AAGD;EACC,kBrKemB;;;AqKXpB;EACC,kBrKOiB;;;AqKJlB;EACC,kBrKGiB;;;AqKAlB;EACC;;;AAGD;EACC,WxKtBqB;EwKuBrB;;;AAGD;EACC,WxK7BsB;EwK8BtB;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;AACA;EACA;EACA;AACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAMD;EACC;EACA,WxK1EqB;EwK2ErB;EACA;;;AAGD;EACC;EACA,WxKjFqB;;;AwKoFtB;EACC;EACA,WxKtFqB;EwKyFrB;EACA,kBrKzEiB;EqK0EjB;EACA,ehK3F6B;;AgK4F7B;EACC;EACA;;AACA;EAHD;IAG4C;;;AAH5C;EAIC;EACA;EACA,OrKzEc;EqK0Ed;;AAED;EACC,kBrK1FW;;AqK4FZ;EACC,axKhFuB;EwKiFvB,WxK3GoB;;AwK+GrB;EACC,kBrKhHiB;;AqKiHjB;EACC;;AAGF;AAAA;EAEC,OrK7Fc;EqK8Fd;;AAED;EACO;EACA;;;AAIR;EACC;EACA;;;AAID;EACC;EACA;EACA,WxKvIsB;;;AwKyIvB;EACC;EACA;EACA,WxK5IsB;;;AwKgJvB;EACC,YhKxJ2B;EgKyJ3B,OrK1He;EqK2Hf;EACA;EACA,WxKrJsB;;;AwKwJvB;EACC,OrKjIe;EqKkIf,axKpIwB;EwKqIxB,kBrK5IiB;;;AqKgJlB;EACC;EACA,kBrKlJiB;EqKmJjB,axK5IwB;EwK6IxB;EACA;EACA;EACA;EACA,ctKpLsB;;;AsKuLvB;EACC,kBrK5JiB;EqK6JjB;EACA;EACA;EACA;EACA,ctK7LsB;EsK8LtB;EACA;;;AAGD;EACC;EACA;EACA,kBrKtKmB;EqKuKnB,WxKzLsB;EwK0LtB;;;AAGD;EACC;;;AAED;EACC;EACA;EACA;EACA,oBtKjNsB;;;AsKoNvB;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA,qBtK7NsB;;;AsKgOvB;AACC;EACA;EACA;;;AAGD;AAAA;EAEC,kBrKhNY;;;AqKmNb;EACC;EACA,ctK7OsB;EsK+OtB;EACA;EAEA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA,oBtKrQsB;;;AsKyQvB;EACC;EACA,kBrKnPY;EqKoPZ;EACA;EACA;EACA;EACA,ctKhRsB;EsKiRtB;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA,ctK3RsB;;;AsK+RvB;EACC;EACA;EACA;EACA;EACA;EACA;EACA,ctKtSsB;;;AsKySvB;EACC;EACA,kBrK/QiB;EqKgRjB;EACA;EACA;EACA;EACA,ctKhTsB;;;AsKmTvB;EACC;EACA,kBrKzRiB;EqK0RjB;EACA;EACA;EACA;EACA,ctK1TsB;;;AsK6TvB;EACC;EACA;EACA;EACA;EACA,WxKrTsB;;AwKuTtB;EACC;EACA;EACA;;;AAIF;EACC,WxK/TsB;;;AwKkUvB;EAEC;AACA;EACA;EACA;EACA;EACA;EACA,ctKvVsB;EsKwVtB,WxK3UsB;AwK4UtB;;;AAGD;EACC,WxKhVsB;EwKiVtB;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA,axKvUwB;;;AwK0UzB;EACC;EACA;;;AAID;EAEC;;;AAID;EACC,OrKrVe;EqKsVf,kBrK/ViB;;;AqKkWlB;EACC;EACA,WxKrXqB;EwKsXrB,axK9VwB;EwK+VxB,kBrK1WY;;;AqKgXb;EACC,axKlWyB;;;AwKqW1B;EACC;EACA;;;AAGD;EACC;EACA;EACA,kBrK5XY;EqK6XZ;EACA;EACA;EACA,ctKxZsB;EsKyZtB,WxK9YqB;EwK+YrB;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA,ctKnasB;EsKoatB,WxKzZqB;EwK0ZrB;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA,ctK9asB;EsK+atB,WxKpaqB;EwKqarB;EACA;;;AAGD;EACC;EACA,kBrK1ZiB;EqK2ZjB;EACA;EACA,ctKzbsB;EsK0btB,WxK/aqB;EwKgbrB;EACA;;;AAGD;EACC;EACA,kBrKraiB;EqKsajB;EACA;EACA,ctKpcsB;EsKqctB,WxK1bqB;EwK2brB;EACA;;;AAGD;EACC;EACA,kBrKpbY;EqKqbZ,WxKpcsB;EwKqctB;EACA;;;AAGD;EACC,OrK9bwB;;;AqKgczB;EACC;EACA;;;AAGD;EACC;EACA,YhKtd2B;;;AgKyd5B;EACC;;AACA;EACC;EACA;;;AAMF;EACC;EACA;;;AAGD;EACC;;;ACnfD;AAEA;EACC;;;AAGD;EACC;;;ACDD;AACA;EACC;;;AAGD;EACC;EACA;EACA,W1KCqB;;;A0KEtB;EACC;;;AAGD;AACA;EACC;EACA;;AAEA;EACC;;;AAIF;EACC;EACA;EACA;;;AAIA;EACC,W1KtBqB;E0KuBrB;EACA;EACA;;AACA;EACC;EACA;EACA;;AAED;EACC;EACA;EACA;EACA;;;AAKH;EACC;;;AAGD;EACC;EACG;;;AAGJ;EACC,kBvK7BiB;EuK8BjB;;;AAID;EACC;;;AAGD;AACC;AAAA;EAEA;EACA;EACA,elKnE8B;;AkKqE9B;EACC;;;AAIF;AACC;AAAA;AAAA;EAGA;EACA;;;AAED;EACC;EACA;;;AAGD;EACC,alKvF8B;;;AkK0F/B;AAAA;EAEC,OnHnGqB;EmHoGrB,QnHpGqB;EmHqGrB;;;AAGD;AACC;EACA;EACA;EACA;;;AAGD;AACA;AACC;;;AAGD;EACC;EACA,clKxHiB;EkKyHjB;;;AAGD;EACC,kBvKlGiB;EuKmGjB,S9H/H0B;E8HgI1B,a1K7FwB;E0K8FxB;EACA;;AACA;EACC;EACA,OvKhGc;;AuKmGf;EACC;EACA;;;AAIF;EACC;EACA;EACA;EACA;AACA;EACA,kBvKxHiB;EuKyHjB;;;AAID;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA,Q9HlKiB;E8HmKjB,exK3JkC;EwK4JlC,oB9HrKiB;E8HsKd,Y9HtKc;;;A8HyKlB;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC,kBvKnKY;;;AuKsKb;EACC,kBvKnKiB;EuKoKjB;;;AAID;EACC;EACA,kBvK9KY;;;AuKiLb;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA,kBvK3LiB;EuK4LjB;EACA;;;AAGD;EACO;;;AAGP;EACO;;;AAGP;EACC;;;AAGD;EACC;;;AAED;EACC,W1K7NqB;;;A2KdtB;AAEA;EACC;EACA;EACA;EACA;EACA,qBxKawB;EwKZxB,oBxKYwB;EwKXxB;EACA,W3KFsB;E2KGtB;EACA;;;AAGD;EACC;EACA;EACA;EACA,W3KTqB;E2KUrB;EACA;EACA;EACA;EACA,qBxKJwB;EwKKxB,oBxKLwB;;AwKMxB;EACC,OxKcoB;;;AwKVtB;EACC;EACA;EACA,W3K1BsB;E2K2BtB,kBxKZY;EwKaZ;;;AAGD;EACC;EACA;EACA;EACA;EACA,W3KlCqB;;;A2KqCtB;EACC;;;AAGD;EACC;;;AAID;AAAA;AAAA;EAGC;EACA;EACA,W3KnDqB;E2KoDrB;EACA;EACA;EACA;EACA;;;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACC,OxKzEc;EwK0Ed,W3K9DoB;;;A2KkEtB;EACC;EACA,OxKvCqB;;;AwK0CtB;EACC;;;AAED;EACC;EACA;;;AAGD;EACC;EACA;EACA,OxKrDqB;EwKsDrB;EACA,W3KxFqB;E2KyFrB;EACA;EACA;;;AAID;EACC;EACA;EACA;;;AAGD;EACC;EACA,OxKtEqB;;;AwK0EtB;EACC;;;AAGD;EACC;EACA;EACA;;;AAIA;EACC;;AAED;EACC;;;AAIF;EACC;EACA,kBxKxIe;EwKyIf;EACA,W3KlIqB;E2KmIrB;EACA;EACA;EACA;EACA,Q3KzHyB;E2K0HzB;EACA;;;AAIA;AAAA;AAAA;AAAA;AAAA;EAGC;;AAED;EACC;;;AAIF;EACC,kBxK9JoB;;;AwKkKrB;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC,OxKtKkB;EwKuKlB;EACA,W3KxKqB;E2KyKrB;EACA;EACA,kBxK1JiB;;;AwK8JlB;EACC;EACA;EACA;;;AAGD;EACC,cxK5LoB;;;AwK+LrB;EAEC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC,kBxKxLY;EwKyLZ;EACA;EACA;EACA;EACA;EACA,W3KzMsB;E2K0MtB;;;AAGD;EACC;;;AAMD;EACC;EACA;;;AAGD;EACC,kBxK/MY;EwKgNZ;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA,kBxK9NY;;;AwKiOb;EACC;;;AAED;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;AACA;AACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;;AAIF;EACC;EACA,YxKjQY;EwKkQZ;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;AAGE;EACC;EACA;EACA;EACA;EACA;;AAED;EACC,OxKpRkB;EwKqRlB;;AAKF;EACC;;AAIF;EACC;;;AAOF;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;AACA;EACC;;;AAGD;EACC;EACA;;;AAGD;AACA;EACC,W3KzWqB;E2K0WrB;EACA,kBxK1ViB;EwK2VjB;EACA;;;AAGD;EACC;EACA,W3KhXsB;E2KiXtB;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC,OxK7Ye;EwK8Yf;EACA;;;AAGD;EACC,OxKnWqB;;;AwKsWtB;EACC,OxKjUqB;;;AwKoUtB;AACA;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC,kBxKrZY;EwKsZZ;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;;AACA;EACC;EACA;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC,kBxKzbY;EwK0bZ;EACA;EACA;EACA;;;AAGD;EACC,kBxKjcY;;;AwKocb;EACC;EACA,W3K/cqB;E2KgdrB;;;AAGD;EACC;EACA,kBxK5cY;EwK6cZ;EACA;;;AAGD;AAEA;EACC;EACA;;;AAGD;EACC,cxK9ee;;;AwKifhB;EACC,cxK1ekB;;;AwK6enB;EACC,cxKpfoB;;;AwKufrB;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA,OxKleqB;;;AwKqetB;EACC,OxKteqB;;;AwKyetB;EACC;;;AAGD;EACC;;;AAGD;EACC,cnKlhB8B;EmKmhB9B,enKnhB8B;EmKohB9B;;AACA;EACC;;AAGA;EACC;EACA;EACA;EACA;EACA,kBxK5gBe;EwK6gBf;EACA;;AAIF;EACC;;AAGD;EACC;EACA;;AAGD;EACC;EACA;;;AAIF;EACC;EACA;EACA;EACA;EACA,W3KvjBqB;E2KwjBrB;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA,kBxKxjBiB;EwKyjBjB;;;AAGD;EACC,kBxKvjBiB;;;AwK0jBlB;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAAA;EAEC;;;AAID;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;AACA;EACC;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;AAAA;AAAA;EAGC;;;AAGD;EACC;;;AAID;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EAEC;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;;;AAIF;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;AAEA;EACC;EACA;;AAGD;EACC;EACA;;AACA;EAHD;IAIE;;;AAIF;EACC,W3K7rBoB;E2K8rBpB,YnK9rB6B;EmK+rB7B,enKxsB0B;;AmK2sB3B;EACC;;AAED;EACC,enK5sB2B;;AmK6sB3B;EACC;;AACA;EACC,W3K5sBmB;;A2K+sBrB;EACC;;AAED;EACC;EACA;EACA;EACA;EACA;;AAED;EACC;EACA,kBxKhtBU;;AwKotBZ;EACC;;;AAIF;AAAA;EAEC;;;AAGD;EACC,YnK3uB6B;;;AmK8uB9B;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAED;EACC;;;AAID;AACA;EACC;;AAEA;EACC;EACA;EACA;;AACA;EACC;EACA;;;AAKH;AAAA;AAAA;AAAA;AAAA;AAKA;EACC;;;AAGD;EAEC,kBxK7wBY;;AwK+wBZ;EACC,kBxK5wBgB;;AwK6wBhB;EACC,kBxK9wBe;EwK+wBf;EACA,OxKvwBa;EwKwwBb;EACA;;AAIF;EACC;;AAGD;EACC;;;AAIF;AAAA;EAEC;EACA,OxKlxBqB;EwKmxBrB;;AAEA;AAAA;EACC;;;AAIF;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;;AACA;EACC;EACA;EACA;;;AAMA;EACC;EACA;;AAED;EACC;;;AhJ91BF;EACC;EACG;;AAEJ;EACC;EAEA,SARwB;EASxB;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;;AiJP1B;AAEA;EACC,W5KQsB;;;A4KLvB;EACC,W5KMqB;;;A4KHtB;EACC;;;ACaD;EACC;EACA;EACA;EAIA;;;AAGD;EACC;EACA;EACA;EACA,a7KDwB;;;A6KKxB;EACC;;;AAYF;E9KqBE,oB8KpBmB;E9KqBhB,iB8KrBgB;E9KsBX,Y8KtBW;EACpB;EACA;;;AAMA;AAAA;EAEC;;;AAIF;EACC;;;AAID;EACC;EACA;;;AAID;AAAA;EAEC;;;AAyBD;EACC;EACA;EACA,QpKvEqB;EoKwErB;EACA,W7KpGqB;E6KqGrB,a7KxFsB;E6KyFtB,O1K5Ee;E0K6Ef,kB1K1FY;E0K2FZ;EACA;EACA,e3KhHuB;EH+DtB,oB8KkDD;E9KjDS,Y8KiDT;E9KmEC,oB8KlED;E9KmEM,e8KnEN;E9KoES,Y8KpET;;AlJjFA;EACC,SAHwB;EAIxB;;A5B8DA;EACE,OI3DkB;EJ4DlB;;AAEF;EAA0B,OI9DN;;AJ+DpB;EAAgC,OI/DZ;;AJ0DpB;EACE,OIlEY;EJmEZ;;AAEF;EAA0B,OIrEZ;;AJsEd;EAAgC,OItElB;;A0K+Ff;EACC;EACA;;AAQD;EAGC,kB1KrHgB;E0KsHhB;;AAGD;EAEC,QAnJgB;;AAuJjB;EACC;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACI;;;AAWJ;EACC;;;AAaD;EAME;AAAA;AAAA;AAAA;IACC,apKpKyB;;;AoK+K5B;EACC,erK5M4B;;;AqKoN7B;AAAA;EAEC;EACA;EACA;EACA;;AAKC;AAAA;AAAA;EACC,QApOe;;AAwOjB;AAAA;EACC,Y7KpNwB;E6KqNxB;EACA;EACA,a7K7MuB;E6K8MvB;;;AAIF;AAAA;AAAA;AAAA;EAIE;EACA;EACA;EACA;;AACA;EARF;AAAA;AAAA;AAAA;IASI;;;;AAGJ;AAAA;EAEE;;;AAGF;AAAA;EAEC;;;AAID;AAAA;EAEC;EACA;EACA;EACA;EACA;EACA,apK9O2B;EoK+O3B,a7KjPwB;E6KkPxB;;;AAGD;EACI,apKpPwB;;;AoKuP5B;AAAA;EAEC;EACA;;;AAOD;AAAA;EAEC;;AAEA;AAAA;AAAA;AAAA;EAGC,QAzSgB;;;AAiTjB;AAAA;AAAA;EAEC,QAnTgB;;;AA6ThB;AAAA;AAAA;EACC,QA9Te;;;AAyUlB;EACC;EACA,O1K1Se;E0K2Sf,W7KrUqB;E6KuUrB;EAEA;;AAEA;EACC;;AAGD;EACC,erKzU0B;;;AqK4V3B;EAGC;IACC;IACA;IACA;;EAID;IACC;IACA;IACA;;EAID;IACC;;EAGD;IACC;IACA;;EAEA;AAAA;AAAA;IAGC;;EAKF;IACC;;EAGD;IACC;IACA;;EAKD;AAAA;IAEC;IACA;IACA;IACA;;EAEA;AAAA;IACC;;EAIF;AAAA;IAEC;IACA;;EAID;IACC;;;;AAiBH;EACC,erKjb8B;EqKkb9B,Y1KzaY;;A0K2aZ;EACC;EACA,arKlcyB;EqKmczB,QrKncyB;EqKoczB,kB1K/aW;;A0KqbV;EACC,arKjc4B;;AqKqc9B;EACC,arKtc6B;;AqKyc9B;EACC;EACA;;AAQF;AAAA;AAAA;AAAA;EAIC;EACA;EACA;EACG;;AAKJ;AAAA;EAEC;;AAGD;EACC,O1K7cc;E0K8cd;EACA;;AAGD;EACC,YpK1dyB;EoK6dzB;EACA;;AACA;EAND;IAOG;IACA;IACA;;;AAEF;EACE;;AAGI;EACE,crKpgBiB;;AqK4b3B;AA2EC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AAeD;EACC,SpKngBiC;;AoKqgBjC;EACC,QpKpgB+B;EoKqgB/B,YpKngBkC;;AoKsgBnC;EACC;;AAGD;EACC;EACA;;AAGD;EACC;;;AAIF;AAAA;EAEC,O1K5gBe;E0K6gBf,kB1K1hBY;;;A0K6hBb;EACC,kB1KvhBmB;E0KwhBnB;EACA,erK/iB4B;EqKgjB5B,arK5iB+B;;AqK8iB/B;EACC,kB1K7hBkB;E0K8hBlB;;AAEA;EAJD;IAKE;;;AAIF;EACC;;;AAKD;EACC,gBrKrjByB;;;AqKyjB3B;EACC;EACA;;;AAGD;EACC;;;AAGD;AACA;AAAA;EAEC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC,O1K7lBkB;A0K8lBlB;;;AAGD;EACC;;;AAGD;AACA;AAAA;EAEC,O1K9kBe;E0K+kBf,kB1K5lBY;E0K6lBZ;;;AAGD;EACC;;AAEA;EACC;;;AAIF;EACC;EACA;;;AAGD;AAAA;EAEC;;;AASD;AAAA;AAAA;EAGC;EACA;;;AAGD;EACC;;;AAKD;AAAA;EAEC;EACA;;;AAGD;AAAA;EAEC;;;AAGD;EACC;;;AAID;EACC;EACA;;;AAGD;AACA;EACC;EACA;;AlJ9nBA;EACC,SAHwB;EAIxB;;;AkJioBF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA,c1K/rBiB;;;A0KksBlB;EACC;;;AAGD;AACA;EACC;;;AAGD;EACI;EACA,kB1KlsBS;E0KmsBT,a3KxtBa;E2KytBb,c3KztBa;E2K0tBb,e3K1tBa;E2K2tBb;EACA,SrKzsBuB;EqK0sBvB;EACA;EACA;;AAEA;EACI,kB1KnsBU;;;A2KpClB;AAEA;EACC,a9KoCwB;;;A8KjCzB;EACC;;;AAGD;EACC;EACA,W9KCqB;;;A8KEtB;AAAA;EAEC;EACA;;;AAGD;AAAA;AAAA;AAAA;EAIC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA,W9KxBqB;E8KyBrB,a9KCwB;E8KAxB;;;AAGD;EACC;;;AAGD;EACC;EACA;;AACA;EAHD;IAIE;;;;AAIF;EACC;EACA;;;AClDD;EACC,QtKoBgC;EsKnBhC,YtKqBmC;;;AsKhBnC;EACC;;AAGD;EACC;EACA;EACA,W/KLqB;;;AgLbvB;AAGC;EADD;IAEE;;;;AAMD;EACE;;AACD;EACC;;AALH;EASC,ahLQyB;EgLPzB;EACA;EACA;;AACA;EAbD;IAcM;IAEA;;EAEA;IACE;;EACA;IACE;;;;AAOV;EACC;;AACA;EACC;;;AAIF;EACC;;AACA;EACC;;;AAIF;EACC,QpIhDiB;EoIiDjB,e9KzCkC;;A8K2ClC;EACC;EACA,kB7K5BgB;;A6K+BjB;EACC;;AAVF;EAaC;EACA;;AACA;EAfD;IAgBE;;;;ACnEF;EACC;;;AAGD;EACC,kB9KoBY;E8KnBZ;;;ACPD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA,WlLbsB;EkLctB;EACA;;;AAGD;EACC;AACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;AACA;EACA,kB/KlBmB;;;A+KqBpB;EACC;EACA;;;ACxDD;AAEA;EACC,anLkCwB;;;AmL/BzB;EACC,anLgCwB;;;AmL7BzB;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAIA;EACC;;AAED;EACC;EACA;;;AAOC;EACC;EACA;EACA;EACA;;;ACvDJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;AAAA;EAEE;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAIA;EACE;EACA;;;AC/KJ;AAEA;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA,WrLHqB;EqLIrB;EACA;EACA;AACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;A1J/BA;AAAA;EACC;EACG;;AAEJ;AAAA;EACC;EAEA,SARwB;EASxB;;AAEA;AAAA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;;AAEzB;EACC;EACG;;AAEJ;EACC;EAEA,SARwB;EASxB;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;;AAoEzB;EACC;EACA,QAJwB;EAKxB;;;AAUD;AAAA;AAAA;EACC;EACA;EACA;EACG;;AAOJ;AAAA;AAAA;EACC;EACA;EACA;EACG;;AA5BJ;AAAA;AAAA;EACC;EACA,QAJwB;EAKxB;;;A0JfF;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AC3ED;AAEA;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;;;ACnBD;AAEA;EACC;EACA;EACA;EACA;EACA;EACA,WvLGsB;;;AuLAvB;EACC;EACA;EACA;EACA;EACA;EACA,kBpLgBmB;;;AoLbpB;EACC;EACA;EACA;EACA;;;ACtBD;AAEA;EACC;;AACA;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;EACA;;AAED;EACC;;;AAIF;EACC;IACC;;;AAIF;EACC,kBrLlBkB;EqLmBlB;EACA;EACA,WxLvBsB;EwLwBtB;EACA;EACA;;AACA;EACC;EACA;;;AAIF;AAEA;EACC;EACA;EACA;;AACA;EACC;EACA;EACA;EACA;EACA;EACA,kBtLpD0B;EsLqD1B;EACA;;AACA;EATD;IAUE;;;AAGF;EACC;EACA;EACA;;AACA;EACC;EACA;;AACA;EAHD;IAIE;;;AAED;EACC;EACA;EACA;EACA;;AACA;EALD;IAME;IACA;;;AAIH;EArBD;IAsBE;;;AAED;EACC;EACA;;AAED;EACC;;AAED;EACC;EACA;EACA;EACA;EACA,YrLrEe;EqLsEf,Q5I/Fe;;A4IgGf;EAPD;IAQE;;;AAED;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAED;EACC;;AAGF;EACC;EACA;EACA;EACA;EACA;EACA,WxL9GoB;EwL+GpB;EACA;EACA;EACA,kBrL1GsB;EqL2GtB;EACA;EACA;EACA;;AACA;EAfD;IAgBE;IACA;IACA;;;AAED;EACC,WxL7HmB;;AwL+HpB;EACC,WxLpImB;;AwLsIpB;EACC;EACA;;AAGF;EACC;;AACA;EAFD;IAGE;;;AAED;EACC;EACA;EACA;EACA;;AACA;EALD;IAME;IACA;IACA;IACA;;;AAGF;EACC;EACA;EACA;EACA;;AACA;EALD;IAME;IACA;IACA;IACA;;;AAKJ;EACC;EACA;;AAED;EACC,kBrL5JgB;;;AqLgKlB;AACC;AAAA;AAAA;;;AAKD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;;AAEA;EALD;IAME;;;;AAIF;EACC;EACA;;AAEA;EAJD;IAKE;IACA;;;;AAIF;EACC;;AACA;EAFD;IAGE;;;;AAIF;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;AACA;EACC;EACA;EzL9DC,oByL+DD;EzL9DM,eyL8DN;EzL7DS,YyL6DT;EACA;;;AAGD;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AClRD;AAEA;AACI;;;AAEJ;EACI;;;AAEJ;EACC,kBtLeY;EsLdZ;;;AAGD;EACC,kBtLUY;;;AsLPb;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;;AACA;EACC;EACA;;;AAIF;EACC,WzLzBqB;EyL0BrB;;;AAGD;EACC,kBtLbiB;EsLcjB;EACA;;AAEC;EACC;EACA;;;AAMF;EACC;;;AAIF;EACC;;;AAGD;EACC,WzLhDqB;EyLiDrB,OtL3Be;EsL4Bf;;;AAGD;EACC,WzLxDsB;EyLyDtB;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAIA;EACC;;AAED;EACC;;;AAIF;EACC,ejLzF4B;;;AiL6F5B;EACC;EACA;;;AAIF;EACC,Y7I1GiB;;A6I2GjB;EACC;;;AAIF;EACC;;;ACtHD;AAcA;EACC;EACA;;;AAID;EACC,W1LVsB;E0LWtB;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC,exL7BgB;EwL8BhB,kBvLTY;;AuLUT;EACI;;;AAKR;EACI;;AAEI;EACI,kBvLpBC;;AuLuBD;EACI;;AAGA;EACI;;;ACtDpB;EACC;;;AAIA;EACC;EACA;EACA;EACA;;;AAIF;EACC;EACA;EACA;EACA;EACA;AACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;;AAGD;EACC;EACA;EACA;;AACA;EACC;EACA;;AAEA;EACC;;AAGD;EACC;EACA;;AAKH;EACC;EACA;EACA;EACA;EACA;EACA,kBxLjCW;;AwLmCX;EACC;;AAGD;EACC;EACA;;AAGD;EACC;;AAGD;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;AAED;EACC;EACA;EACA;;AAED;EACC;EACA;EACA;;AAED;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;;AAGD;EACC;;AAEA;EACC;EACA;;AAGD;EACC;EACA;EACA;;AAGD;EACC;EACA,kBxLxIa;;AwL0Ib;EACC,W3L5JgB;E2L6JhB;EACA;;AAIF;EACC;EACA;;AAIA;EACC;EACA;EACA;;AAKD;EACC;EACA;;AAMA;EACC,W3L3LgB;;A2L+LlB;EACC;EACA,OxL9JgB;EwL+JhB,W3LhMgB;;A2LsMpB;EACC;EACA;EACA;;AAEA;EACC,W3L9MmB;E2L+MnB;EACA;EACA;EACA;EACA;;AAEA;EACC;;AAGD;EACC;EACA;EACA;;AAGD;EACC;;AAGD;EACC;EACA;;AAIF;EACC;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;;AAKH;EACC;EACA;EACA;EACA;;;AAOH;EACC;;AAED;EACC;;;AAIF;EACC;EACA;EACA;EACA;EACA;;;AChTD;AAEA;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;AAEA;EACC;;;AAIF;EACG;EACA;EACA;;;AAGH;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AC7BD;EACC;;AACA;EACC,a7L+BuB;;;A6L1BxB;EACC;EACA;EACA,W7LGoB;E6LFpB;;AAED;EACC;;;AAIF;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA,O1LIe;E0LHf;EACA;EACA;EACA;EACA;E9L8BC,oB8L7BE;E9L8BM,Y8L9BN;EACH;;;AAGD;EACC,kB1LhBiB;E0LiBjB;EACA,W7LrCsB;;A6LsCtB;EACC;;AAED;EACC;EACA;;;AAKD;EACC,arLpD0B;;AqLsD3B;EACC;;AAED;EACC;;;AAIF;EACC;E9LDC,oB8LEE;E9LDM,Y8LCN;EACH,O1LlCe;;;A0LqChB;EACC,a7LtCwB;;;A6LyCzB;EACC;EACA,W7LvEsB;E6LwEtB,a7L9CwB;E6L+CxB;;;AAGD;EACC;;;AAGD;EACC;;AACA;EACC;;;AC9FF;AAEA;EACC,Y3L2BiB;E2L1BjB;EACA;EACA;;;AAGD;EACC;EACA;EACA,W9LKqB;E8LJrB;;;AAGD;EACC;EACA;EACA,W9LJsB;E8LKtB,O3L0BqB;E2LzBrB;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;;;AAGD;EACC,W9LrCsB;E8LsCtB;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC,kB3LjCiB;;;A2LoClB;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;AAEA;EACC;EACA;;;AAKF;EACC,c3LVqB;;;A2LatB;EACC,c3LhBqB;;;A2LmBtB;EACC;;AACA;EACC;EACA;;;AAKD;EACC;;AAED;EACC;;AACA;EACC;EACA;;;AAOH;EACC;;;AAGD;EACC,O3L7CqB;;;A2LgDtB;EACC,O3LnDqB;;;A2LsDtB;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;;AACA;EACC;EACA;;;AAIF;EACC;;;AC9JD;AAEA;EACC;;;AAGD;AAEA;EACC;EACA;EACA,QvLP0B;EuLQ1B,kB5LaY;E4LZZ;EACA;;;AAGD;AAAA;AAAA;AAAA;EAIC;EACA;EACA;EACA,W/LdsB;E+LetB;EACA,kB5LDY;E4LEZ,a/LWwB;;;A+LRzB;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC,W/L/BqB;E+LgCrB,a/LNwB;E+LOxB;EACA;EACA,O5LTe;E4LUf;;;AChCD;EACI;;AAMA;EACI;EACA;EACA;;AAKA;AAAA;EACI;EACA;EACA;;;AAKZ;EACI,axLtCc;EwLuCd,gBxLvCc;EwLwCd,O7LzBe;E6L0Bf;;;AAGJ;EACI;;;AAKF;EACD;EACA;EACA;;AAMC;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE,SxL7Dc;EwL8Dd,ahMvCmB;EgMwCnB;EACA;;AAKH;EACE;EACA;;AAOD;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;;AAKH;EACE;;AAIF;EACE,kB7LpEU;;;A6LgFX;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE,SxLvF0B;;;AwLkG7B;EACE,kB7L9FU;;;A6LwGX;EACD;EACA;;AAEA;EAJC;IAKC;IACA;IACA;IACA;IACA;;EAGA;IACD;;EAOC;AAAA;AAAA;AAAA;AAAA;AAAA;IAEE;;;;AAWL;AAEA;EACC,ahMjIwB;EgMkIxB,kB7LzIiB;E6L0IjB;EACA,WhM9JsB;EgM+JtB;;;AAGD;EACC,ahMzIwB;EgM0IxB,exLvK2B;EwLwK3B;EACA,WhMtKsB;EgMuKtB;EAEA,ahMzJyB;;AgM4JxB;EACC;;AAED;EACC;;AAIF;EACC;;AAED;EAEC;;;AAIF;EACC,O7LlKe;E6LmKf,ahMrKwB;EgMsKxB,kB7L7KiB;E6L8KjB;;;AAGD;EACC;EACA;EACA,kB7LpLiB;;;A6LuLlB;EACC,ahM/KwB;EgMgLxB;EACA,WhM3MqB;EgM4MrB,O7LlLe;E6LmLf;;;AAGD;EACC;EACA;;AACA;EACC;;;AAIF;EACC,ahM/LwB;EgMgMxB,WhMxNsB;EgMyNtB;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA,kB7LrNiB;;;A6LwNlB;EACC,kB7L7NY;E6L8NZ;EACA,WhM5OqB;EgM6OrB;;;AAGD;EACC;;;AAGD;EACC,kB7LpOiB;E6LqOjB;EACA,WhMvPqB;;;AgM0PtB;EACC,O7LjOe;;;A6LoOhB;EACC;;;AAGD;EACC;;;AAID;EACC;EACA;;;AAGD;EACC,WhM/QsB;EgMgRtB;EACA;EACA;EACA,ahMzPwB;EgM0PxB;;AACA;EACC;EACA;EACA;;;AAIF;EACC,kB7L1QiB;E6L2QjB;EACA;;;AAGD;EACC;EACA,kB7LjRiB;E6LkRjB;;;AAGD;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA,WhM7TsB;EgM8TtB;EACA;EACA;;;AAID;EACC,WhMrUsB;EgMsUtB,ahM1SwB;EgM2SxB;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC,ahMvTwB;;;AgM0TzB;EACC,ahM3TwB;EgM4TxB,kB7LnUiB;E6LoUjB,WhMrVqB;EgMsVrB;;;AAGD;AACA;EACC,kB7LvUmB;E6LwUnB,O7LlUe;E6LmUf;;;AAGD;EACC,kB7LpVY;E6LqVZ,O7LxUe;E6LyUf;;;AAGD;EACC;;;AAGD;EACC,kB7LpViB;E6LqVjB,O7LlVe;E6LmVf;;;AAGD;EACC,kB7L7VmB;E6L8VnB,O7LxVe;E6LyVf;EACA;;;AAGD;EACC,kB7L3WY;E6L4WZ,O7L/Ve;E6LgWf;EACA;;;AAGD;EACC,kB7LxWiB;E6LyWjB,O7LtWe;E6LuWf;EACA;;;AAMD;EACC;EACA,kB7L7XY;;;A6LgYb;EACC,kB7LjYY;;A6LqYV;EACC;;;AAMJ;EACI;;;AAKF;EACC;;;AAeH;EACC;IACC;IACA;;;AAIF;EACC;IACC;;;AClcF;AAEA;EACC,WjMOqB;EiMNrB;;;AAGA;EACC;;;AAGF;EACC,kB7L6Be;A6L5Bf;EACA;EACA;EACA;EACA;EACA;EACA,e/LTkC;;A+LclC;EACC;EACA;;AAED;EACC;EACA;;AAED;EACC;EACA;;AAED;EACC;EACA;;AAGD;EACC;EACA;;AAEA;EACC;;;AAKH;EACC;EACA;EACA;;;AAGD;EACC;;;AC9DC;EACE;;;ACAJ;AAEA;EACC;EACA;EACA;;;AAGD;EACC;EACA,WnMGqB;;;AmMAtB;EACC;EACA;EACA;;;AAGD;EACC;EACA,OhMhBe;;;AgMmBhB;EACC,kBhMWiB;;;AgMRlB;EACC,OhMiBqB;EgMhBrB,WnMnBsB;EmMoBtB;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;ACzCD;AAEA;EACC;EACA,kBjMwBiB;;;AiMflB;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA,kBjMFiB;;;AiMKlB;EACC,OjMGe;EiMFf;EACA;EACA;EACA;EACA,apMFwB;EoMGxB,WpM7BqB;;;AoMgCtB;EACC,WpMjCqB;;;AoMoCtB;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAID;EACC,kBjMjCiB;EiMkCjB;;;AAGD;EACC;EACA;EACA;;;AAID;EACC;;;AAGD;AACA;EACC;;;AAGD;EACC;EACA;;;AAGD;EACC,WpMhFsB;EoMiFtB;;;AAGD;EACC;EACA;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;AAAA;EAEC;EACA;ErM7CC,oBqM8CE;ErM7CM,YqM6CN;;;AAKJ;EACC;;;AAGD;AAAA;EAEC;EACA;EACA;EACA,OjMtFqB;EiMuFrB,elMtHkC;;;AkMyHnC;AAAA;EAEC;EACA;EACA;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACI;;;AAGJ;EACC;;AAEA;EACC;;;AAIF;EACC;;;AAIA;EACC;;AAED;EACC,apMzKqB;EoM0KrB;;;ACzLF;AAEA;EACC;EACA;EACA;EACA;EACA;EACA,kBlMUkB;EkMTlB;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA,OlMqBe;EkMpBf;;;AAGD;EACC,OlMqBqB;EkMpBrB;;;AAGD;EACC;EACA;EACA;;;AAIA;EACC;EACA;;;ACpCF;AACA;EACC;EACA;;;AAGD;EACC;;;AAED;EACC,OnM6Be;;AmMzBd;EACC;;AAED;EACC;;;ACdH;EACC;EACA;;;AAGD;EACC;EACA;EACA;;;AAGD;EACC,WvMHqB;EuMIrB;EACA;EACA;EACA,OpMamB;EoMZnB,kBpMhBe;;;AoMmBhB;EACC,kBpMlBoB;;;AqMDrB;AAEA;EACC;EACA;EACA;EACA,eAPiB;;AASjB;EACC;EAEA;;AAGA;AAAA;EAEC;EACA;EACA,WxMToB;EwMUpB,axMCoB;EwMApB;EACA;EACA;EACA;;AAEA;AAAA;AAAA;EAEC,qBrMMY;;AwBiDf;AAAA;EACC;EACA;EACA;EACG;;AAEF;AAAA;EACC;;AAIH;AAAA;EACC;EACA;EACA;EACG;;AAEF;AAAA;EACC;;AAjGH;AAAA;EACC;EACG;;AAEJ;AAAA;EACC;EAEA,SARwB;EASxB;;AAEA;AAAA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;A6KmCvB;EAGC,OrMnBS;EqMoBT;EACA,kBrMRY;EqMSZ,qBrMTY;;;AqMehB;EACC;;;AAGD;EACC;;;AAGD;AACA;EACC;EACA;;AAEA;AAAA;EAEC,chM5D4B;;AgMgE7B;EACC;;AAEA;AAAA;EAEC;EACA;EACA;;AAEA;AAAA;EACC;EACA;;A7KIH;AAAA;EACC;EACA;EACA;EACG;;AAEF;AAAA;EACC;;AAIH;AAAA;EACC;EACA;EACA;EACG;;AAEF;AAAA;EACC;;AAjGH;AAAA;EACC;EACG;;AAEJ;AAAA;EACC;EAEA,SARwB;EASxB;;AAEA;AAAA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;A6KoFvB;EAGC,OrMzFY;EqM0FZ;EACA;;;AAMJ;EACC,ehMzF6B;;;AiMN9B;AAyBA;EACC;EACA;EACA;;AxIrCC;EACE;EACA;EACA;;AwIqCH;EACC;EACA;;AAEA;EACC;EACA;EACA,SA/BgB;;AAiChB;EAEC;;AAKF;EACC,OtM1Be;;AsM4Bf;EAEC,OtM9Bc;EsM+Bd;EACA,QA3Cc;EA4Cd;;AAQF;EAGC,kBtMzCiB;EsM0CjB,ctMtEa;;AsM+Ef;ElM9EC;EACA;EACA;EACA,kBAJyB;;AkMsF1B;EACC;;;AAIF;EACC;EACA;;;AAOD;EAEC;ElG1GC,wBkG4G0B;ElG3G1B,yBkG2G0B;;;AAI5B;EACC;EACA,kBtMrFiB;EsMsFjB,ejMnG8B;;AiMoG9B;EACC,aA/FkB;EAgGlB;EACA,ejM7G2B;;AiM+G5B;EACC;EACA;EACA;;AAED;EACC;EACA;;AACA;EACC;;;AClIH;AAEA;EACC;EACA;EACA,kBvMwBiB;EuMvBjB,SlMU8B;;AkMT9B;EACC,YlMQ6B;;AkML9B;EACC,YlMI6B;;AkMH7B;EACC;;;AAKH;EACC;;;AAGD;EACC;EACA;EACA,a1MUwB;E0MTxB,W1MTwB;;;A0MYzB;EACC,YlMf8B;EkMgB9B,W1MpBqB;E0MqBrB,OvMYqB;;;AuMTtB;EACC;EACA;EACA,a1MHwB;E0MIxB,W1MxBqB;E0MyBrB,OvMHe;;;AuMMhB;EACC,kBvMpBY;;;AuMuBb;EACC;;;AClDD;EACC;;AhLQA;EACC;EACG;;AAEJ;EACC;EAEA,SARwB;EASxB;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EAEA,QAnBuB;EAqBvB,SAtBuB;;;A4CN1B;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AqIKA;AAAA;AAAA;AAMA;AACA;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;;;A3IpCC;EACE;EACA;EACA;;;A2IwCJ;AAAA;EC3CI;;;ADgDJ;AAAA;EC5CI;;;ADiDJ;EACC;;;AAGD;EACC;;;AAGD;AACA;EACC;;;AAGD;EACC;;;AAGD;AAAA;AAEA;EACC;;;AAED;AAEA;AACA;EACC;EACA;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;;AACA;EAHD;IAIE;;;;AAIF;AACA;EACC;;;AAKA;EADD;IAEE;;;;AAKF;EACC;EACA;EACA;EACA,W5MrGqB;E4MsGrB;EACA;;;AAED;EACC,czM/DgB;;;AyMmEjB;EACI;EACA;;;AAIJ;EACI;;;AAIJ;EACC;EACA;EACA;;;AAID;EACI,W5MjIkB;E4MkIrB;;;AAKD;EACC;;;AAUD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkEA;EACC;EACA;;;AAID;EACC;EACA;EACA;EACA;E7MrKC,oB6MsKE;E7MrKM,Y6MqKN;EACH;EACA,kBzMhNiB;EyMiNjB;;AACA;EATD;IAUE;IACA;;;;AASC;EACC;;;ArIjPH;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AqI0OF;ArIvOC;;AACA;EACC;IACC;IACA;IACA;IACA,oBqIkO+B;IrIjO/B;;EAGD;IACC;;;AqI4NH;ArIxNC;;AACA;EACC;IACC;IACA;IACA;IACA,iBqImN+B;IrIlN/B;;EAGD;IACC;;;;AA5CF;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AqI8OF;ArI3OC;;AACA;EACC;IACC;IACA;IACA;IACA,oBqIsO+B;IrIrO/B;;EAGD;IACC;;;AqIgOH;ArI5NC;;AACA;EACC;IACC;IACA;IACA;IACA,iBqIuN+B;IrItN/B;;EAGD;IACC;;;;AA5CF;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AqIkPF;ArI/OC;;AACA;EACC;IACC;IACA;IACA;IACA,oBqI0O+B;IrIzO/B;;EAGD;IACC;;;AqIoOH;ArIhOC;;AACA;EACC;IACC;IACA;IACA;IACA,iBqI2N+B;IrI1N/B;;EAGD;IACC;;;;AA5CF;EACC;EACA;EACA;EACA,avEgBqB;;AuEbtB;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AqIsPF;ArInPC;;AACA;EACC;IACC;IACA;IACA;IACA,oBqI8O+B;IrI7O/B;;EAGD;IACC;;;AqIwOH;ArIpOC;;AACA;EACC;IACC;IACA;IACA;IACA,iBqI+N+B;IrI9N/B;;EAGD;IACC;;;;AqIgOH;ExKpQC;;;AwKwQD;ExKhRC;;;AwKoRD;ExKhRC;;;AwKoRD;EACC;;;AAGD;EACC;;;AAGD;AACA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGD;AACA;EACC;EACA,W5M3SsB;;;A4M8SvB;EACC;EACA,W5MlTqB;;;A4MqTtB;EACC;EACA,W5MzTsB;;;A4M4TvB;EACC;EACA,W5M5TqB;E4M6TrB;;;AAGD;EACC;EACA,W5MlUqB;E4MmUrB,OzMjUiB;;;AyMoUlB;EACC,a5M/SwB;E4MgTxB;EACA;;;AAGD;EACC;EACA,a5MpTwB;E4MqTxB,OzM7UiB;;;AyMgVlB;EACC;EACA,a5M1TwB;E4M2TxB;EACA,OzMpViB;;;AyMuVlB;EACC,OzMxViB;EyMyVjB,W5M3VqB;;;A4M8VtB;EACC;EACA,a5MxUwB;;;A4M4UzB;EACC;EACA,a5M9UwB;;;A4MiVzB;EACC;EACA,a5MnVwB;E4MoVxB,W5M5WqB;;;A4M+WtB;EACC,a5MtVwB;;;A4MyVzB;EACC,a5M1VwB;;;A4M6VzB;EACC,OzMvVqB","file":"delos.scss"} \ No newline at end of file