diff --git a/.gitignore b/.gitignore
index aabd7486658..de95095bf11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ www/build
.sass-cache/
www/lib
e2e/build
+/desktop
diff --git a/AppXManifest.xml b/AppXManifest.xml
new file mode 100644
index 00000000000..d31855a1b76
--- /dev/null
+++ b/AppXManifest.xml
@@ -0,0 +1,44 @@
+
+
+
+
+ Moodle Desktop
+ Moodle Pty Ltd.
+ The official app for Moodle.
+ assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Moodle Mobile URI Scheme
+
+
+
+
+
+
diff --git a/config.xml b/config.xml
index 762cadb9a29..b25195875f3 100644
--- a/config.xml
+++ b/config.xml
@@ -1,77 +1,89 @@
-
- Moodle Mobile
- Official Moodle Mobile app
- Juan Leyva
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Moodle Mobile
+
+ Moodle Mobile official app
+
+
+ Moodle Mobile team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 553a2c9c0d5..d8d37a8dabb 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,11 @@
{
- "name": "mm2",
- "version": "1.0.0",
- "description": "Moodle Mobile 2: The official mobile app for Moodle.",
+ "name": "com.moodle.moodlemobile",
+ "version": "3.3.0",
+ "description": "The official app for Moodle.",
+ "author": {
+ "name": "Moodle Pty Ltd.",
+ "email": "mobile@moodle.com"
+ },
"repository": {
"type": "git",
"url": "https://github.com/moodlehq/moodlemobile2.git"
@@ -14,22 +18,25 @@
}
],
"dependencies": {
+ "electron-windows-notifications": "^1.1.13",
+ "electron-builder-squirrel-windows": "^19.3.0"
},
"devDependencies": {
"appium": "^1.6.0",
"bower": "^1.3.3",
+ "electron-rebuild": "^1.5.11",
"gulp": "^3.9.1",
- "gulp-clean-css": "^3.0.3",
- "gulp-concat": "^2.6.0",
- "gulp-rename": "^1.2.0",
- "gulp-sass": "^2.3.2",
"gulp-clean": "^0.3.2",
+ "gulp-clean-css": "^3.0.3",
"gulp-clip-empty-files": "^0.1.1",
+ "gulp-concat": "^2.6.0",
"gulp-concat-util": "^0.5.2",
"gulp-file": "^0.3.0",
"gulp-insert": "^0.5.0",
"gulp-ng-annotate": "^2.0.0",
"gulp-remove-empty-lines": "0.0.8",
+ "gulp-rename": "^1.2.0",
+ "gulp-sass": "^2.3.2",
"gulp-slash": "^1.1.3",
"gulp-strip-comments": "^2.4.3",
"gulp-tap": "^0.1.3",
@@ -121,6 +128,45 @@
"android": "ionic run android",
"serve.e2e": "ionic serve -b -a",
"serve.dev": "ionic serve",
- "e2e": "protractor e2e/build/protractor.conf.js"
+ "e2e": "protractor e2e/build/protractor.conf.js",
+ "desktop.pack": "build --dir",
+ "desktop.dist": "build",
+ "windows.store": "electron-windows-store --input-directory .\\desktop\\dist\\win-unpacked --output-directory .\\desktop\\store --flatten true -a .\\resources\\desktop -m .\\AppXManifest.xml --package-version 0.0.0.0 --package-name MoodleDesktop"
+ },
+ "main": "www/electron.js",
+ "build": {
+ "appId": "com.moodle.moodlemobile",
+ "productName": "MoodleDesktop",
+ "files": [
+ "!desktop",
+ "!**/e2e",
+ "!hooks",
+ "!platforms",
+ "!plugins",
+ "!resources",
+ "!**/*.scss"
+ ],
+ "directories": {
+ "output": "desktop/dist"
+ },
+ "protocols": [
+ {
+ "name": "Moodle Mobile URL",
+ "schemes": [
+ "moodlemobile"
+ ],
+ "role": "Viewer"
+ }
+ ],
+ "compression": "maximum",
+ "electronVersion": "1.6.11",
+ "mac": {
+ "category": "public.app-category.education",
+ "icon": "resources/desktop/icon.icns"
+ },
+ "win": {
+ "target": "appx",
+ "icon": "resources/desktop/icon.ico"
+ }
}
}
diff --git a/resources/android/icon.png b/resources/android/icon.png
old mode 100644
new mode 100755
index b98d8a19f2a..23e01833453
Binary files a/resources/android/icon.png and b/resources/android/icon.png differ
diff --git a/resources/android/icon/drawable-hdpi-icon.png b/resources/android/icon/drawable-hdpi-icon.png
index 7cf11c2ab6f..d20db6c0a09 100644
Binary files a/resources/android/icon/drawable-hdpi-icon.png and b/resources/android/icon/drawable-hdpi-icon.png differ
diff --git a/resources/android/icon/drawable-ldpi-icon.png b/resources/android/icon/drawable-ldpi-icon.png
index 18cbb4dbd57..f96ff0b7157 100644
Binary files a/resources/android/icon/drawable-ldpi-icon.png and b/resources/android/icon/drawable-ldpi-icon.png differ
diff --git a/resources/android/icon/drawable-mdpi-icon.png b/resources/android/icon/drawable-mdpi-icon.png
index 85492e12e16..1911c9d650d 100644
Binary files a/resources/android/icon/drawable-mdpi-icon.png and b/resources/android/icon/drawable-mdpi-icon.png differ
diff --git a/resources/android/icon/drawable-xhdpi-icon.png b/resources/android/icon/drawable-xhdpi-icon.png
index 408ce3ab19c..b87391cffce 100644
Binary files a/resources/android/icon/drawable-xhdpi-icon.png and b/resources/android/icon/drawable-xhdpi-icon.png differ
diff --git a/resources/android/icon/drawable-xxhdpi-icon.png b/resources/android/icon/drawable-xxhdpi-icon.png
index 68d01f62dc1..3bc10a5e21c 100644
Binary files a/resources/android/icon/drawable-xxhdpi-icon.png and b/resources/android/icon/drawable-xxhdpi-icon.png differ
diff --git a/resources/android/icon/drawable-xxxhdpi-icon.png b/resources/android/icon/drawable-xxxhdpi-icon.png
index 5a73b291c35..91640a3cde5 100644
Binary files a/resources/android/icon/drawable-xxxhdpi-icon.png and b/resources/android/icon/drawable-xxxhdpi-icon.png differ
diff --git a/resources/desktop/Square150x150Logo.png b/resources/desktop/Square150x150Logo.png
new file mode 100644
index 00000000000..dd059984b4a
Binary files /dev/null and b/resources/desktop/Square150x150Logo.png differ
diff --git a/resources/desktop/Square44x44Logo.png b/resources/desktop/Square44x44Logo.png
new file mode 100644
index 00000000000..b1ad9e9bdc2
Binary files /dev/null and b/resources/desktop/Square44x44Logo.png differ
diff --git a/resources/desktop/StoreLogo.png b/resources/desktop/StoreLogo.png
new file mode 100644
index 00000000000..fa5cebb178b
Binary files /dev/null and b/resources/desktop/StoreLogo.png differ
diff --git a/resources/desktop/Wide310x150Logo.png b/resources/desktop/Wide310x150Logo.png
new file mode 100644
index 00000000000..70e54eb7375
Binary files /dev/null and b/resources/desktop/Wide310x150Logo.png differ
diff --git a/resources/desktop/icon.icns b/resources/desktop/icon.icns
new file mode 100644
index 00000000000..4e3c10b84e4
Binary files /dev/null and b/resources/desktop/icon.icns differ
diff --git a/resources/desktop/icon.ico b/resources/desktop/icon.ico
new file mode 100644
index 00000000000..c65354c8136
Binary files /dev/null and b/resources/desktop/icon.ico differ
diff --git a/resources/ios/icon.png b/resources/ios/icon.png
index 2f5b179c7bc..ddcce9da81b 100644
Binary files a/resources/ios/icon.png and b/resources/ios/icon.png differ
diff --git a/resources/ios/icon/icon-40.png b/resources/ios/icon/icon-40.png
index 5f586ad9cdd..9311b8b3f69 100644
Binary files a/resources/ios/icon/icon-40.png and b/resources/ios/icon/icon-40.png differ
diff --git a/resources/ios/icon/icon-40@2x.png b/resources/ios/icon/icon-40@2x.png
index 7b1f2478c51..63f826ea1bd 100644
Binary files a/resources/ios/icon/icon-40@2x.png and b/resources/ios/icon/icon-40@2x.png differ
diff --git a/resources/ios/icon/icon-40@3x.png b/resources/ios/icon/icon-40@3x.png
index bc5c9ba0c20..8d8da619985 100644
Binary files a/resources/ios/icon/icon-40@3x.png and b/resources/ios/icon/icon-40@3x.png differ
diff --git a/resources/ios/icon/icon-50.png b/resources/ios/icon/icon-50.png
index 810b1fa020b..02f6868c01c 100644
Binary files a/resources/ios/icon/icon-50.png and b/resources/ios/icon/icon-50.png differ
diff --git a/resources/ios/icon/icon-50@2x.png b/resources/ios/icon/icon-50@2x.png
index d500206f169..f131e00094e 100644
Binary files a/resources/ios/icon/icon-50@2x.png and b/resources/ios/icon/icon-50@2x.png differ
diff --git a/resources/ios/icon/icon-60.png b/resources/ios/icon/icon-60.png
index 2ab0816738c..854c33f6c09 100644
Binary files a/resources/ios/icon/icon-60.png and b/resources/ios/icon/icon-60.png differ
diff --git a/resources/ios/icon/icon-60@2x.png b/resources/ios/icon/icon-60@2x.png
index bc5c9ba0c20..8d8da619985 100644
Binary files a/resources/ios/icon/icon-60@2x.png and b/resources/ios/icon/icon-60@2x.png differ
diff --git a/resources/ios/icon/icon-60@3x.png b/resources/ios/icon/icon-60@3x.png
index 4c3d9fe188c..b94721b25cd 100644
Binary files a/resources/ios/icon/icon-60@3x.png and b/resources/ios/icon/icon-60@3x.png differ
diff --git a/resources/ios/icon/icon-72.png b/resources/ios/icon/icon-72.png
index 93f8d10b773..9204a054b40 100644
Binary files a/resources/ios/icon/icon-72.png and b/resources/ios/icon/icon-72.png differ
diff --git a/resources/ios/icon/icon-72@2x.png b/resources/ios/icon/icon-72@2x.png
index e0915e1bff8..5dff7993c18 100644
Binary files a/resources/ios/icon/icon-72@2x.png and b/resources/ios/icon/icon-72@2x.png differ
diff --git a/resources/ios/icon/icon-76.png b/resources/ios/icon/icon-76.png
index f57b285daac..87c4cc3f2bf 100644
Binary files a/resources/ios/icon/icon-76.png and b/resources/ios/icon/icon-76.png differ
diff --git a/resources/ios/icon/icon-76@2x.png b/resources/ios/icon/icon-76@2x.png
index 0d753ccd2f5..3345289a548 100644
Binary files a/resources/ios/icon/icon-76@2x.png and b/resources/ios/icon/icon-76@2x.png differ
diff --git a/resources/ios/icon/icon-83.5@2x.png b/resources/ios/icon/icon-83.5@2x.png
index 37c031c37a9..779bb361ae9 100644
Binary files a/resources/ios/icon/icon-83.5@2x.png and b/resources/ios/icon/icon-83.5@2x.png differ
diff --git a/resources/ios/icon/icon-small.png b/resources/ios/icon/icon-small.png
index 0ceb97036ea..457fe4a6580 100644
Binary files a/resources/ios/icon/icon-small.png and b/resources/ios/icon/icon-small.png differ
diff --git a/resources/ios/icon/icon-small@2x.png b/resources/ios/icon/icon-small@2x.png
index 450216cf66c..f7e20964b63 100644
Binary files a/resources/ios/icon/icon-small@2x.png and b/resources/ios/icon/icon-small@2x.png differ
diff --git a/resources/ios/icon/icon-small@3x.png b/resources/ios/icon/icon-small@3x.png
index 1f75d32fa50..95b5d64681b 100644
Binary files a/resources/ios/icon/icon-small@3x.png and b/resources/ios/icon/icon-small@3x.png differ
diff --git a/resources/ios/icon/icon.png b/resources/ios/icon/icon.png
index 1540b259568..2414ad2b8d4 100644
Binary files a/resources/ios/icon/icon.png and b/resources/ios/icon/icon.png differ
diff --git a/resources/ios/icon/icon@2x.png b/resources/ios/icon/icon@2x.png
index 023384d9db2..a0bbf3d384d 100644
Binary files a/resources/ios/icon/icon@2x.png and b/resources/ios/icon/icon@2x.png differ
diff --git a/scss/app.scss b/scss/app.scss
index 3a670e093c7..5d1afb1a84d 100644
--- a/scss/app.scss
+++ b/scss/app.scss
@@ -50,6 +50,14 @@ $mm-color: $orange;
$mm-color-light: lighten($mm-color, 10%);
$mm-color-dark: darken($mm-color, 10%);
+$mm-color-init-screen: #ff5c00;
+$mm-color-init-screen-alt: #ff7600;
+$mm-init-screen-spinner-color: $white;
+$mm-init-screen-logo-width: 60%;
+$mm-init-screen-logo-max-width: 300px;
+
+$mm-fixed-url: false;
+
$mm-buttons-color: $positive;
// Change Ionic default elements colors.
@@ -57,20 +65,31 @@ $base-color: $black !default;
$base-background-color: $gray-light !default;
$item-default-text: $black;
-$sheet-options-text-color: $positive;
+$sheet-options-text-color: $mm-buttons-color;
+
+$item-default-bg: $white;
+$item-divider-bg: $gray-lighter;
+$item-disabled-color: $gray-dark !default;
+
+$button-light-border: $gray;
// Header.
$bar-content-bg: $mm-color !default;
$bar-content-border: transparent !default;
$bar-content-text: $white !default;
-$item-default-bg: $white;
-$item-divider-bg: $gray-lighter;
-$item-disabled-color: $gray-dark !default;
+$bar-side-menu-height: 80px !default;
+$bar-side-menu-color: $bar-content-bg !default;
+$bar-side-menu-border-color: $bar-content-border !default;
+$bar-side-menu-text-color: $bar-content-text !default;
-$button-light-border: $gray;
+$bar-side-menu-item-border-color: $button-light-border;
+$bar-side-menu-item-divider-color: $item-divider-bg;
+$bar-side-menu-item-background-color: $item-default-bg;
+$bar-side-menu-item-text-color: $item-default-text;
+$bar-side-menu-item-icon-color: $gray-darker;
-$toggle-on-default-bg: $blue;
+$toggle-on-default-bg: $mm-buttons-color;
$tabs-off-opacity: 0.6;
$tabs-striped-off-opacity: $tabs-off-opacity;
@@ -82,6 +101,11 @@ $button-default-border: $mm-buttons-color !default;
$button-default-active-bg: $mm-buttons-color !default;
$button-default-active-border: $mm-buttons-color !default;
+$button-positive-bg: $mm-buttons-color !default;
+$button-positive-border: darken($mm-buttons-color, 10%) !default;
+$button-positive-active-bg: darken($mm-buttons-color, 10%) !default;
+$button-positive-active-border: darken($mm-buttons-color, 10%) !default;
+
// The path to the font icons.
$ionicons-font-path: "../lib/ionic/release/fonts" !default;
@@ -92,7 +116,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default;
color: $gray-darker;
&.positive {
- color: $positive;
+ color: $mm-buttons-color;
}
&.assertive {
color: $assertive;
@@ -112,7 +136,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default;
&.activated,
&.active .icon,
&.activated .icon {
- color: $positive;
+ color: $mm-buttons-color;
&.assertive {
color: $assertive;
@@ -144,7 +168,7 @@ $ionicons-font-path: "../lib/ionic/release/fonts" !default;
color: $assertive;
}
-// Setting the default button to button-outline positive.
+// Setting the default button to button-outline $mm-buttons-color.
.button {
&.button-light,
&.button-stable,
diff --git a/www/addons/badges/lang/sr-cr.json b/www/addons/badges/lang/sr-cr.json
new file mode 100644
index 00000000000..dde1e852627
--- /dev/null
+++ b/www/addons/badges/lang/sr-cr.json
@@ -0,0 +1,12 @@
+{
+ "badgedetails": "Подаци о беџу",
+ "badges": "Беџеви",
+ "contact": "Контакт",
+ "dateawarded": "Датум издавања",
+ "expirydate": "Датум истека",
+ "issuancedetails": "Беџ истиче",
+ "issuerdetails": "Подаци о издавачу",
+ "issuername": "Име/назив издавача беџа",
+ "nobadges": "Нема доступних беџева",
+ "recipientdetails": "Детаљи о примаоцу"
+}
\ No newline at end of file
diff --git a/www/addons/badges/lang/sr-lt.json b/www/addons/badges/lang/sr-lt.json
new file mode 100644
index 00000000000..7c2a996f0ba
--- /dev/null
+++ b/www/addons/badges/lang/sr-lt.json
@@ -0,0 +1,12 @@
+{
+ "badgedetails": "Podaci o bedžu",
+ "badges": "Bedževi",
+ "contact": "Kontakt",
+ "dateawarded": "Datum izdavanja",
+ "expirydate": "Datum isteka",
+ "issuancedetails": "Bedž ističe",
+ "issuerdetails": "Podaci o izdavaču",
+ "issuername": "Ime/naziv izdavača bedža",
+ "nobadges": "Nema dostupnih bedževa",
+ "recipientdetails": "Detalji o primaocu"
+}
\ No newline at end of file
diff --git a/www/addons/badges/lang/sv.json b/www/addons/badges/lang/sv.json
index 4c67f9031ef..878282c5e4f 100644
--- a/www/addons/badges/lang/sv.json
+++ b/www/addons/badges/lang/sv.json
@@ -1,6 +1,6 @@
{
"badgedetails": "Detaljer för märke",
- "badges": "Badges",
+ "badges": "Märken",
"contact": "Kontakt",
"dateawarded": "Utfärdandedatum",
"expirydate": "Förfallodatum",
diff --git a/www/addons/badges/lang/tr.json b/www/addons/badges/lang/tr.json
index b540e7cabae..5c79f345058 100644
--- a/www/addons/badges/lang/tr.json
+++ b/www/addons/badges/lang/tr.json
@@ -1,6 +1,6 @@
{
"badgedetails": "Nişan ayrıntıları",
- "badges": "Rozetler",
+ "badges": "Nişanlar",
"contact": "İletişim",
"dateawarded": "Verilen tarih",
"expirydate": "Bitiş Tarihi",
diff --git a/www/addons/calendar/controllers/list.js b/www/addons/calendar/controllers/list.js
index 5ef1ab47781..30f897430f1 100644
--- a/www/addons/calendar/controllers/list.js
+++ b/www/addons/calendar/controllers/list.js
@@ -21,9 +21,9 @@ angular.module('mm.addons.calendar')
* @ngdoc controller
* @name mmaCalendarListCtrl
*/
-.controller('mmaCalendarListCtrl', function($scope, $stateParams, $log, $state, $mmaCalendar, $mmUtil, $ionicHistory, $mmEvents,
+.controller('mmaCalendarListCtrl', function($scope, $stateParams, $log, $state, $mmaCalendar, $mmUtil, $timeout, $mmEvents,
mmaCalendarDaysInterval, $ionicScrollDelegate, $mmLocalNotifications, $mmCourses, mmaCalendarDefaultNotifTimeChangedEvent,
- $ionicPopover, $q, $translate) {
+ $ionicPopover, $q, $translate, $ionicPlatform) {
$log = $log.getInstance('mmaCalendarListCtrl');
@@ -38,10 +38,10 @@ angular.module('mm.addons.calendar')
};
$scope.events = [];
+ $scope.eventToLoad = 1;
- if ($stateParams.eventid) {
- // We arrived here via notification click, let's clear history and redirect to event details.
- $ionicHistory.clearHistory();
+ if ($stateParams.eventid && !$ionicPlatform.isTablet()) {
+ // There is an event to load and it's a phone device, open the event in a new state.
$state.go('site.calendar-event', {id: $stateParams.eventid});
}
@@ -69,7 +69,6 @@ angular.module('mm.addons.calendar')
emptyEventsTimes++;
if (emptyEventsTimes > 5) { // Stop execution if we retrieve empty list 6 consecutive times.
$scope.canLoadMore = false;
- $scope.eventsLoaded = true;
if (refresh) {
$scope.events = [];
}
@@ -90,7 +89,6 @@ angular.module('mm.addons.calendar')
// Filter events with same ID. Repeated events are returned once per WS call, show them only once.
$scope.events = $mmUtil.mergeArraysWithoutDuplicates($scope.events, events, 'id');
}
- $scope.eventsLoaded = true;
$scope.canLoadMore = true;
// Schedule notifications for the events retrieved (might have new events).
@@ -101,7 +99,6 @@ angular.module('mm.addons.calendar')
scrollView.resize();
}, function(error) {
$mmUtil.showErrorModalDefault(error, 'mma.calendar.errorloadevents', true);
- $scope.eventsLoaded = true;
$scope.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
});
}
@@ -121,7 +118,30 @@ angular.module('mm.addons.calendar')
$scope.notificationsEnabled = $mmLocalNotifications.isAvailable();
// Get first events.
- fetchData();
+ fetchData().then(function() {
+ if ($stateParams.eventid && $ionicPlatform.isTablet()) {
+ // There is an event to load and it's a tablet device. Search the position of the event in the list and load it.
+ var found = false;
+
+ for (var i = 0; i < $scope.events.length; i++) {
+ if ($scope.events[i].id == $stateParams.eventid) {
+ $scope.eventToLoad = i + 1;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // Event not found in the list, open it in a new state. Use a $timeout to open the state after the
+ // split view is loaded.
+ $timeout(function() {
+ $state.go('site.calendar-event', {id: $stateParams.eventid});
+ });
+ }
+ }
+ }).finally(function() {
+ $scope.eventsLoaded = true;
+ });
// Init popover.
$ionicPopover.fromTemplateUrl('addons/calendar/templates/course_picker.html', {
diff --git a/www/addons/calendar/lang/ar.json b/www/addons/calendar/lang/ar.json
index 9bece3c914d..23e2ee91b94 100644
--- a/www/addons/calendar/lang/ar.json
+++ b/www/addons/calendar/lang/ar.json
@@ -3,5 +3,5 @@
"errorloadevent": "خطأ في تحميل الحدث",
"errorloadevents": "خطأ في تحميل الأحداث",
"noevents": "لا يوجد أي أحداث",
- "notifications": "إشعارات"
+ "notifications": "الإشعارات"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/da.json b/www/addons/calendar/lang/da.json
index 70693816a85..6826baea7eb 100644
--- a/www/addons/calendar/lang/da.json
+++ b/www/addons/calendar/lang/da.json
@@ -3,5 +3,5 @@
"errorloadevent": "Fejl ved indlæsning af begivenhed.",
"errorloadevents": "Fejl ved indlæsning af begivenheder.",
"noevents": "Der er ingen begivenheder",
- "notifications": "Beskeder"
+ "notifications": "Notifikationer"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/el.json b/www/addons/calendar/lang/el.json
index 744426a674d..9a2040a3e51 100644
--- a/www/addons/calendar/lang/el.json
+++ b/www/addons/calendar/lang/el.json
@@ -1,5 +1,6 @@
{
"calendarevents": "Ημερολόγιο συμβάντων",
+ "defaultnotificationtime": "Προεπιλεγμένος χρόνος ειδοποίησης",
"errorloadevent": "Σφάλμα στην φόρτωση συμβάντου.",
"errorloadevents": "Σφάλμα στην φόρτωση συμβάντων.",
"noevents": "Δεν υπάρχουν συμβάντα",
diff --git a/www/addons/calendar/lang/es.json b/www/addons/calendar/lang/es.json
index 39bf009cfb6..993aec44200 100644
--- a/www/addons/calendar/lang/es.json
+++ b/www/addons/calendar/lang/es.json
@@ -1,5 +1,6 @@
{
"calendarevents": "Eventos de calendario",
+ "defaultnotificationtime": "Tiempo de notificación por defecto",
"errorloadevent": "Error cargando el evento.",
"errorloadevents": "Error cargando los eventos.",
"noevents": "No hay eventos",
diff --git a/www/addons/calendar/lang/es_mx.json b/www/addons/calendar/lang/es_mx.json
deleted file mode 100644
index 43fb72dee96..00000000000
--- a/www/addons/calendar/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "notifications": "Notificaciones"
-}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/fa.json b/www/addons/calendar/lang/fa.json
index 109ac4e7ec6..76813733c1d 100644
--- a/www/addons/calendar/lang/fa.json
+++ b/www/addons/calendar/lang/fa.json
@@ -3,6 +3,6 @@
"defaultnotificationtime": "زمان پیشفرض اطلاعرسانی",
"errorloadevent": "خطا در بارگیری رویداد.",
"errorloadevents": "خطا در بارگیری رویدادها.",
- "noevents": "هیچ رویدادی نیست",
- "notifications": "هشدارها"
+ "noevents": "هیچ مهلتی برای فعالیتهای آتی وجود ندارد",
+ "notifications": "تذکرات"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/he.json b/www/addons/calendar/lang/he.json
index 3702664d6e1..368fb1895c4 100644
--- a/www/addons/calendar/lang/he.json
+++ b/www/addons/calendar/lang/he.json
@@ -2,6 +2,6 @@
"calendarevents": "אירועי לוח שנה",
"errorloadevent": "שגיאה בטעינת האירוע.",
"errorloadevents": "שגיאה בטעינת האירועים.",
- "noevents": "לא קיימות פעילויות עתידיות להן מועד הגשה",
- "notifications": "עדכונים והודעות"
+ "noevents": "אין אירועים",
+ "notifications": "התראות"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/ja.json b/www/addons/calendar/lang/ja.json
index 5064bdee92f..b6e5457e412 100644
--- a/www/addons/calendar/lang/ja.json
+++ b/www/addons/calendar/lang/ja.json
@@ -1,4 +1,8 @@
{
- "noevents": "到来する活動期限はありません。",
+ "calendarevents": "カレンダーイベント",
+ "defaultnotificationtime": "デフォルト通知時間",
+ "errorloadevent": "イベントの読み込み時にエラーがありました。",
+ "errorloadevents": "イベントの読み込み時にエラーがありました。",
+ "noevents": "イベントはありません",
"notifications": "通知"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/pl.json b/www/addons/calendar/lang/pl.json
index 4116997d19c..4f391781a66 100644
--- a/www/addons/calendar/lang/pl.json
+++ b/www/addons/calendar/lang/pl.json
@@ -1,4 +1,4 @@
{
- "noevents": "Brak zdarzeń",
+ "noevents": "Brak nadchodzących terminów zadań",
"notifications": "Powiadomienia"
}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/pt_br.json b/www/addons/calendar/lang/pt_br.json
deleted file mode 100644
index 3037d7d8cf5..00000000000
--- a/www/addons/calendar/lang/pt_br.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "noevents": "Sem eventos",
- "notifications": "Notificação"
-}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/sr-cr.json b/www/addons/calendar/lang/sr-cr.json
new file mode 100644
index 00000000000..dba4ebcd807
--- /dev/null
+++ b/www/addons/calendar/lang/sr-cr.json
@@ -0,0 +1,8 @@
+{
+ "calendarevents": "Догађаји у календару",
+ "defaultnotificationtime": "Подразумевано време за слање обавештења",
+ "errorloadevent": "Грешка приликом учитавања догађаја.",
+ "errorloadevents": "Грешка приликом учитавања догађаја.",
+ "noevents": "Нема догађаја",
+ "notifications": "Обавештења"
+}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/sr-lt.json b/www/addons/calendar/lang/sr-lt.json
new file mode 100644
index 00000000000..7db382ef521
--- /dev/null
+++ b/www/addons/calendar/lang/sr-lt.json
@@ -0,0 +1,8 @@
+{
+ "calendarevents": "Događaji u kalendaru",
+ "defaultnotificationtime": "Podrazumevano vreme za slanje obaveštenja",
+ "errorloadevent": "Greška prilikom učitavanja događaja.",
+ "errorloadevents": "Greška prilikom učitavanja događaja.",
+ "noevents": "Nema događaja",
+ "notifications": "Nema događaja"
+}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/zh_cn.json b/www/addons/calendar/lang/zh_cn.json
deleted file mode 100644
index 5fc1088f46f..00000000000
--- a/www/addons/calendar/lang/zh_cn.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "noevents": "没有事件",
- "notifications": "通知"
-}
\ No newline at end of file
diff --git a/www/addons/calendar/lang/zh_tw.json b/www/addons/calendar/lang/zh_tw.json
deleted file mode 100644
index 24e3b1a572b..00000000000
--- a/www/addons/calendar/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "notifications": "通知"
-}
\ No newline at end of file
diff --git a/www/addons/calendar/templates/list.html b/www/addons/calendar/templates/list.html
index 7ec4466f335..23f07180988 100644
--- a/www/addons/calendar/templates/list.html
+++ b/www/addons/calendar/templates/list.html
@@ -5,7 +5,7 @@
-
+
diff --git a/www/addons/competency/lang/ar.json b/www/addons/competency/lang/ar.json
index 5952485e905..79ce4fda7f6 100644
--- a/www/addons/competency/lang/ar.json
+++ b/www/addons/competency/lang/ar.json
@@ -1,11 +1,11 @@
{
- "activities": "الأنشطة",
- "duedate": "تاريخ تقديم مهمة",
+ "activities": "أنشطة",
+ "duedate": "موعد التسليم",
"errornocompetenciesfound": "لا يوجد أي قدرات موجودة",
"myplans": "خططي للتعلم",
"nocompetencies": "لا يوجد أي قدرات",
"path": "مسار",
"progress": "تقدّم الطالب",
- "status": "الحالة",
+ "status": "الوضع",
"template": "قالب"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/bg.json b/www/addons/competency/lang/bg.json
index 3b3a332e5fb..37d407ff786 100644
--- a/www/addons/competency/lang/bg.json
+++ b/www/addons/competency/lang/bg.json
@@ -6,6 +6,6 @@
"myplans": "Моите учебни планове",
"noplanswerecreated": "Не бяха създадени учебни планове.",
"path": "Път",
- "status": "Състояние",
+ "status": "Състояние на значка",
"template": "Шаблон"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/ca.json b/www/addons/competency/lang/ca.json
index 70962efd930..60ba1a02774 100644
--- a/www/addons/competency/lang/ca.json
+++ b/www/addons/competency/lang/ca.json
@@ -3,7 +3,7 @@
"competenciesmostoftennotproficientincourse": "Competències que més sovint no s'assoleixen en aquest curs",
"coursecompetencies": "Competències del curs",
"crossreferencedcompetencies": "Competències referenciades",
- "duedate": "Data de venciment",
+ "duedate": "Venciment",
"errornocompetenciesfound": "No s'han trobat competències",
"evidence": "Evidència",
"learningplancompetencies": "Competències del pla d'aprenentatge",
@@ -14,13 +14,13 @@
"nocrossreferencedcompetencies": "No hi ha competències amb referències a aquesta.",
"noevidence": "Cap evidència",
"noplanswerecreated": "No s'ha creat cap pla d'aprenentatge.",
- "path": "Camí",
+ "path": "Ruta:",
"proficient": "Superada",
- "progress": "Progrés de l'estudiant",
- "rating": "Valoració",
+ "progress": "Progrés",
+ "rating": "Qualificació",
"reviewstatus": "Estat de la revisió",
- "status": "Estat",
- "template": "Plantilla",
+ "status": "Estat de la insígnia",
+ "template": "Plantilla de pla d'aprenentatge",
"xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competències superades",
"xcompetenciesproficientoutofyincourse": "Heu superat {{$a.x}} de {{$a.y}} competències en aquest curs."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/cs.json b/www/addons/competency/lang/cs.json
index 95324b05ccc..c935260c6c1 100644
--- a/www/addons/competency/lang/cs.json
+++ b/www/addons/competency/lang/cs.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Hodnocení kompetencí v tomto kurzu nemají vliv na studijní plány.",
"coursecompetencyratingsarepushedtouserplans": "Hodnocení kompetencí v tomto kurzu jsou okamžitě aktualizovány v studijních plánech.",
"crossreferencedcompetencies": "Průřezové kompetence",
- "duedate": "Termín odevzdání",
+ "duedate": "Datum platnosti",
"errornocompetenciesfound": "Nebyly nalezeny žádné kompetence",
"evidence": "Evidence",
"learningplancompetencies": "Kompetence studijního plánu",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "K této kompetenci nebyly spojeny další průřezové kompetence.",
"noevidence": "Bez záznamu",
"noplanswerecreated": "Nebyly vytvořeny žádné studijní plány.",
- "path": "Cesta",
+ "path": "Cesta:",
"proficient": "Splněno",
- "progress": "Pokrok studenta",
+ "progress": "Pokrok",
"rating": "Hodnocení",
"reviewstatus": "Stav revize",
- "status": "Stav",
- "template": "Šablona",
+ "status": "Stav odznaku",
+ "template": "Šablona studijního plánu",
"xcompetenciesproficientoutofy": "máte splněno {{$a.x}} z {{$a.y}} kompetencí",
"xcompetenciesproficientoutofyincourse": "V tomto kurzu máte splněno {{$a.x}} z {{$a.y}} kompetencí."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/da.json b/www/addons/competency/lang/da.json
index 57b4efe1f8c..454bb170072 100644
--- a/www/addons/competency/lang/da.json
+++ b/www/addons/competency/lang/da.json
@@ -4,20 +4,20 @@
"coursecompetencyratingsarenotpushedtouserplans": "Kompetencebedømmelser på dette kursus påvirker ikke læringsplaner.",
"coursecompetencyratingsarepushedtouserplans": "Kompetencebedømmelser på dette kursus opdateres straks i læringsplaner.",
"crossreferencedcompetencies": "Kryds-refererede kompetencer",
- "duedate": "Afleveringsdato",
+ "duedate": "Forfaldsdato",
"errornocompetenciesfound": "Ingen kompetencer fundet",
"evidence": "Vidnesbyrd",
"learningplancompetencies": "Læringsplankompetencer",
"learningplans": "Læringsplaner",
"myplans": "Mine læringsplaner",
"noactivities": "Ingen aktiviteter",
- "nocompetencies": "Ingen kompetencer er oprettet i denne ramme.",
+ "nocompetencies": "Ingen kompetencer",
"nocrossreferencedcompetencies": "Ingen andre kompetencer er krydsrefereret til denne kompetence.",
"noevidence": "Ingen vidnesbyrd",
"noplanswerecreated": "Der blev ikke oprettet nogen læringsplaner.",
- "path": "Sti",
- "progress": "Studerendes fremskridt",
+ "path": "Sti:",
+ "progress": "Progression",
"rating": "Bedømmelse",
- "status": "Status",
- "template": "Skabelon"
+ "status": "Badgestatus",
+ "template": "Læringsplanskabelon"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/de.json b/www/addons/competency/lang/de.json
index 2c43a7fb415..30b34122700 100644
--- a/www/addons/competency/lang/de.json
+++ b/www/addons/competency/lang/de.json
@@ -5,9 +5,9 @@
"coursecompetencyratingsarenotpushedtouserplans": "Kompetenzbewertungen in diesem Kurs beeinflussen keine Lernpläne.",
"coursecompetencyratingsarepushedtouserplans": "Kompetenzbewertungen in diesem Kurs werden sofort in den Lernplänen aktualisiert.",
"crossreferencedcompetencies": "Querverwiesene Kompetenzen",
- "duedate": "Fälligkeitsdatum",
+ "duedate": "Termin",
"errornocompetenciesfound": "Keine Kompetenzen gefunden",
- "evidence": "Evidenz",
+ "evidence": "Beleg",
"learningplancompetencies": "Kompetenzen des Lernplans",
"learningplans": "Lernpläne",
"myplans": "Meine Lernpläne",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Keine anderen Kompetenzen wurden zu dieser Kompetenz referiert.",
"noevidence": "Keine Belege",
"noplanswerecreated": "Bisher sind keine Lernpläne angelegt.",
- "path": "Pfad",
+ "path": "Pfad:",
"proficient": "Erfahren",
- "progress": "Bearbeitungsstand",
- "rating": "Bewertung",
+ "progress": "Fortschritt",
+ "rating": "Wertung",
"reviewstatus": "Überprüfungsstatus",
- "status": "Status",
- "template": "Vorlage",
+ "status": "Existierende Einschreibungen erlauben",
+ "template": "Lernplanvorlage",
"xcompetenciesproficientoutofy": "{{$a.x}} von {{$a.y}} Kompetenzen sind eingeübt",
"xcompetenciesproficientoutofyincourse": "Du bist in {{$a.x}} von {{$a.y}} Kompetenzen geübt"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/el.json b/www/addons/competency/lang/el.json
index 3a61231a7af..940c9116122 100644
--- a/www/addons/competency/lang/el.json
+++ b/www/addons/competency/lang/el.json
@@ -1,10 +1,10 @@
{
"activities": "Δραστηριότητες",
- "duedate": "Καταληκτική ημερομηνία",
+ "duedate": "Ημερομηνία εκπνοής",
"errornocompetenciesfound": "Δεν βρέθηκαν ικανότητες",
"nocompetencies": "Δεν βρέθηκαν ικανότητες",
"path": "Διαδρομή",
"progress": "Πρόοδος μαθητών",
- "status": "Κατάσταση",
+ "status": "Επιτρέπεται η πρόσβαση στους επισκέπτες",
"template": "Πρότυπο"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/es-mx.json b/www/addons/competency/lang/es-mx.json
index 276f784e4f3..89fed0897ca 100644
--- a/www/addons/competency/lang/es-mx.json
+++ b/www/addons/competency/lang/es-mx.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Las valoraciones de competencia en este curso no afectan a los planes de aprendizaje.",
"coursecompetencyratingsarepushedtouserplans": "Las valoraciones de competencia en este curso son actualizadas inmediatamente dentro de planes de aprendizaje.",
"crossreferencedcompetencies": "Competencias con referencias-cruzadas",
- "duedate": "Fecha de entrega",
+ "duedate": "Vencimiento",
"errornocompetenciesfound": "No se encontraron competencias",
"evidence": "Evidencia",
"learningplancompetencies": "Competencias del plan de aprendizaje",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "No se han referenciado cruzadamente otras competencias con esta competencia.",
"noevidence": "Sin evidencia",
"noplanswerecreated": "No se crearon planes de aprendizaje.",
- "path": "Ruta",
+ "path": "Ruta:",
"proficient": "Dominio/pericia",
- "progress": "Progreso del estudiante",
- "rating": "Valuación (rating)",
+ "progress": "Progreso",
+ "rating": "Valoración",
"reviewstatus": "Revisar estatus",
- "status": "Estatus",
- "template": "Plantilla",
+ "status": "Estatus de insignias",
+ "template": "Plantilla de plan de aprendizaje",
"xcompetenciesproficientoutofy": "{{$a.x}} de un total de {{$a.y}} competencias se tienen dominadas",
"xcompetenciesproficientoutofyincourse": "Usted es capaz/perito/experto en {{$a.x}} de un total de {{$a.y}} competencias en este curso."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/es.json b/www/addons/competency/lang/es.json
index b87c3dda451..e6a18fa8d33 100644
--- a/www/addons/competency/lang/es.json
+++ b/www/addons/competency/lang/es.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Las calificaciones de competencias de este curso no afectan los planes de aprendizaje.",
"coursecompetencyratingsarepushedtouserplans": "Las calificaciones de competencias en este curso actualizan de inmediato los planes de aprendizaje.",
"crossreferencedcompetencies": "Competencias referenciadas",
- "duedate": "Fecha de entrega",
+ "duedate": "Vencimiento",
"errornocompetenciesfound": "No se encontraron competencias",
"evidence": "Evidencia",
"learningplancompetencies": "Competencias del plan de aprendizaje",
@@ -17,10 +17,10 @@
"noevidence": "Sin evidencias",
"path": "Ruta",
"proficient": "Superada",
- "progress": "Progreso del estudiante",
- "rating": "Clasificación",
+ "progress": "Avance",
+ "rating": "Calificación",
"reviewstatus": "Estado de la revisión",
- "status": "Estado",
+ "status": "Estado de la insignia",
"template": "Plantilla",
"xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competencias superadas",
"xcompetenciesproficientoutofyincourse": "Has superado {{$a.x}} de las {{$a.y}} competencias del curso."
diff --git a/www/addons/competency/lang/eu.json b/www/addons/competency/lang/eu.json
index 3b4e8511411..b039b18b496 100644
--- a/www/addons/competency/lang/eu.json
+++ b/www/addons/competency/lang/eu.json
@@ -12,11 +12,11 @@
"nocompetencies": "Gaitasunik ez",
"noevidence": "Ez dago ebidentziarik",
"noplanswerecreated": "Ez da ikasketa-planik sortu.",
- "path": "Bidea",
+ "path": "Bidea:",
"proficient": "Gai",
- "progress": "Ikaslearen aurrerapena",
+ "progress": "Aurrerapena",
"rating": "Puntuazioa",
"reviewstatus": "Berrikusi egora",
- "status": "Egoera",
- "template": "Txantiloia"
+ "status": "Dominen egoera",
+ "template": "Ikasketa-planerako txantiloia"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/fa.json b/www/addons/competency/lang/fa.json
index 7bec744c8a6..768c777500c 100644
--- a/www/addons/competency/lang/fa.json
+++ b/www/addons/competency/lang/fa.json
@@ -4,7 +4,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "امتیازهای شایستگیها در این درس تاثیری در برنامههای یادگیری ندارند.",
"coursecompetencyratingsarepushedtouserplans": "امتیازهای شایستگیها در این درس بلافاصله در برنامههای یادگیری بهروز میشوند.",
"crossreferencedcompetencies": "شایستگیهای دارای ارجاع متقابل",
- "duedate": "مهلت تحویل",
+ "duedate": "مهلت",
"errornocompetenciesfound": "هیچ شایستگیای پیدا نشد",
"evidence": "مدرک",
"learningplancompetencies": "شایستگیهای برنامه یادگیری",
@@ -13,13 +13,13 @@
"nocrossreferencedcompetencies": "هیچ شایستگی دیگری به این شایستگی بهطور متقابل ارجاع داده نشده است.",
"noevidence": "بدون مدرک",
"noplanswerecreated": "هیچ برنامهٔ یادگیریای ساخته نشده است.",
- "path": "مسیر",
+ "path": "مسیر:",
"proficient": "کسب مهارت",
- "progress": "پیشروی شاگردان",
+ "progress": "پیشروی",
"rating": "امتیاز",
"reviewstatus": "بازبینی وضعیت",
- "status": "وضعیت",
- "template": "الگو",
+ "status": "وضعیت مدال",
+ "template": "الگوی برنامه یادگیری",
"xcompetenciesproficientoutofy": "در {{$a.x}} شایستگی از مجموع {{$a.y}} شایستگی مهارت کسب شده است",
"xcompetenciesproficientoutofyincourse": "شما در {{$a.x}} شایستگی از {{$a.y}} شایستگی ماهر هستید."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/fr.json b/www/addons/competency/lang/fr.json
index 54703a62fc1..e6510df8b0b 100644
--- a/www/addons/competency/lang/fr.json
+++ b/www/addons/competency/lang/fr.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Les évaluations de compétences de ce cours n'ont pas d'influence sur les plans de formation.",
"coursecompetencyratingsarepushedtouserplans": "Les évaluations de compétences de ce cours sont immédiatement reportées dans les plans de formation.",
"crossreferencedcompetencies": "Compétences transversales",
- "duedate": "Date de remise",
+ "duedate": "Délai d'achèvement",
"errornocompetenciesfound": "Aucune compétence trouvée",
"evidence": "Preuve",
"learningplancompetencies": "Compétences du plan de formation",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Aucune autre compétence n'est transversale pour cette compétence.",
"noevidence": "Aucune preuve d'acquis",
"noplanswerecreated": "Aucun plan de formation n'a été créé.",
- "path": "Chemin",
+ "path": "Chemin :",
"proficient": "Compétence acquise",
- "progress": "Suivi des activités des participants",
+ "progress": "Progrès",
"rating": "Évaluation",
"reviewstatus": "Statut de validation",
- "status": "Statut",
- "template": "Modèle",
+ "status": "Statut du badge",
+ "template": "Modèle de plan de formation",
"xcompetenciesproficientoutofy": "{{$a.x}} compétences sur {{$a.y}} sont acquises",
"xcompetenciesproficientoutofyincourse": "Vous avez acquis {{$a.x}} compétences sur {{$a.y}} dans ce cours."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/he.json b/www/addons/competency/lang/he.json
index ffae1727aab..0a89741eb32 100644
--- a/www/addons/competency/lang/he.json
+++ b/www/addons/competency/lang/he.json
@@ -5,8 +5,8 @@
"coursecompetencyratingsarenotpushedtouserplans": "השלמת מיומנויות בקורס זה לא מתעדכנות בתוכניות־הלימוד",
"coursecompetencyratingsarepushedtouserplans": "מצב רכישת מיומנות כתוצאה מהשלמת פעילות בקורס, מתעדכן באופן מידי בתוכניות־הלימוד.",
"crossreferencedcompetencies": "מקושר למיומנויות",
- "duedate": "תאריך סופי",
- "evidence": "סימוכין",
+ "duedate": "עד לתאריך",
+ "evidence": "ראיה לבקיאות",
"learningplancompetencies": "מיומנויות תוכנית־הלימוד",
"learningplans": "תוכניות־לימוד",
"myplans": "תוכניות הלימודים שלי",
@@ -15,13 +15,13 @@
"nocrossreferencedcompetencies": "אף מיומנות לא מקושרת למיומנות זו.",
"noevidence": "טרם צורפה ראיה לבקיאות",
"noplanswerecreated": "טרם נוצרו תוכניות־לימוד.",
- "path": "נתיב:",
+ "path": "נתיב",
"proficient": "בקיאות",
- "progress": "מעקב התקדמות למידה",
- "rating": "דירוג",
+ "progress": "התקדמות",
+ "rating": "דרוג",
"reviewstatus": "סקירת מצב",
- "status": "מצב",
- "template": "תבנית",
+ "status": "סטטוס ההישג",
+ "template": "תבנית תוכנית־לימוד",
"xcompetenciesproficientoutofy": "בקיאות ב {{$a.x}} מיומנויות מתוך {{$a.y}}",
"xcompetenciesproficientoutofyincourse": "רכשתם בקיאות ב {{$a.x}} מתוך {{$a.y}} המיומנויות בקורס זה."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/hu.json b/www/addons/competency/lang/hu.json
index 101f0f9a6a0..eb64c67f47c 100644
--- a/www/addons/competency/lang/hu.json
+++ b/www/addons/competency/lang/hu.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "A kurzus készségbesorolásai nem érintik a tanulási terveket.",
"coursecompetencyratingsarepushedtouserplans": "A kurzus készségbesorolásai azonnal frissülnek a tanulási tervekben.",
"crossreferencedcompetencies": "Kereszthivatkozott készségek",
- "duedate": "Határidő",
+ "duedate": "Esedékesség",
"evidence": "Bizonyíték",
"learningplancompetencies": "Tanulási tervhez tartozó készségek",
"learningplans": "Tanulási tervek",
@@ -15,13 +15,13 @@
"nocrossreferencedcompetencies": "A készséghez kereszthivatkozással nem kapcsolódik más készség.",
"noevidence": "Nincs bizonyíték",
"noplanswerecreated": "Nem jött létre tanulási terv.",
- "path": "Útvonal",
+ "path": "Útvonal:",
"proficient": "Sikeres",
- "progress": "A tanuló előmenetele",
- "rating": "Értékelés",
+ "progress": "Előmenetel",
+ "rating": "Besorolás",
"reviewstatus": "Ellenőrzés állapota",
- "status": "Állapot",
- "template": "Sablon",
+ "status": "A kitűző állapota",
+ "template": "Tanulási tervsablon",
"xcompetenciesproficientoutofy": "{{$a.x}} / {{$a.y}} készség eredményes",
"xcompetenciesproficientoutofyincourse": "Ön a kurzusban {{$a.y}} közül {{$a.x}} készség tekintetében eredményesnek bizonyul."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/it.json b/www/addons/competency/lang/it.json
index 9c5d5159c01..d9cf5441319 100644
--- a/www/addons/competency/lang/it.json
+++ b/www/addons/competency/lang/it.json
@@ -5,9 +5,9 @@
"coursecompetencyratingsarenotpushedtouserplans": "Le valutazioni delle competenze nel corso non si riflettono nei piani di formazione.",
"coursecompetencyratingsarepushedtouserplans": "Le valutazione delle competenze nel corso si riflettono immediatamente nei piani di formazione.",
"crossreferencedcompetencies": "Competenze con riferimento incrociato",
- "duedate": "Termine consegne",
+ "duedate": "Data di termine",
"errornocompetenciesfound": "Non sono state trovate competenze",
- "evidence": "Verifica",
+ "evidence": "Attestazione",
"learningplancompetencies": "Competenze del piano di formazione",
"learningplans": "Piani di formazione",
"myplans": "I miei piani di formazione",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Non ci sono competenze con riferimenti incrociati a questa competenza",
"noevidence": "Non sono presenti attestazioni.",
"noplanswerecreated": "Non sono stati creati piani di formazione",
- "path": "Percorso",
+ "path": "Percorso:",
"proficient": "Esperto",
- "progress": "Situazione dello studente",
+ "progress": "Avanzamento",
"rating": "Valutazione",
"reviewstatus": "Stato della revisione",
- "status": "Stato",
- "template": "Modello",
+ "status": "Stato badge",
+ "template": "Modello di piano di formazione",
"xcompetenciesproficientoutofy": "{{$a.x}} competenze su {{$a.y}} sono a livello di esperto",
"xcompetenciesproficientoutofyincourse": "Possiedi un livello di esperto in {{$a.x}} competenze su {{$a.y}} competenze di questo corso."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/ja.json b/www/addons/competency/lang/ja.json
index 5b45ea08016..d959d9ab61a 100644
--- a/www/addons/competency/lang/ja.json
+++ b/www/addons/competency/lang/ja.json
@@ -5,23 +5,24 @@
"coursecompetencyratingsarenotpushedtouserplans": "このコース内でのコンピテンシー評定は学習プランに影響しません。",
"coursecompetencyratingsarepushedtouserplans": "このコース内でのコンピテンシー評定は学習プラン内ですぐに更新されます。",
"crossreferencedcompetencies": "クロスリファレンスコンピテンシー",
- "duedate": "終了日時",
+ "duedate": "期限",
+ "errornocompetenciesfound": "コンピテンシーが見つかりません",
"evidence": "エビデンス",
"learningplancompetencies": "学習プランコンピテンシー",
"learningplans": "学習プラン",
"myplans": "マイ学習プラン",
"noactivities": "活動なし",
- "nocompetencies": "このフレームワークにコンピテンシーは作成されていません。",
+ "nocompetencies": "コンピテンシーなし",
"nocrossreferencedcompetencies": "このコンピテンシーに相互参照されている他のコンピテンシーはありません。",
"noevidence": "エビデンスなし",
"noplanswerecreated": "学習プランは作成されませんでした。",
- "path": "パス",
+ "path": "パス:",
"proficient": "熟達",
- "progress": "学生の進捗",
- "rating": "評価",
+ "progress": "進捗",
+ "rating": "評定",
"reviewstatus": "レビューステータス",
- "status": "ステータス",
- "template": "テンプレート",
+ "status": "バッジステータス",
+ "template": "学習プランテンプレート",
"xcompetenciesproficientoutofy": "{{$a.x}} / {{$a.y}} のコンピテンシーで熟達しています。",
"xcompetenciesproficientoutofyincourse": "あなたはこのコースに関して {{$a.x}} / {{$a.y}} のコンピテンシーで熟達しています。"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/lt.json b/www/addons/competency/lang/lt.json
index bfd76f8a42c..e7f4c88b879 100644
--- a/www/addons/competency/lang/lt.json
+++ b/www/addons/competency/lang/lt.json
@@ -1,8 +1,9 @@
{
- "activities": "Veikla",
+ "activities": "Veiklos",
"coursecompetencies": "Kurso kompetencijos",
"coursecompetencyratingsarenotpushedtouserplans": "Kompetencijų reitingai šiame kurse neturi įtakos mokymosi planams.",
- "duedate": "Data pristatymui",
+ "crossreferencedcompetencies": "Kryžminės kompetencijos",
+ "duedate": "Terminas",
"errornocompetenciesfound": "Kompetencijų nerasta",
"evidence": "Įrodymas",
"learningplancompetencies": "Mokymosi plano kompetencijos",
@@ -10,10 +11,15 @@
"myplans": "Mano mokymosi planai",
"noactivities": "Nėra veiklų",
"nocompetencies": "Nėra kompetencijų",
+ "nocrossreferencedcompetencies": "Jokios kitos kompetencijos nebuvo susietos kryžmine nuoroda su šia kompetencija.",
+ "noevidence": "Nėra įrodymų",
"noplanswerecreated": "Nebuvo sukurta mokymosi planų.",
"path": "Kelias",
- "progress": "Besimokančiojo pažanga",
- "rating": "Vertinimas",
- "status": "Būsena",
- "template": "Šablonas"
+ "proficient": "Įgūdis",
+ "progress": "Progresas",
+ "rating": "Reitingas",
+ "reviewstatus": "Peržiūros būsena",
+ "status": "Pasiekimo būsena",
+ "template": "Mokymosi plano šablonas",
+ "xcompetenciesproficientoutofyincourse": "Įgijote {{$a.x}} iš {{$a.y}} kompetenciją šiame kurse."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/nl.json b/www/addons/competency/lang/nl.json
index 5dff19cfe87..f03e99ab177 100644
--- a/www/addons/competency/lang/nl.json
+++ b/www/addons/competency/lang/nl.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Competentiebeoordelingen in deze cursus hebben geen invloed op studieplannnen.",
"coursecompetencyratingsarepushedtouserplans": "Competentiebeoordelingen in deze cursus worden onmiddellijk aangepast in studieplannen.",
"crossreferencedcompetencies": "Competenties met kruisverwijzingen",
- "duedate": "Uiterste inleverdatum",
+ "duedate": "Klaar tegen",
"errornocompetenciesfound": "Geen competenties gevonden",
"evidence": "Bewijs",
"learningplancompetencies": "Studieplan competenties",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Er zijn geen andere competenties met een kruisverwijzing naar deze competentie.",
"noevidence": "Geen bewijs",
"noplanswerecreated": "Er zijn nog geen studieplannen gemaakt",
- "path": "Pad",
+ "path": "Pad:",
"proficient": "Geslaagd",
- "progress": "Vordering leerling",
+ "progress": "Vordering",
"rating": "Beoordeling",
"reviewstatus": "Beoordelingsstatus",
- "status": "Status",
- "template": "Sjabloon",
+ "status": "Badge status",
+ "template": "Studieplansjabloon",
"xcompetenciesproficientoutofy": "{{$a.x}} van de {{$a.y}} competenties zijn bekwaam",
"xcompetenciesproficientoutofyincourse": "Je bent bekwaam in {{$a.x}} van de {{$a.y}} competenties in deze cursus."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/pl.json b/www/addons/competency/lang/pl.json
index 2b72a64195a..f548cb4520d 100644
--- a/www/addons/competency/lang/pl.json
+++ b/www/addons/competency/lang/pl.json
@@ -1,7 +1,7 @@
{
"activities": "Aktywności",
"coursecompetencies": "Kompetencje kursu",
- "duedate": "Termin oddania",
+ "duedate": "Termin",
"evidence": "Dowód",
"learningplancompetencies": "Kompetencje planu nauczania",
"learningplans": "Plany nauczania",
@@ -10,10 +10,10 @@
"nocompetencies": "Nie utworzono żadnych kompetencji w tych ramach kwalifikacji.",
"noevidence": "Brak dowodów",
"noplanswerecreated": "Nie utworzono planów uczenia się.",
- "path": "Ścieżka",
- "progress": "Postępy studenta w nauce",
+ "path": "Ścieżka:",
+ "progress": "Postęp",
"rating": "Ocena",
"reviewstatus": "Status przeglądu",
- "status": "Status",
- "template": "Szablon"
+ "status": "Status odznak",
+ "template": "Szablon planu uczenia się."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/pt-br.json b/www/addons/competency/lang/pt-br.json
index 268860975f8..dc30bfcf0d3 100644
--- a/www/addons/competency/lang/pt-br.json
+++ b/www/addons/competency/lang/pt-br.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "Avaliações de competência neste curso não afetam os planos de aprendizagem.",
"coursecompetencyratingsarepushedtouserplans": "Avaliações de competência neste curso são atualizadas imediatamente nos planos de aprendizagem.",
"crossreferencedcompetencies": "Competências referenciadas",
- "duedate": "Data de entrega",
+ "duedate": "Data de encerramento",
"errornocompetenciesfound": "Nenhuma competência encontrada",
"evidence": "Evidência",
"learningplancompetencies": "Competências do plano de aprendizagem",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Nenhuma outra competência foi referenciada a esta competência.",
"noevidence": "Nenhuma evidência",
"noplanswerecreated": "Nenhum plano de aprendizagem foi criado.",
- "path": "Caminho",
+ "path": "Caminho:",
"proficient": "Proficiente",
- "progress": "Progresso do aluno",
+ "progress": "Progresso",
"rating": "Avaliação",
"reviewstatus": "Estado da revisão",
- "status": "Status",
- "template": "Modelo",
+ "status": "Status do emblema",
+ "template": "Modelo de plano de aprendizagem",
"xcompetenciesproficientoutofy": "{{$a.x}} de {{$a.y}} competências são proficiêntes",
"xcompetenciesproficientoutofyincourse": "Você é proficiente em {{$a.x}} de {{$a.y}} competências neste curso."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/pt.json b/www/addons/competency/lang/pt.json
index 9acc0bd20d8..f8d90d2f944 100644
--- a/www/addons/competency/lang/pt.json
+++ b/www/addons/competency/lang/pt.json
@@ -5,9 +5,9 @@
"coursecompetencyratingsarenotpushedtouserplans": "As avaliações das competências nesta disciplina não afetam os planos de aprendizagem.",
"coursecompetencyratingsarepushedtouserplans": "As avaliações das competências nesta disciplina são automaticamente atualizadas nos planos de aprendizagem.",
"crossreferencedcompetencies": "Competências referenciadas",
- "duedate": "Data limite para submeter trabalhos",
+ "duedate": "Data de fim",
"errornocompetenciesfound": "Competências não encontradas",
- "evidence": "Evidência",
+ "evidence": "Comprovativo",
"learningplancompetencies": "Competências do plano de aprendizagem",
"learningplans": "Planos de aprendizagem",
"myplans": "Os meus planos de aprendizagem",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Nenhuma competência foi referenciada a esta competência.",
"noevidence": "Não foi adicionado nenhum comprovativo",
"noplanswerecreated": "Nenhum plano de aprendizagem foi criado.",
- "path": "Caminho",
+ "path": "Localização:",
"proficient": "Proficiente",
- "progress": "Progresso do aluno",
+ "progress": "Progresso",
"rating": "Avaliação",
"reviewstatus": "Estado da revisão",
- "status": "Estado",
- "template": "Modelo",
+ "status": "Estado da Medalha",
+ "template": "Modelo de plano de aprendizagem",
"xcompetenciesproficientoutofy": "Tem proficiência em {{$a.x}} de {{$a.y}} competências",
"xcompetenciesproficientoutofyincourse": "Tem proficiência em {{$a.x}} de {{$a.y}} competências nesta disciplina"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/ro.json b/www/addons/competency/lang/ro.json
index 63d6243c09f..9dec53a5b19 100644
--- a/www/addons/competency/lang/ro.json
+++ b/www/addons/competency/lang/ro.json
@@ -1,10 +1,10 @@
{
- "activities": "Activităţi",
+ "activities": "Activități",
"duedate": "Termen de predare",
"evidence": "Evidență",
"path": "Cale",
"progress": "Progres student",
"rating": "Rating",
- "status": "Status",
+ "status": "Status ecuson",
"template": "Șablon"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/ru.json b/www/addons/competency/lang/ru.json
index d268e9046ac..b4dd1160c36 100644
--- a/www/addons/competency/lang/ru.json
+++ b/www/addons/competency/lang/ru.json
@@ -1,12 +1,12 @@
{
- "activities": "Элементы курса",
+ "activities": "Элементы",
"competenciesmostoftennotproficientincourse": "Компетенции, которые чаще всего оказываются не освоенными в этом курсе",
"coursecompetencies": "Компетенции курса",
"coursecompetencyratingsarenotpushedtouserplans": "Рейтинги компетенций из этого курса не влияют на учебные планы.",
"coursecompetencyratingsarepushedtouserplans": "Рейтинги компетенций из этого курса сразу же обновляются в учебных планах.",
"crossreferencedcompetencies": "Перекрестные компетенции",
- "duedate": "Последний срок сдачи",
- "evidence": "Подтверждение",
+ "duedate": "Срок выполнения",
+ "evidence": "Доказательство",
"learningplancompetencies": "Компетенции учебного плана",
"learningplans": "Учебные планы",
"myplans": "Мои учебные планы",
@@ -15,13 +15,13 @@
"nocrossreferencedcompetencies": "Нет других компетенций, перекрестно ссылающихся на эту компетенцию.",
"noevidence": "Нет доказательств",
"noplanswerecreated": "Учебные планы не были созданы.",
- "path": "Путь",
+ "path": "Путь:",
"proficient": "Освоено",
- "progress": "Достижения студента",
+ "progress": "В процессе",
"rating": "Рейтинг",
"reviewstatus": "Статус пересмотра",
- "status": "Статус",
- "template": "Шаблон",
+ "status": "Статус значка",
+ "template": "Шаблон учебного плана",
"xcompetenciesproficientoutofy": "{{$a.x}} из {{$a.y}} компетенций освоены",
"xcompetenciesproficientoutofyincourse": "Вы освоили {{$a.x}} из {{$a.y}} компетенций в этом курсе."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/sr-cr.json b/www/addons/competency/lang/sr-cr.json
new file mode 100644
index 00000000000..d9f5a2c019b
--- /dev/null
+++ b/www/addons/competency/lang/sr-cr.json
@@ -0,0 +1,28 @@
+{
+ "activities": "Активности",
+ "competenciesmostoftennotproficientincourse": "Компетенције које најчешће нису усавршене на овом курсу",
+ "coursecompetencies": "Компетенције курса",
+ "coursecompetencyratingsarenotpushedtouserplans": "Рангирање компетенција на овом курсу на утиче на планове учења.",
+ "coursecompetencyratingsarepushedtouserplans": "Рангирање компетенција на овом курсу се аутоматски ажурира у плановима учења.",
+ "crossreferencedcompetencies": "Унакрсно повезане компетенције",
+ "duedate": "Крајњи рок",
+ "errornocompetenciesfound": "Није пронађена ниједна компетенција",
+ "evidence": "Доказ",
+ "learningplancompetencies": "Компетенције плана учења",
+ "learningplans": "Планови учења",
+ "myplans": "Моји планови учења",
+ "noactivities": "Нема активности",
+ "nocompetencies": "Нема компетенција",
+ "nocrossreferencedcompetencies": "Ниједна друга компетенција није унакрсно повезана са овом компетенцијом.",
+ "noevidence": "Нема доказа",
+ "noplanswerecreated": "Није креиран ниједан план учења.",
+ "path": "Путања",
+ "proficient": "Стручан",
+ "progress": "Напредовање полазника",
+ "rating": "Оцена",
+ "reviewstatus": "Прегледај статус",
+ "status": "Статус",
+ "template": "Шаблон",
+ "xcompetenciesproficientoutofy": "{{$a.x}} од {{$a.y}} компетенција су на највишем нивоу стручности",
+ "xcompetenciesproficientoutofyincourse": "Стручни сте у {{$a.x}} од {{$a.y}} компетенција на овом курсу."
+}
\ No newline at end of file
diff --git a/www/addons/competency/lang/sr-lt.json b/www/addons/competency/lang/sr-lt.json
new file mode 100644
index 00000000000..2a3c179861a
--- /dev/null
+++ b/www/addons/competency/lang/sr-lt.json
@@ -0,0 +1,28 @@
+{
+ "activities": "Aktivnosti",
+ "competenciesmostoftennotproficientincourse": "Kompetencije koje najčešće nisu usavršene na ovom kursu",
+ "coursecompetencies": "Kompetencije kursa",
+ "coursecompetencyratingsarenotpushedtouserplans": "Rangiranje kompetencija na ovom kursu na utiče na planove učenja.",
+ "coursecompetencyratingsarepushedtouserplans": "Rangiranje kompetencija na ovom kursu se automatski ažurira u planovima učenja.",
+ "crossreferencedcompetencies": "Unakrsno povezane kompetencije",
+ "duedate": "Krajnji rok",
+ "errornocompetenciesfound": "Nije pronađena nijedna kompetencija",
+ "evidence": "Dokaz",
+ "learningplancompetencies": "Kompetencije plana učenja",
+ "learningplans": "Planovi učenja",
+ "myplans": "Moji planovi učenja",
+ "noactivities": "Nema aktivnosti",
+ "nocompetencies": "Nema kompetencija",
+ "nocrossreferencedcompetencies": "Nijedna druga kompetencija nije unakrsno povezana sa ovom kompetencijom.",
+ "noevidence": "Nema dokaza",
+ "noplanswerecreated": "Nije kreiran nijedan plan učenja.",
+ "path": "Putanja",
+ "proficient": "Stručan",
+ "progress": "Napredovanje polaznika",
+ "rating": "Ocena",
+ "reviewstatus": "Pregledaj status",
+ "status": "Status",
+ "template": "Šablon",
+ "xcompetenciesproficientoutofy": "{{$a.x}} od {{$a.y}} kompetencija su na najvišem nivou stručnosti",
+ "xcompetenciesproficientoutofyincourse": "Stručni ste u {{$a.x}} od {{$a.y}} kompetencija na ovom kursu."
+}
\ No newline at end of file
diff --git a/www/addons/competency/lang/sv.json b/www/addons/competency/lang/sv.json
index a87634db442..15a7a9216ef 100644
--- a/www/addons/competency/lang/sv.json
+++ b/www/addons/competency/lang/sv.json
@@ -5,8 +5,8 @@
"coursecompetencyratingsarenotpushedtouserplans": "Bedömning av kompetenser i denna kurs kommer inte att påverka studieplaner.",
"coursecompetencyratingsarepushedtouserplans": "Bedömning av kompetenser i denna kurs uppdateras omedelbart i studieplanerna.",
"crossreferencedcompetencies": "Korsrefererade kompetenser.",
- "duedate": "Stoppdatum/tid",
- "evidence": "Bevis",
+ "duedate": "Sista inskickningsdatum",
+ "evidence": "Verifiering",
"learningplancompetencies": "Kompetenser i studieplaner",
"learningplans": "Studieplaner",
"myplans": "Mina studieplaner",
@@ -15,13 +15,13 @@
"nocrossreferencedcompetencies": "Inga andra kompetenser har korsrefererats till denna kompetens.",
"noevidence": "Inga verifieringar",
"noplanswerecreated": "Inga studieplaner var skapade.",
- "path": "Sökväg",
+ "path": "Sökväg:",
"proficient": "Kunnig",
- "progress": "Kursdeltagares progression",
- "rating": "Betygssättning/omdömen",
+ "progress": "Utveckling",
+ "rating": "Bedömning",
"reviewstatus": "Granska status",
- "status": "Status",
- "template": "Mall",
+ "status": "Status för märke",
+ "template": "Mall för studieplan",
"xcompetenciesproficientoutofy": "{{$a.x}} av {{$a.y}} kompetenser är uppnådda",
"xcompetenciesproficientoutofyincourse": "Du har uppnått {{$a.x}} av {{$a.y}} kompetenser i denna kurs.."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/tr.json b/www/addons/competency/lang/tr.json
index aaf5e15f532..4253ce29f6c 100644
--- a/www/addons/competency/lang/tr.json
+++ b/www/addons/competency/lang/tr.json
@@ -5,8 +5,8 @@
"coursecompetencyratingsarenotpushedtouserplans": "Bu dersin yetkinlik dereceleri öğrenme planlarını etkilemez.",
"coursecompetencyratingsarepushedtouserplans": "Bu dersin yetkinlik dereceleri öğrenme planlarında anında güncellenir.",
"crossreferencedcompetencies": "Çapraz referanslı yetkinlikler",
- "duedate": "Son teslim tarihi",
- "evidence": "Kanıt",
+ "duedate": "Bitiş tarihi",
+ "evidence": "Öğrenme kanıtı",
"learningplancompetencies": "Öğrenme planı yetkinlikleri",
"learningplans": "Öğrenme planları",
"myplans": "Benim öğrenme planlarım",
@@ -15,13 +15,13 @@
"nocrossreferencedcompetencies": "Bu yetkinliğe çapraz referanslı başka yetkinlik bulunmamaktadır.",
"noevidence": "Öğrenme kanıtı yok",
"noplanswerecreated": "Hiçbir öğrenme planı oluşturulmadı.",
- "path": "Yol",
+ "path": "Yol:",
"proficient": "Yeterli",
- "progress": "Öğrenci ilerlemesi",
+ "progress": "İlerleme",
"rating": "Derecelendirme",
"reviewstatus": "İnceleme durumu",
- "status": "Durum",
- "template": "Şablon",
+ "status": "Nişan Durumu",
+ "template": "Öğrenme planı şablonu",
"xcompetenciesproficientoutofy": "{{$a.y}} yetkinliğinden {{$a.x}} dışarıda yeterli",
"xcompetenciesproficientoutofyincourse": "Bu derste {{$a.y}} yetkinliğin dışında {{$a.x}} yeterliliğe sahibisiniz."
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/uk.json b/www/addons/competency/lang/uk.json
index d764c9bda7c..376f4e9d48f 100644
--- a/www/addons/competency/lang/uk.json
+++ b/www/addons/competency/lang/uk.json
@@ -1,13 +1,13 @@
{
- "activities": "Види діяльності",
+ "activities": "Діяльності",
"competenciesmostoftennotproficientincourse": "Компетентності, які найчастіше не досягаються у цьому курсі",
"coursecompetencies": "Компетентності курсу",
"coursecompetencyratingsarenotpushedtouserplans": "Оцінювання компетентностей цього курсу не впливають на навчальні плани",
"coursecompetencyratingsarepushedtouserplans": "Оцінювання компетентностей цього курсу будуть зразу передані в навчальні плани.",
"crossreferencedcompetencies": "Пов'язані компетентності",
- "duedate": "Кінцевий термін здачі",
+ "duedate": "Кінцевий термін",
"errornocompetenciesfound": "Не знайдено компетенції",
- "evidence": "Докази",
+ "evidence": "Підтвердження",
"learningplancompetencies": "Компетентності навчального плану",
"learningplans": "Навчальний план",
"myplans": "Мої навчальні плани",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "Жодна інша компетентність не пов'язана з даною",
"noevidence": "Жодного підтвердження",
"noplanswerecreated": "Жодного навчального плану не було створено",
- "path": "Шлях",
+ "path": "Шлях:",
"proficient": "Набута компетентність",
- "progress": "Прогрес студента",
- "rating": "Оцінка",
+ "progress": "Прогрес",
+ "rating": "Оцінювання",
"reviewstatus": "Статус підтвердження",
- "status": "Статус",
- "template": "Шаблон",
+ "status": "Статус відзнаки",
+ "template": "Шаблон навчального плану",
"xcompetenciesproficientoutofy": "{{$a.x}} компетентностей з {{$a.y}} набуті",
"xcompetenciesproficientoutofyincourse": "Ви набули {{$a.x}} компетентностей з {{$a.y}} наявних у цьому курсі"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/zh-cn.json b/www/addons/competency/lang/zh-cn.json
index e22e787d956..48f9fe6ae99 100644
--- a/www/addons/competency/lang/zh-cn.json
+++ b/www/addons/competency/lang/zh-cn.json
@@ -2,15 +2,15 @@
"activities": "活动",
"competenciesmostoftennotproficientincourse": "在这门课程中你有太多不精通的能力",
"coursecompetencies": "课程能力",
- "duedate": "截止时间",
+ "duedate": "截止日",
"evidence": "凭据",
"noactivities": "没有设置活动",
"path": "路径",
"proficient": "精通",
"progress": "学生进度",
"rating": "正在评分",
- "status": "状态",
- "template": "模板",
+ "status": "勋章状态",
+ "template": "学习计划模板",
"xcompetenciesproficientoutofy": "{{$a.y}}个能力中的{{$a.x}}是精通的",
"xcompetenciesproficientoutofyincourse": "你精通这门课程{{$a.y}}个能力中的{{$a.x}}个。"
}
\ No newline at end of file
diff --git a/www/addons/competency/lang/zh-tw.json b/www/addons/competency/lang/zh-tw.json
index fe0b027bb70..9106adffc4f 100644
--- a/www/addons/competency/lang/zh-tw.json
+++ b/www/addons/competency/lang/zh-tw.json
@@ -5,7 +5,7 @@
"coursecompetencyratingsarenotpushedtouserplans": "在這一課程的核心能力評等不會影響學習計畫",
"coursecompetencyratingsarepushedtouserplans": "在這一課程的核心能力評等在學習計畫上會立即更新",
"crossreferencedcompetencies": "交互參照的核心能力",
- "duedate": "規定繳交時間",
+ "duedate": "到期日",
"errornocompetenciesfound": "找不到能使用的功能",
"evidence": "證據",
"learningplancompetencies": "學習計畫核心能力",
@@ -16,13 +16,13 @@
"nocrossreferencedcompetencies": "沒有其他核心能力被交互參照這一核心能力",
"noevidence": "沒有證據",
"noplanswerecreated": "沒有學習計畫被建立",
- "path": "路徑",
+ "path": "路徑:",
"proficient": "精熟",
- "progress": "學生進度",
- "rating": "評比",
+ "progress": "進度",
+ "rating": "評等",
"reviewstatus": "審查狀況",
- "status": "狀態",
- "template": "範本",
+ "status": "獎章狀態",
+ "template": "學習計畫樣版",
"xcompetenciesproficientoutofy": "在{{$a.y}}個核心能力中有{{$a.x}}個已經精熟",
"xcompetenciesproficientoutofyincourse": "在此課程中有{{$a.y}}個核心能力,你已經精熟{{$a.x}}個。"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/ar.json b/www/addons/coursecompletion/lang/ar.json
index 7faf3c038ac..f88bc955bca 100644
--- a/www/addons/coursecompletion/lang/ar.json
+++ b/www/addons/coursecompletion/lang/ar.json
@@ -1,19 +1,19 @@
{
- "complete": "كامل",
+ "complete": "مكتمل",
"completecourse": "مقرر مكتمل",
- "completed": "تم",
+ "completed": "تم إكمال المقرر",
"completiondate": "تاريخ إكمال المقرر",
"couldnotloadreport": "لا يمكن تحميل تقرير إكمال المقرر، الرجاء المحاولة في وقت آخر",
- "coursecompletion": "إكمال المقرر الدراسي",
- "criteria": "معايير",
- "criteriagroup": "مجموعة المعايير",
+ "coursecompletion": "إكمال المقرر",
+ "criteria": "المعايير",
+ "criteriagroup": "معايير المجموعة",
"criteriarequiredall": "كل المعايير في الأسفل مطلوبة",
- "criteriarequiredany": "أي معيار في الأسفل مطلوب",
+ "criteriarequiredany": "أي معايير في الأسفل مطلوبة",
"inprogress": "قيد التنفيذ",
- "manualselfcompletion": "إكمال يدوي ذاتي",
+ "manualselfcompletion": "إكمال ذاتي يدوي",
"notyetstarted": "لم يبدأ بعد",
- "pending": "معلق",
- "required": "مفروض",
+ "pending": "قيد الانتظار",
+ "required": "مطلوب",
"requiredcriteria": "المعايير المطلوبة",
"requirement": "المتطلبات",
"status": "الحالة",
diff --git a/www/addons/coursecompletion/lang/bg.json b/www/addons/coursecompletion/lang/bg.json
index e60bae81321..245ed87b13c 100644
--- a/www/addons/coursecompletion/lang/bg.json
+++ b/www/addons/coursecompletion/lang/bg.json
@@ -1,14 +1,14 @@
{
- "complete": "Завършен",
- "completed": "Завършено",
- "coursecompletion": "Завършване на курса",
+ "complete": "Отговорен",
+ "completed": "Завършена",
+ "coursecompletion": "Напредване в курса",
"criteria": "Критерии",
"criteriagroup": "Група критерии",
"criteriarequiredall": "Всички критерии по-долу са задължителни",
"criteriarequiredany": "Някои критерии по-долу са задължителни",
"inprogress": "Не е приключен",
"manualselfcompletion": "Ръчно самоотбелязване на завършването",
- "required": "Задължително",
- "status": "Състояние",
+ "required": "Задължителен",
+ "status": "Състояние на значка",
"viewcoursereport": "Вижте отчет за курса"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/da.json b/www/addons/coursecompletion/lang/da.json
index 21281be057e..9d2cdeb93a0 100644
--- a/www/addons/coursecompletion/lang/da.json
+++ b/www/addons/coursecompletion/lang/da.json
@@ -1,20 +1,20 @@
{
- "complete": "Færdiggør",
+ "complete": "Fuldfør",
"completecourse": "Fuldfør kursus",
- "completed": "Gennemført",
+ "completed": "Fuldført",
"completiondate": "Afslutningsdato",
"couldnotloadreport": "Kunne ikke indlæse rapporten vedrørende kursusfuldførelse, prøv igen senere.",
- "coursecompletion": "Kursusgennemførelse",
- "criteria": "Kriterie",
- "criteriagroup": "Kriteriegruppe",
- "criteriarequiredall": "Alle kriterier herunder er påkrævet",
- "criteriarequiredany": "Ethvert kriterium herunder er påkrævet",
- "inprogress": "Igangværende",
- "manualselfcompletion": "Manuel selvregistrering af gennemførelse",
- "notyetstarted": "Ikke begyndt endnu",
- "pending": "Behandles",
- "required": "Påkrævet",
- "requiredcriteria": "Påkrævede kriterier",
+ "coursecompletion": "Kursusfuldførelse",
+ "criteria": "Kriterier",
+ "criteriagroup": "Gruppe af kriterier",
+ "criteriarequiredall": "Alle nedenstående kriterier er påkrævet",
+ "criteriarequiredany": "Hvilken som helst af nedenstående kriterier er påkrævet",
+ "inprogress": "I gang",
+ "manualselfcompletion": "Manuel markering af færdiggørelse",
+ "notyetstarted": "Endnu ikke startet",
+ "pending": "Afventer",
+ "required": "Krævet",
+ "requiredcriteria": "Krævet kriterie",
"requirement": "Krav",
"status": "Status",
"viewcoursereport": "Se kursusrapport"
diff --git a/www/addons/coursecompletion/lang/el.json b/www/addons/coursecompletion/lang/el.json
index 555b60517bd..a6fb10fd47b 100644
--- a/www/addons/coursecompletion/lang/el.json
+++ b/www/addons/coursecompletion/lang/el.json
@@ -10,7 +10,7 @@
"criteriarequiredall": "Όλα τα παρακάτω κριτήρια είναι υποχρεωτικά",
"criteriarequiredany": "Οποιοδήποτε από τα παρακάτω κριτήρια είναι υποχρεωτικά",
"inprogress": "Σε εξέλιξη",
- "manualselfcompletion": "Χειροκίνητη αυτό-ολοκλήρωση",
+ "manualselfcompletion": "Μη αυτόματη ολοκλήρωση",
"notyetstarted": "Δεν έχει ξεκινήσει ακόμα",
"pending": "Εκκρεμής",
"required": "Απαιτείται",
diff --git a/www/addons/coursecompletion/lang/fa.json b/www/addons/coursecompletion/lang/fa.json
index b9ddd4aaa56..2f308382aff 100644
--- a/www/addons/coursecompletion/lang/fa.json
+++ b/www/addons/coursecompletion/lang/fa.json
@@ -1,7 +1,7 @@
{
"complete": "کامل",
- "completed": "تکمیلشده",
- "coursecompletion": "تکمیل درس",
+ "completed": "کامل شده",
+ "coursecompletion": "کاربر باید این درس را تکمیل کند.",
"criteria": "ضابطه",
"criteriagroup": "گروه ضوابط",
"criteriarequiredall": "تمام ضوابط زیر باید برآورده شوند",
@@ -10,8 +10,8 @@
"manualselfcompletion": "علامت زدن به عنوان کامل توسط خود افراد",
"notyetstarted": "هنوز شروع نشده است",
"pending": "معلق",
- "required": "لازم است",
+ "required": "الزامی بودن",
"requiredcriteria": "ضوابط مورد نیاز",
- "status": "وضعیت",
- "viewcoursereport": "مشاهدهٔ گزارش درس"
+ "status": "وضعیت مدال",
+ "viewcoursereport": "مشاهده گزارش درس"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/he.json b/www/addons/coursecompletion/lang/he.json
index 3036661befc..dca12273f76 100644
--- a/www/addons/coursecompletion/lang/he.json
+++ b/www/addons/coursecompletion/lang/he.json
@@ -1,19 +1,19 @@
{
- "complete": "הושלם",
+ "complete": "השלמה",
"completecourse": "השלמת קורס",
"completed": "הושלם",
"completiondate": "תאריך השלמה",
- "coursecompletion": "השלמת הקורס",
- "criteria": "תנאי",
- "criteriagroup": "קבוצת תנאים",
- "criteriarequiredall": "כל התנאים המצויינים מטה נדרשים",
- "criteriarequiredany": "לפחות אחד מהתנאים המצויינים מטה נדרשים",
+ "coursecompletion": "השלמת קורס",
+ "criteria": "מדד־הערכה",
+ "criteriagroup": "קבוצת מדדיי־הערכה",
+ "criteriarequiredall": "כל מדדיי־הערכה להלן נדרשים",
+ "criteriarequiredany": "אחד ממדדיי־הערכה להלן נדרש",
"inprogress": "בתהליך",
- "manualselfcompletion": "השלמה עצמאית ידנית",
- "notyetstarted": "עדיין לא התחיל",
- "pending": "בתהליך למידה",
- "required": "דרוש",
- "requiredcriteria": "תנאי נדרש",
+ "manualselfcompletion": "הזנת השלמה עצמית",
+ "notyetstarted": "עדיין לא החל",
+ "pending": "בהמתנה",
+ "required": "נדרש",
+ "requiredcriteria": "מדד־הערכה נדרש",
"requirement": "דרישה",
"status": "מצב",
"viewcoursereport": "צפיה בדוח הקורס"
diff --git a/www/addons/coursecompletion/lang/hu.json b/www/addons/coursecompletion/lang/hu.json
index d07a78bbda4..361a4bf7069 100644
--- a/www/addons/coursecompletion/lang/hu.json
+++ b/www/addons/coursecompletion/lang/hu.json
@@ -1,17 +1,17 @@
{
- "complete": "Teljes",
- "completed": "Teljesítve",
- "coursecompletion": "Kurzus teljesítése",
+ "complete": "Kész",
+ "completed": "Kész",
+ "coursecompletion": "A tanulóknak teljesíteni kell ezt a kurzust",
"criteria": "Követelmények",
"criteriagroup": "Követelménycsoport",
"criteriarequiredall": "Az összes alábbi követelmény teljesítendő",
"criteriarequiredany": "Bármely alábbi követelmény teljesítendő",
- "inprogress": "Folyamatban",
+ "inprogress": "Folyamatban lévő",
"manualselfcompletion": "Saját teljesítés kézzel",
"notyetstarted": "Még nem kezdődött el",
"pending": "Függőben",
"required": "Kitöltendő",
"requiredcriteria": "Előírt követelmények",
- "status": "Állapot",
+ "status": "A kitűző állapota",
"viewcoursereport": "Kurzusjelentés megtekintése"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/ja.json b/www/addons/coursecompletion/lang/ja.json
index f53547d1c99..344ea673aea 100644
--- a/www/addons/coursecompletion/lang/ja.json
+++ b/www/addons/coursecompletion/lang/ja.json
@@ -1,17 +1,21 @@
{
- "complete": "詳細",
- "completed": "完了",
+ "complete": "完了",
+ "completecourse": "コース完了",
+ "completed": "完了しました",
+ "completiondate": "完了した日",
+ "couldnotloadreport": "コース完了の読み込みができませんでした。後でもう一度試してください。",
"coursecompletion": "コース完了",
"criteria": "クライテリア",
"criteriagroup": "クライテリアグループ",
- "criteriarequiredall": "下記のクライテリアすべてが必須である",
- "criteriarequiredany": "下記いくつかのクライテリアが必須である",
+ "criteriarequiredall": "以下すべてのクライテリアが必要",
+ "criteriarequiredany": "以下のクライテリアいずれかが必要",
"inprogress": "進行中",
- "manualselfcompletion": "手動による自己完了",
- "notyetstarted": "未開始",
- "pending": "保留",
- "required": "必須",
- "requiredcriteria": "必須クライテリア",
- "status": "ステータス",
- "viewcoursereport": "コースレポートを表示する"
+ "manualselfcompletion": "手動自己完了",
+ "notyetstarted": "まだ開始されていない",
+ "pending": "保留中",
+ "required": "必要な",
+ "requiredcriteria": "必要なクライテリア",
+ "requirement": "要求",
+ "status": "状態",
+ "viewcoursereport": "コースレポートを見る"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/pl.json b/www/addons/coursecompletion/lang/pl.json
index db69489a520..c5ffb7263b7 100644
--- a/www/addons/coursecompletion/lang/pl.json
+++ b/www/addons/coursecompletion/lang/pl.json
@@ -1,17 +1,17 @@
{
- "complete": "Pełna wersja",
- "completed": "Ukończony",
- "coursecompletion": "Ukończenie kursu",
+ "complete": "Zakończone",
+ "completed": "zakończony",
+ "coursecompletion": "Użytkownicy muszą ukończyć ten kurs.",
"criteria": "Kryteria",
"criteriagroup": "Grupa kryteriów",
"criteriarequiredall": "Wszystkie poniższe kryteria są wymagane",
"criteriarequiredany": "Wszystkie poniższe kryteria są wymagane",
- "inprogress": "W toku",
+ "inprogress": "Aktualne",
"manualselfcompletion": "Samodzielne oznaczenie ukończenia",
"notyetstarted": "Jeszcze nie rozpoczęto",
- "pending": "Oczekujący",
+ "pending": "Oczekujące",
"required": "Wymagane",
"requiredcriteria": "Wymagane kryteria",
- "status": "Status",
+ "status": "Status odznak",
"viewcoursereport": "Zobacz raport kursu"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/ro.json b/www/addons/coursecompletion/lang/ro.json
index 46b9f21bb93..7a195f67c33 100644
--- a/www/addons/coursecompletion/lang/ro.json
+++ b/www/addons/coursecompletion/lang/ro.json
@@ -1,21 +1,21 @@
{
- "complete": "Complet",
+ "complete": "Finalizează",
"completecourse": "Curs complet",
- "completed": "Complet",
+ "completed": "Finalizare",
"completiondate": "Data limita până la completarea acțiunii",
"couldnotloadreport": "Raportul cu privire la situația completării cursului nu se poate încărca, încercați mai târziu.",
- "coursecompletion": "Completarea cursului",
+ "coursecompletion": "Absolvire curs",
"criteria": "Criterii",
- "criteriagroup": "Criterii pentru grup",
- "criteriarequiredall": "Indeplinirea următoarelor criterii este obligatorie",
- "criteriarequiredany": "Oricare din urmatoarele criterii sunt obligatorii",
- "inprogress": "În progres",
- "manualselfcompletion": "Autocompletare",
- "notyetstarted": "Înca nu a început",
- "pending": "În asteptare",
- "required": "Obligatoriu",
- "requiredcriteria": "Criterii obligatorii",
+ "criteriagroup": "Grup criterii",
+ "criteriarequiredall": "Toate criteriile de mai jos sunt necesare",
+ "criteriarequiredany": "Oricare dintre criteriile de mai jos sunt necesare",
+ "inprogress": "În curs",
+ "manualselfcompletion": "Auto-finalizare manuală",
+ "notyetstarted": "Nu a fost încă început",
+ "pending": "În așteptare",
+ "required": "Necesar",
+ "requiredcriteria": "Criteriu necesar",
"requirement": "Cerințe",
- "status": "Situație",
- "viewcoursereport": "Vizualizați raportul despre curs"
+ "status": "Status",
+ "viewcoursereport": "Vezi raportul cursului"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/sr-cr.json b/www/addons/coursecompletion/lang/sr-cr.json
new file mode 100644
index 00000000000..610e78602a3
--- /dev/null
+++ b/www/addons/coursecompletion/lang/sr-cr.json
@@ -0,0 +1,21 @@
+{
+ "complete": "Заврши",
+ "completecourse": "Заврши курс",
+ "completed": "Завршено",
+ "completiondate": "Датум завршетка",
+ "couldnotloadreport": "Није могуће учитати извештај о завршетку курса. Молимо вас, покушајте поново касније.",
+ "coursecompletion": "Завршетак курса",
+ "criteria": "Критеријуми",
+ "criteriagroup": "Група критеријума",
+ "criteriarequiredall": "Сви доле наведени критеријуми су неопходни",
+ "criteriarequiredany": "Било који од доле наведених критеријума је неопходан",
+ "inprogress": "У току",
+ "manualselfcompletion": "Ручни самостални завршетак",
+ "notyetstarted": "Још није започето",
+ "pending": "На чекању",
+ "required": "Неопходно",
+ "requiredcriteria": "Неопходни критеријуми",
+ "requirement": "Услов",
+ "status": "Статус",
+ "viewcoursereport": "Прикажи извештај са курса"
+}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/sr-lt.json b/www/addons/coursecompletion/lang/sr-lt.json
new file mode 100644
index 00000000000..6553f9f3960
--- /dev/null
+++ b/www/addons/coursecompletion/lang/sr-lt.json
@@ -0,0 +1,21 @@
+{
+ "complete": "Završi",
+ "completecourse": "Završi kurs",
+ "completed": "Završeno",
+ "completiondate": "Datum završetka",
+ "couldnotloadreport": "Nije moguće učitati izveštaj o završetku kursa. Molimo vas, pokušajte ponovo kasnije.",
+ "coursecompletion": "Završetak kursa",
+ "criteria": "Kriterijumi",
+ "criteriagroup": "Grupa kriterijuma",
+ "criteriarequiredall": "Svi dole navedeni kriterijumi su neophodni",
+ "criteriarequiredany": "Bilo koji od dole navedenih kriterijuma je neophodan",
+ "inprogress": "U toku",
+ "manualselfcompletion": "Ručni samostalni završetak",
+ "notyetstarted": "Još nije započeto",
+ "pending": "Na čekanju",
+ "required": "Neophodno",
+ "requiredcriteria": "Neophodni kriterijumi",
+ "requirement": "Uslov",
+ "status": "Status",
+ "viewcoursereport": "Prikaži izveštaj sa kursa"
+}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/tr.json b/www/addons/coursecompletion/lang/tr.json
index 89efac25b4d..3aedfd0238d 100644
--- a/www/addons/coursecompletion/lang/tr.json
+++ b/www/addons/coursecompletion/lang/tr.json
@@ -1,17 +1,17 @@
{
- "complete": "Tamamlanmış",
- "completed": "Bitirmeli",
- "coursecompletion": "Ders tamamlama",
+ "complete": "Tamamlandı",
+ "completed": "Tamamlandı",
+ "coursecompletion": "Kurs tamamlama",
"criteria": "Ölçüt",
"criteriagroup": "Ölçüt Grubu",
"criteriarequiredall": "Aşağıdaki ölçütlerin tümü gereklidir",
"criteriarequiredany": "Aşağıdaki herhangi bir kriter gereklidir",
- "inprogress": "Devam ediyor",
+ "inprogress": "Devam etmekte",
"manualselfcompletion": "Kendi kendine elle tamamlama",
"notyetstarted": "Henüz başlamadı",
"pending": "Bekliyor",
"required": "Gerekli",
"requiredcriteria": "Gerekli Ölçüt",
- "status": "Durum",
+ "status": "Nişan Durumu",
"viewcoursereport": "Kurs raporunu görüntüle"
}
\ No newline at end of file
diff --git a/www/addons/coursecompletion/lang/uk.json b/www/addons/coursecompletion/lang/uk.json
index 86fa3eecf17..790fda5169e 100644
--- a/www/addons/coursecompletion/lang/uk.json
+++ b/www/addons/coursecompletion/lang/uk.json
@@ -10,7 +10,7 @@
"criteriarequiredall": "Всі критерії нижче обов'язкові",
"criteriarequiredany": "Будь-яка критерія нижче обов'язкова",
"inprogress": "В процесі...",
- "manualselfcompletion": "Завершення самостійно",
+ "manualselfcompletion": "Самостійне завершення",
"notyetstarted": "Не розпочато",
"pending": "В очікуванні",
"required": "Необхідно",
diff --git a/www/addons/coursecompletion/lang/zh-cn.json b/www/addons/coursecompletion/lang/zh-cn.json
index f46cbe0662d..eedfdd029f5 100644
--- a/www/addons/coursecompletion/lang/zh-cn.json
+++ b/www/addons/coursecompletion/lang/zh-cn.json
@@ -1,17 +1,17 @@
{
- "complete": "完全",
- "completed": "完成",
- "coursecompletion": "修完课程",
+ "complete": "完成",
+ "completed": "已完成",
+ "coursecompletion": "课程进度跟踪",
"criteria": "条件",
"criteriagroup": "条件组",
"criteriarequiredall": "必须满足以下条件",
"criteriarequiredany": "必须满足下列任一条件",
- "inprogress": "处理中",
+ "inprogress": "进行中",
"manualselfcompletion": "手动自设完成",
"notyetstarted": "还未开始",
- "pending": "等待中",
- "required": "必需的",
+ "pending": "待决",
+ "required": "必须回答",
"requiredcriteria": "必备条件",
- "status": "状态",
+ "status": "勋章状态",
"viewcoursereport": "查看课程报告"
}
\ No newline at end of file
diff --git a/www/addons/files/controllers/list.js b/www/addons/files/controllers/list.js
index 3dd985cc11d..79f1066cf54 100644
--- a/www/addons/files/controllers/list.js
+++ b/www/addons/files/controllers/list.js
@@ -49,8 +49,9 @@ angular.module('mm.addons.files')
return promise.then(function(files) {
$scope.files = files.entries;
$scope.count = files.count;
- }).catch(function() {
- $mmUtil.showErrorModal('mma.files.couldnotloadfiles', true);
+ }).catch(function(error) {
+ $mmUtil.showErrorModalDefault(error, 'mma.files.couldnotloadfiles', true);
+ return $q.reject();
});
}
diff --git a/www/addons/files/lang/ar.json b/www/addons/files/lang/ar.json
index 2ab44cda49c..3521b2b6f32 100644
--- a/www/addons/files/lang/ar.json
+++ b/www/addons/files/lang/ar.json
@@ -4,5 +4,5 @@
"files": "ملفات",
"privatefiles": "ملفات خاصة",
"sitefiles": "ملفات الموقع",
- "uploadfiles": "إرسل ملفات التغذية الراجعة"
+ "uploadfiles": "رفع ملفات"
}
\ No newline at end of file
diff --git a/www/addons/files/lang/da.json b/www/addons/files/lang/da.json
index 5f9d7d54b3b..1453d08f9f7 100644
--- a/www/addons/files/lang/da.json
+++ b/www/addons/files/lang/da.json
@@ -2,12 +2,12 @@
"admindisableddownload": "Bemærk venligst at din Moodleadministrator har deaktiveret download af filer. Du kan se filerne men ikke downloade dem.",
"clicktoupload": "Klik på knappen nedenfor for at uploade filer til dine private filer.",
"couldnotloadfiles": "Fillisten kunne ikke hentes",
- "emptyfilelist": "Der er ingen filer at vise",
+ "emptyfilelist": "Der er ingen filer at vise.",
"erroruploadnotworking": "Desværre er det p.t. ikke muligt at uploade filer til dit site.",
"files": "Filer",
"myprivatefilesdesc": "Filerne som er tilgængelige i dit private område på dette Moodlewebsted.",
"privatefiles": "Private filer",
"sitefiles": "Site filer",
"sitefilesdesc": "De andre filer som er tilgængelige for dig på denne Moodlewebside.",
- "uploadfiles": "Send feedbackfiler"
+ "uploadfiles": "Upload filer"
}
\ No newline at end of file
diff --git a/www/addons/files/lang/de.json b/www/addons/files/lang/de.json
index 39a046af215..337b5b880d1 100644
--- a/www/addons/files/lang/de.json
+++ b/www/addons/files/lang/de.json
@@ -1,11 +1,11 @@
{
"admindisableddownload": "Das Herunterladen von Dateien ist deaktiviert. Sie können nur die Dateiliste sehen.",
- "clicktoupload": "Tippen Sie auf die Taste, um Dateien in 'Meine Dateien' hochzuladen.",
- "couldnotloadfiles": "Die Dateiliste konnte nicht geladen werden.",
+ "clicktoupload": "Tippen Sie auf die Taste, um Dateien in den Bereich 'Meine Dateien' hochzuladen.",
+ "couldnotloadfiles": "Die Liste der Dateien konnte nicht geladen werden.",
"emptyfilelist": "Keine Dateien",
"erroruploadnotworking": "Im Moment können keine Dateien zur Website hochgeladen werden.",
"files": "Dateien",
- "myprivatefilesdesc": "Diese Dateien liegen in Ihrem persönlichen Bereich auf dieser Website.",
+ "myprivatefilesdesc": "Dateien, die in Ihrem persönlichen Bereich auf dieser Website liegen.",
"privatefiles": "Meine Dateien",
"sitefiles": "Dateien",
"sitefilesdesc": "Weitere Dateien, die für Sie in anderen Bereichen der Website verfügbar sind.",
diff --git a/www/addons/files/lang/es.json b/www/addons/files/lang/es.json
index d67044531b0..cca19793086 100644
--- a/www/addons/files/lang/es.json
+++ b/www/addons/files/lang/es.json
@@ -4,7 +4,7 @@
"couldnotloadfiles": "La lista de archivos no ha podido cargarse.",
"emptyfilelist": "No hay archivos que mostrar",
"erroruploadnotworking": "Desafortunadamente en estos momentos no es posible subir archivos al sitio.",
- "files": "Archivos",
+ "files": "Ficheros",
"myprivatefilesdesc": "Los archivos que están disponibles en su área privada en este sitio Moodle.",
"privatefiles": "Ficheros privados",
"sitefiles": "Archivos del sitio",
diff --git a/www/addons/files/lang/he.json b/www/addons/files/lang/he.json
index 6f612548ac8..0ed31567503 100644
--- a/www/addons/files/lang/he.json
+++ b/www/addons/files/lang/he.json
@@ -2,7 +2,7 @@
"admindisableddownload": "יש לשים לב כי מנהל/ת אתר המוודל שלך, ביטל/ה את אפשרות להורדת הקבצים. באפשרותך לעיין בקבצים אך לא להורידם.",
"clicktoupload": "להעלאת הקבצים לקבצים הפרטיים שלך, יש להקליק על הכפתור למטה.",
"couldnotloadfiles": "לא ניתן לטעון את רשימת הקבצים.",
- "emptyfilelist": "אין קבצים להציג",
+ "emptyfilelist": "אין קבצים להצגה.",
"files": "קבצים",
"myprivatefilesdesc": "הקבצים הזמינים לך באזור הפרטי באתר מוודל זה.",
"privatefiles": "הקבצים שלי",
diff --git a/www/addons/files/lang/ja.json b/www/addons/files/lang/ja.json
index 0f3df892d31..de63504d659 100644
--- a/www/addons/files/lang/ja.json
+++ b/www/addons/files/lang/ja.json
@@ -1,7 +1,13 @@
{
- "emptyfilelist": "表示するファイルはありません。",
+ "admindisableddownload": "あなたのMoodle管理者に、ファイルのダウンロードを無効にするよう知らせてください。そうすれば、ファイルをデバイスにダウンロードせず閲覧のみにすることができます。",
+ "clicktoupload": "ファイルをあなたのプライベートファイル領域にアップロードするには、下のボタンをクリックしてください。",
+ "couldnotloadfiles": "以下のファイルが読み込みできませんでした。",
+ "emptyfilelist": "表示するファイルがありません。",
+ "erroruploadnotworking": "残念ながら、現在、あなたのサイトにファイルをアップロードすることはできません。",
"files": "ファイル",
+ "myprivatefilesdesc": "ファイルはMoodleサイト上のあなたのプライベート領域にあります。",
"privatefiles": "プライベートファイル",
"sitefiles": "サイトファイル",
- "uploadfiles": "フィードバックファイルを送信する"
+ "sitefilesdesc": "本Moodleサイトであなたが利用できる他のファイル",
+ "uploadfiles": "アップロードファイル"
}
\ No newline at end of file
diff --git a/www/addons/files/lang/pt.json b/www/addons/files/lang/pt.json
index 3e1ce1acbd4..e37a1840902 100644
--- a/www/addons/files/lang/pt.json
+++ b/www/addons/files/lang/pt.json
@@ -4,7 +4,7 @@
"couldnotloadfiles": "Não foi possível carregar a lista de ficheiros",
"emptyfilelist": "Não há ficheiros",
"erroruploadnotworking": "Infelizmente não é possível carregar ficheiros para o seu site.",
- "files": "Ficheiros",
+ "files": "Anexos",
"myprivatefilesdesc": "Ficheiros disponíveis na sua área privada neste site Moodle",
"privatefiles": "Ficheiros privados",
"sitefiles": "Ficheiros do site",
diff --git a/www/addons/files/lang/ro.json b/www/addons/files/lang/ro.json
index 30500b91c47..d8113b20c3d 100644
--- a/www/addons/files/lang/ro.json
+++ b/www/addons/files/lang/ro.json
@@ -2,8 +2,8 @@
"admindisableddownload": "Atenție! Administratorul platformei a dezactivat descărcarea de fișiere; puteți accesa fișierele dar nu le puteți descărca.",
"clicktoupload": "Apăsați butonul de mai jos pentru a încarcă fișierele în contul dumneavoastră.",
"couldnotloadfiles": "Lista fișierelor nu a putut fi încărcată.",
- "emptyfilelist": "Nu sunt fișiere disponibile.",
- "files": "Fişiere",
+ "emptyfilelist": "Nu există fișiere",
+ "files": "Fișiere",
"myprivatefilesdesc": "Fișierele disponibile din zona personală, pe care o dețineți pe acest site.",
"privatefiles": "Fișiere private",
"sitefiles": "Fişiere site",
diff --git a/www/addons/files/lang/sr-cr.json b/www/addons/files/lang/sr-cr.json
new file mode 100644
index 00000000000..7e6b552125d
--- /dev/null
+++ b/www/addons/files/lang/sr-cr.json
@@ -0,0 +1,13 @@
+{
+ "admindisableddownload": "Имајте у виду да је ваш Moodle администратор онемогућио преузимање датотека. Датотеке можете да прегледате, али не и да их преузмете.",
+ "clicktoupload": "Кликните на доње дугме како бисте отпремили датотеке међу своје приватне датотеке.",
+ "couldnotloadfiles": "Списак датотека не може бити учитан.",
+ "emptyfilelist": "Нема датотека за приказ.",
+ "erroruploadnotworking": "Нажалост, тренутно није могуће отпремити датотеке на ваш сајт.",
+ "files": "Датотеке",
+ "myprivatefilesdesc": "Датотеке које су доступне у вашем приватном простору на овом Moodle сајту.",
+ "privatefiles": "Приватне датотеке",
+ "sitefiles": "Датотеке сајта",
+ "sitefilesdesc": "Остале датотеке које су доступне на овом Moodle сајту.",
+ "uploadfiles": "Отпреми датотеке"
+}
\ No newline at end of file
diff --git a/www/addons/files/lang/sr-lt.json b/www/addons/files/lang/sr-lt.json
new file mode 100644
index 00000000000..8779139baab
--- /dev/null
+++ b/www/addons/files/lang/sr-lt.json
@@ -0,0 +1,13 @@
+{
+ "admindisableddownload": "Imajte u vidu da je vaš Moodle administrator onemogućio preuzimanje datoteka. Datoteke možete da pregledate, ali ne i da ih preuzmete.",
+ "clicktoupload": "Kliknite na donje dugme kako biste otpremili datoteke među svoje privatne datoteke.",
+ "couldnotloadfiles": "Spisak datoteka ne može biti učitan.",
+ "emptyfilelist": "Nema datoteka za prikaz.",
+ "erroruploadnotworking": "Nažalost, trenutno nije moguće otpremiti datoteke na vaš sajt.",
+ "files": "Datoteke",
+ "myprivatefilesdesc": "Datoteke koje su dostupne u vašem privatnom prostoru na ovom Moodle sajtu.",
+ "privatefiles": "Privatne datoteke",
+ "sitefiles": "Datoteke sajta",
+ "sitefilesdesc": "Ostale datoteke koje su dostupne na ovom Moodle sajtu.",
+ "uploadfiles": "Otpremi datoteke"
+}
\ No newline at end of file
diff --git a/www/addons/files/lang/uk.json b/www/addons/files/lang/uk.json
index cb8988a3eaf..083a9f56194 100644
--- a/www/addons/files/lang/uk.json
+++ b/www/addons/files/lang/uk.json
@@ -1,5 +1,5 @@
{
- "admindisableddownload": "Зверніть увагу, що ваш адміністратор Moodle відключив завантаження файлів, ви можете переглядати файли, але не завантажувати їх.",
+ "admindisableddownload": "Зверніть увагу, що ваш адміністратор Moodle відключив завантаження файлів. Ви можете переглядати файли, але не завантажувати їх.",
"clicktoupload": "Натисніть на кнопку нижче, щоб завантажити ваші особисті файли.",
"couldnotloadfiles": "Список файлів не може бути завантажений.",
"emptyfilelist": "Немає файлів для показу.",
diff --git a/www/addons/files/services/files.js b/www/addons/files/services/files.js
index 058c3a9b62e..6f7c543f0bf 100644
--- a/www/addons/files/services/files.js
+++ b/www/addons/files/services/files.js
@@ -71,20 +71,18 @@ angular.module('mm.addons.files')
* - linkId: A hash of the file parameters.
*/
self.getFiles = function(params) {
- var deferred = $q.defer(),
- options = {};
+ var options = {};
options.cacheKey = getFilesListCacheKey(params);
- $mmSite.read('core_files_get_files', params, options).then(function(result) {
+ return $mmSite.read('core_files_get_files', params, options).then(function(result) {
var data = {
entries: [],
count: 0
};
if (typeof result.files == 'undefined') {
- deferred.reject();
- return;
+ return $q.reject();
}
angular.forEach(result.files, function(entry) {
@@ -109,27 +107,13 @@ angular.module('mm.addons.files')
entry.link = JSON.stringify(entry.link);
entry.linkId = md5.createHash(entry.link);
- // entry.localpath = "";
-
- // if (!entry.isdir && entry.url) {
- // // TODO Check $mmSite.
- // var uniqueId = $mmSite.id + "-" + md5.createHash(entry.url);
- // var path = MM.db.get("files", uniqueId);
- // if (path) {
- // entry.localpath = path.get("localpath");
- // }
- // }
data.count += 1;
data.entries.push(entry);
});
- deferred.resolve(data);
- }, function() {
- deferred.reject();
+ return data;
});
-
- return deferred.promise;
};
/**
diff --git a/www/addons/frontpage/lang/da.json b/www/addons/frontpage/lang/da.json
index 14f7474bfce..b3d549ab6ff 100644
--- a/www/addons/frontpage/lang/da.json
+++ b/www/addons/frontpage/lang/da.json
@@ -1,4 +1,4 @@
{
"sitehome": "Webstedets forside",
- "sitenews": "Sitenyheder"
+ "sitenews": "Sitemeddelelser"
}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/es_mx.json b/www/addons/frontpage/lang/es_mx.json
deleted file mode 100644
index 30cd142b296..00000000000
--- a/www/addons/frontpage/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "sitehome": "Portada"
-}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/eu.json b/www/addons/frontpage/lang/eu.json
index 2a21d6f7aa1..332c7d403ff 100644
--- a/www/addons/frontpage/lang/eu.json
+++ b/www/addons/frontpage/lang/eu.json
@@ -1,4 +1,4 @@
{
"sitehome": "Gunearen hasiera",
- "sitenews": "Gunearen berriak"
+ "sitenews": "Guneko albisteak"
}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/pt_br.json b/www/addons/frontpage/lang/pt_br.json
deleted file mode 100644
index 107c32efb31..00000000000
--- a/www/addons/frontpage/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "sitehome": "Página principal"
-}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/sr-cr.json b/www/addons/frontpage/lang/sr-cr.json
new file mode 100644
index 00000000000..de1f7c9cbd7
--- /dev/null
+++ b/www/addons/frontpage/lang/sr-cr.json
@@ -0,0 +1,4 @@
+{
+ "sitehome": "Насловна страница сајта",
+ "sitenews": "Обавештења сајта"
+}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/sr-lt.json b/www/addons/frontpage/lang/sr-lt.json
new file mode 100644
index 00000000000..685ff10dcef
--- /dev/null
+++ b/www/addons/frontpage/lang/sr-lt.json
@@ -0,0 +1,4 @@
+{
+ "sitehome": "Naslovna stranica sajta",
+ "sitenews": "Obaveštenja sajta"
+}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/zh_cn.json b/www/addons/frontpage/lang/zh_cn.json
deleted file mode 100644
index 20eac284d87..00000000000
--- a/www/addons/frontpage/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "sitehome": "首页"
-}
\ No newline at end of file
diff --git a/www/addons/frontpage/lang/zh_tw.json b/www/addons/frontpage/lang/zh_tw.json
deleted file mode 100644
index 6bff0d94024..00000000000
--- a/www/addons/frontpage/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "sitehome": "首頁"
-}
\ No newline at end of file
diff --git a/www/addons/grades/lang/bg.json b/www/addons/grades/lang/bg.json
index 49ff4539d55..02c842d1272 100644
--- a/www/addons/grades/lang/bg.json
+++ b/www/addons/grades/lang/bg.json
@@ -1,3 +1,3 @@
{
- "viewgrades": "Виждане на оценките"
+ "viewgrades": "Разглеждане на оценки"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/el.json b/www/addons/grades/lang/el.json
index c1625a02671..5517b193e17 100644
--- a/www/addons/grades/lang/el.json
+++ b/www/addons/grades/lang/el.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Δεν επιστράφηκε κανένας βαθμός",
- "viewgrades": "Προβολή βαθμών"
+ "viewgrades": "Προβολή Βαθμών"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/fa.json b/www/addons/grades/lang/fa.json
index 6c9c03151dd..fd0241c2bc7 100644
--- a/www/addons/grades/lang/fa.json
+++ b/www/addons/grades/lang/fa.json
@@ -1,3 +1,3 @@
{
- "viewgrades": "مشاهدهٔ نمرهها"
+ "viewgrades": "دیدن نمرهها"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/fr.json b/www/addons/grades/lang/fr.json
index 37ee094566f..1c1ce861d2d 100644
--- a/www/addons/grades/lang/fr.json
+++ b/www/addons/grades/lang/fr.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Aucune note retournée",
- "viewgrades": "Afficher les notes"
+ "viewgrades": "Affichage des notes"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/he.json b/www/addons/grades/lang/he.json
index 63f5df64a1c..f6450d5c884 100644
--- a/www/addons/grades/lang/he.json
+++ b/www/addons/grades/lang/he.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "לא הוחזרו ציונים",
- "viewgrades": "ראה ציונים"
+ "viewgrades": "תצוגת ציונים"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/it.json b/www/addons/grades/lang/it.json
index 194c13b5f5a..883d830fb4f 100644
--- a/www/addons/grades/lang/it.json
+++ b/www/addons/grades/lang/it.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Non è stata ottenuta alcuna valutazione",
- "viewgrades": "Visualizza risultati"
+ "viewgrades": "Visualizza valutazioni"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/ja.json b/www/addons/grades/lang/ja.json
index c49db645dae..23abe78a3be 100644
--- a/www/addons/grades/lang/ja.json
+++ b/www/addons/grades/lang/ja.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "評点がありません。",
- "viewgrades": "評点を表示する"
+ "viewgrades": "評定を表示する"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/nl.json b/www/addons/grades/lang/nl.json
index 1b33ee8446a..a11f8e821e2 100644
--- a/www/addons/grades/lang/nl.json
+++ b/www/addons/grades/lang/nl.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Geen cijfers",
- "viewgrades": "Bekijk de cijfers"
+ "viewgrades": "Bekijk cijfers"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/pl.json b/www/addons/grades/lang/pl.json
index b2abf06357d..0f2f359336e 100644
--- a/www/addons/grades/lang/pl.json
+++ b/www/addons/grades/lang/pl.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Brak stopni",
- "viewgrades": "Pokaż oceny"
+ "viewgrades": "Podgląd ocen"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/ru.json b/www/addons/grades/lang/ru.json
index fac7633651b..733ed0c23e6 100644
--- a/www/addons/grades/lang/ru.json
+++ b/www/addons/grades/lang/ru.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Нет оценок",
- "viewgrades": "Посмотреть оценки"
+ "viewgrades": "Просмотр оценок"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/sr-cr.json b/www/addons/grades/lang/sr-cr.json
new file mode 100644
index 00000000000..88b8e81b468
--- /dev/null
+++ b/www/addons/grades/lang/sr-cr.json
@@ -0,0 +1,4 @@
+{
+ "nogradesreturned": "Нема добијених оцена",
+ "viewgrades": "Приказ оцена"
+}
\ No newline at end of file
diff --git a/www/addons/grades/lang/sr-lt.json b/www/addons/grades/lang/sr-lt.json
new file mode 100644
index 00000000000..bc161c7fd6e
--- /dev/null
+++ b/www/addons/grades/lang/sr-lt.json
@@ -0,0 +1,4 @@
+{
+ "nogradesreturned": "Nema dobijenih ocena",
+ "viewgrades": "Prikaz ocena"
+}
\ No newline at end of file
diff --git a/www/addons/grades/lang/uk.json b/www/addons/grades/lang/uk.json
index 86c7bf00584..32dd4de48eb 100644
--- a/www/addons/grades/lang/uk.json
+++ b/www/addons/grades/lang/uk.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "Немає оцінок",
- "viewgrades": "Подивитися оцінки"
+ "viewgrades": "Перегляд оцінок"
}
\ No newline at end of file
diff --git a/www/addons/grades/lang/zh-tw.json b/www/addons/grades/lang/zh-tw.json
index 9a7313f470a..7dedc8d3d0c 100644
--- a/www/addons/grades/lang/zh-tw.json
+++ b/www/addons/grades/lang/zh-tw.json
@@ -1,4 +1,4 @@
{
"nogradesreturned": "未找到成績",
- "viewgrades": "檢視分數"
+ "viewgrades": "檢視成績"
}
\ No newline at end of file
diff --git a/www/addons/messageoutput/airnotifier/lang/ja.json b/www/addons/messageoutput/airnotifier/lang/ja.json
new file mode 100644
index 00000000000..3746717dab7
--- /dev/null
+++ b/www/addons/messageoutput/airnotifier/lang/ja.json
@@ -0,0 +1,3 @@
+{
+ "processorsettingsdesc": "デバイスの設定"
+}
\ No newline at end of file
diff --git a/www/addons/messageoutput/airnotifier/lang/sr-cr.json b/www/addons/messageoutput/airnotifier/lang/sr-cr.json
new file mode 100644
index 00000000000..fda693e8ae3
--- /dev/null
+++ b/www/addons/messageoutput/airnotifier/lang/sr-cr.json
@@ -0,0 +1,3 @@
+{
+ "processorsettingsdesc": "Конфигуриши уређаје"
+}
\ No newline at end of file
diff --git a/www/addons/messageoutput/airnotifier/lang/sr-lt.json b/www/addons/messageoutput/airnotifier/lang/sr-lt.json
new file mode 100644
index 00000000000..4419d93d89a
--- /dev/null
+++ b/www/addons/messageoutput/airnotifier/lang/sr-lt.json
@@ -0,0 +1,3 @@
+{
+ "processorsettingsdesc": "Komfiguriši uređaj"
+}
\ No newline at end of file
diff --git a/www/addons/messages/lang/ar.json b/www/addons/messages/lang/ar.json
index a047f3dfa6a..5d656811d75 100644
--- a/www/addons/messages/lang/ar.json
+++ b/www/addons/messages/lang/ar.json
@@ -10,10 +10,10 @@
"messages": "رسائل",
"mustbeonlinetosendmessages": "لابد أن تكون متصل بالأنترنت لكي ترسل أي رسائل",
"newmessage": "رسالة جديدة",
- "nomessages": "لا توجد رسائل بعد",
- "nousersfound": "لا يوجد مستخدمون",
+ "nomessages": "لا يوجد رسائل",
+ "nousersfound": "لا يوجد مستخدمين",
"removecontact": "ازل عنوان الاتصال",
- "send": "إرسل",
+ "send": "إرسال",
"sendmessage": "إرسل رسالة",
"type_offline": "غير متصل",
"type_online": "متصل",
diff --git a/www/addons/messages/lang/bg.json b/www/addons/messages/lang/bg.json
index 857ae200454..1cf0cf2e3be 100644
--- a/www/addons/messages/lang/bg.json
+++ b/www/addons/messages/lang/bg.json
@@ -10,16 +10,16 @@
"errorwhileretrievingcontacts": "Грешка при изчитането на списъка с контакти от сървъра.",
"errorwhileretrievingdiscussions": "Грешка при изчитането на дискусиите от сървъра.",
"errorwhileretrievingmessages": "Грешка при изчитането на съобщенията от сървъра.",
- "message": "Текст на съобщението",
+ "message": "Вашето мнение",
"messagenotsent": "Съобщението не беше изпратено. Моля опитайте пак по-късно.",
"messagepreferences": "Предпочитания за съобщенията",
"messages": "Съобщения",
"mustbeonlinetosendmessages": "Трябва да сте онлайн, за да изпращате съобщения.",
"newmessage": "Ново съобщение ...",
- "nomessages": "Няма съобщения.",
+ "nomessages": "Още няма съобщения",
"nousersfound": "Не са намерени потребители",
"removecontact": "Премахване на контакт",
- "send": "изпращане",
+ "send": "Изпращане",
"sendmessage": "Изпращане на съобщение",
"type_blocked": "Блокиран",
"type_offline": "Офлайн",
diff --git a/www/addons/messages/lang/ca.json b/www/addons/messages/lang/ca.json
index f4e5e0357b7..78d880054d7 100644
--- a/www/addons/messages/lang/ca.json
+++ b/www/addons/messages/lang/ca.json
@@ -13,17 +13,18 @@
"errorwhileretrievingdiscussions": "S'ha produït un error mentre es recuperaven els debats del servidor.",
"errorwhileretrievingmessages": "S'ha produït un error descarregant els missatges.",
"loadpreviousmessages": "Carrega els missatges anteriors",
- "message": "Cos del missatge",
+ "message": "Missatge",
"messagenotsent": "El missatge no s'ha enviat. Si us plau, intenteu-ho més tard",
+ "messagepreferences": "Preferències dels missatges",
"messages": "Missatges",
"mustbeonlinetosendmessages": "Heu de tenir connexió a la xarxa per a enviar missatges",
- "newmessage": "Nou missatge...",
+ "newmessage": "Missatge nou",
"newmessages": "Nous missatges",
- "nomessages": "No hi ha missatges.",
+ "nomessages": "No hi ha missatges encara",
"nousersfound": "No s'han trobat usuaris",
"removecontact": "Suprimeix contacte",
"removecontactconfirm": "El contacte s'eliminarà de la vostra llista de contactes.",
- "send": "envia",
+ "send": "Envia",
"sendmessage": "Envia missatge",
"type_blocked": "Bloquejat",
"type_offline": "Fora de línia",
diff --git a/www/addons/messages/lang/cs.json b/www/addons/messages/lang/cs.json
index fe2c22c0fc3..d3aa98a5834 100644
--- a/www/addons/messages/lang/cs.json
+++ b/www/addons/messages/lang/cs.json
@@ -24,8 +24,8 @@
"nousersfound": "Nebyl nalezen žádný uživatel",
"removecontact": "Odebrat kontakt",
"removecontactconfirm": "Kontakt bude odstraněn ze seznamu kontaktů.",
- "send": "odeslat",
- "sendmessage": "Odeslat zprávu",
+ "send": "Odeslat",
+ "sendmessage": "Poslat zprávu",
"type_blocked": "Blokováno",
"type_offline": "Offline",
"type_online": "Online",
diff --git a/www/addons/messages/lang/da.json b/www/addons/messages/lang/da.json
index 160591f104a..c05ede1157e 100644
--- a/www/addons/messages/lang/da.json
+++ b/www/addons/messages/lang/da.json
@@ -11,16 +11,16 @@
"errorwhileretrievingcontacts": "Fejl ved hentning af kontakter fra serveren",
"errorwhileretrievingdiscussions": "Fejl ved hentning af diskussioner fra serveren",
"errorwhileretrievingmessages": "Fejl ved hentning af beskeder fra serveren.",
- "message": "Beskedtekst",
+ "message": "Meddelelse",
"messagenotsent": "Beskeden blev ikke sendt, prøv igen senere.",
"messagepreferences": "Indstillinger for beskeder",
"messages": "Beskeder",
"mustbeonlinetosendmessages": "Du skal være online for at sende beskeder",
- "newmessage": "Ny besked",
- "nomessages": "Ingen beskeder endnu",
+ "newmessage": "Ny besked...",
+ "nomessages": "Ingen besked.",
"nousersfound": "Ingen brugere fundet",
"removecontact": "Fjern kontakt",
- "send": "send",
+ "send": "Send",
"sendmessage": "Send besked",
"type_blocked": "Blokeret",
"type_offline": "Offline",
diff --git a/www/addons/messages/lang/de.json b/www/addons/messages/lang/de.json
index 1f91de7f2a3..6a5fde2d14d 100644
--- a/www/addons/messages/lang/de.json
+++ b/www/addons/messages/lang/de.json
@@ -2,7 +2,7 @@
"addcontact": "Kontakt hinzufügen",
"blockcontact": "Kontakt sperren",
"blockcontactconfirm": "Sie beenden den Mitteilungsempfang von diesem Kontakt.",
- "blocknoncontacts": "Weitere Personen sperren",
+ "blocknoncontacts": "Mitteilungen nur für Kontakte zulassen",
"contactlistempty": "Die Kontaktliste ist leer.",
"contactname": "Name",
"contacts": "Kontakte",
@@ -15,7 +15,7 @@
"loadpreviousmessages": "Vorherige Mitteilungen laden",
"message": "Mitteilung",
"messagenotsent": "Die Mitteilung wurde nicht gesendet. Versuchen Sie es später noch einmal.",
- "messagepreferences": "Mitteilungen konfigurieren",
+ "messagepreferences": "Mitteilungen",
"messages": "Mitteilungen",
"mustbeonlinetosendmessages": "Sie müssen online sein, um Mitteilungen zu senden",
"newmessage": "Neue Mitteilung ...",
diff --git a/www/addons/messages/lang/el.json b/www/addons/messages/lang/el.json
index 3476b0c695a..894c8fd4a8c 100644
--- a/www/addons/messages/lang/el.json
+++ b/www/addons/messages/lang/el.json
@@ -1,6 +1,7 @@
{
"addcontact": "Προσθήκη επαφής",
"blockcontact": "Φραγμός επαφής",
+ "blockcontactconfirm": "Θα σταματήσετε να λαμβάνετε μηνύματα από αυτήν την επαφή.",
"blocknoncontacts": "Φραγή όλων των νέων μηνυμάτων που προέρχονται από χρήστες που δεν βρίσκονται στη λίστα επαφών σας.",
"contactlistempty": "Η λίστα επαφών είναι κενή",
"contactname": "Όνομα επαφής",
@@ -9,15 +10,18 @@
"errorwhileretrievingcontacts": "Σφάλμα κατά την ανάκτηση των επαφών από το διακομιστή.",
"errorwhileretrievingdiscussions": "Σφάλμα κατά την ανάκτηση των συζητήσεων από το διακομιστή.",
"errorwhileretrievingmessages": "Σφάλμα κατά την ανάκτηση των μηνυμάτων από το διακομιστή.",
- "message": "Σώμα μηνύματος",
+ "loadpreviousmessages": "Φορτώστε τα προηγούμενα μηνύματα",
+ "message": "Μήνυμα",
"messagenotsent": "Το μήνυμα δεν στάλθηκε, δοκιμάστε ξανά αργότερα.",
"messagepreferences": "Προτιμήσεις μηνύματος",
"messages": "Μηνύματα",
"mustbeonlinetosendmessages": "Πρέπει να είστε συνδεδεμένοι για να στείλετε μηνύματα",
"newmessage": "Νέο μήνυμα...",
+ "newmessages": "Νέα μηνύματα",
"nomessages": "Κανένα μήνυμα.",
"nousersfound": "Δεν βρέθηκαν χρήστες",
"removecontact": "Αφαίρεσε την επαφή",
+ "removecontactconfirm": "Η επαφή θα καταργηθεί από τη λίστα επαφών σας.",
"send": "Αποστολή",
"sendmessage": "Αποστολή μηνύματος",
"type_blocked": "Μπλοκαρισμένοι",
diff --git a/www/addons/messages/lang/es-mx.json b/www/addons/messages/lang/es-mx.json
index b7a7a579a99..666045c556a 100644
--- a/www/addons/messages/lang/es-mx.json
+++ b/www/addons/messages/lang/es-mx.json
@@ -13,18 +13,18 @@
"errorwhileretrievingdiscussions": "Error al recuperar las discusiones del servidor.",
"errorwhileretrievingmessages": "Error al recuperar los mensajes del servidor.",
"loadpreviousmessages": "Cargar mensajes anteriores",
- "message": "Cuerpo del mensaje",
+ "message": "Mensaje",
"messagenotsent": "El mensaje no fue enviado; por favor inténtelo nuevamente después.",
"messagepreferences": "Preferencias de Mensaje",
"messages": "Mensajes",
"mustbeonlinetosendmessages": "Usted debe de estar en-linea para enviar mensajes",
- "newmessage": "Nuevo mensaje...",
+ "newmessage": "Nuevo mensaje",
"newmessages": "Nuevos mensajes",
- "nomessages": "Sin mensajes.",
+ "nomessages": "Aún no hay mensajes",
"nousersfound": "No se encontraron usuarios",
"removecontact": "Eliminar contacto",
"removecontactconfirm": "El contacto será quitado de su lista de contactos.",
- "send": "enviar",
+ "send": "Enviar",
"sendmessage": "Enviar mensaje",
"type_blocked": "Bloqueado",
"type_offline": "Fuera-de-línea",
diff --git a/www/addons/messages/lang/es.json b/www/addons/messages/lang/es.json
index 9f18c4105e8..129117cec61 100644
--- a/www/addons/messages/lang/es.json
+++ b/www/addons/messages/lang/es.json
@@ -1,6 +1,7 @@
{
"addcontact": "Añadir contacto",
"blockcontact": "Bloquear contacto",
+ "blockcontactconfirm": "Usted dejará de recibir mensajes de este contacto.",
"blocknoncontacts": "Bloquear mensajes de usuarios que no figuren en mi lista de contactos",
"contactlistempty": "Lista de contactos vacía",
"contactname": "Nombre del contacto",
@@ -11,16 +12,19 @@
"errorwhileretrievingcontacts": "Error al recuperar los contactos del servidor.",
"errorwhileretrievingdiscussions": "Error al recuperar las discusiones del servidor.",
"errorwhileretrievingmessages": "Error al recuperar los mensajes del servidor.",
- "message": "Cuerpo del mensaje",
+ "loadpreviousmessages": "Cargar mensajes anteriores",
+ "message": "Mensaje",
"messagenotsent": "El mensaje no fue enviado; por favor inténtelo nuevamente después.",
"messagepreferences": "Preferencias de mensajes",
"messages": "Mensajes",
"mustbeonlinetosendmessages": "Debe conectarse para enviar mensajes",
"newmessage": "Nuevo mensaje...",
+ "newmessages": "Nuevos mensajes",
"nomessages": "No hay mensajes en espera",
"nousersfound": "No se encuentran usuarios",
"removecontact": "Eliminar contacto",
- "send": "enviar",
+ "removecontactconfirm": "El contacto se eliminará de su lista de contactos.",
+ "send": "Enviar",
"sendmessage": "Enviar mensaje",
"type_blocked": "Bloqueado",
"type_offline": "Desconectado",
diff --git a/www/addons/messages/lang/es_mx.json b/www/addons/messages/lang/es_mx.json
deleted file mode 100644
index 8de8efc8eff..00000000000
--- a/www/addons/messages/lang/es_mx.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "addcontact": "Añadir como contacto",
- "blockcontact": "Bloquear contacto",
- "contactlistempty": "La lista de contactos está vacía",
- "contactname": "Nombre del contacto",
- "contacts": "Contactos",
- "messages": "mi Messenger",
- "nomessages": "No hay mensajes en espera",
- "removecontact": "Eliminar contacto",
- "send": "Enviar",
- "sendmessage": "Enviar un mensaje",
- "unblockcontact": "Desbloquear contacto"
-}
\ No newline at end of file
diff --git a/www/addons/messages/lang/eu.json b/www/addons/messages/lang/eu.json
index ed18c8f0e65..7b4d166b262 100644
--- a/www/addons/messages/lang/eu.json
+++ b/www/addons/messages/lang/eu.json
@@ -13,7 +13,7 @@
"errorwhileretrievingdiscussions": "Errorea elkarrizketak zerbitzaritik jasotzean.",
"errorwhileretrievingmessages": "Errorea mezuak zerbitzaritik jasotzean.",
"loadpreviousmessages": "Kargatu aurreko mezuak",
- "message": "Mezuren gurputza",
+ "message": "Mezua",
"messagenotsent": "Mezua ez da bidali, mesedez saiatu beranduago.",
"messagepreferences": "Mezuen hobespenak",
"messages": "Mezuak",
@@ -24,7 +24,7 @@
"nousersfound": "Ez da erabiltzailerik aurkitu",
"removecontact": "Ezabatu kontaktua",
"removecontactconfirm": "Kontaktua zure kontaktuen zerrendatik ezabatuko da.",
- "send": "bidali",
+ "send": "Bidali",
"sendmessage": "Mezua bidali",
"type_blocked": "Blokeatuta",
"type_offline": "Lineaz kanpo",
diff --git a/www/addons/messages/lang/fa.json b/www/addons/messages/lang/fa.json
index a6d80f69982..f5155644c97 100644
--- a/www/addons/messages/lang/fa.json
+++ b/www/addons/messages/lang/fa.json
@@ -6,14 +6,14 @@
"contactname": "نام مخاطب",
"contacts": "مخاطبین",
"errorwhileretrievingdiscussions": "خطا در دریافت مباحثهها از کارگزار.",
- "message": "متن پیام",
+ "message": "متن",
"messagepreferences": "ترجیحات پیامدهی",
"messages": "پیامها",
"newmessage": "پیام جدید",
- "nomessages": "هنوز پیامی گفته نشده است",
+ "nomessages": "هیچ پیغامی منتظر جواب نیست",
"nousersfound": "کاربری پیدا نشد",
"removecontact": "حذف کردن مخاطب",
- "send": "فرستادن",
+ "send": "ارسال",
"sendmessage": "ارسال پیام",
"unblockcontact": "خارج کردن مخاطب از حالت مسدود"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/fr.json b/www/addons/messages/lang/fr.json
index 159b6fe52a9..90f17d9f58f 100644
--- a/www/addons/messages/lang/fr.json
+++ b/www/addons/messages/lang/fr.json
@@ -13,10 +13,10 @@
"errorwhileretrievingdiscussions": "Erreur lors de la récupération des discussions depuis le serveur.",
"errorwhileretrievingmessages": "Erreur lors de la récupération des messages depuis le serveur.",
"loadpreviousmessages": "Charger les messages antérieurs",
- "message": "Corps du message",
+ "message": "Message",
"messagenotsent": "Ce message n'a pas été envoyé. Veuillez essayer plus tard.",
"messagepreferences": "Préférences des messages",
- "messages": "Messages",
+ "messages": "Messages personnels",
"mustbeonlinetosendmessages": "Vous devez être en ligne pour envoyer des messages",
"newmessage": "Nouveau message...",
"newmessages": "Nouveaux messages",
@@ -25,7 +25,7 @@
"removecontact": "Supprimer ce contact",
"removecontactconfirm": "Le contact sera retiré de votre liste.",
"send": "Envoyer",
- "sendmessage": "Envoyer message",
+ "sendmessage": "Envoyer message personnel",
"type_blocked": "Bloqué",
"type_offline": "Hors ligne",
"type_online": "En ligne",
diff --git a/www/addons/messages/lang/he.json b/www/addons/messages/lang/he.json
index fb473cf8205..b0db251c2c8 100644
--- a/www/addons/messages/lang/he.json
+++ b/www/addons/messages/lang/he.json
@@ -10,17 +10,17 @@
"errorwhileretrievingcontacts": "שגיאה בזמן טעינת אנשי קשר מהשרת.",
"errorwhileretrievingdiscussions": "שגיאה בזמן טעינת הדיונים מהשרת.",
"errorwhileretrievingmessages": "שגיאה בזמן טעינת המסרים מהשרת.",
- "message": "גוף ההודעה",
+ "message": "הודעה",
"messagenotsent": "מסר זה לא נשלח, אנא נסה שוב מאוחר יותר.",
"messagepreferences": "העדפות מסרים",
- "messages": "הודעות",
+ "messages": "מסרים",
"mustbeonlinetosendmessages": "עליך להיות מחובר/ת בכדי לשלוח מסר.",
- "newmessage": "הודעה חדשה",
- "nomessages": "אין הודעות עדיין",
- "nousersfound": "לתשומת-לב",
+ "newmessage": "מסר חדש...",
+ "nomessages": "אין מסרים.",
+ "nousersfound": "לא נמצאו משתמשים",
"removecontact": "הסרת איש הקשר",
- "send": "שליחה",
- "sendmessage": "שליחת הודעה",
+ "send": "לשלוח",
+ "sendmessage": "שליחת מסר",
"type_blocked": "חסומים",
"type_offline": "לא מחוברים",
"type_online": "מחוברים",
diff --git a/www/addons/messages/lang/hu.json b/www/addons/messages/lang/hu.json
index 324fe26fe60..af6e18a3d8a 100644
--- a/www/addons/messages/lang/hu.json
+++ b/www/addons/messages/lang/hu.json
@@ -7,14 +7,14 @@
"contacts": "Kapcsolatok",
"deletemessage": "Üzenet törlése",
"deletemessageconfirmation": "Biztosan törli az üzenetet? Az csak a korábbi üzeneteiből törlődik, az azt küldő vagy fogadó fél továbbra is láthatja.",
- "message": "Üzenet törzsszövege",
+ "message": "Üzenet",
"messagepreferences": "Üzenet beállításai",
"messages": "Üzenetek",
"newmessage": "Új üzenet",
- "nomessages": "Még nincs üzenet",
+ "nomessages": "Nincs üzenet.",
"nousersfound": "Nincs felhasználó",
"removecontact": "Kapcsolat törlése",
- "send": "Elküld",
+ "send": "küldés",
"sendmessage": "Üzenet küldése",
"unblockcontact": "Kapcsolat zárolásának feloldása"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/it.json b/www/addons/messages/lang/it.json
index 0762bb1d877..9052dd21da0 100644
--- a/www/addons/messages/lang/it.json
+++ b/www/addons/messages/lang/it.json
@@ -11,7 +11,7 @@
"errorwhileretrievingcontacts": "Si è verificato un errore durante la ricezione dei contatti dal server.",
"errorwhileretrievingdiscussions": "Si è verificato un errore durante la ricezione delle discussioni dal server.",
"errorwhileretrievingmessages": "Si è verificato un errore durante la ricezione dei messaggi dal server.",
- "message": "Corpo del messaggio",
+ "message": "Messaggio",
"messagenotsent": "Il messaggio non è stato inviato, per favore riprova più tardi.",
"messagepreferences": "Preferenze messaggi",
"messages": "Messaggi",
@@ -20,7 +20,7 @@
"nomessages": "Non ci sono messaggi.",
"nousersfound": "Non sono stati trovati utenti",
"removecontact": "Cancella contatti",
- "send": "invia",
+ "send": "Invia",
"sendmessage": "Invia messaggio",
"type_blocked": "Bloccato",
"type_offline": "Offline",
diff --git a/www/addons/messages/lang/ja.json b/www/addons/messages/lang/ja.json
index fdd373a6acd..ab1c8913529 100644
--- a/www/addons/messages/lang/ja.json
+++ b/www/addons/messages/lang/ja.json
@@ -1,20 +1,36 @@
{
"addcontact": "コンタクトに追加する",
"blockcontact": "受信拒否",
+ "blockcontactconfirm": "この連絡先からのメッセージ受信を停止します。",
"blocknoncontacts": "不明なユーザをブロックする",
- "contactlistempty": "コンタクトリストは空です。",
- "contactname": "連絡先",
+ "contactlistempty": "連絡先リストが空",
+ "contactname": "連絡先名称",
"contacts": "コンタクト",
"deletemessage": "メッセージを削除する",
"deletemessageconfirmation": "本当にこのメッセージを削除してもよろしいですか? あなたのメッセージング履歴からのみ削除され、メッセージを送受信したユーザはまだ閲覧することができます。",
- "message": "メッセージ本文",
+ "errordeletemessage": "メッセージ消去中にエラーが発生しました。",
+ "errorwhileretrievingcontacts": "サーバから連絡先を取得中にエラーが発生しました。",
+ "errorwhileretrievingdiscussions": "サーバからディスカッションを受信中にエラーが発生しました。",
+ "errorwhileretrievingmessages": "サーバからメッセージを受信中にエラーが発生しました。",
+ "loadpreviousmessages": "以前のメッセージを読み込み",
+ "message": "メッセージ",
+ "messagenotsent": "メッセージは送信されませんでした。後で再び試みてください。",
"messagepreferences": "メッセージプリファレンス",
"messages": "メッセージ",
- "newmessage": "新しいメッセージ",
+ "mustbeonlinetosendmessages": "メッセージを送信するにはオンラインでなければなりません。",
+ "newmessage": "新規メッセージ...",
+ "newmessages": "新規メッセージ...",
"nomessages": "メッセージがありません。",
- "nousersfound": "ユーザは見つかりませんでした。",
+ "nousersfound": "ユーザが見つかりません",
"removecontact": "コンタクトから削除する",
+ "removecontactconfirm": "連絡先はあなたの連絡先リストから削除されます。",
"send": "送信",
"sendmessage": "メッセージを送信する",
- "unblockcontact": "コンタクトの拒否を解除する"
+ "type_blocked": "ブロックされています",
+ "type_offline": "オフライン",
+ "type_online": "オンライン",
+ "type_search": "結果の検索",
+ "type_strangers": "その他",
+ "unblockcontact": "コンタクトの拒否を解除する",
+ "warningmessagenotsent": "ユーザ {{user}} へのメッセージ送信ができませんでした。 {{error}}"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/lt.json b/www/addons/messages/lang/lt.json
index f63f91053b9..99ebd5052e4 100644
--- a/www/addons/messages/lang/lt.json
+++ b/www/addons/messages/lang/lt.json
@@ -9,16 +9,16 @@
"errorwhileretrievingcontacts": "Klaida nuskaitant kontaktus iš serverio.",
"errorwhileretrievingdiscussions": "Klaida nuskaitant diskusijas iš serverio.",
"errorwhileretrievingmessages": "Klaida nuskaitant pranešimus iš serverio.",
- "message": "Pranešimo tekstas",
+ "message": "Žinutės tekstas",
"messagenotsent": "Žinutė nebuvo išsiųsta, pabandykite vėliau.",
"messagepreferences": "Žinučių nuostatos",
"messages": "Žinutės",
"mustbeonlinetosendmessages": "Norėdamas išsiųsti žinutę, turite prisijungti",
- "newmessage": "Nauja žinutė...",
- "nomessages": "Žinučių nėra.",
+ "newmessage": "Nauja žinutė",
+ "nomessages": "Žinučių dar nėra",
"nousersfound": "Vartotojas nerastas",
"removecontact": "Pašalinti kontaktą",
- "send": "siųsti",
+ "send": "Siųsti",
"sendmessage": "Siųsti žinutę",
"type_blocked": "Užblokuota",
"type_offline": "Neprisjungęs",
diff --git a/www/addons/messages/lang/nl.json b/www/addons/messages/lang/nl.json
index c0cb0d61bb3..c8e2675c258 100644
--- a/www/addons/messages/lang/nl.json
+++ b/www/addons/messages/lang/nl.json
@@ -13,7 +13,7 @@
"errorwhileretrievingdiscussions": "Fout bij het ophalen van discussies van de server.",
"errorwhileretrievingmessages": "Fout bij het ophalen van berichten van de server.",
"loadpreviousmessages": "Laad vorige berichten",
- "message": "Berichtinhoud",
+ "message": "Bericht",
"messagenotsent": "Het bericht is niet verzonden. Probeer het later opnieuw.",
"messagepreferences": "Berichten voorkeuren",
"messages": "Berichten",
@@ -24,7 +24,7 @@
"nousersfound": "Geen gebruikers gevonden",
"removecontact": "Verwijder contactpersoon",
"removecontactconfirm": "Contact zal verwijderd worden van je contactenlijst.",
- "send": "Stuur",
+ "send": "stuur",
"sendmessage": "Stuur bericht",
"type_blocked": "Geblokkeerd",
"type_offline": "Offline",
diff --git a/www/addons/messages/lang/pl.json b/www/addons/messages/lang/pl.json
index a0b20dc95eb..6cb4279d4f9 100644
--- a/www/addons/messages/lang/pl.json
+++ b/www/addons/messages/lang/pl.json
@@ -7,14 +7,14 @@
"contacts": "Kontakty",
"deletemessage": "Usuń wiadomość",
"deletemessageconfirmation": "Czy jesteś pewien, że chcesz usunąć tę wiadomość? Zostanie ona usunięta wyłącznie z twojej historii wiadomości, użytkownik który ją wysłał lub odebrał nadal będzie mógł ją wyświetlić.",
- "message": "Treść wiadomości",
+ "message": "Wiadomość",
"messagepreferences": "Preferencje wiadomości",
"messages": "Wiadomości",
"newmessage": "Nowa wiadomość",
- "nomessages": "Brak wiadomości",
+ "nomessages": "Brak oczekujących wiadomości",
"nousersfound": "Nie znaleziono użytkowników",
"removecontact": "Usuń kontakt",
- "send": "wyślij",
+ "send": "Wyślij",
"sendmessage": "Wyślij wiadomość",
"unblockcontact": "Odblokuj kontakt"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/pt-br.json b/www/addons/messages/lang/pt-br.json
index b7c9da7e6a9..54c1e1b6e2c 100644
--- a/www/addons/messages/lang/pt-br.json
+++ b/www/addons/messages/lang/pt-br.json
@@ -13,17 +13,18 @@
"errorwhileretrievingdiscussions": "Erro ao recuperar discussão do servidor.",
"errorwhileretrievingmessages": "Erro ao recuperar as mensagens do servidor.",
"loadpreviousmessages": "Carregar mensagens anteriores",
- "message": "Corpo da mensagem",
+ "message": "Mensagem",
"messagenotsent": "A mensagem não foi enviada. Por favor tente novamente mais tarde.",
+ "messagepreferences": "Preferências de mensagens",
"messages": "Mensagens",
"mustbeonlinetosendmessages": "Você precisa estar conectado para enviar mensagens.",
- "newmessage": "Nova mensagem...",
+ "newmessage": "Nova Mensagem",
"newmessages": "Novas mensagens",
- "nomessages": "Não há mensagens.",
+ "nomessages": "Nenhuma mensagem ainda",
"nousersfound": "Nenhum usuário encontrado",
"removecontact": "Eliminar contato",
"removecontactconfirm": "O contato será removido da sua lista de contatos.",
- "send": "enviar",
+ "send": "Enviar",
"sendmessage": "Enviar mensagem",
"type_blocked": "Bloqueado",
"type_offline": "Offline",
diff --git a/www/addons/messages/lang/pt.json b/www/addons/messages/lang/pt.json
index b9ae68508bd..0e8975e0f49 100644
--- a/www/addons/messages/lang/pt.json
+++ b/www/addons/messages/lang/pt.json
@@ -13,14 +13,14 @@
"errorwhileretrievingdiscussions": "Erro ao obter os tópicos de discussão do servidor.",
"errorwhileretrievingmessages": "Erro ao obter as mensagens do servidor.",
"loadpreviousmessages": "Carregar mensagens antigas",
- "message": "Corpo da mensagem",
+ "message": "Mensagem",
"messagenotsent": "A mensagem não foi enviada. Por favor, tente novamente mais tarde.",
"messagepreferences": "Preferências das mensagens",
"messages": "Mensagens",
"mustbeonlinetosendmessages": "Precisa de estar online para enviar mensagens",
- "newmessage": "Nova mensagem...",
+ "newmessage": "Nova mensagem",
"newmessages": "Novas mensagens",
- "nomessages": "Sem mensagens.",
+ "nomessages": "Ainda não há mensagens",
"nousersfound": "Nenhum utilizador encontrado",
"removecontact": "Remover contacto",
"removecontactconfirm": "O contacto será removido da sua lista de contactos.",
diff --git a/www/addons/messages/lang/pt_br.json b/www/addons/messages/lang/pt_br.json
deleted file mode 100644
index fb4e3394639..00000000000
--- a/www/addons/messages/lang/pt_br.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "addcontact": "Adicionar como contato",
- "blockcontact": "Bloquear contato",
- "contactlistempty": "Lista de contatos vazia",
- "contactname": "Nome para contato",
- "contacts": "Contatos",
- "messages": "Mensagens",
- "nomessages": "Não há mensagens pendentes",
- "removecontact": "Remover contato",
- "send": "Enviar",
- "sendmessage": "Envie uma mensagem",
- "unblockcontact": "Desbloquear contato"
-}
\ No newline at end of file
diff --git a/www/addons/messages/lang/ro.json b/www/addons/messages/lang/ro.json
index b519bbf378f..1ee83c12782 100644
--- a/www/addons/messages/lang/ro.json
+++ b/www/addons/messages/lang/ro.json
@@ -11,15 +11,15 @@
"errorwhileretrievingcontacts": "A apărut o eroare în găsirea contactelor pe server.",
"errorwhileretrievingdiscussions": "A apărut o eroare în găsirea conversațiilor de pe server.",
"errorwhileretrievingmessages": "A apărut o eroare în găsirea mesajelor de pe server.",
- "message": "Conținut mesaj",
+ "message": "Mesaj",
"messagenotsent": "Mesajul nu a fost expediat, vă rugăm să încercați mai târziu.",
"messages": "Mesaje",
"mustbeonlinetosendmessages": "Trebuie să fiți online pentru a putea trimite mesaje",
"newmessage": "Mesaj nou!",
- "nomessages": "Nu aveți mesaje.",
- "nousersfound": "Nu au fost găsiți utilizatori",
+ "nomessages": "Nu a fost trimis încă niciun mesaj",
+ "nousersfound": "Nu s-au găsit utilizatori",
"removecontact": "Şterge prieten din listă",
- "send": "Trimis",
+ "send": "trimis",
"sendmessage": "Trimite mesaj",
"type_blocked": "Blocat",
"type_offline": "Deconectat",
diff --git a/www/addons/messages/lang/ru.json b/www/addons/messages/lang/ru.json
index be656eda0df..4c6677f9138 100644
--- a/www/addons/messages/lang/ru.json
+++ b/www/addons/messages/lang/ru.json
@@ -11,7 +11,7 @@
"errorwhileretrievingdiscussions": "Ошибка при получении обсуждения с сервера.",
"errorwhileretrievingmessages": "Ошибка при получении сообщения с сервера",
"loadpreviousmessages": "Загрузить предыдущее сообщение",
- "message": "Текст сообщения",
+ "message": "Сообщение",
"messagenotsent": "Сообщение не было отправлено. Повторите попытку позже.",
"messagepreferences": "Настройки сообщений",
"messages": "Сообщения",
diff --git a/www/addons/messages/lang/sr-cr.json b/www/addons/messages/lang/sr-cr.json
new file mode 100644
index 00000000000..18a467fa43c
--- /dev/null
+++ b/www/addons/messages/lang/sr-cr.json
@@ -0,0 +1,34 @@
+{
+ "addcontact": "Додај контакт",
+ "blockcontact": "Блокирај контакт",
+ "blockcontactconfirm": "Нећете више добијати поруке од ове особе.",
+ "blocknoncontacts": "Блокирај све нове поруке од корисника који нису на мојој листи контаката",
+ "contactlistempty": "Листа контаката је празна",
+ "contactname": "Име особе",
+ "contacts": "Контакти",
+ "errordeletemessage": "Грешка приликом брисања поруке.",
+ "errorwhileretrievingcontacts": "Грешка приликом преузимања контаката са сервера.",
+ "errorwhileretrievingdiscussions": "Грешка приликом преузимања дискусија са сервера.",
+ "errorwhileretrievingmessages": "Грешка приликом преузимања порука са сервера.",
+ "loadpreviousmessages": "Учитај претходне поруке",
+ "message": "Тело поруке",
+ "messagenotsent": "Порука није послата. Молимо, покушајте поново касније.",
+ "messagepreferences": "Параметри порука",
+ "messages": "Поруке",
+ "mustbeonlinetosendmessages": "Морате бити онлајн како бисте слали поруке",
+ "newmessage": "Нове поруке...",
+ "newmessages": "Нове поруке",
+ "nomessages": "Нема порука.",
+ "nousersfound": "Није пронађен ниједан корисник",
+ "removecontact": "Обриши контакт",
+ "removecontactconfirm": "Особа ће бити уклоњена са ваше листе контаката.",
+ "send": "Пошаљи",
+ "sendmessage": "Пошаљи поруку",
+ "type_blocked": "Блокиран",
+ "type_offline": "Офлајн",
+ "type_online": "Онлајн",
+ "type_search": "Резултати претраге",
+ "type_strangers": "Други",
+ "unblockcontact": "Одблокирај контакт",
+ "warningmessagenotsent": "Није могуће послати поруку/е кориснику {{user}}. {{error}}"
+}
\ No newline at end of file
diff --git a/www/addons/messages/lang/sr-lt.json b/www/addons/messages/lang/sr-lt.json
new file mode 100644
index 00000000000..3d5a353c5f5
--- /dev/null
+++ b/www/addons/messages/lang/sr-lt.json
@@ -0,0 +1,34 @@
+{
+ "addcontact": "Dodaj kontakt",
+ "blockcontact": "Blokiraj kontakt",
+ "blockcontactconfirm": "Nećete više dobijati poruke od ove osobe.",
+ "blocknoncontacts": "Blokiraj sve nove poruke od korisnika koji nisu na mojoj listi kontakata",
+ "contactlistempty": "Lista kontakata je prazna",
+ "contactname": "Ime osobe",
+ "contacts": "Kontakti",
+ "errordeletemessage": "Greška prilikom brisanja poruke.",
+ "errorwhileretrievingcontacts": "Greška prilikom preuzimanja kontakata sa servera.",
+ "errorwhileretrievingdiscussions": "Greška prilikom preuzimanja diskusija sa servera.",
+ "errorwhileretrievingmessages": "Greška prilikom preuzimanja poruka sa servera.",
+ "loadpreviousmessages": "Učitaj prethodne poruke",
+ "message": "Telo poruke",
+ "messagenotsent": "Poruka nije poslata. Molimo, pokušajte ponovo kasnije.",
+ "messagepreferences": "Parametri poruka",
+ "messages": "Poruke",
+ "mustbeonlinetosendmessages": "Morate biti onlajn kako biste slali poruke",
+ "newmessage": "Nove poruke...",
+ "newmessages": "Nove poruke",
+ "nomessages": "Nema poruka.",
+ "nousersfound": "Nije pronađen nijedan korisnik",
+ "removecontact": "Obriši kontakt",
+ "removecontactconfirm": "Osoba će biti uklonjena sa vaše liste kontakata.",
+ "send": "Pošalji",
+ "sendmessage": "Pošalji poruku",
+ "type_blocked": "Blokiran",
+ "type_offline": "Oflajn",
+ "type_online": "Onlajn",
+ "type_search": "Rezultati pretrage",
+ "type_strangers": "Drugi",
+ "unblockcontact": "Odblokiraj kontakt",
+ "warningmessagenotsent": "Nije moguće poslati poruku/e korisniku {{user}}. {{error}}"
+}
\ No newline at end of file
diff --git a/www/addons/messages/lang/sv.json b/www/addons/messages/lang/sv.json
index 301b34c89a3..d17bc0228ef 100644
--- a/www/addons/messages/lang/sv.json
+++ b/www/addons/messages/lang/sv.json
@@ -11,15 +11,16 @@
"errorwhileretrievingcontacts": "Fel vid hämtning av kontakter från servern.",
"errorwhileretrievingdiscussions": "Fel vid hämtning av diskussionerna från servern.",
"errorwhileretrievingmessages": "Fel vid hämtning meddelanden från servern.",
- "message": "Meddelandets brödtext",
+ "message": "Meddelande",
"messagenotsent": "Meddelandet skickades inte, försök igen senare.",
+ "messagepreferences": "Välj inställningar för meddelanden",
"messages": "Meddelanden",
"mustbeonlinetosendmessages": "Du måste vara online för att skicka meddelanden",
"newmessage": "Ny meddelande...",
"nomessages": "Inga meddelanden",
"nousersfound": "Inga användare hittades",
"removecontact": "Ta bort kontakt",
- "send": "skicka",
+ "send": "Skicka",
"sendmessage": "Skicka meddelande",
"type_blocked": "blockerad",
"type_offline": "Offline",
diff --git a/www/addons/messages/lang/tr.json b/www/addons/messages/lang/tr.json
index 72ef991ede5..38d1a3b1e77 100644
--- a/www/addons/messages/lang/tr.json
+++ b/www/addons/messages/lang/tr.json
@@ -5,11 +5,11 @@
"contactlistempty": "Kişi listeniz şu anda boş",
"contactname": "Adı",
"contacts": "Kişiler",
- "message": "Mesaj gövdesi",
+ "message": "Mesaj",
"messagepreferences": "İleti tercihleri",
"messages": "Mesajlar",
"newmessage": "Yeni ileti",
- "nomessages": "İleti yok.",
+ "nomessages": "Henüz mesaj yok",
"nousersfound": "Kullanıcı bulunamadı",
"removecontact": "Kişiyi sil",
"send": "Gönder",
diff --git a/www/addons/messages/lang/uk.json b/www/addons/messages/lang/uk.json
index 21fa4dc7976..10cf5c336d1 100644
--- a/www/addons/messages/lang/uk.json
+++ b/www/addons/messages/lang/uk.json
@@ -11,7 +11,7 @@
"errorwhileretrievingdiscussions": "Помилка при отриманні обговорення з сервера.",
"errorwhileretrievingmessages": "Помилка при отриманні повідомлень від сервера.",
"loadpreviousmessages": "Завантаження попередніх повідомлень",
- "message": "Текст повідомлення",
+ "message": "Повідомлення",
"messagenotsent": "Повідомлення не було відправлено, будь ласка, спробуйте ще раз пізніше.",
"messages": "Повідомлення",
"mustbeonlinetosendmessages": "Ви повинні бути онлайн, щоб відправляти повідомлення",
@@ -21,7 +21,7 @@
"nousersfound": "Користувачів не знайдено",
"removecontact": "Видалити контакт",
"removecontactconfirm": "Контакт буде видалено зі списку контактів.",
- "send": "Відіслати",
+ "send": "надіслати",
"sendmessage": "Надіслати повідомлення",
"type_blocked": "Заблоковано",
"type_offline": "Офлайн",
@@ -29,5 +29,5 @@
"type_search": "Результати пошуку",
"type_strangers": "Інші",
"unblockcontact": "Розблокувати контакт",
- "warningmessagenotsent": "Неможливо відправити повідомлення до {{user}}. {{error}}"
+ "warningmessagenotsent": "Неможливо відправити повідомлення до {{user}}. {{error}}"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/zh-cn.json b/www/addons/messages/lang/zh-cn.json
index 38ed871a73d..fa7d759934b 100644
--- a/www/addons/messages/lang/zh-cn.json
+++ b/www/addons/messages/lang/zh-cn.json
@@ -6,12 +6,12 @@
"contactname": "联系人",
"contacts": "联系人",
"deletemessage": "删除消息",
- "message": "内容",
+ "message": "正文",
"messages": "消息",
- "nomessages": "无消息",
+ "nomessages": "没有新消息",
"nousersfound": "未找到用户",
"removecontact": "删除联系人",
"send": "发送",
- "sendmessage": "发消息",
+ "sendmessage": "发送消息",
"unblockcontact": "不再阻拦联系人"
}
\ No newline at end of file
diff --git a/www/addons/messages/lang/zh-tw.json b/www/addons/messages/lang/zh-tw.json
index 34693107bc7..60b1bfa8db2 100644
--- a/www/addons/messages/lang/zh-tw.json
+++ b/www/addons/messages/lang/zh-tw.json
@@ -11,17 +11,17 @@
"errorwhileretrievingcontacts": "從伺服器存取聯絡人時出錯",
"errorwhileretrievingdiscussions": "從伺服器存取討論區時出錯",
"errorwhileretrievingmessages": "從伺服器存取訊息時出錯",
- "message": "訊息主文",
+ "message": "訊息",
"messagenotsent": "訊息未發送, 請稍後再試.",
"messagepreferences": "簡訊偏好",
- "messages": "訊息",
+ "messages": "簡訊",
"mustbeonlinetosendmessages": "您必須上線才能發送訊息",
- "newmessage": "新訊息...",
- "nomessages": "沒有任何訊息.",
+ "newmessage": "新簡訊",
+ "nomessages": "尚無訊息",
"nousersfound": "沒有使用者",
"removecontact": "刪除聯絡人",
- "send": "傳送",
- "sendmessage": "寄送訊息",
+ "send": "送出",
+ "sendmessage": "傳送簡訊",
"type_blocked": "已停止",
"type_offline": "離線",
"type_online": "上線",
diff --git a/www/addons/messages/lang/zh_cn.json b/www/addons/messages/lang/zh_cn.json
deleted file mode 100644
index 708e5a301b9..00000000000
--- a/www/addons/messages/lang/zh_cn.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "addcontact": "添加为联系人",
- "blockcontact": "屏蔽联系人",
- "contactlistempty": "您的联系人名单是空的",
- "contactname": "联系人",
- "contacts": "联系人",
- "messages": "消息",
- "nomessages": "没有新消息",
- "removecontact": "删除联系人",
- "send": "发送",
- "sendmessage": "发送消息",
- "unblockcontact": "不再阻拦联系人"
-}
\ No newline at end of file
diff --git a/www/addons/messages/lang/zh_tw.json b/www/addons/messages/lang/zh_tw.json
deleted file mode 100644
index b86c20e0f95..00000000000
--- a/www/addons/messages/lang/zh_tw.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "addcontact": "加入通訊錄",
- "blockcontact": "封鎖聯絡人",
- "contactlistempty": "您的通訊錄是空的",
- "contactname": "聯絡人姓名",
- "contacts": "通訊錄",
- "messages": "我的簡訊",
- "nomessages": "沒有待處理的簡訊",
- "removecontact": "刪除聯絡人",
- "send": "傳送",
- "sendmessage": "傳送訊息",
- "unblockcontact": "不再封鎖聯絡"
-}
\ No newline at end of file
diff --git a/www/addons/messages/main.js b/www/addons/messages/main.js
index 740671284eb..2e7697e54a4 100644
--- a/www/addons/messages/main.js
+++ b/www/addons/messages/main.js
@@ -29,6 +29,7 @@ angular.module('mm.addons.messages', ['mm.core'])
.constant('mmaMessagesReadCronEvent', 'mma-messages_read_cron')
.constant('mmaMessagesAutomSyncedEvent', 'mma_messages_autom_synced')
.constant('mmaMessagesLimitSearchMessages', 50)
+.constant('mmaMessagesPushSimulationComponent', 'mmaMessagesPushSimulation')
.config(function($stateProvider, $mmUserDelegateProvider, $mmSideMenuDelegateProvider, mmaMessagesSendMessagePriority,
mmaMessagesAddContactPriority, mmaMessagesBlockContactPriority, mmaMessagesPriority, $mmContentLinksDelegateProvider,
@@ -87,7 +88,7 @@ angular.module('mm.addons.messages', ['mm.core'])
})
.run(function($mmaMessages, $mmEvents, $state, $mmAddonManager, $mmUtil, mmCoreEventLogin, $mmCronDelegate, $mmaMessagesSync,
- mmCoreEventOnlineStatusChanged, $mmSitesManager) {
+ mmCoreEventOnlineStatusChanged, $mmSitesManager, $mmLocalNotifications, $mmApp, mmaMessagesPushSimulationComponent) {
// Invalidate messaging enabled WS calls.
$mmEvents.on(mmCoreEventLogin, function() {
@@ -99,18 +100,7 @@ angular.module('mm.addons.messages', ['mm.core'])
if ($mmPushNotificationsDelegate) {
$mmPushNotificationsDelegate.registerHandler('mmaMessages', function(notification) {
if ($mmUtil.isFalseOrZero(notification.notif)) {
- $mmaMessages.isMessagingEnabledForSite(notification.site).then(function() {
- $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaMessages', notification.site).then(function(disabled) {
- if (disabled) {
- // Messages are disabled, stop.
- return;
- }
-
- $mmaMessages.invalidateDiscussionsCache().finally(function() {
- $state.go('redirect', {siteid: notification.site, state: 'site.messages'});
- });
- });
- });
+ notificationClicked(notification);
return true;
}
});
@@ -126,4 +116,24 @@ angular.module('mm.addons.messages', ['mm.core'])
$mmaMessagesSync.syncAllDiscussions(undefined, true);
}
});
+
+ if ($mmApp.isDesktop()) {
+ // Listen for clicks in simulated push notifications.
+ $mmLocalNotifications.registerClick(mmaMessagesPushSimulationComponent, notificationClicked);
+ }
+
+ function notificationClicked(notification) {
+ $mmaMessages.isMessagingEnabledForSite(notification.site).then(function() {
+ $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaMessages', notification.site).then(function(disabled) {
+ if (disabled) {
+ // Messages are disabled, stop.
+ return;
+ }
+
+ $mmaMessages.invalidateDiscussionsCache().finally(function() {
+ $state.go('redirect', {siteid: notification.site, state: 'site.messages'});
+ });
+ });
+ });
+ }
});
diff --git a/www/addons/messages/services/handlers.js b/www/addons/messages/services/handlers.js
index 412b112500f..3ce6f4c4c3e 100644
--- a/www/addons/messages/services/handlers.js
+++ b/www/addons/messages/services/handlers.js
@@ -25,11 +25,43 @@ angular.module('mm.addons.messages')
*/
.factory('$mmaMessagesHandlers', function($log, $mmaMessages, $mmSite, $state, $mmUtil, $mmContentLinksHelper, $mmaMessagesSync,
$mmSitesManager, mmUserProfileHandlersTypeCommunication, mmUserProfileHandlersTypeAction, $translate,
- mmaMessagesReadChangedEvent, $mmEvents, mmaMessagesReadCronEvent, $mmAddonManager, $mmContentLinkHandlerFactory) {
+ mmaMessagesReadChangedEvent, $mmEvents, mmaMessagesReadCronEvent, $mmAddonManager, $mmContentLinkHandlerFactory,
+ $mmText, $mmApp, $mmLocalNotifications, $mmEmulatorHelper, mmaMessagesPushSimulationComponent) {
$log = $log.getInstance('$mmaMessagesHandlers');
var self = {};
+ /**
+ * Get the latest unread received messages from a site.
+ *
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved with the notifications.
+ */
+ function fetchMessages(siteId) {
+ return $mmaMessages.getUnreadReceivedMessages(true, false, true, siteId).then(function(response) {
+ return response.messages;
+ });
+ }
+
+ /**
+ * Given a message, return the title and the text for the message.
+ *
+ * @param {Object} message Message.
+ * @return {Promise} Promise resolved with an object with title and text.
+ */
+ function getTitleAndText(message) {
+ var data = {
+ title: message.userfromfullname,
+ };
+
+ return $mmText.formatText(message.text, true, true).catch(function() {
+ return message.text;
+ }).then(function(formattedText) {
+ data.text = formattedText;
+ return data;
+ });
+ }
+
/**
* Add contact handler.
*
@@ -407,6 +439,11 @@ angular.module('mm.addons.messages')
siteid: siteId
});
}
+
+ if ($mmApp.isDesktop() && $mmLocalNotifications.isAvailable()) {
+ $mmEmulatorHelper.checkNewNotifications(
+ mmaMessagesPushSimulationComponent, fetchMessages, getTitleAndText, siteId);
+ }
};
/**
@@ -415,7 +452,7 @@ angular.module('mm.addons.messages')
* @return {Number} Time between consecutive executions (in ms).
*/
self.getInterval = function() {
- return 600000; // 10 minutes.
+ return $mmApp.isDesktop() ? 60000 : 600000; // 1 or 10 minutes.
};
/**
@@ -424,8 +461,9 @@ angular.module('mm.addons.messages')
* @return {Boolean} True if is a sync process, false otherwise.
*/
self.isSync = function() {
- // This is done to use only wifi if using the fallback function
- return !$mmaMessages.isMessageCountEnabled();
+ // This is done to use only wifi if using the fallback function.
+ // In desktop it is always sync, since it fetches messages to see if there's a new one.
+ return !$mmaMessages.isMessageCountEnabled() || $mmApp.isDesktop();
};
/**
diff --git a/www/addons/messages/services/messages.js b/www/addons/messages/services/messages.js
index 41f22f2a6aa..16aa328c250 100644
--- a/www/addons/messages/services/messages.js
+++ b/www/addons/messages/services/messages.js
@@ -22,7 +22,8 @@ angular.module('mm.addons.messages')
* @name $mmaMessages
*/
.factory('$mmaMessages', function($mmSite, $mmSitesManager, $log, $q, $mmUser, $mmaMessagesOffline, $mmApp, $mmUtil,
- mmaMessagesNewMessageEvent, mmaMessagesLimitMessages, mmaMessagesLimitSearchMessages) {
+ mmaMessagesNewMessageEvent, mmaMessagesLimitMessages, mmaMessagesLimitSearchMessages, $mmEmulatorHelper,
+ mmaMessagesPushSimulationComponent) {
$log = $log.getInstance('$mmaMessages');
var self = {};
@@ -286,9 +287,12 @@ angular.module('mm.addons.messages')
* @param {Number} [lfReceivedRead=0] Number of read received messages already fetched, so fetch will be done from this.
* @param {Number} [lfSentUnread=0] Number of unread sent messages already fetched, so fetch will be done from this.
* @param {Number} [lfSentRead=0] Number of read sent messages already fetched, so fetch will be done from this.
+ * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification.
+ * @param {String} [siteId] Site ID. If not defined, use current site.
* @return {Promise} Promise resolved with messages and a boolean telling if can load more messages.
*/
- self.getDiscussion = function(userId, excludePending, lfReceivedUnread, lfReceivedRead, lfSentUnread, lfSentRead) {
+ self.getDiscussion = function(userId, excludePending, lfReceivedUnread, lfReceivedRead, lfSentUnread, lfSentRead, toDisplay,
+ siteId) {
lfReceivedUnread = lfReceivedUnread || 0;
lfReceivedRead = lfReceivedRead || 0;
lfSentUnread = lfSentUnread || 0;
@@ -315,14 +319,15 @@ angular.module('mm.addons.messages')
}
// Get message received by current user.
- return self._getRecentMessages(params, presets, lfReceivedUnread, lfReceivedRead).then(function(response) {
+ return self._getRecentMessages(params, presets, lfReceivedUnread, lfReceivedRead, toDisplay, siteId)
+ .then(function(response) {
result.messages = response;
params.useridto = userId;
params.useridfrom = $mmSite.getUserId();
hasReceived = response.length > 0;
// Get message sent by current user.
- return self._getRecentMessages(params, presets, lfSentUnread, lfSentRead);
+ return self._getRecentMessages(params, presets, lfSentUnread, lfSentRead, toDisplay, siteId);
}).then(function(response) {
result.messages = result.messages.concat(response);
hasSent = response.length > 0;
@@ -524,25 +529,40 @@ angular.module('mm.addons.messages')
* @module mm.addons.messages
* @ngdoc method
* @name $mmaMessages#_getMessages
- * @param {Object} params Parameters to pass to the WS.
- * @param {Object} presets Set of presets for the WS.
+ * @param {Object} params Parameters to pass to the WS.
+ * @param {Object} preSets Set of presets for the WS.
+ * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification.
+ * @param {String} [siteId] Site ID. If not defined, use current site.
* @return {Promise}
* @protected
*/
- self._getMessages = function(params, presets) {
+ self._getMessages = function(params, preSets, toDisplay, siteId) {
+ toDisplay = typeof toDisplay == 'undefined' ? true : toDisplay;
+ siteId = siteId || $mmSite.getId();
+
params = angular.extend(params, {
type: 'conversations',
newestfirst: 1,
});
- return $mmSite.read('core_message_get_messages', params, presets).then(function(response) {
- angular.forEach(response.messages, function(message) {
- message.read = params.read == 0 ? 0 : 1;
- // Convert times to milliseconds.
- message.timecreated = message.timecreated ? message.timecreated * 1000 : 0;
- message.timeread = message.timeread ? message.timeread * 1000 : 0;
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var userId = site.getUserId();
+
+ return site.read('core_message_get_messages', params, preSets).then(function(response) {
+ angular.forEach(response.messages, function(message) {
+ message.read = params.read == 0 ? 0 : 1;
+ // Convert times to milliseconds.
+ message.timecreated = message.timecreated ? message.timecreated * 1000 : 0;
+ message.timeread = message.timeread ? message.timeread * 1000 : 0;
+ });
+
+ if ($mmApp.isDesktop() && toDisplay && !params.read && params.useridto == userId && params.limitfrom === 0) {
+ // Store the last unread received messages. Don't block the user for this.
+ storeLastReceivedMessageIfNeeded(params.useridfrom, response.messages[0], siteId);
+ }
+
+ return response;
});
- return response;
});
};
@@ -556,10 +576,12 @@ angular.module('mm.addons.messages')
* @param {Object} preSets Set of presets for the WS.
* @param {Number} [limitFromUnread=0] Number of read messages already fetched, so fetch will be done from this number.
* @param {Number} [limitFromRead=0] Number of unread messages already fetched, so fetch will be done from this number.
+ * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification.
+ * @param {String} [siteId] Site ID. If not defined, use current site.
* @return {Promise}
* @protected
*/
- self._getRecentMessages = function(params, preSets, limitFromUnread, limitFromRead) {
+ self._getRecentMessages = function(params, preSets, limitFromUnread, limitFromRead, toDisplay, siteId) {
limitFromUnread = limitFromUnread || 0;
limitFromRead = limitFromRead || 0;
@@ -568,7 +590,7 @@ angular.module('mm.addons.messages')
limitfrom: limitFromUnread
});
- return self._getMessages(params, preSets).then(function(response) {
+ return self._getMessages(params, preSets, toDisplay, siteId).then(function(response) {
var messages = response.messages;
if (messages) {
if (messages.length >= params.limitnum) {
@@ -580,7 +602,7 @@ angular.module('mm.addons.messages')
params.read = 1;
params.limitfrom = limitFromRead;
- return self._getMessages(params, preSets).then(function(response) {
+ return self._getMessages(params, preSets, toDisplay, siteId).then(function(response) {
if (response.messages) {
messages = messages.concat(response.messages);
}
@@ -642,11 +664,13 @@ angular.module('mm.addons.messages')
* @return {Promise} Promise resolved with the message unread count.
*/
self.getUnreadConversationsCount = function(userId, siteId) {
+ var params;
+
return $mmSitesManager.getSite(siteId).then(function(site) {
userId = userId || site.getUserId();
if (site.wsAvailable('core_message_get_unread_conversations_count')) {
- var params = {
+ params = {
useridto: userId
},
preSets = {
@@ -663,14 +687,14 @@ angular.module('mm.addons.messages')
}
// Fallback call.
- var params = {
+ params = {
read: 0,
limitfrom: 0,
limitnum: mmaMessagesLimitMessages + 1,
useridto: userId,
useridfrom: 0,
};
- return self._getMessages(params).then(function(response) {
+ return self._getMessages(params, undefined, false, siteId).then(function(response) {
// Count the discussions by filtering same senders.
var discussions = {},
count;
@@ -688,6 +712,40 @@ angular.module('mm.addons.messages')
});
};
+ /**
+ * Get the latest unread received messages.
+ *
+ * @module mm.addons.messages
+ * @ngdoc method
+ * @name $mmaMessages#getUnreadReceivedMessages
+ * @param {Boolean} [toDisplay=true] True if messages will be displayed to the user, either in view or in a notification.
+ * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, use current site.
+ * @return {Promise} Promise resolved with the message unread count.
+ */
+ self.getUnreadReceivedMessages = function(toDisplay, forceCache, ignoreCache, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ read: 0,
+ limitfrom: 0,
+ limitnum: mmaMessagesLimitMessages,
+ useridto: site.getUserId(),
+ useridfrom: 0
+ },
+ preSets = {};
+
+ if (forceCache) {
+ preSets.omitExpires = true;
+ } else if (ignoreCache) {
+ preSets.getFromCache = 0;
+ preSets.emergencyCache = 0;
+ }
+
+ return self._getMessages(params, preSets, toDisplay, siteId);
+ });
+ };
+
/**
* Invalidate all contacts cache.
*
@@ -1274,6 +1332,33 @@ angular.module('mm.addons.messages')
});
}
+ /**
+ * Store the last received message if it's newer than the last stored.
+ *
+ * @param {Number} userIdFrom ID of the useridfrom retrieved, 0 for all users.
+ * @param {Object} message Last message received.
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved when done.
+ */
+ function storeLastReceivedMessageIfNeeded(userIdFrom, message, siteId) {
+ var component = mmaMessagesPushSimulationComponent;
+
+ // Get the last received message.
+ return $mmEmulatorHelper.getLastReceivedNotification(component, siteId).then(function(lastMessage) {
+ if (userIdFrom > 0 && (!message || !lastMessage)) {
+ // Seeing a single discussion. No received message or cannot know if it really is the last received message. Stop.
+ return;
+ }
+
+ if (message && lastMessage && message.timecreated <= lastMessage.timecreated) {
+ // The message isn't newer than the stored message, don't store it.
+ return;
+ }
+
+ return $mmEmulatorHelper.storeLastReceivedNotification(component, message, siteId);
+ });
+ }
+
/**
* Unblock a user.
*
diff --git a/www/addons/mod/assign/lang/ca.json b/www/addons/mod/assign/lang/ca.json
index 9d246a7ff12..065ff663e07 100644
--- a/www/addons/mod/assign/lang/ca.json
+++ b/www/addons/mod/assign/lang/ca.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "No es pot mostrar la informació de la tramesa",
"extensionduedate": "Data de venciment de la pròrroga",
"feedbacknotsupported": "Aquesta retroacció no està admesa per l'aplicació i podria no contenir tota la informació",
- "grade": "Qualifica",
+ "grade": "Qualificació",
"graded": "Qualificada",
"gradedby": "Qualificat per",
"gradedon": "Qualificat el",
diff --git a/www/addons/mod/assign/lang/de.json b/www/addons/mod/assign/lang/de.json
index 802d7887f82..02ebc2a9649 100644
--- a/www/addons/mod/assign/lang/de.json
+++ b/www/addons/mod/assign/lang/de.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "Die Abgabeinformationen können nicht angezeigt werden.",
"extensionduedate": "Verlängerung des Fälligkeitsdatums",
"feedbacknotsupported": "Dieses Feedback wird von der App nicht unterstützt und könnte möglicherweise Informationen unvollständig enthalten.",
- "grade": "Relative Bewertung",
+ "grade": "Bewertung",
"graded": "Bewertet",
"gradedby": "Bewertet von",
"gradedon": "Bewertet am",
diff --git a/www/addons/mod/assign/lang/el.json b/www/addons/mod/assign/lang/el.json
index 321937193aa..f05910d0dc3 100644
--- a/www/addons/mod/assign/lang/el.json
+++ b/www/addons/mod/assign/lang/el.json
@@ -23,15 +23,18 @@
"editsubmission": "Τροποποίηση της υποβολής μου",
"erroreditpluginsnotsupported": "Δεν μπορείτε να προσθέσετε ή να επεξεργαστείτε μια υποβολή στην εφαρμογή επειδή ορισμένα plugins δεν υποστηρίζονται για επεξεργασία:",
"errorshowinginformation": "Δεν μπορούν να εμφανιστούν οι πληροφορίες υποβολής",
+ "feedbacknotsupported": "Αυτό το σχόλιο δεν υποστηρίζεται από την εφαρμογή και μπορεί να μην περιέχει όλες τις πληροφορίες",
"grade": "Βαθμός",
"graded": "Βαθμολογήθηκε",
"gradedby": "Βαθμολογήθηκε από",
"gradedon": "Βαθμολογήθηκε στις",
+ "gradenotsynced": "Η βαθμολογία δεν συγχρονίστηκε",
"gradingstatus": "Κατάσταση Βαθμολόγησης",
"groupsubmissionsettings": "Ρυθμίσεις ομαδικής υποβολής",
"latesubmissions": "Εκπρόθεσμες υποβολές",
"noattempt": "Καμία προσπάθεια",
"nomoresubmissionsaccepted": "Επιτρέπονται μόνο στους συμμετέχοντες που τους έχει χορηγηθεί παράταση",
+ "noonlinesubmissions": "Δεν απαιτείται κάποια υποβολή",
"nosubmission": "Δεν έχει υποβληθεί τίποτα για την εργασία αυτή",
"notallparticipantsareshown": "Συμμετέχοντες χωρίς υποβολές δεν προβάλλονται",
"notgraded": "Χωρίς βαθμό",
diff --git a/www/addons/mod/assign/lang/es.json b/www/addons/mod/assign/lang/es.json
index 35e141f70c9..8b1583be23c 100644
--- a/www/addons/mod/assign/lang/es.json
+++ b/www/addons/mod/assign/lang/es.json
@@ -36,6 +36,7 @@
"graded": "Calificado",
"gradedby": "Calificado por",
"gradedon": "Calificado sobre",
+ "gradenotsynced": "Calificación no sincronizada",
"gradeoutof": "Calificación sobre {{$a}}",
"gradingstatus": "Estado de la calificación",
"groupsubmissionsettings": "Configuración de entrega por grupo",
diff --git a/www/addons/mod/assign/lang/es_mx.json b/www/addons/mod/assign/lang/es_mx.json
deleted file mode 100644
index 5e29ef33e38..00000000000
--- a/www/addons/mod/assign/lang/es_mx.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "addsubmission": "Añadir envío",
- "allowsubmissionsfromdate": "Permitir envíos desde",
- "attemptnumber": "Número de intento",
- "cutoffdate": "Fecha de corte",
- "duedate": "Fecha de entrega",
- "duedateno": "No hay fecha de entrega",
- "submissions": "Entregas",
- "viewsubmission": "Ver entrega"
-}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/eu.json b/www/addons/mod/assign/lang/eu.json
index 1b62e71067f..c5b7f53de20 100644
--- a/www/addons/mod/assign/lang/eu.json
+++ b/www/addons/mod/assign/lang/eu.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "Ezin dugu bidalketaren informazioa erakutsi",
"extensionduedate": "Luzapenaren entregatze-data",
"feedbacknotsupported": "Feedback hau ez da onartzen app-an eta baliteke informazio guztia jasota ez egotea.",
- "grade": "Nota",
+ "grade": "Kalifikazioa",
"graded": "Kalifikatua",
"gradedby": "Nork kalifikatua",
"gradedon": "Noiz kalifikatua",
diff --git a/www/addons/mod/assign/lang/fr.json b/www/addons/mod/assign/lang/fr.json
index 4dc3f9a1b2b..19cfc56bcaf 100644
--- a/www/addons/mod/assign/lang/fr.json
+++ b/www/addons/mod/assign/lang/fr.json
@@ -15,7 +15,7 @@
"attemptreopenmethod_untilpass": "Automatiquement jusqu'à réussite",
"attemptsettings": "Réglages de tentative",
"cannoteditduetostatementsubmission": "Vous ne pouvez pas ajouter, ni modifier de données dans l'app, car il n'est actuellement pas possible de récupérer les conditions d'envoi.",
- "cannotgradefromapp": "Certaines méthodes d'évaluations ne sont pas encore supportées par l'app et ne peuvent pas être modifiées",
+ "cannotgradefromapp": "Certaines méthodes d'évaluations ne sont pas encore supportées par l'app et ne peuvent pas être modifiées.",
"cannotsubmitduetostatementsubmission": "Vous ne pouvez pas déposer de travail à évaluer dans l'app, car il n'est actuellement pas possible de récupérer les conditions d'envoi.",
"confirmsubmission": "Voulez-vous vraiment remettre votre travail pour évaluation ? Vous ne pourrez plus effectuer de changement.",
"currentattempt": "Ceci est la tentative {{$a}}.",
@@ -57,7 +57,7 @@
"nosubmission": "Rien n'a été déposé pour ce devoir",
"notallparticipantsareshown": "Les participants sans travail remis ne sont pas affichés",
"noteam": "Membre d'aucun groupe",
- "notgraded": "Pas évalué",
+ "notgraded": "Non évalué",
"numberofdraftsubmissions": "Brouillons",
"numberofparticipants": "Participants",
"numberofsubmissionsneedgrading": "Nécessitant évaluation",
@@ -76,10 +76,10 @@
"submissionstatus_": "Pas de travail remis",
"submissionstatus_draft": "Brouillon (non remis)",
"submissionstatus_marked": "Noté",
- "submissionstatus_new": "Aucun travail remis",
+ "submissionstatus_new": "Non remis",
"submissionstatus_reopened": "Rouvert",
"submissionstatus_submitted": "Remis pour évaluation",
- "submissionstatusheading": "État du travail remis",
+ "submissionstatusheading": "Statut de remise",
"submissionteam": "Groupe",
"submitassignment": "Envoyer le devoir",
"submitassignment_help": "Une fois ce devoir envoyé, vous ne pourrez plus y effectuer de modification.",
diff --git a/www/addons/mod/assign/lang/he.json b/www/addons/mod/assign/lang/he.json
index 634624ece1e..05f4ea2748c 100644
--- a/www/addons/mod/assign/lang/he.json
+++ b/www/addons/mod/assign/lang/he.json
@@ -25,7 +25,7 @@
"editingstatus": "מצב עריכה",
"editsubmission": "עריכת ההגשה",
"extensionduedate": "הארכת מועד הגשה",
- "grade": "ציונים",
+ "grade": "ציון",
"graded": "נבדק",
"gradedby": "נבדק על-ידי",
"gradedon": "הציון ניתן על",
diff --git a/www/addons/mod/assign/lang/it.json b/www/addons/mod/assign/lang/it.json
index efc338d796b..bfcebef051d 100644
--- a/www/addons/mod/assign/lang/it.json
+++ b/www/addons/mod/assign/lang/it.json
@@ -25,7 +25,7 @@
"editingstatus": "Possibilità di modifica",
"editsubmission": "Modifica consegna",
"extensionduedate": "Data scadenza proroga",
- "grade": "Punteggio",
+ "grade": "Valutazione",
"graded": "Valutata",
"gradedby": "Valutatore",
"gradedon": "Data di valutazione",
diff --git a/www/addons/mod/assign/lang/ja.json b/www/addons/mod/assign/lang/ja.json
index d7f86ec249e..4837351e4cc 100644
--- a/www/addons/mod/assign/lang/ja.json
+++ b/www/addons/mod/assign/lang/ja.json
@@ -1,4 +1,5 @@
{
+ "acceptsubmissionstatement": "提出時宣誓文を受諾してください。",
"addattempt": "別の提出を許可する",
"addnewattempt": "新しい提出を追加する",
"addnewattemptfromprevious": "前回の提出をもとに新しい提出を追加する",
@@ -13,6 +14,9 @@
"attemptreopenmethod_manual": "手動",
"attemptreopenmethod_untilpass": "合格するまで自動",
"attemptsettings": "受験設定",
+ "cannoteditduetostatementsubmission": "サイトから提出時宣誓文を取得することができなかったため、アプリでは提出物の追加や編集ができません。",
+ "cannotgradefromapp": "評定方法にアプリでは未サポートあるいは変更できないものがあります。",
+ "cannotsubmitduetostatementsubmission": "サイトから提出時宣誓文が取得できなかったため、アプリから評定を提出することができませんでした。",
"confirmsubmission": "本当にあなたの作業を評定のために提出してもよろしいですか? これ以上、あなたは変更できないようになります。",
"currentattempt": "これは {{$a}} 回目の提出です。",
"currentattemptof": "これは {{$a.attemptnumber}} 回目の提出です ( {{$a.maxattempts}} 回の提出が許可されています)。",
@@ -24,11 +28,15 @@
"duedatereached": "この課題の提出期限を過ぎました。",
"editingstatus": "編集ステータス",
"editsubmission": "提出を編集する",
+ "erroreditpluginsnotsupported": "提出物の編集がサポートされていないプラグインがあるため、アプリから提出物の追加や編集ができませんでした。",
+ "errorshowinginformation": "提出物の情報を表示できません。",
"extensionduedate": "延長提出期限",
- "grade": "評点",
+ "feedbacknotsupported": "このフィードバックはアプリでは未サポートのため、すべての情報が含まれていない可能性があります",
+ "grade": "評定",
"graded": "評定済み",
"gradedby": "評定者",
"gradedon": "評定日時",
+ "gradenotsynced": "評定が同期できませんでした",
"gradeoutof": "{{$a}} 点中の評点",
"gradingstatus": "評定ステータス",
"groupsubmissionsettings": "グループ提出設定",
@@ -47,6 +55,7 @@
"nomoresubmissionsaccepted": "延長を許可された参加者のみ許可されます。",
"noonlinesubmissions": "この課題においてあなたがオンラインで提出するものはありません。",
"nosubmission": "この課題に関して提出されているものはありません。",
+ "notallparticipantsareshown": "提出物のない参加者は表示されていません",
"noteam": "どのグループのメンバーでもない",
"notgraded": "未評定",
"numberofdraftsubmissions": "下書き",
@@ -61,6 +70,7 @@
"submission": "提出課題",
"submissioneditable": "学生はこの提出を編集できます。",
"submissionnoteditable": "学生はこの提出を編集できません。",
+ "submissionnotsupported": "この提出物はアプリでは未サポートのため、すべての情報が含まれていない可能性があります",
"submissionslocked": "この課題は提出を受け付けていません。",
"submissionstatus": "提出ステータス",
"submissionstatus_": "提出なし",
@@ -80,5 +90,8 @@
"ungroupedusers": "設定「提出にグループを必要とする」が有効にされているため、そして何名かのユーザがグループのメンバーではないため、または2つ以上のグループメンバーであるため、提出することはできません。",
"unlimitedattempts": "無制限",
"userswhoneedtosubmit": "提出が必要なユーザ: {{$a}}",
- "viewsubmission": "提出を表示する"
+ "userwithid": "ID {{id}} を持つユーザ",
+ "viewsubmission": "提出を表示する",
+ "warningsubmissiongrademodified": "提出物の評定がサイト上で変更されました。",
+ "warningsubmissionmodified": "ユーザの提出物がサイト上で変更されました。"
}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/nl.json b/www/addons/mod/assign/lang/nl.json
index cb58014537a..6148bf53066 100644
--- a/www/addons/mod/assign/lang/nl.json
+++ b/www/addons/mod/assign/lang/nl.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "We kunnen de instuurinformatie niet tonen",
"extensionduedate": "Extra tijd einddatum",
"feedbacknotsupported": "Deze feedback wordt niet ondersteund door de app en het is mogelijk dat de informatie onvolledig is",
- "grade": "Cijfer",
+ "grade": "Beoordeling",
"graded": "Beoordeeld",
"gradedby": "Beoordeeld door",
"gradedon": "Beoordeeld op",
diff --git a/www/addons/mod/assign/lang/pt-br.json b/www/addons/mod/assign/lang/pt-br.json
index 1b62b585379..f88df961a39 100644
--- a/www/addons/mod/assign/lang/pt-br.json
+++ b/www/addons/mod/assign/lang/pt-br.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "Nós não podemos exibir as informações do envio",
"extensionduedate": "Extensão do prazo de entrega",
"feedbacknotsupported": "Esse feedback não é suportado pelo aplicativo e pode não conter todas as informações",
- "grade": "Avaliação",
+ "grade": "Nota",
"graded": "Avaliado",
"gradedby": "Avaliado por",
"gradedon": "Avaliado em",
@@ -42,7 +42,7 @@
"groupsubmissionsettings": "Configurações de envio em grupo",
"hiddenuser": "Participante",
"latesubmissions": "Submissões atrasadas",
- "latesubmissionsaccepted": "Somente estudante(s) contemplados com uma extensão ainda poderá(ão) enviar a tarefa",
+ "latesubmissionsaccepted": "Permitido até {{$a}}",
"markingworkflowstate": "Estado do fluxo de avaliação",
"markingworkflowstateinmarking": "Em avaliação",
"markingworkflowstateinreview": "Em revisão",
@@ -50,7 +50,7 @@
"markingworkflowstatereadyforrelease": "Pronto para publicação",
"markingworkflowstatereadyforreview": "Avaliação concluída",
"markingworkflowstatereleased": "Publicado",
- "multipleteams": "Você é membro de vários grupos, entre em contato com o seu professor.",
+ "multipleteams": "Membro de mais de um grupo",
"noattempt": "Nenhuma tentativa",
"nomoresubmissionsaccepted": "Só é permitido para os participantes que tenham beneficiado de uma extensão",
"noonlinesubmissions": "Esta tarefa não requer o envio online",
diff --git a/www/addons/mod/assign/lang/pt.json b/www/addons/mod/assign/lang/pt.json
index e2242d63f5e..f94e6cbb858 100644
--- a/www/addons/mod/assign/lang/pt.json
+++ b/www/addons/mod/assign/lang/pt.json
@@ -32,14 +32,14 @@
"errorshowinginformation": "Não é possível mostrar a informação da submissão",
"extensionduedate": "Prolongamento da data limite",
"feedbacknotsupported": "Este feedback não é suportado pela aplicação e pode não conter toda a informação",
- "grade": "Avaliação",
+ "grade": "Nota",
"graded": "Avaliado",
"gradedby": "Avaliado por",
"gradedon": "Avaliado em",
"gradenotsynced": "Nota não está sincronizada",
"gradeoutof": "Nota (de 0 a {{$a}})",
"gradingstatus": "Estado da avaliação",
- "groupsubmissionsettings": "Configurações das submissões de grupo",
+ "groupsubmissionsettings": "Configurações das submissões em grupo",
"hiddenuser": "Participante",
"latesubmissions": "Submissões com atraso",
"latesubmissionsaccepted": "Disponível até {{$a}}",
diff --git a/www/addons/mod/assign/lang/pt_br.json b/www/addons/mod/assign/lang/pt_br.json
deleted file mode 100644
index ebcaf06b692..00000000000
--- a/www/addons/mod/assign/lang/pt_br.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "addsubmission": "Adicionar tarefa",
- "allowsubmissionsfromdate": "Permite envios a partir de",
- "attemptnumber": "Número da tentativa",
- "cutoffdate": "Data limite",
- "duedate": "Data de entrega",
- "duedateno": "Nenhuma data de entrega",
- "submissions": "Tarefas enviadas",
- "viewsubmission": "Ver envio"
-}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/ro.json b/www/addons/mod/assign/lang/ro.json
index 00faa4cbbda..9e5786fe879 100644
--- a/www/addons/mod/assign/lang/ro.json
+++ b/www/addons/mod/assign/lang/ro.json
@@ -20,7 +20,7 @@
"editingstatus": "Se editează statusul",
"editsubmission": "Editare temă trimisă",
"extensionduedate": "Termen de predare extins",
- "grade": "Notează",
+ "grade": "Notă",
"graded": "Notat",
"gradedby": "Notat de",
"gradedon": "Notat în data de",
diff --git a/www/addons/mod/assign/lang/sr-cr.json b/www/addons/mod/assign/lang/sr-cr.json
new file mode 100644
index 00000000000..3d0bf618245
--- /dev/null
+++ b/www/addons/mod/assign/lang/sr-cr.json
@@ -0,0 +1,97 @@
+{
+ "acceptsubmissionstatement": "Молимо вас да прихватите изјаву о предаји рада.",
+ "addattempt": "Дозволи други покушај",
+ "addnewattempt": "Додај нови покушај",
+ "addnewattemptfromprevious": "Додај нови покушај на основу претходно предатог рада",
+ "addsubmission": "Додај рад",
+ "allowsubmissionsanddescriptionfromdatesummary": "Детаљније информације о задатку и образац за предају радова биће доступни од {{$a}}",
+ "allowsubmissionsfromdate": "Дозволи предају од",
+ "allowsubmissionsfromdatesummary": "Овај задатак ће прихватити предају рада од {{$a}}",
+ "applytoteam": "Примените оцене и повратне информације на целу групу",
+ "assignmentisdue": "Крајњи рок за предају је истекао",
+ "attemptnumber": "Број покушаја",
+ "attemptreopenmethod": "Поновно отварање рада",
+ "attemptreopenmethod_manual": "Ручно",
+ "attemptreopenmethod_untilpass": "Аутоматски док не добије прелазну оцену",
+ "attemptsettings": "Подешавања покушаја",
+ "cannoteditduetostatementsubmission": "Не можете да додате или мењате рад у апликацији јер нисмо могли да преузмемо са сајта изјаву о предаји рада.",
+ "cannotgradefromapp": "Апликације још увек не подржава неке методе оцењивања и оне не могу да се мењају.",
+ "cannotsubmitduetostatementsubmission": "Не можете да предате рад на оцењивање у апликацији јер нисмо могли да преузмемо са сајта изјаву о предаји рада.",
+ "confirmsubmission": "Да ли сте сигурни да желите да предате свој рад на оцењивање? Више нећете моћи да га мењате.",
+ "currentattempt": "Ово је покушај {{$a}}.",
+ "currentattemptof": "Ово је покушај {{$a.attemptnumber}} ( {{$a.maxattempts}} дозвољена/их покушаја ).",
+ "currentgrade": "Тренутна оцена у књизи оцена",
+ "cutoffdate": "Дефинитивни рок",
+ "defaultteam": "Подразумевана група",
+ "duedate": "Крајњи рок",
+ "duedateno": "Нема крајњег рока",
+ "duedatereached": "Крајњи рок за овај задатак је сада истекао",
+ "editingstatus": "Статус уређивања",
+ "editsubmission": "Уреди рад",
+ "erroreditpluginsnotsupported": "Не можете да додате или мењате рад у апликацији јер неки додаци немају подршку за уређивање:",
+ "errorshowinginformation": "Не можемо да прикажемо информације о предатом раду",
+ "extensionduedate": "Продужени рок",
+ "feedbacknotsupported": "Аплликација не подржава ову повратну информацију. Могуће је да она не садржи све информације.",
+ "grade": "Оцена",
+ "graded": "Оцењено",
+ "gradedby": "Оценио/ла",
+ "gradedon": "Оцењено",
+ "gradenotsynced": "Оцена није синхронизована",
+ "gradeoutof": "Оцена од {{$a}}",
+ "gradingstatus": "Статус оцењивања",
+ "groupsubmissionsettings": "Подешавања за групну предају рада",
+ "hiddenuser": "Учесник",
+ "latesubmissions": "Касно предати радови",
+ "latesubmissionsaccepted": "Дозвољено до {{$a}}",
+ "markingworkflowstate": "Стање тока оцењивања",
+ "markingworkflowstateinmarking": "Оцењује се",
+ "markingworkflowstateinreview": "На прегледу",
+ "markingworkflowstatenotmarked": "Није оцењено",
+ "markingworkflowstatereadyforrelease": "Спремно за објаву",
+ "markingworkflowstatereadyforreview": "Оцењивање завршено",
+ "markingworkflowstatereleased": "Објављено",
+ "multipleteams": "Члан више од једне групе",
+ "noattempt": "Нема покушаја",
+ "nomoresubmissionsaccepted": "Дозвољено само полазницима којима је одобрен продужетак",
+ "noonlinesubmissions": "Овај задатак не тражи од вас да било штa предате онлајн",
+ "nosubmission": "За овај задатак још ништа није предато",
+ "notallparticipantsareshown": "Учесници који нису предали рад се не приказују",
+ "noteam": "Није члан ниједне групе.",
+ "notgraded": "Није оцењено",
+ "numberofdraftsubmissions": "Нацрти",
+ "numberofparticipants": "Учесници",
+ "numberofsubmissionsneedgrading": "Тражи оцењивање",
+ "numberofsubmittedassignments": "Предато",
+ "numberofteams": "Групе",
+ "numwords": "{{$a}} реч(и)",
+ "outof": "{{$a.current}} од {{$a.total}}",
+ "overdue": "Крајњи рок за предају рада је истекао пре: {{$a}}",
+ "savechanges": "Сачувај промене",
+ "submission": "Предати рад",
+ "submissioneditable": "Полазници могу да уређују овај задатак",
+ "submissionnoteditable": "Полазници не могу да уређују овај задатак",
+ "submissionnotsupported": "Апликација не подржава овај предати рад. Могуће је да рад не садржи све информације.",
+ "submissionslocked": "Овај задатак не прихвата предају радова",
+ "submissionstatus": "Статус предатог рада",
+ "submissionstatus_": "Нема предатих радова",
+ "submissionstatus_draft": "Нацрт рада (није предато)",
+ "submissionstatus_marked": "Оцењено",
+ "submissionstatus_new": "Нови предати рад",
+ "submissionstatus_reopened": "Поново отворено",
+ "submissionstatus_submitted": "Предато за оцењивање",
+ "submissionstatusheading": "Статус предатог рада",
+ "submissionteam": "Група",
+ "submitassignment": "Predaj rad",
+ "submitassignment_help": "Оног тренутка када предате овај рад више нећете моћи да га мењате.",
+ "submittedearly": "Задатак је предат {{$a}} раније",
+ "submittedlate": "Задатак је предат {{$a}} касније",
+ "timemodified": "Последње измене",
+ "timeremaining": "Преостало време",
+ "ungroupedusers": "Подешавање 'Неопходна је група за предају рада' је омогућено, али неки корисници нису чланови ниједне групе, или су чланови више од једне групе, тако да не могу да предају рад.",
+ "unlimitedattempts": "Неограничено",
+ "userswhoneedtosubmit": "Корисници који треба да предају решење: {{$a}}",
+ "userwithid": "Корисник са ID ознаком {{id}}",
+ "viewsubmission": "Погледај предати рад",
+ "warningsubmissiongrademodified": "Оцена предатог рада је измењена на сајту.",
+ "warningsubmissionmodified": "Предати рад корисника је измењен на сајту."
+}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/sr-lt.json b/www/addons/mod/assign/lang/sr-lt.json
new file mode 100644
index 00000000000..ee08bd63383
--- /dev/null
+++ b/www/addons/mod/assign/lang/sr-lt.json
@@ -0,0 +1,97 @@
+{
+ "acceptsubmissionstatement": "Molimo vas da prihvatite izjavu o predaji rada.",
+ "addattempt": "Dozvoli drugi pokušaj",
+ "addnewattempt": "Dodaj novi pokušaj",
+ "addnewattemptfromprevious": "Dodaj novi pokušaj na osnovu prethodno predatog rada",
+ "addsubmission": "Dodaj rad",
+ "allowsubmissionsanddescriptionfromdatesummary": "Detaljnije informacije o zadatku i obrazac za predaju radova biće dostupni od {{$a}}",
+ "allowsubmissionsfromdate": "Dozvoli predaju od",
+ "allowsubmissionsfromdatesummary": "Ovaj zadatak će prihvatiti predaju rada od {{$a}}",
+ "applytoteam": "Primenite ocene i povratne informacije na celu grupu",
+ "assignmentisdue": "Krajnji rok za predaju je istekao",
+ "attemptnumber": "Broj pokušaja",
+ "attemptreopenmethod": "Ponovno otvaranje rada",
+ "attemptreopenmethod_manual": "Ručno",
+ "attemptreopenmethod_untilpass": "Automatski dok ne dobije prelaznu ocenu",
+ "attemptsettings": "Podešavanja pokušaja",
+ "cannoteditduetostatementsubmission": "Ne možete da dodate ili menjate rad u aplikaciji jer nismo mogli da preuzmemo sa sajta izjavu o predaji rada.",
+ "cannotgradefromapp": "Aplikacije ne podržava neke metode ocenjivanja i one ne mogu da se menjaju.",
+ "cannotsubmitduetostatementsubmission": "Ne možete da predate rad na ocenjivanje u aplikaciji jer nismo mogli da preuzmemo sa sajta izjavu o predaji rada.",
+ "confirmsubmission": "Da li ste sigurni da želite da predate svoj rad na ocenjivanje? Više nećete moći da ga menjate.",
+ "currentattempt": "Ovo je pokušaj {{$a}}.",
+ "currentattemptof": "Ovo je pokušaj {{$a.attemptnumber}} ( {{$a.maxattempts}} dozvoljena/ih pokušaja ).",
+ "currentgrade": "Trenutna ocena u knjizi ocena",
+ "cutoffdate": "Definitivni rok",
+ "defaultteam": "Podrazumevana grupa",
+ "duedate": "Krajnji rok",
+ "duedateno": "Nema krajnjeg roka",
+ "duedatereached": "Krajnji rok za ovaj zadatak je sada istekao",
+ "editingstatus": "Status uređivanja",
+ "editsubmission": "Uredi rad",
+ "erroreditpluginsnotsupported": "Ne možete da dodate ili menjate rad u aplikaciji jer neki dodaci nemaju podršku za uređivanje:",
+ "errorshowinginformation": "Ne možemo da prikažemo informacije o predatom radu",
+ "extensionduedate": "Produženi rok",
+ "feedbacknotsupported": "Apllikacija ne podržava ovu povratnu informaciju. Moguće je da ona ne sadrži sve informacije.",
+ "grade": "Ocena",
+ "graded": "Ocenjeno",
+ "gradedby": "Ocenio/la",
+ "gradedon": "Ocenjeno",
+ "gradenotsynced": "Ocena nije sinhronizovana",
+ "gradeoutof": "Ocena od {{$a}}",
+ "gradingstatus": "Status ocenjivanja",
+ "groupsubmissionsettings": "Podešavanja za grupnu predaju rada",
+ "hiddenuser": "Učesnik",
+ "latesubmissions": "Kasno predati radovi",
+ "latesubmissionsaccepted": "Dozvoljeno do {{$a}}",
+ "markingworkflowstate": "Stanje toka ocenjivanja",
+ "markingworkflowstateinmarking": "Ocenjuje se",
+ "markingworkflowstateinreview": "Na pregledu",
+ "markingworkflowstatenotmarked": "Nije ocenjeno",
+ "markingworkflowstatereadyforrelease": "Spremno za objavu",
+ "markingworkflowstatereadyforreview": "Ocenjivanje završeno",
+ "markingworkflowstatereleased": "Objavljeno",
+ "multipleteams": "Član više od jedne grupe",
+ "noattempt": "Nema pokušaja",
+ "nomoresubmissionsaccepted": "Dozvoljeno samo polaznicima kojima je odobren produžetak",
+ "noonlinesubmissions": "Ovaj zadatak ne traži od vas da bilo šta predate onlajn",
+ "nosubmission": "Za ovaj zadatak još ništa nije predato",
+ "notallparticipantsareshown": "Učesnici koji nisu predali rad se ne prikazuju",
+ "noteam": "Nije član nijedne grupe.",
+ "notgraded": "Nije ocenjeno",
+ "numberofdraftsubmissions": "Nacrti",
+ "numberofparticipants": "Učesnici",
+ "numberofsubmissionsneedgrading": "Traži ocenjivanje",
+ "numberofsubmittedassignments": "Predato",
+ "numberofteams": "Grupe",
+ "numwords": "{{$a}} reč(i)",
+ "outof": "{{$a.current}} od {{$a.total}}",
+ "overdue": "Krajnji rok za predaju rada je istekao pre: {{$a}}",
+ "savechanges": "Sačuvaj promene",
+ "submission": "Predati rad",
+ "submissioneditable": "Polaznici mogu da uređuju ovaj zadatak",
+ "submissionnoteditable": "Polaznici ne mogu da uređuju ovaj zadatak",
+ "submissionnotsupported": "Aplikacija ne podržava ovaj predati rad. Moguće je da rad ne sadrži sve informacije.",
+ "submissionslocked": "Ovaj zadatak ne prihvata predaju radova",
+ "submissionstatus": "Status predatog rada",
+ "submissionstatus_": "Nema predatih radova",
+ "submissionstatus_draft": "Nacrt rada (nije predato)",
+ "submissionstatus_marked": "Ocenjeno",
+ "submissionstatus_new": "Novi predati rad",
+ "submissionstatus_reopened": "Ponovo otvoreno",
+ "submissionstatus_submitted": "Predato za ocenjivanje",
+ "submissionstatusheading": "Status predatog rada",
+ "submissionteam": "Grupa",
+ "submitassignment": "Predaj zadatak",
+ "submitassignment_help": "Onog trenutka kada predate ovaj rad više nećete moći da ga menjate.",
+ "submittedearly": "Zadatak je predat {{$a}} ranije",
+ "submittedlate": "Zadatak je predat {{$a}} kasnije",
+ "timemodified": "Poslednje izmene",
+ "timeremaining": "Preostalo vreme",
+ "ungroupedusers": "Podešavanje 'Neophodna je grupa za predaju rada' je omogućeno, ali neki korisnici nisu članovi nijedne grupe, ili su članovi više od jedne grupe, tako da ne mogu da predaju rad.",
+ "unlimitedattempts": "Neograničeno",
+ "userswhoneedtosubmit": "Korisnici koji treba da predaju rešenje: {{$a}}",
+ "userwithid": "Korisnik sa ID oznakom {{id}}",
+ "viewsubmission": "Pogledaj predati rad",
+ "warningsubmissiongrademodified": "Ocena predatog rada je izmenjena na sajtu.",
+ "warningsubmissionmodified": "Predati rad korisnika je izmenjen na sajtu."
+}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/sv.json b/www/addons/mod/assign/lang/sv.json
index 674db970084..a4ffe14d1c8 100644
--- a/www/addons/mod/assign/lang/sv.json
+++ b/www/addons/mod/assign/lang/sv.json
@@ -13,7 +13,7 @@
"attemptreopenmethod_manual": "Manuellt",
"attemptreopenmethod_untilpass": "Automatiskt tills passerat",
"attemptsettings": "Inställningar försök",
- "confirmsubmission": "Är du säker på att du vill lämna in ditt arbete för betygssättning? Du kommer inte längre att kunna göra några förändringar",
+ "confirmsubmission": "Är du säker på att du vill lämna in ditt arbete för betygssättning? Du kommer inte längre att kunna göra några ändringar",
"currentattempt": "Detta är försök {{$a}}.",
"currentattemptof": "Detta är försök {{$a.attemptnumber}} ( {{$a.maxattempts}} försök tillåten).",
"currentgrade": "Aktuellt betyg/omdöme i betygskatalogen",
@@ -23,9 +23,9 @@
"duedateno": "Inget stoppdatum/tid",
"duedatereached": "Stoppdatum för denna inlämningsuppgift har nu passerat",
"editingstatus": "Redigerar status",
- "editsubmission": "Redigera min inskickade uppgiftslösning",
+ "editsubmission": "Redigera min inlämning",
"extensionduedate": "Förlängning av stoppdatum",
- "grade": "Betyg/omdöme",
+ "grade": "Betyg",
"graded": "Betygssatt",
"gradedby": "Betygssatt av",
"gradedon": "Betygssatt den",
diff --git a/www/addons/mod/assign/lang/tr.json b/www/addons/mod/assign/lang/tr.json
index 72b0e0a2002..d56c55e9e46 100644
--- a/www/addons/mod/assign/lang/tr.json
+++ b/www/addons/mod/assign/lang/tr.json
@@ -25,7 +25,7 @@
"editingstatus": "Durumu düzenleme",
"editsubmission": "Gönderimi düzenle",
"extensionduedate": "Ek sürenin bitiş tarihi",
- "grade": "Not",
+ "grade": "Başarı notu",
"graded": "Notlandırıldı",
"gradedon": "Not verildi",
"gradeoutof": "{{$a}} Dışarıdan notu",
diff --git a/www/addons/mod/assign/lang/uk.json b/www/addons/mod/assign/lang/uk.json
index 2b97cdc9229..96c4002f16f 100644
--- a/www/addons/mod/assign/lang/uk.json
+++ b/www/addons/mod/assign/lang/uk.json
@@ -16,7 +16,7 @@
"attemptsettings": "Налаштування спроби",
"cannoteditduetostatementsubmission": "Ви не можете додати або змінити представлення в додатку, тому що ми не могли отримати заяву з сайту.",
"cannotgradefromapp": "Деякі методи класифікації поки не підтримуються додатком і не можуть бути змінені.",
- "cannotsubmitduetostatementsubmission": "Ви не можете подати для сортування в додатку, тому що ми не могли отримати заява представлення з сайту.",
+ "cannotsubmitduetostatementsubmission": "Ви не можете подати запит для сортування в додатку, тому що ми не могли отримати заява представлення з сайту.",
"confirmsubmission": "Відправити вашу роботу на перевірку? Після цього ви не зможете робити в ній ніяких змін.",
"currentattempt": "Це спроба {{$a}}.",
"currentattemptof": "Це спроба {{$a.attemptnumber}} (дозволено спроб - {{$a.maxattempts}}).",
@@ -36,7 +36,7 @@
"graded": "Оцінено",
"gradedby": "Оцінив",
"gradedon": "Оцінено на",
- "gradenotsynced": "Оцінка не синхронізуються",
+ "gradenotsynced": "Оцінки не синхронізовані",
"gradeoutof": "Оцінка (макс. {{$a}})",
"gradingstatus": "Статус оцінення",
"groupsubmissionsettings": "Налаштування групової здачі",
diff --git a/www/addons/mod/assign/lang/zh-tw.json b/www/addons/mod/assign/lang/zh-tw.json
index 94a6fc83415..674e767eebf 100644
--- a/www/addons/mod/assign/lang/zh-tw.json
+++ b/www/addons/mod/assign/lang/zh-tw.json
@@ -32,7 +32,7 @@
"errorshowinginformation": "我們無法顯示提交資訊",
"extensionduedate": "展延到期日",
"feedbacknotsupported": "該應用程式不支援此回饋, 並且可能不包含所有資訊",
- "grade": "分數",
+ "grade": "成績",
"graded": "已評分",
"gradedby": "已評分由",
"gradedon": "評分標準",
diff --git a/www/addons/mod/assign/lang/zh_cn.json b/www/addons/mod/assign/lang/zh_cn.json
deleted file mode 100644
index 59341a88ccf..00000000000
--- a/www/addons/mod/assign/lang/zh_cn.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "addsubmission": "添加提交",
- "allowsubmissionsfromdate": "开启时间",
- "attemptnumber": "作业提交次数",
- "cutoffdate": "提交截止时间",
- "duedate": "截止时间",
- "duedateno": "无截止时间",
- "submissions": "提交信息",
- "viewsubmission": "查看提交"
-}
\ No newline at end of file
diff --git a/www/addons/mod/assign/lang/zh_tw.json b/www/addons/mod/assign/lang/zh_tw.json
deleted file mode 100644
index 16a48d2186a..00000000000
--- a/www/addons/mod/assign/lang/zh_tw.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "addsubmission": "繳交作業",
- "allowsubmissionsfromdate": "開始繳交時間",
- "attemptnumber": "作業提交次數",
- "cutoffdate": "拒收作業時間",
- "duedate": "規定繳交時間",
- "duedateno": "沒有規定繳交時間",
- "submissions": "繳交",
- "viewsubmission": "檢視繳交的作業"
-}
\ No newline at end of file
diff --git a/www/addons/mod/assign/services/handlers.js b/www/addons/mod/assign/services/handlers.js
index 0dd88eac33b..818e81c48d3 100644
--- a/www/addons/mod/assign/services/handlers.js
+++ b/www/addons/mod/assign/services/handlers.js
@@ -21,7 +21,7 @@ angular.module('mm.addons.mod_assign')
* @ngdoc service
* @name $mmaModAssignHandlers
*/
-.factory('$mmaModAssignHandlers', function($mmCourse, $mmaModAssign, $state, $mmContentLinksHelper, $mmUtil, mmCoreDownloading,
+.factory('$mmaModAssignHandlers', function($mmCourse, $mmaModAssign, $state, $mmContentLinksHelper, $mmUtil, mmCoreDownloading, $q,
mmCoreNotDownloaded, mmCoreOutdated, $mmEvents, mmCoreEventPackageStatusChanged, $mmSite, mmaModAssignComponent,
$mmCoursePrefetchDelegate, $mmaModAssignPrefetchHandler, $mmaModAssignSync) {
var self = {};
@@ -102,9 +102,10 @@ angular.module('mm.addons.mod_assign')
// We need to call getDownloadSize, the package might have been updated.
$mmaModAssignPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModAssignPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModAssignPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/assign/submission/file/directive.js b/www/addons/mod/assign/submission/file/directive.js
index 5345298b55b..96ffcf8ade2 100644
--- a/www/addons/mod/assign/submission/file/directive.js
+++ b/www/addons/mod/assign/submission/file/directive.js
@@ -21,7 +21,7 @@ angular.module('mm.addons.mod_assign')
* @ngdoc directive
* @name mmaModAssignSubmissionFile
*/
-.directive('mmaModAssignSubmissionFile', function($mmaModAssign, $mmaModAssignSubmissionFileSession, $mmaModAssignHelper,
+.directive('mmaModAssignSubmissionFile', function($mmaModAssign, $mmFileSession, mmaModAssignComponent, $mmaModAssignHelper,
$mmaModAssignOffline, mmaModAssignSubmissionFileName, $mmFileUploaderHelper, $q) {
return {
restrict: 'A',
@@ -55,7 +55,7 @@ angular.module('mm.addons.mod_assign')
scope.files = $mmaModAssign.getSubmissionPluginAttachments(scope.plugin);
}
}).finally(function() {
- $mmaModAssignSubmissionFileSession.setFiles(scope.assign.id, scope.files);
+ $mmFileSession.setFiles(mmaModAssignComponent, scope.assign.id, scope.files);
});
}
};
diff --git a/www/addons/mod/assign/submission/file/handlers.js b/www/addons/mod/assign/submission/file/handlers.js
index a0eee0b82b9..3ef411ea46c 100644
--- a/www/addons/mod/assign/submission/file/handlers.js
+++ b/www/addons/mod/assign/submission/file/handlers.js
@@ -23,7 +23,7 @@ angular.module('mm.addons.mod_assign')
* @ngdoc service
* @name $mmaModAssignSubmissionFileHandler
*/
-.factory('$mmaModAssignSubmissionFileHandler', function($mmaModAssignSubmissionFileSession, $mmaModAssign, $mmSite, $q,
+.factory('$mmaModAssignSubmissionFileHandler', function($mmFileSession, mmaModAssignComponent, $mmaModAssign, $mmSite, $q,
$mmaModAssignHelper, $mmWS, $mmFS, $mmFilepool, $mmUtil, $mmaModAssignOffline, mmaModAssignSubmissionFileName,
$mmFileUploaderHelper) {
@@ -60,10 +60,10 @@ angular.module('mm.addons.mod_assign')
* @return {Void}
*/
self.clearTmpData = function(assign, submission, plugin, inputData) {
- var files = $mmaModAssignSubmissionFileSession.getFiles(assign.id);
+ var files = $mmFileSession.getFiles(mmaModAssignComponent, assign.id);
// Clear the files in session for this assign.
- $mmaModAssignSubmissionFileSession.clearFiles(assign.id);
+ $mmFileSession.clearFiles(mmaModAssignComponent, assign.id);
// Now delete the local files from the tmp folder.
$mmFileUploaderHelper.clearTmpFiles(files);
};
@@ -156,7 +156,7 @@ angular.module('mm.addons.mod_assign')
// Check if there's any change.
if (self.hasDataChanged(assign, submission, plugin, inputData)) {
- var files = $mmaModAssignSubmissionFileSession.getFiles(assign.id),
+ var files = $mmFileSession.getFiles(mmaModAssignComponent, assign.id),
totalSize = 0,
promises = [];
@@ -278,7 +278,7 @@ angular.module('mm.addons.mod_assign')
var pluginFiles = $mmaModAssign.getSubmissionPluginAttachments(plugin);
return pluginFiles && pluginFiles.length;
}).then(function(numFiles) {
- var currentFiles = $mmaModAssignSubmissionFileSession.getFiles(assign.id);
+ var currentFiles = $mmFileSession.getFiles(mmaModAssignComponent, assign.id);
if (currentFiles.length != numFiles) {
// Number of files has changed.
@@ -320,7 +320,7 @@ angular.module('mm.addons.mod_assign')
if (self.hasDataChanged(assign, submission, plugin, inputData)) {
// Data has changed, we need to upload new files and re-upload all the existing files.
- var currentFiles = $mmaModAssignSubmissionFileSession.getFiles(assign.id),
+ var currentFiles = $mmFileSession.getFiles(mmaModAssignComponent, assign.id),
error = $mmUtil.hasRepeatedFilenames(currentFiles);
if (error) {
diff --git a/www/addons/mod/assign/submission/file/session.js b/www/addons/mod/assign/submission/file/session.js
deleted file mode 100644
index cc29a18343a..00000000000
--- a/www/addons/mod/assign/submission/file/session.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// (C) Copyright 2015 Martin Dougiamas
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-angular.module('mm.addons.mod_assign')
-
-/**
- * Helper to store some temporary data for submission file.
- *
- * @module mm.addons.mod_assign
- * @ngdoc service
- * @name $mmaModAssignSubmissionFileSession
- */
-.factory('$mmaModAssignSubmissionFileSession', function($mmSite) {
-
- var self = {},
- files = {};
-
- /**
- * Add a file to the session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#addFile
- * @param {Number} assignmentId Assignment ID.
- * @param {Object} file File to add.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Void}
- */
- self.addFile = function(assignmentId, file, siteId) {
- siteId = siteId || $mmSite.getId();
-
- if (!files[siteId]) {
- files[siteId] = {};
- }
-
- if (!files[siteId][assignmentId]) {
- files[siteId][assignmentId] = [];
- }
-
- files[siteId][assignmentId].push(file);
- };
-
- /**
- * Clear files stored in session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#clearFiles
- * @param {Number} assignmentId Assignment ID.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Void}
- */
- self.clearFiles = function(assignmentId, siteId) {
- siteId = siteId || $mmSite.getId();
- if (files[siteId] && files[siteId][assignmentId]) {
- files[siteId][assignmentId] = [];
- }
- };
-
- /**
- * Get files stored in session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#getFiles
- * @param {Number} assignmentId Assignment ID.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Object[]} Files in session.
- */
- self.getFiles = function(assignmentId, siteId) {
- siteId = siteId || $mmSite.getId();
- if (files[siteId] && files[siteId][assignmentId]) {
- return files[siteId][assignmentId];
- }
- return [];
- };
-
- /**
- * Remove a file stored in session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#removeFile
- * @param {Number} assignmentId Assignment ID.
- * @param {Object} file File to remove. The instance should be exactly the same as the one stored in session.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Void}
- */
- self.removeFile = function(assignmentId, file, siteId) {
- siteId = siteId || $mmSite.getId();
- if (files[siteId] && files[siteId][assignmentId]) {
- var position = files[siteId][assignmentId].indexOf(file);
- if (position != -1) {
- files[siteId][assignmentId].splice(position, 1);
- }
- }
- };
-
- /**
- * Remove a file stored in session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#removeFileByIndex
- * @param {Number} assignmentId Assignment ID.
- * @param {Number} index Position of the file to remove.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Void}
- */
- self.removeFileByIndex = function(assignmentId, index, siteId) {
- siteId = siteId || $mmSite.getId();
- if (files[siteId] && files[siteId][assignmentId] && index >= 0 && index < files[siteId][assignmentId].length) {
- files[siteId][assignmentId].splice(index, 1);
- }
- };
-
- /**
- * Set a group of files in the session.
- *
- * @module mm.addons.mod_assign
- * @ngdoc method
- * @name $mmaModAssignSubmissionFileSession#setFiles
- * @param {Number} assignmentId Assignment ID.
- * @param {Object[]} newFiles Files to set.
- * @param {String} [siteId] Site ID. If not defined, current site.
- * @return {Void}
- */
- self.setFiles = function(assignmentId, newFiles, siteId) {
- siteId = siteId || $mmSite.getId();
-
- if (!files[siteId]) {
- files[siteId] = {};
- }
-
- files[siteId][assignmentId] = newFiles;
- };
-
- return self;
-});
diff --git a/www/addons/mod/book/controllers/index.js b/www/addons/mod/book/controllers/index.js
index 8ab97e48515..9677627c1d4 100644
--- a/www/addons/mod/book/controllers/index.js
+++ b/www/addons/mod/book/controllers/index.js
@@ -56,8 +56,8 @@ angular.module('mm.addons.mod_book')
$mmCourse.checkModuleCompletion(courseId, module.completionstatus);
}
});
- }).catch(function() {
- $mmUtil.showErrorModal('mma.mod_book.errorchapter', true);
+ }).catch(function(error) {
+ $mmUtil.showErrorModalDefault(error, 'mma.mod_book.errorchapter', true);
return $q.reject();
}).finally(function() {
$scope.loaded = true;
diff --git a/www/addons/mod/book/lang/es_mx.json b/www/addons/mod/book/lang/es_mx.json
deleted file mode 100644
index d5d45d924a2..00000000000
--- a/www/addons/mod/book/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "errorchapter": "Error al leer capítulo del libro."
-}
\ No newline at end of file
diff --git a/www/addons/mod/book/lang/pt_br.json b/www/addons/mod/book/lang/pt_br.json
deleted file mode 100644
index 4c5835d59ae..00000000000
--- a/www/addons/mod/book/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "errorchapter": "Erro ao ler capítulo de livro."
-}
\ No newline at end of file
diff --git a/www/addons/mod/book/lang/zh_cn.json b/www/addons/mod/book/lang/zh_cn.json
deleted file mode 100644
index 52b287ee7da..00000000000
--- a/www/addons/mod/book/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "errorchapter": "读取图书章节发生错误。"
-}
\ No newline at end of file
diff --git a/www/addons/mod/book/lang/zh_tw.json b/www/addons/mod/book/lang/zh_tw.json
deleted file mode 100644
index 32642d09bd0..00000000000
--- a/www/addons/mod/book/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "errorchapter": "讀取章節發生錯誤"
-}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/cs.json b/www/addons/mod/chat/lang/cs.json
index 5a2dbd232b7..a0e6fc3cd3b 100644
--- a/www/addons/mod/chat/lang/cs.json
+++ b/www/addons/mod/chat/lang/cs.json
@@ -14,6 +14,6 @@
"mustbeonlinetosendmessages": "Pro odesílání zpráv musíte být online",
"nomessages": "Zatím žádné zprávy",
"send": "Odeslat",
- "sessionstart": "Další chatování začne v {{$a}}, (za {{$a.fromnow}})",
+ "sessionstart": "Další chatování začne v: {{$a.date}} (tj. za {{$a.fromnow}})",
"talk": "Diskuse"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/de.json b/www/addons/mod/chat/lang/de.json
index 9f7bc7161e6..77a921dd9cc 100644
--- a/www/addons/mod/chat/lang/de.json
+++ b/www/addons/mod/chat/lang/de.json
@@ -14,6 +14,6 @@
"mustbeonlinetosendmessages": "Sie müssen online sein, um Mitteilungen zu senden",
"nomessages": "Keine Mitteilungen",
"send": "Senden",
- "sessionstart": "Nächster Chat beginnt am {{$a.date}}. ({{$a.fromnow}} von jetzt)",
+ "sessionstart": "Nächster Chat beginnt {{$a.date}}, (also in {{$a.fromnow}})",
"talk": "Sprechen"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/es_mx.json b/www/addons/mod/chat/lang/es_mx.json
deleted file mode 100644
index d3e0fbd4d66..00000000000
--- a/www/addons/mod/chat/lang/es_mx.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "beep": "Bip",
- "currentusers": "Usuarios",
- "enterchat": "Entrar a la sala",
- "entermessage": "Escriba su mensaje",
- "messagebeepsyou": "{{$a}} le acaba de enviar un beep",
- "messageenter": "{{$a}} entró a la sala",
- "messageexit": "{{$a}} salió de la sala",
- "nomessages": "Aún no hay mensajes",
- "send": "Enviar",
- "sessionstart": "La siguiente sesión de chat comenzará en: {{$a}}",
- "talk": "Charla"
-}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/he.json b/www/addons/mod/chat/lang/he.json
index 8cd72c5f92d..129855c2b7c 100644
--- a/www/addons/mod/chat/lang/he.json
+++ b/www/addons/mod/chat/lang/he.json
@@ -10,6 +10,6 @@
"mustbeonlinetosendmessages": "עליך להיות מחובר בכדי לשלוח הודעות.",
"nomessages": "אין הודעות עדיין",
"send": "שליחה",
- "sessionstart": "מפגש הרב-שיח הבא יתחיל ב: {{$a}}",
+ "sessionstart": "מפגש הרב-שיח הבא יתחיל ב: {{$a.date}}, ({{$a.fromnow}} מעכשיו)",
"talk": "דברו"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/ja.json b/www/addons/mod/chat/lang/ja.json
index 052232c43bf..37dd5b0164d 100644
--- a/www/addons/mod/chat/lang/ja.json
+++ b/www/addons/mod/chat/lang/ja.json
@@ -3,10 +3,15 @@
"currentusers": "現在のユーザ",
"enterchat": "ここをクリックしてチャットルームに入室する",
"entermessage": "あなたのメッセージを入力してください。",
- "errorwhilesendingmessage": "メッセージの送信中にエラーが発生しました。後で再度お試しください。",
+ "errorwhileconnecting": "チャットに接続する際にエラーが発生しました。",
+ "errorwhilegettingchatdata": "チャットのデータを取得中にエラーが発生しました。",
+ "errorwhilegettingchatusers": "チャットのユーザを取得中にエラーが発生しました。",
+ "errorwhileretrievingmessages": "サーバからメッセージを取得中にエラーが発生しました。",
+ "errorwhilesendingmessage": "メッセージ送信中にエラーが発生しました。",
"messagebeepsyou": "{{$a}} があなたにビープしました!",
"messageenter": "このチャットに {{$a}} が入室しました。",
"messageexit": "このチャットから {{$a}} が退室しました。",
+ "mustbeonlinetosendmessages": "メッセージを送信するにはオンラインでなければなりません。",
"nomessages": "メッセージがありません。",
"send": "送信",
"sessionstart": "次のチャットセッションは {{$a.date}} に開始されます (現在から {{$a.fromnow}} 後)。",
diff --git a/www/addons/mod/chat/lang/lt.json b/www/addons/mod/chat/lang/lt.json
index 0eb4caa16f1..b71c2b82006 100644
--- a/www/addons/mod/chat/lang/lt.json
+++ b/www/addons/mod/chat/lang/lt.json
@@ -14,6 +14,6 @@
"mustbeonlinetosendmessages": "Norėdamas išsiųsti žinutę, turite būti prisijungęs.",
"nomessages": "Žinučių dar nėra",
"send": "Siųsti",
- "sessionstart": "Pokalbio seansas bus pradėtas po: {{$a}}",
+ "sessionstart": "Kitas pokalbio seansas prasidės {{$a.date}}, ({{$a.fromnow}} nuo dabar)",
"talk": "Kalbėti"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/pl.json b/www/addons/mod/chat/lang/pl.json
index b1a54b073ef..f8fbf09ec3f 100644
--- a/www/addons/mod/chat/lang/pl.json
+++ b/www/addons/mod/chat/lang/pl.json
@@ -9,6 +9,6 @@
"messageexit": "{{$a}} opuścił czat",
"nomessages": "Brak wiadomości",
"send": "Wyślij",
- "sessionstart": "Sesja czatu rozpocznie się za: {$ a}}",
+ "sessionstart": "Sesja czatu rozpocznie się {{$a.date}}, za ({{$a.fromnow}}",
"talk": "Dyskusja"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/pt-br.json b/www/addons/mod/chat/lang/pt-br.json
index 474fea465ec..eca3a53a9e6 100644
--- a/www/addons/mod/chat/lang/pt-br.json
+++ b/www/addons/mod/chat/lang/pt-br.json
@@ -14,6 +14,6 @@
"mustbeonlinetosendmessages": "Você deve estar online para enviar mensagens",
"nomessages": "Nenhuma mensagem ainda",
"send": "Enviar",
- "sessionstart": "A próxima sessão de chat irá começar em {{$a}}",
+ "sessionstart": "A próxima sessão de chat irá começar em {{$a.date}}, ({{$a.fromnow}} a partir de agora)",
"talk": "Falar"
}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/pt_br.json b/www/addons/mod/chat/lang/pt_br.json
deleted file mode 100644
index af36af4277c..00000000000
--- a/www/addons/mod/chat/lang/pt_br.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "beep": "Bip",
- "currentusers": "Usuários atuais",
- "enterchat": "Clique aqui para entrar no chat agora",
- "entermessage": "Digite sua mensagem",
- "messagebeepsyou": "{{$a}} está bipando você!",
- "messageenter": "{{$a}} entrou no chat",
- "messageexit": "{{$a}} abandonou este chat",
- "nomessages": "Nenhuma mensagem ainda",
- "send": "Enviar",
- "sessionstart": "A próxima sessão de chat irá começar em {{$a}}",
- "talk": "Falar"
-}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/sr-cr.json b/www/addons/mod/chat/lang/sr-cr.json
new file mode 100644
index 00000000000..be3c293d91c
--- /dev/null
+++ b/www/addons/mod/chat/lang/sr-cr.json
@@ -0,0 +1,19 @@
+{
+ "beep": "Звучни сигнал",
+ "currentusers": "Тренутни корисници",
+ "enterchat": "Кликните овде за улазак у причаоницу",
+ "entermessage": "Унесите вашу поруку",
+ "errorwhileconnecting": "Грешка приликом повезивања са причаоницом.",
+ "errorwhilegettingchatdata": "Грешка приликом преузимања података за 'Причаоницу'.",
+ "errorwhilegettingchatusers": "Грешка приликом преузимања корисника причаонице.",
+ "errorwhileretrievingmessages": "Грешка приликом преузимања порука са сервера.",
+ "errorwhilesendingmessage": "Грешка приликом слања поруке.",
+ "messagebeepsyou": "{{$a}} вас је управо поздравио/ла звучним сигналом!",
+ "messageenter": "Учесник {{$a}} управо улази у причаоницу",
+ "messageexit": "Учесник {{$a}} управо напушта причаоницу",
+ "mustbeonlinetosendmessages": "Морате бити онлајн како бисте слали поруке.",
+ "nomessages": "Још нема порука",
+ "send": "Пошаљи",
+ "sessionstart": "Следећа сесија ће почети дана {{$a.date}}, ({{$a.fromnow}} од сада)",
+ "talk": "Причај"
+}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/sr-lt.json b/www/addons/mod/chat/lang/sr-lt.json
new file mode 100644
index 00000000000..dca8b6cbd39
--- /dev/null
+++ b/www/addons/mod/chat/lang/sr-lt.json
@@ -0,0 +1,19 @@
+{
+ "beep": "Zvučni signal",
+ "currentusers": "Trenutni korisnici",
+ "enterchat": "Kliknite ovde za ulazak u pričaonicu",
+ "entermessage": "Unesite vašu poruku",
+ "errorwhileconnecting": "Greška prilikom povezivanja sa pričaonicom.",
+ "errorwhilegettingchatdata": "Greška prilikom preuzimanja podataka za 'Pričaonicu'.",
+ "errorwhilegettingchatusers": "Greška prilikom preuzimanja korisnika pričaonice.",
+ "errorwhileretrievingmessages": "Greška prilikom preuzimanja poruka sa servera.",
+ "errorwhilesendingmessage": "Greška prilikom slanja poruke.",
+ "messagebeepsyou": "{{$a}} vas je upravo pozdravio/la zvučnim signalom!",
+ "messageenter": "Učesnik {{$a}} upravo ulazi u pričaonicu",
+ "messageexit": "Učesnik {{$a}} upravo napušta pričaonicu",
+ "mustbeonlinetosendmessages": "Morate biti onlajn kako biste slali poruke.",
+ "nomessages": "Još nema poruka",
+ "send": "Pošalji",
+ "sessionstart": "Sledeća sesija će početi dana {{$a.date}}, ({{$a.fromnow}} od sada)",
+ "talk": "Pričaj"
+}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/sv.json b/www/addons/mod/chat/lang/sv.json
index cc26779e559..d5a2d85343a 100644
--- a/www/addons/mod/chat/lang/sv.json
+++ b/www/addons/mod/chat/lang/sv.json
@@ -1,14 +1,14 @@
{
- "beep": "pipsignal",
+ "beep": "Pipsignal",
"currentusers": "Aktuella användare",
"enterchat": "Klicka här för att gå in i direktsamtalet nu",
- "entermessage": "Sriv ditt meddelande",
+ "entermessage": "Skriv ditt meddelande",
"errorwhileconnecting": "Fel vid anslutning till chatten",
"errorwhilegettingchatdata": "Fel vid vid hämtning av chattdata",
"errorwhilegettingchatusers": "Fel vid vid hämtning av chattanvändare",
"errorwhileretrievingmessages": "Fel vid hämtning av meddelanden från servern",
"errorwhilesendingmessage": "Fel när meddelandet skickades",
- "messagebeepsyou": "{{$a}} har just skickat en pipsignal till Dig",
+ "messagebeepsyou": "{{$a}} har just skickat en pipsignal till dig",
"messageenter": "{{$a}} har precis kommit in i detta direktsamtal",
"messageexit": "{{$a}} har lämnat det här direktsamtalet",
"mustbeonlinetosendmessages": "Du måste vara online för att skicka meddelanden",
diff --git a/www/addons/mod/chat/lang/uk.json b/www/addons/mod/chat/lang/uk.json
index 66503297072..ab756410d89 100644
--- a/www/addons/mod/chat/lang/uk.json
+++ b/www/addons/mod/chat/lang/uk.json
@@ -6,8 +6,8 @@
"errorwhileconnecting": "Помилка при підключенні до чату.",
"errorwhilegettingchatdata": "Помилка отримання даних чату.",
"errorwhilegettingchatusers": "Помилка отримання користувачів чату.",
- "errorwhileretrievingmessages": "Помилка отримання повідомлень з серверу",
- "errorwhilesendingmessage": "Помилка відправки повідомлення",
+ "errorwhileretrievingmessages": "Помилка отримання повідомлень з серверу.",
+ "errorwhilesendingmessage": "Помилка відправки повідомлення.",
"messagebeepsyou": "{{$a}} відправив Вам сигнал!",
"messageenter": "{{$a}} з'явився в чаті",
"messageexit": "{{$a}} пішов із чату",
diff --git a/www/addons/mod/chat/lang/zh_cn.json b/www/addons/mod/chat/lang/zh_cn.json
deleted file mode 100644
index b8c1f9af432..00000000000
--- a/www/addons/mod/chat/lang/zh_cn.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "beep": "呼叫",
- "currentusers": "当前用户",
- "enterchat": "进入聊天室",
- "entermessage": "输入您的信息",
- "messagebeepsyou": "{{$a}}刚刚呼叫您!",
- "messageenter": "{{$a}}刚刚进入聊天室",
- "messageexit": "{{$a}}已退出聊天室",
- "nomessages": "无消息",
- "send": "发送",
- "sessionstart": "聊天会话开始时间:{{$a}}",
- "talk": "交谈"
-}
\ No newline at end of file
diff --git a/www/addons/mod/chat/lang/zh_tw.json b/www/addons/mod/chat/lang/zh_tw.json
deleted file mode 100644
index 511cfbb8352..00000000000
--- a/www/addons/mod/chat/lang/zh_tw.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "beep": "呼叫",
- "currentusers": "當前用戶",
- "enterchat": "點選這裡進入聊天室",
- "entermessage": "輸入您的訊息",
- "messagebeepsyou": "{{$a}} 呼叫您",
- "messageenter": "{{$a}} 剛加入這次聊天",
- "messageexit": "{{$a}} 已退出這次聊天",
- "nomessages": "尚無訊息",
- "send": "傳送",
- "sessionstart": "下一個對話時段將開始於:{{$a}}",
- "talk": "交談"
-}
\ No newline at end of file
diff --git a/www/addons/mod/choice/lang/ar.json b/www/addons/mod/choice/lang/ar.json
index 60ff70d91f6..507d25fbe0c 100644
--- a/www/addons/mod/choice/lang/ar.json
+++ b/www/addons/mod/choice/lang/ar.json
@@ -4,7 +4,7 @@
"full": "(كامل)",
"noresultsviewable": "حالياً لا يمكن معاينة النتائج",
"notopenyet": "عذرا، هذا النشاط سيكون متوفر في {{$a}}",
- "numberofuser": "عدد المستخدمين",
+ "numberofuser": "عدد المشاركين",
"numberofuserinpercentage": "عدد المستخدمين كنسبة",
"removemychoice": "استبعد خياري",
"responses": "إجابات",
diff --git a/www/addons/mod/choice/lang/ca.json b/www/addons/mod/choice/lang/ca.json
index fc6af3e2e89..c0a93b72130 100644
--- a/www/addons/mod/choice/lang/ca.json
+++ b/www/addons/mod/choice/lang/ca.json
@@ -6,8 +6,8 @@
"full": "(Complet)",
"noresultsviewable": "A hores d'ara no es poden veure els resultats",
"notopenyet": "Aquesta activitat no estarà disponible fins al dia {{$a}}",
- "numberofuser": "Nombre de participants",
- "numberofuserinpercentage": "Percentatge de participants",
+ "numberofuser": "Nombre de respostes",
+ "numberofuserinpercentage": "Percentatge de respostes (%)",
"previewonly": "Això és sols una vista prèvia de les opcions disponibles en aquesta activitat. No esteu habilitat per enviar consultes fins {{$a}}.",
"removemychoice": "Suprimeix la meva resposta",
"responses": "Respostes",
diff --git a/www/addons/mod/choice/lang/da.json b/www/addons/mod/choice/lang/da.json
index e462afcd51a..3ef6b107e4d 100644
--- a/www/addons/mod/choice/lang/da.json
+++ b/www/addons/mod/choice/lang/da.json
@@ -6,8 +6,8 @@
"full": "(Fuld)",
"noresultsviewable": "Resultaterne er ikke tilgængelige på nuværende tidspunkt.",
"notopenyet": "Denne aktivitet er tilgængelig fra {{$a}}",
- "numberofuser": "Antal svar",
- "numberofuserinpercentage": "Antal svar i procent",
+ "numberofuser": "Antal deltagere",
+ "numberofuserinpercentage": "Procentdel af deltagerne",
"previewonly": "Dette er en forhåndsvisning af de tilgængelige valgmuligheder i denne afstemning. Du kan ikke indsende dine valg før {{$a}}.",
"removemychoice": "Slet mit valg",
"responses": "Besvarelser",
diff --git a/www/addons/mod/choice/lang/es-mx.json b/www/addons/mod/choice/lang/es-mx.json
index 41b15bb932f..ceddb82adc6 100644
--- a/www/addons/mod/choice/lang/es-mx.json
+++ b/www/addons/mod/choice/lang/es-mx.json
@@ -6,8 +6,8 @@
"full": "(Lleno)",
"noresultsviewable": "Los resultados no pueden verse en este momento.",
"notopenyet": "Lo sentimos, esta actividad no estará disponible hasta {{$a}}",
- "numberofuser": "Número de participantes",
- "numberofuserinpercentage": "Porcentaje de participantes",
+ "numberofuser": "Número de respuestas",
+ "numberofuserinpercentage": "Porcentaje de respuestas",
"previewonly": "Esto es solamente una vista previa de las opciones disponibles para esta actividad. Usted no podrá enviar su elección hasta {{$a}}.",
"removemychoice": "Eliminar mi elección",
"responses": "Respuestas",
diff --git a/www/addons/mod/choice/lang/ja.json b/www/addons/mod/choice/lang/ja.json
index 02afe740bcd..5f5b78343c7 100644
--- a/www/addons/mod/choice/lang/ja.json
+++ b/www/addons/mod/choice/lang/ja.json
@@ -1,16 +1,19 @@
{
"cannotsubmit": "申し訳ございません、あなたの投票送信時に問題が発生しました。再度お試しください。",
"choiceoptions": "投票オプション",
+ "errorgetchoice": "選択データの取得中にエラーが発生しました。",
"expired": "申し訳ございません、この活動は {{$a}} に終了しているため、これ以上利用することはできません。",
"full": "(上限到達)",
"noresultsviewable": "現在、投票結果は閲覧できません。",
"notopenyet": "申し訳ございません、この活動は {{$a}} まで利用することができません。",
- "numberofuser": "投票者数",
- "numberofuserinpercentage": "投票者数 (%)",
+ "numberofuser": "参加者数",
+ "numberofuserinpercentage": "参加者の割合",
"previewonly": "これはこの活動で利用可能なオプションのプレビューです。あなたの投票は {{$a}} まで送信することができません。",
"removemychoice": "私の投票を削除する",
"responses": "投票結果",
+ "responsesresultgraphdescription": "{{number}}% のユーザが選択肢: {{text}} を選択しました。",
"responsesresultgraphheader": "グラフ表示",
+ "resultsnotsynced": "結果にあなたの最後のレスポンスが含まれていません。更新のため、同期を行ってください。",
"savemychoice": "私の投票を保存する",
"userchoosethisoption": "このオプションを選択したユーザ",
"yourselection": "あなたの投票"
diff --git a/www/addons/mod/choice/lang/lt.json b/www/addons/mod/choice/lang/lt.json
index 94e682f5d51..ee1bf2c25c3 100644
--- a/www/addons/mod/choice/lang/lt.json
+++ b/www/addons/mod/choice/lang/lt.json
@@ -6,8 +6,8 @@
"full": "(Visas)",
"noresultsviewable": "Rezultatai dabar nematomi.",
"notopenyet": "Apgailestaujame, ši veikla negalima iki {{$a}}",
- "numberofuser": "Dalyvių skaičius",
- "numberofuserinpercentage": "Dalyvių procentas",
+ "numberofuser": "Atsakymų skaičius",
+ "numberofuserinpercentage": "Atsakymų procentas",
"previewonly": "Tai yra tik šios veiklos galimų variantų peržiūra. Savo pasirinkimo negalėsite pateikti iki {{$a}}.",
"removemychoice": "Pašalinti mano pasirinkimą",
"responses": "Atsakymai",
diff --git a/www/addons/mod/choice/lang/pt-br.json b/www/addons/mod/choice/lang/pt-br.json
index f8fbe81990b..e1220130458 100644
--- a/www/addons/mod/choice/lang/pt-br.json
+++ b/www/addons/mod/choice/lang/pt-br.json
@@ -6,8 +6,8 @@
"full": "(Cheio)",
"noresultsviewable": "Não é possível visualizar os resultados neste momento.",
"notopenyet": "Esta atividade será acessível a partir de {{$a}}",
- "numberofuser": "Número de participantes",
- "numberofuserinpercentage": "Porcentagem de participantes",
+ "numberofuser": "Número de respostas",
+ "numberofuserinpercentage": "Percentagem de respostas",
"previewonly": "Esta é somente uma previsualização das opções dessa atividade. Você somente poderá enviar sua escolha a partir de {{$a}}",
"removemychoice": "Remover a minha resposta",
"responses": "Respostas",
diff --git a/www/addons/mod/choice/lang/pt.json b/www/addons/mod/choice/lang/pt.json
index a5b426bc80b..68e628591c5 100644
--- a/www/addons/mod/choice/lang/pt.json
+++ b/www/addons/mod/choice/lang/pt.json
@@ -6,8 +6,8 @@
"full": "Completa",
"noresultsviewable": "Os resultados da sondagem ainda não estão disponíveis.",
"notopenyet": "Lamentamos mas esta atividade só estará disponível em {{$a}}",
- "numberofuser": "Número de participantes",
- "numberofuserinpercentage": "Percentagem de participantes",
+ "numberofuser": "Número de respostas",
+ "numberofuserinpercentage": "Percentagem de respostas",
"previewonly": "Esta é apenas uma pré-visualização das opções disponíveis para esta atividade. Não poderá submeter a sua escolha até {{$a}}.",
"removemychoice": "Apagar a minha resposta",
"responses": "Respostas",
diff --git a/www/addons/mod/choice/lang/ro.json b/www/addons/mod/choice/lang/ro.json
index eb9c1bc300b..2133b57b951 100644
--- a/www/addons/mod/choice/lang/ro.json
+++ b/www/addons/mod/choice/lang/ro.json
@@ -4,8 +4,8 @@
"full": "(plin)",
"noresultsviewable": "În acest moment rezultatele nu pot fi vizualizate.",
"notopenyet": "Ne pare rău, această activitate nu este disponibilă mai devreme de {{$a}}",
- "numberofuser": "Numărul participanților",
- "numberofuserinpercentage": "Procentul participanților",
+ "numberofuser": "Numărul de răspunsuri",
+ "numberofuserinpercentage": "Procentajul răspunsurilor",
"previewonly": "Acesta este doar o prezentare a opțiunilor existente pentru această activitate. Nu veți putea trimite opțiunea dvs. până la {{$a}}.",
"removemychoice": "Șterge alegerea mea",
"responses": "Răspunsuri",
diff --git a/www/addons/mod/choice/lang/ru.json b/www/addons/mod/choice/lang/ru.json
index a8b13940e57..38f9cf75ee3 100644
--- a/www/addons/mod/choice/lang/ru.json
+++ b/www/addons/mod/choice/lang/ru.json
@@ -2,7 +2,7 @@
"cannotsubmit": "Извините, возникла проблема при отправке Вашего ответа на опрос. Пожалуйста, повторите снова.",
"choiceoptions": "Варианты ответа",
"errorgetchoice": "Ошибка при получении данных выбора",
- "expired": "Извините эта активность закрыта {{$a}} и более недоступна",
+ "expired": "Извините, этот элемент курса закрыт {{$a}} и более недоступен",
"full": "(Заполнено)",
"noresultsviewable": "Вы не можете в данный момент просматривать результаты опроса.",
"notopenyet": "Извините, данное действие недоступно до {{$a}}",
diff --git a/www/addons/mod/choice/lang/sr-cr.json b/www/addons/mod/choice/lang/sr-cr.json
new file mode 100644
index 00000000000..10465df2265
--- /dev/null
+++ b/www/addons/mod/choice/lang/sr-cr.json
@@ -0,0 +1,20 @@
+{
+ "cannotsubmit": "Извините, дошло је до проблема приликом чувања одабраног одговора. Молимо покушајте поново.",
+ "choiceoptions": "Опције за избор",
+ "errorgetchoice": "Грешка приликом преузимања података за 'Избор'",
+ "expired": "Нажалост, ова активност је затворена дана {{$a}} и није више доступна",
+ "full": "(Попуњено)",
+ "noresultsviewable": "Резултати тренутно нису видљиви.",
+ "notopenyet": "Нажалост, ова активност није доступна до {{$a}}",
+ "numberofuser": "Број учесника",
+ "numberofuserinpercentage": "Проценат учесника",
+ "previewonly": "Ово је само приказ доступних опција за ову активност. Нећете бити у могућности да извршите одабир до {{$a}}.",
+ "removemychoice": "Уклони мој избор",
+ "responses": "Одговори",
+ "responsesresultgraphdescription": "{{number}}% корисника је изабрало опцију: {{text}}.",
+ "responsesresultgraphheader": "Графички приказ",
+ "resultsnotsynced": "Резултати не укључује ваш последњи одговор. Покрените синхронизацију како бисте их ажурирали.",
+ "savemychoice": "Сачувај мој избор",
+ "userchoosethisoption": "Корисници који су изабрали ову опцију",
+ "yourselection": "Ваш избор"
+}
\ No newline at end of file
diff --git a/www/addons/mod/choice/lang/sr-lt.json b/www/addons/mod/choice/lang/sr-lt.json
new file mode 100644
index 00000000000..7fc4232b84d
--- /dev/null
+++ b/www/addons/mod/choice/lang/sr-lt.json
@@ -0,0 +1,20 @@
+{
+ "cannotsubmit": "Izvinite, došlo je do problema prilikom čuvanja odabranog odgovora. Molimo pokušajte ponovo.",
+ "choiceoptions": "Opcije za izbor",
+ "errorgetchoice": "Greška prilikom preuzimanja podataka za 'Izbor'",
+ "expired": "Nažalost, ova aktivnost je zatvorena dana {{$a}} i nije više dostupna",
+ "full": "(Popunjeno)",
+ "noresultsviewable": "Rezultati trenutno nisu vidljivi.",
+ "notopenyet": "Nažalost, ova aktivnost nije dostupna do {{$a}}",
+ "numberofuser": "Broj učesnika",
+ "numberofuserinpercentage": "Procenat učesnika",
+ "previewonly": "Ovo je samo prikaz dostupnih opcija za ovu aktivnost. Nećete biti u mogućnosti da izvršite odabir do {{$a}}.",
+ "removemychoice": "Ukloni moj izbor",
+ "responses": "Odgovori",
+ "responsesresultgraphdescription": "{{number}}% korisnika je izabralo opciju: {{text}}.",
+ "responsesresultgraphheader": "Grafički prikaz",
+ "resultsnotsynced": "Rezultati ne uključuje vaš poslednji odgovor. Pokrenite sinhronizaciju kako biste ih ažurirali.",
+ "savemychoice": "Sačuvaj moj izbor",
+ "userchoosethisoption": "Korisnici koji su izabrali ovu opciju",
+ "yourselection": "Vaš izbor"
+}
\ No newline at end of file
diff --git a/www/addons/mod/choice/lang/sv.json b/www/addons/mod/choice/lang/sv.json
index 62217bdb227..9b79b1cc765 100644
--- a/www/addons/mod/choice/lang/sv.json
+++ b/www/addons/mod/choice/lang/sv.json
@@ -14,6 +14,6 @@
"responsesresultgraphdescription": "{{number}}% Av användarna valde alternativet: {{text}}",
"responsesresultgraphheader": "Visa en graf",
"savemychoice": "Spara min opinionsundersökning",
- "userchoosethisoption": "Användaren väljer detta alternativ",
+ "userchoosethisoption": "Användare som valt detta alternativ",
"yourselection": "Ditt urval"
}
\ No newline at end of file
diff --git a/www/addons/mod/choice/lang/uk.json b/www/addons/mod/choice/lang/uk.json
index 3587cc22f86..7c22b1890c7 100644
--- a/www/addons/mod/choice/lang/uk.json
+++ b/www/addons/mod/choice/lang/uk.json
@@ -1,7 +1,7 @@
{
"cannotsubmit": "Вибачте, але трапилася проблема під час збереження вашого вибору. Повторіть, будь ласка, ще раз.",
"choiceoptions": "Параметри вибору",
- "errorgetchoice": "Помилка при отриманні даних вибору.",
+ "errorgetchoice": "Помилка при отриманні даних виборки.",
"expired": "На жаль, ця діяльність закрита для {{$a}} та більше недоступна",
"full": "(Все)",
"noresultsviewable": "В даний час результати не можна побачити.",
diff --git a/www/addons/mod/choice/lang/zh-tw.json b/www/addons/mod/choice/lang/zh-tw.json
index fd45e3f3362..c97305fd6fa 100644
--- a/www/addons/mod/choice/lang/zh-tw.json
+++ b/www/addons/mod/choice/lang/zh-tw.json
@@ -6,8 +6,8 @@
"full": "(已滿)",
"noresultsviewable": "目前無法檢視票選結果",
"notopenyet": "抱歉,這個活動在{{$a}}之前不能使用",
- "numberofuser": "參與者人數",
- "numberofuserinpercentage": "參與者百分比",
+ "numberofuser": "回應的人數",
+ "numberofuserinpercentage": "回應人數的百分比",
"previewonly": "這只是這一活動的可用選項的預覽。你要等到{{$a}}才可以進行投票。",
"removemychoice": "移除我的選擇",
"responses": "答覆",
diff --git a/www/addons/mod/choice/services/handlers.js b/www/addons/mod/choice/services/handlers.js
index 4d9145c5d7f..96c13d47b93 100644
--- a/www/addons/mod/choice/services/handlers.js
+++ b/www/addons/mod/choice/services/handlers.js
@@ -21,7 +21,7 @@ angular.module('mm.addons.mod_choice')
* @ngdoc service
* @name $mmaModChoiceHandlers
*/
-.factory('$mmaModChoiceHandlers', function($mmCourse, $mmaModChoice, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite,
+.factory('$mmaModChoiceHandlers', function($mmCourse, $mmaModChoice, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, $q,
$mmaModChoicePrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated,
mmaModChoiceComponent, mmCoreEventPackageStatusChanged, mmCoreDownloaded, $mmaModChoiceSync) {
var self = {};
@@ -103,9 +103,10 @@ angular.module('mm.addons.mod_choice')
// Get download size to ask for confirm if it's high.
$mmaModChoicePrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModChoicePrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModChoicePrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/data/controllers/edit.js b/www/addons/mod/data/controllers/edit.js
new file mode 100644
index 00000000000..90bec456681
--- /dev/null
+++ b/www/addons/mod/data/controllers/edit.js
@@ -0,0 +1,252 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Data add and edit controller.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc controller
+ * @name mmaModDataEditCtrl
+ */
+.controller('mmaModDataEditCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $q, $mmUtil, $mmaModDataHelper,
+ $mmGroups, $ionicHistory, $mmEvents, mmaModDataEventEntryChanged, $mmSite, $translate, $mmFileUploaderHelper, $timeout,
+ $ionicScrollDelegate, $mmApp, $mmaModDataOffline) {
+
+ var module = $stateParams.module || {},
+ courseId = $stateParams.courseid,
+ data,
+ scrollView,
+ offlineActions,
+ siteId = $mmSite.getId(),
+ offline = !$mmApp.isOnline(),
+ entryId = $stateParams.entryid || false,
+ entry;
+
+ $scope.title = module.name;
+ $scope.component = mmaModDataComponent;
+ $scope.databaseLoaded = false;
+ $scope.selectedGroup = $stateParams.group || 0;
+
+ // Block leaving the view, we want to show a confirm to the user if there's unsaved data.
+ $mmUtil.blockLeaveView($scope, cancel);
+
+ function fetchEntryData() {
+
+ return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) {
+ data = databaseData;
+
+ $scope.title = data.name || $scope.title;
+ $scope.data = databaseData;
+
+ return $mmaModData.getDatabaseAccessInformation(data.id);
+ }).then(function(accessData) {
+ $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id);
+
+ if (entryId !== false) {
+ // Adding, get groups because it's not set.
+ return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) {
+ $scope.groupInfo = groupInfo;
+
+ // Check selected group is accessible.
+ if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) {
+ var found = false;
+ for (var x in groupInfo.groups) {
+ if (groupInfo.groups[x].id == $scope.selectedGroup) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ $scope.selectedGroup = groupInfo.groups[0].id;
+ }
+ }
+ });
+ }
+ }).then(function() {
+ return $mmaModDataOffline.getEntryActions(data.id, entryId);
+ }).then(function(actions) {
+ offlineActions = actions;
+
+ return $mmaModData.getFields(data.id);
+ }).then(function(fieldsData) {
+ $scope.fields = {};
+ angular.forEach(fieldsData, function(field) {
+ $scope.fields[field.id] = field;
+ });
+
+ return $mmaModDataHelper.getEntry(data, entryId, offlineActions);
+ }).then(function(entryData) {
+ if (entryData) {
+ entry = entryData.entry;
+
+ // Index contents by fieldid.
+ var contents = {};
+ angular.forEach(entry.contents, function(field) {
+ contents[field.fieldid] = field;
+ });
+ entry.contents = contents;
+ } else {
+ entry = {};
+ entry.contents = {};
+ }
+
+ return $mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields);
+ }).then(function(entryData) {
+ $scope.entry = entryData;
+
+ $scope.editForm = $mmaModDataHelper.displayEditFields(data.addtemplate, $scope.fields, entry.contents);
+ }).catch(function(message) {
+ $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ }).finally(function() {
+ $scope.databaseLoaded = true;
+ });
+ }
+
+ // Set group to see the database.
+ $scope.setGroup = function(groupId) {
+ $scope.selectedGroup = groupId;
+ $scope.databaseLoaded = false;
+
+ return fetchEntryData();
+ };
+
+ // Saves data.
+ $scope.save = function() {
+ return $mmaModDataHelper.hasEditDataChanged(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ $scope.entry.contents).then(function(changed) {
+
+ if (!changed) {
+ if (entryId) {
+ return returnToEntryList();
+ } else {
+ // New entry, no changes means no field filled, warn the user.
+ return $q.reject('mma.mod_data.emptyaddform');
+ }
+ }
+
+ var modal = $mmUtil.showModalLoading('mm.core.sending', true);
+
+ // Create an ID to assign files.
+ var entryTemp = entryId;
+ if (typeof entryId == "undefined" || entryId === false) {
+ entryTemp = - (new Date().getTime());
+ }
+
+ return $mmaModDataHelper.getEditDataFromForm(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ entryTemp, $scope.entry.contents, offline).catch(function(e) {
+ if (!offline) {
+ // Cannot submit in online, prepare for offline usage.
+ offline = true;
+
+ return $mmaModDataHelper.getEditDataFromForm(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ entryTemp, $scope.entry.contents, offline);
+ }
+
+ return $q.reject(e);
+ }).then(function(editData) {
+
+ if (editData.length > 0) {
+ if (entryId !== false) {
+ return $mmaModData.editEntry(data.id, entryId, courseId, editData, $scope.fields, undefined, offline);
+ }
+ return $mmaModData.addEntry(data.id, entryTemp, courseId, editData, $scope.selectedGroup, $scope.fields, undefined,
+ offline);
+ }
+ }).then(function(result) {
+ if (!result) {
+ // No field filled, warn the user.
+ return $q.reject('mma.mod_data.emptyaddform');
+ }
+
+ // This is done if entry is updated when editing or creating if not.
+ if ((entryId !== false && result.updated) || (!entryId && result.newentryid)) {
+ var promises = [];
+
+ entryId = entryId || result.newentryid;
+
+ promises.push($mmaModData.invalidateEntryData(data.id, entryId, siteId));
+ promises.push($mmaModData.invalidateEntriesData(data.id, siteId));
+
+ return $q.all(promises).then(function() {
+ $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: data.id, entryId: entryId, siteId: siteId});
+ }).finally(function() {
+ return returnToEntryList();
+ });
+ } else {
+ $scope.errors = {};
+ angular.forEach(result.fieldnotifications, function(field) {
+ for (var x in $scope.fields) {
+ if ($scope.fields[x].name == field.fieldname) {
+ $scope.errors[$scope.fields[x].id] = field.notification;
+ return;
+ }
+ }
+ });
+ $timeout(function() {
+ scrollToFirstError();
+ });
+ }
+ }).finally(function() {
+ modal.dismiss();
+ });
+ }).catch(function(error) {
+ $mmUtil.showErrorModalDefault(error, 'Cannot edit entry', true);
+ return $q.reject();
+ });
+ };
+
+ // Scroll to first error.
+ function scrollToFirstError() {
+ if (!scrollView) {
+ scrollView = $ionicScrollDelegate.$getByHandle('mmaModDataEntryScroll');
+ }
+ if (!$mmUtil.scrollToElement(document.body, '.mm-data-error', scrollView)) {
+ scrollView && scrollView.scrollTop && scrollView.scrollTop();
+ }
+ }
+
+ function returnToEntryList() {
+ return $mmaModDataHelper.getEditTmpFiles(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ $scope.entry.contents).then(function(files) {
+ $mmFileUploaderHelper.clearTmpFiles(files);
+ }).finally(function() {
+ // Go back to discussions list.
+ $ionicHistory.goBack();
+ });
+ }
+
+ // Just ask to confirm the lost of data.
+ function cancel() {
+ return $mmaModDataHelper.hasEditDataChanged(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ $scope.entry.contents).then(function(changed) {
+ if (!changed) {
+ return $q.when();
+ }
+ // Show confirmation if some data has been modified.
+ return $mmUtil.showConfirm($translate('mm.core.confirmcanceledit'));
+ }).then(function() {
+ // Delete the local files from the tmp folder.
+ return $mmaModDataHelper.getEditTmpFiles(document.forms['mma-mod_data-edit-form'], $scope.fields, data.id,
+ $scope.entry.contents).then(function(files) {
+ $mmFileUploaderHelper.clearTmpFiles(files);
+ });
+ });
+ }
+
+ fetchEntryData();
+
+});
diff --git a/www/addons/mod/data/controllers/entry.js b/www/addons/mod/data/controllers/entry.js
new file mode 100644
index 00000000000..156098179ec
--- /dev/null
+++ b/www/addons/mod/data/controllers/entry.js
@@ -0,0 +1,236 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Data entry controller.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc controller
+ * @name mmaModDataEntryCtrl
+ */
+.controller('mmaModDataEntryCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $mmCourse, $q, $mmEvents,
+ $mmText, $translate, $mmUtil, $mmSite, $mmaModDataHelper, $mmGroups, $ionicScrollDelegate, mmaModDataEventEntryChanged,
+ $ionicHistory, $mmaModDataOffline, mmaModDataEventAutomSynced) {
+
+ var module = $stateParams.module || {},
+ courseId = $stateParams.courseid,
+ entryId = $stateParams.entryid || false,
+ page = $stateParams.page || false,
+ data,
+ entryChangedObserver,
+ syncObserver,
+ scrollView,
+ access,
+ offlineActions = [];
+
+ $scope.title = module.name;
+ $scope.description = module.description;
+ $scope.moduleUrl = module.url;
+ $scope.moduleName = $mmCourse.translateModuleName('data');
+ $scope.component = mmaModDataComponent;
+ $scope.databaseLoaded = false;
+ $scope.selectedGroup = $stateParams.group || 0;
+ $scope.entries = {};
+
+ function fetchEntryData(refresh) {
+ return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) {
+ data = databaseData;
+
+ $scope.title = data.name || $scope.title;
+ $scope.description = data.intro || $scope.description;
+ $scope.data = databaseData;
+
+ return setEntryIdFromPage(data.id, page, $scope.selectedGroup).then(function() {
+ return $mmaModData.getDatabaseAccessInformation(data.id);
+ });
+ }).then(function(accessData) {
+ access = accessData;
+ return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) {
+ $scope.groupInfo = groupInfo;
+
+ // Check selected group is accessible.
+ if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) {
+ var found = false;
+ for (var x in groupInfo.groups) {
+ if (groupInfo.groups[x].id == $scope.selectedGroup) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ $scope.selectedGroup = groupInfo.groups[0].id;
+ }
+ }
+
+ return $mmaModDataOffline.getEntryActions(data.id, entryId);
+ });
+ }).then(function(actions) {
+ offlineActions = actions;
+ $scope.hasOffline = !!offlineActions.length;
+
+ return $mmaModData.getFields(data.id).then(function(fieldsData) {
+ $scope.fields = {};
+ angular.forEach(fieldsData, function(field) {
+ $scope.fields[field.id] = field;
+ });
+
+ return $mmaModDataHelper.getEntry(data, entryId, offlineActions);
+ });
+ }).then(function(entry) {
+ entry = entry.entry;
+ $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id);
+
+ // Index contents by fieldid.
+ var contents = {};
+ angular.forEach(entry.contents, function(field) {
+ contents[field.fieldid] = field;
+ });
+ entry.contents = contents;
+
+ return $mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields);
+ }).then(function(entryData) {
+ $scope.entry = entryData;
+
+ $scope.entries[entryId] = $scope.entry;
+
+ var actions = $mmaModDataHelper.getActions(data, access, $scope.entry);
+
+ $scope.entryRendered = $mmaModDataHelper.displayShowFields(data.singletemplate, $scope.fields,
+ $scope.entry, 'show', actions);
+ $scope.showComments = actions.comments;
+
+ return $mmaModDataHelper.getPageInfoByEntry(data.id, entryId, $scope.selectedGroup).then(function(result) {
+ $scope.previousId = result.previousId;
+ $scope.nextId = result.nextId;
+ });
+ }).catch(function(message) {
+ if (!refresh) {
+ // Some call failed, retry without using cache since it might be a new activity.
+ return refreshAllData();
+ }
+
+ $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ }).finally(function() {
+ scrollTop();
+ $scope.databaseLoaded = true;
+ });
+ }
+
+ // Set group to see the database.
+ $scope.setGroup = function(groupId) {
+ $scope.selectedGroup = groupId;
+ $scope.databaseLoaded = false;
+
+ return setEntryIdFromPage(data.id, 0, $scope.selectedGroup).then(function() {
+ return fetchEntryData();
+ });
+ };
+
+ // Go to selected entry without changing state.
+ $scope.gotoEntry = function(entry) {
+ entryId = entry;
+ page = false;
+ $scope.databaseLoaded = false;
+ return fetchEntryData();
+
+ };
+
+ // Convenience function to refresh all the data.
+ function refreshAllData() {
+ var promises = [];
+
+ promises.push($mmaModData.invalidateDatabaseData(courseId));
+ if (data) {
+ promises.push($mmaModData.invalidateEntryData(data.id, entryId));
+ promises.push($mmGroups.invalidateActivityGroupInfo(data.coursemodule));
+ promises.push($mmaModData.invalidateEntriesData(data.id));
+ }
+
+ return $q.all(promises).finally(function() {
+ return fetchEntryData(true);
+ });
+ }
+
+ // Convenience function to translate page number to entry identifier.
+ function setEntryIdFromPage(dataId, pageNumber, group) {
+ if (pageNumber !== false) {
+ return $mmaModDataHelper.getPageInfoByPage(dataId, pageNumber, group).then(function(result) {
+ entryId = result.entryId;
+ page = false;
+ });
+ }
+
+ return $q.when();
+ }
+
+ fetchEntryData();
+
+ // Scroll to top.
+ function scrollTop() {
+ if (!scrollView) {
+ scrollView = $ionicScrollDelegate.$getByHandle('mmaModDataEntryScroll');
+ }
+ scrollView && scrollView.scrollTop && scrollView.scrollTop();
+ }
+
+ // Context Menu Description action.
+ $scope.expandDescription = function() {
+ $mmText.expandText($translate.instant('mm.core.description'), $scope.description, false, mmaModDataComponent, module.id);
+ };
+
+ // Pull to refresh.
+ $scope.refreshDatabase = function() {
+ if ($scope.databaseLoaded) {
+ return refreshAllData().finally(function() {
+ $scope.$broadcast('scroll.refreshComplete');
+ });
+ }
+ };
+
+ // Refresh entry on change.
+ entryChangedObserver = $mmEvents.on(mmaModDataEventEntryChanged, function(eventData) {
+ if (eventData.entryId == entryId && data.id == eventData.dataId && $mmSite.getId() == eventData.siteId) {
+ if (eventData.deleted) {
+ // If deleted, go back.
+ $ionicHistory.goBack();
+ } else {
+ $scope.databaseLoaded = false;
+ return fetchEntryData(true);
+ }
+ }
+ });
+
+ // Refresh entry on sync.
+ syncObserver = $mmEvents.on(mmaModDataEventAutomSynced, function(eventData) {
+ if ((eventData.entryid == entryId || eventData.offlineentryid == entryId) && data.id == eventData.dataid &&
+ $mmSite.getId() == eventData.siteid) {
+ if (eventData.deleted) {
+ // If deleted, go back.
+ $ionicHistory.goBack();
+ } else {
+ entryId = eventData.entryid;
+ $scope.databaseLoaded = false;
+ fetchEntryData(true);
+ }
+ }
+ });
+
+ $scope.$on('$destroy', function() {
+ entryChangedObserver && entryChangedObserver.off && entryChangedObserver.off();
+ syncObserver && syncObserver.off && syncObserver.off();
+ });
+});
diff --git a/www/addons/mod/data/controllers/index.js b/www/addons/mod/data/controllers/index.js
new file mode 100644
index 00000000000..65a1ea09c17
--- /dev/null
+++ b/www/addons/mod/data/controllers/index.js
@@ -0,0 +1,451 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Data index controller.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc controller
+ * @name mmaModDataIndexCtrl
+ */
+.controller('mmaModDataIndexCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $mmCourse, $mmCourseHelper, $q,
+ $mmText, $translate, $mmEvents, mmCoreEventOnlineStatusChanged, $mmApp, $mmUtil, $mmSite, $mmaModDataHelper, $mmGroups,
+ mmaModDataEventEntryChanged, $ionicModal, mmaModDataPerPage, $state, $mmComments, $mmaModDataOffline, $mmaModDataSync,
+ mmaModDataEventAutomSynced) {
+
+ var module = $stateParams.module || {},
+ courseId = $stateParams.courseid,
+ siteId = $mmSite.getId(),
+ data,
+ entryChangedObserver,
+ onlineObserver,
+ syncObserver,
+ hasComments = false;
+
+ $scope.title = module.name;
+ $scope.description = module.description;
+ $scope.moduleUrl = module.url;
+ $scope.moduleName = $mmCourse.translateModuleName('data');
+ $scope.refreshIcon = 'spinner';
+ $scope.syncIcon = 'spinner';
+ $scope.component = mmaModDataComponent;
+ $scope.databaseLoaded = false;
+ $scope.selectedGroup = $stateParams.group || 0;
+ $scope.entries = {};
+
+ $scope.search = {
+ sortBy: "0",
+ sortDirection: "DESC",
+ page: 0,
+ text: "",
+ searching: false,
+ searchingAdvanced: false,
+ advanced: {}
+ };
+
+ function fetchDatabaseData(refresh, sync, showErrors) {
+ $scope.isOnline = $mmApp.isOnline();
+
+ return $mmaModData.getDatabase(courseId, module.id).then(function(databaseData) {
+ data = databaseData;
+
+ $scope.title = data.name || $scope.title;
+ $scope.description = data.intro || $scope.description;
+ $scope.data = databaseData;
+
+ if (sync) {
+ // Try to synchronize the database.
+ return syncDatabase(showErrors).catch(function() {
+ // Ignore errors.
+ });
+ }
+ }).then(function() {
+ return $mmaModData.getDatabaseAccessInformation(data.id);
+ }).then(function(accessData) {
+ $scope.access = accessData;
+
+ if (!accessData.timeavailable) {
+ var time = $mmUtil.timestamp();
+
+ $scope.timeAvailableFrom = data.timeavailablefrom && time < data.timeavailablefrom ?
+ parseInt(data.timeavailablefrom, 10) * 1000 : false;
+ $scope.timeAvailableFromReadable = $scope.timeAvailableFrom ?
+ moment($scope.timeAvailableFrom).format('LLL') : false;
+ $scope.timeAvailableTo = data.timeavailableto && time > data.timeavailableto ?
+ parseInt(data.timeavailableto, 10) * 1000 : false;
+ $scope.timeAvailableToReadable = $scope.timeAvailableTo ? moment($scope.timeAvailableTo).format('LLL') : false;
+
+ $scope.isEmpty = true;
+ $scope.groupInfo = false;
+ return false;
+ }
+
+ $scope.canSearch = true;
+ $scope.canAdd = accessData.canaddentry;
+
+ return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) {
+ $scope.groupInfo = groupInfo;
+
+ // Check selected group is accessible.
+ if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) {
+ var found = false;
+ for (var x in groupInfo.groups) {
+ if (groupInfo.groups[x].id == $scope.selectedGroup) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ $scope.selectedGroup = groupInfo.groups[0].id;
+ }
+ }
+ return fetchOfflineEntries();
+ });
+ }).then(function() {
+ return $mmaModData.getFields(data.id).then(function(fields) {
+ if (fields.length == 0) {
+ $scope.canSearch = false;
+ $scope.canAdd = false;
+ }
+ $scope.search.advanced = {};
+
+ $scope.fields = {};
+ angular.forEach(fields, function(field) {
+ $scope.fields[field.id] = field;
+ });
+ $scope.advancedSearch = $mmaModDataHelper.displayAdvancedSearchFields(data.asearchtemplate, $scope.fields);
+
+ return fetchEntriesData();
+ });
+ }).then(function() {
+ // All data obtained, now fill the context menu.
+ $mmCourseHelper.fillContextMenu($scope, module, courseId, refresh, mmaModDataComponent);
+ }).catch(function(message) {
+ if (!refresh) {
+ // Some call failed, retry without using cache since it might be a new activity.
+ return refreshAllData();
+ }
+
+ $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ }).finally(function() {
+ $scope.databaseLoaded = true;
+ });
+ }
+
+ function fetchOfflineEntries() {
+ // Check if there are entries stored in offline.
+ return $mmaModDataOffline.getDatabaseEntries(data.id).then(function(offlineEntries) {
+ $scope.hasOffline = !!offlineEntries.length;
+
+ $scope.offlineActions = {};
+ $scope.offlineEntries = {};
+
+ // Only show offline entries on first page.
+ if ($scope.search.page == 0 && $scope.hasOffline) {
+ angular.forEach(offlineEntries, function(entry) {
+ if (entry.entryid > 0) {
+ if (typeof $scope.offlineActions[entry.entryid] == "undefined") {
+ $scope.offlineActions[entry.entryid] = [];
+ }
+ $scope.offlineActions[entry.entryid].push(entry);
+ } else {
+ if (typeof $scope.offlineActions[entry.entryid] == "undefined") {
+ $scope.offlineEntries[entry.entryid] = [];
+ }
+ $scope.offlineEntries[entry.entryid].push(entry);
+ }
+ });
+ }
+ });
+ }
+
+ function fetchEntriesData() {
+ hasComments = false;
+
+ return $mmaModData.getDatabaseAccessInformation(data.id, $scope.selectedGroup).then(function(accessData) {
+ // Update values for current group.
+ $scope.access.canaddentry = accessData.canaddentry;
+
+ if ($scope.search.searching) {
+ var text = $scope.search.searchingAdvanced ? undefined : $scope.search.text;
+ advanced = $scope.search.searchingAdvanced ? $scope.search.advanced : undefined;
+ return $mmaModData.searchEntries(data.id, $scope.selectedGroup, text, advanced, $scope.search.sortBy,
+ $scope.search.sortDirection, $scope.search.page);
+ } else {
+ return $mmaModData.getEntries(data.id, $scope.selectedGroup, $scope.search.sortBy, $scope.search.sortDirection,
+ $scope.search.page);
+ }
+ }).then(function(entries) {
+ var numEntries = (entries && entries.entries && entries.entries.length) || 0;
+ $scope.isEmpty = !numEntries && !Object.keys($scope.offlineActions).length && !Object.keys($scope.offlineEntries).length;
+ $scope.hasNextPage = numEntries >= mmaModDataPerPage && (($scope.search.page + 1) * mmaModDataPerPage) < entries.totalcount;
+ $scope.entriesRendered = "";
+
+ if (!$scope.isEmpty) {
+ $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id);
+
+ var siteInfo = $mmSite.getInfo(),
+ promises = [];
+
+ angular.forEach($scope.offlineEntries, function(offlineActions) {
+ var entry;
+
+ angular.forEach(offlineActions, function(offlineEntry) {
+ if (offlineEntry.action == 'add') {
+ entry = {
+ id: offlineEntry.entryid,
+ canmanageentry: true,
+ approved: !data.approval || data.manageapproved,
+ dataid: offlineEntry.dataid,
+ groupid: offlineEntry.groupid,
+ timecreated: -offlineEntry.entryid,
+ timemodified: -offlineEntry.entryid,
+ userid: siteInfo.userid,
+ fullname: siteInfo.fullname,
+ contents: {}
+ };
+ }
+ });
+
+ if (entry) {
+ if (offlineActions.length > 0) {
+ promises.push($mmaModDataHelper.applyOfflineActions(entry, offlineActions, $scope.fields));
+ } else {
+ promises.push($q.when(entry));
+ }
+ }
+
+ });
+
+ angular.forEach(entries.entries, function(entry) {
+ // Index contents by fieldid.
+ var contents = {};
+ angular.forEach(entry.contents, function(field) {
+ contents[field.fieldid] = field;
+ });
+ entry.contents = contents;
+
+ if (typeof $scope.offlineActions[entry.id] != "undefined") {
+ promises.push($mmaModDataHelper.applyOfflineActions(entry, $scope.offlineActions[entry.id], $scope.fields));
+ } else {
+ promises.push($q.when(entry));
+ }
+ });
+
+ return $q.all(promises).then(function(entries) {
+ var entriesHTML = data.listtemplateheader;
+
+ angular.forEach(entries, function(entry) {
+ $scope.entries[entry.id] = entry;
+
+ var actions = $mmaModDataHelper.getActions(data, $scope.access, entry);
+
+ entriesHTML += $mmaModDataHelper.displayShowFields(data.listtemplate, $scope.fields, entry, 'list', actions);
+ });
+ entriesHTML += data.listtemplatefooter;
+
+ $scope.entriesRendered = entriesHTML;
+ });
+ } else if (!$scope.search.searching) {
+ $scope.canSearch = false;
+ }
+ });
+ }
+
+ // Set group to see the database.
+ $scope.setGroup = function(groupId) {
+ $scope.selectedGroup = groupId;
+ return fetchEntriesData().catch(function(message) {
+ $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ });
+ };
+
+ // Convenience function to refresh all the data.
+ function refreshAllData(sync, showErrors) {
+ var promises = [];
+
+ promises.push($mmaModData.invalidateDatabaseData(courseId));
+ if (data) {
+ promises.push($mmaModData.invalidateDatabaseAccessInformationData(data.id));
+ promises.push($mmGroups.invalidateActivityGroupInfo(data.coursemodule));
+ promises.push($mmaModData.invalidateEntriesData(data.id));
+ if (hasComments) {
+ promises.push($mmComments.invalidateCommentsByInstance('module', data.coursemodule));
+ }
+ }
+
+ return $q.all(promises).finally(function() {
+ return fetchDatabaseData(true, sync, showErrors);
+ });
+ }
+
+ // Tries to synchronize the database.
+ function syncDatabase(showErrors) {
+ return $mmaModDataSync.syncDatabase(data.id).then(function(result) {
+ if (result.warnings && result.warnings.length) {
+ $mmUtil.showErrorModal(result.warnings[0]);
+ }
+
+ return result.updated;
+ }).catch(function(error) {
+ if (showErrors) {
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errorsync', true);
+ }
+ return $q.reject();
+ });
+ }
+
+ fetchDatabaseData(false, true).then(function() {
+ $mmaModData.logView(data.id).then(function() {
+ $mmCourse.checkModuleCompletion(courseId, module.completionstatus);
+ });
+ }).finally(function() {
+ $scope.refreshIcon = 'ion-refresh';
+ $scope.syncIcon = 'ion-loop';
+ });
+
+ // Confirm and Remove action.
+ $scope.removeFiles = function() {
+ $mmCourseHelper.confirmAndRemove(module, courseId);
+ };
+
+ // Context Menu Prefetch action.
+ $scope.prefetch = function() {
+ $mmCourseHelper.contextMenuPrefetch($scope, module, courseId);
+ };
+ // Context Menu Description action.
+ $scope.expandDescription = function() {
+ $mmText.expandText($translate.instant('mm.core.description'), $scope.description, false, mmaModDataComponent, module.id);
+ };
+
+ // Pull to refresh.
+ $scope.refreshDatabase = function(showErrors) {
+ if ($scope.databaseLoaded) {
+ $scope.refreshIcon = 'spinner';
+ $scope.syncIcon = 'spinner';
+ return refreshAllData(true, showErrors).finally(function() {
+ $scope.refreshIcon = 'ion-refresh';
+ $scope.syncIcon = 'ion-loop';
+ $scope.$broadcast('scroll.refreshComplete');
+ });
+ }
+ };
+
+ // Setup search modal.
+ $ionicModal.fromTemplateUrl('addons/mod/data/templates/search-modal.html', {
+ scope: $scope,
+ animation: 'slide-in-up'
+ }).then(function(searchModal) {
+ $scope.showSearch = function() {
+ searchModal.show();
+ };
+ $scope.closeSearch = function() {
+ searchModal.hide();
+ };
+ $scope.$on('$destroy', function() {
+ searchModal.remove();
+ });
+ });
+
+ // Performs the search and closes the modal.
+ $scope.searchEntries = function(page) {
+ $scope.closeSearch();
+ $scope.databaseLoaded = false;
+ $scope.search.page = page;
+
+ if ($scope.search.searchingAdvanced) {
+ $scope.search.advanced = $mmaModDataHelper.getSearchDataFromForm(document.forms['mma-mod_data-advanced-search-form'],
+ $scope.fields);
+ $scope.search.searching = $scope.search.advanced.length > 0;
+ } else {
+ $scope.search.searching = $scope.search.text.length > 0;
+ }
+ return fetchEntriesData().catch(function(message) {
+ $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ }).finally(function() {
+ $scope.databaseLoaded = true;
+ });
+ };
+
+ // Reset all search filters and closes the modal.
+ $scope.searchReset = function() {
+ $scope.search.sortBy = "0";
+ $scope.search.sortDirection = "DESC";
+ $scope.search.text = "";
+ $scope.search.advanced = {};
+ $scope.search.searchingAdvanced = false;
+ $scope.search.searching = false;
+ $scope.searchEntries(0);
+ };
+
+ // Switches between advanced to normal search
+ $scope.switchAdvanced = function(enable) {
+ $scope.search.searchingAdvanced = enable;
+ };
+
+ // Opens add entries form
+ $scope.gotoAddEntries = function() {
+ var stateParams = {
+ moduleid: module.id,
+ module: module,
+ courseid: courseId,
+ group: $scope.selectedGroup
+ };
+ $state.go('site.mod_data-edit', stateParams);
+ };
+
+ $scope.gotoEntry = function(entryId) {
+ var stateParams = {
+ module: module,
+ moduleid: module.id,
+ courseid: courseId,
+ entryid: entryId,
+ group: $scope.selectedGroup
+ };
+ $state.go('site.mod_data-entry', stateParams);
+ };
+
+ // Refresh online status when changes.
+ onlineObserver = $mmEvents.on(mmCoreEventOnlineStatusChanged, function(online) {
+ $scope.isOnline = online;
+ });
+
+ // Refresh entries on change.
+ entryChangedObserver = $mmEvents.on(mmaModDataEventEntryChanged, function(eventData) {
+ if (data.id == eventData.dataId && siteId == eventData.siteId) {
+ $scope.databaseLoaded = false;
+ return fetchDatabaseData(true);
+ }
+ });
+
+ // Refresh entries on sync.
+ syncObserver = $mmEvents.on(mmaModDataEventAutomSynced, function(eventData) {
+ // Update just when all database is synced.
+ if (data.id == eventData.dataid && siteId == eventData.siteid && typeof eventData.entryid == "undefined") {
+ $scope.databaseLoaded = false;
+ fetchDatabaseData(true);
+ }
+ });
+
+ $scope.$on('$destroy', function() {
+ onlineObserver && onlineObserver.off && onlineObserver.off();
+ entryChangedObserver && entryChangedObserver.off && entryChangedObserver.off();
+ syncObserver && syncObserver.off && syncObserver.off();
+ });
+});
diff --git a/www/addons/mod/data/directives/action.js b/www/addons/mod/data/directives/action.js
new file mode 100644
index 00000000000..747edede8f9
--- /dev/null
+++ b/www/addons/mod/data/directives/action.js
@@ -0,0 +1,56 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data action.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataAction
+ */
+.directive('mmaModDataAction', function($mmSite, $mmUser, $mmaModDataOffline, $mmEvents, mmaModDataEventEntryChanged) {
+ return {
+ restrict: 'E',
+ priority: 100,
+ scope: {
+ action: '@',
+ database: '=',
+ entry: '=?',
+ mode: '@'
+ },
+ templateUrl: 'addons/mod/data/templates/action.html',
+ link: function(scope) {
+ scope.url = $mmSite.getURL();
+
+ if (scope.action == 'userpicture') {
+ $mmUser.getProfile(scope.entry.userid, scope.database.courseid).then(function(profile) {
+ scope.userpicture = profile.profileimageurl;
+ });
+ }
+
+ scope.undoDelete = function() {
+ var dataId = scope.database.id;
+ entryId = scope.entry.id;
+ return $mmaModDataOffline.getEntry(dataId, entryId, 'delete').then(function() {
+ // Found. Just delete the action.
+ return $mmaModDataOffline.deleteEntry(dataId, entryId, 'delete');
+ }).then(function() {
+ $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: $mmSite.getId()});
+ });
+ };
+ }
+ };
+});
diff --git a/www/addons/mod/data/directives/field.js b/www/addons/mod/data/directives/field.js
new file mode 100644
index 00000000000..97039efa03e
--- /dev/null
+++ b/www/addons/mod/data/directives/field.js
@@ -0,0 +1,59 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataField
+ */
+.directive('mmaModDataField', function($mmaModDataFieldsDelegate, $compile) {
+ return {
+ restrict: 'E',
+ priority: 100,
+ scope: {
+ field: '=',
+ value: '=?',
+ database: '=?',
+ error: '=?',
+ viewAction: '&?',
+ mode: '@'
+ },
+ templateUrl: 'addons/mod/data/templates/field.html',
+ link: function(scope, element) {
+ var field = scope.field,
+ container = element[0].querySelector('.mma-mod-data-field-container'),
+ directive;
+
+ if (!field || !container) {
+ return;
+ }
+
+ // Check if the plugin has defined its own directive to render itself.
+ directive = $mmaModDataFieldsDelegate.getDirectiveForPlugin(field);
+
+ if (directive) {
+ // Add the directive to the element.
+ container.setAttribute(directive, '');
+ // Compile the new directive.
+ $compile(container)(scope);
+ } else {
+ scope.fieldLoaded = true;
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/checkbox/directive.js b/www/addons/mod/data/fields/checkbox/directive.js
new file mode 100644
index 00000000000..16e95b2ca4e
--- /dev/null
+++ b/www/addons/mod/data/fields/checkbox/directive.js
@@ -0,0 +1,52 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.filter('mmaModDataFieldCheckboxFormat', function() {
+ return function(text) {
+ return text.split("##").join(" ");
+ };
+})
+
+/**
+ * Directive to render data checkbox field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldCheckbox
+ */
+.directive('mmaModDataFieldCheckbox', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/checkbox/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ return;
+ }
+
+ scope.options = scope.field.param1.split("\n");
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.values = {};
+
+ angular.forEach(scope.value.content.split("##"), function(value) {
+ scope.values[value] = true;
+ });
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/checkbox/handler.js b/www/addons/mod/data/fields/checkbox/handler.js
new file mode 100644
index 00000000000..d7d89c69554
--- /dev/null
+++ b/www/addons/mod/data/fields/checkbox/handler.js
@@ -0,0 +1,148 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for checkbox data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldCheckboxHandler
+ */
+.factory('$mmaModDataFieldCheckboxHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id,
+ reqName = 'f_' + field.id + '_allreq';
+
+ var checkboxes = [],
+ values = [];
+ angular.forEach(inputData[fieldName], function(value, option) {
+ if (value) {
+ checkboxes.push(option);
+ }
+ });
+ if (checkboxes.length > 0) {
+ values.push({
+ name: fieldName,
+ value: checkboxes
+ });
+
+ if (inputData[reqName]['1']) {
+ values.push({
+ name: reqName,
+ value: true
+ });
+ }
+ return values;
+ }
+
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ var checkboxes = [];
+ angular.forEach(inputData[fieldName], function(value, option) {
+ if (value) {
+ checkboxes.push(option);
+ }
+ });
+ if (checkboxes.length > 0) {
+ return [{
+ fieldid: field.id,
+ value: checkboxes
+ }];
+ }
+
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ checkboxes = [];
+
+ angular.forEach(inputData[fieldName], function(value, option) {
+ if (value) {
+ checkboxes.push(option);
+ }
+ });
+
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+ return checkboxes.join("##") != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = (offlineContent[''] && offlineContent[''].join("##")) || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldCheckbox', 'checkbox', '$mmaModDataFieldCheckboxHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/checkbox/template.html b/www/addons/mod/data/fields/checkbox/template.html
new file mode 100644
index 00000000000..82c3ac440c3
--- /dev/null
+++ b/www/addons/mod/data/fields/checkbox/template.html
@@ -0,0 +1,7 @@
+
+
+ {{ error }}
+ {{ option }}
+ {{ 'mma.mod_data.selectedrequired' | translate }}
+
+{{ value.content | mmaModDataFieldCheckboxFormat }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/date/directive.js b/www/addons/mod/data/fields/date/directive.js
new file mode 100644
index 00000000000..9626c53b9f0
--- /dev/null
+++ b/www/addons/mod/data/fields/date/directive.js
@@ -0,0 +1,52 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.filter('mmaModDataFieldDateFormat', function() {
+ return function(text) {
+ return text * 1000;
+ };
+})
+
+/**
+ * Directive to render data date field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldDate
+ */
+.directive('mmaModDataFieldDate', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/date/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ return;
+ }
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.enable = true;
+ } else {
+ scope.value = {
+ content: Math.floor(Date.now() / 1000)
+ };
+ scope.enable = false;
+ }
+ scope.val = new Date(scope.value.content * 1000);
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/date/handler.js b/www/addons/mod/data/fields/date/handler.js
new file mode 100644
index 00000000000..a41d81653e3
--- /dev/null
+++ b/www/addons/mod/data/fields/date/handler.js
@@ -0,0 +1,161 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for date data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldDateHandler
+ */
+.factory('$mmaModDataFieldDateHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id,
+ enabledName = fieldName + '_z';
+
+ if (inputData[enabledName]['1']) {
+ var values = [],
+ date = inputData[fieldName].split('-'),
+ year = date[0],
+ month = date[1],
+ day = date[2];
+ values.push({
+ name: fieldName + '_y',
+ value: year
+ });
+ values.push({
+ name: fieldName + '_m',
+ value: month
+ });
+ values.push({
+ name: fieldName + '_d',
+ value: day
+ });
+ values.push({
+ name: enabledName,
+ value: 1
+ });
+ return values;
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ if (inputData[fieldName]) {
+ var values = [],
+ date = inputData[fieldName].split('-'),
+ year = date[0],
+ month = date[1],
+ day = date[2];
+ values.push({
+ fieldid: field.id,
+ subfield: 'year',
+ value: year
+ });
+ values.push({
+ fieldid: field.id,
+ subfield: 'month',
+ value: month
+ });
+ values.push({
+ fieldid: field.id,
+ subfield: 'day',
+ value: day
+ });
+ return values;
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+
+ originalFieldData = (originalFieldData && originalFieldData.content &&
+ new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required &&
+ (!inputData || inputData.length < 2 || !inputData[0].value || !inputData[1].value || !inputData[2].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ var date = Date.UTC(offlineContent.year || "", offlineContent.month ? offlineContent.month - 1 : "",
+ offlineContent.day || "");
+ date = Math.floor(date / 1000);
+
+ originalContent.content = date || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldDate', 'date', '$mmaModDataFieldDateHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/date/template.html b/www/addons/mod/data/fields/date/template.html
new file mode 100644
index 00000000000..783d1fc842b
--- /dev/null
+++ b/www/addons/mod/data/fields/date/template.html
@@ -0,0 +1,5 @@
+
+{{ error }}
+
+{{ 'mma.mod_data.usedate' | translate }}
+{{ value.content | mmaModDataFieldDateFormat | mmFormatDate:"dfdaymonthyear" }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/file/directive.js b/www/addons/mod/data/fields/file/directive.js
new file mode 100644
index 00000000000..238d362ce52
--- /dev/null
+++ b/www/addons/mod/data/fields/file/directive.js
@@ -0,0 +1,68 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data file field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldFile
+ */
+.directive('mmaModDataFieldFile', function($mmFileSession, mmaModDataComponent) {
+
+ /**
+ * Get the files from the input value.
+ *
+ * @param {Object} value Input value.
+ * @return {Object[]} List of files.
+ */
+ function getFiles(value) {
+ var files = (value && value.files) || [];
+
+ // Reduce to first element.
+ if (files.length > 0) {
+ files = [files[0]];
+ }
+
+ return files;
+ }
+
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/file/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show' || scope.mode == 'edit') {
+ scope.component = mmaModDataComponent;
+ scope.componentId = scope.database.coursemodule;
+
+ if (scope.mode == 'show') {
+ // Displaying the list of files, watch the value to update the list if it changes.
+ scope.$watch('value', function(newValue) {
+ scope.files = getFiles(newValue);
+ });
+ } else {
+ // Edit mode, the list shouldn't change so there is no need to watch it.
+ scope.files = getFiles(scope.value);
+
+ scope.maxSizeBytes = parseInt(scope.field.param3, 10);
+ $mmFileSession.setFiles(mmaModDataComponent, scope.database.id + '_' + scope.field.id, scope.files);
+ }
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/file/handler.js b/www/addons/mod/data/fields/file/handler.js
new file mode 100644
index 00000000000..9785294c354
--- /dev/null
+++ b/www/addons/mod/data/fields/file/handler.js
@@ -0,0 +1,137 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for file data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldFileHandler
+ */
+.factory('$mmaModDataFieldFileHandler', function($mmFileSession, mmaModDataComponent, $mmFileUploaderHelper, $translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field) {
+ var files = self.getFieldEditFiles(field);
+ if (files.length) {
+ return [{
+ fieldid: field.id,
+ subfield: 'file',
+ files: files
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit files in the input data.
+ *
+ * @param {Object} field Defines the field..
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditFiles = function(field) {
+ return $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id);
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var files = $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id) || [],
+ originalFiles = (originalFieldData && originalFieldData.files) || [];
+
+ if (originalFiles.length) {
+ originalFiles = [originalFiles[0]];
+ }
+
+ return $mmFileUploaderHelper.areFileListDifferent(files, originalFiles);
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @param {Array} offlineFiles Array with all the offline files in the field.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent, offlineFiles) {
+ if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) {
+ originalContent.content = offlineFiles[0].filename;
+ originalContent.files = [offlineFiles[0]];
+ } else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) {
+ originalContent.content = offlineContent.file.online[0].filename;
+ originalContent.files = [offlineContent.file.online[0]];
+ }
+
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldFile', 'file', '$mmaModDataFieldFileHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/file/template.html b/www/addons/mod/data/fields/file/template.html
new file mode 100644
index 00000000000..713ac633e29
--- /dev/null
+++ b/www/addons/mod/data/fields/file/template.html
@@ -0,0 +1,10 @@
+
+{{ error }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/latlong/directive.js b/www/addons/mod/data/fields/latlong/directive.js
new file mode 100644
index 00000000000..9d3bf66b413
--- /dev/null
+++ b/www/addons/mod/data/fields/latlong/directive.js
@@ -0,0 +1,58 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.filter('mmaModDataFieldLatLongFormat', function() {
+ return function(value) {
+ var north = (value && parseFloat(value.content)) || "",
+ east = (value && parseFloat(value.content1)) || "";
+
+ if (north !== '' || east !== '') {
+ north = north ? north.toFixed(4) : '0.0000';
+ east = east ? east.toFixed(4) : '0.0000';
+
+ var latitude = north < 0 ? -north + '°S' : north + '°N',
+ longitude = east < 0 ? -east + '°W' : east + '°E',
+ link = ionic.Platform.isAndroid() ? 'geo:' + north + ',' + east :
+ 'http://maps.apple.com/?ll=' + north + ',' + east + '&near=' + north + ',' + east;
+
+ return '' + latitude + ' ' + longitude + '';
+ }
+ };
+})
+
+/**
+ * Directive to render data latlong field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldLatlong
+ */
+.directive('mmaModDataFieldLatlong', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/latlong/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.value) {
+ if (scope.mode == 'edit') {
+ scope.north = (scope.value && parseFloat(scope.value.content)) || "";
+ scope.east = (scope.value && parseFloat(scope.value.content1)) || "";
+ }
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/latlong/handler.js b/www/addons/mod/data/fields/latlong/handler.js
new file mode 100644
index 00000000000..9922c1397a1
--- /dev/null
+++ b/www/addons/mod/data/fields/latlong/handler.js
@@ -0,0 +1,143 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for latlong data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldLatlongHandler
+ */
+.factory('$mmaModDataFieldLatlongHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ var values = [];
+
+ if (inputData[fieldName + '_0']) {
+ values.push({
+ fieldid: field.id,
+ subfield: '0',
+ value: inputData[fieldName + '_0']
+ });
+ }
+ if (inputData[fieldName + '_1']) {
+ values.push({
+ fieldid: field.id,
+ subfield: '1',
+ value: inputData[fieldName + '_1']
+ });
+ }
+ return values;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ lat = inputData[fieldName + '_0'] || "",
+ long = inputData[fieldName + '_1'] || "",
+ originalLat = (originalFieldData && originalFieldData.content) || "",
+ originalLong = (originalFieldData && originalFieldData.content1) || "";
+
+ return lat != originalLat || long != originalLong;
+ };
+
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ var valueCount = 0;
+
+ // The lat long class has two values that need to be checked.
+ angular.forEach(inputData, function(value) {
+ if (typeof value.value != "undefined" && value.value != "") {
+ valueCount++;
+ }
+ });
+
+ // If we get here then only one field has been filled in.
+ if (valueCount == 1) {
+ return $translate.instant('mma.mod_data.latlongboth');
+ } else if (field.required && valueCount == 0) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[0] || "";
+ originalContent.content1 = offlineContent[1] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldLatlong', 'latlong', '$mmaModDataFieldLatlongHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/latlong/template.html b/www/addons/mod/data/fields/latlong/template.html
new file mode 100644
index 00000000000..5f0383efcde
--- /dev/null
+++ b/www/addons/mod/data/fields/latlong/template.html
@@ -0,0 +1,13 @@
+
+
+{{ error }}
+
+
+
+
diff --git a/www/addons/mod/data/fields/menu/directive.js b/www/addons/mod/data/fields/menu/directive.js
new file mode 100644
index 00000000000..d4d6bcbbd4d
--- /dev/null
+++ b/www/addons/mod/data/fields/menu/directive.js
@@ -0,0 +1,42 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data menu field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldMenu
+ */
+.directive('mmaModDataFieldMenu', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/menu/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ return;
+ }
+
+ scope.options = scope.field.param1.split("\n");
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.val = scope.value.content;
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/menu/handler.js b/www/addons/mod/data/fields/menu/handler.js
new file mode 100644
index 00000000000..08af08fefb9
--- /dev/null
+++ b/www/addons/mod/data/fields/menu/handler.js
@@ -0,0 +1,117 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for menu data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldMenuHandler
+ */
+.factory('$mmaModDataFieldMenuHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ if (inputData[fieldName]) {
+ return [{
+ fieldid: field.id,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldMenu', 'menu', '$mmaModDataFieldMenuHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/menu/template.html b/www/addons/mod/data/fields/menu/template.html
new file mode 100644
index 00000000000..0966a1b3f34
--- /dev/null
+++ b/www/addons/mod/data/fields/menu/template.html
@@ -0,0 +1,9 @@
+
+{{ error }}
+
+
+
+{{ value.content }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/multimenu/directive.js b/www/addons/mod/data/fields/multimenu/directive.js
new file mode 100644
index 00000000000..612b71d7f7b
--- /dev/null
+++ b/www/addons/mod/data/fields/multimenu/directive.js
@@ -0,0 +1,57 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.filter('mmaModDataFieldMultimenuFormat', function() {
+ return function(text) {
+ return text.split("##").join(" ");
+ };
+})
+
+/**
+ * Directive to render data multimenu field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldMultimenu
+ */
+.directive('mmaModDataFieldMultimenu', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/multimenu/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ return;
+ }
+
+ scope.options = scope.field.param1.split("\n").map(function(option) {
+ return {key: option, value: option};
+ });
+
+ if (scope.mode == 'edit' && scope.value && scope.value.content) {
+ angular.forEach(scope.value.content.split("##"), function(value) {
+ for (var x in scope.options) {
+ if (value == scope.options[x].key) {
+ scope.options[x].selected = true;
+ break;
+ }
+ }
+ });
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/multimenu/handler.js b/www/addons/mod/data/fields/multimenu/handler.js
new file mode 100644
index 00000000000..ada5c6c7704
--- /dev/null
+++ b/www/addons/mod/data/fields/multimenu/handler.js
@@ -0,0 +1,137 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for multimenu data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldMultimenuHandler
+ */
+.factory('$mmaModDataFieldMultimenuHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id,
+ reqName = 'f_' + field.id + '_allreq';
+
+ if (inputData[fieldName].length > 0) {
+ var options = inputData[fieldName].split('###');
+ values = [];
+ if (options.length > 0) {
+ values.push({
+ name: fieldName,
+ value: options
+ });
+
+ if (inputData[reqName]['1']) {
+ values.push({
+ name: reqName,
+ value: true
+ });
+ }
+ return values;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ if (inputData[fieldName] && inputData[fieldName].length > 0) {
+ var options = inputData[fieldName].split('###');
+ if (options.length > 0) {
+ return [{
+ fieldid: field.id,
+ value: options
+ }];
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = (offlineContent[''] && offlineContent[''].join("###")) || "";
+ return originalContent;
+ };
+
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldMultimenu', 'multimenu', '$mmaModDataFieldMultimenuHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/multimenu/template.html b/www/addons/mod/data/fields/multimenu/template.html
new file mode 100644
index 00000000000..bae95d7a2ce
--- /dev/null
+++ b/www/addons/mod/data/fields/multimenu/template.html
@@ -0,0 +1,5 @@
+
+{{ error }}
+
+{{ 'mma.mod_data.selectedrequired' | translate }}
+{{ value.content | mmaModDataFieldMultimenuFormat }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/number/directive.js b/www/addons/mod/data/fields/number/directive.js
new file mode 100644
index 00000000000..b3dcb81413d
--- /dev/null
+++ b/www/addons/mod/data/fields/number/directive.js
@@ -0,0 +1,37 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data number field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldNumber
+ */
+.directive('mmaModDataFieldNumber', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/number/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.val = scope.value && parseFloat(scope.value.content);
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/number/handler.js b/www/addons/mod/data/fields/number/handler.js
new file mode 100644
index 00000000000..0229ff1b1cb
--- /dev/null
+++ b/www/addons/mod/data/fields/number/handler.js
@@ -0,0 +1,117 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for number data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldNumberHandler
+ */
+.factory('$mmaModDataFieldNumberHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ fieldid: field.id,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || inputData[0].value == "")) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldNumber', 'number', '$mmaModDataFieldNumberHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/number/template.html b/www/addons/mod/data/fields/number/template.html
new file mode 100644
index 00000000000..4f1dd5780ab
--- /dev/null
+++ b/www/addons/mod/data/fields/number/template.html
@@ -0,0 +1,4 @@
+
+{{ error }}
+
+{{ value.content }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/picture/directive.js b/www/addons/mod/data/fields/picture/directive.js
new file mode 100644
index 00000000000..cf5a0419f5b
--- /dev/null
+++ b/www/addons/mod/data/fields/picture/directive.js
@@ -0,0 +1,102 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data picture field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldPicture
+ */
+.directive('mmaModDataFieldPicture', function(mmaModDataComponent, $mmFileSession) {
+
+ // Find file in a list.
+ function findFile(files, filenameSeek) {
+ for (var x in files) {
+ if (files[x].filename == filenameSeek) {
+ return files[x];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Given an input value, extract the image files and all the required data.
+ *
+ * @param {Object} scope Directive's scope.
+ * @param {Object} value Field value.
+ * @return {Void}
+ */
+ function treatFiles(scope, value) {
+ var files = value && value.files || [];
+
+ // Get image or thumb.
+ if (files.length > 0) {
+ var filenameSeek = scope.mode == 'list' ? 'thumb_' + value.content : value.content;
+ scope.image = findFile(files, filenameSeek);
+
+ if (!scope.image && scope.mode == 'list') {
+ scope.image = findFile(files, value.content);
+ }
+
+ scope.files = [scope.image];
+ } else {
+ scope.image = false;
+ scope.files = [];
+ }
+
+ if (scope.mode == 'edit') {
+ scope.maxSizeBytes = parseInt(scope.field.param3, 10);
+ $mmFileSession.setFiles(mmaModDataComponent, scope.database.id + '_' + scope.field.id, scope.files);
+ scope.alttext = (value && value.content1) || "";
+ } else {
+ scope.entryId = (value && value.recordid) || false;
+ scope.title = (value && value.content1) || "";
+ scope.imageUrl = false;
+ if (scope.image) {
+ if (scope.image.offline) {
+ scope.imageUrl = (scope.image && scope.image.toURL()) || false;
+ } else {
+ scope.imageUrl = (scope.image && scope.image.fileurl) || false;
+ }
+ }
+ scope.width = scope.field.param1 || "";
+ scope.height = scope.field.param2 || "";
+ }
+ }
+
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/picture/template.html',
+ link: function(scope) {
+ if (scope.mode != 'search') {
+ scope.component = mmaModDataComponent;
+ scope.componentId = scope.database.coursemodule;
+
+ if (scope.mode == 'show') {
+ // Displaying the list of files, watch the value to update the list if it changes.
+ scope.$watch('value', function(newValue) {
+ treatFiles(scope, newValue);
+ });
+ } else {
+ // Edit mode, the list shouldn't change so there is no need to watch it.
+ treatFiles(scope, scope.value);
+ }
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/picture/handler.js b/www/addons/mod/data/fields/picture/handler.js
new file mode 100644
index 00000000000..e8fd592b4a6
--- /dev/null
+++ b/www/addons/mod/data/fields/picture/handler.js
@@ -0,0 +1,175 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for picture data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldPictureHandler
+ */
+.factory('$mmaModDataFieldPictureHandler', function($mmFileSession, mmaModDataComponent, $mmFileUploaderHelper, $translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var files = self.getFieldEditFiles(field),
+ values = [],
+ fieldName = 'f_' + field.id + '_alttext';
+
+ if (files.length) {
+ values.push({
+ fieldid: field.id,
+ subfield: 'file',
+ files: files
+ });
+ }
+
+ if (inputData[fieldName]) {
+ values.push({
+ fieldid: field.id,
+ subfield: 'alttext',
+ value: inputData[fieldName]
+ });
+ }
+ return values;
+ };
+
+ /**
+ * Get field edit files in the input data.
+ *
+ * @param {Object} field Defines the field..
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditFiles = function(field) {
+ return $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id);
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id + '_alttext',
+ altText = inputData[fieldName] || "",
+ originalAltText = (originalFieldData && originalFieldData.content1) || "",
+ files = $mmFileSession.getFiles(mmaModDataComponent, field.dataid + '_' + field.id) || [],
+ originalFiles = (originalFieldData && originalFieldData.files) || [];
+
+ // Get image.
+ if (originalFiles.length > 0) {
+ var filenameSeek = (originalFieldData && originalFieldData.content) || "";
+ for (var x in originalFiles) {
+ if (originalFiles[x].filename == filenameSeek) {
+ originalFiles = originalFiles[x];
+ break;
+ }
+ }
+ originalFiles = [originalFiles];
+ } else {
+ originalFiles = [];
+ }
+
+ return altText != originalAltText || $mmFileUploaderHelper.areFileListDifferent(files, originalFiles);
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required) {
+ if (!inputData || !inputData.length) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ var found = false;
+ for (var x in inputData) {
+ if (typeof inputData[x].subfield !="undefined" && inputData[x].subfield == 'file') {
+ found = !!inputData[x].value;
+ break;
+ }
+ }
+
+ if (!found) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @param {Array} offlineFiles Array with all the offline files in the field.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent, offlineFiles) {
+ if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) {
+ originalContent.content = offlineFiles[0].filename;
+ originalContent.files = [offlineFiles[0]];
+ } else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) {
+ originalContent.content = offlineContent.file.online[0].filename;
+ originalContent.files = [offlineContent.file.online[0]];
+ }
+
+ originalContent.content1 = offlineContent.alttext || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldPicture', 'picture', '$mmaModDataFieldPictureHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/picture/template.html b/www/addons/mod/data/fields/picture/template.html
new file mode 100644
index 00000000000..9b92ee53e3b
--- /dev/null
+++ b/www/addons/mod/data/fields/picture/template.html
@@ -0,0 +1,11 @@
+
+{{ error }}
+
+
+
+ {{ 'mma.mod_data.alttext' | translate }}
+
+
+
+
+
diff --git a/www/addons/mod/data/fields/radiobutton/directive.js b/www/addons/mod/data/fields/radiobutton/directive.js
new file mode 100644
index 00000000000..86eaf2bd78f
--- /dev/null
+++ b/www/addons/mod/data/fields/radiobutton/directive.js
@@ -0,0 +1,42 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data radiobutton field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldRadiobutton
+ */
+.directive('mmaModDataFieldRadiobutton', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/radiobutton/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ return;
+ }
+
+ scope.options = scope.field.param1.split("\n");
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.val = scope.value.content;
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/radiobutton/handler.js b/www/addons/mod/data/fields/radiobutton/handler.js
new file mode 100644
index 00000000000..93fd7d5d740
--- /dev/null
+++ b/www/addons/mod/data/fields/radiobutton/handler.js
@@ -0,0 +1,117 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for radiobutton data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldRadiobuttonHandler
+ */
+.factory('$mmaModDataFieldRadiobuttonHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+
+ if (inputData[fieldName]) {
+ return [{
+ fieldid: field.id,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldRadiobutton', 'radiobutton', '$mmaModDataFieldRadiobuttonHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/radiobutton/template.html b/www/addons/mod/data/fields/radiobutton/template.html
new file mode 100644
index 00000000000..0966a1b3f34
--- /dev/null
+++ b/www/addons/mod/data/fields/radiobutton/template.html
@@ -0,0 +1,9 @@
+
+{{ error }}
+
+
+
+{{ value.content }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/text/directive.js b/www/addons/mod/data/fields/text/directive.js
new file mode 100644
index 00000000000..18bdb2c3362
--- /dev/null
+++ b/www/addons/mod/data/fields/text/directive.js
@@ -0,0 +1,37 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data text field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldText
+ */
+.directive('mmaModDataFieldText', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/text/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.val = scope.value.content;
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/text/handler.js b/www/addons/mod/data/fields/text/handler.js
new file mode 100644
index 00000000000..909a1e2b92c
--- /dev/null
+++ b/www/addons/mod/data/fields/text/handler.js
@@ -0,0 +1,116 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for text data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldTextHandler
+ */
+.factory('$mmaModDataFieldTextHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ fieldid: field.id,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldText', 'text', '$mmaModDataFieldTextHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/text/template.html b/www/addons/mod/data/fields/text/template.html
new file mode 100644
index 00000000000..3fe5aa19cba
--- /dev/null
+++ b/www/addons/mod/data/fields/text/template.html
@@ -0,0 +1,4 @@
+
+{{ error }}
+
+{{ value.content }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/textarea/directive.js b/www/addons/mod/data/fields/textarea/directive.js
new file mode 100644
index 00000000000..66662e9d2ad
--- /dev/null
+++ b/www/addons/mod/data/fields/textarea/directive.js
@@ -0,0 +1,63 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.filter('mmaModDataFieldTextareaFormat', function($mmText) {
+ return function(value) {
+ var files = (value && value.files) || [];
+ return value ? $mmText.replacePluginfileUrls(value.content, files) : '';
+ };
+})
+
+/**
+ * Directive to render data textarea field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldTextarea
+ */
+.directive('mmaModDataFieldTextarea', function($mmText, mmaModDataComponent) {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/textarea/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+ if (scope.mode == 'show') {
+ scope.component = mmaModDataComponent;
+ scope.componentId = scope.database.coursemodule;
+ return;
+ }
+
+ // Check if rich text editor is enabled.
+ if (scope.mode == 'edit') {
+ var files = (scope.value && scope.value.files) || [],
+ text = scope.value ? $mmText.replacePluginfileUrls(scope.value.content, files) : "";
+
+ // Get the text.
+ scope.model = {
+ text: text
+ };
+
+ scope.firstRender = function() {
+ if (!scope.value) {
+ scope.value = {};
+ }
+ scope.value.content = scope.model.text;
+ };
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/textarea/handler.js b/www/addons/mod/data/fields/textarea/handler.js
new file mode 100644
index 00000000000..0e04c8951ae
--- /dev/null
+++ b/www/addons/mod/data/fields/textarea/handler.js
@@ -0,0 +1,168 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for textarea data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldTextareaHandler
+ */
+.factory('$mmaModDataFieldTextareaHandler', function($mmText, $mmUtil, $translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return $mmUtil.isRichTextEditorEnabled().then(function(enabled) {
+ var files = self.getFieldEditFiles(field, inputData, originalFieldData),
+ text = $mmText.restorePluginfileUrls(inputData[fieldName], files);
+
+ if (!enabled) {
+ // Rich text editor not enabled, add some HTML to the text if needed.
+ text = $mmText.formatHtmlLines(text);
+ }
+
+ return [{
+ fieldid: field.id,
+ value: text
+ },
+ {
+ fieldid: field.id,
+ subfield: 'content1',
+ value: 1
+ },
+ {
+ fieldid: field.id,
+ subfield: 'itemid',
+ files: files
+ }
+ ];
+ });
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit files in the input data.
+ *
+ * @param {Object} field Defines the field..
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Promise} With name and value of the data to be sent.
+ */
+ self.getFieldEditFiles = function(field, inputData, originalFieldData) {
+ return (originalFieldData && originalFieldData.files) || [];
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required) {
+ if (!inputData || !inputData.length) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ var found = false;
+ for (var x in inputData) {
+ if (!inputData[x].subfield) {
+ found = inputData[x].value;
+ break;
+ }
+ }
+
+ if (!found) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ if (originalContent.content.length > 0 && originalContent.files && originalContent.files.length > 0) {
+ // Take the original files since we cannot edit them on the app.
+ originalContent.content = $mmText.replacePluginfileUrls(originalContent.content, originalContent.files);
+ }
+
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldTextarea', 'textarea', '$mmaModDataFieldTextareaHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/textarea/template.html b/www/addons/mod/data/fields/textarea/template.html
new file mode 100644
index 00000000000..4260325d1a6
--- /dev/null
+++ b/www/addons/mod/data/fields/textarea/template.html
@@ -0,0 +1,7 @@
+
+{{ error }}
+
+
+
+
+{{ value | mmaModDataFieldTextareaFormat }}
\ No newline at end of file
diff --git a/www/addons/mod/data/fields/url/directive.js b/www/addons/mod/data/fields/url/directive.js
new file mode 100644
index 00000000000..5306dbd9904
--- /dev/null
+++ b/www/addons/mod/data/fields/url/directive.js
@@ -0,0 +1,37 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Directive to render data url field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc directive
+ * @name mmaModDataFieldUrl
+ */
+.directive('mmaModDataFieldUrl', function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ templateUrl: 'addons/mod/data/fields/url/template.html',
+ link: function(scope) {
+ scope.mode = scope.mode == 'list' ? 'show' : scope.mode;
+
+ if (scope.mode == 'edit' && scope.value) {
+ scope.val = scope.value.content;
+ }
+ }
+ };
+});
diff --git a/www/addons/mod/data/fields/url/handler.js b/www/addons/mod/data/fields/url/handler.js
new file mode 100644
index 00000000000..8719873723f
--- /dev/null
+++ b/www/addons/mod/data/fields/url/handler.js
@@ -0,0 +1,116 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Handler for url data field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldUrlHandler
+ */
+.factory('$mmaModDataFieldUrlHandler', function($translate) {
+
+ var self = {};
+
+ /**
+ * Get field search data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ name: fieldName,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field edit data in the input data.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {Array} With name and value of the data to be sent.
+ */
+ self.getFieldEditData = function(field, inputData) {
+ var fieldName = 'f_' + field.id;
+ if (inputData[fieldName]) {
+ return [{
+ fieldid: field.id,
+ value: inputData[fieldName]
+ }];
+ }
+ return false;
+ };
+
+ /**
+ * Get field data in changed.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Boolean} If the field has changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var fieldName = 'f_' + field.id,
+ input = inputData[fieldName] || "";
+ originalFieldData = (originalFieldData && originalFieldData.content) || "";
+
+ return input != originalFieldData;
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
+ return $translate.instant('mma.mod_data.errormustsupplyvalue');
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(originalContent, offlineContent) {
+ originalContent.content = offlineContent[''] || "";
+ return originalContent;
+ };
+
+ return self;
+})
+
+.run(function($mmAddonManager) {
+ // Use addon manager to inject $mmaModDataFieldsDelegate. This is to provide an example for remote addons,
+ // since they cannot assume that the data addon will be packaged in custom apps.
+ var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ if ($mmaModDataFieldsDelegate) {
+ $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldUrl', 'url', '$mmaModDataFieldUrlHandler');
+ }
+});
diff --git a/www/addons/mod/data/fields/url/template.html b/www/addons/mod/data/fields/url/template.html
new file mode 100644
index 00000000000..cd181b6fd86
--- /dev/null
+++ b/www/addons/mod/data/fields/url/template.html
@@ -0,0 +1,3 @@
+
+
+{{field.name}}
diff --git a/www/addons/mod/data/lang/ar.json b/www/addons/mod/data/lang/ar.json
new file mode 100644
index 00000000000..241c0dfb51c
--- /dev/null
+++ b/www/addons/mod/data/lang/ar.json
@@ -0,0 +1,31 @@
+{
+ "addentries": "أضف مدخلات",
+ "advancedsearch": "بحث متقدم",
+ "alttext": "النص البديل",
+ "approve": "اسمح/وافق",
+ "approved": "تم الموافقة",
+ "ascending": "تصاعدي",
+ "authorfirstname": "الاسم الأول للكاتب",
+ "authorlastname": "الاسم الأخير للكاتب",
+ "confirmdeleterecord": "هل فعلا ترغب في حذف هذا السجل؟",
+ "descending": "تنازليا",
+ "emptyaddform": "لم تقم بتعبئة الحقول!",
+ "expired": "عذراً، تم إغلاق هذا النشاط في {{$a}} وهو غير متوفر الآن.",
+ "fields": "حقول",
+ "menuchoose": "اختار",
+ "more": "المزيد",
+ "nomatch": "لم يتم العثور على مدخلات مطابقة!",
+ "norecords": "لا يوجد مدخلات في قاعدة البيانات",
+ "notapproved": "لم يتم الموافقة على المدخل بعد",
+ "notopenyet": "عذراً، هذا النشاط لن يتاح حتى {{$a}}",
+ "numrecords": "{{$a}} سجلات",
+ "other": "اخر",
+ "recordapproved": "تم الموافقه على السجل",
+ "recorddeleted": "تم حذف السجل",
+ "resetsettings": "إعادة تعين الحقول",
+ "search": "بحث",
+ "selectedrequired": "كل المختار مطلوب",
+ "timeadded": "وقت الإضافة",
+ "timemodified": "وقت التعديل",
+ "usedate": "تضمين في البحث"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/bg.json b/www/addons/mod/data/lang/bg.json
new file mode 100644
index 00000000000..2210bbfe18e
--- /dev/null
+++ b/www/addons/mod/data/lang/bg.json
@@ -0,0 +1,35 @@
+{
+ "addentries": "Добавяне на записи",
+ "advancedsearch": "Разширено търсене",
+ "alttext": "Алтернативен текст",
+ "approve": "Одобрение",
+ "approved": "Одобрен",
+ "ascending": "По нарастване",
+ "authorfirstname": "Име на автора",
+ "authorlastname": "Презиме на автора",
+ "confirmdeleterecord": "Сигурни ли сте, че искате да изтриете това?",
+ "descending": "По намаляване",
+ "disapprove": "Отхвърляне на одобрение",
+ "emptyaddform": "Не сте попълнили никакви полета!",
+ "entrieslefttoadd": "Трябва да добавите още {{$a.entriesleft}} записи, за да завършите тази дейност",
+ "entrieslefttoaddtoview": "Трябва да добавите още {{$a.entrieslefttoview}} записи преди да можете да видите записите на другите участници.",
+ "expired": "За съжаление тази дейност е затворена в {{$a}} и вече не е достъпна",
+ "fields": "Полета",
+ "menuchoose": "Изберете...",
+ "more": "Още",
+ "nomatch": "Не са намерени съответстващи записи!",
+ "norecords": "Няма записи в базата данни",
+ "notapproved": "Записът още не е качен",
+ "notopenyet": "За съжаление тази дейност не е достъпна от {{$a}}",
+ "numrecords": "{{$a}} записи",
+ "other": "Друго",
+ "recordapproved": "Записът качен",
+ "recorddeleted": "Записът изтрит",
+ "recorddisapproved": "Записът не е одобрен",
+ "resetsettings": "Нулиране на филтрите",
+ "search": "Търсене",
+ "selectedrequired": "Всичко избрано се изисква",
+ "timeadded": "Време на добавяне",
+ "timemodified": "Време на промяна",
+ "usedate": "Включване в търсене."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/ca.json b/www/addons/mod/data/lang/ca.json
new file mode 100644
index 00000000000..fc0c0d549bd
--- /dev/null
+++ b/www/addons/mod/data/lang/ca.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Afegeix entrades",
+ "advancedsearch": "Cerca avançada",
+ "alttext": "Text alternatiu",
+ "approve": "Aprova",
+ "approved": "Acceptat",
+ "ascending": "Ascendent",
+ "authorfirstname": "Nom de l'autor/autora",
+ "authorlastname": "Cognoms de l'autor/autora",
+ "confirmdeleterecord": "Segur que voleu suprimir aquesta entrada?",
+ "descending": "Descendent",
+ "disapprove": "Desfés l'aprovació",
+ "emptyaddform": "No heu emplenat cap camp",
+ "entrieslefttoadd": "Heu d'afegir {{$a.entriesleft}} una entrada o més per completar aquesta activitat",
+ "entrieslefttoaddtoview": "Heu d'afegir {{$a.entrieslefttoview}} una entrada o més abans que pugueu veure les entrades d'altres participants",
+ "errormustsupplyvalue": "Cal que poseu un valor aquí.",
+ "expired": "Aquesta activitat es va tancar el dia {{$a}} i ja no està disponible",
+ "fields": "Camps",
+ "latlongboth": "Cal posar tant la latitud com la longitud.",
+ "menuchoose": "Trieu...",
+ "more": "Més",
+ "nomatch": "No s'han trobat entrades que coincideixin",
+ "norecords": "No hi ha entrades en la base de dades",
+ "notapproved": "L'entrada encara no està aprovada.",
+ "notopenyet": "Aquesta activitat no estarà disponible fins al dia {{$a}}",
+ "numrecords": "{{$a}} entrades",
+ "other": "Un altre",
+ "recordapproved": "S'ha aprovat l'entrada",
+ "recorddeleted": "S'ha suprimit l'entrada",
+ "recorddisapproved": "Entrada no aprovada",
+ "resetsettings": "Reinicialitza els filtres",
+ "search": "Cerca",
+ "selectedrequired": "Cal que estigui tot seleccionat",
+ "timeadded": "Hora de la incorporació",
+ "timemodified": "Hora de la modificació",
+ "usedate": "Inclou en la cerca."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/cs.json b/www/addons/mod/data/lang/cs.json
new file mode 100644
index 00000000000..8430a087b16
--- /dev/null
+++ b/www/addons/mod/data/lang/cs.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Přidat záznamy",
+ "advancedsearch": "Pokročilé vyhledávání",
+ "alttext": "Alternativní text",
+ "approve": "Schválit",
+ "approved": "Schváleno",
+ "ascending": "Vzestupně",
+ "authorfirstname": "Křestní jméno autora",
+ "authorlastname": "Příjmení autora",
+ "confirmdeleterecord": "Chcete skutečně odstranit tento záznam?",
+ "descending": "Sestupně",
+ "disapprove": "Odvolat schválení",
+ "emptyaddform": "Nevyplnili jste žádná pole!",
+ "entrieslefttoadd": "Ještě musíte vložit {{$a.entriesleft}} záznamů(-y), abyste dokončili tuto činnost",
+ "entrieslefttoaddtoview": "Ještě musíte vložit {{$a.entrieslefttoview}} záznamů(-y), než budete moci vidět záznamy ostatních účastníků.",
+ "errormustsupplyvalue": "Musí obsahovat nějakou hodnotu.",
+ "expired": "Tato činnost byla ukončena {{$a}} a není již nadále dostupná.",
+ "fields": "Pole",
+ "latlongboth": "Je požadována zeměpisná šířka i délka.",
+ "menuchoose": "Vybrat...",
+ "more": "Podrobněji",
+ "nomatch": "Nenalezeny žádné záznamy!",
+ "norecords": "Nejsou k dispozici žádné záznamy",
+ "notapproved": "Záznam není zatím schválen",
+ "notopenyet": "Tato činnost nebude dostupná až do {{$a}}",
+ "numrecords": "{{$a}} záznamů",
+ "other": "Jiné",
+ "recordapproved": "Záznam byl schválen",
+ "recorddeleted": "Záznam byl smazán",
+ "recorddisapproved": "Neschválený záznam",
+ "resetsettings": "Resetovat filtry",
+ "search": "Vyhledat",
+ "selectedrequired": "Všechna zvolená povinná",
+ "timeadded": "Čas vložení",
+ "timemodified": "Čas poslední úpravy",
+ "usedate": "Zahrnout do vyhledávání."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/da.json b/www/addons/mod/data/lang/da.json
new file mode 100644
index 00000000000..6509111b86e
--- /dev/null
+++ b/www/addons/mod/data/lang/da.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Tilføj indlæg",
+ "advancedsearch": "Avanceret søgning",
+ "alttext": "Alternativ tekst",
+ "approve": "Godkend",
+ "approved": "Godkendt",
+ "ascending": "Stigende",
+ "authorfirstname": "Forfatterens fornavn",
+ "authorlastname": "Forfatterens efternavn",
+ "confirmdeleterecord": "Er du sikker på at du vil slette denne post?",
+ "descending": "Faldende",
+ "disapprove": "Fortryd godkendelse",
+ "emptyaddform": "Du udfyldte ingen felter!",
+ "entrieslefttoadd": "Du mangler at tilføje {{$a.entriesleft}} post(er) til denne database.",
+ "entrieslefttoaddtoview": "Du skal tilføje {{$a.entrieslefttoview}} post(er mere) til denne database før du kan se andre deltageres bidrag.",
+ "errormustsupplyvalue": "Du skal indsætte en værdi her.",
+ "expired": "Beklager, denne aktivitet lukkede {{$a}} og er ikke længere tilgængelig",
+ "fields": "Felter",
+ "latlongboth": "Skriv både bredde- og længdegrad",
+ "menuchoose": "Vælg...",
+ "more": "Flere",
+ "nomatch": "Ingen passende indlæg fundet",
+ "norecords": "Ingen indlæg i databasen",
+ "notapproved": "Posten er ikke godkendt endnu.",
+ "notopenyet": "Beklager, denne aktivitet er først tilgængelig {{$a}}",
+ "numrecords": "{{$a}} poster",
+ "other": "Anden",
+ "recordapproved": "Post godkendt",
+ "recorddeleted": "Posten er slettet",
+ "recorddisapproved": "Posten er ikke godkendt",
+ "resetsettings": "Nulstil filtre",
+ "search": "Søg",
+ "selectedrequired": "Alle valgte er påkrævet",
+ "timeadded": "Tilføjet",
+ "timemodified": "Ændret",
+ "usedate": "Inkluder i søgning."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/de.json b/www/addons/mod/data/lang/de.json
new file mode 100644
index 00000000000..f9e7fff488f
--- /dev/null
+++ b/www/addons/mod/data/lang/de.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Einträge hinzufügen",
+ "advancedsearch": "Erweiterte Suche",
+ "alttext": "Alternativer Text",
+ "approve": "Zulassen",
+ "approved": "Bestätigt",
+ "ascending": "Aufsteigend",
+ "authorfirstname": "Vorname (Autor)",
+ "authorlastname": "Nachname (Autor)",
+ "confirmdeleterecord": "Möchten Sie diesen Datensatz wirklich in der Datenbank löschen?",
+ "descending": "Absteigend",
+ "disapprove": "Eintrag nicht freigegeben",
+ "emptyaddform": "Sie haben keine Einträge vorgenommen!",
+ "entrieslefttoadd": "Sie müssen {{$a.entriesleft}} (weitere) Einträge vornehmen, um diese Aktivität zu beenden.",
+ "entrieslefttoaddtoview": "Sie müssen {{$a.entrieslefttoview}} (weitere) Einträge vornehmen, bevor Sie andere Teilnehmerbeiträge betrachten können.",
+ "errorapproving": "Fehler beim Freigeben bzw. Ablehnen des Eintrags",
+ "errordeleting": "Fehler beim Löschen des Eintrags",
+ "errormustsupplyvalue": "Sie müssen hier einen Wert eintragen.",
+ "expired": "Die Aktivität wurde am {{$a}} abgeschlossen und ist nicht weiter verfügbar.",
+ "fields": "Felder",
+ "latlongboth": "Längen- und Breitengrad müssen eingetragen werden.",
+ "menuchoose": "Auswählen ...",
+ "more": "Einzelansicht",
+ "nomatch": "Keine passenden Einträge gefunden",
+ "norecords": "Keine Einträge in der Datenbank",
+ "notapproved": "Der Eintrag wurde bisher nicht freigegeben",
+ "notopenyet": "Die Aktivität ist nicht verfügbar bis {{$a}}.",
+ "numrecords": "{{$a}} Datensätze",
+ "other": "Andere",
+ "recordapproved": "Datensatz wurde angenommen",
+ "recorddeleted": "Datensatz gelöscht",
+ "recorddisapproved": "Eintrag nicht freigegeben",
+ "resetsettings": "Filter zurücksetzen",
+ "search": "Suche",
+ "selectedrequired": "Gesamte Auswahl ist erforderlich",
+ "timeadded": "Zeit erstellt",
+ "timemodified": "Zeit geändert",
+ "usedate": "In Suche einbeziehen"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/el.json b/www/addons/mod/data/lang/el.json
new file mode 100644
index 00000000000..8afbe5fdcc4
--- /dev/null
+++ b/www/addons/mod/data/lang/el.json
@@ -0,0 +1,31 @@
+{
+ "addentries": "Προσθήκη καταχωρήσεων",
+ "advancedsearch": "Advanced search",
+ "alttext": "Εναλλακτικό κείμενο",
+ "approve": "Έγκριση",
+ "approved": "Εγκρίθηκε",
+ "ascending": "Αύξουσα",
+ "authorfirstname": "Όνομα συγγραφέα",
+ "authorlastname": "Επίθετο συγγραφέα",
+ "confirmdeleterecord": "Σίγουρα θέλετε να διαγραφεί αυτή η καταχώρηση;",
+ "descending": "Φθίνουσα",
+ "emptyaddform": "Δεν συμπληρώσατε κανένα από τα πεδία!",
+ "entrieslefttoadd": "Πρέπει να προσθέσετε {{$a.entriesleft}} περισσότερες καταχωρήσεις ώστε να ολοκληρώσετε αυτήν τη δραστηριότητα",
+ "entrieslefttoaddtoview": "Πρέπει να προσθέσετε {{$a.entrieslefttoview}} περισσότερες καταχωρήσεις πριν να μπορέσετε να δείτε τις καταχωρήσεις άλλων χρηστών.",
+ "expired": "Η δραστηριότητα αυτή έκλεισε στις {{$a}} και δεν είναι πλέον διαθέσιμη",
+ "fields": "Πεδία",
+ "menuchoose": "Επιλέξτε....",
+ "more": "Περισσότερα",
+ "nomatch": "Δεν βρέθηκαν καταχωρήσεις που να ταιριάζουν!",
+ "norecords": "Δεν υπάρχουν καταχωρήσεις στη βάση δεδομένων",
+ "notopenyet": "Συγνώμη, αυτή η δραστηριότητα δεν είναι διαθέσιμη μέχρι {{$a}}",
+ "numrecords": "{{$a}} καταχωρήσεις",
+ "other": "Άλλο",
+ "recordapproved": "Η καταχώρηση εγκρίθηκε",
+ "recorddeleted": "Η καταχώρηση διαγράφθηκε",
+ "resetsettings": "Επανορισμός φίλτρων",
+ "search": "Αναζήτηση",
+ "selectedrequired": "Απαιτούνται όλα τα επιλεγμένα",
+ "timeadded": "Προστέθηκε χρόνος",
+ "timemodified": "Ο χρόνος μεταβλήθηκε"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/en.json b/www/addons/mod/data/lang/en.json
new file mode 100644
index 00000000000..8ad92b9ec45
--- /dev/null
+++ b/www/addons/mod/data/lang/en.json
@@ -0,0 +1,41 @@
+{
+ "addentries": "Add entries",
+ "advancedsearch": "Advanced search",
+ "alttext": "Alternative text",
+ "approve": "Approve",
+ "approved": "Approved",
+ "authorfirstname": "Author first name",
+ "authorlastname": "Author surname",
+ "ascending": "Ascending",
+ "authorfirstname": "Author first name",
+ "authorlastname": "Author surname",
+ "confirmdeleterecord": "Are you sure you want to delete this entry?",
+ "descending": "Descending",
+ "disapprove": "Undo approval",
+ "emptyaddform": "You did not fill out any fields!",
+ "entrieslefttoadd": "You must add {{$a.entriesleft}} more entry/entries in order to complete this activity",
+ "entrieslefttoaddtoview": "You must add {{$a.entrieslefttoview}} more entry/entries before you can view other participants' entries.",
+ "errorapproving": "Error approving or unapproving entry.",
+ "errordeleting": "Error deleting the entry.",
+ "errormustsupplyvalue": "You must supply a value here.",
+ "expired": "Sorry, this activity closed on {{$a}} and is no longer available",
+ "fields": "Fields",
+ "latlongboth": "Both latitude and longitude are required.",
+ "menuchoose": "Choose...",
+ "more": "More",
+ "nomatch": "No matching entries found!",
+ "norecords": "No entries in database",
+ "notapproved": "Entry is not approved yet.",
+ "notopenyet": "Sorry, this activity is not available until {{$a}}",
+ "numrecords": "{{$a}} entries",
+ "other": "Other",
+ "recordapproved": "Entry approved",
+ "recorddeleted": "Entry deleted",
+ "recorddisapproved": "Entry unapproved",
+ "resetsettings": "Reset filters",
+ "search": "Search",
+ "selectedrequired": "All selected required",
+ "timeadded": "Time added",
+ "timemodified": "Time modified",
+ "usedate": "Include in search."
+}
diff --git a/www/addons/mod/data/lang/es-mx.json b/www/addons/mod/data/lang/es-mx.json
new file mode 100644
index 00000000000..44cb6f922de
--- /dev/null
+++ b/www/addons/mod/data/lang/es-mx.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Añadir entradas",
+ "advancedsearch": "Búsqueda avanzada",
+ "alttext": "Texto alternativo",
+ "approve": "Aprobar",
+ "approved": "Aprobado",
+ "ascending": "Ascendente",
+ "authorfirstname": "Nombre del autor",
+ "authorlastname": "Apellidos del autor",
+ "confirmdeleterecord": "¿Está seguro de que desea eliminar esta entrada?",
+ "descending": "Descendente",
+ "disapprove": "Deshacer aprobación",
+ "emptyaddform": "¡No ha rellenado ningún campo!",
+ "entrieslefttoadd": "Debe añadir {{$a.entriesleft}} entrada(s) más antes de poder ver las entradas de otro participante.",
+ "entrieslefttoaddtoview": "Debe añadir {{$a.entrieslefttoview}} entrada(s) antes de poder ver las entradas de otros participantes.",
+ "errorapproving": "Error al aprobar o des_aprobar una entrada.",
+ "errordeleting": "Error al eliminar la entrada.",
+ "errormustsupplyvalue": "Usted debe proporcionar un valor aquí.",
+ "expired": "Lo sentimos, esta actividad se cerró el {{$a}} y ya no está disponible",
+ "fields": "Campos",
+ "latlongboth": "Tanto la Latitud como la Longitud son necesarias.",
+ "menuchoose": "Seleccionar...",
+ "more": "Más",
+ "nomatch": "No se han encontrado entradas",
+ "norecords": "No entradas en la base de datos",
+ "notapproved": "La entrada aún no ha sido aprobada.",
+ "notopenyet": "Lo sentimos, esta actividad no está disponible hasta {{$a}}",
+ "numrecords": "{{$a}} entradas",
+ "other": "Otro",
+ "recordapproved": "Entrada aprobada",
+ "recorddeleted": "Entrada eliminada",
+ "recorddisapproved": "Entrada desaprobada",
+ "resetsettings": "Restablecer filtros",
+ "search": "Buscar",
+ "selectedrequired": "Se requieren todos los seleccionados",
+ "timeadded": "Tiempo añadido",
+ "timemodified": "Tiempo modificado",
+ "usedate": "Incluir en búsqueda."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/es.json b/www/addons/mod/data/lang/es.json
new file mode 100644
index 00000000000..f03697158fa
--- /dev/null
+++ b/www/addons/mod/data/lang/es.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Añadir entradas",
+ "advancedsearch": "Búsqueda avanzada",
+ "alttext": "Texto alternativo",
+ "approve": "Aprobar",
+ "approved": "Aprobado",
+ "ascending": "Ascendente",
+ "authorfirstname": "Nombre del autor",
+ "authorlastname": "Apellido del autor",
+ "confirmdeleterecord": "¿Está seguro de que desea eliminar esta entrada?",
+ "descending": "Descendente",
+ "disapprove": "Desaprobar",
+ "emptyaddform": "¡No ha rellenado ningún campo!",
+ "entrieslefttoadd": "Debe agregar {{$a.entriesleft}} entrada(s) más para poder finalizar esta actividad",
+ "entrieslefttoaddtoview": "Debe añadir {{$a.entrieslefttoview}} entrada(s) antes de poder ver las entradas de otros participantes.",
+ "errormustsupplyvalue": "Debe proporcionar un valor aquí.",
+ "expired": "Lo sentimos, esta actividad se cerró el {{$a}} y ya no está disponible",
+ "fields": "Campos",
+ "latlongboth": "Tanto la latitud como la longitud son necesarias.",
+ "menuchoose": "Seleccionar...",
+ "more": "Más",
+ "nomatch": "No se han encontrado entradas",
+ "norecords": "No hay entradas en la base de datos",
+ "notapproved": "La entrada aún no ha sido aprobada.",
+ "notopenyet": "Lo sentimos, esta actividad no está disponible hasta {{$a}}",
+ "numrecords": "{{$a}} entradas",
+ "other": "Otro",
+ "recordapproved": "Entrada aprobada",
+ "recorddeleted": "Entrada eliminada",
+ "recorddisapproved": "Entrada desaprobada",
+ "resetsettings": "Restablecer filtros",
+ "search": "Buscar",
+ "selectedrequired": "Se requieren todos los seleccionados",
+ "timeadded": "Tiempo añadido",
+ "timemodified": "Tiempo modificado",
+ "usedate": "Incluir en la búsqueda"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/eu.json b/www/addons/mod/data/lang/eu.json
new file mode 100644
index 00000000000..e7e02cdd912
--- /dev/null
+++ b/www/addons/mod/data/lang/eu.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Gehitu sarrerak",
+ "advancedsearch": "Bilaketa aurreratua",
+ "alttext": "Ordezko testua",
+ "approve": "Onartu",
+ "approved": "Onartuta",
+ "ascending": "Goranzkoa",
+ "authorfirstname": "Egilearen izena",
+ "authorlastname": "Egilearen deitura",
+ "confirmdeleterecord": "Ziur al zaude sarrera hau ezabatu nahi duzula?",
+ "descending": "Beheranzkoa",
+ "disapprove": "Onarpena desegin",
+ "emptyaddform": "Ez duzu eremuren bat bete!",
+ "entrieslefttoadd": "{{$a.entriesleft}} sarrera gehiago gehitu behar dituzu jarduera hau osatzeko.",
+ "entrieslefttoaddtoview": "{{$a.entrieslefttoview}} sarrera gehiago gehitu behar dituzu beste partaideen sarrerak ikusi ahal izateko.",
+ "errormustsupplyvalue": "Hemen balio bat eman behar duzu.",
+ "expired": "Barkatu, jarduera hau {{$a}} datan itxi zen eta dagoeneko ez dago eskuragarri",
+ "fields": "Eremuak",
+ "latlongboth": "Latitudea eta longitudea beharrekoak dira.",
+ "menuchoose": "Aukeratu...",
+ "more": "Gehiago",
+ "nomatch": "Ez da sarrera egokirik aurkitu!",
+ "norecords": "Datu-basean sarrerarik ez",
+ "notapproved": "Sarrera ez da oraindik onartu",
+ "notopenyet": "Barkatu, jarduera hau ez dago eskuragarri {{$a}} arte",
+ "numrecords": "{{$a}} sarrera(k)",
+ "other": "Beste bat",
+ "recordapproved": "Sarrera onartu da",
+ "recorddeleted": "Sarrera ezabatu da",
+ "recorddisapproved": "Onartu gabeko sarrera",
+ "resetsettings": "Berrabiarazi iragazkiak",
+ "search": "Bilatu",
+ "selectedrequired": "Aukeratutako guztia beharrezkoa",
+ "timeadded": "Denbora gehituta",
+ "timemodified": "Denbora aldatuta",
+ "usedate": "Sartu bilaketan."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/fa.json b/www/addons/mod/data/lang/fa.json
new file mode 100644
index 00000000000..c6a248a09b0
--- /dev/null
+++ b/www/addons/mod/data/lang/fa.json
@@ -0,0 +1,32 @@
+{
+ "addentries": "دادههایی را اضافه کنید",
+ "advancedsearch": "جستجوی پیشرفته",
+ "alttext": "متن جایگزین",
+ "approve": "تایید",
+ "approved": "وضعیت تایید",
+ "ascending": "صعودی",
+ "authorfirstname": "نام وارد کننده",
+ "authorlastname": "نام خانوادگی وارد کننده",
+ "confirmdeleterecord": "آیا مطمئن هستید که میخواهید این مورد را حذف کنید؟",
+ "descending": "نزولی",
+ "emptyaddform": "شما هیچ فیلدی را پر نکردید!",
+ "entrieslefttoadd": "برای کامل کردن این فعالیت باید {{$a.entriesleft}} دادهٔ دیگر وارد کنید",
+ "entrieslefttoaddtoview": "باید {{$a.entrieslefttoview}} دادهٔ دیگر وارد کنید تا بتوانید دادههای وارد شده توسط سایرین را ببینید.",
+ "expired": "متأسفیم، این فعالیت در {{$a}} بسته شد و دیگر در دسترس نیست",
+ "fields": "فیلدها",
+ "menuchoose": "انتخاب کنید...",
+ "more": "نمایش جزئیات",
+ "nomatch": "دادهٔ مطابقی پیدا نشد!",
+ "norecords": "بانک اطلاعاتی خالی است",
+ "notapproved": "دادهٔ ورودی هنوز تایید نشده است.",
+ "notopenyet": "با عرض پوزش، این فعالیت تا قبل از {{$a}} در دسترس نیست",
+ "numrecords": "{{$a}} دادهٔ ورودی",
+ "other": "غیره",
+ "recordapproved": "دادهٔ ورودی تایید شد",
+ "recorddeleted": "حذف شد",
+ "resetsettings": "بازنشانی فیلترها",
+ "search": "جستجو",
+ "selectedrequired": "تمامی گزینههای انتخاب شده لازم هستند",
+ "timeadded": "زمان اضافه شدن",
+ "timemodified": "زمان آخرین تغییر"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/fr.json b/www/addons/mod/data/lang/fr.json
new file mode 100644
index 00000000000..d9c3b73be8e
--- /dev/null
+++ b/www/addons/mod/data/lang/fr.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Ajouter des fiches",
+ "advancedsearch": "Recherche avancée",
+ "alttext": "Texte alternatif",
+ "approve": "Approuver",
+ "approved": "Approuvé",
+ "ascending": "Ascendant",
+ "authorfirstname": "Prénom auteur",
+ "authorlastname": "Nom auteur",
+ "confirmdeleterecord": "Voulez-vous vraiment supprimer cette fiche ?",
+ "descending": "Descendant",
+ "disapprove": "Retirer l'approbation",
+ "emptyaddform": "Vous n'avez rempli aucun champ !",
+ "entrieslefttoadd": "Vous devez ajouter encore {{$a.entriesleft}} fiches pour terminer cette activité",
+ "entrieslefttoaddtoview": "Vous devez ajouter encore {{$a.entrieslefttoview}} fiches avant de pouvoir consulter les fiches des autres participants.",
+ "errorapproving": "Erreur lors de l'approbation ou de la désapprobation de la fiche.",
+ "errordeleting": "Erreur lors de suppression de la fiche.",
+ "errormustsupplyvalue": "Veuillez renseigner une valeur.",
+ "expired": "Cette activité est fermée depuis {{$a}} et n'est plus disponible",
+ "fields": "Champs",
+ "latlongboth": "La latitude et la longitude sont requises.",
+ "menuchoose": "Sélectionner...",
+ "more": "Plus",
+ "nomatch": "Aucune fiche trouvée !",
+ "norecords": "Aucune fiche dans la base de données",
+ "notapproved": "La fiche n'est pas encore approuvée.",
+ "notopenyet": "Cette activité n'est pas disponible avant le {{$a}}",
+ "numrecords": "{{$a}} fiches",
+ "other": "Autre",
+ "recordapproved": "Fiche approuvée",
+ "recorddeleted": "Fiche supprimée",
+ "recorddisapproved": "Fiche désapprouvée",
+ "resetsettings": "Réinitialiser les filtres",
+ "search": "Recherche",
+ "selectedrequired": "Toute la sélection requise",
+ "timeadded": "Date ajout",
+ "timemodified": "Date modification",
+ "usedate": "Inclure dans la recherche."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/he.json b/www/addons/mod/data/lang/he.json
new file mode 100644
index 00000000000..e3495248234
--- /dev/null
+++ b/www/addons/mod/data/lang/he.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "הוספת פריטים",
+ "advancedsearch": "חיפוש מורחב",
+ "alttext": "תוכן חלופי",
+ "approve": "אישור",
+ "approved": "מאושר",
+ "ascending": "בסדר עולה",
+ "authorfirstname": "שם פרטי של המחבר",
+ "authorlastname": "שם משפחה של המחבר",
+ "confirmdeleterecord": "האם למחוק את הפריט הזה?",
+ "descending": "בסדר יורד",
+ "disapprove": "ביטול האישור",
+ "emptyaddform": "לא מילאת אף שדה!",
+ "entrieslefttoadd": "יש להזין {{$a.entriesleft}} פריטים נוספים בכדי להשלים פעילות זו",
+ "entrieslefttoaddtoview": "יש להזין {{$a.entrieslefttoview}} פריטים נוספים בכדי לראות פריטים של משתתפים אחרים.",
+ "errormustsupplyvalue": "יש להזין ערך בשדה זה.",
+ "expired": "מצטערים, פעילות זו נסגרה ב {{$a}} ואיננה זמינה יותר.",
+ "fields": "שדות",
+ "latlongboth": "נדרשים נתוני קו־רוחב וגם קו־אורך",
+ "menuchoose": "יש לבחור...",
+ "more": "עוד",
+ "nomatch": "לא נמצאו פריטים מתאימים!",
+ "norecords": "אין פריטים בבסיס הנתונים",
+ "notapproved": "הפריט עדיין לא אושר.",
+ "notopenyet": "מצטערים, פעילות זו איננה זמינה עד {{$a}} .",
+ "numrecords": "{{$a}} פריטים",
+ "other": "אחר",
+ "recordapproved": "הפריט אושר",
+ "recorddeleted": "הפריט נמחק",
+ "recorddisapproved": "הפריט לא מאושר",
+ "resetsettings": "איפוס שדות",
+ "search": "חיפוש",
+ "selectedrequired": "כל הנבחרים דרושים",
+ "timeadded": "זמן הוספה",
+ "timemodified": "זמן עדכון",
+ "usedate": "כלול בחיפוש"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/hu.json b/www/addons/mod/data/lang/hu.json
new file mode 100644
index 00000000000..a42ee251c97
--- /dev/null
+++ b/www/addons/mod/data/lang/hu.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Bejegyzések hozzáadása",
+ "advancedsearch": "Részletes keresés",
+ "alttext": "Alternatív szöveg",
+ "approve": "Jóváhagy",
+ "approved": "Jóváhagyva",
+ "ascending": "Növekvő",
+ "authorfirstname": "Szerző keresztneve",
+ "authorlastname": "Szerző vezetékneve",
+ "confirmdeleterecord": "Biztosan törölni akarja ezt a bejegyzést?",
+ "descending": "Csökkenő",
+ "disapprove": "Jóváhagyás elvetése",
+ "emptyaddform": "Nem töltött ki egy mezőt sem!",
+ "entrieslefttoadd": "A tevékenység befejezéséhez {{$a.entriesleft}} további tételt kell hozzáadnia.",
+ "entrieslefttoaddtoview": "Még {{$a.entrieslefttoview}} bejegyzést kell hozzáadnia, mielőtt megtekintheti más résztvevők bejegyzéseit.",
+ "errormustsupplyvalue": "Itt egy értéket kell megadnia.",
+ "expired": "A tevékenység {{$a}} időpontban lezárult és már nem érhető el.",
+ "fields": "Mezők",
+ "latlongboth": "Mind a szélesség, mind a hosszúság kitöltendő.",
+ "menuchoose": "Választás...",
+ "more": "Tovább",
+ "nomatch": "Nincs egyező fogalom!",
+ "norecords": "Nincsenek bejegyzések az adatbázisban",
+ "notapproved": "A bejegyzés még nincs jóváhagyva.",
+ "notopenyet": "A tevékenység {{$a}} időpontig nem elérhető.",
+ "numrecords": "{{$a}} bejegyzés",
+ "other": "Más",
+ "recordapproved": "Bejegyzés jóváhagyva",
+ "recorddeleted": "Bejegyzés törölve",
+ "recorddisapproved": "Nem jóváhagyott fogalom",
+ "resetsettings": "Szűrők visszaállítása",
+ "search": "Keresés",
+ "selectedrequired": "Minden kiválasztott szükséges",
+ "timeadded": "Időpont hozzáadva",
+ "timemodified": "Időpont módosult",
+ "usedate": "Keresésben szerepeljen."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/it.json b/www/addons/mod/data/lang/it.json
new file mode 100644
index 00000000000..81aa26d1e83
--- /dev/null
+++ b/www/addons/mod/data/lang/it.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Aggiungi record",
+ "advancedsearch": "Ricerca avanzata",
+ "alttext": "Testo alternativo",
+ "approve": "Approva",
+ "approved": "Approvato",
+ "ascending": "Crescente",
+ "authorfirstname": "Nome autore",
+ "authorlastname": "Cognome autore",
+ "confirmdeleterecord": "Stai per eliminare questo record. Ne sei certo?",
+ "descending": "Decrescente",
+ "disapprove": "Disapprova",
+ "emptyaddform": "Non hai riempito nessun campo!",
+ "entrieslefttoadd": "Per poter visualizzare i record inseriti dagli altri partecipanti è necessario inserire altri {{$a.entriesleft}} record.",
+ "entrieslefttoaddtoview": "Devi aggiungere {{$a.entrieslefttoview}} altri record prima di poter vedere i record degli altri partecipanti.",
+ "errormustsupplyvalue": "Devi inserire un valore.",
+ "expired": "Spiacente, l'attività non è più disponibile poiché è stata chiusa il {{$a}} ",
+ "fields": "Campi",
+ "latlongboth": "Devi compilare sia la latitudine sia la longitudine.",
+ "menuchoose": "Scegli...",
+ "more": "Dettagli",
+ "nomatch": "Non è stato trovato nessun record che corrisponda!",
+ "norecords": "Nessun record è presente nel Database",
+ "notapproved": "Il record inserito è in attesa di essere approvato.",
+ "notopenyet": "Spiacente, questa attività non sarà disponibile prima del {{$a}}",
+ "numrecords": "{{$a}} record",
+ "other": "Altro",
+ "recordapproved": "Record approvati",
+ "recorddeleted": "Il record è stato eliminato",
+ "recorddisapproved": "Record disapprovato",
+ "resetsettings": "Reimposta filtri",
+ "search": "Cerca",
+ "selectedrequired": "Necessari tutti i selezionati",
+ "timeadded": "Data/ora inserimento",
+ "timemodified": "Data/ora modifica",
+ "usedate": "Includi nella ricerca."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/ja.json b/www/addons/mod/data/lang/ja.json
new file mode 100644
index 00000000000..a779faabe27
--- /dev/null
+++ b/www/addons/mod/data/lang/ja.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "エントリを追加する",
+ "advancedsearch": "高度な検索",
+ "alttext": "代替テキスト",
+ "approve": "承認",
+ "approved": "承認日時",
+ "ascending": "昇順",
+ "authorfirstname": "著者の名",
+ "authorlastname": "著者の姓",
+ "confirmdeleterecord": "本当にこのエントリを削除してもよろしいですか?",
+ "descending": "降順",
+ "disapprove": "承認を取り消す",
+ "emptyaddform": "あなたはどのフィールドにも入力していません!",
+ "entrieslefttoadd": "この活動を完了するにはさらに {{$a.entriesleft}} 件以上のエントリを追加してください。",
+ "entrieslefttoaddtoview": "他の参加者のエントリを閲覧するにはさらに {{$a.entrieslefttoview}} 件以上のエントリを追加してください。",
+ "errormustsupplyvalue": "あなたはここで値を提供する必要があります。",
+ "expired": "申し訳ございません、この活動は {{$a}} に終了して利用することはできません。",
+ "fields": "フィールド",
+ "latlongboth": "緯度および経度の両方とも必須です。",
+ "menuchoose": "選択 ...",
+ "more": "詳細",
+ "nomatch": "該当するエントリが見つかりませんでした!",
+ "norecords": "データベースにエントリはありません。",
+ "notapproved": "エントリはまだ承認されていません。",
+ "notopenyet": "申し訳ございません、この活動は {{$a}} まで利用できません。",
+ "numrecords": "{{$a}} エントリ",
+ "other": "その他",
+ "recordapproved": "エントリが承認されました。",
+ "recorddeleted": "エントリが削除されました。",
+ "recorddisapproved": "エントリ未承認",
+ "resetsettings": "フィルタをリセットする",
+ "search": "検索",
+ "selectedrequired": "選択したすべてを含む",
+ "timeadded": "追加日時",
+ "timemodified": "修正日時",
+ "usedate": "検索に含む"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/lt.json b/www/addons/mod/data/lang/lt.json
new file mode 100644
index 00000000000..1c83b6faf07
--- /dev/null
+++ b/www/addons/mod/data/lang/lt.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Įtraukti įrašus",
+ "advancedsearch": "Išplėstinė paieška",
+ "alttext": "Alternatyvusis tekstas",
+ "approve": "Patvirtinti",
+ "approved": "Patvirtinta",
+ "ascending": "Didėjimo tvarka",
+ "authorfirstname": "Autoriaus vardas",
+ "authorlastname": "Autoriaus pavardė",
+ "confirmdeleterecord": "Ar tikrai norite naikinti šį įrašą?",
+ "descending": "Mažėjimo tvarka",
+ "disapprove": "Atšaukti patvirtinimą",
+ "emptyaddform": "Neužpildėte jokių laukų!",
+ "entrieslefttoadd": "Turite įtraukti dar {{$a.entriesleft}} įrašus (-ų), kad galėtumėte užbaigti šią veiklą",
+ "entrieslefttoaddtoview": "Turite įtraukti dar {{$a.entrieslefttoview}} įrašus (-ų), kad galėtumėte peržiūrėti kitų dalyvių įrašus.",
+ "errormustsupplyvalue": "Privalote pateikti reikšmę čia.",
+ "expired": "Apgailestaujame, ši veikla uždaryta {{$a}} ir nebegalima",
+ "fields": "Laukai",
+ "latlongboth": "Abu, platuma ir ilguma, yra privalomi.",
+ "menuchoose": "Pasirinkite...",
+ "more": "Daugiau",
+ "nomatch": "Nerasta atitinkančių įrašų!",
+ "norecords": "Duomenų bazėje nėra įrašų",
+ "notapproved": "Įrašas dar nepatvirtintas.",
+ "notopenyet": "Apgailestaujame, ši veikla negalima iki {{$a}}",
+ "numrecords": "{{$a}} įrašai (-ų)",
+ "other": "Kita",
+ "recordapproved": "Įrašas patvirtintas",
+ "recorddeleted": "Įrašas panaikintas",
+ "recorddisapproved": "Įrašas nepatvirtintas",
+ "resetsettings": "Nustatyti filtrus iš naujo",
+ "search": "Ieškoti",
+ "selectedrequired": "Visi pasirinkti būtini",
+ "timeadded": "Įtraukimo laikas",
+ "timemodified": "Modifikavimo laikas",
+ "usedate": "Įtraukti į paiešką."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/nl.json b/www/addons/mod/data/lang/nl.json
new file mode 100644
index 00000000000..deb0be88f87
--- /dev/null
+++ b/www/addons/mod/data/lang/nl.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Items goedkeuren",
+ "advancedsearch": "Geavanceerd zoeken",
+ "alttext": "Alternatieve tekst",
+ "approve": "Goedkeuren",
+ "approved": "Goedgekeurd",
+ "ascending": "Oplopend",
+ "authorfirstname": "Voornaam auteur",
+ "authorlastname": "Achternaam auteur",
+ "confirmdeleterecord": "Je gaat deze record verwijderen. Ben je zeker?",
+ "descending": "Aflopend",
+ "disapprove": "Verwerp",
+ "emptyaddform": "Je hebt geen velden ingevuld!",
+ "entrieslefttoadd": "Je moet {{$a.entriesleft}} meer item(s) ingeven voor je de items van anderen kunt zien.",
+ "entrieslefttoaddtoview": "je moet {{$a.entrieslefttoview}} items meer toevoegen voor je de items van anderen kan zien.",
+ "errorapproving": "Fout bij het goedkeuren of verwerpen van het nieuwe item.",
+ "errordeleting": "Fout bij het verwijderen van het item.",
+ "errormustsupplyvalue": "Je moet hier een waarde geven.",
+ "expired": "Deze activiteit is gesloten op {{$a}} en is niet langer beschikbaar",
+ "fields": "Velden",
+ "latlongboth": "Zowel de breedtegraad als de lengtegraad zijn vereist.",
+ "menuchoose": "Kies...",
+ "more": "Meer",
+ "nomatch": "Geen overeenkomende items gevonden",
+ "norecords": "Geen items in de databank",
+ "notapproved": "Item is nog niet goedgekeurd",
+ "notopenyet": "Deze actieviteit is niet beschikbaar tot {{$a}}",
+ "numrecords": "{{$a}} records",
+ "other": "Andere",
+ "recordapproved": "Item goedgekeurd",
+ "recorddeleted": "Record verwijderd",
+ "recorddisapproved": "Item verworpen",
+ "resetsettings": "Reset filters",
+ "search": "Zoek",
+ "selectedrequired": "Alle geselecteerde vereist",
+ "timeadded": "Toegevoegd op",
+ "timemodified": "Gewijzigd op",
+ "usedate": "Ook zoeken"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/pl.json b/www/addons/mod/data/lang/pl.json
new file mode 100644
index 00000000000..3d8d44e49c3
--- /dev/null
+++ b/www/addons/mod/data/lang/pl.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Dodaj wpisy",
+ "advancedsearch": "Wyszukiwanie zaawansowane",
+ "alttext": "Alternatywny tekst",
+ "approve": "Zatwierdź",
+ "approved": "Zatwierdzony",
+ "ascending": "Rosnąco",
+ "authorfirstname": "Imię autora",
+ "authorlastname": "Nazwisko autora",
+ "confirmdeleterecord": "Na pewno chcesz usunąć ten wpis?",
+ "descending": "Malejąco",
+ "disapprove": "Cofnij zatwierdzenie",
+ "emptyaddform": "Nie wypełniłeś wszystkich pól",
+ "entrieslefttoadd": "Musisz dodać {{$a.entriesleft}} więcej wpisów, aby zakończyć tą aktywność",
+ "entrieslefttoaddtoview": "Musisz dodać {{$a.entrieslefttoview}} więcej wpisów, aby móc wyświetlać wpisy innych użytkowników.",
+ "errormustsupplyvalue": "Musisz podać wartość tutaj.",
+ "expired": "Niestety, ta aktywność została zamknięta {{$a}} i nie jest już dłużej dostępna",
+ "fields": "Pola",
+ "latlongboth": "Wymagana jest zarówno szerokość i długość geograficzna.",
+ "menuchoose": "Wybierz...",
+ "more": "Więcej",
+ "nomatch": "Żaden wpis nie został znaleziony.",
+ "norecords": "Brak wpisów w bazie danych",
+ "notapproved": "Wpis nie jest jeszcze zatwierdzony.",
+ "notopenyet": "Niestety, ta aktywność jest niedostępna aż do {{$a}}",
+ "numrecords": "{{$a}} wpisów",
+ "other": "Inne",
+ "recordapproved": "Wpis zatwierdzony",
+ "recorddeleted": "Wpis usunięty",
+ "recorddisapproved": "Wpis odrzucony",
+ "resetsettings": "Resetuj pola",
+ "search": "Szukaj",
+ "selectedrequired": "Wszystkie zaznaczone są wymagane",
+ "timeadded": "Dodano czas",
+ "timemodified": "Zmodyfikowano czas",
+ "usedate": "Uwzględnij w wyszukiwaniu."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/pt-br.json b/www/addons/mod/data/lang/pt-br.json
new file mode 100644
index 00000000000..6574d31f4c8
--- /dev/null
+++ b/www/addons/mod/data/lang/pt-br.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Acrescentar itens",
+ "advancedsearch": "Busca avançada",
+ "alttext": "Texto alternativo",
+ "approve": "Aprovar",
+ "approved": "Aprovado",
+ "ascending": "Crescente",
+ "authorfirstname": "Nome do autor",
+ "authorlastname": "Sobrenome do autor",
+ "confirmdeleterecord": "Tem certeza que quer excluir este item?",
+ "descending": "Decrescente",
+ "disapprove": "Desfazer aprovação",
+ "emptyaddform": "Você não completou nenhum campo!",
+ "entrieslefttoadd": "Você precisa adicionar mais {{$a.entriesleft}} item(ns) para completar esta atividade",
+ "entrieslefttoaddtoview": "Você precisa adicionar mais {{$a.entrieslefttoview}} item(ns) antes de poder ver os itens dos outros participantes.",
+ "errormustsupplyvalue": "Você precisa fornecer um valor aqui.",
+ "expired": "Sinto muito, mas esta atividade foi fechada em {{$a}} e não está mais disponível",
+ "fields": "Campos",
+ "latlongboth": "Tanto a Latitude quanto a Longitude devem ser preenchidas.",
+ "menuchoose": "Selecionar...",
+ "more": "Mais",
+ "nomatch": "Nenhum item correspondente encontrado!",
+ "norecords": "Nenhum item na base de dados",
+ "notapproved": "O item ainda não foi aprovado.",
+ "notopenyet": "Desculpe, esta atividade não está disponível até {{$a}}",
+ "numrecords": "{{$a}} itens",
+ "other": "Outro",
+ "recordapproved": "Item aprovado",
+ "recorddeleted": "Item cancelado",
+ "recorddisapproved": "Entrada não aprovada",
+ "resetsettings": "Reconfigurar filtros",
+ "search": "Busca",
+ "selectedrequired": "Todos os itens selecionados são obrigatórios",
+ "timeadded": "Tempo adicionado",
+ "timemodified": "Tempo modificado",
+ "usedate": "Incluir na pesquisa."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/pt.json b/www/addons/mod/data/lang/pt.json
new file mode 100644
index 00000000000..fe1adf4e1cb
--- /dev/null
+++ b/www/addons/mod/data/lang/pt.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Adicionar registos",
+ "advancedsearch": "Pesquisa avançada",
+ "alttext": "Texto alternativo",
+ "approve": "Aprovar",
+ "approved": "Aprovado",
+ "ascending": "Ascendente",
+ "authorfirstname": "Primeiro nome do autor",
+ "authorlastname": "Apelido do autor",
+ "confirmdeleterecord": "Tem a certeza de que pretende apagar este registo?",
+ "descending": "Descendente",
+ "disapprove": "Anular aprovação",
+ "emptyaddform": "Não preencheu nenhum campo!",
+ "entrieslefttoadd": "Tem que adicionar mais {{$a.entriesleft}} registo(s) para completar esta atividade",
+ "entrieslefttoaddtoview": "Tem que adicionar mais {{$a.entrieslefttoview}} registos para conseguir visualizar as entradas dos outros participantes.",
+ "errormustsupplyvalue": "Indique aqui um valor.",
+ "expired": "A atividade terminou em {{$a}} e não se encontra disponível",
+ "fields": "Campos",
+ "latlongboth": "É necessário a latitude e a longitude.",
+ "menuchoose": "Selecione...",
+ "more": "Mais",
+ "nomatch": "Não foram encontrados registos correspondentes!",
+ "norecords": "Não existem registos na base de dados",
+ "notapproved": "O registo ainda não foi aprovado.",
+ "notopenyet": "A atividade apenas será disponibilizada em {{$a}}",
+ "numrecords": "{{$a}} registos",
+ "other": "Outro",
+ "recordapproved": "Registo aprovado",
+ "recorddeleted": "Registo apagado",
+ "recorddisapproved": "Entrada não aprovada",
+ "resetsettings": "Reiniciar filtros",
+ "search": "Pesquisar",
+ "selectedrequired": "Todos os selecionados são obrigatórios",
+ "timeadded": "Data de criação",
+ "timemodified": "Data da última edição",
+ "usedate": "Incluir na pesquisa."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/ro.json b/www/addons/mod/data/lang/ro.json
new file mode 100644
index 00000000000..76ddb872d74
--- /dev/null
+++ b/www/addons/mod/data/lang/ro.json
@@ -0,0 +1,36 @@
+{
+ "addentries": "Adaugă articole",
+ "advancedsearch": "Căutare complexă",
+ "alttext": "Text alternativ",
+ "approve": "Aprobă",
+ "approved": "Aprobat",
+ "ascending": "Crescător",
+ "authorfirstname": "Prenume autor",
+ "authorlastname": "Nume autor",
+ "confirmdeleterecord": "Sunteţi sigur că doriţi să ştergeţi acest articol?",
+ "descending": "Descrescător",
+ "disapprove": "Anulați aprobarea",
+ "emptyaddform": "Nu aţi completat niciun câmp!",
+ "entrieslefttoadd": "Pentru a finaliza această activitate trebuie să mai adăugaţi {{$a.entriesleft}} more entry/entries articole",
+ "entrieslefttoaddtoview": "Pentru a vedea articolele postate de ceilalţi participanţi trebuie să mai adăugaţi {{$a.entrieslefttoview}} articole.",
+ "errormustsupplyvalue": "Trebuie să inserați o valoare aici.",
+ "expired": "Ne pare rău, activitatea s-a închis în {{$a}} și nu mai este disponibilă",
+ "fields": "Câmpuri",
+ "menuchoose": "Alegeţi...",
+ "more": "Detalii suplimentare",
+ "nomatch": "Nu s-au găsit articole care să corespundă criteriilor selectate!",
+ "norecords": "Nu s-au găsit articole în baza de date",
+ "notapproved": "Acest articol nu a fost încă aprobat.",
+ "notopenyet": "Ne pare rău, această activitate nu este disponibilă până în {{$a}}",
+ "numrecords": "{{$a}} articole",
+ "other": "Altele",
+ "recordapproved": "Articol aprobat",
+ "recorddeleted": "Articol şters",
+ "recorddisapproved": "Postare neaprobată",
+ "resetsettings": "Resetează filtre",
+ "search": "Căutare",
+ "selectedrequired": "Toate elementele selectate sunt obligatorii",
+ "timeadded": "Ora la care a fost adăugat",
+ "timemodified": "Ora la care a fost modificat",
+ "usedate": "Include în căutare"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/ru.json b/www/addons/mod/data/lang/ru.json
new file mode 100644
index 00000000000..260f25ebd98
--- /dev/null
+++ b/www/addons/mod/data/lang/ru.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Добавить записи",
+ "advancedsearch": "Расширенный поиск",
+ "alttext": "Альтернативный текст",
+ "approve": "Одобрить",
+ "approved": "Одобрено",
+ "ascending": "По возрастанию",
+ "authorfirstname": "Имя автора",
+ "authorlastname": "Фамилия автора",
+ "confirmdeleterecord": "Вы уверены, что хотите удалить эту запись?",
+ "descending": "По убыванию",
+ "disapprove": "Отменить одобрение",
+ "emptyaddform": "Вы не заполнили ни одного поля",
+ "entrieslefttoadd": "Чтобы просматривать записи других участников Вы должны добавить еще записи - ({{$a.entriesleft}})",
+ "entrieslefttoaddtoview": "Вы должны еще добавить записи ({{$a.entrieslefttoview}}), прежде чем сможете просматривать записи других участников.",
+ "errormustsupplyvalue": "Вы должны здесь указать значение.",
+ "expired": "К сожалению, эта база данных закрыта {{$a}} и больше не доступна",
+ "fields": "Поля",
+ "latlongboth": "Необходимо задать и широту, и долготу.",
+ "menuchoose": "Выбрать...",
+ "more": "Просмотр записи",
+ "nomatch": "Соответствующих записей не найдено!",
+ "norecords": "Нет записей в базе данных",
+ "notapproved": "Запись пока не одобрена.",
+ "notopenyet": "Извините, этот элемент курса не доступен до {{$a}}",
+ "numrecords": "{{$a}} записей",
+ "other": "Другое",
+ "recordapproved": "Запись одобрена",
+ "recorddeleted": "Запись удалена",
+ "recorddisapproved": "Снято одобрение записи",
+ "resetsettings": "Сбросить фильтры",
+ "search": "Поиск",
+ "selectedrequired": "Требуются все выбранные",
+ "timeadded": "Время добавления",
+ "timemodified": "Время изменения",
+ "usedate": "Включить в поиск"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/sr-cr.json b/www/addons/mod/data/lang/sr-cr.json
new file mode 100644
index 00000000000..a8ce67ae329
--- /dev/null
+++ b/www/addons/mod/data/lang/sr-cr.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Додај уносе",
+ "advancedsearch": "Напредно претраживање",
+ "alttext": "Алтернативни текст",
+ "approve": "Одобри",
+ "approved": "Одобрено",
+ "ascending": "Растуће",
+ "authorfirstname": "Име аутора",
+ "authorlastname": "Презиме аутора",
+ "confirmdeleterecord": "Да ли сте сигурни да желите да обришете овај унос?",
+ "descending": "Опадајуће",
+ "disapprove": "Повуци одобрење",
+ "emptyaddform": "Нисте испунили ниједно поље!",
+ "entrieslefttoadd": "Морате да додате још {{$a.entriesleft}} унос(а) како бисте завршили ову активност",
+ "entrieslefttoaddtoview": "Морате да додате још {{$a.entrieslefttoview}} уноса пре него што будете могли да видите уносе других корисника.",
+ "errorapproving": "Грешка приликом одобравања или неодобравања уноса.",
+ "errordeleting": "Грешка приликом брисања уноса.",
+ "errormustsupplyvalue": "Морате овде задати вредност.",
+ "expired": "Нажалост, ова активност је затворена {$}} и више није доступна",
+ "fields": "Поља",
+ "latlongboth": "Поља за географску ширина и дужина су обавезна.",
+ "menuchoose": "Изаберите...",
+ "more": "Још",
+ "nomatch": "Нема уноса који се поклапају!",
+ "norecords": "Нема уноса у бази података",
+ "notapproved": "Унос још није одобрен",
+ "notopenyet": "Нажалост, ова активност није доступна до {{$a}}",
+ "numrecords": "{{$a}} уноса",
+ "other": "Друго",
+ "recordapproved": "Унос је одобрен",
+ "recorddeleted": "Унос је обрисан",
+ "recorddisapproved": "Унос није одобрен",
+ "resetsettings": "Ресетуј филтере",
+ "search": "Тражи",
+ "selectedrequired": "Све изабрано обавезно",
+ "timeadded": "Време додавања",
+ "timemodified": "Време измене",
+ "usedate": "Укључи у претраживање."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/sr-lt.json b/www/addons/mod/data/lang/sr-lt.json
new file mode 100644
index 00000000000..01163f8f244
--- /dev/null
+++ b/www/addons/mod/data/lang/sr-lt.json
@@ -0,0 +1,39 @@
+{
+ "addentries": "Dodaj unose",
+ "advancedsearch": "Napredno pretraživanje",
+ "alttext": "Alternativni tekst",
+ "approve": "Odobri",
+ "approved": "Odobreno",
+ "ascending": "Rastuće",
+ "authorfirstname": "Ime autora",
+ "authorlastname": "Prezime autora",
+ "confirmdeleterecord": "Da li ste sigurni da želite da obrišete ovaj unos?",
+ "descending": "Opadajuće",
+ "disapprove": "Povuci odobrenje",
+ "emptyaddform": "Niste ispunili nijedno polje!",
+ "entrieslefttoadd": "Morate da dodate još {{$a.entriesleft}} unos(a) kako biste završili ovu aktivnost",
+ "entrieslefttoaddtoview": "Morate da dodate još {{$a.entrieslefttoview}} unosa pre nego što budete mogli da vidite unose drugih korisnika.",
+ "errorapproving": "Greška prilikom odobravanja ili neodobravanja unosa.",
+ "errordeleting": "Greška prilikom brisanja unosa.",
+ "errormustsupplyvalue": "Morate ovde zadati vrednost.",
+ "expired": "Nažalost, ova aktivnost je zatvorena {$}} i više nije dostupna",
+ "fields": "Polja",
+ "latlongboth": "Polja za geografsku širina i dužina su obavezna.",
+ "menuchoose": "Izaberite...",
+ "more": "Još",
+ "nomatch": "Nema unosa koji se poklapaju!",
+ "norecords": "Nema unosa u bazi podataka",
+ "notapproved": "Unos još nije odobren",
+ "notopenyet": "Nažalost, ova aktivnost nije dostupna do {{$a}}",
+ "numrecords": "{{$a}} unosa",
+ "other": "Drugo",
+ "recordapproved": "Unos je odobren",
+ "recorddeleted": "Unos je obrisan",
+ "recorddisapproved": "Unos nije odobren",
+ "resetsettings": "Resetuj filtere",
+ "search": "Traži",
+ "selectedrequired": "Sve izabrano obavezno",
+ "timeadded": "Vreme dodavanja",
+ "timemodified": "Vreme izmene",
+ "usedate": "Uključi u pretraživanje."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/sv.json b/www/addons/mod/data/lang/sv.json
new file mode 100644
index 00000000000..a99d7225328
--- /dev/null
+++ b/www/addons/mod/data/lang/sv.json
@@ -0,0 +1,33 @@
+{
+ "addentries": "Lägg till bidrag",
+ "advancedsearch": "Avancerad sökning",
+ "alttext": "Alternativ text",
+ "approve": "Godkänn",
+ "approved": "Godkänd",
+ "ascending": "Stigande",
+ "authorfirstname": "Författarens förnamn",
+ "authorlastname": "Författarens efternamn",
+ "confirmdeleterecord": "Är Du säker på att du vill ta bort det här bidraget?",
+ "descending": "Fallande",
+ "emptyaddform": "Du fyllde inte i alla fält!",
+ "entrieslefttoadd": "Du måste lägga till {{$a.entriesleft}} fler bidrag för att fullfölja den här aktiviteten.",
+ "entrieslefttoaddtoview": "Du måste lägga till {{$a.entrieslefttoview}} fler bidrag innan du kan få se de andra deltagarnas bidrag.",
+ "expired": "Den här aktiviteten stängdes tyvärr den {{$a}} och är inte längre tillgänglig.",
+ "fields": "Fält",
+ "menuchoose": "Välj...",
+ "more": "Fler",
+ "nomatch": "Det gick inte att hitta några matchande bidrag!",
+ "norecords": "Det finns inga bidrag i databasen",
+ "notapproved": "Bidraget är inte godkänt än",
+ "notopenyet": "Den här aktiviteten är tyvärr inte tillgänglig förrän {$}}",
+ "numrecords": "{{$a}} bidrag",
+ "other": "Övrigt",
+ "recordapproved": "Bidraget har godkänts",
+ "recorddeleted": "Bidraget har tagits bort",
+ "resetsettings": "Filter för återställning",
+ "search": "Sök",
+ "selectedrequired": "Alla de valda är obligatoriska",
+ "timeadded": "Tillagd när",
+ "timemodified": "Modifierad när",
+ "usedate": "Ta med i sökning"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/tr.json b/www/addons/mod/data/lang/tr.json
new file mode 100644
index 00000000000..c250d4477cb
--- /dev/null
+++ b/www/addons/mod/data/lang/tr.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Kayıtları ekle",
+ "advancedsearch": "Gelişmiş arama",
+ "alttext": "Alternatif metin",
+ "approve": "Onayla",
+ "approved": "Onaylandı",
+ "ascending": "Artan",
+ "authorfirstname": "Yazarın adı",
+ "authorlastname": "Yazarın soyadı",
+ "confirmdeleterecord": "Bu kaydı silmek istediğinizden emin misiniz?",
+ "descending": "Azalan",
+ "disapprove": "Onayı geri al",
+ "emptyaddform": "Hiçbir alanı doldurmadınız!",
+ "entrieslefttoadd": "Bu etkinliği bitirmek için {{$a.entriesleft}} kayıt daha eklemelisiniz.",
+ "entrieslefttoaddtoview": "Diğer katılımcıların kayıtlarını görebilmek için {{$a.entrieslefttoview}} kayıt daha eklemelisiniz.",
+ "errormustsupplyvalue": "Burada bir değer vermelisiniz.",
+ "expired": "Maalesef, bu etkinlik {{$a}} tarihinde kapandı ve artık mevcut değil",
+ "fields": "Alanlar",
+ "latlongboth": "Enlem ve boylam gereklidir.",
+ "menuchoose": "Seç...",
+ "more": "Dahası",
+ "nomatch": "Eşleşen kayıt bulunamadı!",
+ "norecords": "Veritabanında kayıt yok",
+ "notapproved": "Kayıt henüz onaylanmamış.",
+ "notopenyet": "Üzgünüz, bu etkinlik {{$a}} kadar kullanılamıyor",
+ "numrecords": "{{$a}} kayıt",
+ "other": "Diğer",
+ "recordapproved": "Kayıt onaylandı",
+ "recorddeleted": "Kayıt silindi",
+ "recorddisapproved": "Giriş onaylanmadı",
+ "resetsettings": "Alanları Temizle",
+ "search": "Ara",
+ "selectedrequired": "Tüm seçililer gereklidir",
+ "timeadded": "Ekleme zamanı",
+ "timemodified": "Düzenleme zamanı",
+ "usedate": "Aramaya dahil et."
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/uk.json b/www/addons/mod/data/lang/uk.json
new file mode 100644
index 00000000000..5221866c401
--- /dev/null
+++ b/www/addons/mod/data/lang/uk.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "Додати записи",
+ "advancedsearch": "Розширений пошук",
+ "alttext": "Альтернативний текст",
+ "approve": "Прийняти",
+ "approved": "Прийнято",
+ "ascending": "за зростанням",
+ "authorfirstname": "Ім’я автора",
+ "authorlastname": "Прізвище автора",
+ "confirmdeleterecord": "Ви впевнені, що хочете видалити цей запис?",
+ "descending": "за спаданням",
+ "disapprove": "Скасувати схвалення",
+ "emptyaddform": "Ви не заповнили жодного поля!",
+ "entrieslefttoadd": "Вам потрібно додати більше чим {{$a}} записів перед тим, як ви зможете побачити записи інших учасників.",
+ "entrieslefttoaddtoview": "Ви повинні ввести більше чим {{$a.entrieslefttoview}} запис(ів) перед тим, як матимете змогу бачити записи інших.",
+ "errormustsupplyvalue": "Ви повинні тут вказати значення.",
+ "expired": "На жаль, ця діяльність закрита на {{$a}} і більше не доступна",
+ "fields": "Поля",
+ "latlongboth": "Широта і довгота є обов’язковими.",
+ "menuchoose": "Вибрати...",
+ "more": "Детальний перегляд...",
+ "nomatch": "Жодного запису не знайдено!",
+ "norecords": "Немає записів у базі даних",
+ "notapproved": "Запис ще не схвалено",
+ "notopenyet": "ця діяльність не доступна до {{$a}}",
+ "numrecords": "{{$a}} записів",
+ "other": "Інше",
+ "recordapproved": "Запис погоджено",
+ "recorddeleted": "Запис вилучено",
+ "recorddisapproved": "Запис не схвалено",
+ "resetsettings": "Скинути фільтри",
+ "search": "Пошук",
+ "selectedrequired": "Всі відібрані вимоги",
+ "timeadded": "Час введення",
+ "timemodified": "Час модифікації",
+ "usedate": "Включити в пошук"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/zh-cn.json b/www/addons/mod/data/lang/zh-cn.json
new file mode 100644
index 00000000000..6ee9c6d0542
--- /dev/null
+++ b/www/addons/mod/data/lang/zh-cn.json
@@ -0,0 +1,36 @@
+{
+ "addentries": "添加条目",
+ "advancedsearch": "高级搜索",
+ "alttext": "可替代文本",
+ "approve": "批准",
+ "approved": "许可",
+ "ascending": "升序",
+ "authorfirstname": "姓",
+ "authorlastname": "名",
+ "confirmdeleterecord": "您确定要删除这条记录?",
+ "descending": "降序",
+ "disapprove": "撤消审核",
+ "emptyaddform": "您未填写任何字段",
+ "entrieslefttoadd": "在完成此活动前,您还需添加 {{$a.entriesleft}} 条目",
+ "entrieslefttoaddtoview": "在查看其他参与者的条目前,您还需添加 {{$a.entrieslefttoview}} 条目",
+ "errormustsupplyvalue": "这儿你必须提供一个值。",
+ "expired": "对不起,这项活动截止于{{$a}},不再有效",
+ "fields": "字段",
+ "menuchoose": "选择...",
+ "more": "更多",
+ "nomatch": "未找到匹配的条目",
+ "norecords": "数据库中无条目",
+ "notapproved": "条目尚未被核准。",
+ "notopenyet": "抱歉,此活动直到{{$a}}才可用",
+ "numrecords": "{{$a}} 条记录",
+ "other": "其他",
+ "recordapproved": "记录已核准",
+ "recorddeleted": "记录已删除",
+ "recorddisapproved": "不可进入",
+ "resetsettings": "重置字段",
+ "search": "搜索",
+ "selectedrequired": "全选",
+ "timeadded": "追加时间",
+ "timemodified": "编辑时间",
+ "usedate": "包含到搜索中。"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/lang/zh-tw.json b/www/addons/mod/data/lang/zh-tw.json
new file mode 100644
index 00000000000..7ccf7b95f73
--- /dev/null
+++ b/www/addons/mod/data/lang/zh-tw.json
@@ -0,0 +1,37 @@
+{
+ "addentries": "新增條目",
+ "advancedsearch": "進階搜尋",
+ "alttext": "替代文字",
+ "approve": "審核",
+ "approved": "已核准",
+ "ascending": "升冪",
+ "authorfirstname": "作者的名字",
+ "authorlastname": "作者的姓氏",
+ "confirmdeleterecord": "您確定要刪除這筆資料嗎?",
+ "descending": "降冪",
+ "disapprove": "取消核准",
+ "emptyaddform": "您沒有填入任何欄位!",
+ "entrieslefttoadd": "在您要瀏覽其他同學提供的資料前,您必須要再新增{{$a.entriesleft}} 筆資料。",
+ "entrieslefttoaddtoview": "您必須新增{{$a.entrieslefttoview}}筆以上資料,才能夠看到其他同學提供的資料。",
+ "errormustsupplyvalue": "這裡你必須提供一個數值。",
+ "expired": "抱歉,這活動已經在 {{$a}}關閉,已經無法使用。",
+ "fields": "欄位",
+ "latlongboth": "緯度和經度兩者都要填寫",
+ "menuchoose": "選擇...",
+ "more": "更多",
+ "nomatch": "找不到符合的資料!",
+ "norecords": "資料庫中沒有資料",
+ "notapproved": "資料尚未審核。",
+ "notopenyet": "抱歉,這一活動要等到{{$a}}才開始",
+ "numrecords": "{{$a}} 筆資料",
+ "other": "其他",
+ "recordapproved": "資料已審核",
+ "recorddeleted": "資料已刪除",
+ "recorddisapproved": "不可進入",
+ "resetsettings": "重設欄位",
+ "search": "搜尋",
+ "selectedrequired": "所有必要的選擇",
+ "timeadded": "新增的時間",
+ "timemodified": "修改的時間",
+ "usedate": "包含在搜尋中"
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/main.js b/www/addons/mod/data/main.js
new file mode 100644
index 00000000000..3ce8a7aa2eb
--- /dev/null
+++ b/www/addons/mod/data/main.js
@@ -0,0 +1,91 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data', ['mm.core'])
+
+.constant('mmaModDataComponent', 'mmaModData')
+.constant('mmaModDataEventEntryChanged', 'mma-mod_data_entry_changed')
+.constant('mmaModDataPerPage', 25)
+.constant('mmaModDataEventAutomSynced', 'mma_mod_data_autom_synced')
+.constant('mmaModDataSyncTime', 300000) // In milliseconds.
+
+.config(function($stateProvider) {
+
+ $stateProvider
+
+ .state('site.mod_data', {
+ url: '/mod_data',
+ params: {
+ module: null,
+ courseid: null,
+ group: null
+ },
+ views: {
+ 'site': {
+ controller: 'mmaModDataIndexCtrl',
+ templateUrl: 'addons/mod/data/templates/index.html'
+ }
+ }
+ })
+
+ .state('site.mod_data-entry', {
+ url: '/mod_data-entry',
+ params: {
+ module: null,
+ moduleid: null, // Redundant parameter to fix a problem passing object as parameters. To be fixed in MOBILE-1370.
+ courseid: null,
+ entryid: null,
+ page: null,
+ group: null
+ },
+ views: {
+ 'site': {
+ controller: 'mmaModDataEntryCtrl',
+ templateUrl: 'addons/mod/data/templates/entry.html'
+ }
+ }
+ })
+
+ .state('site.mod_data-edit', {
+ url: '/mod_data-edit',
+ params: {
+ module: null,
+ moduleid: null, // Redundant parameter to fix a problem passing object as parameters. To be fixed in MOBILE-1370.
+ courseid: null,
+ entryid: null,
+ group: null
+ },
+ views: {
+ 'site': {
+ controller: 'mmaModDataEditCtrl',
+ templateUrl: 'addons/mod/data/templates/edit.html'
+ }
+ }
+ });
+})
+
+.config(function($mmCourseDelegateProvider, $mmContentLinksDelegateProvider, $mmCoursePrefetchDelegateProvider) {
+ $mmCourseDelegateProvider.registerContentHandler('mmaModData', 'data', '$mmaModDataHandlers.courseContent');
+ $mmCoursePrefetchDelegateProvider.registerPrefetchHandler('mmaModData', 'data', '$mmaModDataPrefetchHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:index', '$mmaModDataHandlers.indexLinksHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:entry', '$mmaModDataHandlers.showEntryLinksHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:approve', '$mmaModDataHandlers.approveEntryLinksHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:delete', '$mmaModDataHandlers.deleteEntryLinksHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:edit', '$mmaModDataHandlers.editEntryLinksHandler');
+})
+
+.run(function($mmCronDelegate) {
+ // Register sync handler.
+ $mmCronDelegate.register('mmaModData', '$mmaModDataHandlers.syncHandler');
+});
diff --git a/www/addons/mod/data/scss/styles.scss b/www/addons/mod/data/scss/styles.scss
new file mode 100644
index 00000000000..4fcffde0547
--- /dev/null
+++ b/www/addons/mod/data/scss/styles.scss
@@ -0,0 +1,138 @@
+
+.mm-site_mod_data {
+ .recordcheckbox {
+ display: none;
+ }
+}
+
+.mm-data-contents {
+ overflow: visible;
+ white-space: normal;
+ word-break: break-word;
+ padding: $item-padding;
+ background-color: white;
+ border-top-width: $item-border-width;
+ border-bottom-width: $item-border-width;
+ border-style: solid;
+ border-color: $item-default-border;
+
+ table, tbody {
+ display: block;
+ }
+
+ tr {
+ @extend .row;
+ padding: 0;
+ }
+
+ td, th {
+ @extend .col;
+ }
+}
+
+#mma-mod_data-advanced-search-form,
+#mma-mod_data-edit-form {
+ table {
+ width: 100%;
+ }
+ td {
+ vertical-align: top;
+ }
+
+ textarea,
+ input[type="text"],
+ input[type="password"],
+ input[type="datetime"],
+ input[type="datetime-local"],
+ input[type="date"],
+ input[type="month"],
+ input[type="time"],
+ input[type="week"],
+ input[type="number"],
+ input[type="email"],
+ input[type="url"],
+ input[type="search"],
+ input[type="tel"],
+ input[type="color"],
+ .item-select,
+ mm-attachments>.item-border {
+ width: 100%;
+ margin: -1px;
+ border: 1px solid $gray;
+ padding: 16px 0 16px 16px;
+ height: 56px;
+ }
+
+ input[type="datetime"],
+ input[type="datetime-local"],
+ input[type="date"] {
+ -webkit-appearance: none;
+ }
+
+ mm-attachments .item-media {
+ width: 100%;
+ margin: -1px;
+ border: 1px solid $gray;
+ height: 56px;
+ }
+
+ mm-multiple-select .item {
+ width: 100%;
+ margin: -1px;
+ border: 1px solid $gray;
+ padding: 16px 0 16px 16px;
+ }
+
+ mm-attachments + .item-stacked-label {
+ border-top: 0px;
+ padding: 0;
+ margin-right: 1px;
+
+ ion-label {
+ margin: 0;
+ padding-left: 16px;
+ }
+
+ input {
+ border: 0;
+ margin: 0;
+ }
+ }
+
+ mm-attachments .item {
+ width: 100%;
+ margin: -1px;
+ border: 1px solid $gray;
+ overflow: hidden;
+ }
+
+ .item-checkbox {
+ margin-right: 1px;
+ }
+
+ .item-input.item-select {
+ margin-bottom: -6px;
+
+ select {
+ width: 100%;
+ left: 0;
+ max-width: none;
+ }
+ }
+
+ .item-input.mm-latlong {
+ width: 100%;
+ margin: -1px;
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: 0;
+
+ input {
+ border: 0;
+ }
+ }
+
+ .mm-item-has-rich-text-editor {
+ margin-right: 1px;
+ }
+}
\ No newline at end of file
diff --git a/www/addons/mod/data/services/data.js b/www/addons/mod/data/services/data.js
new file mode 100644
index 00000000000..29e819afac1
--- /dev/null
+++ b/www/addons/mod/data/services/data.js
@@ -0,0 +1,993 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Data service.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc controller
+ * @name $mmaModData
+ */
+.factory('$mmaModData', function($q, $mmSitesManager, mmaModDataComponent, $mmFilepool, $mmSite, mmaModDataPerPage, $mmApp, $mmUtil,
+ $mmaModDataOffline, $mmaModDataFieldsDelegate) {
+ var self = {};
+
+ /**
+ * Get cache key for database data WS calls.
+ *
+ * @param {Number} courseId Course ID.
+ * @return {String} Cache key.
+ */
+ function getDatabaseDataCacheKey(courseId) {
+ return 'mmaModData:data:' + courseId;
+ }
+
+ /**
+ * Get prefix cache key for all database activity data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @return {String} Cache key.
+ */
+ function getDatabaseDataPrefixCacheKey(dataId) {
+ return 'mmaModData:' + dataId;
+ }
+
+
+ /**
+ * Get prefix cache key for all database access information data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @return {String} Cache key.
+ */
+ function getDatabaseAccessInformationDataPrefixCacheKey(dataId) {
+ return getDatabaseDataPrefixCacheKey(dataId) + ':access:';
+ }
+
+ /**
+ * Get cache key for database access information data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @param {Number} [groupId] Group ID.
+ * @return {String} Cache key.
+ */
+ function getDatabaseAccessInformationDataCacheKey(dataId, groupId) {
+ groupId = groupId || 0;
+ return getDatabaseAccessInformationDataPrefixCacheKey(dataId) + groupId;
+ }
+
+ /**
+ * Get prefix cache key for database all entries data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @return {String} Cache key.
+ */
+ function getEntriesPrefixCacheKey(dataId) {
+ return getDatabaseDataPrefixCacheKey(dataId) + ':entries:';
+ }
+
+ /**
+ * Get cache key for database entries data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @param {Number} [groupId] Group ID.
+ * @return {String} Cache key.
+ */
+ function getEntriesCacheKey(dataId, groupId) {
+ groupId = groupId || 0;
+ return getEntriesPrefixCacheKey(dataId) + groupId;
+ }
+
+ /**
+ * Get cache key for database entry data WS calls.
+ *
+ * @param {Number} dataId Data ID for caching purposes.
+ * @param {Number} entryId Entry ID.
+ * @return {String} Cache key.
+ */
+ function getEntryCacheKey(dataId, entryId) {
+ return getDatabaseDataPrefixCacheKey(dataId) + ':entry:' + entryId;
+ }
+
+ /**
+ * Get cache key for database fields data WS calls.
+ *
+ * @param {Number} dataId Data ID.
+ * @return {String} Cache key.
+ */
+ function getFieldsCacheKey(dataId) {
+ return getDatabaseDataPrefixCacheKey(dataId) + ':fields';
+ }
+
+ /**
+ * Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the database WS are available.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#isPluginEnabled
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
+ */
+ self.isPluginEnabled = function(siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.wsAvailable('mod_data_get_databases_by_courses') &&
+ site.wsAvailable('mod_data_get_data_access_information');
+ });
+ };
+
+ /**
+ * Get a database with key=value. If more than one is found, only the first will be returned.
+ *
+ * @param {Number} courseId Course ID.
+ * @param {String} key Name of the property to check.
+ * @param {Mixed} value Value to search.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @return {Promise} Promise resolved when the database is retrieved.
+ */
+ function getDatabase(courseId, key, value, siteId, forceCache) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ courseids: [courseId]
+ },
+ preSets = {
+ cacheKey: getDatabaseDataCacheKey(courseId)
+ };
+
+ if (forceCache) {
+ preSets.omitExpires = true;
+ }
+
+ return site.read('mod_data_get_databases_by_courses', params, preSets).then(function(response) {
+ if (response && response.databases) {
+ for (var x in response.databases) {
+ if (response.databases[x][key] == value) {
+ return response.databases[x];
+ }
+ }
+ }
+ return $q.reject();
+ });
+ });
+ }
+
+ /**
+ * Get a database by course module ID.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getDatabase
+ * @param {Number} courseId Course ID.
+ * @param {Number} cmId Course module ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @return {Promise} Promise resolved when the database is retrieved.
+ */
+ self.getDatabase = function(courseId, cmId, siteId, forceCache) {
+ return getDatabase(courseId, 'coursemodule', cmId, siteId, forceCache);
+ };
+
+ /**
+ * Get a database by ID.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getDatabaseById
+ * @param {Number} courseId Course ID.
+ * @param {Number} id Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @return {Promise} Promise resolved when the database is retrieved.
+ */
+ self.getDatabaseById = function(courseId, id, siteId, forceCache) {
+ return getDatabase(courseId, 'id', id, siteId, forceCache);
+ };
+
+ /**
+ * Invalidates database data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateDatabaseData
+ * @param {Number} courseId Course ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the database is invalidated.
+ */
+ self.invalidateDatabaseData = function(courseId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKey(getDatabaseDataCacheKey(courseId));
+ });
+ };
+
+ /**
+ * Invalidates database data except files and module info.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateDatabaseWSData
+ * @param {Number} databaseId Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ self.invalidateDatabaseWSData = function(databaseId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKeyStartingWith(getDatabaseDataPrefixCacheKey(databaseId));
+
+ });
+ };
+
+ /**
+ * Get access information for a given database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getDatabaseAccessInformation
+ * @param {Number} dataId Data ID.
+ * @param {Number} [groupId] Group ID.
+ * @param {Boolean} offline True if it should return cached data. Has priority over ignoreCache.
+ * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the database is retrieved.
+ */
+ self.getDatabaseAccessInformation = function(dataId, groupId, offline, ignoreCache, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ databaseid: dataId
+ },
+ preSets = {
+ cacheKey: getDatabaseAccessInformationDataCacheKey(dataId, groupId)
+ };
+
+ if (typeof groupId !== "undefined") {
+ params.groupid = groupId;
+ }
+
+ if (offline) {
+ preSets.omitExpires = true;
+ } else if (ignoreCache) {
+ preSets.getFromCache = 0;
+ preSets.emergencyCache = 0;
+ }
+
+ return site.read('mod_data_get_data_access_information', params, preSets);
+ });
+ };
+
+ /**
+ * Invalidates database access information data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateDatabaseAccessInformationData
+ * @param {Number} dataId Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ self.invalidateDatabaseAccessInformationData = function(dataId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKeyStartingWith(getDatabaseAccessInformationDataPrefixCacheKey(dataId));
+ });
+ };
+
+ /**
+ * Get entries for a specific database and group.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getEntries
+ * @param {Number} dataId Data ID.
+ * @param {Number} [groupId] Group ID.
+ * @param {Number} [sort] Sort the records by this field id, reserved ids are:
+ * 0: timeadded
+ * -1: firstname
+ * -2: lastname
+ * -3: approved
+ * -4: timemodified.
+ * Empty for using the default database setting.
+ * @param {String} [order] The direction of the sorting: 'ASC' or 'DESC'.
+ * Empty for using the default database setting.
+ * @param {Number} [page] Page of records to return.
+ * @param {Number} [perPage] Records per page to return. Default on mmaModDataPerPage.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the database is retrieved.
+ */
+ self.getEntries = function(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ // Always use sort and order params to improve cache usage (entries are identified by params).
+ var params = {
+ databaseid: dataId,
+ returncontents: 1,
+ page: page || 0,
+ perpage: perPage || mmaModDataPerPage,
+ groupid: groupId || 0,
+ sort: sort || "0",
+ order: order || "DESC"
+ },
+ preSets = {
+ cacheKey: getEntriesCacheKey(dataId, groupId)
+ };
+
+ if (forceCache) {
+ preSets.omitExpires = true;
+ } else if (ignoreCache) {
+ preSets.getFromCache = 0;
+ preSets.emergencyCache = 0;
+ }
+
+ return site.read('mod_data_get_entries', params, preSets);
+ });
+ };
+
+ /**
+ * Invalidates database entries data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateEntriesData
+ * @param {Number} dataId Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ self.invalidateEntriesData = function(dataId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKeyStartingWith(getEntriesPrefixCacheKey(dataId));
+ });
+ };
+
+ /**
+ * Get an entry of the database activity.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getEntry
+ * @param {Number} dataId Data ID for caching purposes.
+ * @param {Number} entryId Entry ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the database entry is retrieved.
+ */
+ self.getEntry = function(dataId, entryId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ entryid: entryId,
+ returncontents: 1
+ },
+ preSets = {
+ cacheKey: getEntryCacheKey(dataId, entryId)
+ };
+
+ return site.read('mod_data_get_entry', params, preSets);
+ });
+ };
+
+ /**
+ * Invalidates database entry data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateEntryData
+ * @param {Number} dataId Data ID for caching purposes.
+ * @param {Number} entryId Entry ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ self.invalidateEntryData = function(dataId, entryId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKey(getEntryCacheKey(dataId, entryId));
+ });
+ };
+
+ /**
+ * Approves or unapproves an entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#approveEntry
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID.
+ * @param {Boolean} approve Whether to approve (true) or unapprove the entry.
+ * @param {Number} courseId Course ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.approveEntry = function(dataId, entryId, approve, courseId, siteId) {
+ siteId = siteId || $mmSite.getId();
+
+ // Get if the opposite action is not synced.
+ var action = approve ? 'disapprove' : 'approve';
+ return $mmaModDataOffline.getEntry(dataId, entryId, action, siteId).then(function() {
+ // Found. Just delete the action.
+ return $mmaModDataOffline.deleteEntry(dataId, entryId, action, siteId);
+ }).catch(function() {
+
+ if (!$mmApp.isOnline()) {
+ // App is offline, store the action.
+ return storeOffline();
+ }
+
+ return self.approveEntryOnline(entryId, approve, siteId).catch(function(error) {
+ if (error && !error.wserror) {
+ // Couldn't connect to server, store in offline.
+ return storeOffline();
+ } else {
+ // The WebService has thrown an error or offline not supported, reject.
+ return $q.reject(error.error);
+ }
+ });
+ });
+
+ // Convenience function to store a data to be synchronized later.
+ function storeOffline() {
+ var action = approve ? 'approve' : 'disapprove';
+ return $mmaModDataOffline.saveEntry(dataId, entryId, action, courseId, undefined, false, undefined, siteId);
+ }
+ };
+
+ /**
+ * Approves or unapproves an entry. It does not cache calls. It will fail if offline or cannot connect.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#approveEntryOnline
+ * @param {Number} entryId Entry ID.
+ * @param {Boolean} approve Whether to approve (true) or unapprove the entry.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done. Rejected with object containing the error message
+ * (if any) and a boolean indicating if the error was returned by WS.
+ */
+ self.approveEntryOnline = function(entryId, approve, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ entryid: entryId,
+ approve: approve ? 1 : 0
+ };
+
+ return site.write('mod_data_approve_entry', params).catch(function(error) {
+ return $q.reject({
+ error: error,
+ wserror: $mmUtil.isWebServiceError(error)
+ });
+ });
+ });
+ };
+
+
+ /**
+ * Deletes an entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#deleteEntry
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID.
+ * @param {Number} courseId Course ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.deleteEntry = function(dataId, entryId, courseId, siteId) {
+ siteId = siteId || $mmSite.getId();
+ var justAdded = false;
+
+ // Check if the opposite action is not synced and just delete it.
+ return $mmaModDataOffline.getEntryActions(dataId, entryId, siteId).then(function(entries) {
+ if (entries && entries.length) {
+ // Found. Delete other actions first.
+ var proms = [];
+ angular.forEach(entries, function(entry) {
+ if (entry.action == 'add') {
+ justAdded = true;
+ }
+ proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
+ });
+
+ return $q.all(proms);
+ }
+ }).then(function() {
+ if (justAdded) {
+ // The field was added offline, delete and stop.
+ return;
+ }
+
+ if (!$mmApp.isOnline()) {
+ // App is offline, store the action.
+ return storeOffline();
+ }
+
+ return self.deleteEntryOnline(entryId, siteId).catch(function(error) {
+ if (error && !error.wserror) {
+ // Couldn't connect to server, store in offline.
+ return storeOffline();
+ } else {
+ // The WebService has thrown an error or offline not supported, reject.
+ return $q.reject(error.error);
+ }
+ });
+ });
+
+ // Convenience function to store a data to be synchronized later.
+ function storeOffline() {
+ return $mmaModDataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, false, undefined, siteId);
+ }
+ };
+
+ /**
+ * Deletes an entry. It does not cache calls. It will fail if offline or cannot connect.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#deleteEntryOnline
+ * @param {Number} entryId Entry ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done. Rejected with object containing
+ * the error message (if any) and a boolean indicating if the error was returned by WS.
+ */
+ self.deleteEntryOnline = function(entryId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ entryid: entryId
+ };
+
+ return site.write('mod_data_delete_entry', params).catch(function(error) {
+ return $q.reject({
+ error: error,
+ wserror: $mmUtil.isWebServiceError(error)
+ });
+ });
+ });
+ };
+
+ /**
+ * Adds a new entry to a database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#addEntry
+ * @param {Number} dataId Data instance ID.
+ * @param {Number} entryId EntryId or provisional entry ID when offline.
+ * @param {Number} courseId Course ID.
+ * @param {Object} contents The fields data to be created.
+ * @param {Number} [groupId] Group id, 0 means that the function will determine the user group.
+ * @param {Object} fields The fields that define the contents.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @param {Boolean} forceOffline Force editing entry in offline.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.addEntry = function(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline) {
+ siteId = siteId || $mmSite.getId();
+
+ if (!$mmApp.isOnline() || forceOffline) {
+ var notifications = checkFields(fields, contents);
+ if (notifications) {
+ return {
+ fieldnotifications: notifications
+ };
+ }
+ }
+
+ return self.addEntryOnline(dataId, contents, groupId, siteId).catch(function(error) {
+ if (error && !error.wserror) {
+ // Couldn't connect to server, store in offline.
+ return storeOffline();
+ } else {
+ // The WebService has thrown an error or offline not supported, reject.
+ return $q.reject(error.error);
+ }
+ });
+
+ // Convenience function to store a data to be synchronized later.
+ function storeOffline() {
+ return $mmaModDataOffline.saveEntry(dataId, entryId, 'add', courseId, groupId, contents, undefined, siteId)
+ .then(function(entry) {
+ return {
+ // Return provissional entry Id.
+ newentryid: entry[1]
+ };
+ });
+ }
+ };
+
+ /**
+ * Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#addEntryOnline
+ * @param {Number} dataId Database ID.
+ * @param {Object} data The fields data to be created.
+ * @param {Number} [groupId] Group id, 0 means that the function will determine the user group.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.addEntryOnline = function(dataId, data, groupId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ databaseid: dataId,
+ data: data
+ };
+
+ if (typeof groupId !== "undefined") {
+ params.groupid = groupId;
+ }
+
+ return site.write('mod_data_add_entry', params).catch(function(error) {
+ return $q.reject({
+ error: error,
+ wserror: $mmUtil.isWebServiceError(error)
+ });
+ });
+ });
+ };
+
+ /**
+ * Updates an existing entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#editEntry
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID.
+ * @param {Number} courseId Course ID.
+ * @param {Object} contents The contents data to be updated.
+ * @param {Object} fields The fields that define the contents.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @param {Boolean} forceOffline Force editing entry in offline.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.editEntry = function(dataId, entryId, courseId, contents, fields, siteId, forceOffline) {
+ siteId = siteId || $mmSite.getId();
+ var justAdded = false,
+ groupId;
+
+ if (!$mmApp.isOnline() || forceOffline) {
+ var notifications = checkFields(fields, contents);
+ if (notifications) {
+ return {
+ fieldnotifications: notifications
+ };
+ }
+ }
+
+ // Get other not not synced actions.
+ return $mmaModDataOffline.getEntryActions(dataId, entryId, siteId).then(function(entries) {
+ if (entries && entries.length) {
+ // Found. Delete add and edit actions first.
+ var proms = [];
+ angular.forEach(entries, function(entry) {
+ if (entry.action == 'add') {
+ justAdded = true;
+ groupId = entry.groupid;
+ proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
+ } else if (entry.action == 'edit') {
+ proms.push($mmaModDataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
+ }
+ });
+
+ return $q.all(proms);
+ }
+ }).then(function() {
+ if (justAdded) {
+ // The field was added offline, add again and stop.
+ return self.addEntry(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline)
+ .then(function(result) {
+ result.updated = true;
+ return result;
+ });
+ }
+
+ if (!$mmApp.isOnline() || forceOffline) {
+ // App is offline, store the action.
+ return storeOffline();
+ }
+
+ return self.editEntryOnline(entryId, contents, siteId).catch(function(error) {
+ if (error && !error.wserror) {
+ // Couldn't connect to server, store in offline.
+ return storeOffline();
+ } else {
+ // The WebService has thrown an error or offline not supported, reject.
+ return $q.reject(error.error);
+ }
+ });
+ });
+
+ // Convenience function to store a data to be synchronized later.
+ function storeOffline() {
+ return $mmaModDataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId)
+ .then(function() {
+ return {
+ updated: true
+ };
+ });
+ }
+ };
+
+ /**
+ * Convenience function to check fields requeriments here named "notifications"
+ *
+ * @param {Object} fields The fields that define the contents.
+ * @param {Object} contents The contents data of the fields.
+ * @return {Array} Array of notifications if any or false.
+ */
+ function checkFields(fields, contents) {
+ var notifications = [],
+ notification,
+ contentsIndexed = {};
+
+ angular.forEach(contents, function(content) {
+ if (typeof contentsIndexed[content.fieldid] == "undefined") {
+ contentsIndexed[content.fieldid] = [];
+ }
+ contentsIndexed[content.fieldid].push(content);
+ });
+
+ // App is offline, check required fields.
+ angular.forEach(fields, function(field) {
+ notification = $mmaModDataFieldsDelegate.getFieldsNotifications(field, contentsIndexed[field.id]);
+ if (notification) {
+ notifications.push({
+ fieldname: field.name,
+ notification: notification
+ });
+ }
+ });
+
+ return notifications.length ? notifications : false;
+ }
+
+ /**
+ * Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#editEntryOnline
+ * @param {Number} entryId Entry ID.
+ * @param {Object} data The fields data to be updated.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.editEntryOnline = function(entryId, data, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ entryid: entryId,
+ data: data
+ };
+
+ return site.write('mod_data_update_entry', params).catch(function(error) {
+ return $q.reject({
+ error: error,
+ wserror: $mmUtil.isWebServiceError(error)
+ });
+ });
+ });
+ };
+
+
+ /**
+ * Performs search over a database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#searchEntries
+ * @param {Number} databaseId The data instance id.
+ * @param {Number} [groupId] Group id, 0 means that the function will determine the user group.
+ * @param {String} [search] Search text. It will be used if advSearch is not defined.
+ * @param {Array} [advSearch] Advanced search data.
+ * @param {String} [sort] Sort by this field.
+ * @param {Number} [order] The direction of the sorting.
+ * @param {Number} [page] Page of records to return.
+ * @param {Number} [perPage] Records per page to return. Default on mmaModDataPerPage.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the action is done.
+ */
+ self.searchEntries = function(databaseId, groupId, search, advSearch, sort, order, page, perPage, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ databaseid: databaseId,
+ groupid: groupId || 0,
+ returncontents: 1,
+ page: page || 0,
+ perpage: perPage || mmaModDataPerPage
+ },
+ preSets = {
+ getFromCache: 0,
+ saveToCache: 1,
+ emergencyCache: 1
+ };
+
+ if (typeof sort != "undefined") {
+ params.sort = sort;
+ }
+
+ if (typeof order !== "undefined") {
+ params.order = order;
+ }
+
+ if (typeof search !== "undefined") {
+ params.search = search;
+ }
+
+ if (typeof advSearch !== "undefined") {
+ params.advsearch = advSearch;
+ }
+
+ return site.read('mod_data_search_entries', params, preSets);
+ });
+ };
+
+ /**
+ * Get the list of configured fields for the given database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#getFields
+ * @param {Number} dataId Data ID.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the fields are retrieved.
+ */
+ self.getFields = function(dataId, forceCache, ignoreCache, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ databaseid: dataId
+ },
+ preSets = {
+ cacheKey: getFieldsCacheKey(dataId)
+ };
+
+ if (forceCache) {
+ preSets.omitExpires = true;
+ } else if (ignoreCache) {
+ preSets.getFromCache = 0;
+ preSets.emergencyCache = 0;
+ }
+
+ return site.read('mod_data_get_fields', params, preSets).then(function(response) {
+ if (response && response.fields) {
+ return response.fields;
+ }
+ return $q.reject();
+ });
+ });
+ };
+
+ /**
+ * Invalidates database fields data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateFieldsData
+ * @param {Number} dataId Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ self.invalidateFieldsData = function(dataId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.invalidateWsCacheForKey(getFieldsCacheKey(dataId));
+ });
+ };
+
+ /**
+ * Performs the whole fetch of the entries in the database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#fetchAllEntries
+ * @param {Number} dataId Data ID.
+ * @param {Number} [groupId] Group ID.
+ * @param {Number} [sort] Sort the records by this field id. See $mmaModData#getEntries for more information.
+ * @param {String} [order] The direction of the sorting. See $mmaModData#getEntries for more information.
+ * @param {Number} [perPage] Records per page to fetch. It has to match with the prefetch.
+ * Default on mmaModDataPerPage.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when done.
+ */
+ self.fetchAllEntries = function(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, siteId) {
+ siteId = siteId || $mmSite.getId();
+ perPage = perPage || mmaModDataPerPage;
+ return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId);
+ };
+
+ /**
+ * Recursive call on fetch all entries.
+ *
+ * @param {Number} dataId Data ID.
+ * @param {Number} groupId Group ID.
+ * @param {Number} sort Sort the records by this field id. See $mmaModData#getEntries for more information.
+ * @param {String} order The direction of the sorting. See $mmaModData#getEntries for more information.
+ * @param {Number} perPage Records per page to fetch. It has to match with the prefetch.
+ * @param {Boolean} forceCache True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {Array} entries Entries already fetch (just to concatenate them).
+ * @param {Number} page Page of records to return.
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved when done.
+ */
+ function fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page, siteId) {
+ return self.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId)
+ .then(function(result) {
+ entries = entries.concat(result.entries);
+
+ var canLoadMore = ((page + 1) * perPage) < result.totalcount;
+ if (canLoadMore) {
+ return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page + 1,
+ siteId);
+ }
+ return entries;
+ });
+ }
+
+ /**
+ * Invalidate the prefetched content except files.
+ * To invalidate files, use $mmaModData#invalidateFiles.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateContent
+ * @param {Number} moduleId The module ID.
+ * @param {Number} courseId Course ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise}
+ */
+ self.invalidateContent = function(moduleId, courseId, siteId) {
+ siteId = siteId || $mmSite.getId();
+ return self.getDatabase(courseId, moduleId, siteId, true).then(function(data) {
+ var ps = [];
+ // Do not invalidate database data before getting database info, we need it!
+ ps.push(self.invalidateDatabaseData(courseId, siteId));
+ ps.push(self.invalidateDatabaseWSData(data.id, siteId));
+
+ return $q.all(ps);
+ });
+ };
+
+ /**
+ * Invalidate the prefetched files.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#invalidateFiles
+ * @param {Number} moduleId The module ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the files are invalidated.
+ */
+ self.invalidateFiles = function(moduleId, siteId) {
+ return $mmFilepool.invalidateFilesByComponent(siteId, mmaModDataComponent, moduleId);
+ };
+
+ /**
+ * Report the database as being viewed.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModData#logView
+ * @param {String} id Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the WS call is successful.
+ */
+ self.logView = function(id, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var params = {
+ databaseid: id
+ };
+ return site.write('mod_data_view_database', params);
+ });
+ };
+
+ return self;
+});
diff --git a/www/addons/mod/data/services/data_offline.js b/www/addons/mod/data/services/data_offline.js
new file mode 100644
index 00000000000..916a46ae8cc
--- /dev/null
+++ b/www/addons/mod/data/services/data_offline.js
@@ -0,0 +1,261 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+.constant('mmaModDataEntriesStore', 'mma_mod_data_entry')
+
+.config(function($mmSitesFactoryProvider, mmaModDataEntriesStore) {
+ var stores = [
+ {
+ name: mmaModDataEntriesStore,
+ keyPath: ['dataid', 'entryid', 'action'],
+ indexes: [
+ {
+ name: 'dataid'
+ },
+ {
+ name: 'courseid'
+ },
+ {
+ name: 'groupid'
+ },
+ {
+ name: 'action'
+ },
+ {
+ name: 'entryid'
+ },
+ {
+ name: 'timemodified'
+ },
+ {
+ name: 'dataAndEntry',
+ keyPath: ['dataid', 'entryid']
+ }
+ ]
+ }
+ ];
+ $mmSitesFactoryProvider.registerStores(stores);
+})
+
+/**
+ * Offline data factory.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataOffline
+ */
+.factory('$mmaModDataOffline', function($mmSitesManager, $log, $mmFS, mmaModDataEntriesStore) {
+ $log = $log.getInstance('$mmaModDataOffline');
+
+ var self = {};
+
+ /**
+ * Delete all the actions of an entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#deleteAllEntryActions
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Database entry ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if deleted, rejected if failure.
+ */
+ self.deleteAllEntryActions = function(dataId, entryId, siteId) {
+ return self.getEntryActions(dataId, entryId, siteId).then(function(actions) {
+ var promises = [];
+ angular.forEach(actions, function(action) {
+ promises.push(self.deleteEntry(dataId, entryId, action.action, siteId));
+ });
+ return $q.all(promises);
+ });
+ };
+
+ /**
+ * Delete an stored entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#deleteEntry
+ * @param {Number} dataId Database ID.
+ * @param {String} entryId Database entry Id.
+ * @param {String} action Action to be done
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if deleted, rejected if failure.
+ */
+ self.deleteEntry = function(dataId, entryId, action, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.getDb().remove(mmaModDataEntriesStore, [dataId, entryId, action]);
+ });
+ };
+
+ /**
+ * Get all the stored entry data from all the databases.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getAllEntries
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with entries.
+ */
+ self.getAllEntries = function(siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.getDb().getAll(mmaModDataEntriesStore);
+ });
+ };
+
+ /**
+ * Get an stored entry data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getEntry
+ * @param {Number} dataId Database ID.
+ * @param {String} entryId Database entry Id.
+ * @param {String} action Action to be done
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with entry.
+ */
+ self.getEntry = function(dataId, entryId, action, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.getDb().get(mmaModDataEntriesStore, [dataId, entryId, action]);
+ });
+ };
+
+ /**
+ * Get an all stored entry actions data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getEntryActions
+ * @param {Number} dataId Database ID.
+ * @param {String} entryId Database entry Id.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with entry actions.
+ */
+ self.getEntryActions = function(dataId, entryId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.getDb().whereEqual(mmaModDataEntriesStore, 'dataAndEntry', [dataId, entryId]);
+ });
+ };
+
+ /**
+ * Get all the stored entry data from a certain database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getDatabaseEntries
+ * @param {Number} dataId Database ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with entries.
+ */
+ self.getDatabaseEntries = function(dataId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ return site.getDb().whereEqual(mmaModDataEntriesStore, 'dataid', dataId);
+ });
+ };
+
+ /**
+ * Check if there are offline entries to send.
+ *
+ * @module mm.addons.method
+ * @ngdoc method
+ * @name $mmaModDataOffline#hasOfflineData
+ * @param {Number} dataId Database ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with boolean: true if has offline answers, false otherwise.
+ */
+ self.hasOfflineData = function(dataId, siteId) {
+ return self.getDatabaseEntries(dataId, siteId).then(function(entries) {
+ return !!entries.length;
+ }).catch(function() {
+ // No offline data found, return false.
+ return false;
+ });
+ };
+
+ /**
+ * Save an entry data to be sent later.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#saveEntry
+ * @param {Number} dataId Database ID.
+ * @param {String} entryId Database entry Id. If action is add entryId should be 0 and -timemodified will be used.
+ * @param {String} action Action to be done to the entry: [add, edit, delete, approve, disapprove]
+ * @param {Number} courseId Course ID of the database.
+ * @param {Number} [groupId] Group ID. ONly provided when adding.
+ * @param {Array} [fields] Array of field data of the entry if needed.
+ * @param {Number} [timemodified] The time the entry was modified. If not defined, current time.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if stored, rejected if failure.
+ */
+ self.saveEntry = function(dataId, entryId, action, courseId, groupId, fields, timemodified, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ timemodified = timemodified || new Date().getTime();
+ entryId = typeof entryId == "undefined" || entryId === false ? -timemodified : entryId;
+ var entry = {
+ dataid: dataId,
+ courseid: courseId,
+ groupid: groupId,
+ action: action,
+ entryid: entryId,
+ fields: fields,
+ timemodified: timemodified
+ };
+ return site.getDb().insert(mmaModDataEntriesStore, entry);
+ });
+ };
+
+ /**
+ * Get the path to the folder where to store files for offline files in a database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getDatabaseFolder
+ * @param {Number} dataId Database ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with the path.
+ */
+ self.getDatabaseFolder = function(dataId, siteId) {
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+
+ var siteFolderPath = $mmFS.getSiteFolder(site.getId()),
+ folderPath = 'offlinedatabase/' + dataId;
+
+ return $mmFS.concatenatePaths(siteFolderPath, folderPath);
+ });
+ };
+
+ /**
+ * Get the path to the folder where to store files for a new offline entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataOffline#getEntryFieldFolder
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId The ID of the entry.
+ * @param {Number} fieldId Field ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with the path.
+ */
+ self.getEntryFieldFolder = function(dataId, entryId, fieldId ,siteId) {
+ return self.getDatabaseFolder(dataId, siteId).then(function(folderPath) {
+ return $mmFS.concatenatePaths(folderPath, entryId + '_' + fieldId);
+ });
+ };
+
+ return self;
+});
\ No newline at end of file
diff --git a/www/addons/mod/data/services/data_sync.js b/www/addons/mod/data/services/data_sync.js
new file mode 100644
index 00000000000..5618175fa6c
--- /dev/null
+++ b/www/addons/mod/data/services/data_sync.js
@@ -0,0 +1,348 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Data synchronization service.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataSync
+ */
+.factory('$mmaModDataSync', function($log, $mmaModData, $mmSite, $mmSitesManager, $q, $mmaModDataOffline, $mmCourse, $mmUtil,
+ $mmApp, $mmEvents, $translate, mmaModDataSyncTime, $mmSync, mmaModDataEventAutomSynced, mmaModDataComponent,
+ $mmSyncBlock, $mmLang, $mmaModDataHelper) {
+
+ $log = $log.getInstance('$mmaModDataSync');
+
+ // Inherit self from $mmSync.
+ var self = $mmSync.createChild(mmaModDataComponent, mmaModDataSyncTime);
+
+ /**
+ * Check if a database has data to synchronize.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataSync#hasDataToSync
+ * @param {Number} dataId Database ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with boolean: true if has data to sync, false otherwise.
+ */
+ self.hasDataToSync = function(dataId, siteId) {
+ return $mmaModDataOffline.hasOfflineData(dataId, siteId);
+ };
+
+ /**
+ * Try to synchronize all data that need it and haven't been synchronized in a while.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataSync#syncAllDatabases
+ * @param {String} [siteId] Site ID to sync. If not defined, sync all sites.
+ * @return {Promise} Promise resolved when the sync is done.
+ */
+ self.syncAllDatabases = function(siteId) {
+ if (!$mmApp.isOnline()) {
+ $log.debug('Cannot sync all databases because device is offline.');
+ return $q.reject();
+ }
+
+ var promise;
+ if (!siteId) {
+ // No site ID defined, sync all sites.
+ $log.debug('Try to sync database in all sites.');
+ promise = $mmSitesManager.getSitesIds();
+ } else {
+ $log.debug('Try to sync database in site ' + siteId);
+ promise = $q.when([siteId]);
+ }
+
+ return promise.then(function(siteIds) {
+ var sitePromises = [];
+
+ angular.forEach(siteIds, function(siteId) {
+ // Sync submissions.
+ sitePromises.push($mmaModDataOffline.getAllEntries(siteId).then(function(offlineActions) {
+ var promises = {};
+
+ // Do not sync same database twice.
+ angular.forEach(offlineActions, function(action) {
+ if (typeof promises[action.dataid] != 'undefined') {
+ return;
+ }
+
+ promises[action.dataid] = self.syncDatabaseIfNeeded(action.dataid, siteId)
+ .then(function(result) {
+ if (result && result.updated) {
+ // Sync done. Send event.
+ $mmEvents.trigger(mmaModDataEventAutomSynced, {
+ siteid: siteId,
+ dataid: action.dataid,
+ warnings: result.warnings
+ });
+ }
+ });
+ });
+ // Promises will be an object so, convert to an array first;
+ promises = $mmUtil.objectToArray(promises);
+
+ return $q.all(promises);
+ }));
+ });
+
+ return $q.all(sitePromises);
+ });
+ };
+
+ /**
+ * Sync a database only if a certain time has passed since the last time.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataSync#syncDatabaseIfNeeded
+ * @param {Number} dataId Database ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is synced or if it doesn't need to be synced.
+ */
+ self.syncDatabaseIfNeeded = function(dataId, siteId) {
+ return self.isSyncNeeded(dataId, siteId).then(function(needed) {
+ if (needed) {
+ return self.syncDatabase(dataId, siteId);
+ }
+ });
+ };
+
+ /**
+ * Try to synchronize a database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataSync#syncDatabase
+ * @param {Number} dataId Data ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if sync is successful, rejected otherwise.
+ */
+ self.syncDatabase = function(dataId, siteId) {
+ siteId = siteId || $mmSite.getId();
+
+ var syncPromise,
+ data,
+ courseId,
+ result = {
+ warnings: [],
+ updated: false
+ };
+
+ if (self.isSyncing(dataId, siteId)) {
+ // There's already a sync ongoing for this discussion, return the promise.
+ return self.getOngoingSync(dataId, siteId);
+ }
+
+ // Verify that data isn't blocked.
+ if ($mmSyncBlock.isBlocked(mmaModDataComponent, dataId, siteId)) {
+ $log.debug('Cannot sync database ' + dataId + ' because it is blocked.');
+ var modulename = $mmCourse.translateModuleName('data');
+ return $mmLang.translateAndReject('mm.core.errorsyncblocked', {$a: modulename});
+ }
+
+ $log.debug('Try to sync database ' + dataId);
+
+ // Get offline actions to be sent.
+ syncPromise = $mmaModDataOffline.getDatabaseEntries(dataId, siteId).catch(function() {
+ // No offline data found, return empty array.
+ return [];
+ }).then(function(offlineActions) {
+ if (!offlineActions.length) {
+ // Nothing to sync.
+ return;
+ } else if (!$mmApp.isOnline()) {
+ // Cannot sync in offline.
+ return $q.reject();
+ }
+
+ courseId = offlineActions[0].courseid;
+
+ return $mmaModData.getDatabaseById(courseId, dataId, siteId).then(function(database) {
+ data = database;
+
+ var promises = [],
+ offlineEntries = {};
+
+ angular.forEach(offlineActions, function(entry) {
+ if (typeof offlineEntries[entry.entryid] == "undefined") {
+ offlineEntries[entry.entryid] = [];
+ }
+ offlineEntries[entry.entryid].push(entry);
+ });
+
+ angular.forEach(offlineEntries, function(entryActions) {
+ promises.push(syncEntry(data, entryActions, result, siteId));
+ });
+
+ return $q.all(promises);
+ }).then(function() {
+ if (result.updated) {
+ // Data has been sent to server. Now invalidate the WS calls.
+ return $mmaModData.invalidateContent(data.cmid, courseId, siteId).catch(function() {
+ // Ignore errors.
+ });
+ }
+ });
+ }).then(function() {
+ // Sync finished, set sync time.
+ return self.setSyncTime(dataId, siteId).catch(function() {
+ // Ignore errors.
+ });
+ }).then(function() {
+ // All done, return the warnings.
+ return result;
+ });
+
+ return self.addOngoingSync(dataId, syncPromise, siteId);
+ };
+
+ /**
+ * Synchronize an entry.
+ *
+ * @param {Object} data Database.
+ * @param {Object} entryActions Entry actions.
+ * @param {Object} result Object with the result of the sync.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if success, rejected otherwise.
+ */
+ function syncEntry(data, entryActions, result, siteId) {
+ var discardError,
+ timePromise,
+ entryId = 0,
+ offlineId,
+ deleted = false,
+ promises = [];
+
+ // Sort entries by timemodified.
+ entryActions = entryActions.sort(function(a, b) {
+ return a.timemodified - b.timemodified;
+ });
+
+ entryId = entryActions[0].entryid;
+
+ if (entryId > 0) {
+ timePromise = $mmaModData.getEntry(data.id, entryId, siteId).then(function(entry) {
+ return entry.entry.timemodified;
+ }).catch(function() {
+ return -1;
+ });
+ } else {
+ offlineId = entryId;
+ timePromise = $q.when(0);
+ }
+
+ return timePromise.then(function(timemodified) {
+ if (timemodified < 0 || timemodified >= entryActions[0].timemodified) {
+ // The entry was not found in Moodle or the entry has been modified, discard the action.
+ result.updated = true;
+ discardError = $translate.instant('mma.mod_data.warningsubmissionmodified');
+ return $mmaModDataOffline.deleteAllEntryActions(data.id, entryId, siteId);
+ }
+
+ angular.forEach(entryActions, function(action) {
+ var actionPromise,
+ proms = [];
+
+ entryId = action.entryid > 0 ? action.entryid : entryId;
+
+ if (action.fields) {
+ angular.forEach(action.fields, function(field) {
+ // Upload Files if asked.
+ var value = JSON.parse(field.value);
+ if (value.online || value.offline) {
+ var files = value.online || [],
+ fileProm = value.offline ? $mmaModDataHelper.getStoredFiles(action.dataid, entryId, field.fieldid) :
+ $q.when([]);
+
+ proms.push(fileProm.then(function(offlineFiles) {
+ files = files.concat(offlineFiles);
+ return $mmaModDataHelper.uploadOrStoreFiles(action.dataid, 0, entryId, field.fieldid, files, false,
+ siteId).then(function(filesResult) {
+ field.value = JSON.stringify(filesResult);
+ });
+ }));
+ }
+ });
+ }
+
+ actionPromise = $q.all(proms).then(function() {
+ // Perform the action.
+ switch (action.action) {
+ case 'add':
+ return $mmaModData.addEntryOnline(action.dataid, action.fields, data.groupid, siteId)
+ .then(function(result) {
+ entryId = result.newentryid;
+ });
+ case 'edit':
+ return $mmaModData.editEntryOnline(entryId, action.fields, siteId);
+ case 'approve':
+ return $mmaModData.approveEntryOnline(entryId, true, siteId);
+ case 'disapprove':
+ return $mmaModData.approveEntryOnline(entryId, false, siteId);
+ case 'delete':
+ return $mmaModData.deleteEntryOnline(entryId, siteId).then(function() {
+ deleted = true;
+ });
+ }
+ });
+
+ promises.push(actionPromise.catch(function(error) {
+ if (error && error.wserror) {
+ // The WebService has thrown an error, this means it cannot be performed. Discard.
+ discardError = error.error;
+ } else {
+ // Couldn't connect to server, reject.
+ return $q.reject(error && error.error);
+ }
+ }).then(function() {
+ // Delete the offline data.
+ result.updated = true;
+ return $mmaModDataOffline.deleteEntry(action.dataid, action.entryid, action.action, siteId);
+ }));
+ });
+ return $q.all(promises);
+ }).then(function() {
+ if (discardError) {
+ // Submission was discarded, add a warning.
+ var message = $translate.instant('mm.core.warningofflinedatadeleted', {
+ component: $mmCourse.translateModuleName('data'),
+ name: data.name,
+ error: discardError
+ });
+
+ if (result.warnings.indexOf(message) == -1) {
+ result.warnings.push(message);
+ }
+ }
+
+ // Sync done. Send event.
+ $mmEvents.trigger(mmaModDataEventAutomSynced, {
+ siteid: siteId,
+ dataid: data.id,
+ entryid: entryId,
+ offlineentryid: offlineId,
+ warnings: result.warnings,
+ deleted: deleted
+ });
+ });
+ }
+
+ return self;
+});
diff --git a/www/addons/mod/data/services/fieldsdelegate.js b/www/addons/mod/data/services/fieldsdelegate.js
new file mode 100644
index 00000000000..5e3f3c0cd0a
--- /dev/null
+++ b/www/addons/mod/data/services/fieldsdelegate.js
@@ -0,0 +1,363 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Delegate to register database fields handlers.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataFieldsDelegate
+ * @description
+ *
+ * Delegate to register database fields handlers.
+ * You can use this service to register your own fields handlers to be used in a database.
+ *
+ * To register a handler:
+ *
+ * $mmaModDataFieldsDelegate.registerHandler('mmaYourAddon', 'pluginType', 'handlerName');
+ *
+ * Please take into account that this delegate belongs to an addon so it might not be available in custom apps.
+ * We recommend using $mmAddonManager to inject this delegate to avoid errors.
+ *
+ * Example:
+ *
+ * .run(function($mmAddonManager) {
+ * var $mmaModDataFieldsDelegate = $mmAddonManager.get('$mmaModDataFieldsDelegate');
+ * if ($mmaModDataFieldsDelegate) {
+ * $mmaModDataFieldsDelegate.registerHandler('mmaModDataFieldText', 'text', '$mmaModDataFieldTextHandler');
+ * }
+ * });
+ *
+ * @see $mmaModDataFieldsDelegate#registerHandler to see the methods your handle needs to implement.
+ */
+.factory('$mmaModDataFieldsDelegate', function($log, $mmSite, $mmUtil, $q) {
+ $log = $log.getInstance('$mmaModDataFieldsDelegate');
+
+ var handlers = {},
+ enabledHandlers = {},
+ self = {},
+ lastUpdateHandlersStart;
+
+ /**
+ * Get the handler for a certain field plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getPluginHandler
+ * @param {String} pluginType Type of the plugin.
+ * @return {Object} Handler. Undefined if no handler found for the plugin.
+ */
+ self.getPluginHandler = function(pluginType) {
+ if (typeof enabledHandlers[pluginType] != 'undefined') {
+ return enabledHandlers[pluginType];
+ }
+ };
+
+ /**
+ * Get database data in the input data to search.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getFieldSearchData
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @return {Array} Name and data field.
+ */
+ self.getFieldSearchData = function(field, inputData) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.getFieldSearchData) {
+ return handler.getFieldSearchData(field, inputData);
+ }
+ return false;
+ };
+
+ /**
+ * Get database data in the input data to add or update entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getFieldEditData
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Array} Name and data field.
+ */
+ self.getFieldEditData = function(field, inputData, originalFieldData) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.getFieldEditData) {
+ return handler.getFieldEditData(field, inputData, originalFieldData);
+ }
+ return false;
+ };
+
+ /**
+ * Get database data in the input files to add or update entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getFieldEditFiles
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Array} Name and data field.
+ */
+ self.getFieldEditFiles = function(field, inputData, originalFieldData) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.getFieldEditFiles) {
+ return handler.getFieldEditFiles(field, inputData, originalFieldData);
+ }
+ return [];
+ };
+
+ /**
+ * Check if field type manage files or not.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#hasFiles
+ * @param {Object} field Defines the field to be checked.
+ * @return {Boolean} If the field type manages files.
+ */
+ self.hasFiles = function(field) {
+ var handler = self.getPluginHandler(field.type);
+ return handler && handler.getFieldEditFiles;
+ };
+
+ /**
+ * Check if the data has changed for a certain field.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#hasFieldDataChanged
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the search form.
+ * @param {Object} originalFieldData Original field entered data.
+ * @return {Promise} Promise rejected if has changed, resolved if no changes.
+ */
+ self.hasFieldDataChanged = function(field, inputData, originalFieldData) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.hasFieldDataChanged) {
+ return $q.when(handler.hasFieldDataChanged(field, inputData, originalFieldData)).then(function(result) {
+ return result ? $q.reject() : $q.when();
+ });
+ }
+ return $q.when();
+ };
+
+ /**
+ * Check and get field requeriments.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getFieldsNotification
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} inputData Data entered in the edit form.
+ * @return {String} String with the notification or false.
+ */
+ self.getFieldsNotifications = function(field, inputData) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.getFieldsNotifications) {
+ return handler.getFieldsNotifications(field, inputData);
+ }
+ return false;
+ };
+
+ /**
+ * Override field content data with offline submission.
+ *
+ * @param {Object} field Defines the field to be rendered.
+ * @param {Object} originalContent Original data to be overriden.
+ * @param {Array} offlineContent Array with all the offline data to override.
+ * @param {Array} offlineFiles Array with all the offline files in the field.
+ * @return {Object} Data overriden
+ */
+ self.overrideData = function(field, originalContent, offlineContent, offlineFiles) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler && handler.overrideData && offlineContent) {
+ return handler.overrideData(originalContent || {}, offlineContent, offlineFiles);
+ }
+ return originalContent;
+ };
+
+ /**
+ * Get the directive to use for a certain database plugin.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#getDirectiveForPlugin
+ * @param {Object} field Defines the field to be rendered.
+ * @return {String} Directive name. Undefined if no directive found.
+ */
+ self.getDirectiveForPlugin = function(field) {
+ var handler = self.getPluginHandler(field.type);
+ if (handler) {
+ if (handler.getDirectiveName) {
+ return handler.getDirectiveName(field);
+ }
+
+ // Fallback.
+ return 'mma-mod-data-field-' + field.type;
+ }
+ };
+
+ /**
+ * Check if a field plugin is supported.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#isPluginSupported
+ * @param {String} pluginType Type of the plugin.
+ * @return {Boolean} True if supported, false otherwise.
+ */
+ self.isPluginSupported = function(pluginType) {
+ return typeof enabledHandlers[pluginType] != 'undefined';
+ };
+
+
+ /**
+ * Register a field plugin handler.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#registerHandler
+ * @param {String} addon Handler's name.
+ * @param {String} pluginType Type of the plugin the handler supports.
+ * @param {String|Object|Function} handler Must be resolved to an object defining the following properties. Or to a function
+ * returning an object defining these properties. See {@link $mmUtil#resolveObject}.
+ * - getFieldSearchData(field, inputData) Optional.
+ * Should return name and data entered to the field.
+ * - getFieldEditData(field, inputData, originalFieldData) Optional.
+ * Should return fieldid and data entered to the field in a promise
+ * or array.
+ * - hasFieldDataChanged(field, inputData, originalFieldData) Optional.
+ * Should return if field has been changed by the user.
+ * - getFieldEditFiles(field, inputData, originalFieldData) Optional.
+ * Should return an array of files stored in temp store.
+ * - getFieldsNotifications(field, inputData) Optional.
+ * Should return an array of notifications before sending data.
+ * - overrideData(originalContent, offlineContent, offlineFiles) Optional.
+ * Should return an object with the overriden content from offline
+ * submission.
+ */
+ self.registerHandler = function(addon, pluginType, handler) {
+ if (typeof handlers[pluginType] !== 'undefined') {
+ $log.debug("Addon '" + addon + "' already registered as handler for '" + pluginType + "'");
+ return false;
+ }
+ $log.debug("Registered handler '" + addon + "' for field plugin '" + pluginType + "'");
+ handlers[pluginType] = {
+ addon: addon,
+ instance: undefined,
+ handler: handler
+ };
+
+ // Handlers are registered in the "run" phase, it can happen that a handler is registered after updateHandlers
+ // has been executed. If the user is logged in we'll run updateHandler to be sure it has been executed for this site.
+ if ($mmSite.isLoggedIn()) {
+ self.updateHandler(pluginType, handlers[pluginType]);
+ }
+ };
+
+ /**
+ * Check if a time belongs to the last update handlers call.
+ * This is to handle the cases where updateHandlers don't finish in the same order as they're called.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#isLastUpdateCall
+ * @param {Number} time Time to check.
+ * @return {Boolean} True if equal, false otherwise.
+ */
+ self.isLastUpdateCall = function(time) {
+ if (!lastUpdateHandlersStart) {
+ return true;
+ }
+ return time == lastUpdateHandlersStart;
+ };
+
+
+ /**
+ * Check if a handler is enabled for a certain site and add/remove it to enabledHandlers.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#updateHandler
+ * @param {String} pluginType The type of the plugin this handler handles.
+ * @param {Object} handlerInfo The handler details.
+ * @param {Number} time Time this update process started.
+ * @return {Promise} Resolved when done.
+ * @protected
+ */
+ self.updateHandler = function(pluginType, handlerInfo, time) {
+ var siteId = $mmSite.getId();
+
+
+ if (typeof handlerInfo.instance === 'undefined') {
+ handlerInfo.instance = $mmUtil.resolveObject(handlerInfo.handler, true);
+ }
+
+ // Checks if site is enabled.
+ var enabled = $mmSite.isLoggedIn();
+
+ // Verify that this call is the last one that was started.
+ // Check that site hasn't changed since the check started.
+ if (self.isLastUpdateCall(time) && $mmSite.isLoggedIn() && $mmSite.getId() === siteId) {
+ if (enabled) {
+ enabledHandlers[pluginType] = handlerInfo.instance;
+ } else {
+ delete enabledHandlers[pluginType];
+ }
+ }
+ };
+
+ /**
+ * Update the enabled handlers for the current site.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataFieldsDelegate#updateHandlers
+ * @return {Promise} Resolved when done.
+ * @protected
+ */
+ self.updateHandlers = function() {
+ var promises = [],
+ now = new Date().getTime();
+
+ $log.debug('Updating handlers for current site.');
+
+ lastUpdateHandlersStart = now;
+
+ // Loop over all the handlers.
+ angular.forEach(handlers, function(handlerInfo, pluginType) {
+ promises.push(self.updateHandler(pluginType, handlerInfo, now));
+ });
+
+ return $q.all(promises).then(function() {
+ return true;
+ }, function() {
+ // Never reject.
+ return true;
+ });
+ };
+
+ return self;
+})
+
+.run(function($mmEvents, mmCoreEventLogin, mmCoreEventSiteUpdated, $mmaModDataFieldsDelegate, mmCoreEventRemoteAddonsLoaded) {
+ $mmEvents.on(mmCoreEventLogin, $mmaModDataFieldsDelegate.updateHandlers);
+ $mmEvents.on(mmCoreEventSiteUpdated, $mmaModDataFieldsDelegate.updateHandlers);
+ $mmEvents.on(mmCoreEventRemoteAddonsLoaded, $mmaModDataFieldsDelegate.updateHandlers);
+});
diff --git a/www/addons/mod/data/services/handlers.js b/www/addons/mod/data/services/handlers.js
new file mode 100644
index 00000000000..28a535209c7
--- /dev/null
+++ b/www/addons/mod/data/services/handlers.js
@@ -0,0 +1,453 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Mod data handlers.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataHandlers
+ */
+.factory('$mmaModDataHandlers', function($mmCourse, $mmaModData, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite, $q,
+ mmaModDataComponent, $mmaModDataPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmContentLinkHandlerFactory,
+ mmCoreEventPackageStatusChanged, mmCoreOutdated, $mmCoursePrefetchDelegate, mmaModDataEventEntryChanged, $translate,
+ $mmaModDataSync) {
+ var self = {};
+
+ /**
+ * Course content handler.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#courseContent
+ */
+ self.courseContent = function() {
+
+ var self = {};
+
+ /**
+ * Whether or not the module is enabled for the site.
+ *
+ * @return {Boolean}
+ */
+ self.isEnabled = function() {
+ return $mmaModData.isPluginEnabled();
+ };
+
+ /**
+ * Get the controller.
+ *
+ * @param {Object} module The module info.
+ * @param {Number} courseId The course ID.
+ * @return {Function}
+ */
+ self.getController = function(module, courseId) {
+ return function($scope) {
+ var downloadBtn = {
+ hidden: true,
+ icon: 'ion-ios-cloud-download-outline',
+ label: 'mm.core.download',
+ action: function(e) {
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ download();
+ }
+ },
+ refreshBtn = {
+ hidden: true,
+ icon: 'ion-android-refresh',
+ label: 'mm.core.refresh',
+ action: function(e) {
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ $mmaModData.invalidateContent(module.id, courseId).finally(function() {
+ download();
+ });
+ }
+ };
+
+ $scope.title = module.name;
+ $scope.icon = $mmCourse.getModuleIconSrc('data');
+ $scope.class = 'mma-mod_data-handler';
+ $scope.buttons = [downloadBtn, refreshBtn];
+ $scope.spinner = true; // Show spinner while calculating status.
+
+ $scope.action = function(e) {
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ $state.go('site.mod_data', {module: module, moduleid: module.id, courseid: courseId});
+ };
+
+ function download() {
+
+ $scope.spinner = true; // Show spinner since this operation might take a while.
+ // We need to call getDownloadSize, the package might have been updated.
+ $mmaModDataPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
+ $mmUtil.confirmDownloadSize(size).then(function() {
+ return $mmaModDataPrefetchHandler.prefetch(module, courseId).catch(function(error) {
+ if (!$scope.$$destroyed) {
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
+ }
+ });
+ }).catch(function() {
+ // User hasn't confirmed, stop spinner.
+ $scope.spinner = false;
+ });
+ }).catch(function(error) {
+ $scope.spinner = false;
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ });
+ }
+
+ // Show buttons according to module status.
+ function showStatus(status) {
+ if (status) {
+ $scope.spinner = status === mmCoreDownloading;
+ downloadBtn.hidden = status !== mmCoreNotDownloaded;
+ refreshBtn.hidden = status !== mmCoreOutdated;
+ }
+ }
+
+ // Listen for changes on this module status.
+ var statusObserver = $mmEvents.on(mmCoreEventPackageStatusChanged, function(data) {
+ if (data.siteid === $mmSite.getId() && data.componentId === module.id &&
+ data.component === mmaModDataComponent) {
+ showStatus(data.status);
+ }
+ });
+
+ // Get current status to decide which icon should be shown.
+ $mmCoursePrefetchDelegate.getModuleStatus(module, courseId).then(showStatus);
+
+ $scope.$on('$destroy', function() {
+ statusObserver && statusObserver.off && statusObserver.off();
+ });
+ };
+ };
+
+ return self;
+ };
+
+ /**
+ * Content links handler for module index page.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#indexLinksHandler
+ */
+ self.indexLinksHandler = $mmContentLinksHelper.createModuleIndexLinkHandler('mmaModData', 'data', $mmaModData);
+
+
+ /**
+ * Content links handler for database show entry.
+ * Match mod/data/view.php?d=6&rid=5 with a valid data id and entryid.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#showEntryLinksHandler
+ */
+ self.showEntryLinksHandler = $mmContentLinkHandlerFactory.createChild(
+ /\/mod\/data\/view\.php.*([\?\&](d|rid|page|group|mode)=\d+)/, '$mmCourseDelegate_mmaModData');
+
+ // Check if the showEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled.
+ self.showEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled;
+
+ // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions.
+ self.showEntryLinksHandler.getActions = function(siteIds, url, params, courseId) {
+ if (typeof params.d == 'undefined') {
+ // Id not defined. Cannot treat the URL.
+ return false;
+ }
+
+ if ((!params.mode || params.mode != "single") && typeof params.rid == 'undefined') {
+ return false;
+ }
+
+ return [{
+ action: function(siteId) {
+ var modal = $mmUtil.showModalLoading(),
+ dataId = parseInt(params.d, 10),
+ rId = parseInt(params.rid, 10) || false,
+ group = parseInt(params.group, 10) || false,
+ page = parseInt(params.page, 10) || false;
+
+ return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) {
+ var stateParams = {
+ moduleid: module.id,
+ module: module,
+ courseid: module.course
+ };
+
+ if (group) {
+ stateParams.group = group;
+ }
+
+ if (params.mode && params.mode == "single") {
+ stateParams.page = page || 1;
+ } else if (rId) {
+ stateParams.entryid = rId;
+ }
+
+
+ return $mmContentLinksHelper.goInSite('site.mod_data-entry', stateParams, siteId);
+ }).finally(function() {
+ modal.dismiss();
+ });
+ }
+ }];
+ };
+
+ /**
+ * Convenience function to help get courseId.
+ * @param {Number} dataId Database Id.
+ * @param {Number} siteId Site Id, if not set, current site will be used.
+ * @param {Number} courseId Course Id if already set.
+ * @return {Promise} Resolved with course Id when done.
+ */
+ function getActivityCourseIdIfNotSet(dataId, siteId, courseId) {
+ if (courseId) {
+ return $q.when(courseId);
+ }
+
+ return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) {
+ return module.course;
+ });
+ }
+
+ /**
+ * Content links handler for database approve/disapprove entry.
+ * Match mod/data/view.php?d=6&approve=5 with a valid data id and entryid.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#approveEntryLinksHandler
+ */
+ self.approveEntryLinksHandler = $mmContentLinkHandlerFactory.createChild(
+ /\/mod\/data\/view\.php.*([\?\&](d|approve|disapprove)=\d+)/, '$mmCourseDelegate_mmaModData');
+
+ // Check if the approveEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled.
+ self.approveEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled;
+
+ // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions.
+ self.approveEntryLinksHandler.getActions = function(siteIds, url, params, courseId) {
+ if (typeof params.d == 'undefined' || (typeof params.approve == 'undefined' && typeof params.disapprove == 'undefined')) {
+ // Required fields not defined. Cannot treat the URL.
+ return false;
+ }
+
+ return [{
+ action: function(siteId) {
+ var modal = $mmUtil.showModalLoading(),
+ dataId = parseInt(params.d, 10),
+ entryId = parseInt(params.approve, 10) || parseInt(params.disapprove, 10),
+ approve = parseInt(params.approve, 10) ? true : false;
+
+ return getActivityCourseIdIfNotSet(dataId, siteId, courseId).then(function(cId) {
+ courseId = cId;
+
+ // Approve/disapprove entry.
+ return $mmaModData.approveEntry(dataId, entryId, approve, courseId, siteId).catch(function(message) {
+ modal.dismiss();
+ $mmUtil.showErrorModalDefault(message, 'mma.mod_data.errorapproving', true);
+
+ return $q.reject();
+ });
+ }).then(function() {
+ var promises = [];
+ promises.push($mmaModData.invalidateEntryData(dataId, entryId, siteId));
+ promises.push($mmaModData.invalidateEntriesData(dataId, siteId));
+
+ return $q.all(promises);
+ }).then(function() {
+ $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: siteId});
+
+ modal.dismiss();
+ $mmUtil.showToast(approve ? 'mma.mod_data.recordapproved' : 'mma.mod_data.recorddisapproved', true, 3000);
+ }).finally(function() {
+ // Just in case. In fact we need to dismiss the modal before showing a toast or error message.
+ modal.dismiss();
+ });
+ }
+ }];
+ };
+
+ /**
+ * Content links handler for database delete entry.
+ * Match mod/data/view.php?d=6&delete=5 with a valid data id and entryid.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#deleteEntryLinksHandler
+ */
+ self.deleteEntryLinksHandler = $mmContentLinkHandlerFactory.createChild(
+ /\/mod\/data\/view\.php.*([\?\&](d|delete)=\d+)/, '$mmCourseDelegate_mmaModData');
+
+ // Check if the deleteEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled.
+ self.deleteEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled;
+
+ // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions.
+ self.deleteEntryLinksHandler.getActions = function(siteIds, url, params, courseId) {
+ if (typeof params.d == 'undefined' || typeof params.delete == 'undefined') {
+ // Required fields not defined. Cannot treat the URL.
+ return false;
+ }
+
+ return [{
+ action: function(siteId) {
+ // Confirm before delete.
+ return $mmUtil.showConfirm($translate.instant('mma.mod_data.confirmdeleterecord')).then(function() {
+ var modal = $mmUtil.showModalLoading(),
+ dataId = parseInt(params.d, 10),
+ entryId = parseInt(params.delete, 10);
+
+ return getActivityCourseIdIfNotSet(dataId, siteId, courseId).then(function(cId) {
+ courseId = cId;
+
+ // Delete entry.
+ return $mmaModData.deleteEntry(dataId, entryId, courseId, siteId, true).catch(function(message) {
+ modal.dismiss();
+ $mmUtil.showErrorModalDefault(message, 'mma.mod_data.errordeleting', true);
+
+ return $q.reject();
+ });
+ }).then(function() {
+ var promises = [];
+ promises.push($mmaModData.invalidateEntryData(dataId, entryId, siteId));
+ promises.push($mmaModData.invalidateEntriesData(dataId, siteId));
+
+ return $q.all(promises);
+ }).then(function() {
+ $mmEvents.trigger(mmaModDataEventEntryChanged, {dataId: dataId, entryId: entryId, siteId: siteId,
+ deleted: true});
+
+ modal.dismiss();
+ $mmUtil.showToast('mma.mod_data.recorddeleted', true, 3000);
+ }).finally(function() {
+ // Just in case. In fact we need to dismiss the modal before showing a toast or error message.
+ modal.dismiss();
+ });
+ });
+ }
+ }];
+ };
+
+ /**
+ * Content links handler for database add or edit entry.
+ * Match mod/data/edit.php?d=6&rid=6 with a valid data and optional record id.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#editEntryLinksHandler
+ */
+ self.editEntryLinksHandler = $mmContentLinkHandlerFactory.createChild(
+ /\/mod\/data\/edit\.php.*([\?\&](d|rid)=\d+)/, '$mmCourseDelegate_mmaModData');
+
+ // Check if the showEntryLinksHandler is enabled for a certain site. See $mmContentLinkHandlerFactory#isEnabled.
+ self.editEntryLinksHandler.isEnabled = $mmaModData.isPluginEnabled;
+
+ // Get actions to perform with the link. See $mmContentLinkHandlerFactory#getActions.
+ self.editEntryLinksHandler.getActions = function(siteIds, url, params, courseId) {
+ if (typeof params.d == 'undefined') {
+ // Id not defined. Cannot treat the URL.
+ return false;
+ }
+
+ return [{
+ action: function(siteId) {
+ var modal = $mmUtil.showModalLoading(),
+ dataId = parseInt(params.d, 10),
+ rId = parseInt(params.rid, 10) || false;
+
+ return $mmCourse.getModuleBasicInfoByInstance(dataId, 'data', siteId).then(function(module) {
+ var stateParams = {
+ moduleid: module.id,
+ module: module,
+ courseid: module.course
+ };
+
+ if (rId) {
+ stateParams.entryid = rId;
+ }
+
+ return $mmContentLinksHelper.goInSite('site.mod_data-edit', stateParams, siteId);
+ }).finally(function() {
+ modal.dismiss();
+ });
+ }
+ }];
+ };
+
+ /**
+ * Synchronization handler.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHandlers#syncHandler
+ */
+ self.syncHandler = function() {
+
+ var self = {};
+
+ /**
+ * Execute the process.
+ * Receives the ID of the site affected, undefined for all sites.
+ *
+ * @param {String} [siteId] ID of the site affected, undefined for all sites.
+ * @return {Promise} Promise resolved when done, rejected if failure.
+ */
+ self.execute = function(siteId) {
+ return $mmaModDataSync.syncAllDatabases(siteId);
+ };
+
+ /**
+ * Get the time between consecutive executions.
+ *
+ * @return {Number} Time between consecutive executions (in ms).
+ */
+ self.getInterval = function() {
+ return 600000; // 10 minutes.
+ };
+
+ /**
+ * Whether it's a synchronization process or not.
+ *
+ * @return {Boolean} True if is a sync process, false otherwise.
+ */
+ self.isSync = function() {
+ return true;
+ };
+
+ /**
+ * Whether the process uses network or not.
+ *
+ * @return {Boolean} True if uses network, false otherwise.
+ */
+ self.usesNetwork = function() {
+ return true;
+ };
+
+ return self;
+ };
+
+ return self;
+});
diff --git a/www/addons/mod/data/services/helper.js b/www/addons/mod/data/services/helper.js
new file mode 100644
index 00000000000..a07ccd36b4f
--- /dev/null
+++ b/www/addons/mod/data/services/helper.js
@@ -0,0 +1,711 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Helper to gather some common functions for database.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataHelper
+ */
+.factory('$mmaModDataHelper', function($mmaModData, $mmaModDataFieldsDelegate, $q, mmaModDataComponent, $mmFileUploader, $mmSite,
+ $mmaModDataOffline, $mmFS, $mmFileUploaderHelper, $mmSitesManager, $translate) {
+
+ var self = {
+ searchOther: {
+ 'fn': 'firstname',
+ 'ln': 'lastname'
+ }
+ };
+
+ /**
+ * Displays fields for being shown.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#displayShowFields
+ * @param {String} template Template HMTL.
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @param {Object} entry Entry.
+ * @param {String} mode Mode list or show.
+ * @param {Object} actions Actions that can be performed to the record.
+ * @return {String} Generated HTML.
+ */
+ self.displayShowFields = function(template, fields, entry, mode, actions) {
+ if (!template) {
+ return "";
+ }
+
+ var replace, render;
+
+ // Replace the fields found on template.
+ angular.forEach(fields, function(field) {
+ replace = "[[" + field.name + "]]";
+ replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ replace = new RegExp(replace, 'gi');
+
+ // Replace field by a generic directive.
+ render = '';
+ template = template.replace(replace, render);
+ });
+
+ angular.forEach(actions, function(enabled, action) {
+ replace = new RegExp("##" + action + "##", 'gi');
+ if (enabled) {
+ if (action == 'moreurl') {
+ // Render more url directly because it can be part of an HTML attribute.
+ render = $mmSite.getURL() + '/mod/data/view.php?d={{data.id}}&rid=' + entry.id;
+ } else if (action == 'approvalstatus') {
+ render = $translate.instant('mma.mod_data.' + (entry.approved ? 'approved' : 'notapproved'));
+ } else {
+ render = '';
+ }
+ template = template.replace(replace, render);
+ } else {
+ template = template.replace(replace, "");
+ }
+ });
+
+ return template;
+ };
+
+ /**
+ * Returns an object with all the actions that the user can do over the record.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getActions
+ * @param {Object} database Database activity.
+ * @param {Object} accessInfo Access info to the activity.
+ * @param {Object} record Entry or record where the actions will be performed.
+ * @return {Object} Keyed with the action names and boolean to evalute if it can or cannot be done.
+ */
+ self.getActions = function(database, accessInfo, record) {
+ var replacements = {};
+
+ replacements.more = true;
+ replacements.moreurl = true;
+ replacements.user = true;
+ replacements.userpicture = true;
+ replacements.timeadded = true;
+ replacements.timemodified = true;
+
+ replacements.edit = record.canmanageentry && !record.deleted; // This already checks capabilities and readonly period.
+ replacements.delete = record.canmanageentry;
+ replacements.approve = database.approval && accessInfo.canapprove && !record.approved && !record.deleted;
+ replacements.disapprove = database.approval && accessInfo.canapprove && record.approved && !record.deleted;
+
+ replacements.approvalstatus = database.approval;
+ replacements.comments = database.comments;
+
+ // Unsupported actions.
+ replacements.delcheck = false;
+ replacements.export = false;
+
+ return replacements;
+ };
+
+ /**
+ * Returns the record with the offline actions applied.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#applyOfflineActions
+ * @param {Object} record Entry to modify.
+ * @param {Object} offlineActions Offline data with the actions done.
+ * @param {Object} fields Entry defined fields indexed by fieldid.
+ * @return {Object} Modified entry.
+ */
+ self.applyOfflineActions = function(record, offlineActions, fields) {
+ var promises = [];
+ angular.forEach(offlineActions, function(action) {
+ switch (action.action) {
+ case 'approve':
+ record.approved = true;
+ break;
+ case 'disapprove':
+ record.approved = false;
+ break;
+ case 'delete':
+ record.deleted = true;
+ break;
+ case 'add':
+ case 'edit':
+ var offlineContents = {};
+ angular.forEach(action.fields, function(offlineContent) {
+ if (typeof offlineContents[offlineContent.fieldid] == "undefined") {
+ offlineContents[offlineContent.fieldid] = {};
+ }
+
+ if (offlineContent.subfield) {
+ offlineContents[offlineContent.fieldid][offlineContent.subfield] = JSON.parse(offlineContent.value);
+ } else {
+ offlineContents[offlineContent.fieldid][''] = JSON.parse(offlineContent.value);
+ }
+ });
+
+ // Override field contents.
+ angular.forEach(fields, function(field) {
+ if ($mmaModDataFieldsDelegate.hasFiles(field)) {
+ promises.push(self.getStoredFiles(record.dataid, record.id, field.id).then(function(offlineFiles) {
+ record.contents[field.id] = $mmaModDataFieldsDelegate.overrideData(field, record.contents[field.id],
+ offlineContents[field.id], offlineFiles);
+ }));
+ } else {
+ record.contents[field.id] = $mmaModDataFieldsDelegate.overrideData(field, record.contents[field.id],
+ offlineContents[field.id]);
+ }
+ });
+ break;
+ }
+ });
+ return $q.all(promises).then(function() {
+ return record;
+ });
+ };
+
+ /**
+ * Displays Advanced Search Fields.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#displayAdvancedSearchFields
+ * @param {String} template Template HMTL.
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @return {String} Generated HTML.
+ */
+ self.displayAdvancedSearchFields = function(template, fields) {
+ if (!template) {
+ return "";
+ }
+
+ var replace;
+
+ // Replace the fields found on template.
+ angular.forEach(fields, function(field) {
+ replace = "[[" + field.name + "]]";
+ replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ replace = new RegExp(replace, 'gi');
+
+ // Replace field by a generic directive.
+ var render = '';
+ template = template.replace(replace, render);
+ });
+
+ // Not pluginable other search elements.
+ angular.forEach(self.searchOther, function(field, name) {
+ replace = new RegExp("##" + field + "##", 'gi');
+
+ // Replace field by the text input.
+ var render = '';
+ template = template.replace(replace, render);
+ });
+ return template;
+ };
+
+ /**
+ * Return the form data.
+ *
+ * @param {Object} form Form (DOM element).
+ * @return {Object} Data retrieved from form.
+ */
+ function getFormData(form) {
+ var formData = {};
+
+ angular.forEach(form.elements, function(element) {
+ var name = element.name || '';
+ // Ignore submit inputs.
+ if (!name || element.type == 'submit' || element.tagName == 'BUTTON') {
+ return;
+ }
+
+ // Get the value.
+ if (element.type == 'checkbox') {
+ if (typeof formData[name] == "undefined") {
+ formData[name] = {};
+ }
+ formData[name][element.value] = !!element.checked;
+ } else if (element.type == 'radio') {
+ if (element.checked) {
+ formData[name] = element.value;
+ }
+ } else {
+ formData[name] = element.value;
+ }
+ });
+
+ return formData;
+ }
+
+ /**
+ * Retrieve the entered data in search in a form.
+ * We don't use ng-model because it doesn't detect changes done by JavaScript.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getSearchDataFromForm
+ * @param {Object} form Form (DOM element).
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @return {Object} Object with the answers.
+ */
+ self.getSearchDataFromForm = function(form, fields) {
+ if (!form || !form.elements) {
+ return {};
+ }
+
+ var searchedData = getFormData(form);
+
+ // Filter and translate fields to each field plugin.
+ var advancedSearch = [];
+ angular.forEach(fields, function(field) {
+ var fieldData = $mmaModDataFieldsDelegate.getFieldSearchData(field, searchedData);
+ if (fieldData) {
+ angular.forEach(fieldData, function(data) {
+ data.value = JSON.stringify(data.value);
+ // WS wants values in Json format.
+ advancedSearch.push(data);
+ });
+ }
+ });
+
+ // Not pluginable other search elements.
+ angular.forEach(self.searchOther, function(field, name) {
+ if (searchedData[name]) {
+ // WS wants values in Json format.
+ advancedSearch.push({
+ name: name,
+ value: JSON.stringify(searchedData[name])
+ });
+ }
+ });
+
+ return advancedSearch;
+ };
+
+ /**
+ * Displays Edit Search Fields.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#displayEditFields
+ * @param {String} template Template HMTL.
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @param {Array} [contents] Contents for the editing entry (if editing).
+ * @return {String} Generated HTML.
+ */
+ self.displayEditFields = function(template, fields) {
+ if (!template) {
+ return "";
+ }
+
+ var replace;
+
+ // Replace the fields found on template.
+ angular.forEach(fields, function(field) {
+ replace = "[[" + field.name + "]]";
+ replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ replace = new RegExp(replace, 'gi');
+
+ // Replace field by a generic directive.
+ var render = '';
+ template = template.replace(replace, render);
+
+ // Replace the field id tag.
+ replace = "[[" + field.name + "#id]]";
+ replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ replace = new RegExp(replace, 'gi');
+
+ template = template.replace(replace, 'field_'+ field.id);
+ });
+
+ return template;
+ };
+
+ /**
+ * Retrieve the entered data in the edit form.
+ * We don't use ng-model because it doesn't detect changes done by JavaScript.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getEditDataFromForm
+ * @param {Object} form Form (DOM element).
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @param {Number} [dataId] Database Id. If set, files will be uploaded and itemId set.
+ * @param {Number} entryId Entry Id.
+ * @param {Object} entryContents Original entry contents indexed by field id.
+ * @param {Boolean} offline True to prepare the data for an offline uploading, false otherwise.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} That contains object with the answers.
+ */
+ self.getEditDataFromForm = function(form, fields, dataId, entryId, entryContents, offline, siteId) {
+ if (!form || !form.elements) {
+ return $q.when({});
+ }
+
+ siteId = siteId || $mmSite.getId();
+
+ var formData = getFormData(form);
+
+ // Filter and translate fields to each field plugin.
+ var edit = [],
+ promises = [];
+ angular.forEach(fields, function(field) {
+ promises.push($q.when($mmaModDataFieldsDelegate.getFieldEditData(field, formData, entryContents[field.id]))
+ .then(function (fieldData) {
+ if (fieldData) {
+ var proms = [];
+
+ angular.forEach(fieldData, function(data) {
+ var dataProm;
+
+ // Upload Files if asked.
+ if (dataId && data.files) {
+ dataProm = self.uploadOrStoreFiles(dataId, 0, entryId, data.fieldid, data.files, offline, siteId).then(function(filesResult) {
+ delete data.files;
+ data.value = filesResult;
+ });
+ } else {
+ dataProm = $q.when();
+ }
+
+ proms.push(dataProm.then(function() {
+ if (data.value) {
+ data.value = JSON.stringify(data.value);
+ }
+ if (typeof data.subfield == "undefined") {
+ data.subfield = "";
+ }
+
+ // WS wants values in Json format.
+ edit.push(data);
+ }));
+ });
+
+ return $q.all(proms);
+ }
+ }));
+ });
+
+ return $q.all(promises).then(function() {
+ return edit;
+ });
+ };
+
+ /**
+ * Retrieve the temp files to be updated.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getEditTmpFiles
+ * @param {Object} form Form (DOM element).
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @param {Number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
+ * @param {Object} entryContents Original entry contents indexed by field id.
+ * @return {Promise} That contains object with the files.
+ */
+ self.getEditTmpFiles = function(form, fields, dataId, entryContents) {
+ if (!form || !form.elements) {
+ return $q.when([]);
+ }
+
+ var formData = getFormData(form);
+
+ // Filter and translate fields to each field plugin.
+ var promises = [];
+ angular.forEach(fields, function(field) {
+ promises.push(
+ $q.when($mmaModDataFieldsDelegate.getFieldEditFiles(field, formData, entryContents[field.id]))
+ );
+ });
+
+ return $q.all(promises).then(function(fieldsFiles) {
+ var files = [];
+
+ angular.forEach(fieldsFiles, function(fieldFiles) {
+ files = files.concat(fieldFiles);
+ });
+ return files;
+ });
+ };
+
+ /**
+ * Check if data has been changed by the user.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#hasEditDataChanged
+ * @param {Object} form Form (DOM element).
+ * @param {Array} fields Fields that defines every content in the entry.
+ * @param {Number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
+ * @param {Object} entryContents Original entry contents indexed by field id.
+ * @return {Promise} True if changed, false if not.
+ */
+ self.hasEditDataChanged = function(form, fields, dataId, entryContents) {
+ var inputData = getFormData(form),
+ promises = [];
+
+ angular.forEach(fields, function(field) {
+ promises.push($mmaModDataFieldsDelegate.hasFieldDataChanged(field, inputData, entryContents[field.id]));
+ });
+ // Will reject on first change detected.
+ return $q.all(promises).then(function() {
+ // No changes.
+ return false;
+ }).catch(function() {
+ // Has changes.
+ return true;
+ });
+ };
+
+ /**
+ * Upload or store some files, depending if the user is offline or not.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#uploadOrStoreFiles
+ * @param {Number} dataId Database ID.
+ * @param {Number} [itemId] Draft ID to use. Undefined or 0 to create a new draft ID.
+ * @param {Number} entryId Entry ID or, if creating, timemodified.
+ * @param {Number} fieldId Field ID.
+ * @param {Object[]} files List of files.
+ * @param {Boolean} offline True if files sould be stored for offline, false to upload them.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if success.
+ */
+ self.uploadOrStoreFiles = function(dataId, itemId, entryId, fieldId, files, offline, siteId) {
+ if (files.length) {
+ if (offline) {
+ return self.storeFiles(dataId, entryId, fieldId, files, siteId);
+ }
+ return $mmFileUploader.uploadOrReuploadFiles(files, mmaModDataComponent, itemId, siteId);
+ }
+ return $q.when(0);
+ };
+
+ /**
+ * Given a list of files (either online files or local files), store the local files in a local folder
+ * to be submitted later.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#storeFiles
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID or, if creating, timemodified.
+ * @param {Number} fieldId Field ID.
+ * @param {Object[]} files List of files.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved if success, rejected otherwise.
+ */
+ self.storeFiles = function(dataId, entryId, fieldId, files, siteId) {
+ // Get the folder where to store the files.
+ return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) {
+ return $mmFileUploader.storeFilesToUpload(folderPath, files);
+ });
+ };
+
+ /**
+ * Delete stored attachment files for an entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#deleteStoredFiles
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID or, if creating, timemodified.
+ * @param {Number} fieldId Field ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when deleted.
+ */
+ self.deleteStoredFiles = function(dataId, entryId, fieldId, siteId) {
+ return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) {
+ return $mmFS.removeDir(folderPath);
+ });
+ };
+
+ /**
+ * Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getStoredFiles
+ * @param {Number} dataId Database ID.
+ * @param {Number} entryId Entry ID or, if creating, timemodified.
+ * @param {Number} fieldId Field ID.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with the files.
+ */
+ self.getStoredFiles = function(dataId, entryId, fieldId, siteId) {
+ return $mmaModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId).then(function(folderPath) {
+ return $mmFileUploaderHelper.getStoredFiles(folderPath).catch(function() {
+ // Ignore not found files.
+ return [];
+ });
+ });
+ };
+
+ /**
+ * Add a prefix to all rules in a CSS string.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#prefixCSS
+ * @param {String} css CSS code to be prefixed.
+ * @param {String} prefix Prefix css selector.
+ * @return {String} Prefixed CSS.
+ */
+ self.prefixCSS = function(css, prefix) {
+ if (!css) {
+ return "";
+ }
+ // Remove comments first.
+ var regExp = /\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm;
+ css = css.replace(regExp, "");
+ // Add prefix.
+ regExp = /([^]*?)({[^]*?}|,)/g;
+ return css.replace(regExp, prefix + " $1 $2");
+ };
+
+ /**
+ * Get page info related to an entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getPageInfoByEntry
+ * @param {Number} dataId Data ID.
+ * @param {Number} entryId Entry ID.
+ * @param {Number} groupId Group ID.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. Current if not defined.
+ * @return {Promise} Containing page number, if has next and have following page.
+ */
+ self.getPageInfoByEntry = function(dataId, entryId, groupId, forceCache, ignoreCache, siteId) {
+ return self.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then(function(entries) {
+ for (var index in entries) {
+ if (entries[index] == entryId) {
+ index = parseInt(index, 10);
+ return {
+ previousId: entries[index - 1] || false,
+ nextId: entries[index + 1] || false,
+ entryId: entryId,
+ page: index + 1, // Parsed to natural language.
+ numEntries: entries.length
+ };
+ }
+ }
+ return false;
+ });
+ };
+
+ /**
+ * Get page info related to an entry by page number.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getPageInfoByPage
+ * @param {Number} dataId Data ID.
+ * @param {Number} page Page number.
+ * @param {Number} groupId Group ID.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. Current if not defined.
+ * @return {Promise} Containing page number, if has next and have following page.
+ */
+ self.getPageInfoByPage = function(dataId, page, groupId, forceCache, ignoreCache, siteId) {
+ return self.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then(function(entries) {
+ var index = parseInt(page, 10) - 1,
+ entryId = entries[index];
+ if (entryId) {
+ return {
+ previousId: entries[index - 1] || false,
+ nextId: entries[index + 1] || false,
+ entryId: entryId,
+ page: page, // Parsed to natural language.
+ numEntries: entries.length
+ };
+ }
+ return false;
+ });
+ };
+
+ /**
+ * Fetch all entries and return it's Id
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getAllEntriesIds
+ * @param {Number} dataId Data ID.
+ * @param {Number} groupId Group ID.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. Current if not defined.
+ * @return {Promise} Resolved with an array of entry ID.
+ */
+ self.getAllEntriesIds = function(dataId, groupId, forceCache, ignoreCache, siteId) {
+ return $mmaModData.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId)
+ .then(function(entries) {
+ return entries.map(function(entry) {
+ return entry.id;
+ });
+ });
+ };
+
+ /**
+ * Get an online or offline entry.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataHelper#getEntry
+ * @param {Object} data Database.
+ * @param {Number} entryId Entry ID.
+ * @param {Object} [offlineActions] Offline data with the actions done. Required for offline entries.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with the entry.
+ */
+ self.getEntry = function(data, entryId, offlineActions, siteId) {
+ if (entryId > 0) {
+ // It's an online entry, get it from WS.
+ return $mmaModData.getEntry(data.id, entryId, siteId);
+ }
+
+ // It's an offline entry, search it in the offline actions.
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ for (var x in offlineActions) {
+ if (offlineActions[x].action == 'add') {
+ var offlineEntry = offlineActions[x],
+ siteInfo = site.getInfo(),
+ entryData = {
+ id: offlineEntry.entryid,
+ canmanageentry: true,
+ approved: !data.approval || data.manageapproved,
+ dataid: offlineEntry.dataid,
+ groupid: offlineEntry.groupid,
+ timecreated: -offlineEntry.entryid,
+ timemodified: -offlineEntry.entryid,
+ userid: siteInfo.userid,
+ fullname: siteInfo.fullname,
+ contents: {}
+ };
+
+ return {entry: entryData};
+ }
+ }
+ });
+ };
+
+ return self;
+});
diff --git a/www/addons/mod/data/services/prefetch_handler.js b/www/addons/mod/data/services/prefetch_handler.js
new file mode 100644
index 00000000000..bdcf40f3a66
--- /dev/null
+++ b/www/addons/mod/data/services/prefetch_handler.js
@@ -0,0 +1,364 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+angular.module('mm.addons.mod_data')
+
+/**
+ * Mod data prefetch handler.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc service
+ * @name $mmaModDataPrefetchHandler
+ */
+.factory('$mmaModDataPrefetchHandler', function($mmaModData, mmaModDataComponent, $mmFilepool, $q, $mmUtil, $mmPrefetchFactory,
+ $mmSite, $mmGroups, $mmCourse, $mmComments) {
+
+ var self = $mmPrefetchFactory.createPrefetchHandler(mmaModDataComponent);
+
+ // RegExp to check if a module has updates based on the result of $mmCoursePrefetchDelegate#getCourseUpdates.
+ self.updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/;
+
+ /**
+ * Download the module.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#download
+ * @param {Object} module The module object returned by WS.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @return {Promise} Promise resolved when all files have been downloaded. Data returned is not reliable.
+ */
+ self.download = function(module, courseId) {
+ // Database cannot be downloaded right away, only prefetched.
+ return self.prefetch(module, courseId);
+ };
+
+ /**
+ * Get the list of downloadable files.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#getFiles
+ * @param {Object} module Module to get the files.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @param {String} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved with the list of files.
+ */
+ self.getFiles = function(module, courseId, siteId) {
+ siteId = siteId || $mmSite.getId();
+
+ return getDatabaseInfoHelper(module, courseId, true, undefined, undefined, siteId).then(function(info) {
+ return info.files;
+ });
+ };
+
+ /**
+ * Helper function to get all database info just once.
+ *
+ * @param {Object} module Module to get the files.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @param {Boolean} [omitFail] True to always return even if fails. Default false.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved with the info fetched.
+ */
+ function getDatabaseInfoHelper(module, courseId, omitFail, forceCache, ignoreCache, siteId) {
+ var database,
+ groups = [],
+ entries = [],
+ files = [];
+
+ return $mmaModData.getDatabase(courseId, module.id, siteId, forceCache).then(function(data) {
+ files = self.getIntroFilesFromInstance(module, data);
+
+ database = data;
+ return $mmGroups.getActivityGroupInfo(module.id, false, undefined, siteId).then(function(groupInfo) {
+ if (!groupInfo.groups || groupInfo.groups.length == 0) {
+ groupInfo.groups = [{id: 0}];
+ }
+ groups = groupInfo.groups;
+
+ return getAllUniqueEntries(database.id, groups, forceCache, ignoreCache, siteId);
+ });
+ }).then(function(uniqueEntries) {
+ entries = uniqueEntries;
+ files = files.concat(getEntriesFiles(entries));
+
+ return {
+ database: database,
+ groups: groups,
+ entries: entries,
+ files: files
+ };
+ }).catch(function(message) {
+ if (omitFail) {
+ // Any error, return the info we have.
+ return {
+ database: database,
+ groups: groups,
+ entries: entries,
+ files: files
+ };
+ }
+ return $q.reject(message);
+ });
+ }
+
+ /**
+ * Retrieves all the entries for all the groups and then returns only unique entries.
+ *
+ * @param {Number} dataId Database Id.
+ * @param {Array} groups Array of groups in the activity.
+ * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} siteId Site ID.
+ * @return {Promise} All unique entries.
+ */
+ function getAllUniqueEntries(dataId, groups, forceCache, ignoreCache, siteId) {
+ var promises = [];
+
+ angular.forEach(groups, function(group) {
+ promises.push($mmaModData.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache,
+ ignoreCache, siteId));
+ });
+
+ return $q.all(promises).then(function(responses) {
+ var uniqueEntries = {};
+
+ angular.forEach(responses, function(groupEntries) {
+ angular.forEach(groupEntries, function(entry) {
+ uniqueEntries[entry.id] = entry;
+ });
+ });
+
+ return uniqueEntries;
+ });
+ }
+
+ /**
+ * Returns the file contained in the entries.
+ *
+ * @param {Array} entries List of entries to get files from.
+ * @return {Array} List of files.
+ */
+ function getEntriesFiles(entries) {
+ var files = [];
+
+ angular.forEach(entries, function(entry) {
+ angular.forEach(entry.contents, function(content) {
+ files = files.concat(content.files);
+ });
+ });
+
+ return files;
+ }
+
+ /**
+ * Returns database intro files.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#getIntroFiles
+ * @param {Object} module The module object returned by WS.
+ * @param {Number} courseId Course ID.
+ * @return {Promise} Promise resolved with list of intro files.
+ */
+ self.getIntroFiles = function(module, courseId) {
+ return $mmaModData.getDatabase(courseId, module.id).catch(function() {
+ // Not found, return undefined so module description is used.
+ }).then(function(database) {
+ return self.getIntroFilesFromInstance(module, database);
+ });
+ };
+
+ /**
+ * Get revision of a data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#getRevision
+ * @param {Object} module Module to get the revision.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @return {Number} Promise resolved with revision.
+ */
+ self.getRevision = function(module, courseId) {
+ // Data will always be controlled using the getCourseUpdates.
+ return 0;
+ };
+
+ /**
+ * Get timemodified of a data.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#getTimemodified
+ * @param {Object} module Module to get the timemodified.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @return {Promise} Promise resolved with timemodified.
+ */
+ self.getTimemodified = function(module, courseId) {
+ var siteId = $mmSite.getId();
+
+ return $mmaModData.getDatabase(courseId, module.id, siteId).then(function(database) {
+ var files = self.getIntroFilesFromInstance(module, database);
+
+ return Math.max(database.timemodified || 0, $mmFilepool.getTimemodifiedFromFileList(files));
+ }).catch(function() {
+ return 0;
+ });
+ };
+
+ /**
+ * Invalidate the prefetched content.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#invalidateContent
+ * @param {Number} moduleId The module ID.
+ * @param {Number} courseId Course ID of the module.
+ * @return {Promise}
+ */
+ self.invalidateContent = function(moduleId, courseId) {
+ return $mmaModData.invalidateContent(moduleId, courseId);
+ };
+
+ /**
+ * Invalidates WS calls needed to determine module status.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#invalidateModule
+ * @param {Object} module Module to invalidate.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @return {Promise} Promise resolved when done.
+ */
+ self.invalidateModule = function(module, courseId) {
+ return $mmaModData.invalidateDatabaseData(courseId);
+ };
+
+ /**
+ * Check if a database is downloadable.
+ * A database isn't downloadable if it's not open yet.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#isDownloadable
+ * @param {Object} module Module to check.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @return {Promise} Promise resolved with true if downloadable, resolved with false otherwise.
+ */
+ self.isDownloadable = function(module, courseId) {
+ return $mmaModData.getDatabase(courseId, module.id, false, true).then(function(database) {
+ return $mmaModData.getDatabaseAccessInformation(database.id).then(function(accessData) {
+ // Check if database is restricted by time.
+ if (!accessData.timeavailable) {
+ var time = $mmUtil.timestamp();
+
+ // It is restricted, checking times.
+ if (database.timeavailablefrom && time < database.timeavailablefrom) {
+ return false;
+ }
+ if (database.timeavailableto && time > database.timeavailableto) {
+ return false;
+ }
+ }
+ return true;
+ });
+ });
+ };
+
+ /**
+ * Whether or not the module is enabled for the site.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#isEnabled
+ * @return {Boolean}
+ */
+ self.isEnabled = function() {
+ return $mmaModData.isPluginEnabled();
+ };
+
+ /**
+ * Prefetch the module.
+ *
+ * @module mm.addons.mod_data
+ * @ngdoc method
+ * @name $mmaModDataPrefetchHandler#prefetch
+ * @param {Object} module The module object returned by WS.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @param {Boolean} single True if we're downloading a single module, false if we're downloading a whole section.
+ * @return {Promise} Promise resolved when all files have been downloaded. Data returned is not reliable.
+ */
+ self.prefetch = function(module, courseId, single) {
+ return self.prefetchPackage(module, courseId, single, prefetchDatabase);
+ };
+
+ /**
+ * Prefetch a database.
+ *
+ * @param {Object} module The module object returned by WS.
+ * @param {Number} courseId Course ID the module belongs to.
+ * @param {Boolean} single True if we're downloading a single module, false if we're downloading a whole section.
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved with an object with 'revision' and 'timemod'.
+ */
+ function prefetchDatabase(module, courseId, single, siteId) {
+ siteId = siteId || $mmSite.getId();
+
+ // Prefetch the database data.
+ return getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then(function(info) {
+ var database = info.database,
+ promises = [];
+
+ promises.push($mmaModData.getFields(database.id, false, true, siteId));
+
+ promises.push($mmFilepool.addFilesToQueueByUrl(siteId, info.files, self.component, module.id));
+
+ angular.forEach(info.groups, function(group) {
+ promises.push($mmaModData.getDatabaseAccessInformation(database.id, group.id, false, true, siteId));
+ });
+
+ angular.forEach(info.entries, function(entry) {
+ promises.push($mmaModData.getEntry(database.id, entry.id, siteId));
+ if (database.comments) {
+ promises.push($mmComments.getComments('module', database.coursemodule, 'mod_data', entry.id, 'database_entry',
+ 0, siteId));
+ }
+ });
+
+ // Add Basic Info to manage links.
+ promises.push($mmCourse.getModuleBasicInfoByInstance(database.id, 'data', siteId));
+
+ return $q.all(promises);
+ }).then(function() {
+ // Get revision and timemodified.
+
+ var promises = [];
+ promises.push(self.getRevision(module, courseId));
+ promises.push(self.getTimemodified(module, courseId));
+
+ // Return revision and timemodified.
+ return $q.all(promises).then(function(list) {
+ return {
+ revision: list[0],
+ timemod: list[1]
+ };
+ });
+ });
+ }
+
+ return self;
+});
diff --git a/www/addons/mod/data/templates/action.html b/www/addons/mod/data/templates/action.html
new file mode 100644
index 00000000000..8c111539f47
--- /dev/null
+++ b/www/addons/mod/data/templates/action.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+{{ entry.timecreated * 1000 | mmFormatDate:"dffulldate" }}
+{{ entry.timemodified * 1000 | mmFormatDate:"dffulldate" }}
+
+
+
+
+
+
+{{entry.fullname}}
diff --git a/www/addons/mod/data/templates/edit.html b/www/addons/mod/data/templates/edit.html
new file mode 100644
index 00000000000..275ed7517ea
--- /dev/null
+++ b/www/addons/mod/data/templates/edit.html
@@ -0,0 +1,27 @@
+
+ {{ title }}
+
+ {{ 'mm.core.save' | translate }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/www/addons/mod/feedback/lang/cs.json b/www/addons/mod/feedback/lang/cs.json
index 50c98674c0f..af958dc96ff 100644
--- a/www/addons/mod/feedback/lang/cs.json
+++ b/www/addons/mod/feedback/lang/cs.json
@@ -6,7 +6,7 @@
"captchaofflinewarning": "Dotazník se souborem captcha nemůže být dokončen, pokud není nakonfigurován režim offline nebo s vypnutým serverem.",
"complete_the_form": "Klikněte zde a odpovězte na otázky...",
"completed_feedbacks": "Odevzdané odpovědi",
- "continue_the_form": "Pokračovat ve formuláři",
+ "continue_the_form": "Pokračovat v zodpovídání otázek ...",
"feedback_is_not_open": "Dotazník není přístupný",
"feedback_submitted_offline": "Tento dotazník byl uložen k pozdějšímu odevzdání.",
"feedbackclose": "Povolit odpovědi",
diff --git a/www/addons/mod/feedback/lang/da.json b/www/addons/mod/feedback/lang/da.json
index 55d1b3cd1ba..6147eb30f82 100644
--- a/www/addons/mod/feedback/lang/da.json
+++ b/www/addons/mod/feedback/lang/da.json
@@ -5,7 +5,7 @@
"average": "Gennemsnit",
"complete_the_form": "Svar på spørgsmålene...",
"completed_feedbacks": "Afleverede svar",
- "continue_the_form": "Fortsæt formularen",
+ "continue_the_form": "Fortsæt med at besvare spørgsmålene",
"feedback_is_not_open": "Feedbacken er ikke åben",
"feedbackclose": "Tillad svar til",
"feedbackopen": "Tillad svar fra",
diff --git a/www/addons/mod/feedback/lang/de.json b/www/addons/mod/feedback/lang/de.json
index 7c665bbb337..4bb27721583 100644
--- a/www/addons/mod/feedback/lang/de.json
+++ b/www/addons/mod/feedback/lang/de.json
@@ -3,10 +3,10 @@
"anonymous": "Anonym",
"anonymous_entries": "Anonyme Einträge ({{$a}})",
"average": "Mittelwert",
- "captchaofflinewarning": "Ein Feedback mit Captcha kann offline nicht beendet werden. Captcha funktioniert nicht, wenn der Server nicht konfiguriert ist oder der Server nicht antwortet.",
+ "captchaofflinewarning": "Ein Feedback mit Captcha kann nicht offline beendet werden. Captcha funktioniert nur, wenn der Server antwortet.",
"complete_the_form": "Formular ausfüllen...",
"completed_feedbacks": "Ausgefüllte Feedbacks",
- "continue_the_form": "Ausfüllen fortsetzen",
+ "continue_the_form": "Beantwortung der Fragen fortsetzen ...",
"feedback_is_not_open": "Feedback ist zu diesem Zeitpunkt nicht möglich",
"feedback_submitted_offline": "Das Feedback wurde gespeichert, um es später zu übemitteln.",
"feedbackclose": "Antworten erlauben bis",
diff --git a/www/addons/mod/feedback/lang/el.json b/www/addons/mod/feedback/lang/el.json
index 7dd8e2abab8..1d5dec70464 100644
--- a/www/addons/mod/feedback/lang/el.json
+++ b/www/addons/mod/feedback/lang/el.json
@@ -3,10 +3,12 @@
"anonymous": "Ανώνυμα",
"anonymous_entries": "Ανώνυμες καταχωρήσεις",
"average": "Μέσος όρος",
+ "captchaofflinewarning": "Η ανατροφοδότηση με την χρήση captcha δεν μπορεί να ολοκληρωθεί εάν δεν έχει διαμορφωθεί, εάν βρίσκεστε εκτός λειτουργίας ή με ο server δεν λειτουργεί.",
"complete_the_form": "Απαντήστε τις ερωτήσεις...",
"completed_feedbacks": "Απαντήσεις που έχουν υποβληθεί",
"continue_the_form": "Συνεχίστε τη φόρμα",
"feedback_is_not_open": "Το σχόλιο δεν είναι ανοιχτό",
+ "feedback_submitted_offline": "Αυτή η ανατροφοδότηση έχει αποθηκευτεί για να υποβληθεί αργότερα.",
"feedbackclose": "Κλείσε το σχόλιο στις",
"feedbackopen": "Άνοιξε το σχόλιο στις",
"mapcourses": "Αντιστοίχηση σχόλιου σε μαθήματα",
diff --git a/www/addons/mod/feedback/lang/es-mx.json b/www/addons/mod/feedback/lang/es-mx.json
index 6c9cfa558f6..48c0b709868 100644
--- a/www/addons/mod/feedback/lang/es-mx.json
+++ b/www/addons/mod/feedback/lang/es-mx.json
@@ -3,10 +3,10 @@
"anonymous": "Anónima",
"anonymous_entries": "Respuestas anónimas ({{$a}})",
"average": "Promedio",
- "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada si no está configurada, si está en modo fuera-de-línea o con el servidor tirado.",
+ "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada fuera-de-línea, o si no está configurada, o con el servidor tirado.",
"complete_the_form": "Responda a las preguntas...",
"completed_feedbacks": "Respuestas enviadas",
- "continue_the_form": "Continuar con el formato",
+ "continue_the_form": "Continuar contestando las preguntas...",
"feedback_is_not_open": "La retroalimentación no está disponible",
"feedback_submitted_offline": "Esta retroalimentación ha sido guardada para enviarse más tarde.",
"feedbackclose": "Permitir respuestas a",
diff --git a/www/addons/mod/feedback/lang/es.json b/www/addons/mod/feedback/lang/es.json
index b0d70fa540b..d6fc51f295d 100644
--- a/www/addons/mod/feedback/lang/es.json
+++ b/www/addons/mod/feedback/lang/es.json
@@ -3,10 +3,12 @@
"anonymous": "Anónima",
"anonymous_entries": "Respuestas anónimas",
"average": "Promedio",
+ "captchaofflinewarning": "La retroalimentación con captcha no puede ser completada si no está configurada, si está en modo fuera-de-línea o con el servidor caído.",
"complete_the_form": "Responda a las preguntas...",
"completed_feedbacks": "Respuestas enviadas",
"continue_the_form": "Continuar con el formulario",
"feedback_is_not_open": "La encuesta no está disponible",
+ "feedback_submitted_offline": "Esta retroalimentación ha sido guardada para enviarse más tarde.",
"feedbackclose": "Permitir respuestas a",
"feedbackopen": "Permitir respuestas de",
"mapcourses": "Asignar encuesta a cursos",
diff --git a/www/addons/mod/feedback/lang/eu.json b/www/addons/mod/feedback/lang/eu.json
index 1f74e6b554e..b0a1488eb4f 100644
--- a/www/addons/mod/feedback/lang/eu.json
+++ b/www/addons/mod/feedback/lang/eu.json
@@ -9,8 +9,8 @@
"continue_the_form": "Jarraitu formularioarekin",
"feedback_is_not_open": "Inkesta ez dago zabalik",
"feedback_submitted_offline": "Feedback hau beranduago bidaltzeko gorde da.",
- "feedbackclose": "Noiz itxi inkesta",
- "feedbackopen": "Noiz zabaldu inkesta",
+ "feedbackclose": "Noiz arte baimendu erantzunak",
+ "feedbackopen": "Noiztik baimendu erantzunak",
"mapcourses": "Esleitu feedback-a ikastaroetarako",
"mode": "Modua",
"next_page": "Hurrengo orria",
@@ -18,7 +18,7 @@
"non_anonymous_entries": "Sarrera anonimorik ez ({{$a}})",
"non_respondents_students": "Erantzun ez duten ikasleak ({{$a}})",
"not_selected": "Aukeratu gabea",
- "not_started": "hasi gabea",
+ "not_started": "Hasi gabea",
"numberoutofrange": "Tartetik kanpoko zenbakia",
"overview": "Ikuspegi orokorra",
"page_after_submit": "Osaketa-mezua",
@@ -30,6 +30,6 @@
"save_entries": "Bidali zure erantzunak",
"show_entries": "Erakutsi erantzunak",
"show_nonrespondents": "Erakutsi erantzun gabeak",
- "started": "hasita",
+ "started": "Hasita",
"this_feedback_is_already_submitted": "Dagoeneko egina duzu jarduera hau."
}
\ No newline at end of file
diff --git a/www/addons/mod/feedback/lang/fr.json b/www/addons/mod/feedback/lang/fr.json
index e043077cb6a..032ec9ba573 100644
--- a/www/addons/mod/feedback/lang/fr.json
+++ b/www/addons/mod/feedback/lang/fr.json
@@ -3,10 +3,12 @@
"anonymous": "Anonyme",
"anonymous_entries": "Réponses anonymes ({{$a}})",
"average": "Moyenne",
+ "captchaofflinewarning": "Le feedback avec captcha ne peut pas être terminé hors ligne, ou s'il n'est pas configuré, ou si le serveur est arrêté.",
"complete_the_form": "Répondre aux questions...",
"completed_feedbacks": "Réponses envoyées",
- "continue_the_form": "Continuer le formulaire",
+ "continue_the_form": "Continuer à répondre aux questions...",
"feedback_is_not_open": "Le feedback n'est pas ouvert",
+ "feedback_submitted_offline": "Ce feedback a été enregistré pour être remis plus tard.",
"feedbackclose": "Permettre les réponses jusqu'au",
"feedbackopen": "Permettre les réponses dès le",
"mapcourses": "Associer le feedback aux cours",
diff --git a/www/addons/mod/feedback/lang/he.json b/www/addons/mod/feedback/lang/he.json
index 52e5c8f67b8..d1cac22f250 100644
--- a/www/addons/mod/feedback/lang/he.json
+++ b/www/addons/mod/feedback/lang/he.json
@@ -1,7 +1,7 @@
{
"analysis": "ניתוח",
"anonymous": "אנונימי",
- "anonymous_entries": "משובים אנונימיים",
+ "anonymous_entries": "משובים אנונימיים ({{$a}})",
"average": "ממוצע",
"complete_the_form": "מענה על השאלות...",
"completed_feedbacks": "תשובות אשר הוגשו",
diff --git a/www/addons/mod/feedback/lang/hu.json b/www/addons/mod/feedback/lang/hu.json
index 4c096d23974..40c06756007 100644
--- a/www/addons/mod/feedback/lang/hu.json
+++ b/www/addons/mod/feedback/lang/hu.json
@@ -5,7 +5,7 @@
"average": "Átlag",
"complete_the_form": "Válaszoljon a kérdésekre...",
"completed_feedbacks": "Leadott válaszok",
- "continue_the_form": "Űrlap folytatása",
+ "continue_the_form": "Kérdések megválaszolásának folytatása...",
"feedback_is_not_open": "A visszajelzés nincs nyitva",
"feedbackclose": "Válaszok engedélyezése a címzettnek",
"feedbackopen": "Válaszok engedélyezése a feladótól",
diff --git a/www/addons/mod/feedback/lang/ja.json b/www/addons/mod/feedback/lang/ja.json
index 63503d3cc28..1fa5c5c7b9a 100644
--- a/www/addons/mod/feedback/lang/ja.json
+++ b/www/addons/mod/feedback/lang/ja.json
@@ -3,10 +3,12 @@
"anonymous": "匿名",
"anonymous_entries": "匿名エントリ ({{$a}})",
"average": "平均",
+ "captchaofflinewarning": "Capchaつきのフィードバックは、未設定の場合、オフラインモードの場合、サーバがダウンしている場合には完了できません。",
"complete_the_form": "質問に回答する ...",
"completed_feedbacks": "送信済み回答",
- "continue_the_form": "フォームを続ける",
+ "continue_the_form": "質問への回答を続ける ...",
"feedback_is_not_open": "フィードバックは利用できません。",
+ "feedback_submitted_offline": "このフィードバックを、あとで提出するために保存しました。",
"feedbackclose": "フィードバック終了日時",
"feedbackopen": "フィードバック開始日時",
"mapcourses": "フィードバックをコースにマップする",
diff --git a/www/addons/mod/feedback/lang/lt.json b/www/addons/mod/feedback/lang/lt.json
index dbe395c1dd6..e08688c5507 100644
--- a/www/addons/mod/feedback/lang/lt.json
+++ b/www/addons/mod/feedback/lang/lt.json
@@ -5,7 +5,7 @@
"average": "Vidurkis",
"complete_the_form": "Atsakyti klausimus...",
"completed_feedbacks": "Pateikti atsakymai",
- "continue_the_form": "Tęsti formą",
+ "continue_the_form": "Tęsti atsakymus į klausimus...",
"feedback_is_not_open": "Atsiliepimas neatidarytas",
"feedbackclose": "Uždaryti atsiliepimą",
"feedbackopen": "Atidaryti atsiliepimą",
diff --git a/www/addons/mod/feedback/lang/nl.json b/www/addons/mod/feedback/lang/nl.json
index 92250c29608..46203a58213 100644
--- a/www/addons/mod/feedback/lang/nl.json
+++ b/www/addons/mod/feedback/lang/nl.json
@@ -3,10 +3,10 @@
"anonymous": "Anoniem",
"anonymous_entries": "Anoniem ingevulde formulieren ({{$a}})",
"average": "Gemiddelde",
- "captchaofflinewarning": "Feedback met captcha kan niet voltooid worden als dat niet geconfigureerd is, in offline modus of wanneer de server onbereikbaar is.",
+ "captchaofflinewarning": "Feedback met captcha kan niet offline voltooid worden of wanneer dat niet geconfigureerd is of wanneer de server onbereikbaar is.",
"complete_the_form": "Beantwoord de vragen...",
"completed_feedbacks": "Ingevulde antwoorden",
- "continue_the_form": "Ga verder met dit formulier",
+ "continue_the_form": "Ga verder met het beantwoorden van de vragen...",
"feedback_is_not_open": "De feedback is niet open",
"feedback_submitted_offline": "Deze feedback is bewaard om later in te sturen.",
"feedbackclose": "Antwoorden toestaan tot",
diff --git a/www/addons/mod/feedback/lang/pt-br.json b/www/addons/mod/feedback/lang/pt-br.json
index 98fb2ece613..bc007fed595 100644
--- a/www/addons/mod/feedback/lang/pt-br.json
+++ b/www/addons/mod/feedback/lang/pt-br.json
@@ -1,7 +1,7 @@
{
"analysis": "Análise",
"anonymous": "Anônimo",
- "anonymous_entries": "Entradas anônimas",
+ "anonymous_entries": "Entradas anônimas ({{$a}})",
"average": "Média",
"complete_the_form": "Responda as questões...",
"completed_feedbacks": "Respostas submetidas",
@@ -13,10 +13,11 @@
"mode": "Modo",
"next_page": "Próxima página",
"non_anonymous": "O nome do usuário será registrado e mostrado com as respostas",
- "non_anonymous_entries": "entradas não anônimas",
- "non_respondents_students": "estudantes não respondentes",
+ "non_anonymous_entries": "Entradas não anônimas ({{$a}})",
+ "non_respondents_students": "Estudantes não respondentes ({{$a}})",
"not_selected": "Não selecionado",
"not_started": "não iniciado",
+ "numberoutofrange": "Valor fora do intervalo",
"overview": "Visão geral",
"page_after_submit": "Mensagem de conclusão",
"preview": "Previsão",
diff --git a/www/addons/mod/feedback/lang/pt.json b/www/addons/mod/feedback/lang/pt.json
index a6ba4bcbd66..23aced64222 100644
--- a/www/addons/mod/feedback/lang/pt.json
+++ b/www/addons/mod/feedback/lang/pt.json
@@ -6,7 +6,7 @@
"captchaofflinewarning": "Inquérito com captcha não pode ser concluído se não estiver configurado, nem em modo offline ou com o servidor em baixo.",
"complete_the_form": "Responder às questões...",
"completed_feedbacks": "Respostas submetidas",
- "continue_the_form": "Continuar o inquérito",
+ "continue_the_form": "Continuar a responder às perguntas...",
"feedback_is_not_open": "O inquérito não está aberto",
"feedback_submitted_offline": "O Inquérito foi gravado para ser enviado mais tarde.",
"feedbackclose": "Permitir respostas até",
@@ -30,6 +30,6 @@
"save_entries": "Submeter respostas",
"show_entries": "Respostas",
"show_nonrespondents": "Utilizadores que não responderam",
- "started": "iniciado",
+ "started": "Iniciado",
"this_feedback_is_already_submitted": "Já completou esta atividade"
}
\ No newline at end of file
diff --git a/www/addons/mod/feedback/lang/sr-cr.json b/www/addons/mod/feedback/lang/sr-cr.json
new file mode 100644
index 00000000000..a1cdc9bcc78
--- /dev/null
+++ b/www/addons/mod/feedback/lang/sr-cr.json
@@ -0,0 +1,35 @@
+{
+ "analysis": "Анализа",
+ "anonymous": "Анонимни упитник",
+ "anonymous_entries": "Анонимни одговори ({{$a}})",
+ "average": "Просечно",
+ "captchaofflinewarning": "Упитник са Captcha елементом не може да буде завршен ако није конфигурисан, ако сте у офлајн режиму или ако је сервер искључен.",
+ "complete_the_form": "Одговори на питања...",
+ "completed_feedbacks": "Анализа одговорa",
+ "continue_the_form": "Настави са одговарањем на питања...",
+ "feedback_is_not_open": "Упитник није отворен",
+ "feedback_submitted_offline": "Овај упитник је сачуван како би касније био предат.",
+ "feedbackclose": "Упитник доступан до",
+ "feedbackopen": "Упитник доступан од",
+ "mapcourses": "Повежи упитник са курсевима",
+ "mode": "Врста упитника",
+ "next_page": "Следећа страница",
+ "non_anonymous": "Име корисника биће записано и приказано заједно са одговорима",
+ "non_anonymous_entries": "Неанонимни одговори ({{$a}})",
+ "non_respondents_students": "Полазници који нису одговорили на упитник ({{$a}})",
+ "not_selected": "Није изабрано",
+ "not_started": "Није започето",
+ "numberoutofrange": "Број изван опсега",
+ "overview": "Преглед",
+ "page_after_submit": "Порука која ће бити приказана кориснику након што попуни упитник",
+ "preview": "Преглед",
+ "previous_page": "Претходна страница",
+ "questions": "Питања",
+ "response_nr": "Одговор бр.",
+ "responses": "Одговори",
+ "save_entries": "Пошаљи своје одговоре",
+ "show_entries": "Прикажи одговоре",
+ "show_nonrespondents": "Прикажи кориснике које нису одговорили на упитник",
+ "started": "Започето",
+ "this_feedback_is_already_submitted": "Већ сте попунили овај упитник."
+}
\ No newline at end of file
diff --git a/www/addons/mod/feedback/lang/sr-lt.json b/www/addons/mod/feedback/lang/sr-lt.json
new file mode 100644
index 00000000000..8f2198ecfcc
--- /dev/null
+++ b/www/addons/mod/feedback/lang/sr-lt.json
@@ -0,0 +1,35 @@
+{
+ "analysis": "Analiza",
+ "anonymous": "Anonimni upitnik",
+ "anonymous_entries": "Anonimni odgovori ({{$a}})",
+ "average": "Prosečno",
+ "captchaofflinewarning": "Upitnik sa Captcha elementom ne može da bude završen ako nije konfigurisan, ako ste u oflajn režimu ili ako je server isključen.",
+ "complete_the_form": "Odgovori na pitanja...",
+ "completed_feedbacks": "Analiza odgovora",
+ "continue_the_form": "Nastavi sa odgovaranjem na pitanja...",
+ "feedback_is_not_open": "Upitnik nije otvoren",
+ "feedback_submitted_offline": "Ovaj upitnik je sačuvan kako bi kasnije bio predat.",
+ "feedbackclose": "Upitnik dostupan do",
+ "feedbackopen": "Upitnik dostupan od",
+ "mapcourses": "Poveži upitnik sa kursevima",
+ "mode": "Vrsta upitnika",
+ "next_page": "Sledeća stranica",
+ "non_anonymous": "Ime korisnika biće zapisano i prikazano zajedno sa odgovorima",
+ "non_anonymous_entries": "Neanonimni odgovori ({{$a}})",
+ "non_respondents_students": "Polaznici koji nisu odgovorili na upitnik ({{$a}})",
+ "not_selected": "Nije izabrano",
+ "not_started": "Nije započeto",
+ "numberoutofrange": "Broj izvan opsega",
+ "overview": "Pregled",
+ "page_after_submit": "Poruka koja će biti prikazana korisniku nakon što popuni upitnik",
+ "preview": "Pregled",
+ "previous_page": "Prethodna stranica",
+ "questions": "Pitanja",
+ "response_nr": "Odgovor br.",
+ "responses": "Odgovori",
+ "save_entries": "Pošalji svoje odgovore",
+ "show_entries": "Prikaži odgovore",
+ "show_nonrespondents": "Prikaži korisnike koje nisu odgovorili na upitnik",
+ "started": "Započeto",
+ "this_feedback_is_already_submitted": "Već ste popunili ovaj upitnik."
+}
\ No newline at end of file
diff --git a/www/addons/mod/feedback/lang/sv.json b/www/addons/mod/feedback/lang/sv.json
index c749faa8094..b2b4102df5d 100644
--- a/www/addons/mod/feedback/lang/sv.json
+++ b/www/addons/mod/feedback/lang/sv.json
@@ -16,7 +16,7 @@
"non_anonymous_entries": "Inga anonyma bidrag",
"non_respondents_students": "Studenter/elever/deltagare/lärande som inte har lämnat några svar",
"not_selected": "Inte vald",
- "not_started": "inte påbörjad",
+ "not_started": "Inte påbörjad",
"overview": "Översikt",
"page_after_submit": "Sida efter inskickning",
"preview": "Förhandsgranska",
diff --git a/www/addons/mod/feedback/lang/tr.json b/www/addons/mod/feedback/lang/tr.json
index b1c57c37b04..e4720de3ad0 100644
--- a/www/addons/mod/feedback/lang/tr.json
+++ b/www/addons/mod/feedback/lang/tr.json
@@ -1,14 +1,14 @@
{
"analysis": "Analiz",
"anonymous": "Anonim",
- "anonymous_entries": "Anonim kayıtlar",
+ "anonymous_entries": "Anonim kayıtlar ({{$a}})",
"average": "Ortalama",
"complete_the_form": "Soruları cevaplayın...",
"completed_feedbacks": "Gönderilen cevaplar",
- "continue_the_form": "Devam et",
+ "continue_the_form": "Soruları cevaplamaya devam et...",
"feedback_is_not_open": "Geribildirim açık değil",
- "feedbackclose": "Geribildirimi kapat",
- "feedbackopen": "Geribildirimi aç",
+ "feedbackclose": "Şuna yazılan cevaplara izin ver:",
+ "feedbackopen": "Şunlardan gelen cevaplara izin ver:",
"mapcourses": "Geribildirimi derslere eşleştirin",
"mode": "Mod",
"next_page": "Sonraki sayfa",
@@ -19,11 +19,11 @@
"not_started": "Başlatılmadı",
"numberoutofrange": "Aralık dışı numara",
"overview": "Gözat",
- "page_after_submit": "Geribildirim doldurulduktan sonraki sayfa",
+ "page_after_submit": "Tamamlama bildirimi",
"preview": "Önizleme",
"previous_page": "Önceki sayfa",
"questions": "Sorular",
- "response_nr": "Yanıt No.",
+ "response_nr": "Yanıt numarası",
"responses": "Yanıtlar",
"save_entries": "Cevaplarınızı gönderin",
"show_entries": "Yanıtları göster",
diff --git a/www/addons/mod/feedback/services/handlers.js b/www/addons/mod/feedback/services/handlers.js
index 48661bcd919..04b5f6d2613 100644
--- a/www/addons/mod/feedback/services/handlers.js
+++ b/www/addons/mod/feedback/services/handlers.js
@@ -22,7 +22,7 @@ angular.module('mm.addons.mod_feedback')
* @name $mmaModFeedbackHandlers
*/
.factory('$mmaModFeedbackHandlers', function($mmCourse, $mmaModFeedback, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite,
- mmaModFeedbackComponent, $mmaModFeedbackPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmaModFeedbackSync,
+ mmaModFeedbackComponent, $mmaModFeedbackPrefetchHandler, mmCoreDownloading, mmCoreNotDownloaded, $mmaModFeedbackSync, $q,
mmCoreEventPackageStatusChanged, mmCoreOutdated, $mmCoursePrefetchDelegate, $mmContentLinkHandlerFactory) {
var self = {};
@@ -102,9 +102,10 @@ angular.module('mm.addons.mod_feedback')
// We need to call getDownloadSize, the package might have been updated.
$mmaModFeedbackPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModFeedbackPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModFeedbackPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/folder/lang/da.json b/www/addons/mod/folder/lang/da.json
index c53b3a994ed..2337bed4841 100644
--- a/www/addons/mod/folder/lang/da.json
+++ b/www/addons/mod/folder/lang/da.json
@@ -1,4 +1,4 @@
{
- "emptyfilelist": "Der er ingen filer at vise",
+ "emptyfilelist": "Der er ingen filer at vise.",
"errorwhilegettingfolder": "Fejl ved hentning af mappedata."
}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/es_mx.json b/www/addons/mod/folder/lang/es_mx.json
deleted file mode 100644
index 3a342984727..00000000000
--- a/www/addons/mod/folder/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "emptyfilelist": "No hay archivos que mostrar"
-}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/he.json b/www/addons/mod/folder/lang/he.json
index 1c2ec27977b..55811600621 100644
--- a/www/addons/mod/folder/lang/he.json
+++ b/www/addons/mod/folder/lang/he.json
@@ -1,3 +1,3 @@
{
- "emptyfilelist": "אין קבצים להציג"
+ "emptyfilelist": "אין קבצים להציג."
}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/ja.json b/www/addons/mod/folder/lang/ja.json
index 39c4d9fcfbd..61980e500fc 100644
--- a/www/addons/mod/folder/lang/ja.json
+++ b/www/addons/mod/folder/lang/ja.json
@@ -1,3 +1,4 @@
{
- "emptyfilelist": "表示するファイルはありません。"
+ "emptyfilelist": "表示するファイルがありません。",
+ "errorwhilegettingfolder": "フォルダのデータを取得中にエラーが発生しました。"
}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/pt_br.json b/www/addons/mod/folder/lang/pt_br.json
deleted file mode 100644
index 0821fd73ad7..00000000000
--- a/www/addons/mod/folder/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "emptyfilelist": "Não há arquivos para exibir"
-}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/ro.json b/www/addons/mod/folder/lang/ro.json
index a66c107ebcd..0277b91b35f 100644
--- a/www/addons/mod/folder/lang/ro.json
+++ b/www/addons/mod/folder/lang/ro.json
@@ -1,4 +1,4 @@
{
- "emptyfilelist": "Nu sunt fișiere disponibile pentru vizualizare.",
+ "emptyfilelist": "Nu există fișiere",
"errorwhilegettingfolder": "A apărut o eroare la obținerea dosarului cu datele cerute."
}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/sr-cr.json b/www/addons/mod/folder/lang/sr-cr.json
new file mode 100644
index 00000000000..a65fb8697c7
--- /dev/null
+++ b/www/addons/mod/folder/lang/sr-cr.json
@@ -0,0 +1,4 @@
+{
+ "emptyfilelist": "Нема датотека за приказ.",
+ "errorwhilegettingfolder": "Грешка приликом преузимања података за 'Директоријум'"
+}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/sr-lt.json b/www/addons/mod/folder/lang/sr-lt.json
new file mode 100644
index 00000000000..9bfdf403335
--- /dev/null
+++ b/www/addons/mod/folder/lang/sr-lt.json
@@ -0,0 +1,4 @@
+{
+ "emptyfilelist": "Nema datoteka za prikaz.",
+ "errorwhilegettingfolder": "Greška prilikom preuzimanja podataka za 'Direktorijum'"
+}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/uk.json b/www/addons/mod/folder/lang/uk.json
index 28ec6cd8e8a..1357444e2a4 100644
--- a/www/addons/mod/folder/lang/uk.json
+++ b/www/addons/mod/folder/lang/uk.json
@@ -1,4 +1,4 @@
{
- "emptyfilelist": "Немає файдів для показу",
+ "emptyfilelist": "Немає файлів для показу",
"errorwhilegettingfolder": "Помилка отримання інформації про папку"
}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/zh_cn.json b/www/addons/mod/folder/lang/zh_cn.json
deleted file mode 100644
index edc8a70a528..00000000000
--- a/www/addons/mod/folder/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "emptyfilelist": "没有可显示的文件"
-}
\ No newline at end of file
diff --git a/www/addons/mod/folder/lang/zh_tw.json b/www/addons/mod/folder/lang/zh_tw.json
deleted file mode 100644
index c53d23b870f..00000000000
--- a/www/addons/mod/folder/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "emptyfilelist": "沒有可以顯示的檔案"
-}
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/ca.json b/www/addons/mod/forum/lang/ca.json
index 5f1be9cd58c..42bf0d4d3d0 100644
--- a/www/addons/mod/forum/lang/ca.json
+++ b/www/addons/mod/forum/lang/ca.json
@@ -5,6 +5,7 @@
"cannotcreatediscussion": "No s'ha pogut obrir un debat nou",
"couldnotadd": "Un error desconegut ha impedit afegir el vostre missatge",
"discussion": "Debat",
+ "discussionlocked": "Aquest fil de debat ha finalitzat, així que no admet respostes.",
"discussionpinned": "Fixat",
"discussionsubscription": "Subscripció als debats",
"edit": "Edita",
diff --git a/www/addons/mod/forum/lang/da.json b/www/addons/mod/forum/lang/da.json
index 38dca8ad7f1..bdbd7c0a872 100644
--- a/www/addons/mod/forum/lang/da.json
+++ b/www/addons/mod/forum/lang/da.json
@@ -9,7 +9,7 @@
"discussionsubscription": "Abonnement på tråd",
"edit": "Rediger",
"erroremptymessage": "Indlægget kan ikke være tomt.",
- "erroremptysubject": "Indlæggets emne kan ikke være tomt.",
+ "erroremptysubject": "Emnefeltet kan ikke være tomt",
"errorgetforum": "Fejl ved hentning af forumdata.",
"errorgetgroups": "Fejl ved hentning af gruppeindstillinger.",
"forumnodiscussionsyet": "Der er endnu ingen indlæg i dette forum.",
diff --git a/www/addons/mod/forum/lang/es-mx.json b/www/addons/mod/forum/lang/es-mx.json
index c3743416512..48404906707 100644
--- a/www/addons/mod/forum/lang/es-mx.json
+++ b/www/addons/mod/forum/lang/es-mx.json
@@ -10,7 +10,7 @@
"discussionsubscription": "Suscripción a discusión",
"edit": "Editar",
"erroremptymessage": "El mensaje no puede estar vacío",
- "erroremptysubject": "El asunto de la publicación no puede estar vacío",
+ "erroremptysubject": "El asunto del mensaje no puede estar vacío.",
"errorgetforum": "Error al obtener datos del foro.",
"errorgetgroups": "Error al obtener configuraciones de grupo.",
"forumnodiscussionsyet": "Todavía no hay tópicos de discusión en este foro.",
diff --git a/www/addons/mod/forum/lang/es_mx.json b/www/addons/mod/forum/lang/es_mx.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/forum/lang/es_mx.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/he.json b/www/addons/mod/forum/lang/he.json
index 665cc87e1b4..21f3b132b0c 100644
--- a/www/addons/mod/forum/lang/he.json
+++ b/www/addons/mod/forum/lang/he.json
@@ -5,11 +5,12 @@
"cannotcreatediscussion": "כשלון ביצירת דיון חדש.",
"couldnotadd": "ההודעה שלך לא פורסמה עקב תקלה בלתי מזוהה",
"discussion": "דיון",
+ "discussionlocked": "הדיון ננעל, כך שלא ניתן יותר להגיב אליו.",
"discussionpinned": "בראש הרשימה",
"discussionsubscription": "מנוי לעדכונים בדיון",
"edit": "עריכה",
"erroremptymessage": "הודעת הפרסום איננה יכולה להיות ריקה",
- "erroremptysubject": "הנושא הפרסום אינו יכול להיות ריק",
+ "erroremptysubject": "נושא ההודעה אינו יכול להיות ריק",
"errorgetforum": "שגיאה בטעינת מידע הפורום.",
"errorgetgroups": "שגיאה בטעינת הגדרות קבוצה.",
"forumnodiscussionsyet": "עדיין לא קיימים נושאי דיונים בפורום זה.",
diff --git a/www/addons/mod/forum/lang/ja.json b/www/addons/mod/forum/lang/ja.json
index c6861af9156..df4dba7bc16 100644
--- a/www/addons/mod/forum/lang/ja.json
+++ b/www/addons/mod/forum/lang/ja.json
@@ -3,22 +3,28 @@
"cannotadddiscussion": "このフォーラムにディスカッションを追加するにはグループのメンバーである必要があります。",
"cannotadddiscussionall": "あなたにはすべての参加者のための新しいディスカッショントピックを追加するパーミッションがありません。",
"cannotcreatediscussion": "新しいディスカッションを作成できませんでした。",
- "couldnotadd": "不明なエラーのため、あなたの投稿を追加できませんでした。",
+ "couldnotadd": "不明なエラーのためあなたの投稿を追加できませんでした。",
"discussion": "ディスカッション",
"discussionlocked": "このディスカッションはロックされているため、あなたは返信することはできません。",
"discussionpinned": "ピン留め",
"discussionsubscription": "ディスカッション購読",
"edit": "編集",
"erroremptymessage": "投稿メッセージを空にすることはできません。",
- "erroremptysubject": "投稿件名を空にすることはできません。",
+ "erroremptysubject": "投稿の件名は必須です",
+ "errorgetforum": "フォーラムのデータ取得中にエラーが発生しました。",
+ "errorgetgroups": "グループ設定の取得中にエラーが発生しました。",
"forumnodiscussionsyet": "このフォーラムにはまだディスカッショントピックがありません",
"group": "グループ",
"message": "メッセージ",
"modeflatnewestfirst": "返信を新しいものからフラット表示する",
"modeflatoldestfirst": "返信を古いものからフラット表示する",
"modenested": "返信をネスト表示する",
+ "numdiscussions": "ディスカッション数 {{numdiscussions}}",
+ "numreplies": "返信数 {{numreplies}}",
"posttoforum": "フォーラムに投稿する",
"re": "Re:",
+ "refreshdiscussions": "ディスカッションをリフレッシュ",
+ "refreshposts": "ディスカッション投稿をリフレッシュ",
"reply": "返信",
"subject": "件名",
"unread": "未読",
diff --git a/www/addons/mod/forum/lang/lt.json b/www/addons/mod/forum/lang/lt.json
index 82a99a7e4f4..93f37fba562 100644
--- a/www/addons/mod/forum/lang/lt.json
+++ b/www/addons/mod/forum/lang/lt.json
@@ -10,7 +10,7 @@
"discussionsubscription": "Diskusijos prenumerata",
"edit": "Redaguoti",
"erroremptymessage": "Skelbimo žinutė negali būti tuščia",
- "erroremptysubject": "Pranešimo temos langelis negali būti tuščias",
+ "erroremptysubject": "Skelbimo tema negali būti tuščia.",
"errorgetforum": "Klaida gaunant forumo duomenis.",
"errorgetgroups": "Klaida gaunant grupės nustatymus.",
"forumnodiscussionsyet": "Pokalbio temų forume dar nėra.",
diff --git a/www/addons/mod/forum/lang/pl.json b/www/addons/mod/forum/lang/pl.json
index 67a495dd1a6..0f761c4b8ec 100644
--- a/www/addons/mod/forum/lang/pl.json
+++ b/www/addons/mod/forum/lang/pl.json
@@ -7,7 +7,7 @@
"discussion": "Temat",
"discussionlocked": "Dyskusja została zablokowana, więc nie możesz już odpowiedzieć.",
"discussionpinned": "Przypięta",
- "discussionsubscription": "Subskrypcja dyskusja",
+ "discussionsubscription": "Subskrypcja dyskusji",
"edit": "Edycja",
"erroremptymessage": "Wiadomość nie może być pusta",
"erroremptysubject": "Tytuł wpisu nie może być pusty.",
diff --git a/www/addons/mod/forum/lang/pt-br.json b/www/addons/mod/forum/lang/pt-br.json
index f7d9cf730e2..a4df46a5972 100644
--- a/www/addons/mod/forum/lang/pt-br.json
+++ b/www/addons/mod/forum/lang/pt-br.json
@@ -5,10 +5,12 @@
"cannotcreatediscussion": "Não foi possível criar uma nova discussão",
"couldnotadd": "Não foi possível publicar a sua mensagem. Infelizmente a causa do erro não foi identificada.",
"discussion": "Tópico",
+ "discussionlocked": "Esta discussão foi bloqueada e já não é possível responder a ela.",
+ "discussionpinned": "Destacado",
"discussionsubscription": "Assinatura de discussão",
"edit": "Editar",
"erroremptymessage": "A mensagem não pode ser vazia.",
- "erroremptysubject": "Assunto não pode estar vazio",
+ "erroremptysubject": "O assunto da mensagem não pode ser vazio.",
"errorgetforum": "Erro ao buscar dados de fórum.",
"errorgetgroups": "Erro ao obter configurações do grupo.",
"forumnodiscussionsyet": "Não existem tópicos neste fórum ainda",
diff --git a/www/addons/mod/forum/lang/pt_br.json b/www/addons/mod/forum/lang/pt_br.json
deleted file mode 100644
index 9f3e79857ff..00000000000
--- a/www/addons/mod/forum/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "forumnodiscussionsyet": "Não existem tópicos neste fórum ainda"
-}
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/ro.json b/www/addons/mod/forum/lang/ro.json
index 99d4fc77c16..2dd31a2be41 100644
--- a/www/addons/mod/forum/lang/ro.json
+++ b/www/addons/mod/forum/lang/ro.json
@@ -7,7 +7,7 @@
"discussion": "Discuție",
"edit": "Modifică",
"erroremptymessage": "Mesajul nu poate fi necompletat",
- "erroremptysubject": "Subiectul nu poate rămâne necompletat",
+ "erroremptysubject": "Subiectul nu poate fi necompletat",
"errorgetforum": "A apărut o eroare la obținerea datelor despre forum.",
"errorgetgroups": "Eroare la obținerea setărilor pentru grup.",
"forumnodiscussionsyet": "Nu există subiecte deschise în acest forum.",
diff --git a/www/addons/mod/forum/lang/sr-cr.json b/www/addons/mod/forum/lang/sr-cr.json
new file mode 100644
index 00000000000..0b8b9f761b2
--- /dev/null
+++ b/www/addons/mod/forum/lang/sr-cr.json
@@ -0,0 +1,32 @@
+{
+ "addanewdiscussion": "Додај нову тему за дискусију",
+ "cannotadddiscussion": "Додавање дискусије у оквиру овог форума захтева групно чланство.",
+ "cannotadddiscussionall": "Немате дозволу да додајете нову тему за дискусију за све учеснике.",
+ "cannotcreatediscussion": "Није било могуће отворити нову дискусију",
+ "couldnotadd": "Нажалост, није могуће додати Вашу поруку због непознате грешке",
+ "discussion": "Дискусија",
+ "discussionlocked": "Ова дискусија је закључана тако да више не можете одговарати на њој.",
+ "discussionpinned": "Фиксирана",
+ "discussionsubscription": "Претплата на дискусију",
+ "edit": "Уреди",
+ "erroremptymessage": "Тело поруке не може бити празно",
+ "erroremptysubject": "Тема поруке не може бити празна",
+ "errorgetforum": "Грешка приликом преузимања података за 'Форум'",
+ "errorgetgroups": "Грешка приликом преузимања подешавања група.",
+ "forumnodiscussionsyet": "Још нема тема за дискусију на овом форуму.",
+ "group": "Група",
+ "message": "Порука",
+ "modeflatnewestfirst": "Приказ одговора, почевши прво с најновијим",
+ "modeflatoldestfirst": "Приказ одговора, почевши прво с најстаријим",
+ "modenested": "Приказ одговора у угнежђеној форми",
+ "numdiscussions": "{{numdiscussions}} дискусије/а",
+ "numreplies": "{{numreplies}} одговора",
+ "posttoforum": "Пошаљи поруку на форум",
+ "re": "Одговор:",
+ "refreshdiscussions": "Освежи дискусије",
+ "refreshposts": "Освежи постове",
+ "reply": "Одговори",
+ "subject": "Тема",
+ "unread": "Непрочитано",
+ "unreadpostsnumber": "Број непрочитаних порука: {{$a}}"
+}
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/sr-lt.json b/www/addons/mod/forum/lang/sr-lt.json
new file mode 100644
index 00000000000..c71aef2a6fc
--- /dev/null
+++ b/www/addons/mod/forum/lang/sr-lt.json
@@ -0,0 +1,32 @@
+{
+ "addanewdiscussion": "Dodaj novu temu za diskusiju",
+ "cannotadddiscussion": "Dodavanje diskusije u okviru ovog foruma zahteva grupno članstvo.",
+ "cannotadddiscussionall": "Nemate dozvolu da dodajete novu temu za diskusiju za sve učesnike.",
+ "cannotcreatediscussion": "Nije bilo moguće otvoriti novu diskusiju",
+ "couldnotadd": "Nažalost, nije moguće dodati Vašu poruku zbog nepoznate greške",
+ "discussion": "Diskusija",
+ "discussionlocked": "Ova diskusija je zaključana tako da više ne možete odgovarati na njoj.",
+ "discussionpinned": "Fiksirana",
+ "discussionsubscription": "Pretplata na diskusiju",
+ "edit": "Uredi",
+ "erroremptymessage": "Telo poruke ne može biti prazno",
+ "erroremptysubject": "Tema poruke ne može biti prazna",
+ "errorgetforum": "Greška prilikom preuzimanja podataka za 'Forum'",
+ "errorgetgroups": "Greška prilikom preuzimanja podešavanja grupa.",
+ "forumnodiscussionsyet": "Greška prilikom preuzimanja podešavanja grupa.",
+ "group": "Grupa",
+ "message": "Poruka",
+ "modeflatnewestfirst": "Prikaz odgovora, počevši prvo s najnovijim",
+ "modeflatoldestfirst": "Prikaz odgovora, počevši prvo s najstarijim",
+ "modenested": "Prikaz odgovora u ugnežđenoj formi",
+ "numdiscussions": "{{numdiscussions}} diskusije/a",
+ "numreplies": "{{numreplies}} odgovora",
+ "posttoforum": "Pošalji poruku na forum",
+ "re": "Odgovor:",
+ "refreshdiscussions": "Osveži diskusije",
+ "refreshposts": "Osveži postove",
+ "reply": "Odgovori",
+ "subject": "Tema",
+ "unread": "Nepročitano",
+ "unreadpostsnumber": "Broj nepročitanih poruka: {{$a}}"
+}
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/sv.json b/www/addons/mod/forum/lang/sv.json
index 676e5ba9fa1..41354d355f0 100644
--- a/www/addons/mod/forum/lang/sv.json
+++ b/www/addons/mod/forum/lang/sv.json
@@ -3,9 +3,11 @@
"cannotadddiscussion": "För att lägga till diskussionsämnen till det här forumet krävs det att man är medlem av en grupp.",
"cannotadddiscussionall": "Du har inte tillstånd att lägga till ett nytt diskussionsämne för alla deltagare. ",
"cannotcreatediscussion": "Det gick inte att skapa en ny diskussion",
- "couldnotadd": "Det gick inte att lägga till Ditt inlägg på grund av okänt fel.",
+ "couldnotadd": "Det gick inte att lägga till ditt inlägg på grund av okänt fel.",
"discussion": "Diskussionsämne",
- "discussionsubscription": "Diskussions prenumeration",
+ "discussionlocked": "Denna diskussion är stängd och du kan inte längre göra inlägg i den.",
+ "discussionpinned": "Fastnålad",
+ "discussionsubscription": "Prenumeration på diskussion",
"edit": "Redigera",
"erroremptymessage": "Meddelandet i inlägget kan inte vara tomt",
"erroremptysubject": "Rubriken kan inte vara tom",
diff --git a/www/addons/mod/forum/lang/zh-tw.json b/www/addons/mod/forum/lang/zh-tw.json
index a2d74d28770..6a91914a48c 100644
--- a/www/addons/mod/forum/lang/zh-tw.json
+++ b/www/addons/mod/forum/lang/zh-tw.json
@@ -10,7 +10,7 @@
"discussionsubscription": "議題訂閱",
"edit": "編輯",
"erroremptymessage": "貼文的訊息不能是空白",
- "erroremptysubject": "貼文的標題不可以是空的",
+ "erroremptysubject": "貼文的主旨不能是空白",
"errorgetforum": "讀取討論區資料發生錯誤",
"errorgetgroups": "讀取群組設定發生錯誤",
"forumnodiscussionsyet": "這個討論區還沒有討論主題",
diff --git a/www/addons/mod/forum/lang/zh_cn.json b/www/addons/mod/forum/lang/zh_cn.json
deleted file mode 100644
index 266cde0a80d..00000000000
--- a/www/addons/mod/forum/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "forumnodiscussionsyet": "此论坛中还没有讨论话题"
-}
\ No newline at end of file
diff --git a/www/addons/mod/forum/lang/zh_tw.json b/www/addons/mod/forum/lang/zh_tw.json
deleted file mode 100644
index 21e18ea567e..00000000000
--- a/www/addons/mod/forum/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "forumnodiscussionsyet": "這個討論區還沒有討論主題"
-}
\ No newline at end of file
diff --git a/www/addons/mod/forum/services/handlers.js b/www/addons/mod/forum/services/handlers.js
index dd5160f0a50..c8db7b531ac 100644
--- a/www/addons/mod/forum/services/handlers.js
+++ b/www/addons/mod/forum/services/handlers.js
@@ -21,7 +21,7 @@ angular.module('mm.addons.mod_forum')
* @ngdoc service
* @name $mmaModForumHandlers
*/
-.factory('$mmaModForumHandlers', function($mmCourse, $mmaModForum, $state, $mmUtil, $mmContentLinksHelper, $mmEvents, $mmSite,
+.factory('$mmaModForumHandlers', function($mmCourse, $mmaModForum, $state, $mmUtil, $mmContentLinksHelper, $mmEvents, $mmSite, $q,
$mmaModForumPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated,
mmaModForumComponent, mmCoreEventPackageStatusChanged, $mmaModForumSync, $mmContentLinkHandlerFactory) {
var self = {};
@@ -110,9 +110,10 @@ angular.module('mm.addons.mod_forum')
// Get download size to ask for confirm if it's high.
$mmaModForumPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModForumPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModForumPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/glossary/controllers/index.js b/www/addons/mod/glossary/controllers/index.js
index 29913639991..168344cafcd 100644
--- a/www/addons/mod/glossary/controllers/index.js
+++ b/www/addons/mod/glossary/controllers/index.js
@@ -168,8 +168,10 @@ angular.module('mm.addons.mod_glossary')
var promises = [];
// Ignore search mode that is not set yet.
if (fetchMode != 'search' || $scope.searchQuery) {
- var args = angular.extend([], fetchArguments);
- promises.push(fetchInvalidate.apply(this, args));
+ if (fetchInvalidate) {
+ var args = angular.extend([], fetchArguments);
+ promises.push(fetchInvalidate.apply(this, args));
+ }
promises.push($mmaModGlossary.invalidateCourseGlossaries(courseId));
}
if (glossary && glossary.id) {
@@ -356,9 +358,9 @@ angular.module('mm.addons.mod_glossary')
$scope.canLoadMore = (limitFrom + limitNum) < result.count;
$scope.showNoEntries = ($scope.entries.length + $scope.offlineEntries.length) <= 0;
- }).catch(function() {
+ }).catch(function(error) {
if (append) {
- $mmUtil.showErrorModal('mma.mod_glossary.errorloadingentries', true);
+ $mmUtil.showErrorModalDefault(error, 'mma.mod_glossary.errorloadingentries', true);
}
$scope.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
return $q.reject();
diff --git a/www/addons/mod/glossary/lang/ar.json b/www/addons/mod/glossary/lang/ar.json
index e92d720edeb..b52d6059283 100644
--- a/www/addons/mod/glossary/lang/ar.json
+++ b/www/addons/mod/glossary/lang/ar.json
@@ -1,10 +1,10 @@
{
- "attachment": "مرفقات",
+ "attachment": "ملف مرفق",
"browsemode": "النمط العرضي",
"byauthor": "التجميع طبقا للمؤلف",
"bynewestfirst": "الأحدث أولا",
"byrecentlyupdated": "تم تحديثه مؤخرا",
"bysearch": "بحث",
- "casesensitive": "استخدم التعابير المعتادة",
- "categories": "تصنيفات المقررات الدراسية"
+ "casesensitive": "مطابقة حالة الأحرف",
+ "categories": "التصنيفات"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/bg.json b/www/addons/mod/glossary/lang/bg.json
index dc6e44a0dcd..593e987ab1a 100644
--- a/www/addons/mod/glossary/lang/bg.json
+++ b/www/addons/mod/glossary/lang/bg.json
@@ -1,6 +1,6 @@
{
- "attachment": "Прикрепване на значката към съобщението.",
+ "attachment": "Прикачен файл",
"browsemode": "Режим на преглеждане",
- "casesensitive": "Използване на регулярни изрази",
- "categories": "Категории курсове"
+ "casesensitive": "Чувствителност главни/малки букви",
+ "categories": "Категории"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/ca.json b/www/addons/mod/glossary/lang/ca.json
index 191d2db0090..f5a0cfc5ded 100644
--- a/www/addons/mod/glossary/lang/ca.json
+++ b/www/addons/mod/glossary/lang/ca.json
@@ -1,5 +1,5 @@
{
- "attachment": "Adjunt",
+ "attachment": "Adjunta la insígnia al missatge",
"browsemode": "Navegueu per les entrades",
"byalphabet": "Alfabèticament",
"byauthor": "Agrupat per autor",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Actualitzat recentment",
"bysearch": "Cerca",
"cannoteditentry": "No es pot editar l'entrada",
- "casesensitive": "Utilitzeu expressions regulars",
- "categories": "Categories de cursos",
+ "casesensitive": "Distingeix majúscules",
+ "categories": "Categories",
"entriestobesynced": "Entrades per sincronitzar",
"entrypendingapproval": "Aquesta entrada està pendent d'aprovació.",
"errorloadingentries": "S'ha produït un error en carregar les entrades.",
diff --git a/www/addons/mod/glossary/lang/cs.json b/www/addons/mod/glossary/lang/cs.json
index 3421f566a83..9d81e677a27 100644
--- a/www/addons/mod/glossary/lang/cs.json
+++ b/www/addons/mod/glossary/lang/cs.json
@@ -1,5 +1,5 @@
{
- "attachment": "Připojit odznak do zprávy",
+ "attachment": "Příloha",
"browsemode": "Prohlížení příspěvků",
"byalphabet": "Abecedně",
"byauthor": "Skupina podle autora",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Posledně aktualizované",
"bysearch": "Hledat",
"cannoteditentry": "Záznam nelze upravit",
- "casesensitive": "Používat regulární výrazy",
- "categories": "Kategorie kurzů",
+ "casesensitive": "Rozlišovat malá/VELKÁ",
+ "categories": "Kategorie",
"entriestobesynced": "Příspěvky, které mají být synchronizovány",
"entrypendingapproval": "Tato položka čeká na schválení",
"errorloadingentries": "Při načítání položek došlo k chybě",
diff --git a/www/addons/mod/glossary/lang/da.json b/www/addons/mod/glossary/lang/da.json
index bd0f0d93d2e..2e7da2ee000 100644
--- a/www/addons/mod/glossary/lang/da.json
+++ b/www/addons/mod/glossary/lang/da.json
@@ -1,13 +1,13 @@
{
- "attachment": "Tilføj badge til besked",
- "browsemode": "Forhåndsvisning",
+ "attachment": "Bilag",
+ "browsemode": "Skim indlæg",
"byalphabet": "Alfabetisk",
"byauthor": "Grupper efter forfatter",
"bynewestfirst": "Nyeste først",
"byrecentlyupdated": "Senest opdateret",
"bysearch": "Søg",
- "casesensitive": "Brug regulære udtryk",
- "categories": "Kursuskategorier",
+ "casesensitive": "Store og små bogstaver",
+ "categories": "Kategorier",
"entrypendingapproval": "Dette opslag afventer godkendelse",
"errorloadingentries": "Der opstod en fejl under indlæsning af opslag",
"errorloadingentry": "Der opstod en fejl under indlæsning af opslaget",
diff --git a/www/addons/mod/glossary/lang/de.json b/www/addons/mod/glossary/lang/de.json
index 6b5589a0b0c..03bb7f1a602 100644
--- a/www/addons/mod/glossary/lang/de.json
+++ b/www/addons/mod/glossary/lang/de.json
@@ -1,5 +1,5 @@
{
- "attachment": "Auszeichnung an Mitteilung anhängen",
+ "attachment": "Anhang",
"browsemode": "Einträge durchblättern",
"byalphabet": "Alphabetisch",
"byauthor": "Nach Autor/in",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Gerade aktualisiert",
"bysearch": "Suchen",
"cannoteditentry": "Eintrag nicht bearbeitbar",
- "casesensitive": "Reguläre Ausdrücke verwenden",
- "categories": "Kursbereiche",
+ "casesensitive": "Groß-/Kleinschreibung",
+ "categories": "Kategorien",
"entriestobesynced": "Einträge zum Synchronisieren",
"entrypendingapproval": "Dieser Eintrag wartet auf eine Freigabe.",
"errorloadingentries": "Fehler beim Laden von Einträgen",
diff --git a/www/addons/mod/glossary/lang/el.json b/www/addons/mod/glossary/lang/el.json
index c79bed26793..6a40931cf03 100644
--- a/www/addons/mod/glossary/lang/el.json
+++ b/www/addons/mod/glossary/lang/el.json
@@ -1,13 +1,16 @@
{
- "attachment": "Συνημμένα",
+ "attachment": "Επισυναπτόμενο",
"browsemode": "Περιήγηση στις καταχωρήσεις",
"byalphabet": "Αλφαβητικά",
"byauthor": "Ομαδοποίηση ανά συγγραφέα",
+ "bycategory": "Ομαδοποίηση ανά κατηγορία",
"bynewestfirst": "Νεότερα πρώτα",
"byrecentlyupdated": "Ανανεώθηκαν πρόσφατα",
"bysearch": "Αναζήτηση",
- "casesensitive": "Χρήση κανονικών εκφράσεων",
- "categories": "Κατηγορίες μαθημάτων",
+ "cannoteditentry": "Δεν είναι δυνατή η επεξεργασία της καταχώρισης",
+ "casesensitive": "Διάκριση μικρών/κεφαλαίων",
+ "categories": "Κατηγορίες",
+ "entriestobesynced": "Entries που πρέπει να συγχρονιστούν",
"entrypendingapproval": "Εκκρεμεί η έγκριση για αυτή την καταχώρηση.",
"errorloadingentries": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση των καταχωρήσεων.",
"errorloadingentry": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση της καταχώρησης.",
diff --git a/www/addons/mod/glossary/lang/es-mx.json b/www/addons/mod/glossary/lang/es-mx.json
index 158ea571325..8cb29128da9 100644
--- a/www/addons/mod/glossary/lang/es-mx.json
+++ b/www/addons/mod/glossary/lang/es-mx.json
@@ -1,5 +1,5 @@
{
- "attachment": "Adjunto",
+ "attachment": "Anexar insignia al mensaje",
"browsemode": "Ver entradas",
"byalphabet": "Alfabéticamente",
"byauthor": "Agrupar por autor",
@@ -8,7 +8,7 @@
"byrecentlyupdated": "Recientemente actualizado",
"bysearch": "Buscar",
"cannoteditentry": "No puede editarse entrada",
- "casesensitive": "Usar expresiones regulares",
+ "casesensitive": "Diferencia entre MAYÚSCULAS y minúsculas",
"categories": "Categorías",
"entriestobesynced": "Entradas para ser sincronizadas",
"entrypendingapproval": "Esta entrada está pendiente de aprobación.",
diff --git a/www/addons/mod/glossary/lang/es.json b/www/addons/mod/glossary/lang/es.json
index 02d8e633d5c..ba144c727bc 100644
--- a/www/addons/mod/glossary/lang/es.json
+++ b/www/addons/mod/glossary/lang/es.json
@@ -1,13 +1,16 @@
{
- "attachment": "Adjunto",
+ "attachment": "Adjuntar insignia al mensaje",
"browsemode": "Navegar por las entradas",
"byalphabet": "Alfabéticamente",
"byauthor": "Agrupado por autor",
+ "bycategory": "Agrupar por categoría",
"bynewestfirst": "El más reciente primero",
"byrecentlyupdated": "Actualizado recientemente",
"bysearch": "Busca",
- "casesensitive": "Usar expresiones regulares",
+ "cannoteditentry": "No se puede editar la entrada",
+ "casesensitive": "Diferencia entre mayúsculas y minúsculas",
"categories": "Categorías",
+ "entriestobesynced": "Entradas pendientes de ser sincronizadas",
"entrypendingapproval": "Esta entrada está pendiente de aprobación.",
"errorloadingentries": "Ha ocurrido un error cargando las entradas.",
"errorloadingentry": "Ha ocurrido un error cargando la entrada.",
diff --git a/www/addons/mod/glossary/lang/eu.json b/www/addons/mod/glossary/lang/eu.json
index c6ab2a7e186..5aa5b982604 100644
--- a/www/addons/mod/glossary/lang/eu.json
+++ b/www/addons/mod/glossary/lang/eu.json
@@ -1,5 +1,5 @@
{
- "attachment": "Erantsi domina mezuari",
+ "attachment": "Eranskina",
"browsemode": "Aztertu sarrerak",
"byalphabet": "Alfabetikoki",
"byauthor": "Taldekatu egilearen arabera",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Duela gutxi eguneratuak",
"bysearch": "Bilatu",
"cannoteditentry": "Ezin da sarrera editatu",
- "casesensitive": "Erabil adierazpen erregularrak",
- "categories": "Ikastaro-kategoriak",
+ "casesensitive": "Letra larriak eta xeheak bereiziz",
+ "categories": "Kategoriak",
"entriestobesynced": "Sinkronizatu beharreko sarrerak",
"entrypendingapproval": "Sarrera hau onarpenaren zain dago.",
"errorloadingentries": "Errorea gertatu da sarrerak kargatzean.",
diff --git a/www/addons/mod/glossary/lang/fa.json b/www/addons/mod/glossary/lang/fa.json
index 637de884db4..8b6788b82aa 100644
--- a/www/addons/mod/glossary/lang/fa.json
+++ b/www/addons/mod/glossary/lang/fa.json
@@ -1,6 +1,6 @@
{
- "attachment": "فایل پیوست",
+ "attachment": "ضمیمه کردن مدال به پیام",
"browsemode": "حالت پیشنمایش",
- "casesensitive": "استفاده از عبارتهای منظم",
- "categories": "طبقههای درسی"
+ "casesensitive": "حساس بودن به بزرگ و کوچکی حروف",
+ "categories": "دستهها"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/fr.json b/www/addons/mod/glossary/lang/fr.json
index 712afea4266..f72096c8b1b 100644
--- a/www/addons/mod/glossary/lang/fr.json
+++ b/www/addons/mod/glossary/lang/fr.json
@@ -1,5 +1,5 @@
{
- "attachment": "Joindre le badge à un courriel",
+ "attachment": "Annexe",
"browsemode": "Parcourir les articles",
"byalphabet": "Alphabétiquement",
"byauthor": "Grouper par auteur",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Modifiés récemment",
"bysearch": "Rechercher",
"cannoteditentry": "Impossible de modifier l'article",
- "casesensitive": "Utiliser les expressions régulières",
- "categories": "Catégories de cours",
+ "casesensitive": "Casse des caractères",
+ "categories": "Catégories",
"entriestobesynced": "Articles à synchroniser",
"entrypendingapproval": "Cet article est en attente d'approbation",
"errorloadingentries": "Une erreur est survenue lors du chargement des articles.",
diff --git a/www/addons/mod/glossary/lang/he.json b/www/addons/mod/glossary/lang/he.json
index abad848638c..e4d971b4c35 100644
--- a/www/addons/mod/glossary/lang/he.json
+++ b/www/addons/mod/glossary/lang/he.json
@@ -1,6 +1,6 @@
{
- "attachment": "צירוף ההישג להודעה",
+ "attachment": "קובץ מצורף",
"browsemode": "מצב תצוגה מקדימה",
- "casesensitive": "השתמש בביטויים רגולריים",
- "categories": "קטגוריות קורסים"
+ "casesensitive": "תלוי אותיות רישיות",
+ "categories": "קטגוריות חישוב ציונים"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/hu.json b/www/addons/mod/glossary/lang/hu.json
index acb16b009bd..c74a20c85ed 100644
--- a/www/addons/mod/glossary/lang/hu.json
+++ b/www/addons/mod/glossary/lang/hu.json
@@ -1,6 +1,6 @@
{
- "attachment": "Csatolt állomány:",
+ "attachment": "Kitűző hozzákapcsolása az üzenethez",
"browsemode": "Előzetes megtekintés üzemmódja",
- "casesensitive": "Reguláris kifejezések használata",
- "categories": "Kurzuskategóriák"
+ "casesensitive": "Kis-/nagybetű különböző",
+ "categories": "Kategóriák"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/it.json b/www/addons/mod/glossary/lang/it.json
index 581b16835e1..aa1cfe7fe09 100644
--- a/www/addons/mod/glossary/lang/it.json
+++ b/www/addons/mod/glossary/lang/it.json
@@ -1,10 +1,10 @@
{
- "attachment": "Allega badge al messaggio",
+ "attachment": "Allegato",
"browsemode": "Modalità anteprima",
"byrecentlyupdated": "Aggiornati di recente",
"bysearch": "Cerca",
- "casesensitive": "Utilizza regular expression",
- "categories": "Categorie di corso",
+ "casesensitive": "Rilevanza maiuscolo/minuscolo",
+ "categories": "Categorie",
"entrypendingapproval": "Questa voce è in attesa di approvazione.",
"errorloadingentries": "Si è verificato un errore durante il caricamento delle voci.",
"errorloadingentry": "Si è verificato un errore durante il caricamento della voce.",
diff --git a/www/addons/mod/glossary/lang/ja.json b/www/addons/mod/glossary/lang/ja.json
index b518d805074..b68170abdd2 100644
--- a/www/addons/mod/glossary/lang/ja.json
+++ b/www/addons/mod/glossary/lang/ja.json
@@ -1,6 +1,20 @@
{
- "attachment": "添付",
- "browsemode": "プレビューモード",
- "casesensitive": "正規表現を使用する",
- "categories": "コースカテゴリ"
+ "attachment": "メッセージにバッジを添付する",
+ "browsemode": "エントリをブラウズ",
+ "byalphabet": "アルファベット順",
+ "byauthor": "著者でグループ",
+ "bycategory": "カテゴリでグループ",
+ "bynewestfirst": "新規順",
+ "byrecentlyupdated": "最近の更新",
+ "bysearch": "検索",
+ "cannoteditentry": "エントリの編集ができませんでした",
+ "casesensitive": "大文字小文字の区別",
+ "categories": "カテゴリ",
+ "entriestobesynced": "エントリの同期ができませんでした",
+ "entrypendingapproval": "このエントリは承認待ちです。",
+ "errorloadingentries": "エントリ読み込み中にエラーが発生しました。",
+ "errorloadingentry": "エントリ読み込み中にエラーが発生しました。",
+ "errorloadingglossary": "用語集を読み込み中にエラーが発生しました。",
+ "noentriesfound": "エントリが見つかりませんでした。",
+ "searchquery": "検索内容"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/lt.json b/www/addons/mod/glossary/lang/lt.json
index 18f6cc6763e..016538035b9 100644
--- a/www/addons/mod/glossary/lang/lt.json
+++ b/www/addons/mod/glossary/lang/lt.json
@@ -1,13 +1,13 @@
{
- "attachment": "Prikabinti pasiekimą prie pranešimo",
+ "attachment": "Priedas",
"browsemode": "Peržiūrėti įrašus",
"byalphabet": "Abėcėlės tvarka",
"byauthor": "Pagal autorių",
"bynewestfirst": "Naujausi",
"byrecentlyupdated": "Neseniai atnaujinti",
"bysearch": "Paieška",
- "casesensitive": "Naudoti reguliariąsias išraiškas",
- "categories": "Kursų kategorijos",
+ "casesensitive": "Didžiųjų ir mažųjų raidžių skyrimas",
+ "categories": "Kategorijos",
"entrypendingapproval": "Patvirtinti įrašą.",
"errorloadingentries": "Klaida keliant įrašus.",
"errorloadingentry": "Klaida įkeliant įrašą.",
diff --git a/www/addons/mod/glossary/lang/nl.json b/www/addons/mod/glossary/lang/nl.json
index 7c06a87db9a..5a53d5a1d7a 100644
--- a/www/addons/mod/glossary/lang/nl.json
+++ b/www/addons/mod/glossary/lang/nl.json
@@ -1,5 +1,5 @@
{
- "attachment": "Badge als bijlage bij bericht",
+ "attachment": "Bijlage",
"browsemode": "Blader door items",
"byalphabet": "Alfabetisch",
"byauthor": "Groepeer per auteur",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Onlangs gewijzigd",
"bysearch": "Zoek",
"cannoteditentry": "Kan item niet bewerken",
- "casesensitive": "Regular expressions gebruiken",
- "categories": "Cursuscategorieën",
+ "casesensitive": "Gevoeligheid voor hoofd/kleine letters",
+ "categories": "Categorieën",
"entriestobesynced": "Items niet gesynchroniseerd",
"entrypendingapproval": "Dit item wacht op goedkeuring.",
"errorloadingentries": "Fout bij het laden van de items.",
diff --git a/www/addons/mod/glossary/lang/pl.json b/www/addons/mod/glossary/lang/pl.json
index 7effb708160..dc3225deb6a 100644
--- a/www/addons/mod/glossary/lang/pl.json
+++ b/www/addons/mod/glossary/lang/pl.json
@@ -1,6 +1,6 @@
{
- "attachment": "Dołącz odznakę do wiadomości",
+ "attachment": "Załącznik",
"browsemode": "Tryb przeglądania",
- "casesensitive": "Użyj wyrażeń regularnych",
- "categories": "Kategorie kursów"
+ "casesensitive": "Uwzględnianie wielkości liter",
+ "categories": "Kategorie"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/pt-br.json b/www/addons/mod/glossary/lang/pt-br.json
index 7eeca932a54..57059a9b327 100644
--- a/www/addons/mod/glossary/lang/pt-br.json
+++ b/www/addons/mod/glossary/lang/pt-br.json
@@ -1,5 +1,5 @@
{
- "attachment": "Anexar emblema à mensagem",
+ "attachment": "Anexo",
"browsemode": "Navegar nas entradas",
"byalphabet": "Alfabeticamente",
"byauthor": "Agrupar por autor",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Recentemente atualizados",
"bysearch": "Pesquisa",
"cannoteditentry": "Não é possível editar o item",
- "casesensitive": "Usar expressões regulares",
- "categories": "Categorias de Cursos",
+ "casesensitive": "Considerar diferenças entre maiúsculas e minúsculas",
+ "categories": "Categorias",
"entriestobesynced": "Itens a serem sincronizados",
"entrypendingapproval": "A entrada está pendente de aprovação.",
"errorloadingentries": "Ocorreu um erro enquanto carregava entradas.",
diff --git a/www/addons/mod/glossary/lang/pt.json b/www/addons/mod/glossary/lang/pt.json
index 151febb1e95..6887c9ff44c 100644
--- a/www/addons/mod/glossary/lang/pt.json
+++ b/www/addons/mod/glossary/lang/pt.json
@@ -1,5 +1,5 @@
{
- "attachment": "Anexar Medalha à mensagem",
+ "attachment": "Anexo",
"browsemode": "Ver entradas",
"byalphabet": "Alfabeticamente",
"byauthor": "Agrupar por autor",
@@ -8,8 +8,8 @@
"byrecentlyupdated": "Recentemente atualizados",
"bysearch": "Pesquisar",
"cannoteditentry": "Não é possível editar a entrada",
- "casesensitive": "Usar regular expressions",
- "categories": "Categorias de disciplinas",
+ "casesensitive": "Respeitar maiúsculas/minúsculas",
+ "categories": "Categorias",
"entriestobesynced": "Entradas a ser sincronizadas",
"entrypendingapproval": "Este termo aguarda aprovação.",
"errorloadingentries": "Ocorreu um erro ao carregar os termos.",
diff --git a/www/addons/mod/glossary/lang/ro.json b/www/addons/mod/glossary/lang/ro.json
index 1711d27b159..697bdf70ba4 100644
--- a/www/addons/mod/glossary/lang/ro.json
+++ b/www/addons/mod/glossary/lang/ro.json
@@ -1,13 +1,13 @@
{
- "attachment": "Atașament",
- "browsemode": "Căutați în datele introduse",
+ "attachment": "Adaugă o etichetă mesajului",
+ "browsemode": "Mod Căutare",
"byalphabet": "Alfabetic",
"byauthor": "Grupare după autor",
"bynewestfirst": "Cele mai noi sunt dispuse primele",
"byrecentlyupdated": "Actualizări recente",
"bysearch": "Căutare",
- "casesensitive": "Foloseşte Regular Expressions",
- "categories": "Categorii de cursuri",
+ "casesensitive": "Senzitivitate caractere",
+ "categories": "Categorii",
"entrypendingapproval": "Această",
"errorloadingentries": "A apărut o eroare la încărcarea intrărilor.",
"errorloadingentry": "A apărut o eroare la încărcarea intrărilor.",
diff --git a/www/addons/mod/glossary/lang/ru.json b/www/addons/mod/glossary/lang/ru.json
index 05189841b97..487d64188b1 100644
--- a/www/addons/mod/glossary/lang/ru.json
+++ b/www/addons/mod/glossary/lang/ru.json
@@ -1,10 +1,10 @@
{
- "attachment": "Вложение:",
+ "attachment": "Прикрепить значок к сообщению",
"browsemode": "Режим предпросмотра",
"byalphabet": "Алфавитно",
"byauthor": "Группировать по автору",
"bycategory": "Группировать по категориям",
"bysearch": "Поиск",
- "casesensitive": "Использовать регулярные выражения",
- "categories": "Категории курсов"
+ "casesensitive": "Чувствительность ответа к регистру",
+ "categories": "Категории"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/sr-cr.json b/www/addons/mod/glossary/lang/sr-cr.json
new file mode 100644
index 00000000000..79d5aec0558
--- /dev/null
+++ b/www/addons/mod/glossary/lang/sr-cr.json
@@ -0,0 +1,20 @@
+{
+ "attachment": "Прилог",
+ "browsemode": "Прегледај појмове",
+ "byalphabet": "Азбучним редом",
+ "byauthor": "Групиши по аутору",
+ "bycategory": "Групиши по категорији",
+ "bynewestfirst": "Најновији прво",
+ "byrecentlyupdated": "Недавно ажурирани",
+ "bysearch": "Претражи",
+ "cannoteditentry": "Не можете да уређујете појам",
+ "casesensitive": "Користи регуларне изразе",
+ "categories": "Категорије курсева",
+ "entriestobesynced": "Појмови за синхронизацију",
+ "entrypendingapproval": "Овај појам чека одобрење.",
+ "errorloadingentries": "Дошло је до грешке приликом учитавања појмова.",
+ "errorloadingentry": "Дошло је до грешке приликом учитавања појма.",
+ "errorloadingglossary": "Дошло је до грешке приликом учитавања речника.",
+ "noentriesfound": "Није пронађен ниједан појам.",
+ "searchquery": "Упит за претрагу"
+}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/sr-lt.json b/www/addons/mod/glossary/lang/sr-lt.json
new file mode 100644
index 00000000000..4edfb5a1f41
--- /dev/null
+++ b/www/addons/mod/glossary/lang/sr-lt.json
@@ -0,0 +1,20 @@
+{
+ "attachment": "Prilog",
+ "browsemode": "Pregledaj pojmove",
+ "byalphabet": "Abecednim redom",
+ "byauthor": "Grupiši po autoru",
+ "bycategory": "Grupiši po kategoriji",
+ "bynewestfirst": "Najnoviji prvo",
+ "byrecentlyupdated": "Nedavno ažurirani",
+ "bysearch": "Pretraži",
+ "cannoteditentry": "Ne možete da uređujete pojam",
+ "casesensitive": "Koristi regularne izraze",
+ "categories": "Kategorije kurseva",
+ "entriestobesynced": "Pojmovi za sinhronizaciju",
+ "entrypendingapproval": "Ovaj pojam čeka odobrenje.",
+ "errorloadingentries": "Došlo je do greške prilikom učitavanja pojmova.",
+ "errorloadingentry": "Došlo je do greške prilikom učitavanja pojma.",
+ "errorloadingglossary": "Došlo je do greške prilikom učitavanja rečnika.",
+ "noentriesfound": "Nije pronađen nijedan pojam.",
+ "searchquery": "Upit za pretragu"
+}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/sv.json b/www/addons/mod/glossary/lang/sv.json
index f9dc8d60f6a..7fb8c3d2643 100644
--- a/www/addons/mod/glossary/lang/sv.json
+++ b/www/addons/mod/glossary/lang/sv.json
@@ -1,13 +1,13 @@
{
- "attachment": "Bifoga märke med meddelande",
+ "attachment": "Bilaga",
"browsemode": "Bläddrar bland poster",
"byalphabet": "Alfabetiskt",
"byauthor": "Sortera efter författare",
"bynewestfirst": "Nyaste först",
"byrecentlyupdated": "Nyligen uppdaterade",
"bysearch": "Sök",
- "casesensitive": "Använd standarduttryck",
- "categories": "Kurskategorier",
+ "casesensitive": "Stor eller liten bokstav gör skillnad",
+ "categories": "Kategorier",
"entrypendingapproval": "Detta inlägg väntar på godkännande",
"errorloadingentries": "Ett fel uppstod vid inläsning av inläggen",
"errorloadingentry": "Ett fel uppstod vid inläsning av inlägget",
diff --git a/www/addons/mod/glossary/lang/tr.json b/www/addons/mod/glossary/lang/tr.json
index ed836454608..6acccdba883 100644
--- a/www/addons/mod/glossary/lang/tr.json
+++ b/www/addons/mod/glossary/lang/tr.json
@@ -1,6 +1,6 @@
{
- "attachment": "Rozete mesaj ekle",
+ "attachment": "Dosya",
"browsemode": "Önizleme Modu",
- "casesensitive": "Düzenli İfadeleri Kullan",
- "categories": "Ders Kategorileri"
+ "casesensitive": "Harf duyarlılığı",
+ "categories": "Kategoriler"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/uk.json b/www/addons/mod/glossary/lang/uk.json
index 5452c0da423..fecbe90319d 100644
--- a/www/addons/mod/glossary/lang/uk.json
+++ b/www/addons/mod/glossary/lang/uk.json
@@ -1,15 +1,15 @@
{
- "attachment": "Долучення",
+ "attachment": "Прикріпити відзнаку до повідомлення",
"browsemode": "Перегляд записів",
"byalphabet": "По алфавіту",
"byauthor": "Групувати за автором",
"bycategory": "Групувати за категорією",
"bynewestfirst": "Новіші перші",
- "byrecentlyupdated": "Недавно оновлені",
+ "byrecentlyupdated": "Нещодавно оновлені",
"bysearch": "Пошук",
- "cannoteditentry": "Неможливо задагувати запис",
- "casesensitive": "Використовувати регулярні вирази",
- "categories": "Категорії курсів",
+ "cannoteditentry": "Неможливо редагувати запис",
+ "casesensitive": "Чутливість відповіді до регістра",
+ "categories": "Категорії",
"entriestobesynced": "Записи будуть синхронізовані",
"entrypendingapproval": "Цей запис очікує схвалення.",
"errorloadingentries": "Сталася помилка під час завантаження записів.",
diff --git a/www/addons/mod/glossary/lang/zh-cn.json b/www/addons/mod/glossary/lang/zh-cn.json
index 761fdac404e..3af5cbb310e 100644
--- a/www/addons/mod/glossary/lang/zh-cn.json
+++ b/www/addons/mod/glossary/lang/zh-cn.json
@@ -1,6 +1,6 @@
{
- "attachment": "附件发送",
+ "attachment": "附件",
"browsemode": "预览模式",
- "casesensitive": "使用正则表达式",
- "categories": "课程分类"
+ "casesensitive": "区分大小写字母",
+ "categories": "类别"
}
\ No newline at end of file
diff --git a/www/addons/mod/glossary/lang/zh-tw.json b/www/addons/mod/glossary/lang/zh-tw.json
index d89166a41e8..8c24d72719a 100644
--- a/www/addons/mod/glossary/lang/zh-tw.json
+++ b/www/addons/mod/glossary/lang/zh-tw.json
@@ -1,13 +1,13 @@
{
- "attachment": "在訊息上附加上獎章",
+ "attachment": "附件",
"browsemode": "瀏覽條目",
"byalphabet": "按字母順序排列",
"byauthor": "以作者為分群",
"bynewestfirst": "最新的優先",
"byrecentlyupdated": "最近的更新",
"bysearch": "搜尋",
- "casesensitive": "區分大小寫",
- "categories": "課程類別",
+ "casesensitive": "區分字母的大小寫",
+ "categories": "類別",
"entrypendingapproval": "這個項目已被暫緩核可",
"errorloadingentries": "載入項目時發生錯誤",
"errorloadingentry": "載入項目時發生錯誤",
diff --git a/www/addons/mod/glossary/services/handlers.js b/www/addons/mod/glossary/services/handlers.js
index 0cf6d199865..80834abf457 100644
--- a/www/addons/mod/glossary/services/handlers.js
+++ b/www/addons/mod/glossary/services/handlers.js
@@ -105,9 +105,10 @@ angular.module('mm.addons.mod_glossary')
// Get download size to ask for confirm if it's high.
$mmaModGlossaryPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModGlossaryPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModGlossaryPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/imscp/controllers/index.js b/www/addons/mod/imscp/controllers/index.js
index 506860b14c5..41f6ebd7227 100644
--- a/www/addons/mod/imscp/controllers/index.js
+++ b/www/addons/mod/imscp/controllers/index.js
@@ -101,8 +101,8 @@ angular.module('mm.addons.mod_imscp')
// We could load the main file but the download failed. Show error message.
$mmUtil.showErrorModal('mm.core.errordownloadingsomefiles', true);
}
- }).catch(function() {
- $mmUtil.showErrorModal('mma.mod_imscp.deploymenterror', true);
+ }).catch(function(error) {
+ $mmUtil.showErrorModalDefault(error, 'mma.mod_imscp.deploymenterror', true);
return $q.reject();
});
}).finally(function() {
diff --git a/www/addons/mod/imscp/lang/es_mx.json b/www/addons/mod/imscp/lang/es_mx.json
deleted file mode 100644
index 175d34d526d..00000000000
--- a/www/addons/mod/imscp/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "deploymenterror": "¡Error en paquete de contenidos!"
-}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/ja.json b/www/addons/mod/imscp/lang/ja.json
index 66c407ae43e..5bd979018e4 100644
--- a/www/addons/mod/imscp/lang/ja.json
+++ b/www/addons/mod/imscp/lang/ja.json
@@ -1,3 +1,4 @@
{
- "deploymenterror": "コンテンツパッケージエラー!"
+ "deploymenterror": "コンテンツパッケージエラー!",
+ "showmoduledescription": "説明の表示"
}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/pt_br.json b/www/addons/mod/imscp/lang/pt_br.json
deleted file mode 100644
index cb7e6aec6a1..00000000000
--- a/www/addons/mod/imscp/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "deploymenterror": "Erro no conte"
-}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/sr-cr.json b/www/addons/mod/imscp/lang/sr-cr.json
new file mode 100644
index 00000000000..939547b3b5f
--- /dev/null
+++ b/www/addons/mod/imscp/lang/sr-cr.json
@@ -0,0 +1,3 @@
+{
+ "showmoduledescription": "Прикажи опис"
+}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/sr-lt.json b/www/addons/mod/imscp/lang/sr-lt.json
new file mode 100644
index 00000000000..8519e32307b
--- /dev/null
+++ b/www/addons/mod/imscp/lang/sr-lt.json
@@ -0,0 +1,3 @@
+{
+ "showmoduledescription": "Prikaži opis"
+}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/zh_cn.json b/www/addons/mod/imscp/lang/zh_cn.json
deleted file mode 100644
index 29923d4664e..00000000000
--- a/www/addons/mod/imscp/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "deploymenterror": "内容包有错!"
-}
\ No newline at end of file
diff --git a/www/addons/mod/imscp/lang/zh_tw.json b/www/addons/mod/imscp/lang/zh_tw.json
deleted file mode 100644
index f2f35ec5337..00000000000
--- a/www/addons/mod/imscp/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "deploymenterror": "內容包有錯誤!"
-}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/es_mx.json b/www/addons/mod/label/lang/es_mx.json
deleted file mode 100644
index 129eb9e3838..00000000000
--- a/www/addons/mod/label/lang/es_mx.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "Etiqueta"
-}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/he.json b/www/addons/mod/label/lang/he.json
index 232aff3b2bf..7f0814d0381 100644
--- a/www/addons/mod/label/lang/he.json
+++ b/www/addons/mod/label/lang/he.json
@@ -1,3 +1,3 @@
{
- "label": "תווית לשאלה מותנית (באנגלית)"
+ "label": "תווית"
}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/pt_br.json b/www/addons/mod/label/lang/pt_br.json
deleted file mode 100644
index fdfc1ff9392..00000000000
--- a/www/addons/mod/label/lang/pt_br.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "Rótulo"
-}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/sr-cr.json b/www/addons/mod/label/lang/sr-cr.json
new file mode 100644
index 00000000000..ee0697520d2
--- /dev/null
+++ b/www/addons/mod/label/lang/sr-cr.json
@@ -0,0 +1,3 @@
+{
+ "label": "Натпис"
+}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/sr-lt.json b/www/addons/mod/label/lang/sr-lt.json
new file mode 100644
index 00000000000..c2a3f10a06e
--- /dev/null
+++ b/www/addons/mod/label/lang/sr-lt.json
@@ -0,0 +1,3 @@
+{
+ "label": "Natpis"
+}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/zh_cn.json b/www/addons/mod/label/lang/zh_cn.json
deleted file mode 100644
index 4bbc4110d7a..00000000000
--- a/www/addons/mod/label/lang/zh_cn.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "标签"
-}
\ No newline at end of file
diff --git a/www/addons/mod/label/lang/zh_tw.json b/www/addons/mod/label/lang/zh_tw.json
deleted file mode 100644
index c1a016fd047..00000000000
--- a/www/addons/mod/label/lang/zh_tw.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "標籤"
-}
\ No newline at end of file
diff --git a/www/addons/mod/lesson/controllers/player.js b/www/addons/mod/lesson/controllers/player.js
index 7c2e5f840d5..b7eb0b459c1 100644
--- a/www/addons/mod/lesson/controllers/player.js
+++ b/www/addons/mod/lesson/controllers/player.js
@@ -190,7 +190,7 @@ angular.module('mm.addons.mod_lesson')
$scope.pageData = data;
$scope.title = data.page.title;
- $scope.pageContent = data.page.contents;
+ $scope.pageContent = $mmaModLessonHelper.getPageContentsFromPageData(data);
$scope.pageLoaded = true;
$scope.currentPage = pageId;
$scope.messages = $scope.messages.concat(data.messages);
diff --git a/www/addons/mod/lesson/lang/ar.json b/www/addons/mod/lesson/lang/ar.json
index e314397c4ae..4f326bb530d 100644
--- a/www/addons/mod/lesson/lang/ar.json
+++ b/www/addons/mod/lesson/lang/ar.json
@@ -1,5 +1,6 @@
{
"answer": "أجب",
+ "attempt": "محاولة: {{$a}}",
"averagescore": "متوسط الدرجة",
"averagetime": "متوسط الوقت",
"branchtable": "محتوى",
@@ -36,7 +37,7 @@
"review": "مراجعة",
"reviewlesson": "مراجعة الدرس",
"reviewquestionback": "نعم، أرغب في المحاولة ثانياً",
- "submit": "سلم",
+ "submit": "سلم/قدم",
"thatsthecorrectanswer": "هذه إجابة صحيحة",
"thatsthewronganswer": "هذه إجابة خاطئة",
"timeremaining": "الزمن المتبقى",
diff --git a/www/addons/mod/lesson/lang/bg.json b/www/addons/mod/lesson/lang/bg.json
index a1b9df04b2a..599f091c09d 100644
--- a/www/addons/mod/lesson/lang/bg.json
+++ b/www/addons/mod/lesson/lang/bg.json
@@ -1,5 +1,6 @@
{
"answer": "Отговор",
+ "attempt": "{{$a}} опит",
"attemptsremaining": "Имате оставащ(и) {{$a}} опит(a)",
"averagescore": "Среден резултат",
"averagetime": "Средно време",
diff --git a/www/addons/mod/lesson/lang/ca.json b/www/addons/mod/lesson/lang/ca.json
index ad28463c750..8978fa00b80 100644
--- a/www/addons/mod/lesson/lang/ca.json
+++ b/www/addons/mod/lesson/lang/ca.json
@@ -1,5 +1,6 @@
{
"answer": "Resposta",
+ "attempt": "Intent: {{$a}}",
"attemptheader": "Intent",
"attemptsremaining": "Us resten {{$a}} intents",
"averagescore": "Puntuació mitjana",
diff --git a/www/addons/mod/lesson/lang/cs.json b/www/addons/mod/lesson/lang/cs.json
index c6b5605a360..9918f0689c7 100644
--- a/www/addons/mod/lesson/lang/cs.json
+++ b/www/addons/mod/lesson/lang/cs.json
@@ -1,5 +1,6 @@
{
"answer": "Odpověď",
+ "attempt": "Pokus: {{$a}}",
"attemptheader": "Pokus",
"attemptsremaining": "Zbývající počet pokusů: {{$a}}",
"averagescore": "Průměrná známka",
diff --git a/www/addons/mod/lesson/lang/da.json b/www/addons/mod/lesson/lang/da.json
index d00ff2ab04e..54d6c8482c3 100644
--- a/www/addons/mod/lesson/lang/da.json
+++ b/www/addons/mod/lesson/lang/da.json
@@ -1,5 +1,6 @@
{
"answer": "Svar",
+ "attempt": "Forsøg: {{$a}}",
"attemptheader": "Forsøg",
"attemptsremaining": "Du har {{$a}} forsøg endnu",
"averagescore": "Gennemsnitlig score",
diff --git a/www/addons/mod/lesson/lang/de.json b/www/addons/mod/lesson/lang/de.json
index 60f5cf0ae98..dd4695db26b 100644
--- a/www/addons/mod/lesson/lang/de.json
+++ b/www/addons/mod/lesson/lang/de.json
@@ -1,5 +1,6 @@
{
"answer": "Antwort",
+ "attempt": "Versuch: {{$a}}",
"attemptheader": "Versuch",
"attemptsremaining": "Verbleibende Versuche: {{$a}}",
"averagescore": "Durchschnittliche Bewertung",
@@ -21,6 +22,7 @@
"emptypassword": "Das Kennwort muss eingegeben werden",
"enterpassword": "Bitte geben Sie das Kennwort ein:",
"eolstudentoutoftimenoanswers": "Sie haben keine Fragen beantwortet. Sie erhalten daher 0 Punkte für die Lektion.",
+ "errorprefetchrandombranch": "Diese Lektion enthält einen Sprung zu einer zufälligen Seite. Sie kann nicht in der App versucht werden, ohne im Web begonnen zu sein.",
"errorreviewretakenotlast": "Dieser Versuch kann nicht erneut angesehen werden, weil ein weiterer Versuch beendet wurde.",
"finish": "Fertigstellen",
"finishretakeoffline": "Dieser Versuch wurde offline beendet.",
diff --git a/www/addons/mod/lesson/lang/el.json b/www/addons/mod/lesson/lang/el.json
index d2c0aa91741..cff02dafbf6 100644
--- a/www/addons/mod/lesson/lang/el.json
+++ b/www/addons/mod/lesson/lang/el.json
@@ -1,5 +1,6 @@
{
"answer": "Απάντηση",
+ "attempt": "Προσπάθεια: {{$a}}",
"attemptsremaining": "Σας απομένουν {{$a}} προσπάθειες",
"averagescore": "Μέσος βαθμός",
"averagetime": "Μέσος χρόνος",
@@ -19,6 +20,8 @@
"emptypassword": "Ο κωδικός πρόσβασης δεν μπορεί να είναι κενός",
"enterpassword": "Παρακαλώ εισάγετε τον κωδικό:",
"eolstudentoutoftimenoanswers": "Δεν απαντήσατε καμία ερώτηση. Πήρατε 0 σε αυτή την ενότητα.",
+ "errorreviewretakenotlast": "Αυτή η προσπάθεια δεν μπορεί πλέον να αναθεωρηθεί επειδή μια άλλη προσπάθεια έχει ήδη ολοκληρωθεί.",
+ "finishretakeoffline": "Αυτή η προσπάθεια έχει ολοκληρωθεί εκτός σύνδεσης.",
"firstwrong": "Δυστυχώς δεν μπορείτε να κερδίσετε αυτό το βαθμό γιατί η απάντησή σας ήταν λάθος. Θέλετε να συνεχίσετε να μαντεύετε, μόνο για τη χαρά της μάθησης (δεν θα λάβετε το βαθμολογικό μπόνους);",
"grade": "Βαθμός",
"highscore": "Υψηλός βαθμός",
@@ -49,6 +52,9 @@
"rawgrade": "Βαθμός χωρίς επεξεργασία",
"reports": "Αναφορές",
"response": "Ανταπόκριση",
+ "retakefinishedinsync": "Μια προσπάθεια εκτός σύνδεσης συγχρονίστηκε. Θέλετε να την αναθεωρήσετε;",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
"review": "Αναθεώρηση",
"reviewlesson": "Αναθεώρηση ενότητας",
"reviewquestionback": "Ναι, θα ήθελα να δοκιμάσω πάλι",
@@ -63,6 +69,7 @@
"timeremaining": "Υπολοιπόμενος χρόνος",
"timetaken": "Χρόνος που χρειάστηκε",
"unseenpageinbranch": "Ερώτηση μέσα σε διακλάδωση που δεν εμφανίσθηκε",
+ "warningretakefinished": "Η προσπάθεια ολοκληρώθηκε στον ιστότοπο.",
"welldone": "Μπράβο!",
"youhaveseen": "Έχετε δει περισσότερες από μία σελίδες αυτής της ενότητας. Θέλετε να ξεκινήσετε από την τελευταία σελίδα που είδατε;",
"youranswer": "Η απάντησή σας",
diff --git a/www/addons/mod/lesson/lang/en.json b/www/addons/mod/lesson/lang/en.json
index 92a9bb049b6..f9425621099 100644
--- a/www/addons/mod/lesson/lang/en.json
+++ b/www/addons/mod/lesson/lang/en.json
@@ -22,7 +22,7 @@
"emptypassword": "Password cannot be empty",
"enterpassword": "Please enter the password:",
"eolstudentoutoftimenoanswers": "You did not answer any questions. You have received a 0 for this lesson.",
- "errorprefetchrandombranch": "This lesson contains a jump to a random content page, it cannot be attempted in the app until it has been started in web.",
+ "errorprefetchrandombranch": "This lesson contains a jump to a random content page. It can't be attempted in the app until it has been started in a web browser.",
"errorreviewretakenotlast": "This attempt can no longer be reviewed because another attempt has been finished.",
"finish": "Finish",
"finishretakeoffline": "This attempt was finished offline.",
diff --git a/www/addons/mod/lesson/lang/es-mx.json b/www/addons/mod/lesson/lang/es-mx.json
index ead72ecbab5..b45c0a2544c 100644
--- a/www/addons/mod/lesson/lang/es-mx.json
+++ b/www/addons/mod/lesson/lang/es-mx.json
@@ -1,5 +1,6 @@
{
"answer": "Respuesta",
+ "attempt": "Intento: {{$a}}",
"attemptheader": "Intento",
"attemptsremaining": "Tiene {{$a}} intento(s) restante(s)",
"averagescore": "Puntuación promedio",
@@ -21,9 +22,10 @@
"emptypassword": "La contraseña no puede estar vacía",
"enterpassword": "Por favor, escriba la contraseña:",
"eolstudentoutoftimenoanswers": "No ha contestado a ninguna pregunta. En esta lección ha obtenido 0 puntos.",
- "errorreviewretakenotlast": "Este intento no puede ser revisado más porque se ha terminado otro intento.",
+ "errorprefetchrandombranch": "Esta lección contiene un salto hacia una página aleatoria de contenido; no puede ser intentada en la App hasta que haya sido comenzada en web.",
+ "errorreviewretakenotlast": "Este intento ya no puede ser revisado más porque se ha terminado otro intento.",
"finish": "Terminar",
- "finishretakeoffline": "Este intento se ha terminado en fuera-de-línea.",
+ "finishretakeoffline": "Este intento fue terminado fuera-de-línea.",
"firstwrong": "Lo sentimos, usted ha contestado incorrectamente. ¡Le gustaría volver a intentar la pregunta de nuevo? (si Usted contesta ahora la pregunta correctamente, no contará hacia su puntaje final).",
"gotoendoflesson": "Ir al final de lección",
"grade": "Calificación",
@@ -74,7 +76,7 @@
"timeremaining": "Tiempo restante",
"timetaken": "Tiempo empleado",
"unseenpageinbranch": "Pregunta no vista dentro de una página de conenidos",
- "warningretakefinished": "Este intento fue terminado en el sitio.",
+ "warningretakefinished": "Este intento fue terminado en el sitio web.",
"welldone": "¡Bien hecho!",
"youhaveseen": "Usted ya ha visto más de una página de esta lección. ¿Desea comenzar desde la última página vista?",
"youranswer": "Su respuesta",
diff --git a/www/addons/mod/lesson/lang/es.json b/www/addons/mod/lesson/lang/es.json
index 1b960b84214..9c084627631 100644
--- a/www/addons/mod/lesson/lang/es.json
+++ b/www/addons/mod/lesson/lang/es.json
@@ -1,5 +1,6 @@
{
"answer": "Respuesta",
+ "attempt": "Intento: {{$a}}",
"attemptheader": "Intento",
"attemptsremaining": "Tiene {{$a}} intento(s) pendiente(s)",
"averagescore": "Puntuación promedio",
@@ -21,7 +22,9 @@
"emptypassword": "La contraseña no puede estar vacía",
"enterpassword": "Por favor, escriba la contraseña:",
"eolstudentoutoftimenoanswers": "No ha contestado a ninguna pregunta. En esta lección ha obtenido 0 puntos.",
+ "errorreviewretakenotlast": "Este intento no puede ser revisado ya que se ha terminado otro intento.",
"finish": "Terminado",
+ "finishretakeoffline": "Este intento se ha terminado en fuera-de-línea.",
"firstwrong": "Lo sentimos, usted no puede obtener este punto porque su respuesta no es correcta. ¿Desea seguir intentándolo? (únicamente para aprender, no para ganar el punto).",
"gotoendoflesson": "Ir al final de la lección",
"grade": "Calificación",
@@ -55,6 +58,9 @@
"rawgrade": "Calificación en bruto",
"reports": "Informes",
"response": "Comentario",
+ "retakefinishedinsync": "Un intento fuera-de-línea fue sincronizado. ¿Quiere usted revisarlo?",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
"review": "Revisión",
"reviewlesson": "Revisar lección",
"reviewquestionback": "Sí, me gustaría probar de nuevo",
@@ -69,6 +75,7 @@
"timeremaining": "Tiempo restante",
"timetaken": "Tiempo empleado",
"unseenpageinbranch": "Pregunta no vista dentro de una página de conenidos",
+ "warningretakefinished": "Este intento se terminó en el sitio.",
"welldone": "¡Bien hecho!",
"youhaveseen": "Usted ya ha visto más de una página de esta lección. ¿Desea comenzar desde la última página vista?",
"youranswer": "Su respuesta",
diff --git a/www/addons/mod/lesson/lang/eu.json b/www/addons/mod/lesson/lang/eu.json
index eb0cc12c6b0..fac71d304b6 100644
--- a/www/addons/mod/lesson/lang/eu.json
+++ b/www/addons/mod/lesson/lang/eu.json
@@ -1,5 +1,6 @@
{
"answer": "Erantzuna",
+ "attempt": "Saiakera: {{$a}}",
"attemptheader": "Saiakera",
"attemptsremaining": "{{$a}} saiakera pendiente daukazu",
"averagescore": "Batez besteko puntuazioa",
@@ -24,7 +25,7 @@
"errorreviewretakenotlast": "Saiakera hau ezin da berrikusi dagoeneko beste saiakera bat amaitu duzulako.",
"finish": "Amaitu",
"finishretakeoffline": "Saiakera lineaz kanpo bukatu da.",
- "firstwrong": "Sentitzen dugu. Ez duzu puntua lortu zure erantzuna zuzena izan ez delako. Berriz saiatu nahi al duzu? (ikasteko bakarrik, ez puntua lortzeko).",
+ "firstwrong": "Zure erantzuna ez da zuzena izan. Berriz saiatu nahi al duzu? (Oraingoan ondo erantzunez gero ez da zure azken emaitzan zenbatuko).",
"gotoendoflesson": "Joan ikasgaiaren amaierara",
"grade": "Kalifikazioa",
"highscore": "Puntuazio altua",
diff --git a/www/addons/mod/lesson/lang/fa.json b/www/addons/mod/lesson/lang/fa.json
index 79774430714..36d3d14fd74 100644
--- a/www/addons/mod/lesson/lang/fa.json
+++ b/www/addons/mod/lesson/lang/fa.json
@@ -1,5 +1,6 @@
{
"answer": "جواب",
+ "attempt": "تلاش: {{$a}}",
"attemptsremaining": "میتوانید {{$a}} بار دیگر تلاش کنید",
"averagescore": "نمرهٔ میانگین",
"averagetime": "زمان میانگین",
diff --git a/www/addons/mod/lesson/lang/fr.json b/www/addons/mod/lesson/lang/fr.json
index 2b8652437b9..538cdcf99bb 100644
--- a/www/addons/mod/lesson/lang/fr.json
+++ b/www/addons/mod/lesson/lang/fr.json
@@ -1,5 +1,6 @@
{
"answer": "Réponse",
+ "attempt": "Tentative : {{$a}}",
"attemptheader": "Tentative",
"attemptsremaining": "Il vous reste {{$a}} tentative(s)",
"averagescore": "Note moyenne",
@@ -21,7 +22,10 @@
"emptypassword": "Le mot de passe ne peut pas être vide",
"enterpassword": "Veuillez saisir le mot de passe :",
"eolstudentoutoftimenoanswers": "vous n'avez répondu à aucune question. Votre note pour cette leçon est de 0.",
+ "errorprefetchrandombranch": "Cette leçon comporte un saut vers une page aléatoire. Elle ne peut être effectuée dans l'app avant d'avoir été commencée dans un navigateur.",
+ "errorreviewretakenotlast": "Cette tentative ne peut plus être relue, car une autre tentative a été terminée.",
"finish": "Terminer",
+ "finishretakeoffline": "Cette tentative a été terminée hors ligne.",
"firstwrong": "Vous n'avez pas répondu correctement. Voulez-vous essayer de deviner la bonne réponse ? Si vous répondez maintenant correctement, vous ne recevrez cependant pas de point.",
"gotoendoflesson": "Aller à la fin de la leçon",
"grade": "Note",
@@ -55,13 +59,16 @@
"rawgrade": "Note brute",
"reports": "Rapports",
"response": "Feedback",
+ "retakefinishedinsync": "Une tentative hors ligne a été synchronisée. Voulez-vous la relire ?",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
"review": "Relecture",
"reviewlesson": "Revoir la leçon",
"reviewquestionback": "Oui, j'aimerais essayer à nouveau",
"reviewquestioncontinue": "Non, je veux passer à la question suivante",
"secondpluswrong": "Pas tout à fait. Voulez-vous essayer à nouveau ?",
"submit": "Envoyer",
- "teacherjumpwarning": "Un lien {{$a.cluster}} ou un lien {{$a.unseen}} est utilisé dans cette leçon. Un lien « Page suivante » sera utilisé à sa place. Veuillez vous connecter en tant que participant pour tester ces liens.",
+ "teacherjumpwarning": "Un lien {{$a.cluster}} ou un lien {{$a.unseen}} est utilisé dans cette leçon. Un lien « Page suivante » sera utilisé à sa place. Veuillez vous connecter en tant qu'étudiant pour tester ces liens.",
"teacherongoingwarning": "Le score actuel n'est affiché que pour les étudiants. Veuillez vous connecter en tant qu'étudiant pour tester le score actuel.",
"teachertimerwarning": "Le chronomètre ne fonctionne que pour les étudiants. Veuillez vous connecter en tant qu'étudiant pour tester le chronomètre.",
"thatsthecorrectanswer": "C'est une réponse correcte",
@@ -69,6 +76,7 @@
"timeremaining": "Durée restante",
"timetaken": "Durée utilisée",
"unseenpageinbranch": "Question non vue au sein d'une page de contenu",
+ "warningretakefinished": "Cette tentative a été terminée dans un navigateur.",
"welldone": "Bien joué !",
"youhaveseen": "Vous avez déjà vu au moins une page de cette leçon. Voulez-vous commencer à la dernière page que vous avez vue ?",
"youranswer": "Votre réponse",
diff --git a/www/addons/mod/lesson/lang/he.json b/www/addons/mod/lesson/lang/he.json
index cc0a9600655..637604577d7 100644
--- a/www/addons/mod/lesson/lang/he.json
+++ b/www/addons/mod/lesson/lang/he.json
@@ -1,5 +1,6 @@
{
"answer": "תשובה",
+ "attempt": "ניסיון: {{$a}}",
"attemptheader": "ניסיון",
"attemptsremaining": "נשארו לך עוד {{$a}} ניסיונות",
"averagescore": "תוצאה ממוצעת",
diff --git a/www/addons/mod/lesson/lang/hu.json b/www/addons/mod/lesson/lang/hu.json
index d46a7ad2909..4c2bb5a14a2 100644
--- a/www/addons/mod/lesson/lang/hu.json
+++ b/www/addons/mod/lesson/lang/hu.json
@@ -1,5 +1,6 @@
{
"answer": "Válasz",
+ "attempt": "Próbálkozás: {{$a}}",
"attemptheader": "Próbálkozás",
"attemptsremaining": "{{$a}} próbálkozása maradt",
"averagescore": "Átlagpontszám",
diff --git a/www/addons/mod/lesson/lang/it.json b/www/addons/mod/lesson/lang/it.json
index de8299fe5af..3cd913414eb 100644
--- a/www/addons/mod/lesson/lang/it.json
+++ b/www/addons/mod/lesson/lang/it.json
@@ -1,5 +1,6 @@
{
"answer": "Risposta",
+ "attempt": "Tentativo: {{$a}}",
"attemptheader": "Tentativo",
"attemptsremaining": "Ti rimangono {{$a}} tentativo/i",
"averagescore": "Punteggio medio",
diff --git a/www/addons/mod/lesson/lang/ja.json b/www/addons/mod/lesson/lang/ja.json
index 18e3ade173c..786b3484757 100644
--- a/www/addons/mod/lesson/lang/ja.json
+++ b/www/addons/mod/lesson/lang/ja.json
@@ -1,5 +1,6 @@
{
- "answer": "答え/選択肢",
+ "answer": "答え",
+ "attempt": "受験: {{$a}}",
"attemptheader": "受験",
"attemptsremaining": "あなたには {{$a}} 回の受験回数が残っています。",
"averagescore": "平均評点",
@@ -21,14 +22,16 @@
"emptypassword": "パスワードは空白にできません。",
"enterpassword": "パスワードを入力してください:",
"eolstudentoutoftimenoanswers": "あなたはどの問題にも解答していません。このレッスンのあなたの評点は0点です。",
+ "errorreviewretakenotlast": "この回答は、別の回答が完了しているため評価できません。",
"finish": "終了",
+ "finishretakeoffline": "この回答はオフライン状態で完了しました。",
"firstwrong": "あなたの解答は正しくありません。問題を再度受験しますか? (今から問題に正しく解答した場合、あなたの最終評点には加算されません)",
"gotoendoflesson": "レッスンの最後に移動する",
"grade": "評点",
"highscore": "最高評点",
"hightime": "最長時間",
"leftduringtimed": "あなたは制限時間のあるレッスンを途中で終了しました。 レッスンを再スタートするには「続ける」をクリックしてください。",
- "leftduringtimednoretake": "あなたは制限時間のあるレッスンを途中で終了しました。 レッスンを再受験または継続は許可されていません。",
+ "leftduringtimednoretake": "あなたは制限時間のあるレッスンを途中で終了しました。 レッスンの再受験または継続は許可されていません。",
"lessonmenu": "レッスンメニュー",
"lessonstats": "レッスン統計",
"linkedmedia": "リンクメディア",
@@ -36,10 +39,10 @@
"lowscore": "最低評点",
"lowtime": "最短時間",
"maximumnumberofattemptsreached": "最大受験回数に達しました - 次のページに移動しています。",
- "modattemptsnoteacher": "学生レビューは学生のみに表示されます。",
+ "modattemptsnoteacher": "学生レビューは学生にのみ表示されます。",
"noanswer": "1つまたはそれ以上の問題が解答されていません。戻って解答を送信してください。",
"nolessonattempts": "このレッスンは受験されていません。",
- "nolessonattemptsgroup": "このレッスンの {{$a}} グループメンバーによる受験はありません。",
+ "nolessonattemptsgroup": "このレッスンでは {{$a}} グループメンバーによる受験はありません。",
"notcompleted": "未了",
"numberofcorrectanswers": "正解数: {{$a}}",
"numberofpagesviewed": "解答済み問題数: {{$a}}",
@@ -55,6 +58,9 @@
"rawgrade": "素点",
"reports": "レポート",
"response": "返答",
+ "retakefinishedinsync": "オフラインの回答が同期されました。評価しますか?",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
"review": "レビュー",
"reviewlesson": "レッスンをレビューする",
"reviewquestionback": "はい、もう一度受験します",
@@ -62,13 +68,14 @@
"secondpluswrong": "もう一度受験しますか?",
"submit": "送信",
"teacherjumpwarning": "このレッスンでは {{$a.cluster}} ジャンプまたは {{$a.unseen}} ジャンプが使用されています。代わりに「次のページ」へのジャンプが使用されます。これらのジャンプを確認するには学生としてログインしてください。",
- "teacherongoingwarning": "進行中の評点は学生にのみ表示されます。進行中のスコアをテストするには学生としてログインしてください。",
+ "teacherongoingwarning": "進行中の評点は学生にのみ表示されます。進行中の評点をテストするには学生としてログインしてください。",
"teachertimerwarning": "タイマーは学生に対してのみ作動します。タイマーをテストするには学生としてログインしてください。",
"thatsthecorrectanswer": "正解です。",
"thatsthewronganswer": "不正解です。",
"timeremaining": "残り時間",
"timetaken": "経過時間",
"unseenpageinbranch": "コンテンツページ内の未閲覧の問題",
+ "warningretakefinished": "回答はサイト内で完了しました。",
"welldone": "よくできました!",
"youhaveseen": "あなたはすでにこのレッスンを2ページ以上表示しました。 あなたが表示した最後のページから始めますか?",
"youranswer": "あなたの答え",
diff --git a/www/addons/mod/lesson/lang/lt.json b/www/addons/mod/lesson/lang/lt.json
index e088a565222..d342ddcca33 100644
--- a/www/addons/mod/lesson/lang/lt.json
+++ b/www/addons/mod/lesson/lang/lt.json
@@ -1,5 +1,6 @@
{
"answer": "Atsakyti",
+ "attempt": "Bandymas: {{$a}}",
"attemptheader": "Bandymas",
"attemptsremaining": "Turite likusių bandymų: {{$a}}",
"averagescore": "Vidutinis balas",
diff --git a/www/addons/mod/lesson/lang/nl.json b/www/addons/mod/lesson/lang/nl.json
index e2620a8cabf..1dfe7b3bc47 100644
--- a/www/addons/mod/lesson/lang/nl.json
+++ b/www/addons/mod/lesson/lang/nl.json
@@ -1,5 +1,6 @@
{
"answer": "Antwoord",
+ "attempt": "Poging: {{$a}}",
"attemptheader": "Poging",
"attemptsremaining": "Je kan nog {{$a}} poging(en) doen",
"averagescore": "Gemiddelde score",
@@ -21,9 +22,10 @@
"emptypassword": "Wachtwoord kan niet leeg zijn",
"enterpassword": "Geef het wachtwoord:",
"eolstudentoutoftimenoanswers": "Je hebt geen enkele vraag beantwoord. Je hebt een 0 voor deze les",
+ "errorprefetchrandombranch": "Deze les bevat een sprong naar een willekeurige inhoudspagina. De les kan niet gestart worden in de app zonder dat die gestart is op het web.",
"errorreviewretakenotlast": "Deze poging kan niet meer nagekeken worden omdat er al een andere poging voltooid is.",
"finish": "Einde",
- "finishretakeoffline": "Deze poging is voltooid in offline modus",
+ "finishretakeoffline": "Deze poging is voltooid in offline modus.",
"firstwrong": "Je antwoord is fout. Wil je de vraag opnieuw proberen te beantwoorden? Als je het antwoord weet, zul je er geen punten meer mee verdienen.",
"gotoendoflesson": "Ga naar het einde van de les",
"grade": "Cijfer",
diff --git a/www/addons/mod/lesson/lang/pl.json b/www/addons/mod/lesson/lang/pl.json
index c36b7ae91cf..410586113e2 100644
--- a/www/addons/mod/lesson/lang/pl.json
+++ b/www/addons/mod/lesson/lang/pl.json
@@ -1,5 +1,6 @@
{
"answer": "Odpowiedź",
+ "attempt": "Podejście: {{$a}}",
"attemptheader": "Próba",
"attemptsremaining": "Pozostało Ci {{$a}} podejść",
"averagescore": "Średnia liczba punktów",
diff --git a/www/addons/mod/lesson/lang/pt-br.json b/www/addons/mod/lesson/lang/pt-br.json
index a50382f3902..613d8d5c741 100644
--- a/www/addons/mod/lesson/lang/pt-br.json
+++ b/www/addons/mod/lesson/lang/pt-br.json
@@ -1,5 +1,6 @@
{
"answer": "Resposta",
+ "attempt": "Tentativa: {{$a}}",
"attemptheader": "Tentativa",
"attemptsremaining": "Você tem ainda {{$a}} tentativas",
"averagescore": "Pontuação média",
diff --git a/www/addons/mod/lesson/lang/pt.json b/www/addons/mod/lesson/lang/pt.json
index e236e65f35a..eab86d3e961 100644
--- a/www/addons/mod/lesson/lang/pt.json
+++ b/www/addons/mod/lesson/lang/pt.json
@@ -1,5 +1,6 @@
{
"answer": "Resposta",
+ "attempt": "Tentativa: {{$a}}",
"attemptheader": "Tentativa",
"attemptsremaining": "Ainda pode realizar {{$a}} tentativa(s)",
"averagescore": "Pontuação média",
@@ -16,7 +17,7 @@
"detailedstats": "Estatísticas detalhadas",
"didnotanswerquestion": "Não respondeu a esta pergunta",
"displayofgrade": "Exibição da nota (apenas para alunos)",
- "displayscorewithessays": "Obteve {{$a.score}} num máximo de {{$a.tempmaxgrade}}. As suas respostas à(s) pergunta(s) de desenvolvimento {{$a.essayquestions resposta(s)}} serão avaliadas posteriormente, sendo a pontuação correspondente adicionada à pontuação final.
A sua classificação atual, sem as perguntas que faltam avaliar, é de {{$a.score}} num máximo de {{$a.grade}}.",
+ "displayscorewithessays": "Obteve {{$a.score}} num máximo de {{$a.tempmaxgrade}}. As suas respostas à(s) pergunta(s) de desenvolvimento {{$a.essayquestions}} resposta(s) serão avaliadas posteriormente, sendo a pontuação correspondente adicionada à pontuação final.
A sua classificação atual, sem as perguntas que faltam avaliar, é de {{$a.score}} num máximo de {{$a.grade}}.",
"displayscorewithoutessays": "Obteve uma pontuação de {{$a.score}} (em {{$a.grade}}). Clique em Ver notas para ver a sua nota final na pauta",
"emptypassword": "A palava-chave não pode estar em branco",
"enterpassword": "Introduza a senha:",
@@ -66,11 +67,11 @@
"reviewquestioncontinue": "Não, quero avançar para a pergunta seguinte",
"secondpluswrong": "Resposta incorreta. Quer voltar a tentar?",
"submit": "Submeter",
- "teacherjumpwarning": "Nesta lição, há páginas que seguem para {{$a.cluster}} ou {{$a.unseen}}. Esta sequência será ignorada e a lição seguirá para a página seguinte. Para testar a sequência das páginas entre como aluno.",
+ "teacherjumpwarning": "Nesta lição, há páginas que seguem para {{$a.cluster}} ou para {{$a.unseen}}. Esta sequência será ignorada e a lição seguirá para a página seguinte. Para testar a sequência das páginas entre como aluno.",
"teacherongoingwarning": "A exibição da pontuação no decorrer da lição só é visível para os alunos. Para ver a pontuação no decorrer da lição entre como aluno.",
"teachertimerwarning": "O cronómetro só é visível para os alunos. Para testar esta funcionalidade, entre como aluno.",
"thatsthecorrectanswer": "A sua resposta está correta.",
- "thatsthewronganswer": "A sua resposta não está correta.",
+ "thatsthewronganswer": "A sua resposta não está correta.",
"timeremaining": "Tempo restante",
"timetaken": "Tempo usado",
"unseenpageinbranch": "Pergunta não vista da sequência",
diff --git a/www/addons/mod/lesson/lang/ro.json b/www/addons/mod/lesson/lang/ro.json
index e921358830b..b13962e5dd6 100644
--- a/www/addons/mod/lesson/lang/ro.json
+++ b/www/addons/mod/lesson/lang/ro.json
@@ -1,5 +1,6 @@
{
"answer": "Răspuns",
+ "attempt": "Încercarea cu numărul: {{$a}}",
"attemptheader": "Încercare",
"attemptsremaining": "Mai aveţi {{$a}} încercări disponibile",
"averagescore": "Punctaj mediu obţinut",
diff --git a/www/addons/mod/lesson/lang/ru.json b/www/addons/mod/lesson/lang/ru.json
index cdfe818e247..f8db842221a 100644
--- a/www/addons/mod/lesson/lang/ru.json
+++ b/www/addons/mod/lesson/lang/ru.json
@@ -1,5 +1,6 @@
{
"answer": "Ответ",
+ "attempt": "Попытка: {{$a}}",
"attemptheader": "Попытка",
"attemptsremaining": "У вас осталось {{$a}} попыток",
"averagescore": "Средний балл",
diff --git a/www/addons/mod/lesson/lang/sr-cr.json b/www/addons/mod/lesson/lang/sr-cr.json
new file mode 100644
index 00000000000..a09a8dc2437
--- /dev/null
+++ b/www/addons/mod/lesson/lang/sr-cr.json
@@ -0,0 +1,85 @@
+{
+ "answer": "Одговор",
+ "attempt": "Покушај: {{$a}}",
+ "attemptheader": "Покушај",
+ "attemptsremaining": "Број покушаја који вам је преостао: {{$a}}",
+ "averagescore": "Просечан број бодова",
+ "averagetime": "Просечно време",
+ "branchtable": "Садржај са гранањем",
+ "cannotfindattempt": "Грешка: није пронађен покушај",
+ "cannotfinduser": "Грешка: нису пронађени слогови у табели lesson_timer",
+ "clusterjump": "Још неприказано питање из групе питања",
+ "completed": "Завршено",
+ "congratulations": "Честитамо - стигли сте до краја лекције",
+ "continue": "Настави",
+ "continuetonextpage": "Идите на следећу страницу",
+ "defaultessayresponse": "Предавач ће оценити ваш есеј.",
+ "detailedstats": "Детаљна статистика",
+ "didnotanswerquestion": "Нисте одговорили на ово питање.",
+ "displayofgrade": "Приказ оцена (само за полазнике)",
+ "displayscorewithessays": "
Освојили сте {{$a.score}} од максималних {{$a.tempmaxgrade}} бодова за питања која се аутоматски оцењују.
\n
Ваш {{$a.essayquestions}} одговор на питања у форми есеја биће ускоро прегледан и оцењен, а оцена ће касније бити додата у ваш финални резултат.
\n
Ваша тренутна оцена без есеја је {{$a.score}} од {{$a.grade}}
",
+ "displayscorewithoutessays": "Ваш резултат је {{$a.score}} (од могућих {{$a.grade}}).",
+ "emptypassword": "Поље за лозинку не може бити празно",
+ "enterpassword": "Молимо унесите лозинку:",
+ "eolstudentoutoftimenoanswers": "Нисте одговорили ни на једно питање. Ваша оцена за ову лекцију је 0.",
+ "errorprefetchrandombranch": "Ова лекција садржи прелаз на наусимично одабрану страницу са садржајем, па је није могуће урадити у апликацији док се не покрене на веб сајту.",
+ "errorreviewretakenotlast": "Ова покушај не може више бити прегледан зато што је завршен други покушај.",
+ "finish": "Заврши",
+ "finishretakeoffline": "Овај покушај је завршен у офлајн режиму.",
+ "firstwrong": "Погрешно сте одговорили на питање. Да ли желите да покушате поново? (ако сада тачно одговорите на питање, то се неће рачунати у ваш коначан резултат.)",
+ "gotoendoflesson": "Иди на крај лекције",
+ "grade": "Оцена",
+ "highscore": "Најбољи резултат",
+ "hightime": "Најдуже време",
+ "leftduringtimed": "Напустили сте лекцију која је временски ограничена. Притисните тастер за наставак да бисте погледали лекцију од почетка.",
+ "leftduringtimednoretake": "Напустили сте лекцију која је временски ограничена и није Вам дозвољено да наставите или почнете лекцију из почетка.",
+ "lessonmenu": "Мени лекције",
+ "lessonstats": "Статистика лекције",
+ "linkedmedia": "Повезани медији",
+ "loginfail": "Погрешна пријава, молимо покушајте поново...",
+ "lowscore": "Наслабији резултат",
+ "lowtime": "Најкраће време",
+ "maximumnumberofattemptsreached": "Достигнут је максималан број покушаја - прелази се на следећу страницу",
+ "modattemptsnoteacher": "Полазнички преглед функционише само за полазнике.",
+ "noanswer": "На једно или више питања није дат одговор. Молимо вратите се назад и дајте свој одговор.",
+ "nolessonattempts": "Нико још није покушао да прође кроз ову лекцију.",
+ "nolessonattemptsgroup": "Није било покушаја за ову лекцију од стране чланова групе {{$a}}.",
+ "notcompleted": "Није завршено",
+ "numberofcorrectanswers": "Број тачних одговора: {{$a}}",
+ "numberofpagesviewed": "Број прегледаних страница: {{$a}}",
+ "numberofpagesviewednotice": "Број питања на које је дат одговор: {{$a.nquestions}} (Требало би их бити бар {{$a.minquestions}})",
+ "ongoingcustom": "До сада сте освојили {{$a.score}} од максимално {{$a.currenthigh}} бодова.",
+ "ongoingnormal": "Тачно сте одговорили на {{$a.correct}} од {{$a.viewed}} питања која сте видели.",
+ "or": "ИЛИ",
+ "overview": "Преглед",
+ "preview": "Преглед",
+ "progressbarteacherwarning2": "Нећете видети траку напредовања зато што можете да уређујете ову лекцију",
+ "progresscompleted": "Завршили сте {{$a}}% лекције",
+ "question": "Питање",
+ "rawgrade": "Необрађена оцена",
+ "reports": "Извештаји",
+ "response": "Повратне информације",
+ "retakefinishedinsync": "Офлајн покушај је синхронизован. Да ли желите да га прегледате?",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
+ "review": "Преглед",
+ "reviewlesson": "Преглед лекције",
+ "reviewquestionback": "Да, волео/ла бих да поново покушам",
+ "reviewquestioncontinue": "Не, желим да пређем на следеће питање",
+ "secondpluswrong": "Није баш. Да ли желите да покушате поново?",
+ "submit": "Пошаљи",
+ "teacherjumpwarning": "У овој лекцији се користе {{$a.cluster}} или {{$a.unseen}} прелаз између страница. Прелаз \"Следећа страница\" ће се користити уместо њих током овог приказа. За тестирање ових прелаза пријавите се на систем у улози полазника.",
+ "teacherongoingwarning": "Тренутни резултат током прегледа лекције се приказује само полазницима. Пријавите се на систем у улози полазника да бисте тестирали ову могућност.",
+ "teachertimerwarning": "Мерач времена могу да виде само полазници. Како бисте тестирали мерач времена пријавите се на систем у улози полазника.",
+ "thatsthecorrectanswer": "Тачан одговор",
+ "thatsthewronganswer": "Погрешан одговор",
+ "timeremaining": "Преостало време",
+ "timetaken": "Потрошено време",
+ "unseenpageinbranch": "Још неприказано питање унутар стране са садржајем и гранањем",
+ "warningretakefinished": "Покушај је завршен на веб сајту.",
+ "welldone": "Браво!",
+ "youhaveseen": "Већ сте видели више од једне странице ове лекције. Желите ли почети од последње странице коју сте видели?",
+ "youranswer": "Ваш одговор",
+ "yourcurrentgradeisoutof": "Ваша тренутна оцена је {{$a.grade}} од могућих {{$a.total}}",
+ "youshouldview": "Требало би да одговорите на барем: {{$a}}"
+}
\ No newline at end of file
diff --git a/www/addons/mod/lesson/lang/sr-lt.json b/www/addons/mod/lesson/lang/sr-lt.json
new file mode 100644
index 00000000000..a98cc2242e1
--- /dev/null
+++ b/www/addons/mod/lesson/lang/sr-lt.json
@@ -0,0 +1,85 @@
+{
+ "answer": "Odgovor",
+ "attempt": "Pokušaj: {{$a}}",
+ "attemptheader": "Pokušaj",
+ "attemptsremaining": "Broj pokušaja koji vam je preostao: {{$a}}",
+ "averagescore": "Prosečan broj bodova",
+ "averagetime": "Prosečno vreme",
+ "branchtable": "Sadržaj sa grananjem",
+ "cannotfindattempt": "Greška: nije pronađen pokušaj",
+ "cannotfinduser": "Greška: nisu pronađeni slogovi u tabeli lesson_timer",
+ "clusterjump": "Još neprikazano pitanje iz grupe pitanja",
+ "completed": "Završeno",
+ "congratulations": "Čestitamo - stigli ste do kraja lekcije",
+ "continue": "Nastavi",
+ "continuetonextpage": "Idite na sledeću stranicu",
+ "defaultessayresponse": "Predavač će oceniti vaš esej.",
+ "detailedstats": "Detaljna statistika",
+ "didnotanswerquestion": "Niste odgovorili na ovo pitanje.",
+ "displayofgrade": "Prikaz ocena (samo za polaznike)",
+ "displayscorewithessays": "
Osvojili ste {{$a.score}} od maksimalnih {{$a.tempmaxgrade}} bodova za pitanja koja se automatski ocenjuju.
\n
Vaš {{$a.essayquestions}} odgovor na pitanja u formi eseja biće uskoro pregledan i ocenjen, a ocena će kasnije biti dodata u vaš finalni rezultat.
\n
Vaša trenutna ocena bez eseja je {{$a.score}} od {{$a.grade}}
",
+ "displayscorewithoutessays": "Vaš rezultat je {{$a.score}} (od mogućih {{$a.grade}}).",
+ "emptypassword": "Polje za lozinku ne može biti prazno",
+ "enterpassword": "Molimo unesite lozinku:",
+ "eolstudentoutoftimenoanswers": "Niste odgovorili ni na jedno pitanje. Vaša ocena za ovu lekciju je 0.",
+ "errorprefetchrandombranch": "Ova lekcija sadrži prelaz na nausimično odabranu stranicu sa sadržajem, pa je nije moguće uraditi u aplikaciji dok se ne pokrene na veb sajtu.",
+ "errorreviewretakenotlast": "Ova pokušaj ne može više biti pregledan zato što je završen drugi pokušaj.",
+ "finish": "Završi",
+ "finishretakeoffline": "Ovaj pokušaj je završen u oflajn režimu.",
+ "firstwrong": "Pogrešno ste odgovorili na pitanje. Da li želite da pokušate ponovo? (ako sada tačno odgovorite na pitanje, to se neće računati u vaš konačan rezultat.)",
+ "gotoendoflesson": "Idi na kraj lekcije",
+ "grade": "Ocena",
+ "highscore": "Najbolji rezultat",
+ "hightime": "Najduže vreme",
+ "leftduringtimed": "Napustili ste lekciju koja je vremenski ograničena. Pritisnite taster za nastavak da biste pogledali lekciju od početka.",
+ "leftduringtimednoretake": "Napustili ste lekciju koja je vremenski ograničena i nije Vam dozvoljeno da nastavite ili počnete lekciju iz početka.",
+ "lessonmenu": "Meni lekcije",
+ "lessonstats": "Statistika lekcije",
+ "linkedmedia": "Povezani mediji",
+ "loginfail": "Pogrešna prijava, molimo pokušajte ponovo...",
+ "lowscore": "Naslabiji rezultat",
+ "lowtime": "Najkraće vreme",
+ "maximumnumberofattemptsreached": "Dostignut je maksimalan broj pokušaja - prelazi se na sledeću stranicu",
+ "modattemptsnoteacher": "Polaznički pregled funkcioniše samo za polaznike",
+ "noanswer": "Na jedno ili više pitanja nije dat odgovor. Molimo vratite se nazad i dajte svoj odgovor.",
+ "nolessonattempts": "Niko još nije pokušao da prođe kroz ovu lekciju.",
+ "nolessonattemptsgroup": "Nije bilo pokušaja za ovu lekciju od strane članova grupe {{$a}}.",
+ "notcompleted": "Nije završeno",
+ "numberofcorrectanswers": "Broj tačnih odgovora: {{$a}}",
+ "numberofpagesviewed": "Broj pregledanih stranica: {{$a}}",
+ "numberofpagesviewednotice": "Broj pitanja na koje je dat odgovor: {{$a.nquestions}} (Trebalo bi ih biti bar {{$a.minquestions}})",
+ "ongoingcustom": "Do sada ste osvojili {{$a.score}} od maksimalno {{$a.currenthigh}} bodova.",
+ "ongoingnormal": "Tačno ste odgovorili na {{$a.correct}} od {{$a.viewed}} pitanja koja ste videli.",
+ "or": "ILI",
+ "overview": "Pregled",
+ "preview": "Pregled",
+ "progressbarteacherwarning2": "Nećete videti traku napredovanja zato što možete da uređujete ovu lekciju",
+ "progresscompleted": "Završili ste {{$a}}% lekcije",
+ "question": "Pitanje",
+ "rawgrade": "Neobrađena ocena",
+ "reports": "Izveštaji",
+ "response": "Povratne informacije",
+ "retakefinishedinsync": "Oflajn pokušaj je sinhronizovan. Da li želite da ga pregledate?",
+ "retakelabelfull": "{{retake}}: {{grade}} {{timestart}} ({{duration}})",
+ "retakelabelshort": "{{retake}}: {{grade}} {{timestart}}",
+ "review": "Pregled",
+ "reviewlesson": "Pregled lekcije",
+ "reviewquestionback": "Da, voleo/la bih da ponovo pokušam",
+ "reviewquestioncontinue": "Ne, želim da pređem na sledeće pitanje",
+ "secondpluswrong": "Nije baš. Da li želite da pokušate ponovo?",
+ "submit": "Pošalji",
+ "teacherjumpwarning": "U ovoj lekciji se koriste {{$a.cluster}} ili {{$a.unseen}} prelaz između stranica. Prelaz \"Sledeća stranica\" će se koristiti umesto njih tokom ovog prikaza. Za testiranje ovih prelaza prijavite se na sistem u ulozi polaznika.",
+ "teacherongoingwarning": "Trenutni rezultat tokom pregleda lekcije se prikazuje samo polaznicima. Prijavite se na sistem u ulozi polaznika da biste testirali ovu mogućnost.",
+ "teachertimerwarning": "Merač vremena mogu da vide samo polaznici. Kako biste testirali merač vremena prijavite se na sistem u ulozi polaznika.",
+ "thatsthecorrectanswer": "Tačan odgovor",
+ "thatsthewronganswer": "Pogrešan odgovor",
+ "timeremaining": "Preostalo vreme",
+ "timetaken": "Potrošeno vreme",
+ "unseenpageinbranch": "Još neprikazano pitanje unutar strane sa sadržajem i grananjem",
+ "warningretakefinished": "Pokušaj je završen na veb sajtu.",
+ "welldone": "Bravo!",
+ "youhaveseen": "Već ste videli više od jedne stranice ove lekcije. Želite li početi od poslednje stranice koju ste videli?",
+ "youranswer": "Vaš odgovor",
+ "yourcurrentgradeisoutof": "Vaša trenutna ocena je {{$a.grade}} od mogućih {{$a.total}}",
+ "youshouldview": "Trebalo bi da odgovorite na barem: {{$a}}"
+}
\ No newline at end of file
diff --git a/www/addons/mod/lesson/lang/sv.json b/www/addons/mod/lesson/lang/sv.json
index fe0a53b2702..747a688c78b 100644
--- a/www/addons/mod/lesson/lang/sv.json
+++ b/www/addons/mod/lesson/lang/sv.json
@@ -1,5 +1,6 @@
{
"answer": "Svar",
+ "attempt": "Försök: {{$a}}",
"attemptsremaining": "Du har {{$a}} återstående försök",
"averagescore": "Genomsnittsligt resultat",
"averagetime": "Genomsnittslig tid",
diff --git a/www/addons/mod/lesson/lang/tr.json b/www/addons/mod/lesson/lang/tr.json
index 99d0bd338e2..7f50d81d9ea 100644
--- a/www/addons/mod/lesson/lang/tr.json
+++ b/www/addons/mod/lesson/lang/tr.json
@@ -1,5 +1,6 @@
{
"answer": "Cevap",
+ "attempt": "Uygulama: {{$a}}",
"attemptheader": "Deneme(Teşebbüs)",
"attemptsremaining": "{{$a}} uygulama hakkınız kaldı",
"averagescore": "Ortalama not",
diff --git a/www/addons/mod/lesson/lang/uk.json b/www/addons/mod/lesson/lang/uk.json
index e6a5762d90d..64f4e4e242a 100644
--- a/www/addons/mod/lesson/lang/uk.json
+++ b/www/addons/mod/lesson/lang/uk.json
@@ -1,5 +1,6 @@
{
"answer": "Відповідь",
+ "attempt": "Спроба: {{$a}}",
"attemptheader": "Спроба",
"attemptsremaining": "У Вас залишилося {{$a}} спроб(и)",
"averagescore": "Середній бал",
@@ -21,7 +22,7 @@
"emptypassword": "Пароль не може бути порожнім",
"enterpassword": "Будь ласка, введіть пароль:",
"eolstudentoutoftimenoanswers": "Ви не дали відповіді на жодне запитання. Ви отримуєте нуль за цей урок.",
- "errorreviewretakenotlast": "Ця спроба не може бути переглянута більше, тому що ще одна спроба була закінчена.",
+ "errorreviewretakenotlast": "Ця спроба не може бути переглянута, тому що ще одна спроба була закінчена.",
"finish": "Завершити",
"finishretakeoffline": "Ця спроба була закінчена в автономному режимі.",
"firstwrong": "На жаль, за неправильної відповіді Ви не можете отримати бал. Ви хочете продовжити вгадування в цілях навчання (але не в цілях отримання балів)?",
diff --git a/www/addons/mod/lesson/lang/zh-cn.json b/www/addons/mod/lesson/lang/zh-cn.json
index 3c06c89a713..1cb9bce4497 100644
--- a/www/addons/mod/lesson/lang/zh-cn.json
+++ b/www/addons/mod/lesson/lang/zh-cn.json
@@ -1,5 +1,6 @@
{
"answer": "答案",
+ "attempt": "尝试:{{$a}}",
"attemptsremaining": "您还有{{$a}}次机会",
"averagescore": "平均分",
"averagetime": "平均耗时",
diff --git a/www/addons/mod/lesson/lang/zh-tw.json b/www/addons/mod/lesson/lang/zh-tw.json
index 42b9529905a..bcbb5ed10a1 100644
--- a/www/addons/mod/lesson/lang/zh-tw.json
+++ b/www/addons/mod/lesson/lang/zh-tw.json
@@ -1,5 +1,6 @@
{
"answer": "答案",
+ "attempt": "作答:{{$a}}",
"attemptheader": "作答",
"attemptsremaining": "您還有{{$a}}次作答機會",
"averagescore": "平均分數",
@@ -35,7 +36,7 @@
"loginfail": "登入錯誤,請重試",
"lowscore": "最低分數",
"lowtime": "最短時間",
- "maximumnumberofattemptsreached": "達到嘗試次數上限 - 請進入下一頁",
+ "maximumnumberofattemptsreached": "已達到作答次的上限 - 將進入下一頁",
"modattemptsnoteacher": "學生回顧功能只開放給學生們。",
"noanswer": "有一個或以上的問題沒有回答。請回頭並提交一個答案。",
"nolessonattempts": "這個課程還沒有人嘗試。",
@@ -47,7 +48,7 @@
"ongoingcustom": "目前的{{$a.currenthigh}}分中,您已獲得{{$a.score}}分。",
"ongoingnormal": "到目前為止的{{$a.viewed}}問題中,您答對了{{$a.correct}}題。",
"or": "或",
- "overview": "概要",
+ "overview": "綜覽",
"preview": "預覽",
"progressbarteacherwarning2": "你不能看到這進度列,因為你可以編輯這一編序學習。",
"progresscompleted": "在這一編序學習,你已經完成{{$a}}%",
diff --git a/www/addons/mod/lesson/main.js b/www/addons/mod/lesson/main.js
index e786c188432..fae4bc2fefd 100644
--- a/www/addons/mod/lesson/main.js
+++ b/www/addons/mod/lesson/main.js
@@ -83,6 +83,7 @@ angular.module('mm.addons.mod_lesson', ['mm.core'])
$mmCoursePrefetchDelegateProvider.registerPrefetchHandler('mmaModLesson', 'lesson', '$mmaModLessonPrefetchHandler');
$mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:view', '$mmaModLessonHandlers.viewLinksHandler');
$mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:overview', '$mmaModLessonHandlers.overviewLinksHandler');
+ $mmContentLinksDelegateProvider.registerLinkHandler('mmaModLesson:grade', '$mmaModLessonHandlers.gradeLinksHandler');
})
.run(function($mmCronDelegate) {
diff --git a/www/addons/mod/lesson/services/handlers.js b/www/addons/mod/lesson/services/handlers.js
index f1308aa0422..61fb53e1c37 100644
--- a/www/addons/mod/lesson/services/handlers.js
+++ b/www/addons/mod/lesson/services/handlers.js
@@ -98,9 +98,10 @@ angular.module('mm.addons.mod_lesson')
$mmaModLessonPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModLessonPrefetchHandler.prefetch(module, courseId).catch(function(error) {
+ return $mmaModLessonPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
$mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
@@ -363,5 +364,60 @@ angular.module('mm.addons.mod_lesson')
});
}
+ /**
+ * Content links handler for lesson grade link.
+ *
+ * @module mm.addons.mod_lesson
+ * @ngdoc method
+ * @name $mmaModLessonHandlers#gradeLinksHandler
+ */
+ self.gradeLinksHandler = $mmContentLinksHelper.createModuleGradeLinkHandler('mmaModLesson', 'lesson', $mmaModLesson, viewGrade);
+
+ /**
+ * Treat a grade link to a user different than current one.
+ *
+ * @param {String} url URL to treat.
+ * @param {Object} params Params of the URL.
+ * @param {Number} [courseId] Course ID related to the URL.
+ * @param {String} siteId Site ID.
+ * @return {[type]} [description]
+ */
+ function viewGrade(url, params, courseId, siteId) {
+ siteId = siteId || $mmSite.getId();
+
+ var moduleId = parseInt(params.id, 10),
+ modal = $mmUtil.showModalLoading(),
+ module;
+
+ return $mmCourse.getModuleBasicInfo(moduleId, siteId).then(function(mod) {
+ module = mod;
+ courseId = module.course || courseId || params.courseid || params.cid;
+
+ // Check if the user can see the user reports in the lesson.
+ return $mmaModLesson.getAccessInformation(module.instance);
+ }).then(function(info) {
+ if (info.canviewreports) {
+ // User can view reports, go to view the report.
+ return $state.go('redirect', {
+ siteid: siteId,
+ state: 'site.mod_lesson-userretake',
+ params: {
+ courseid: courseId,
+ lessonid: module.instance,
+ userid: parseInt(params.userid, 10)
+ }
+ });
+ } else {
+ // User cannot view the report, go to lesson index.
+ return $mmCourseHelper.navigateToModule(moduleId, siteId, courseId, module.section);
+ }
+ }).catch(function(error) {
+ $mmUtil.showErrorModalDefault(error, 'mm.course.errorgetmodule', true);
+ return $q.reject();
+ }).finally(function() {
+ modal.dismiss();
+ });
+ }
+
return self;
});
diff --git a/www/addons/mod/lesson/services/helper.js b/www/addons/mod/lesson/services/helper.js
index 7999d10a59e..4cbe8b8c462 100644
--- a/www/addons/mod/lesson/services/helper.js
+++ b/www/addons/mod/lesson/services/helper.js
@@ -93,8 +93,7 @@ angular.module('mm.addons.mod_lesson')
var buttons = [],
rootElement = document.createElement('div'),
buttonsContainer,
- forms,
- isLegacy = false;
+ forms;
// Get the container of the buttons if it exists.
rootElement.innerHTML = html;
@@ -106,14 +105,12 @@ angular.module('mm.addons.mod_lesson')
// No buttons found.
return buttons;
}
- isLegacy = true;
buttonsContainer = rootElement;
}
forms = buttonsContainer.querySelectorAll('form');
angular.forEach(forms, function(form) {
- var buttonSelector = isLegacy ? 'input[type="submit"]' : 'button[type="submit"]',
- buttonEl = form.querySelector(buttonSelector),
+ var buttonEl = form.querySelector('input[type="submit"], button[type="submit"]'),
inputs = form.querySelectorAll('input'),
button;
@@ -125,7 +122,7 @@ angular.module('mm.addons.mod_lesson')
button = {
id: buttonEl.id,
title: buttonEl.title || buttonEl.value,
- content: isLegacy ? buttonEl.value : buttonEl.innerHTML.trim(),
+ content: buttonEl.tagName == 'INPUT' ? buttonEl.value : buttonEl.innerHTML.trim(),
data: {}
};
@@ -141,6 +138,31 @@ angular.module('mm.addons.mod_lesson')
return buttons;
};
+ /**
+ * Given a page data (result of getPageData), get the page contents.
+ *
+ * @module mm.addons.mod_lesson
+ * @ngdoc method
+ * @name $mmaModLessonHelper#getPageContentsFromPageData
+ * @param {Object} data Page data.
+ * @return {String} Page contents.
+ */
+ self.getPageContentsFromPageData = function(data) {
+ var contents,
+ rootElement = document.createElement('div');
+
+ // Search the page contents inside the whole page HTML. Use data.pagecontent because it's filtered.
+ rootElement.innerHTML = data.pagecontent;
+ contents = rootElement.querySelector('.contents');
+
+ if (contents) {
+ return contents.innerHTML.trim();
+ }
+
+ // Cannot find contents element, return the page.contents (some elements like videos might not work).
+ return data.page.contents;
+ };
+
/**
* Given the HTML of an answer from a question page, extract the data to render the answer.
*
diff --git a/www/addons/mod/lti/lang/ja.json b/www/addons/mod/lti/lang/ja.json
new file mode 100644
index 00000000000..b3e5bba2e60
--- /dev/null
+++ b/www/addons/mod/lti/lang/ja.json
@@ -0,0 +1,5 @@
+{
+ "errorgetlti": "モジュールデータ取得中にエラーが発生しました。",
+ "errorinvalidlaunchurl": "起動するURLが不正です。",
+ "launchactivity": "アクティビティを起動"
+}
\ No newline at end of file
diff --git a/www/addons/mod/lti/lang/sr-cr.json b/www/addons/mod/lti/lang/sr-cr.json
new file mode 100644
index 00000000000..6f616981561
--- /dev/null
+++ b/www/addons/mod/lti/lang/sr-cr.json
@@ -0,0 +1,5 @@
+{
+ "errorgetlti": "Грешка приликом преузимања података модула.",
+ "errorinvalidlaunchurl": "Иницијална URL адреса није исправна.",
+ "launchactivity": "Покрени активност"
+}
\ No newline at end of file
diff --git a/www/addons/mod/lti/lang/sr-lt.json b/www/addons/mod/lti/lang/sr-lt.json
new file mode 100644
index 00000000000..0feaaf89a14
--- /dev/null
+++ b/www/addons/mod/lti/lang/sr-lt.json
@@ -0,0 +1,5 @@
+{
+ "errorgetlti": "Greška prilikom preuzimanja podataka modula.",
+ "errorinvalidlaunchurl": "Inicijalna URL adresa nije ispravna.",
+ "launchactivity": "Pokreni aktivnost"
+}
\ No newline at end of file
diff --git a/www/addons/mod/lti/lang/uk.json b/www/addons/mod/lti/lang/uk.json
index cc542981fd4..8569afbe6c1 100644
--- a/www/addons/mod/lti/lang/uk.json
+++ b/www/addons/mod/lti/lang/uk.json
@@ -1,5 +1,5 @@
{
"errorgetlti": "Помилка при отриманні даних модуля.",
- "errorinvalidlaunchurl": "Запуск URL не є дійсним.",
+ "errorinvalidlaunchurl": "Цей URL не є дійсним.",
"launchactivity": "Запуск діяльності"
}
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/es_mx.json b/www/addons/mod/page/lang/es_mx.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/page/lang/es_mx.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/ja.json b/www/addons/mod/page/lang/ja.json
index 0637a088a01..4084af15212 100644
--- a/www/addons/mod/page/lang/ja.json
+++ b/www/addons/mod/page/lang/ja.json
@@ -1 +1,3 @@
-[]
\ No newline at end of file
+{
+ "errorwhileloadingthepage": "ページ内容を読み込み中にエラーが発生しました。"
+}
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/pt_br.json b/www/addons/mod/page/lang/pt_br.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/page/lang/pt_br.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/sr-cr.json b/www/addons/mod/page/lang/sr-cr.json
new file mode 100644
index 00000000000..bb2b30f0d8b
--- /dev/null
+++ b/www/addons/mod/page/lang/sr-cr.json
@@ -0,0 +1,3 @@
+{
+ "errorwhileloadingthepage": "Грешка приликом учитавања садржаја странице."
+}
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/sr-lt.json b/www/addons/mod/page/lang/sr-lt.json
new file mode 100644
index 00000000000..683b241e992
--- /dev/null
+++ b/www/addons/mod/page/lang/sr-lt.json
@@ -0,0 +1,3 @@
+{
+ "errorwhileloadingthepage": "Greška prilikom učitavanja sadržaja stranice."
+}
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/zh_cn.json b/www/addons/mod/page/lang/zh_cn.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/page/lang/zh_cn.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/page/lang/zh_tw.json b/www/addons/mod/page/lang/zh_tw.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/page/lang/zh_tw.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/quiz/lang/ja.json b/www/addons/mod/quiz/lang/ja.json
index f7b4d3d133f..62382e648d4 100644
--- a/www/addons/mod/quiz/lang/ja.json
+++ b/www/addons/mod/quiz/lang/ja.json
@@ -4,32 +4,49 @@
"attemptnumber": "受験",
"attemptquiznow": "問題を受験する",
"attemptstate": "状態",
+ "cannotsubmitquizdueto": "このクイズの回答は、以下の理由で提出できませんでした:",
"comment": "コメント",
"completedon": "完了日時",
- "confirmclose": "送信した場合、この受験に関して、これ以上あなたの答えを変更することはできません。",
+ "confirmclose": "送信した場合、あなたはこれ以上受験の答えを変更できないようになります。",
+ "confirmcontinueoffline": "この回答は、理由「 {{$a}} 」により、同期できませんでした。もしあなたが別のデバイスで回答を続けていた場合、データが失われている可能性があります。",
+ "confirmleavequizonerror": "回答の保存中にエラーが発生しました。クイズを終了してもよいですか?",
"confirmstart": "この小テストには {{$a}} の時間制限があります。あなたが受験を開始した時点から時間が計測されます。あなたは有効期限前に送信する必要があります。今から開始してもよろしいですか?",
"confirmstartheader": "時間制限小テスト",
- "connectionerror": "ネットワークコネクションが切断されました (オートセーブ失敗)。\n\nこのページで入力した最後の数分間の解答をメモした後、再接続を試みてください。\n\n接続が再確立された場合、あなたの解答は保存され、このメッセージは表示されなくなります。",
+ "connectionerror": "ネットワークコネクションが切断されました (オートセーブ失敗)。\n\nこのページで入力した最後の数分間の解答をメモした後、再接続を試みてください。\n\n再度接続が確立された場合、あなたの解答は保存されこのメッセージは表示されなくなります。",
"continueattemptquiz": "前回の受験を続ける",
- "continuepreview": "前回受験のプレビューを続ける",
+ "continuepreview": "前回のプレビューを続ける",
+ "errorbehaviournotsupported": "このクイズは、アプリでサポートされていない動作が含まれているため回答することができません。",
+ "errordownloading": "必要なデータのダウンロード中にエラーが発生しました。",
+ "errorgetattempt": "回答データの取得中にエラーが発生しました。",
+ "errorgetquestions": "質問の取得中にエラーが発生しました。",
+ "errorgetquiz": "クイズデータの取得中にエラーが発生しました。",
+ "errorparsequestions": "質問の読み込み中にエラーが発生しました。Webブラウザからこのクイズに回答してください。",
+ "errorquestionsnotsupported": "このクイズは、アプリでサポートされていない質問を含む可能性があるため回答することができません。",
+ "errorrulesnotsupported": "このクイズは、アプリでサポートされていないアクセスルールがあるため回答することができません。",
+ "errorsaveattempt": "回答データの保存中にエラーが発生しました。",
+ "errorsyncquiz": "同期中にエラーが発生しました。再度同期してください。",
+ "errorsyncquizblocked": "このクイズは、進行中のプロセスがあるためすぐには同期できません。後で再び同期してください。この問題が連続する場合、アプリを再起動してみてください。",
"feedback": "フィードバック",
"finishattemptdots": "受験を終了する ...",
+ "finishnotsynced": "完了しましたが同期されていません。",
"grade": "評点",
"gradeaverage": "平均評点",
"gradehighest": "最高評点",
"grademethod": "評定方法",
"gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}",
+ "hasdatatosync": "このクイズには同期が必要なオフラインデータがあります。",
"marks": "得点",
"mustbesubmittedby": "この受験は {{$a}} までに送信される必要があります。",
"noquestions": "まだ問題が追加されていません。",
"noreviewattempt": "あなたはこの受験のレビューを許可されていません。",
"notyetgraded": "未評定",
+ "opentoc": "ナビゲーションポップオーバーを開いてください。",
"outof": "{{$a.grade}} / {{$a.maxgrade}}",
"outofpercent": "{{$a.grade}} / {{$a.maxgrade}} ({{$a.percent}}%)",
"outofshort": "{{$a.grade}} / {{$a.maxgrade}}",
"overallfeedback": "全体のフィードバック",
"overdue": "期限切れ",
- "overduemustbesubmittedby": "この受験は制限時間を過ぎています。そして、すでに送信されている必要があります。あなたがこの小テストの評定を希望する場合、{{$a}} までに送信してください。それまでに送信しない場合、この受験の評点はカウントされません。",
+ "overduemustbesubmittedby": "この受験は制限時間を過ぎています。この受験はすでに送信されている必要があります。あなたがこの小テストの評定を希望する場合、{{$a}} までに送信してください。それまでに送信しない場合、この受験の評点はカウントされません。",
"preview": "プレビュー",
"previewquiznow": "小テストをプレビューする",
"question": "問題",
@@ -56,5 +73,8 @@
"summaryofattempts": "あなたの前回の受験概要",
"timeleft": "残り時間",
"timetaken": "所要時間",
+ "warningattemptfinished": "オフラインの回答は、サイト上で完了していた、もしくは見当たらなかったため廃棄されました。",
+ "warningdatadiscarded": "質問文がオンラインで変更されたため、一部のオフライン回答が廃棄されました。",
+ "warningdatadiscardedfromfinished": "オフライン回答が廃棄されたため、回答が完了していません。回答内容を確認し、回答を再度提出してください。",
"yourfinalgradeis": "あなたの小テスト最終評点は {{$a}} です。"
}
\ No newline at end of file
diff --git a/www/addons/mod/quiz/lang/lt.json b/www/addons/mod/quiz/lang/lt.json
index 3d18000f600..0e24a274c6e 100644
--- a/www/addons/mod/quiz/lang/lt.json
+++ b/www/addons/mod/quiz/lang/lt.json
@@ -46,6 +46,7 @@
"outofshort": "{{$a.grade}}/{{$a.maxgrade}}",
"overallfeedback": "Bendras atsiliepimas",
"overdue": "Uždelstas",
+ "overduemustbesubmittedby": "Šis bandymas jau pavėluotas. Jis jau turėjo būti pateiktas. Jei norite, kad šis testas būtų įvertintas, turite jį patvirtinti {{$a}}. Jei nepateiksite, tada balas šiam bandymui nebus skaičiuojamas.",
"preview": "Peržiūra",
"previewquiznow": "Peržiūrėti testą dabar",
"question": "Klausimas",
diff --git a/www/addons/mod/quiz/lang/sr-cr.json b/www/addons/mod/quiz/lang/sr-cr.json
new file mode 100644
index 00000000000..41be728b1ad
--- /dev/null
+++ b/www/addons/mod/quiz/lang/sr-cr.json
@@ -0,0 +1,80 @@
+{
+ "attemptfirst": "Први покушај",
+ "attemptlast": "Последњи покушај",
+ "attemptnumber": "Покушај",
+ "attemptquiznow": "Започни тест",
+ "attemptstate": "Стање",
+ "cannotsubmitquizdueto": "Овај покушај решавања теста не може да буде предат због следећих разлога:",
+ "comment": "Коментар",
+ "completedon": "Завршено дана",
+ "confirmclose": "Када предате тест нећете више бити у могућности да мењате своје одговоре.",
+ "confirmcontinueoffline": "Овај покушај није синхронизован од {{$a}}. Ако сте у међувремену овај покушај наставили на неком другом уређају, постоји могућност да сте изгубили податке.",
+ "confirmleavequizonerror": "Дошло је до грешке приликом покушаја да се сачувају одговори. Да ли сте сигурни да желите да напустите тест?",
+ "confirmstart": "Тест има временско ограничење ({{$a}}). Време ће се одбројавати од момента почетка покушаја и морате предати своје одговоре пре него што истекне. Да ли сте сигурни да сада желите да започнете решавање теста?",
+ "confirmstartheader": "Временски ограничен тест",
+ "connectionerror": "Мрежна веза је изгубљена. (Аутоматско чување није успело).\n\nЗапишите све одговора унетих на овој страници у последњих неколико минута, а затим покушајте поново да се повежете.\n\nКада се веза поново успостави ваши одговори би требало да буду сачувани а ова порука ће нестати.",
+ "continueattemptquiz": "Наставите последњи покушај",
+ "continuepreview": "Настави последњи преглед",
+ "errorbehaviournotsupported": "Овај тест не можете решавати у апликацији зато што она не подржава понашање питања:",
+ "errordownloading": "Грешка приликом преузимања неопходних података.",
+ "errorgetattempt": "Грешка приликом преузимања података о покушају решавања теста.",
+ "errorgetquestions": "Грешка приликом преузимања питања.",
+ "errorgetquiz": "Грешка приликом преузимања података о тесту.",
+ "errorparsequestions": "Дошло је до грешке приликом учитавања питања. Молимо, покушајте да решите овај тест у веб читачу.",
+ "errorquestionsnotsupported": "Овај тест се не може решавати у апликацији зато што садржи питања које апликација не подржава:",
+ "errorrulesnotsupported": "Овај тест се не може решавати у апликацији зато што садржи правила за приступ које апликација не подржава:",
+ "errorsaveattempt": "Дошло је до грешке приликом снимања података о покушају решавања теста.",
+ "errorsyncquiz": "Дошло је до грешке приликом синхронизације. Молимо, покушајте поново.",
+ "errorsyncquizblocked": "Овај тест сада не може бити синхронизован због другог процеса који је тренутно у току. Молимо, покушајте поново касније. Ако и даље будете имали проблема, покушајте да покренете апликацију испочетка.",
+ "feedback": "Повратне информације",
+ "finishattemptdots": "Заврши покушај...",
+ "finishnotsynced": "Тест је завршен, али није синхронизован",
+ "grade": "Оцена",
+ "gradeaverage": "Просечна оцена",
+ "gradehighest": "Највиша оцена",
+ "grademethod": "Метод оцењивања",
+ "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.",
+ "hasdatatosync": "Овај тест има офлајн податке које треба синхронизовати.",
+ "marks": "Оцене",
+ "mustbesubmittedby": "Овај покушај мора бити предат до {{$a}}.",
+ "noquestions": "Ниједно питање још није додато",
+ "noreviewattempt": "Није Вам дозвољено да прегледате овај покушај",
+ "notyetgraded": "Још није оцењено",
+ "opentoc": "Отвори навигациони мени.",
+ "outof": "{{$a.grade}} од {{$a.maxgrade}}",
+ "outofpercent": "{{$a.grade}} од {{$a.maxgrade}}",
+ "outofshort": "{{$a.grade}}/{{$a.maxgrade}}",
+ "overallfeedback": "Свеобухватне повратне информације",
+ "overdue": "Закаснели",
+ "overduemustbesubmittedby": "Време за овај покушај решавање теста је истекло. Покушај је већ требало предати. Ако желите да овај тест буде оцењен морате га предати до {{$a}}. Ако то не урадите до наведеног рока, оцене за овај покушај се неће рачунати.",
+ "preview": "Преглед",
+ "previewquiznow": "Прегледај тест сада",
+ "question": "Питање",
+ "quizpassword": "Лозинка теста",
+ "reattemptquiz": "Поновни покушај решавања теста",
+ "requirepasswordmessage": "Да бисте приступили решавању овог теста морате знати лозинку теста",
+ "returnattempt": "Повратак на покушај",
+ "review": "Преглед",
+ "reviewofattempt": "Преглед покушаја {{$a}}",
+ "reviewofpreview": "Преглед приказа",
+ "showall": "Прикажи сва питања на једној страници",
+ "showeachpage": "Прикажи једну по једну страницу",
+ "startattempt": "Започни покушај решавања",
+ "startedon": "Започето",
+ "stateabandoned": "Никад предато",
+ "statefinished": "Завршено",
+ "statefinisheddetails": "Предато {{$a}}",
+ "stateinprogress": "У току",
+ "stateoverdue": "Закаснела предаја",
+ "stateoverduedetails": "Мора се предати до {{$a}}",
+ "status": "Статус",
+ "submitallandfinish": "Предај све одговоре и заврши тест",
+ "summaryofattempt": "Резиме покушаја",
+ "summaryofattempts": "Резиме ваших претходних покушаја",
+ "timeleft": "Преостало време",
+ "timetaken": "Утрошено време",
+ "warningattemptfinished": "Офлајн покушај је одбачен зато што је или завршен на сајту или није пронађен.",
+ "warningdatadiscarded": "Неки офлајн одговори су одбачени зато што су питања измењена онлајн.",
+ "warningdatadiscardedfromfinished": "Покушај решавања теста је није завршен зато што су неки офлајн одговори одбачени. Прегледајте своје одговоре, а затим поново пошаљите свој покушај.",
+ "yourfinalgradeis": "Ваша коначна оцена на овом тесту је {{$a}}."
+}
\ No newline at end of file
diff --git a/www/addons/mod/quiz/lang/sr-lt.json b/www/addons/mod/quiz/lang/sr-lt.json
new file mode 100644
index 00000000000..0bff65e68b6
--- /dev/null
+++ b/www/addons/mod/quiz/lang/sr-lt.json
@@ -0,0 +1,80 @@
+{
+ "attemptfirst": "Prvi pokušaj",
+ "attemptlast": "Poslednji pokušaj",
+ "attemptnumber": "Pokušaj",
+ "attemptquiznow": "Započni test",
+ "attemptstate": "Stanje",
+ "cannotsubmitquizdueto": "Ovaj pokušaj rešavanja testa ne može da bude predat zbog sledećih razloga:",
+ "comment": "Komentar",
+ "completedon": "Završeno dana",
+ "confirmclose": "Kada predate test nećete više biti u mogućnosti da menjate svoje odgovore.",
+ "confirmcontinueoffline": "Ovaj pokušaj nije sinhronizovan od {{$a}}. Ako ste u međuvremenu ovaj pokušaj nastavili na nekom drugom uređaju, postoji mogućnost da ste izgubili podatke.",
+ "confirmleavequizonerror": "Došlo je do greške prilikom pokušaja da se sačuvaju odgovori. Da li ste sigurni da želite da napustite test?",
+ "confirmstart": "Test ima vremensko ograničenje ({{$a}}). Vreme će se odbrojavati od momenta početka pokušaja i morate predati svoje odgovore pre nego što istekne. Da li ste sigurni da sada želite da započnete rešavanje testa?",
+ "confirmstartheader": "Vremenski ograničen test",
+ "connectionerror": "Mrežna veza je izgubljena. (Automatsko čuvanje nije uspelo).\n\nZapišite sve odgovora unetih na ovoj stranici u poslednjih nekoliko minuta, a zatim pokušajte ponovo da se povežete.\n\nKada se veza ponovo uspostavi vaši odgovori bi trebalo da budu sačuvani a ova poruka će nestati.",
+ "continueattemptquiz": "Nastavite poslednji pokušaj",
+ "continuepreview": "Nastavi poslednji pregled",
+ "errorbehaviournotsupported": "Ovaj test ne možete rešavati u aplikaciji zato što ona ne podržava ponašanje pitanja:",
+ "errordownloading": "Greška prilikom preuzimanja neophodnih podataka.",
+ "errorgetattempt": "Greška prilikom preuzimanja podataka o pokušaju rešavanja testa.",
+ "errorgetquestions": "Greška prilikom preuzimanja pitanja.",
+ "errorgetquiz": "Greška prilikom preuzimanja podataka o testu.",
+ "errorparsequestions": "Došlo je do greške prilikom učitavanja pitanja. Molimo, pokušajte da rešite ovaj test u veb čitaču.",
+ "errorquestionsnotsupported": "Ovaj test se ne može rešavati u aplikaciji zato što sadrži pitanja koje aplikacija ne podržava:",
+ "errorrulesnotsupported": "Ovaj test se ne može rešavati u aplikaciji zato što sadrži pravila za pristup koje aplikacija ne podržava:",
+ "errorsaveattempt": "Došlo je do greške prilikom snimanja podataka o pokušaju rešavanja testa.",
+ "errorsyncquiz": "Došlo je do greške prilikom sinhronizacije. Molimo, pokušajte ponovo.",
+ "errorsyncquizblocked": "Ovaj test sada ne može biti sinhronizovan zbog drugog procesa koji je trenutno u toku. Molimo, pokušajte ponovo kasnije. Ako i dalje budete imali problema, pokušajte da pokrenete aplikaciju ispočetka.",
+ "feedback": "Povratne informacije",
+ "finishattemptdots": "Završi pokušaj...",
+ "finishnotsynced": "Test je završen, ali nije sinhronizovan",
+ "grade": "Ocena",
+ "gradeaverage": "Prosečna ocena",
+ "gradehighest": "Najviša ocena",
+ "grademethod": "Metod ocenjivanja",
+ "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.",
+ "hasdatatosync": "Ovaj test ima oflajn podatke koje treba sinhronizovati.",
+ "marks": "Ocene",
+ "mustbesubmittedby": "Ovaj pokušaj mora biti predat do {{$a}}.",
+ "noquestions": "Nijedno pitanje još nije dodato",
+ "noreviewattempt": "Nije Vam dozvoljeno da pregledate ovaj pokušaj",
+ "notyetgraded": "Još nije ocenjeno",
+ "opentoc": "Otvori navigacioni meni.",
+ "outof": "{{$a.grade}} od {{$a.maxgrade}}",
+ "outofpercent": "{{$a.grade}} od {{$a.maxgrade}}",
+ "outofshort": "{{$a.grade}}/{{$a.maxgrade}}",
+ "overallfeedback": "Sveobuhvatne povratne informacije",
+ "overdue": "Zakasneli",
+ "overduemustbesubmittedby": "Vreme za ovaj pokušaj rešavanje testa je isteklo. Pokušaj je već trebalo predati. Ako želite da ovaj test bude ocenjen morate ga predati do {{$a}}. Ako to ne uradite do navedenog roka, ocene za ovaj pokušaj se neće računati.",
+ "preview": "Pregled",
+ "previewquiznow": "Pregledaj test sada",
+ "question": "Pitanje",
+ "quizpassword": "Lozinka testa",
+ "reattemptquiz": "Ponovni pokušaj rešavanja testa",
+ "requirepasswordmessage": "Da biste pristupili rešavanju ovog testa morate znati lozinku testa",
+ "returnattempt": "Povratak na pokušaj",
+ "review": "Pregled",
+ "reviewofattempt": "Pregled pokušaja {{$a}}",
+ "reviewofpreview": "Pregled prikaza",
+ "showall": "Prikaži sva pitanja na jednoj stranici",
+ "showeachpage": "Prikaži jednu po jednu stranicu",
+ "startattempt": "Započni pokušaj rešavanja",
+ "startedon": "Započeto",
+ "stateabandoned": "Nikad predato",
+ "statefinished": "Završeno",
+ "statefinisheddetails": "Predato {{$a}}",
+ "stateinprogress": "U toku",
+ "stateoverdue": "Zakasnela predaja",
+ "stateoverduedetails": "Mora se predati do {{$a}}",
+ "status": "Status",
+ "submitallandfinish": "Predaj sve odgovore i završi test",
+ "summaryofattempt": "Rezime pokušaja",
+ "summaryofattempts": "Rezime vaših prethodnih pokušaja",
+ "timeleft": "Preostalo vreme",
+ "timetaken": "Utrošeno vreme",
+ "warningattemptfinished": "Oflajn pokušaj je odbačen zato što je ili završen na sajtu ili nije pronađen.",
+ "warningdatadiscarded": "Neki oflajn odgovori su odbačeni zato što su pitanja izmenjena onlajn.",
+ "warningdatadiscardedfromfinished": "Pokušaj rešavanja testa je nije završen zato što su neki oflajn odgovori odbačeni. Pregledajte svoje odgovore, a zatim ponovo pošaljite svoj pokušaj.",
+ "yourfinalgradeis": "Vaša konačna ocena na ovom testu je {{$a}}."
+}
\ No newline at end of file
diff --git a/www/addons/mod/quiz/lang/sv.json b/www/addons/mod/quiz/lang/sv.json
index cb771aab8be..f330a8a5999 100644
--- a/www/addons/mod/quiz/lang/sv.json
+++ b/www/addons/mod/quiz/lang/sv.json
@@ -6,7 +6,7 @@
"attemptstate": "Tillstånd",
"comment": "Kommentar",
"completedon": "Fullgjord den",
- "confirmclose": "Du håller på att avsluta det här försöket. När Du väl har avslutat försöket kommer Du inte längre att kunna ändra Dina svar.",
+ "confirmclose": "dDu håller på att avsluta det här försöket. När du väl har avslutat försöket kommer du inte längre att kunna ändra dina svar.",
"connectionerror": "Nätverksanslutning förlorade (autospara misslyckades).\n\nAnteckna alla svar som angavs på webbplatsen de sista minuterna på papper, försöka sedan att återansluta.\n\nNär anslutningen har återupprättats, bör dina svar sparas och detta meddelande kommer att försvinna.",
"continueattemptquiz": "Fortsätt med det senaste försöket",
"continuepreview": "Fortsätt med den senaste förhandsgranskningen",
diff --git a/www/addons/mod/quiz/lang/uk.json b/www/addons/mod/quiz/lang/uk.json
index 3c6c7b28f67..33bfc0688f7 100644
--- a/www/addons/mod/quiz/lang/uk.json
+++ b/www/addons/mod/quiz/lang/uk.json
@@ -8,24 +8,24 @@
"comment": "Коментар",
"completedon": "Завершено",
"confirmclose": "Ви вибрали закінчення тесту (даної спроби). Якщо ви це підтверджуєте, Ви більше не зможете змінювати ваші відповіді.",
- "confirmcontinueoffline": "Ця спроба не була синхронізована, {{$a}}. Якщо ви продовжили цю спробу в іншому пристрої з тих пір, ви можете втратити дані.",
+ "confirmcontinueoffline": "Ця спроба не була синхронізована, {{$a}}. Якщо ви продовжили цю спробу на іншому пристрої, ви можете втратити дані.",
"confirmleavequizonerror": "При збереженні відповідей сталася помилка. Ви впевнені, що хочете залишити тест?",
"confirmstart": "Цей тест має обмеження в часі {{$a}}. Час почне відраховуватися з моменту, коли ви починаєте вашу спробу, і ви повинні будете закінчити вашу спробу допоки не спливе термін. Ви впевнені, що хочете почати зараз?",
"confirmstartheader": "Тест з обмеженням в часі",
"connectionerror": "Мережеве підключення втрачено. (Автозбереження не вдалося).\n\nЗапишіть відповіді введені на цій сторінці за останні кілька хвилин, потім спробуйте знову підключити.\n\nПісля того, як з'єднання буде відновлено, ваші відповіді мають бути збережені і це повідомлення зникне.",
"continueattemptquiz": "Продовжити останню спробу",
"continuepreview": "Продовжити останній перегляд",
- "errorbehaviournotsupported": "Цей тест не може бути зроблений в додатку, тому що поведінка не підтримуються додатком:",
+ "errorbehaviournotsupported": "Цей тест не може бути зроблений в додатку, тому що не підтримується додатком:",
"errordownloading": "Помилка при завантаженні потрібних даних.",
"errorgetattempt": "Помилка при отриманні даних спроби.",
"errorgetquestions": "Помилка отримання питань.",
"errorgetquiz": "Помилка при отриманні даних тесту.",
- "errorparsequestions": "Сталася помилка під час читання питання. Будь ласка, спроба цей тест в веб-браузері.",
+ "errorparsequestions": "Сталася помилка під час читання питання. Будь ласка, спробуйте цей тест в веб-браузері.",
"errorquestionsnotsupported": "Цей тест не може бути вирішених в додатку, оскільки він може містити питання, які не підтримуються додатком:",
- "errorrulesnotsupported": "Цей тест не може бути зроблений в додатку, оскільки він має правило доступу, що не підтримується додатком:",
+ "errorrulesnotsupported": "Цей тест не може бути зроблений в додатку, оскільки він має правила доступу, що не підтримується додатком:",
"errorsaveattempt": "При збереженні даних спроби сталася помилка.",
"errorsyncquiz": "Під час синхронізації сталася помилка. Будь ласка спробуйте ще раз.",
- "errorsyncquizblocked": "Цей тест не може бути синхронізований прямо зараз через триваючий процес. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.",
+ "errorsyncquizblocked": "Цей тест не може бути синхронізований прямо зараз через навантаження на сервер. Будь-ласка спробуйте пізніше. Якщо питання залишається невирішеним, спробуйте перезапустити програму.",
"feedback": "Відгук",
"finishattemptdots": "Завершити спробу...",
"finishnotsynced": "Готово, але не синхронізовано",
diff --git a/www/addons/mod/resource/lang/es_mx.json b/www/addons/mod/resource/lang/es_mx.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/resource/lang/es_mx.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/ja.json b/www/addons/mod/resource/lang/ja.json
index 0637a088a01..8a0d7d9a02d 100644
--- a/www/addons/mod/resource/lang/ja.json
+++ b/www/addons/mod/resource/lang/ja.json
@@ -1 +1,4 @@
-[]
\ No newline at end of file
+{
+ "errorwhileloadingthecontent": "内容を読み込み中にエラーが発生しました。",
+ "openthefile": "ファイルを開く"
+}
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/pt_br.json b/www/addons/mod/resource/lang/pt_br.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/resource/lang/pt_br.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/sr-cr.json b/www/addons/mod/resource/lang/sr-cr.json
new file mode 100644
index 00000000000..260ac7e4935
--- /dev/null
+++ b/www/addons/mod/resource/lang/sr-cr.json
@@ -0,0 +1,4 @@
+{
+ "errorwhileloadingthecontent": "Грешка приликом учитавања садржаја.",
+ "openthefile": "Отвори датотеку"
+}
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/sr-lt.json b/www/addons/mod/resource/lang/sr-lt.json
new file mode 100644
index 00000000000..8120d454e8a
--- /dev/null
+++ b/www/addons/mod/resource/lang/sr-lt.json
@@ -0,0 +1,4 @@
+{
+ "errorwhileloadingthecontent": "Greška prilikom učitavanja sadržaja.",
+ "openthefile": "Otvori datoteku"
+}
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/zh_cn.json b/www/addons/mod/resource/lang/zh_cn.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/resource/lang/zh_cn.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/resource/lang/zh_tw.json b/www/addons/mod/resource/lang/zh_tw.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/resource/lang/zh_tw.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/scorm/controllers/index.js b/www/addons/mod/scorm/controllers/index.js
index f73a74bf913..e4073952ac5 100644
--- a/www/addons/mod/scorm/controllers/index.js
+++ b/www/addons/mod/scorm/controllers/index.js
@@ -323,6 +323,7 @@ angular.module('mm.addons.mod_scorm')
}
} else if (progress.message) { // Show a message.
$scope.progressMessage = progress.message;
+ $scope.percentage = undefined;
} else if (progress.loaded && progress.total) { // Unzipping package.
$scope.percentage = (parseFloat(progress.loaded / progress.total) * 100).toFixed(1);
} else {
@@ -418,9 +419,9 @@ angular.module('mm.addons.mod_scorm')
if (!$scope.$$destroyed) {
openScorm(scoId);
}
- }).catch(function() {
+ }).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmaModScormHelper.showDownloadError(scorm);
+ $mmaModScormHelper.showDownloadError(scorm, error);
}
});
});
diff --git a/www/addons/mod/scorm/lang/el.json b/www/addons/mod/scorm/lang/el.json
index a819301fbee..e5fbfbe4a46 100644
--- a/www/addons/mod/scorm/lang/el.json
+++ b/www/addons/mod/scorm/lang/el.json
@@ -46,5 +46,6 @@
"scormstatusnotdownloaded": "Αυτό το SCORM δεν έχει κατέβει. Θα κατέβει αυτόματα όταν το ανοίξετε.",
"scormstatusoutdated": "Αυτό το SCORM έχει τροποποιηθεί από την τελευταία λήψη. Θα κατέβει αυτόματα όταν το ανοίξετε.",
"suspended": "Αναστέλλεται",
+ "warningofflinedatadeleted": "Ορισμένα δεδομένα εκτός σύνδεσης της προσπάθειας {{number}} διαγράφηκαν επειδή δεν ήταν δυνατή η δημιουργία νέας προσπάθειας.",
"warningsynconlineincomplete": "Κάποιες προσπάθειες δεν μπόρεσαν να συγχρονιστούν με το site διότι η τελευταία online προσπάθεια δεν έχει ολοκληρωθεί. Παρακαλώ τελειώστε την online προσπάθεια πρώτα."
}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/lang/eu.json b/www/addons/mod/scorm/lang/eu.json
index d6315ef6681..cb26ace868a 100644
--- a/www/addons/mod/scorm/lang/eu.json
+++ b/www/addons/mod/scorm/lang/eu.json
@@ -20,7 +20,7 @@
"errorpackagefile": "Barkatu, aplikazioak ZIP paketeak besterik ez du onartzen.",
"errorsyncscorm": "Errorea gertatu da sinkronizatzean. Mesedez, saiatu berriz.",
"exceededmaxattempts": "Gehienezko saiakera-kopurua egin duzu.",
- "failed": "Errorea",
+ "failed": "Gainditu gabea",
"firstattempt": "Lehenengo saiakera",
"gradeaverage": "Batez besteko kalifikazioa",
"gradeforattempt": "Saikerarako kalifikazioa",
diff --git a/www/addons/mod/scorm/lang/ja.json b/www/addons/mod/scorm/lang/ja.json
index df57f44b198..031b2f60a58 100644
--- a/www/addons/mod/scorm/lang/ja.json
+++ b/www/addons/mod/scorm/lang/ja.json
@@ -6,9 +6,19 @@
"browse": "プレビュー",
"browsed": "閲覧済み",
"browsemode": "プレビューモード",
+ "cannotcalculategrade": "評定が計算できませんでした。",
"completed": "完了",
"contents": "コンテンツ",
+ "dataattemptshown": "このデータは回答番号 {{number}} に該当します。",
"enter": "問題に入る",
+ "errorcreateofflineattempt": "新たなオフライン回答の作成中にエラーが発生しました。再度実行してください。",
+ "errordownloadscorm": "SCORM \"{{name}}\" のダウンロード中にエラーが発生しました。",
+ "errorgetscorm": "SCORMデータの取得中にエラーが発生しました。",
+ "errorinvalidversion": "申し訳ありません。アプリケーションはSCORM 1.2のみをサポートしています。",
+ "errornotdownloadable": "あなたのMoodleサイトではSCORMパッケージのダウンロードができません。Moodleサイト管理者に連絡してください。",
+ "errornovalidsco": "このSCORMはロードに必要な表示できるSCOがありません。",
+ "errorpackagefile": "申し訳ありません。アプリケーションはZIPパッケージのみをサポートしています。",
+ "errorsyncscorm": "同期中にエラーが発生しました。再度実行してください。",
"exceededmaxattempts": "あなたは最大受験回数に達しました。",
"failed": "不合格",
"firstattempt": "最初の受験",
@@ -28,8 +38,14 @@
"noattemptsmade": "あなたの受験回数",
"normal": "ノーマル",
"notattempted": "未受験",
+ "offlineattemptnote": "この回答には動悸されなかったデータがあります。",
+ "offlineattemptovermax": "受験可能回数を超えたため、この回答を送信できません。",
"organizations": "組織",
"passed": "合格",
"reviewmode": "レビューモード",
- "suspended": "一時停止"
+ "scormstatusnotdownloaded": "このSCORMはダウンロードされていません。これを開くときに、自動的にダウンロードされます。",
+ "scormstatusoutdated": "このSCORMは最後にダウンロードされた後に更新されています。開くときに、自動的に新しいものがダウンロードされます。",
+ "suspended": "一時停止",
+ "warningofflinedatadeleted": "回答番号 {{number}} を新しい回答として作成することができなかったため、オフラインデータの一部が消去されました。",
+ "warningsynconlineincomplete": "最終のオンライン回答が完了していないため、一部の回答が同期できませんでした。先にオンライン回答を完了してください。"
}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/lang/sr-cr.json b/www/addons/mod/scorm/lang/sr-cr.json
new file mode 100644
index 00000000000..e35b5f6a6b6
--- /dev/null
+++ b/www/addons/mod/scorm/lang/sr-cr.json
@@ -0,0 +1,51 @@
+{
+ "asset": "Елемент",
+ "assetlaunched": "Елемент - Прегледано",
+ "attempts": "Покушаји",
+ "averageattempt": "Просечни број покушаја",
+ "browse": "Преглед",
+ "browsed": "Претражено",
+ "browsemode": "Режим прегледа",
+ "cannotcalculategrade": "Оцена не може да се израчуна.",
+ "completed": "Завршено",
+ "contents": "Садржај",
+ "dataattemptshown": "Ови подаци припадају покушају број {{number}}.",
+ "enter": "Уђи",
+ "errorcreateofflineattempt": "Дошло је до грешке приликом покушаја креирања новог офлајн покушаја. Молимо, покушајте поново.",
+ "errordownloadscorm": "Грешка приликом преузимања SCORM пакета: \"{{name}}\".",
+ "errorgetscorm": "Грешка приликом преузимања података SCORM пакета.",
+ "errorinvalidversion": "Извините, апликација подржава само SCORM 1.2.",
+ "errornotdownloadable": "Преузимање SCORM пакета је онемогућено на вашем сајту. Молимо, обратите се администратору вашег Moodle сајта.",
+ "errornovalidsco": "Овај SCORM пакет нема видљив SCO који би био учитан.",
+ "errorpackagefile": "Извините, апликација подржава само ZIP архиве.",
+ "errorsyncscorm": "Дошло је до грешке приликом синхронизације. Молимо, покушајте поново.",
+ "exceededmaxattempts": "Достигли сте максималан број покушаја",
+ "failed": "Није успело",
+ "firstattempt": "Први покушај",
+ "gradeaverage": "Просечна оцена",
+ "gradeforattempt": "Оцена за покушај",
+ "gradehighest": "Највиша оцена",
+ "grademethod": "Метод оцењивања",
+ "gradereported": "Извештај о оценама",
+ "gradescoes": "Објекти за учење",
+ "gradesum": "Коначна оцена",
+ "highestattempt": "Најбољи покушај",
+ "incomplete": "Непотпуно",
+ "lastattempt": "Последњи завршени покушај",
+ "mode": "Режим рада",
+ "newattempt": "Почни нови покушај",
+ "noattemptsallowed": "Број дозвољених покушаја",
+ "noattemptsmade": "Број покушаја који сте имали",
+ "normal": "Нормално",
+ "notattempted": "Није покушавано",
+ "offlineattemptnote": "Овај покушај има податке који нису синхронизован.",
+ "offlineattemptovermax": "Овај покушај не може бити послат зато што сте премашили максималан број дозвољених покушаја.",
+ "organizations": "Организације",
+ "passed": "Положено",
+ "reviewmode": "Режим прегледа",
+ "scormstatusnotdownloaded": "Овај SCORM пакет није преузет. Биће аутоматски преузет када га отворите.",
+ "scormstatusoutdated": "Овај SCORM пакет је мењан од последњег преузимања. Биће аутоматски преузет када га отворите.",
+ "suspended": "Суспендовано",
+ "warningofflinedatadeleted": "Неки офлајн подаци о покушају {{number}} су обрисани зато што их није могуће креирати у новом покушају.",
+ "warningsynconlineincomplete": "Неки покушаји нису могли бити синхронизовани са сајтом зато што последњи онлине покушај није завршен. Молимо вас да прво завршите онлајн покушај."
+}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/lang/sr-lt.json b/www/addons/mod/scorm/lang/sr-lt.json
new file mode 100644
index 00000000000..7f75f400c9b
--- /dev/null
+++ b/www/addons/mod/scorm/lang/sr-lt.json
@@ -0,0 +1,51 @@
+{
+ "asset": "Element",
+ "assetlaunched": "Element - Pregledano",
+ "attempts": "Pokušaji",
+ "averageattempt": "Prosečni broj pokušaja",
+ "browse": "Pregled",
+ "browsed": "Pretraženo",
+ "browsemode": "Režim pregleda",
+ "cannotcalculategrade": "Ocena ne može da se izračuna.",
+ "completed": "Završeno",
+ "contents": "Sadržaj",
+ "dataattemptshown": "Ovi podaci pripadaju pokušaju broj {{number}}.",
+ "enter": "Uđi",
+ "errorcreateofflineattempt": "Došlo je do greške prilikom pokušaja kreiranja novog oflajn pokušaja. Molimo, pokušajte ponovo.",
+ "errordownloadscorm": "Greška prilikom preuzimanja SCORM paketa: \"{{name}}\".",
+ "errorgetscorm": "Greška prilikom preuzimanja podataka SCORM paketa.",
+ "errorinvalidversion": "Izvinite, aplikacija podržava samo SCORM 1.2.",
+ "errornotdownloadable": "Preuzimanje SCORM paketa je onemogućeno na vašem sajtu. Molimo, obratite se administratoru vašeg Moodle sajta.",
+ "errornovalidsco": "Ovaj SCORM paket nema vidljiv SCO koji bi bio učitan.",
+ "errorpackagefile": "Izvinite, aplikacija podržava samo ZIP arhive.",
+ "errorsyncscorm": "Došlo je do greške prilikom sinhronizacije. Molimo, pokušajte ponovo.",
+ "exceededmaxattempts": "Dostigli ste maksimalan broj pokušaja",
+ "failed": "Nije uspelo",
+ "firstattempt": "Prvi pokušaj",
+ "gradeaverage": "Prosečna ocena",
+ "gradeforattempt": "Ocena za pokušaj",
+ "gradehighest": "Najviša ocena",
+ "grademethod": "Metod ocenjivanja",
+ "gradereported": "Izveštaj o ocenama",
+ "gradescoes": "Objekti za učenje",
+ "gradesum": "Konačna ocena",
+ "highestattempt": "Najbolji pokušaj",
+ "incomplete": "Nepotpuno",
+ "lastattempt": "Poslednji završeni pokušaj",
+ "mode": "Režim rada",
+ "newattempt": "Počni novi pokušaj",
+ "noattemptsallowed": "Broj dozvoljenih pokušaja",
+ "noattemptsmade": "Broj pokušaja koji ste imali",
+ "normal": "Normalno",
+ "notattempted": "Nije pokušavano",
+ "offlineattemptnote": "Ovaj pokušaj ima podatke koji nisu sinhronizovan.",
+ "offlineattemptovermax": "Ovaj pokušaj ne može biti poslat zato što ste premašili maksimalan broj dozvoljenih pokušaja.",
+ "organizations": "Organizacije",
+ "passed": "Položeno",
+ "reviewmode": "Režim prikaza",
+ "scormstatusnotdownloaded": "Ovaj SCORM paket nije preuzet. Biće automatski preuzet kada ga otvorite.",
+ "scormstatusoutdated": "Ovaj SCORM paket je menjan od poslednjeg preuzimanja. Biće automatski preuzet kada ga otvorite.",
+ "suspended": "Suspendovano",
+ "warningofflinedatadeleted": "Neki oflajn podaci o pokušaju {{number}} su obrisani zato što ih nije moguće kreirati u novom pokušaju.",
+ "warningsynconlineincomplete": "Neki pokušaji nisu mogli biti sinhronizovani sa sajtom zato što poslednji online pokušaj nije završen. Molimo vas da prvo završite onlajn pokušaj."
+}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/lang/uk.json b/www/addons/mod/scorm/lang/uk.json
index 47edde51210..dc0f5cb8a29 100644
--- a/www/addons/mod/scorm/lang/uk.json
+++ b/www/addons/mod/scorm/lang/uk.json
@@ -12,7 +12,7 @@
"dataattemptshown": "Ці дані належать до спроби № {{number}}.",
"enter": "Ввести",
"errorcreateofflineattempt": "При створенні нового форуму сталася помилка. Будь ласка спробуйте ще раз.",
- "errordownloadscorm": "Помилка завантаження SCORM: \"{{name}}\".",
+ "errordownloadscorm": "Помилка завантаження SCORM: \"{{name}}\".",
"errorgetscorm": "Помилка отримання SCORM-даних.",
"errorinvalidversion": "На жаль, додаток підтримує тільки SCORM 1.2.",
"errornotdownloadable": "Завантаження SCORM пакетів відключене у вашому сайті Moodle. Будь ласка, зверніться до адміністратора сайту Moodle.",
@@ -39,13 +39,13 @@
"normal": "Нормальний",
"notattempted": "Не було спроб",
"offlineattemptnote": "Ця спроба має дані, що не були синхронізовані.",
- "offlineattemptovermax": "Ця спроба не може бути відправлена, так як ви перевершили максимальну кількість спроб.",
+ "offlineattemptovermax": "Ця спроба не може бути відправлена, так як ви перевищили максимальну кількість спроб.",
"organizations": "Організації",
"passed": "Пропущено",
"reviewmode": "Режим перегляду",
- "scormstatusnotdownloaded": "Це SCORM не завантажується. Він буде автоматично завантажуватися при її відкритті.",
+ "scormstatusnotdownloaded": "Цей SCORM не завантажений. Він буде автоматично завантажуватися при його відкритті.",
"scormstatusoutdated": "Цей SCORM був змінений з моменту останнього завантаження. Він буде автоматично завантажуватися при її відкритті.",
"suspended": "Заблокований",
- "warningofflinedatadeleted": "Деякі автономні дані про спробу № {{number}} були видалений, тому що він не може бути створений в новій спробі.",
+ "warningofflinedatadeleted": "Деякі автономні дані про спробу № {{number}} були видалені, тому що вони не можуть бути створені в новій спробі.",
"warningsynconlineincomplete": "Деякі спроби не можуть бути синхронізовані з сайтом, тому що онлайн спроба не закінчена. Будь ласка закінчіть спробу онлайн спершу."
}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/lang/zh-tw.json b/www/addons/mod/scorm/lang/zh-tw.json
index ec476e126b9..c46213ad3fa 100644
--- a/www/addons/mod/scorm/lang/zh-tw.json
+++ b/www/addons/mod/scorm/lang/zh-tw.json
@@ -21,23 +21,23 @@
"errorsyncscorm": "同步時發生錯誤. 請再試一次.",
"exceededmaxattempts": "你已經達到最大的作答次數",
"failed": "失敗",
- "firstattempt": "第一次使用",
+ "firstattempt": "第一次作答",
"gradeaverage": "平均成績",
"gradeforattempt": "作答次的分數",
"gradehighest": "最高成績",
- "grademethod": "評分方式",
+ "grademethod": "成績採計方式",
"gradereported": "成績報告",
"gradescoes": "學習目標",
"gradesum": "加總",
- "highestattempt": "最高使用次數",
+ "highestattempt": "最高作答次數",
"incomplete": "不完整",
"lastattempt": "最後完成的作答次",
"mode": "模式",
- "newattempt": "開始新的使用",
+ "newattempt": "開始一個新的作答次",
"noattemptsallowed": "允許作答的次數",
"noattemptsmade": "你已經作答的次數",
"normal": "一般",
- "notattempted": "未嘗試",
+ "notattempted": "尚未作答",
"offlineattemptnote": "此嘗試包含尚未同步的資料.",
"offlineattemptovermax": "無法發送此嘗試, 因為您超過了最大嘗試次數.",
"organizations": "組織",
@@ -45,7 +45,7 @@
"reviewmode": "複習模式",
"scormstatusnotdownloaded": "此SCORM未下載. 它會在您打開時自動下載.",
"scormstatusoutdated": "此SCORM自上次下載以來已被修改. 它會在您打開時自動下載.",
- "suspended": "中止",
+ "suspended": "已休學",
"warningofflinedatadeleted": "嘗試{{number}}的某些離線資料已被刪除, 因為無法建立新的嘗試.",
"warningsynconlineincomplete": "某些嘗試無法與網站同步, 因為上次上線嘗試未完成, 請先完成上線嘗試."
}
\ No newline at end of file
diff --git a/www/addons/mod/scorm/services/handlers.js b/www/addons/mod/scorm/services/handlers.js
index b9048febd28..8e9bf9b482c 100644
--- a/www/addons/mod/scorm/services/handlers.js
+++ b/www/addons/mod/scorm/services/handlers.js
@@ -23,7 +23,7 @@ angular.module('mm.addons.mod_scorm')
*/
.factory('$mmaModScormHandlers', function($mmCourse, $mmaModScorm, $mmEvents, $state, $mmSite, $mmaModScormHelper,
$mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, mmCoreEventPackageStatusChanged,
- mmaModScormComponent, $q, $mmContentLinksHelper, $mmUtil, $mmaModScormSync, $mmaModScormPrefetchHandler) {
+ mmaModScormComponent, $q, $mmContentLinksHelper, $mmaModScormSync, $mmaModScormPrefetchHandler) {
var self = {};
/**
@@ -95,9 +95,10 @@ angular.module('mm.addons.mod_scorm')
$scope.spinner = true; // Show spinner since this operation might take a while.
$mmaModScorm.getScorm(courseid, module.id, module.url).then(function(scorm) {
$mmaModScormHelper.confirmDownload(scorm, isOutdated).then(function() {
- $mmaModScormPrefetchHandler.prefetch(module, courseid).catch(function() {
+ return $mmaModScormPrefetchHandler.prefetch(module, courseid).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmaModScormHelper.showDownloadError(scorm);
+ $mmaModScormHelper.showDownloadError(scorm, error);
+ return $q.reject();
}
});
}).catch(function() {
@@ -106,11 +107,7 @@ angular.module('mm.addons.mod_scorm')
});
}).catch(function(error) {
$scope.spinner = false;
- if (error) {
- $mmUtil.showErrorModal(error);
- } else {
- $mmaModScormHelper.showDownloadError(scorm);
- }
+ $mmaModScormHelper.showDownloadError(scorm, error);
});
}
@@ -156,6 +153,9 @@ angular.module('mm.addons.mod_scorm')
$scope.$on('$destroy', function() {
statusObserver && statusObserver.off && statusObserver.off();
});
+ }).catch(function() {
+ // Error getting SCORM, hide the spinner.
+ $scope.spinner = false;
});
};
};
diff --git a/www/addons/mod/scorm/services/helper.js b/www/addons/mod/scorm/services/helper.js
index 056636d7a38..052b2654c29 100644
--- a/www/addons/mod/scorm/services/helper.js
+++ b/www/addons/mod/scorm/services/helper.js
@@ -352,13 +352,12 @@ angular.module('mm.addons.mod_scorm')
* @module mm.addons.mod_scorm
* @ngdoc method
* @name $mmaModScormHelper#showDownloadError
- * @param {Object} scorm SCORM downloaded.
+ * @param {Object} scorm SCORM downloaded.
+ * @param {String} [error] Error returned by the download.
* @return {Void}
*/
- self.showDownloadError = function(scorm) {
- $translate('mma.mod_scorm.errordownloadscorm', {name: scorm.name}).then(function(message) {
- $mmUtil.showErrorModal(message);
- });
+ self.showDownloadError = function(scorm, error) {
+ $mmUtil.showErrorModalDefault(error, $translate.instant('mma.mod_scorm.errordownloadscorm', {name: scorm.name}));
};
return self;
diff --git a/www/addons/mod/survey/controllers/index.js b/www/addons/mod/survey/controllers/index.js
index 469f5cc7b63..5d4f0dab873 100644
--- a/www/addons/mod/survey/controllers/index.js
+++ b/www/addons/mod/survey/controllers/index.js
@@ -110,6 +110,13 @@ angular.module('mm.addons.mod_survey')
var isTextArea = q.multi && q.multi.length === 0 && q.type === 0;
$scope.answers[q.name] = q.required ? -1 : (isTextArea ? '' : '0');
}
+
+ if (q.multi && !q.multi.length && q.parent === 0 && q.type > 0) {
+ // Options shown in a select. Remove all HTML.
+ q.options = q.options.map(function(option) {
+ return $mmText.cleanTags(option);
+ });
+ }
});
});
});
diff --git a/www/addons/mod/survey/lang/ar.json b/www/addons/mod/survey/lang/ar.json
index 30dd1d2fed3..dd271b759c7 100644
--- a/www/addons/mod/survey/lang/ar.json
+++ b/www/addons/mod/survey/lang/ar.json
@@ -2,5 +2,5 @@
"ifoundthat": "وجدت أن",
"ipreferthat": "أفضل أن",
"responses": "إجابات",
- "results": "نتائج"
+ "results": "النتائج"
}
\ No newline at end of file
diff --git a/www/addons/mod/survey/lang/ja.json b/www/addons/mod/survey/lang/ja.json
index 9880b35045a..35fbcedcc0d 100644
--- a/www/addons/mod/survey/lang/ja.json
+++ b/www/addons/mod/survey/lang/ja.json
@@ -1,4 +1,6 @@
{
+ "cannotsubmitsurvey": "申し訳ありません。あなたの調査提出で問題が発生しました。再度提出を実行してください。",
+ "errorgetsurvey": "調査データの取得中にエラーが発生しました。",
"ifoundthat": "私は次のことを発見しました:",
"ipreferthat": "私は次のことが好きです:",
"responses": "回答",
diff --git a/www/addons/mod/survey/lang/pl.json b/www/addons/mod/survey/lang/pl.json
index 3b9a9921b72..cc6f6480b61 100644
--- a/www/addons/mod/survey/lang/pl.json
+++ b/www/addons/mod/survey/lang/pl.json
@@ -2,6 +2,6 @@
"ifoundthat": "Stwierdziłem, że",
"ipreferthat": "Wolę to",
"responses": "Odpowiedzi",
- "results": "Wynik",
+ "results": "Wyniki",
"surveycompletednograph": "Już wypełniłeś tą ankietę."
}
\ No newline at end of file
diff --git a/www/addons/mod/survey/lang/sr-cr.json b/www/addons/mod/survey/lang/sr-cr.json
new file mode 100644
index 00000000000..b09d2613a67
--- /dev/null
+++ b/www/addons/mod/survey/lang/sr-cr.json
@@ -0,0 +1,9 @@
+{
+ "cannotsubmitsurvey": "Нажалост, било је проблема са предајом вашег упитника. Молим вас, покушајте поново.",
+ "errorgetsurvey": "Грешка приликом преузимања података за 'Упитник' (Survey)",
+ "ifoundthat": "Открио/ла сам да",
+ "ipreferthat": "Преферирам",
+ "responses": "Одговори",
+ "results": "Резултати",
+ "surveycompletednograph": "Испунили сте анкету."
+}
\ No newline at end of file
diff --git a/www/addons/mod/survey/lang/sr-lt.json b/www/addons/mod/survey/lang/sr-lt.json
new file mode 100644
index 00000000000..7e1fed7f8d7
--- /dev/null
+++ b/www/addons/mod/survey/lang/sr-lt.json
@@ -0,0 +1,9 @@
+{
+ "cannotsubmitsurvey": "Nažalost, bilo je problema sa predajom vašeg upitnika. Molim vas, pokušajte ponovo.",
+ "errorgetsurvey": "Greška prilikom preuzimanja podataka za 'Upitnik' (Survey)",
+ "ifoundthat": "Otkrio/la sam da",
+ "ipreferthat": "Preferiram",
+ "responses": "Odgovori",
+ "results": "Rezultati",
+ "surveycompletednograph": "Ispunili ste anketu."
+}
\ No newline at end of file
diff --git a/www/addons/mod/survey/lang/tr.json b/www/addons/mod/survey/lang/tr.json
index f42edcb4d3f..471798df02c 100644
--- a/www/addons/mod/survey/lang/tr.json
+++ b/www/addons/mod/survey/lang/tr.json
@@ -2,6 +2,6 @@
"ifoundthat": "Gerçekte olan",
"ipreferthat": "İstediğim",
"responses": "Yanıtlar",
- "results": "Sonuç",
+ "results": "Sonuçlar",
"surveycompletednograph": "Bu anketi tamamladınız."
}
\ No newline at end of file
diff --git a/www/addons/mod/survey/lang/uk.json b/www/addons/mod/survey/lang/uk.json
index 74dd0374658..c0e91783cb7 100644
--- a/www/addons/mod/survey/lang/uk.json
+++ b/www/addons/mod/survey/lang/uk.json
@@ -1,6 +1,6 @@
{
- "cannotsubmitsurvey": "На жаль, існує проблема представлення вашого обстеження. Будь ласка спробуйте ще раз.",
- "errorgetsurvey": "Помилка при отриманні даних обстеження.",
+ "cannotsubmitsurvey": "На жаль, існує проблема вашого представлення. Будь ласка спробуйте ще раз.",
+ "errorgetsurvey": "Помилка при отриманні даних.",
"ifoundthat": "Я довідався, що",
"ipreferthat": "Я волію, щоб",
"responses": "Відповіді",
diff --git a/www/addons/mod/survey/lang/zh-cn.json b/www/addons/mod/survey/lang/zh-cn.json
index 912d8caa96b..7ef142e9e7a 100644
--- a/www/addons/mod/survey/lang/zh-cn.json
+++ b/www/addons/mod/survey/lang/zh-cn.json
@@ -2,5 +2,5 @@
"ifoundthat": "我发现",
"ipreferthat": "我希望的是",
"responses": "回复",
- "results": "投票结果"
+ "results": "结果"
}
\ No newline at end of file
diff --git a/www/addons/mod/survey/services/handlers.js b/www/addons/mod/survey/services/handlers.js
index 4bbccfbe032..22a6cb83fbf 100644
--- a/www/addons/mod/survey/services/handlers.js
+++ b/www/addons/mod/survey/services/handlers.js
@@ -22,7 +22,7 @@ angular.module('mm.addons.mod_survey')
* @name $mmaModSurveyHandlers
*/
.factory('$mmaModSurveyHandlers', function($mmCourse, $mmaModSurvey, $state, $mmContentLinksHelper, $mmUtil, $mmEvents, $mmSite,
- $mmaModSurveyPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated,
+ $mmaModSurveyPrefetchHandler, $mmCoursePrefetchDelegate, mmCoreDownloading, mmCoreNotDownloaded, mmCoreOutdated, $q,
mmaModSurveyComponent, mmCoreEventPackageStatusChanged, $mmaModSurveySync) {
var self = {};
@@ -103,9 +103,10 @@ angular.module('mm.addons.mod_survey')
// Get download size to ask for confirm if it's high.
$mmaModSurveyPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModSurveyPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModSurveyPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/mod/survey/templates/index.html b/www/addons/mod/survey/templates/index.html
index e3f4ac67837..f9ef701c354 100644
--- a/www/addons/mod/survey/templates/index.html
+++ b/www/addons/mod/survey/templates/index.html
@@ -70,7 +70,7 @@
{{ question.text }}
-
diff --git a/www/addons/mod/url/lang/es_mx.json b/www/addons/mod/url/lang/es_mx.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/url/lang/es_mx.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/ja.json b/www/addons/mod/url/lang/ja.json
index 0637a088a01..350006f4a7f 100644
--- a/www/addons/mod/url/lang/ja.json
+++ b/www/addons/mod/url/lang/ja.json
@@ -1 +1,4 @@
-[]
\ No newline at end of file
+{
+ "accessurl": "URLへのアクセス",
+ "pointingtourl": "このリソースを示すURL"
+}
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/pt_br.json b/www/addons/mod/url/lang/pt_br.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/url/lang/pt_br.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/sr-cr.json b/www/addons/mod/url/lang/sr-cr.json
new file mode 100644
index 00000000000..8559de48806
--- /dev/null
+++ b/www/addons/mod/url/lang/sr-cr.json
@@ -0,0 +1,4 @@
+{
+ "accessurl": "Приступи URL адреси",
+ "pointingtourl": "URL адреса са којом је овај ресурс повезан"
+}
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/sr-lt.json b/www/addons/mod/url/lang/sr-lt.json
new file mode 100644
index 00000000000..a266fc49df5
--- /dev/null
+++ b/www/addons/mod/url/lang/sr-lt.json
@@ -0,0 +1,4 @@
+{
+ "accessurl": "Pristupi URL adresi",
+ "pointingtourl": "URL adresa sa kojom je ovaj resurs povezan"
+}
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/zh_cn.json b/www/addons/mod/url/lang/zh_cn.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/url/lang/zh_cn.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/url/lang/zh_tw.json b/www/addons/mod/url/lang/zh_tw.json
deleted file mode 100644
index 0637a088a01..00000000000
--- a/www/addons/mod/url/lang/zh_tw.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/ar.json b/www/addons/mod/wiki/lang/ar.json
index 1bff5b0f91c..794020d3f62 100644
--- a/www/addons/mod/wiki/lang/ar.json
+++ b/www/addons/mod/wiki/lang/ar.json
@@ -6,7 +6,7 @@
"newpagetitle": "عنواو صفحة جديد",
"nocontent": "لا يوجد محتوى في هذه الصفحة",
"notingroup": "لا ينتمي إلى مجموعة",
- "page": "صفحة",
+ "page": "صفحة: {{$a}}",
"pagename": "اسم الصفحة",
"wrongversionlock": "قام مستخدم آخر بتحديث هذه الصفحة بينما كنت أنت تحررها، أصبحت تعديلاتك قديمة."
}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/bg.json b/www/addons/mod/wiki/lang/bg.json
index dbe95df13e3..cfe93c0370e 100644
--- a/www/addons/mod/wiki/lang/bg.json
+++ b/www/addons/mod/wiki/lang/bg.json
@@ -4,8 +4,8 @@
"editingpage": "Редактиране на страница \"{{$a}}\"",
"map": "Карта",
"newpagetitle": "Заглавие на новата страница",
- "notingroup": "Извинете, но трябва да сте част от групата за да видите тази дейност.",
- "page": "Страница",
+ "notingroup": "За съжаление Вие трябва да се част от група за да виждате този форум.",
+ "page": "Страница: {{$a}}",
"pagename": "Име на страница",
"wrongversionlock": "Друг потребител редактира тази страница докато Вие редактирахте и Вашата редакция вече е остаряла."
}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/el.json b/www/addons/mod/wiki/lang/el.json
index 801399e1135..7a3a3058446 100644
--- a/www/addons/mod/wiki/lang/el.json
+++ b/www/addons/mod/wiki/lang/el.json
@@ -2,7 +2,7 @@
"errorloadingpage": "Παρουσιάστηκε σφάλμα κατά τη φόρτωση της σελίδας.",
"errornowikiavailable": "Αυτό το wiki δεν έχει ακόμα περιεχόμενο.",
"gowikihome": "Go Wiki home",
- "notingroup": "Συγνώμη, αλλά θα πρέπει να είστε μέλος μιας ομάδας για να δείτε αυτήν τη δραστηριότητα",
+ "notingroup": "Συγγνώμη, αλλά πρέπει να είστε μέλος ομάδας για να δείτε αυτό την ομάδα συζητήσεων.",
"page": "Σελίδα",
"subwiki": "Subwiki",
"titleshouldnotbeempty": "Ο τίτλος δεν πρέπει να είναι κενός",
diff --git a/www/addons/mod/wiki/lang/fa.json b/www/addons/mod/wiki/lang/fa.json
index 3ea0f81b588..645adbdab85 100644
--- a/www/addons/mod/wiki/lang/fa.json
+++ b/www/addons/mod/wiki/lang/fa.json
@@ -5,7 +5,7 @@
"newpagetitle": "عنوان صفحهٔ جدید",
"nocontent": "محتوایی برای این صفحه وجود ندارد",
"notingroup": "بدون گروه",
- "page": "صفحه",
+ "page": "صفحهٔ {{$a}}",
"pageexists": "این صفحه در حال حاضر وجود دارد. در حال تغییر مسیر به صفحهٔ موجود.",
"viewpage": "مشاهدهٔ صفحه",
"wrongversionlock": "هنگامی که شما در حال ویرایش این صفحه بودید، کاربر دیگری آن را ویرایش کرد و محتوایش را تغییر داد."
diff --git a/www/addons/mod/wiki/lang/he.json b/www/addons/mod/wiki/lang/he.json
index 46bd85d687c..6d94870a86a 100644
--- a/www/addons/mod/wiki/lang/he.json
+++ b/www/addons/mod/wiki/lang/he.json
@@ -7,7 +7,7 @@
"newpagetitle": "כותרת דף חדש",
"nocontent": "אין תוכן לדף זה",
"notingroup": "לא בקבוצה",
- "page": "עמוד",
+ "page": "עמוד: {{$a}}",
"pageexists": "הדף כבר קיים. הפנה אליו מחדש.",
"pagename": "שם העמוד",
"wrongversionlock": "משתמש אחר ערך את הדף הזה בזמן שאת/ה ערכת/ה. התוכן שלך לא ישמר."
diff --git a/www/addons/mod/wiki/lang/hu.json b/www/addons/mod/wiki/lang/hu.json
index 19b98951ec9..52eb1a43078 100644
--- a/www/addons/mod/wiki/lang/hu.json
+++ b/www/addons/mod/wiki/lang/hu.json
@@ -7,7 +7,7 @@
"newpagetitle": "Új oldalcím",
"nocontent": "Az oldalhoz nincs tartalom",
"notingroup": "Nem része a csoportnak",
- "page": "Oldal",
+ "page": "Oldal: {{$a}}",
"pageexists": "Az oldal már létezik. Átirányítás az oldalra.",
"pagename": "Oldal neve",
"wrongversionlock": "A szerkesztés közben egy másik felhasználó szerkesztette ezt az oldalt, így az Ön tartalma elavult."
diff --git a/www/addons/mod/wiki/lang/it.json b/www/addons/mod/wiki/lang/it.json
index 5acbfeed47e..188539ca68d 100644
--- a/www/addons/mod/wiki/lang/it.json
+++ b/www/addons/mod/wiki/lang/it.json
@@ -10,7 +10,7 @@
"newpagetitle": "Titolo nuova pagina",
"nocontent": "Questa pagina non ha contenuti",
"notingroup": "Non è in un gruppo",
- "page": "Pagina",
+ "page": "Pagina: {{$a}}",
"pageexists": "La pagina esiste già.",
"pagename": "Nome pagina",
"subwiki": "Subwiki",
diff --git a/www/addons/mod/wiki/lang/ja.json b/www/addons/mod/wiki/lang/ja.json
index fbfaad517e5..602d4646668 100644
--- a/www/addons/mod/wiki/lang/ja.json
+++ b/www/addons/mod/wiki/lang/ja.json
@@ -2,6 +2,9 @@
"cannoteditpage": "あなたはこのページを編集できません。",
"createpage": "ページを作成する",
"editingpage": "このページ「 {{$a}} 」の編集",
+ "errorloadingpage": "ページの読み込み中にエラーが発生しました。",
+ "errornowikiavailable": "このwikiにはまだ内容がありません。",
+ "gowikihome": "Wikiのホームへ移動",
"map": "マップ",
"newpagehdr": "新しいページ",
"newpagetitle": "新しいページタイトル",
@@ -10,5 +13,9 @@
"page": "ページ",
"pageexists": "このページはすでに存在します。",
"pagename": "ページ名",
+ "subwiki": "サブwiki",
+ "titleshouldnotbeempty": "空のタイトルは受け付けられません",
+ "viewpage": "ページを表示",
+ "wikipage": "Wikiページ",
"wrongversionlock": "あなたが編集している間、別のユーザがこのページを編集しました。そのため、あなたのコンテンツは古くなりました。"
}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/pl.json b/www/addons/mod/wiki/lang/pl.json
index 8515710e26a..391b0fbc350 100644
--- a/www/addons/mod/wiki/lang/pl.json
+++ b/www/addons/mod/wiki/lang/pl.json
@@ -7,7 +7,7 @@
"newpagetitle": "Tytuł nowej strony",
"nocontent": "Brak zawartości dla tej strony",
"notingroup": "Nie w grupie",
- "page": "Strona",
+ "page": "Strona: {{$a}}",
"pageexists": "Ta strona już istnieje. Przekierowuje do niej.",
"pagename": "Nazwa strony",
"wrongversionlock": "Inny użytkownik edytował tę stronę w czasie, kiedy ty ją edytowałeś i twoja zawartość jest przestarzała."
diff --git a/www/addons/mod/wiki/lang/ro.json b/www/addons/mod/wiki/lang/ro.json
index 79fdc396e4f..2b0c326bec6 100644
--- a/www/addons/mod/wiki/lang/ro.json
+++ b/www/addons/mod/wiki/lang/ro.json
@@ -5,7 +5,7 @@
"newpagehdr": "Pagină nouă",
"newpagetitle": "Un nou titlu de pagină",
"nocontent": "Nu există conținut pentru această pagină",
- "notingroup": "Ne pare rău, dar trebuie să faceţi parte dintr-un grup pentru a putea vizualiza această activitate.",
- "page": "Pagină",
+ "notingroup": "Ne pare rău, pentru a putea vizualiza acest forum trebuie să fiţi membru al unui grup.",
+ "page": "Pagina {{$a}}",
"pagename": "Nume pagină"
}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/sr-cr.json b/www/addons/mod/wiki/lang/sr-cr.json
new file mode 100644
index 00000000000..9620e198c9d
--- /dev/null
+++ b/www/addons/mod/wiki/lang/sr-cr.json
@@ -0,0 +1,21 @@
+{
+ "cannoteditpage": "Не можете да уређујете ову страницу.",
+ "createpage": "Креирај страницу",
+ "editingpage": "Уређивање ове странице '{{$a}}'",
+ "errorloadingpage": "Дошло је до грешке приликом учитавања странице.",
+ "errornowikiavailable": "Овај вики још увек нема садржај.",
+ "gowikihome": "Иди на почетну страницу викија",
+ "map": "Мапа",
+ "newpagehdr": "Нова страница",
+ "newpagetitle": "Наслов нове странице",
+ "nocontent": "На овој страници нема садржаја",
+ "notingroup": "Није у групи",
+ "page": "Страница",
+ "pageexists": "Ова страница већ постоји.",
+ "pagename": "Назив странице",
+ "subwiki": "Подвики",
+ "titleshouldnotbeempty": "Наслов не би требало да буде празан",
+ "viewpage": "Погледај страницу",
+ "wikipage": "Вики страница",
+ "wrongversionlock": "Други корисник је уређивао ову страницу у исто време када и ви. Ваш садржај је застарео."
+}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/sr-lt.json b/www/addons/mod/wiki/lang/sr-lt.json
new file mode 100644
index 00000000000..11efcb2e226
--- /dev/null
+++ b/www/addons/mod/wiki/lang/sr-lt.json
@@ -0,0 +1,21 @@
+{
+ "cannoteditpage": "Ne možete da uređujete ovu stranicu.",
+ "createpage": "Kreiraj stranicu",
+ "editingpage": "Uređivanje ove stranice '{{$a}}'",
+ "errorloadingpage": "Došlo je do greške prilikom učitavanja stranice.",
+ "errornowikiavailable": "Ovaj viki još uvek nema sadržaj.",
+ "gowikihome": "Idi na početnu stranicu vikija",
+ "map": "Mapa",
+ "newpagehdr": "Nova stranica",
+ "newpagetitle": "Naslov nove stranice",
+ "nocontent": "Na ovoj stranici nema sadržaja",
+ "notingroup": "Nije u grupi",
+ "page": "Stranica",
+ "pageexists": "Ova stranica već postoji.",
+ "pagename": "Naziv stranice",
+ "subwiki": "Podviki",
+ "titleshouldnotbeempty": "Naslov ne bi trebalo da bude prazan",
+ "viewpage": "Pogledaj stranicu",
+ "wikipage": "Viki stranica",
+ "wrongversionlock": "Drugi korisnik je uređivao ovu stranicu u isto vreme kada i vi. Vaš sadržaj je zastareo."
+}
\ No newline at end of file
diff --git a/www/addons/mod/wiki/lang/sv.json b/www/addons/mod/wiki/lang/sv.json
index f9ebf16c762..43bd89b4601 100644
--- a/www/addons/mod/wiki/lang/sv.json
+++ b/www/addons/mod/wiki/lang/sv.json
@@ -10,7 +10,7 @@
"newpagetitle": "Ny titel på sida",
"nocontent": "Det finns inget innehåll för den här sidan",
"notingroup": "Inte i grupp",
- "page": "Sida",
+ "page": "Sida: {{$a}}",
"pageexists": "Den här sidan finns redan, länkning dit pågår",
"pagename": "Namn på sida",
"subwiki": "Subwiki",
diff --git a/www/addons/mod/wiki/lang/uk.json b/www/addons/mod/wiki/lang/uk.json
index c19abe51cb9..cd89e56c9cc 100644
--- a/www/addons/mod/wiki/lang/uk.json
+++ b/www/addons/mod/wiki/lang/uk.json
@@ -13,7 +13,7 @@
"page": "Сторінка",
"pageexists": "Ця сторінка вже існує. Перенаправити до неї.",
"pagename": "Назва сторінки",
- "subwiki": "Сабвікі",
+ "subwiki": "Субвікі",
"titleshouldnotbeempty": "Заголовок не може бути порожнім",
"viewpage": "Переглянути сторінку",
"wikipage": "Вікі-сторінка",
diff --git a/www/addons/mod/wiki/lang/zh-cn.json b/www/addons/mod/wiki/lang/zh-cn.json
index 1eb2563a117..28e5c1b23ad 100644
--- a/www/addons/mod/wiki/lang/zh-cn.json
+++ b/www/addons/mod/wiki/lang/zh-cn.json
@@ -7,7 +7,7 @@
"newpagetitle": "新页面标题",
"nocontent": "此页面无内容",
"notingroup": "不在小组内",
- "page": "页",
+ "page": "页面",
"pageexists": "页面已存在。重定向到它",
"pagename": "页码",
"wrongversionlock": "在您正编辑此页面时,另一个人已经做了编辑,所以您的修改已过时。"
diff --git a/www/addons/mod/wiki/services/handlers.js b/www/addons/mod/wiki/services/handlers.js
index 04ecf9ea010..eacdbf6c62f 100644
--- a/www/addons/mod/wiki/services/handlers.js
+++ b/www/addons/mod/wiki/services/handlers.js
@@ -102,9 +102,10 @@ angular.module('mm.addons.mod_wiki')
// We need to call getDownloadSize, the package might have been updated.
$mmaModWikiPrefetchHandler.getDownloadSize(module, courseId).then(function(size) {
$mmUtil.confirmDownloadSize(size).then(function() {
- $mmaModWikiPrefetchHandler.prefetch(module, courseId).catch(function() {
+ return $mmaModWikiPrefetchHandler.prefetch(module, courseId).catch(function(error) {
if (!$scope.$$destroyed) {
- $mmUtil.showErrorModal('mm.core.errordownloading', true);
+ $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true);
+ return $q.reject();
}
});
}).catch(function() {
diff --git a/www/addons/myoverview/lang/ca.json b/www/addons/myoverview/lang/ca.json
index 6f57cd536b3..7d74942e12e 100644
--- a/www/addons/myoverview/lang/ca.json
+++ b/www/addons/myoverview/lang/ca.json
@@ -1,5 +1,18 @@
{
- "inprogress": "En curs",
- "nocourses": "No hi ha informació de cursos per mostrar.",
- "pluginname": "Nom del connector de repositori"
+ "future": "Futurs",
+ "inprogress": "En progrés",
+ "morecourses": "Més cursos",
+ "next30days": "Propers 30 dies",
+ "next7days": "Propers 7 dies",
+ "nocourses": "Cap curs",
+ "nocoursesfuture": "Cap curs futur",
+ "nocoursesinprogress": "Cap curs en progrés",
+ "nocoursespast": "Cap curs passat",
+ "noevents": "Cap activitat venç properament",
+ "past": "Passats",
+ "pluginname": "Resum del curs",
+ "recentlyoverdue": "Vençuda recentment",
+ "sortbycourses": "Ordena per cursos",
+ "sortbydates": "Ordena per dates",
+ "timeline": "Línia de temps"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/da.json b/www/addons/myoverview/lang/da.json
index 6b0e076a3e8..93f96452658 100644
--- a/www/addons/myoverview/lang/da.json
+++ b/www/addons/myoverview/lang/da.json
@@ -1,5 +1,17 @@
{
- "inprogress": "Igangværende",
- "nocourses": "Du er ikke tilmeldt nogen kurser.",
- "pluginname": "Navn på filarkiv-plugin"
+ "future": "Fremtidige",
+ "inprogress": "I gang",
+ "morecourses": "Flere kurser",
+ "next30days": "Næste 30 dage",
+ "next7days": "Næste 7 dage",
+ "nocourses": "Ingen kurser",
+ "nocoursesfuture": "Ingen fremtidige kurser",
+ "nocoursesinprogress": "Ingen igangværende kurser",
+ "nocoursespast": "Ingen tidligere kurser",
+ "noevents": "Ingen forestående aktiviteter",
+ "past": "Tidligere",
+ "pluginname": "Kursusoversigt",
+ "sortbycourses": "Sorter efter kurser",
+ "sortbydates": "Sorter efter dato",
+ "timeline": "Tidslinje"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/de.json b/www/addons/myoverview/lang/de.json
index 5eeb1d65140..48617009585 100644
--- a/www/addons/myoverview/lang/de.json
+++ b/www/addons/myoverview/lang/de.json
@@ -14,5 +14,5 @@
"recentlyoverdue": "Kürzlich überfällig",
"sortbycourses": "Nach Kurs sortieren",
"sortbydates": "Nach Datum sortieren",
- "timeline": "Timeline"
+ "timeline": "Zeitleiste"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/es.json b/www/addons/myoverview/lang/es.json
index b796e0b88b4..44a7a41e6f1 100644
--- a/www/addons/myoverview/lang/es.json
+++ b/www/addons/myoverview/lang/es.json
@@ -1,5 +1,5 @@
{
- "future": "Futuro",
+ "future": "Futuros",
"inprogress": "En progreso",
"morecourses": "Más cursos",
"next30days": "Próximos 30 días",
@@ -9,7 +9,7 @@
"nocoursesinprogress": "Sin cursos en progreso",
"nocoursespast": "Sin cursos pasados",
"noevents": "No hay actividades próximas pendientes",
- "past": "Pasado",
+ "past": "Pasados",
"pluginname": "Vista general de curso",
"recentlyoverdue": "Recientemente vencidas",
"sortbycourses": "Ordenar por curso",
diff --git a/www/addons/myoverview/lang/eu.json b/www/addons/myoverview/lang/eu.json
index 63ad1570d13..75bf1d67080 100644
--- a/www/addons/myoverview/lang/eu.json
+++ b/www/addons/myoverview/lang/eu.json
@@ -6,13 +6,13 @@
"next7days": "Datozen 7 egunetan",
"nocourses": "Ez dago ikastarorik",
"nocoursesfuture": "Ez dago ikastarorik etorkizunean",
- "nocoursesinprogress": "",
+ "nocoursesinprogress": "Ez dago martxan dagoen ikastarorik",
"nocoursespast": "Ez dago ikastarorik iraganean",
- "noevents": "",
+ "noevents": "Ez dago jardueren muga-egunik laster",
"past": "Iragana",
- "pluginname": "",
- "recentlyoverdue": "",
+ "pluginname": "Ikuspegi orokorra",
+ "recentlyoverdue": "Orain dela gutxi iragotako muga-egunak",
"sortbycourses": "Ordenatu ikastaroen arabera",
"sortbydates": "Ordenatu dataren arabera",
- "timeline": ""
+ "timeline": "Kronologia"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/fr.json b/www/addons/myoverview/lang/fr.json
index 266d636a4b5..2a74ad739d4 100644
--- a/www/addons/myoverview/lang/fr.json
+++ b/www/addons/myoverview/lang/fr.json
@@ -10,7 +10,7 @@
"nocoursespast": "Pas de cours dans le passé",
"noevents": "Aucune activité",
"past": "Passé",
- "pluginname": "Vue d'ensemble du cours",
+ "pluginname": "Vue d'ensemble des cours",
"recentlyoverdue": "Récemment en retard",
"sortbycourses": "Tri par cours",
"sortbydates": "Tri par date",
diff --git a/www/addons/myoverview/lang/he.json b/www/addons/myoverview/lang/he.json
index 2c8bcae7be2..d0b13672129 100644
--- a/www/addons/myoverview/lang/he.json
+++ b/www/addons/myoverview/lang/he.json
@@ -1,7 +1,7 @@
{
"future": "עתידי",
"inprogress": "בלמידה",
- "morecourses": "",
+ "morecourses": "קורסים נוספים",
"next30days": "ב 30 הימים הבאים",
"next7days": "ב 7 הימים הבאים",
"nocourses": "טרם נרשמתם לקורס כלשהו",
@@ -10,7 +10,7 @@
"nocoursespast": "אינכם רשומים לקורס אשר הסתיימו",
"noevents": "לא קיימות פעילויות עתידיות להן מועד הגשה",
"past": "עבר",
- "pluginname": "עדכונים בקורסים שלי",
+ "pluginname": "סקירה כללית",
"recentlyoverdue": "מועד־ההגשה עבר, לאחרונה",
"sortbycourses": "מיון לפי שמות קורסים",
"sortbydates": "מיון לפי תאריכים",
diff --git a/www/addons/myoverview/lang/it.json b/www/addons/myoverview/lang/it.json
index 3e157ff6e5c..cca29fb3c13 100644
--- a/www/addons/myoverview/lang/it.json
+++ b/www/addons/myoverview/lang/it.json
@@ -1,17 +1,17 @@
{
- "future": "",
- "inprogress": "",
- "morecourses": "",
- "next30days": "",
- "next7days": "",
+ "future": "Prossimi",
+ "inprogress": "In svolgimento",
+ "morecourses": "Altri corsi",
+ "next30days": "Prossimi 30 giorni",
+ "next7days": "Prossimi 7 giorni",
"nocourses": "Non ci sono corsi",
- "nocoursesfuture": "",
+ "nocoursesfuture": "Non ci sono corsi di prossima attivazione",
"nocoursesinprogress": "Non ci sono corsi in svolgimento",
- "nocoursespast": "",
+ "nocoursespast": "Non ci sono corsi conclusi",
"noevents": "Non ci sono attività da svolgere",
- "past": "",
+ "past": "Conclusi",
"pluginname": "Panoramica corsi",
- "recentlyoverdue": "",
+ "recentlyoverdue": "Scadute di recente",
"sortbycourses": "Ordina per corso",
"sortbydates": "Ordina per data",
"timeline": "Cronologia"
diff --git a/www/addons/myoverview/lang/ja.json b/www/addons/myoverview/lang/ja.json
index 3671d43e7ee..af5dc09b17a 100644
--- a/www/addons/myoverview/lang/ja.json
+++ b/www/addons/myoverview/lang/ja.json
@@ -1,11 +1,11 @@
{
- "future": "今後",
+ "future": "未来",
"inprogress": "進行中",
"morecourses": "コースをさらに",
"next30days": "次の30日",
"next7days": "次の7日",
"nocourses": "コースなし",
- "nocoursesfuture": "今後のコースはありません。",
+ "nocoursesfuture": "未来のコースはありません。",
"nocoursesinprogress": "進行中のコースはありません。",
"nocoursespast": "過去のコースはありません。",
"noevents": "到来する活動期限はありません。",
diff --git a/www/addons/myoverview/lang/lt.json b/www/addons/myoverview/lang/lt.json
index cba79f81ce3..c7d17b3aea6 100644
--- a/www/addons/myoverview/lang/lt.json
+++ b/www/addons/myoverview/lang/lt.json
@@ -1,5 +1,18 @@
{
- "inprogress": "Nebaigta",
- "nocourses": "Nėra rodytinos kursų informacijos",
- "pluginname": "Saugyklos priedo pavadinimas"
+ "future": "Būsimi",
+ "inprogress": "Vykstantys",
+ "morecourses": "Daugiau kursų",
+ "next30days": "Kitas 30 dienų",
+ "next7days": "Kitas 7 dienas",
+ "nocourses": "Nėra kursų",
+ "nocoursesfuture": "Nėra būsimų kursų",
+ "nocoursesinprogress": "Nėra vykstančių kursų",
+ "nocoursespast": "Nėra pasibaigusių kursų",
+ "noevents": "Nėra numatytų artėjančių veiklų",
+ "past": "Pasibaigę",
+ "pluginname": "Kursų apžvalga",
+ "recentlyoverdue": "Neseniai pavėluotas",
+ "sortbycourses": "Rūšiuoti pagal kursus",
+ "sortbydates": "Rūšiuoti pagal datą",
+ "timeline": "Laiko skalė"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/pl.json b/www/addons/myoverview/lang/pl.json
index 08052becbb2..26323a8f098 100644
--- a/www/addons/myoverview/lang/pl.json
+++ b/www/addons/myoverview/lang/pl.json
@@ -1,5 +1,18 @@
{
- "inprogress": "W toku",
- "nocourses": "Nie ma informacji do pokazania",
- "pluginname": "Nazwa wtyczki repozytorium"
+ "future": "Nadchodzące",
+ "inprogress": "Aktualne",
+ "morecourses": "Więcej kursów",
+ "next30days": "Następne 30 dni",
+ "next7days": "Następne 7 dni",
+ "nocourses": "Brak kursów",
+ "nocoursesfuture": "Brak nadchodzących kursów",
+ "nocoursesinprogress": "Brak aktualnych kursów",
+ "nocoursespast": "Brak zakończonych kursów",
+ "noevents": "Brak nadchodzących terminów zadań",
+ "past": "Zakończone",
+ "pluginname": "Przegląd kursu",
+ "recentlyoverdue": "Obecnie opóźnione",
+ "sortbycourses": "Sortuj wg kursów",
+ "sortbydates": "Sortuj wg dat",
+ "timeline": "Porządek chronologiczny"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/pt-br.json b/www/addons/myoverview/lang/pt-br.json
index c02df1adb37..f768881904f 100644
--- a/www/addons/myoverview/lang/pt-br.json
+++ b/www/addons/myoverview/lang/pt-br.json
@@ -1,5 +1,18 @@
{
+ "future": "Não iniciados",
"inprogress": "Em andamento",
- "nocourses": "Nenhuma informação disponível sobre o curso.",
- "pluginname": "Nome do plugin de repositório"
+ "morecourses": "Mais cursos",
+ "next30days": "Próximos 30 dias",
+ "next7days": "Próximos 7 dias",
+ "nocourses": "Não há cursos",
+ "nocoursesfuture": "Não há cursos não iniciados",
+ "nocoursesinprogress": "Não há cursos em andamento",
+ "nocoursespast": "Não há cursos encerrados",
+ "noevents": "Não há atividades pendentes",
+ "past": "Encerrados",
+ "pluginname": "Resumo dos cursos",
+ "recentlyoverdue": "Atividades atrasadas",
+ "sortbycourses": "Ordenar por cursos",
+ "sortbydates": "Ordenar por data",
+ "timeline": "Linha do tempo"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/pt.json b/www/addons/myoverview/lang/pt.json
index b019a3830aa..1c084d2e2f3 100644
--- a/www/addons/myoverview/lang/pt.json
+++ b/www/addons/myoverview/lang/pt.json
@@ -1,5 +1,18 @@
{
+ "future": "Futuro",
"inprogress": "Em progresso",
- "nocourses": "Sem informação das suas disciplinas para mostrar.",
- "pluginname": "Nome do módulo de repositório"
+ "morecourses": "Mais disciplinas",
+ "next30days": "Próximos 30 dias",
+ "next7days": "Próximos 7 dias",
+ "nocourses": "Sem disciplinas",
+ "nocoursesfuture": "Nenhuma disciplina a começar",
+ "nocoursesinprogress": "Nenhuma disciplina a decorrer",
+ "nocoursespast": "Nenhuma disciplina terminada",
+ "noevents": "Nenhuma atividade programada",
+ "past": "Passado",
+ "pluginname": "Vista geral",
+ "recentlyoverdue": "Terminadas recentemente",
+ "sortbycourses": "Ordenar por disciplinas",
+ "sortbydates": "Ordenar por datas",
+ "timeline": "Cronograma"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/ru.json b/www/addons/myoverview/lang/ru.json
index fbfa8f8a870..1a29c7d620b 100644
--- a/www/addons/myoverview/lang/ru.json
+++ b/www/addons/myoverview/lang/ru.json
@@ -1,5 +1,18 @@
{
+ "future": "Будущие",
"inprogress": "В процессе",
- "nocourses": "Нет информации для отображения.",
- "pluginname": "Имя плагина хранилища"
+ "morecourses": "Больше курсов",
+ "next30days": "Следующие 30 дней",
+ "next7days": "Следующие 7 дней",
+ "nocourses": "Нет курсов",
+ "nocoursesfuture": "Нет будущих курсов",
+ "nocoursesinprogress": "Нет курсов в процессе",
+ "nocoursespast": "Нет прошлых курсов",
+ "noevents": "Нет предстоящих заданий",
+ "past": "Прошлые",
+ "pluginname": "Обзор курсов",
+ "recentlyoverdue": "Недавно пропущенное",
+ "sortbycourses": "Сортировать по курсам",
+ "sortbydates": "Сортировать по датам",
+ "timeline": "Обзор"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/sr-cr.json b/www/addons/myoverview/lang/sr-cr.json
new file mode 100644
index 00000000000..218f9ebde77
--- /dev/null
+++ b/www/addons/myoverview/lang/sr-cr.json
@@ -0,0 +1,18 @@
+{
+ "future": "Будући",
+ "inprogress": "У току",
+ "morecourses": "Више курсева",
+ "next30days": "Следећих 30 дана",
+ "next7days": "Следећих 7 дана",
+ "nocourses": "Нема курсева",
+ "nocoursesfuture": "Нема будућих курсева",
+ "nocoursesinprogress": "Нема курсева који су току",
+ "nocoursespast": "Нема прошлих курсева",
+ "noevents": "Нема активности које се ускоро завршавају",
+ "past": "Прошли",
+ "pluginname": "Преглед курсева",
+ "recentlyoverdue": "Недавно завршене активности",
+ "sortbycourses": "Сортирај по курсевима",
+ "sortbydates": "Сортирају по датумима",
+ "timeline": "Временски распоред"
+}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/sr-lt.json b/www/addons/myoverview/lang/sr-lt.json
new file mode 100644
index 00000000000..953d764faa8
--- /dev/null
+++ b/www/addons/myoverview/lang/sr-lt.json
@@ -0,0 +1,18 @@
+{
+ "future": "Budući",
+ "inprogress": "U toku",
+ "morecourses": "Više kurseva",
+ "next30days": "Sledećih 30 dana",
+ "next7days": "Sledećih 7 dana",
+ "nocourses": "Nema kurseva",
+ "nocoursesfuture": "Nema budućih kurseva",
+ "nocoursesinprogress": "Nema kurseva koji su toku",
+ "nocoursespast": "Nema prošlih kurseva",
+ "noevents": "Nema aktivnosti koje se uskoro završavaju",
+ "past": "Prošli",
+ "pluginname": "Pregled kurseva",
+ "recentlyoverdue": "Nedavno završene aktivnosti",
+ "sortbycourses": "Sortiraj po kursevima",
+ "sortbydates": "Sortiraju po datumima",
+ "timeline": "Vremenski raspored"
+}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/sv.json b/www/addons/myoverview/lang/sv.json
index 977e7631d0d..004122c5c20 100644
--- a/www/addons/myoverview/lang/sv.json
+++ b/www/addons/myoverview/lang/sv.json
@@ -1,5 +1,16 @@
{
- "inprogress": "Pågår",
- "nocourses": "Det finns ingen kursinformation att visa.",
- "pluginname": "Namn på plugin-program för arkiv"
+ "future": "Kommande",
+ "inprogress": "Pågående",
+ "morecourses": "Fler kurser",
+ "next30days": "30 dagar framåt",
+ "next7days": "7 dagar framåt",
+ "nocourses": "Inga kurser",
+ "nocoursesfuture": "Inga kommande kurser",
+ "nocoursesinprogress": "Inga pågående kurser",
+ "nocoursespast": "Inga tidigare kurser",
+ "past": "Tidigare",
+ "pluginname": "Kursöversikt",
+ "sortbycourses": "Sortera efter kurser",
+ "sortbydates": "Sortera efter datum",
+ "timeline": "Tidslinje"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/uk.json b/www/addons/myoverview/lang/uk.json
new file mode 100644
index 00000000000..1b4fb0f4e46
--- /dev/null
+++ b/www/addons/myoverview/lang/uk.json
@@ -0,0 +1,18 @@
+{
+ "future": "Заплановані",
+ "inprogress": "В процесі",
+ "morecourses": "Більше курсів",
+ "next30days": "Наступні 30 днів",
+ "next7days": "Наступні 7 днів",
+ "nocourses": "Курси відсутні",
+ "nocoursesfuture": "Немає запланових курсів",
+ "nocoursesinprogress": "Курси в прогресі відсутні",
+ "nocoursespast": "Пройдені курси відсутні",
+ "noevents": "Наразі, заплановані активності відсутні",
+ "past": "Минулі",
+ "pluginname": "Огляд курсу",
+ "recentlyoverdue": "Нещодавно прострочені",
+ "sortbycourses": "Сортувати за назвою курсів",
+ "sortbydates": "Сортувати за датою",
+ "timeline": "Часова пряма"
+}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/zh-cn.json b/www/addons/myoverview/lang/zh-cn.json
index ce98820d486..0694737081f 100644
--- a/www/addons/myoverview/lang/zh-cn.json
+++ b/www/addons/myoverview/lang/zh-cn.json
@@ -1,5 +1,18 @@
{
- "inprogress": "处理中",
- "nocourses": "没有可显示的课程信息。",
- "pluginname": "容器插件名"
+ "future": "未来",
+ "inprogress": "进行中",
+ "morecourses": "更多课程",
+ "next30days": "下一月",
+ "next7days": "下一周",
+ "nocourses": "没有课程",
+ "nocoursesfuture": "没有未来的课程",
+ "nocoursesinprogress": "没有进行中的课程",
+ "nocoursespast": "没有过去的课程",
+ "noevents": "没有即将到期的活动",
+ "past": "过去",
+ "pluginname": "课程概览",
+ "recentlyoverdue": "最近逾期的",
+ "sortbycourses": "按课程排序",
+ "sortbydates": "按日期排序",
+ "timeline": "时间进度"
}
\ No newline at end of file
diff --git a/www/addons/myoverview/lang/zh-tw.json b/www/addons/myoverview/lang/zh-tw.json
index 18cfa0860fc..16d60ff4766 100644
--- a/www/addons/myoverview/lang/zh-tw.json
+++ b/www/addons/myoverview/lang/zh-tw.json
@@ -11,7 +11,7 @@
"noevents": "沒有即將到期的活動",
"past": "過去",
"pluginname": "課程概觀",
- "recentlyoverdue": "",
+ "recentlyoverdue": "最近逾期的",
"sortbycourses": "依課程排序",
"sortbydates": "依日期排序",
"timeline": "時間軸"
diff --git a/www/addons/notes/lang/ar.json b/www/addons/notes/lang/ar.json
index df8de0cf069..30b58e0c705 100644
--- a/www/addons/notes/lang/ar.json
+++ b/www/addons/notes/lang/ar.json
@@ -2,7 +2,7 @@
"addnewnote": "إضافة ملاحظة جديدة",
"coursenotes": "ملاحظات المقرر الدراسي",
"note": "ملحوظة",
- "notes": "تحليلك وملاحظاتك الخاصة",
+ "notes": "ملاحظات",
"personalnotes": "ملاحظات شخصية",
"publishstate": "السياق",
"sitenotes": "ملاحظات الموقع"
diff --git a/www/addons/notes/lang/bg.json b/www/addons/notes/lang/bg.json
index 606e3b6a09d..89cc6664d9d 100644
--- a/www/addons/notes/lang/bg.json
+++ b/www/addons/notes/lang/bg.json
@@ -4,7 +4,7 @@
"eventnotecreated": "Бележката създадена",
"nonotes": "Все още няма бележки от този тип.",
"note": "Бележка",
- "notes": "Бележки",
+ "notes": "Вашият личен анализ и бележки",
"personalnotes": "Лични бележки",
"publishstate": "Контекст",
"sitenotes": "Бележки за сайта"
diff --git a/www/addons/notes/lang/da.json b/www/addons/notes/lang/da.json
index cf35362b164..3dadb18f0eb 100644
--- a/www/addons/notes/lang/da.json
+++ b/www/addons/notes/lang/da.json
@@ -4,7 +4,7 @@
"eventnotecreated": "Note oprettet",
"nonotes": "Der er endnu ingen noter af denne type",
"note": "Note",
- "notes": "Dine private kommentarer og noter",
+ "notes": "Noter",
"personalnotes": "Personlige noter",
"publishstate": "Sammenhæng",
"sitenotes": "Webstedsnoter",
diff --git a/www/addons/notes/lang/es_mx.json b/www/addons/notes/lang/es_mx.json
deleted file mode 100644
index 0eb20a78105..00000000000
--- a/www/addons/notes/lang/es_mx.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "addnewnote": "Añadir una nota nueva",
- "coursenotes": "Notas del curso",
- "eventnotecreated": "Nota creada",
- "note": "Nota",
- "personalnotes": "Notas personales",
- "publishstate": "Contexto",
- "sitenotes": "Notas del sitio"
-}
\ No newline at end of file
diff --git a/www/addons/notes/lang/he.json b/www/addons/notes/lang/he.json
index 2e3c5dd9644..416427b2dec 100644
--- a/www/addons/notes/lang/he.json
+++ b/www/addons/notes/lang/he.json
@@ -4,7 +4,7 @@
"eventnotecreated": "הערה נוצרה",
"nonotes": "עדיין לא קיימות הערות מסוג זה",
"note": "הערה",
- "notes": "ההערות והניתוח הפרטיים שלך.",
+ "notes": "הערות",
"personalnotes": "הערות אישיות",
"publishstate": "תוכן",
"sitenotes": "הערות אתר",
diff --git a/www/addons/notes/lang/ja.json b/www/addons/notes/lang/ja.json
index 31c68f19f28..6b3304c8067 100644
--- a/www/addons/notes/lang/ja.json
+++ b/www/addons/notes/lang/ja.json
@@ -1,10 +1,13 @@
{
- "addnewnote": "新しいノートを追加する",
+ "addnewnote": "新しいノートを追加",
"coursenotes": "コースノート",
- "eventnotecreated": "ノートが作成されました。",
+ "eventnotecreated": "作成したノート",
+ "nonotes": "このタイプのノートはまだ存在しません",
"note": "ノート",
- "notes": "あなたの個人分析およびノート",
+ "notes": "ノート",
"personalnotes": "パーソナルノート",
- "publishstate": "コンテクスト",
- "sitenotes": "サイトノート"
+ "publishstate": "コンテキスト",
+ "sitenotes": "サイトノート",
+ "userwithid": "ID {{id}} のユーザ",
+ "warningnotenotsent": "コース {{course}} にノートを追加することができません。 {{error}}"
}
\ No newline at end of file
diff --git a/www/addons/notes/lang/pt_br.json b/www/addons/notes/lang/pt_br.json
deleted file mode 100644
index 3d49facd550..00000000000
--- a/www/addons/notes/lang/pt_br.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "addnewnote": "Escrever uma nova anotação",
- "coursenotes": "Anotações do Curso",
- "eventnotecreated": "Anotação criada",
- "note": "Anotação",
- "personalnotes": "Anotações individuais",
- "publishstate": "Estado",
- "sitenotes": "Anotações do site"
-}
\ No newline at end of file
diff --git a/www/addons/notes/lang/ro.json b/www/addons/notes/lang/ro.json
index 605a02f2299..1115becc8d5 100644
--- a/www/addons/notes/lang/ro.json
+++ b/www/addons/notes/lang/ro.json
@@ -4,7 +4,7 @@
"eventnotecreated": "A fost creată o notă",
"nonotes": "Momentan nu există note de acest tip",
"note": "Notă",
- "notes": "Note",
+ "notes": "Analiza şi notele tale particulare",
"personalnotes": "Note personale",
"publishstate": "Context",
"sitenotes": "Note de site",
diff --git a/www/addons/notes/lang/sr-cr.json b/www/addons/notes/lang/sr-cr.json
new file mode 100644
index 00000000000..0690900c3c5
--- /dev/null
+++ b/www/addons/notes/lang/sr-cr.json
@@ -0,0 +1,13 @@
+{
+ "addnewnote": "Додај нову белешку",
+ "coursenotes": "Белешке курса",
+ "eventnotecreated": "Белешка креирана",
+ "nonotes": "Још не постоје белешке овог типа",
+ "note": "Белешка",
+ "notes": "Белешке",
+ "personalnotes": "Личне белешке",
+ "publishstate": "Контекст",
+ "sitenotes": "Белешке сајта",
+ "userwithid": "Корисник са ID ознаком {{id}}",
+ "warningnotenotsent": "Није могуће додати белешку/е курсу {{course}}. {{error}}"
+}
\ No newline at end of file
diff --git a/www/addons/notes/lang/sr-lt.json b/www/addons/notes/lang/sr-lt.json
new file mode 100644
index 00000000000..d4a1ef87e7f
--- /dev/null
+++ b/www/addons/notes/lang/sr-lt.json
@@ -0,0 +1,13 @@
+{
+ "addnewnote": "Dodaj novu belešku",
+ "coursenotes": "Beleške kursa",
+ "eventnotecreated": "Beleška kreirana",
+ "nonotes": "Još ne postoje beleške ovog tipa",
+ "note": "Beleška",
+ "notes": "Beleške",
+ "personalnotes": "Lične beleške",
+ "publishstate": "Kontekst",
+ "sitenotes": "Beleške sajta",
+ "userwithid": "Korisnik sa ID oznakom {{id}}",
+ "warningnotenotsent": "Nije moguće dodati belešku/e kursu {{course}}. {{error}}"
+}
\ No newline at end of file
diff --git a/www/addons/notes/lang/uk.json b/www/addons/notes/lang/uk.json
index 8f58e17054e..8c815080c16 100644
--- a/www/addons/notes/lang/uk.json
+++ b/www/addons/notes/lang/uk.json
@@ -9,5 +9,5 @@
"publishstate": "Контекст",
"sitenotes": "Записки сайту",
"userwithid": "Користувач з Id {{id}}",
- "warningnotenotsent": "Неможливо додати записку до курсу{{course}}. {{error}}"
+ "warningnotenotsent": "Неможливо додати записку до курсу {{course}}. {{error}}"
}
\ No newline at end of file
diff --git a/www/addons/notes/lang/zh_cn.json b/www/addons/notes/lang/zh_cn.json
deleted file mode 100644
index 786909fa20c..00000000000
--- a/www/addons/notes/lang/zh_cn.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "addnewnote": "添加新备注",
- "coursenotes": "课程备注",
- "eventnotecreated": "创建了笔记",
- "note": "备注",
- "personalnotes": "私人备注",
- "publishstate": "上下文",
- "sitenotes": "全站备注"
-}
\ No newline at end of file
diff --git a/www/addons/notes/lang/zh_tw.json b/www/addons/notes/lang/zh_tw.json
deleted file mode 100644
index 2b90c1325c7..00000000000
--- a/www/addons/notes/lang/zh_tw.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "addnewnote": "添加一筆新註記",
- "coursenotes": "課程註記",
- "eventnotecreated": "已建立註記",
- "note": "註記",
- "personalnotes": "個人的註記",
- "publishstate": "使用的情境",
- "sitenotes": "網站註記"
-}
\ No newline at end of file
diff --git a/www/addons/notifications/controllers/preferences.js b/www/addons/notifications/controllers/preferences.js
index 226a12fcaab..efe6168083f 100644
--- a/www/addons/notifications/controllers/preferences.js
+++ b/www/addons/notifications/controllers/preferences.js
@@ -23,23 +23,26 @@ angular.module('mm.addons.notifications')
*/
.controller('mmaNotificationsPreferencesCtrl', function($scope, $mmaNotifications, $mmUtil, $ionicPlatform, $mmUser, $mmConfig,
$mmaMessageOutputDelegate, $q, $timeout, $mmSettingsHelper, mmCoreSettingsNotificationSound, $mmLocalNotifications,
- $mmEvents, mmCoreEventNotificationSoundChanged) {
+ $mmEvents, mmCoreEventNotificationSoundChanged, $mmApp) {
var updateTimeout;
$scope.isTablet = $ionicPlatform.isTablet();
$scope.notifPrefsEnabled = $mmaNotifications.isNotificationPreferencesEnabled();
+ $scope.canChangeSound = $mmLocalNotifications.isAvailable() && !$mmApp.isDesktop();
- // Notification sound setting.
- $mmConfig.get(mmCoreSettingsNotificationSound, true).then(function(enabled) {
- $scope.notificationSound = enabled;
- });
+ if ($scope.canChangeSound) {
+ // Notification sound setting.
+ $mmConfig.get(mmCoreSettingsNotificationSound, true).then(function(enabled) {
+ $scope.notificationSound = enabled;
+ });
- $scope.notificationSoundChanged = function(enabled) {
- $mmConfig.set(mmCoreSettingsNotificationSound, enabled);
- $mmEvents.trigger(mmCoreEventNotificationSoundChanged, enabled);
- $mmLocalNotifications.rescheduleAll();
- };
+ $scope.notificationSoundChanged = function(enabled) {
+ $mmConfig.set(mmCoreSettingsNotificationSound, enabled);
+ $mmEvents.trigger(mmCoreEventNotificationSoundChanged, enabled);
+ $mmLocalNotifications.rescheduleAll();
+ };
+ }
if (!$scope.notifPrefsEnabled) {
// Notification preferences aren't enabled, stop.
diff --git a/www/addons/notifications/lang/ar.json b/www/addons/notifications/lang/ar.json
index cab5daac101..edbc8f11446 100644
--- a/www/addons/notifications/lang/ar.json
+++ b/www/addons/notifications/lang/ar.json
@@ -1,5 +1,5 @@
{
"errorgetnotifications": "خطأ في الحصول على الإشعارات",
- "notifications": "إشعارات",
+ "notifications": "الإشعارات",
"therearentnotificationsyet": "لا توجد إشعارات"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/da.json b/www/addons/notifications/lang/da.json
index 2e190040f35..56219f0789c 100644
--- a/www/addons/notifications/lang/da.json
+++ b/www/addons/notifications/lang/da.json
@@ -1,6 +1,6 @@
{
"errorgetnotifications": "Fejl ved hentning af underretninger",
"notificationpreferences": "Indstillinger for underretninger",
- "notifications": "Beskeder",
+ "notifications": "Underretninger",
"therearentnotificationsyet": "Der er ingen underretninger"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/de.json b/www/addons/notifications/lang/de.json
index 6dc2a08c68c..4175d5121e3 100644
--- a/www/addons/notifications/lang/de.json
+++ b/www/addons/notifications/lang/de.json
@@ -2,6 +2,6 @@
"errorgetnotifications": "Fehler beim Laden der Mitteilungen",
"notificationpreferences": "Systemmitteilungen",
"notifications": "Systemmitteilungen",
- "playsound": "Audio abspielen",
+ "playsound": "Signalton abspielen",
"therearentnotificationsyet": "Keine Mitteilungen"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/el.json b/www/addons/notifications/lang/el.json
index 287c60968cc..d5d645008b8 100644
--- a/www/addons/notifications/lang/el.json
+++ b/www/addons/notifications/lang/el.json
@@ -2,5 +2,6 @@
"errorgetnotifications": "Σφάλμα κατά τη λήψη ειδοποιήσεων",
"notificationpreferences": "Προτιμήσεις ειδοποιήσεων",
"notifications": "Ειδοποιήσεις",
+ "playsound": "Αναπαραγωγή ήχου",
"therearentnotificationsyet": "Δεν υπάρχουν ειδοποιήσεις"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/es.json b/www/addons/notifications/lang/es.json
index e73e272de69..db11ade05af 100644
--- a/www/addons/notifications/lang/es.json
+++ b/www/addons/notifications/lang/es.json
@@ -2,5 +2,6 @@
"errorgetnotifications": "Error al obtener notificaciones",
"notificationpreferences": "Preferencias de notificaciones",
"notifications": "Notificaciones",
+ "playsound": "Reproducir sonido",
"therearentnotificationsyet": "No hay notificaciones"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/es_mx.json b/www/addons/notifications/lang/es_mx.json
deleted file mode 100644
index 80b4b5e0dbc..00000000000
--- a/www/addons/notifications/lang/es_mx.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "notifications": "Notificaciones",
- "therearentnotificationsyet": "No hay notificaciones"
-}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/fa.json b/www/addons/notifications/lang/fa.json
index dcfecb86fba..f641bf74805 100644
--- a/www/addons/notifications/lang/fa.json
+++ b/www/addons/notifications/lang/fa.json
@@ -1,5 +1,5 @@
{
"notificationpreferences": "ترجیحات اطلاعیهها",
- "notifications": "هشدارها",
+ "notifications": "تذکرات",
"therearentnotificationsyet": "هیچ هشداری وجود ندارد"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/fr.json b/www/addons/notifications/lang/fr.json
index edb4a631896..f5c2621dbba 100644
--- a/www/addons/notifications/lang/fr.json
+++ b/www/addons/notifications/lang/fr.json
@@ -2,5 +2,6 @@
"errorgetnotifications": "Erreur lors de la récupération des notifications.",
"notificationpreferences": "Préférences de notification",
"notifications": "Notifications",
+ "playsound": "Jouer le son",
"therearentnotificationsyet": "Aucune notification"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/he.json b/www/addons/notifications/lang/he.json
index 39e5a6ed7a5..1c1591b94ed 100644
--- a/www/addons/notifications/lang/he.json
+++ b/www/addons/notifications/lang/he.json
@@ -1,6 +1,6 @@
{
"errorgetnotifications": "שגיאה בטעינת התראות",
"notificationpreferences": "העדפות הודעות",
- "notifications": "עדכונים והודעות",
+ "notifications": "התראות",
"therearentnotificationsyet": "אין התראות"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/ja.json b/www/addons/notifications/lang/ja.json
index a253cfba0ae..22daa00358e 100644
--- a/www/addons/notifications/lang/ja.json
+++ b/www/addons/notifications/lang/ja.json
@@ -1,5 +1,7 @@
{
- "notificationpreferences": "通知プリファレンス",
+ "errorgetnotifications": "通知の取得中にエラーが発生しました。",
+ "notificationpreferences": "通知の設定",
"notifications": "通知",
+ "playsound": "音を出力",
"therearentnotificationsyet": "通知はありません"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/pt_br.json b/www/addons/notifications/lang/pt_br.json
deleted file mode 100644
index 3913f917f41..00000000000
--- a/www/addons/notifications/lang/pt_br.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "notifications": "Notificação",
- "therearentnotificationsyet": "Não há notificações"
-}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/ru.json b/www/addons/notifications/lang/ru.json
index 46e6247828f..3bb79943f46 100644
--- a/www/addons/notifications/lang/ru.json
+++ b/www/addons/notifications/lang/ru.json
@@ -2,5 +2,6 @@
"errorgetnotifications": "Ошибка получения уведомления",
"notificationpreferences": "Настройка уведомлений",
"notifications": "Уведомления",
+ "playsound": "Проигрывать звук",
"therearentnotificationsyet": "Уведомлений нет"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/sr-cr.json b/www/addons/notifications/lang/sr-cr.json
new file mode 100644
index 00000000000..f45f0611020
--- /dev/null
+++ b/www/addons/notifications/lang/sr-cr.json
@@ -0,0 +1,7 @@
+{
+ "errorgetnotifications": "Грешка приликом преузимања обавештења",
+ "notificationpreferences": "Параметри обавештења",
+ "notifications": "Обавештења",
+ "playsound": "Репродукуј звук",
+ "therearentnotificationsyet": "Нема обавештења"
+}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/sr-lt.json b/www/addons/notifications/lang/sr-lt.json
new file mode 100644
index 00000000000..74bfd3d17cb
--- /dev/null
+++ b/www/addons/notifications/lang/sr-lt.json
@@ -0,0 +1,7 @@
+{
+ "errorgetnotifications": "Greška prilikom preuzimanja obaveštenja",
+ "notificationpreferences": "Parametri obaveštenja",
+ "notifications": "Obaveštenja",
+ "playsound": "Reprodukuj zvuk",
+ "therearentnotificationsyet": "Nema obaveštenja"
+}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/sv.json b/www/addons/notifications/lang/sv.json
index 2aa4e69322a..8029962c563 100644
--- a/www/addons/notifications/lang/sv.json
+++ b/www/addons/notifications/lang/sv.json
@@ -1,5 +1,6 @@
{
"errorgetnotifications": "Fel att få meddelanden",
+ "notificationpreferences": "Välj inställningar för notiser",
"notifications": "Meddelanden",
"therearentnotificationsyet": "Det finns inga meddelanden"
}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/zh_cn.json b/www/addons/notifications/lang/zh_cn.json
deleted file mode 100644
index 7d236d7f15d..00000000000
--- a/www/addons/notifications/lang/zh_cn.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "notifications": "通知",
- "therearentnotificationsyet": "没有通知"
-}
\ No newline at end of file
diff --git a/www/addons/notifications/lang/zh_tw.json b/www/addons/notifications/lang/zh_tw.json
deleted file mode 100644
index 957a61b5db7..00000000000
--- a/www/addons/notifications/lang/zh_tw.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "notifications": "通知",
- "therearentnotificationsyet": "沒有通知訊息"
-}
\ No newline at end of file
diff --git a/www/addons/notifications/main.js b/www/addons/notifications/main.js
index 715ca9acb8d..d178e938f10 100644
--- a/www/addons/notifications/main.js
+++ b/www/addons/notifications/main.js
@@ -19,6 +19,7 @@ angular.module('mm.addons.notifications', [])
.constant('mmaNotificationsPreferencesPriority', 500)
.constant('mmaNotificationsReadChangedEvent', 'mma-notifications_read_changed')
.constant('mmaNotificationsReadCronEvent', 'mma-notifications_read_cron')
+.constant('mmaNotificationsPushSimulationComponent', 'mmaNotificationsPushSimulation')
.config(function($stateProvider, $mmSideMenuDelegateProvider, mmaNotificationsPriority, $mmSettingsDelegateProvider,
mmaNotificationsPreferencesPriority) {
@@ -53,7 +54,8 @@ angular.module('mm.addons.notifications', [])
'$mmaNotificationsHandlers.preferences', mmaNotificationsPreferencesPriority);
})
-.run(function($log, $mmaNotifications, $mmUtil, $state, $mmAddonManager, $mmCronDelegate, $mmSitesManager) {
+.run(function($log, $mmaNotifications, $mmUtil, $state, $mmAddonManager, $mmCronDelegate, $mmSitesManager, $mmLocalNotifications,
+ $mmApp, mmaNotificationsPushSimulationComponent) {
$log = $log.getInstance('mmaNotifications');
// Register push notification clicks.
@@ -61,19 +63,7 @@ angular.module('mm.addons.notifications', [])
if ($mmPushNotificationsDelegate) {
$mmPushNotificationsDelegate.registerHandler('mmaNotifications', function(notification) {
if ($mmUtil.isTrueOrOne(notification.notif)) {
- $mmaNotifications.isPluginEnabledForSite(notification.site).then(function() {
- $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaNotifications', notification.site)
- .then(function(disabled) {
- if (disabled) {
- // Notifications are disabled, stop.
- return;
- }
-
- $mmaNotifications.invalidateNotificationsList().finally(function() {
- $state.go('redirect', {siteid: notification.site, state: 'site.notifications'});
- });
- });
- });
+ notificationClicked(notification);
return true;
}
});
@@ -81,4 +71,26 @@ angular.module('mm.addons.notifications', [])
// Register sync process.
$mmCronDelegate.register('mmaNotificationsMenu', '$mmaNotificationsHandlers.sideMenuNav');
+
+ if ($mmApp.isDesktop()) {
+ // Listen for clicks in simulated push notifications.
+ $mmLocalNotifications.registerClick(mmaNotificationsPushSimulationComponent, notificationClicked);
+ }
+
+ // A push notification belonging to notifications was clicked.
+ function notificationClicked(notification) {
+ return $mmaNotifications.isPluginEnabledForSite(notification.site).then(function() {
+ $mmSitesManager.isFeatureDisabled('$mmSideMenuDelegate_mmaNotifications', notification.site)
+ .then(function(disabled) {
+ if (disabled) {
+ // Notifications are disabled, stop.
+ return;
+ }
+
+ $mmaNotifications.invalidateNotificationsList().finally(function() {
+ $state.go('redirect', {siteid: notification.site, state: 'site.notifications'});
+ });
+ });
+ });
+ }
});
diff --git a/www/addons/notifications/services/handlers.js b/www/addons/notifications/services/handlers.js
index f832baa8c98..9dd39235d82 100644
--- a/www/addons/notifications/services/handlers.js
+++ b/www/addons/notifications/services/handlers.js
@@ -24,11 +24,38 @@ angular.module('mm.addons.notifications')
* @name $mmaNotificationsHandlers
*/
.factory('$mmaNotificationsHandlers', function($log, $mmaNotifications, $mmEvents, $mmSitesManager, $mmUtil, $mmSite,
- mmaNotificationsReadChangedEvent, mmaNotificationsReadCronEvent, $mmAddonManager) {
+ mmaNotificationsReadChangedEvent, mmaNotificationsReadCronEvent, $mmAddonManager, $mmApp, $mmLocalNotifications,
+ $mmEmulatorHelper, $mmText, mmaNotificationsPushSimulationComponent) {
$log = $log.getInstance('$mmaNotificationsHandlers');
var self = {};
+ /**
+ * Get the latest unread notifications from a site.
+ *
+ * @param {String} siteId Site ID.
+ * @return {Promise} Promise resolved with the notifications.
+ */
+ function fetchNotifications(siteId) {
+ return $mmaNotifications.getUnreadNotifications(0, undefined, true, false, true, siteId);
+ }
+
+ /**
+ * Given a notification, return the title and the text for the notification.
+ *
+ * @param {Object} notification Notification.
+ * @return {Object} Object with title and text.
+ */
+ function getTitleAndText(notification) {
+ var data = {
+ title: notification.userfromfullname,
+ text: notification.mobiletext.replace(/-{4,}/ig, '')
+ };
+ data.text = $mmText.replaceNewLines(data.text, ' ');
+
+ return data;
+ }
+
/**
* Side menu nav handler.
*
@@ -142,6 +169,11 @@ angular.module('mm.addons.notifications')
siteid: siteId
});
}
+
+ if ($mmApp.isDesktop() && $mmLocalNotifications.isAvailable()) {
+ $mmEmulatorHelper.checkNewNotifications(
+ mmaNotificationsPushSimulationComponent, fetchNotifications, getTitleAndText, siteId);
+ }
};
/**
@@ -150,7 +182,7 @@ angular.module('mm.addons.notifications')
* @return {Number} Time between consecutive executions (in ms).
*/
self.getInterval = function() {
- return 600000; // 10 minutes.
+ return $mmApp.isDesktop() ? 60000 : 600000; // 1 or 10 minutes.
};
/**
@@ -159,8 +191,9 @@ angular.module('mm.addons.notifications')
* @return {Boolean} True if is a sync process, false otherwise.
*/
self.isSync = function() {
- // This is done to use only wifi if using the fallback function
- return !$mmaNotifications.isNotificationCountEnabled();
+ // This is done to use only wifi if using the fallback function.
+ // In desktop it is always sync, since it fetches notification to see if there's a new one.
+ return !$mmaNotifications.isNotificationCountEnabled() || $mmApp.isDesktop();
};
/**
diff --git a/www/addons/notifications/services/notifications.js b/www/addons/notifications/services/notifications.js
index 44e7179dca3..58a3470f1ba 100644
--- a/www/addons/notifications/services/notifications.js
+++ b/www/addons/notifications/services/notifications.js
@@ -21,13 +21,19 @@ angular.module('mm.addons.notifications')
* @ngdoc service
* @name $mmaNotifications
*/
-.factory('$mmaNotifications', function($q, $log, $mmSite, $mmSitesManager, $mmUser, $mmUtil, mmaNotificationsListLimit) {
+.factory('$mmaNotifications', function($q, $log, $mmSite, $mmSitesManager, $mmUser, $mmUtil, $mmApp, mmaNotificationsListLimit,
+ mmaNotificationsPushSimulationComponent, $mmEmulatorHelper) {
$log = $log.getInstance('$mmaNotifications');
var self = {};
- // Function to format notification data.
+ /**
+ * Function to format notification data.
+ *
+ * @param {Object[]} notifications List of notifications.
+ * @return {Void}
+ */
function formatNotificationsData(notifications) {
angular.forEach(notifications, function(notification) {
// Set message to show.
@@ -97,39 +103,60 @@ angular.module('mm.addons.notifications')
* @module mm.addons.notifications
* @ngdoc method
* @name $mmaNotifications#getNotifications
- * @param {Boolean} read True if should get read notifications, false otherwise.
- * @param {Number} limitFrom Position of the first notification to get.
- * @param {Number} limitNumber Number of notifications to get.
- * @return {Promise} Promise resolved with notifications.
+ * @param {Boolean} read True if should get read notifications, false otherwise.
+ * @param {Number} limitFrom Position of the first notification to get.
+ * @param {Number} limitNumber Number of notifications to get.
+ * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification.
+ * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, use current site.
+ * @return {Promise} Promise resolved with notifications.
*/
- self.getNotifications = function(read, limitFrom, limitNumber) {
+ self.getNotifications = function(read, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) {
+ toDisplay = typeof toDisplay == 'undefined' ? true : toDisplay;
limitFrom = limitFrom || 0;
limitNumber = limitNumber || mmaNotificationsListLimit;
+ siteId = siteId || $mmSite.getId();
$log.debug('Get ' + (read ? 'read' : 'unread') + ' notifications from ' + limitFrom + '. Limit: ' + limitNumber);
- var data = {
- useridto: $mmSite.getUserId(),
- useridfrom: 0,
- type: 'notifications',
- read: read ? 1 : 0,
- newestfirst: 1,
- limitfrom: limitFrom,
- limitnum: limitNumber
- };
- var preSets = {
- cacheKey: getNotificationsCacheKey()
- };
-
- // Get unread notifications.
- return $mmSite.read('core_message_get_messages', data, preSets).then(function(response) {
- if (response.messages) {
- var notifications = response.messages;
- formatNotificationsData(notifications);
- return notifications;
- } else {
- return $q.reject();
+ return $mmSitesManager.getSite(siteId).then(function(site) {
+ var data = {
+ useridto: site.getUserId(),
+ useridfrom: 0,
+ type: 'notifications',
+ read: read ? 1 : 0,
+ newestfirst: 1,
+ limitfrom: limitFrom,
+ limitnum: limitNumber
+ }, preSets = {
+ cacheKey: getNotificationsCacheKey()
+ };
+
+ if (forceCache) {
+ preSets.omitExpires = true;
+ } else if (ignoreCache) {
+ preSets.getFromCache = 0;
+ preSets.emergencyCache = 0;
}
+
+ // Get unread notifications.
+ return site.read('core_message_get_messages', data, preSets).then(function(response) {
+ if (response.messages) {
+ var notifications = response.messages;
+ formatNotificationsData(notifications);
+
+ if ($mmApp.isDesktop() && toDisplay && !read && limitFrom === 0) {
+ // Store the last received notification. Don't block the user for this.
+ $mmEmulatorHelper.storeLastReceivedNotification(
+ mmaNotificationsPushSimulationComponent, notifications[0], siteId);
+ }
+
+ return notifications;
+ } else {
+ return $q.reject();
+ }
+ });
});
};
@@ -139,12 +166,16 @@ angular.module('mm.addons.notifications')
* @module mm.addons.notifications
* @ngdoc method
* @name $mmaNotifications#getReadNotifications
- * @param {Number} limitFrom Position of the first notification to get.
- * @param {Number} limitNumber Number of notifications to get.
- * @return {Promise} Promise resolved with notifications.
+ * @param {Number} limitFrom Position of the first notification to get.
+ * @param {Number} limitNumber Number of notifications to get.
+ * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification.
+ * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, use current site.
+ * @return {Promise} Promise resolved with notifications.
*/
- self.getReadNotifications = function(limitFrom, limitNumber) {
- return self.getNotifications(true, limitFrom, limitNumber);
+ self.getReadNotifications = function(limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) {
+ return self.getNotifications(true, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
};
/**
@@ -153,12 +184,16 @@ angular.module('mm.addons.notifications')
* @module mm.addons.notifications
* @ngdoc method
* @name $mmaNotifications#getUnreadNotifications
- * @param {Number} limitFrom Position of the first notification to get.
- * @param {Number} limitNumber Number of notifications to get.
- * @return {Promise} Promise resolved with notifications.
+ * @param {Number} limitFrom Position of the first notification to get.
+ * @param {Number} limitNumber Number of notifications to get.
+ * @param {Boolean} [toDisplay=true] True if notifications will be displayed to the user, either in view or in a notification.
+ * @param {Boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache.
+ * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
+ * @param {String} [siteId] Site ID. If not defined, use current site.
+ * @return {Promise} Promise resolved with notifications.
*/
- self.getUnreadNotifications = function(limitFrom, limitNumber) {
- return self.getNotifications(false, limitFrom, limitNumber);
+ self.getUnreadNotifications = function(limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId) {
+ return self.getNotifications(false, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
};
/**
@@ -193,7 +228,8 @@ angular.module('mm.addons.notifications')
}
// Fallback call.
- return self.getNotifications(false, 0, mmaNotificationsListLimit + 1).then(function(unread) {
+ var limit = mmaNotificationsListLimit + 1;
+ return self.getUnreadNotifications(0, limit, false, false, false, siteId).then(function(unread) {
// Add + sign if there are more than the limit reachable.
return (unread.length > mmaNotificationsListLimit) ? unread.length + "+" : unread.length;
}).catch(function() {
diff --git a/www/addons/notifications/templates/preferences.html b/www/addons/notifications/templates/preferences.html
index 94ec50727c0..1b35e02a80b 100644
--- a/www/addons/notifications/templates/preferences.html
+++ b/www/addons/notifications/templates/preferences.html
@@ -10,7 +10,7 @@
-
+
والآن قم باختيار المقرر الدراسي الذي ترغب المشاركة فيه.
\n
من الآن فصاعدا يمكنك الدخول عن طريق إدخال اسم المستخدم وكلمة المرور (في النموذج المقابل بهذه الصفحة) ، وتستطيع الاتصال الكامل المقرر الدراسي ، وتصل إلى أي مقرر دراسي تريد التسجيل به.
\n
إذا طلب منك ''مفتاح التسجيل'' - استخدم المفتاح الذي أعطاه لك المدرس. هذا سيجعلك ''تشارك'' في المقرر الدراسي.
\n
لا حظ أن كل مقرر دراسي قد يكون له أيضا \"مفتاح تسجيل\" ستحتاج إليه لاحقا.
\n ",
diff --git a/www/core/components/login/lang/bg.json b/www/core/components/login/lang/bg.json
index 42351bce95a..c21497bd5f6 100644
--- a/www/core/components/login/lang/bg.json
+++ b/www/core/components/login/lang/bg.json
@@ -1,7 +1,7 @@
{
"authenticating": "Удостоверяване",
"cancel": "Отказване",
- "connect": "Свързване!",
+ "connect": "Свързване",
"connecttomoodle": "Свързване към Moodle",
"createaccount": "Създаване на моята регистрация",
"createuserandpass": "Изберете Вашето име и парола",
@@ -27,7 +27,7 @@
"mobileservicesnotenabled": "Услугите от Moodle не са активирани на Вашия сайт. Моля, свържете се с администратор на Moodle, ако мислите, че мобилния достъп трябва да бъде разрешен.",
"newaccount": "Нова потребителска регистрация",
"notloggedin": "Трябва са сте влезли в сайта.",
- "password": "Ключ за записване",
+ "password": "Парола",
"passwordrequired": "Паролата е задължителна",
"policyaccept": "Разбирам и съм съгласен",
"policyagree": "Трябва да се съгласите с тези условия за ползване, за да продължите да ползвате сайта. Съгласен/на ли сте?",
diff --git a/www/core/components/login/lang/ca.json b/www/core/components/login/lang/ca.json
index d14a659e218..30577d6307d 100644
--- a/www/core/components/login/lang/ca.json
+++ b/www/core/components/login/lang/ca.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "La versió de Moodle no és vàlida. Cal com a mínim la versió 2.4.",
"invalidsite": "L'URL del lloc no és vàlid.",
"invalidtime": "L'hora no és vàlida",
- "invalidurl": "L'URL no és vàlid",
+ "invalidurl": "L'URL que heu introduït no és vàlid",
"invalidvaluemax": "El valor màxim és {{$a}}",
"invalidvaluemin": "El valor mínim és {{$a}}",
"localmobileunexpectedresponse": "Les característiques addicionals de Moodle Mobile han tornat una resposta inesperada, us heu d'autenticar fent servir el servei estàndard de Mobile.",
@@ -44,7 +44,7 @@
"newaccount": "Nou compte",
"newsitedescription": "Introduïu l'URL del vostre lloc Moodle. Tingueu en compte que podria no estar configurat per treballar amb aquesta aplicació.",
"notloggedin": "Heu d'entrar al lloc.",
- "password": "Clau d'inscripció",
+ "password": "Contrasenya",
"passwordrequired": "Contrasenya obligatòria",
"policyaccept": "Entès i conforme",
"policyagree": "Heu d'acceptar la normativa abans d'entrar en aquest lloc. Hi esteu d'acord?",
diff --git a/www/core/components/login/lang/cs.json b/www/core/components/login/lang/cs.json
index 8b4a2c704cd..e6b11b3d959 100644
--- a/www/core/components/login/lang/cs.json
+++ b/www/core/components/login/lang/cs.json
@@ -1,7 +1,7 @@
{
"auth_email": "Registrace na základě e-mailu",
"authenticating": "Autentizace",
- "cancel": "Přerušit",
+ "cancel": "Zrušit",
"checksiteversion": "Zkontrolujte, zda web používá Moodle 2.4 nebo novější.",
"confirmdeletesite": "Jste si jisti, že chcete smazat web {{sitename}}?",
"connect": "Připojit!",
@@ -19,7 +19,7 @@
"errorupdatesite": "Došlo k chybě při aktualizaci tokenu webu.",
"firsttime": "Jste tady poprvé?",
"getanothercaptcha": "Získat jiné CAPTCHA",
- "help": "Nápověda",
+ "help": "Pomoc",
"helpmelogin": "
Existuje mnoho tisíc webů Moodle po celém světě. Tato aplikace může připojit pouze ke stránkám Moodle, které povolily, mobilní přístup k aplikaci.
Pokud se nemůžete k Moodle připojit, pak je třeba kontaktovat správce web Moodle, kam se chcete připojit a požádat, aby přečetl http://docs.moodle.org/en/Mobile_app
Chcete-li otestovat aplikaci na Moodle demo webu jako učitel nebo student na pole Adresa stránky a klikněte na tlačítko Připojit .
",
"instructions": "Pokyny",
"invalidaccount": "Zkontrolujte si prosím své přihlašovací údaje nebo se obraťte na správce webu, aby zkontroloval nastavení.",
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Neplatná verze Moodle. Minimální potřebná verze je:",
"invalidsite": "Adresa URL stránky je chybná",
"invalidtime": "Neplatný čas",
- "invalidurl": "Neplatná URL",
+ "invalidurl": "Použité URL není platné",
"invalidvaluemax": "Maximální hodnota je {{$a}}",
"invalidvaluemin": "Minimální hodnota je {{$a}}",
"localmobileunexpectedresponse": "Kontrola rozšířených vlastností Moodle Mobile vrátil neočekávanou odezvu, budete ověřen pomocí standardních služeb mobilu .",
@@ -44,7 +44,7 @@
"newaccount": "Nový účet",
"newsitedescription": "Zadejte prosím adresu URL vašeho webu Moodle. Všimněte si, že nemusí být nakonfigurován pro práci s touto aplikací.",
"notloggedin": "Musíte být přihlášeni.",
- "password": "Sdílené heslo",
+ "password": "Heslo",
"passwordrequired": "Je požadováno heslo",
"policyaccept": "Rozumím a souhlasím",
"policyagree": "Před dalším používáním těchto stránek musíte souhlasit s těmito pravidly. Souhlasíte s nimi?",
diff --git a/www/core/components/login/lang/da.json b/www/core/components/login/lang/da.json
index 71bccdcbe1d..ba85230503e 100644
--- a/www/core/components/login/lang/da.json
+++ b/www/core/components/login/lang/da.json
@@ -2,7 +2,7 @@
"authenticating": "Godkender",
"cancel": "Annuller",
"confirmdeletesite": "Er du sikker på at du ønsker at slette websiden {{sitename}}?",
- "connect": "Forbind",
+ "connect": "Tilslut!",
"connecttomoodle": "Tilslut til Moodle",
"createaccount": "Opret ny profil",
"createuserandpass": "Vælg brugernavn og adgangskode",
@@ -21,7 +21,7 @@
"invalidemail": "Ugyldig e-mailadresse",
"invalidmoodleversion": "Ugyldig Moodle version. Der kræves minimum 2.4.",
"invalidsite": "Denne webadresse er ugyldig.",
- "invalidurl": "Ugyldig URL",
+ "invalidurl": "Den URL, du har skrevet, er ikke korrekt",
"localmobileunexpectedresponse": "Du har fået en uventet reaktion fra Moodle Mobile Additional Features, så du vil blive godkendt ved hjælp af standard Mobile service.",
"login": "Log ind",
"loginbutton": "Login",
@@ -34,7 +34,7 @@
"newaccount": "Ny konto",
"newsitedescription": "Skriv din Moodles webadresse. Bemærk at Moodle kan være konfigureret, så den ikke virker med denne app.",
"notloggedin": "Du skal være logget på.",
- "password": "Delt hemmelig streng",
+ "password": "Adgangskode",
"passwordrequired": "Adgangskode kræves",
"policyaccept": "Jeg forstår og er enig",
"policyagree": "Du må acceptere disse retningslinjer for at benytte dette site.\nAccepterer du?",
diff --git a/www/core/components/login/lang/de.json b/www/core/components/login/lang/de.json
index e88b1eeed67..ca4835372f7 100644
--- a/www/core/components/login/lang/de.json
+++ b/www/core/components/login/lang/de.json
@@ -2,7 +2,7 @@
"auth_email": "E-Mail-Registrierung",
"authenticating": "Authentifizieren ...",
"cancel": "Abbrechen",
- "checksiteversion": "Prüfen Sie, ob Ihre Website mindestens Moodle 2.4 verwendet.",
+ "checksiteversion": "Prüfen Sie, ob die Website mindestens Moodle 2.4 verwendet.",
"confirmdeletesite": "Möchten Sie '{{sitename}}' wirklich aus der Liste löschen?",
"connect": "Verbinden",
"connecttomoodle": "Website verbinden",
@@ -20,7 +20,7 @@
"firsttime": "Sind Sie zum ersten Mal auf dieser Webseite?",
"getanothercaptcha": "Neues Captcha laden",
"help": "Hilfe",
- "helpmelogin": "
Die Moodle Mobile App funktioniert nur mit Websites, die speziell für den mobilen Zugriff freigegeben wurden.
Wenn Sie die App mit einer Demo-Website testen möchten, tragen Sie bitte teacher oder student in das Feld URL der Website ein. Tippen Sie dann auf die Taste Verbinden.
",
+ "helpmelogin": "
Es gibt viele tausend Moodle-Websites auf der Welt. Die mobile App funktioniert nur mit Websites, für die der mobile Zugriff freigegeben wurde.
Wenn Sie die App mit einer Demo-Website testen möchten, tragen Sie bitte teacher oder student in das Feld URL der Website ein. Tippen Sie dann auf die Taste Verbinden.
",
"instructions": "Anleitung",
"invalidaccount": "Prüfen Sie Ihre Anmeldedaten oder wenden Sie sich an den Administrator der Website.",
"invaliddate": "Ungültiges Datum",
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Falsche Version. Mindestens Moodle 2.4 ist notwendig.",
"invalidsite": "Die URL der Website ist ungültig.",
"invalidtime": "Ungültige Zeitangabe",
- "invalidurl": "Ungültige URL",
+ "invalidurl": "Die eingegebene URL ist nicht gültig.",
"invalidvaluemax": "Der Maximalwert ist {{$a}}.",
"invalidvaluemin": "Der Minimalwert ist {{$a}}.",
"localmobileunexpectedresponse": "Die Verbindung zum Plugin 'Moodle Mobile - Zusatzfeatures' ist fehlgeschlagen. Sie werden über den standardmäßigen mobilen Webservice authentifiziert.",
diff --git a/www/core/components/login/lang/el.json b/www/core/components/login/lang/el.json
index cb0a2b6fbae..171e2d567ae 100644
--- a/www/core/components/login/lang/el.json
+++ b/www/core/components/login/lang/el.json
@@ -1,7 +1,7 @@
{
"auth_email": "Email-based αυτο-εγγραφή",
"authenticating": "Έλεγχος ταυτότητας",
- "cancel": "Άκυρο",
+ "cancel": "Ακύρωση",
"checksiteversion": "Ελέγξτε ποια έκδοση Moodle χρησιμοποιεί το site, Moodle 2.4 ή μετέπειτα έκδοση.",
"confirmdeletesite": "Είστε σίγουροι ότι θέλετε να διαγράψετε το site {{sitename}};",
"connect": "Σύνδεση!",
@@ -14,30 +14,64 @@
"emailconfirmsent": "
Ένα email έχει σταλεί στη διεύθυνση σας {{$a}}
Περιέχει εύκολες οδηγίες για να ολοκληρώσετε την εγγραφή σας.
Εάν συνεχίσετε να έχετε δυσκολίες επικοινωνήστε με το διαχειριστή του site.
",
"emailnotmatch": "Οι διευθύνσεις email δεν ταιριάζουν",
"enterthewordsabove": "Enter the words above",
+ "erroraccesscontrolalloworigin": "Η κλήση πολλαπλών προελεύσεων (Cross-Origin call) που προσπαθείτε να εκτελέσετε έχει απορριφθεί. Παρακαλώ ελέγξτε https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium",
"errordeletesite": "Παρουσιάστηκε σφάλμα κατά τη διάρκεια της διαγραφής του site. Δοκιμάστε ξανά αργότερα.",
"errorupdatesite": "Παρουσιάστηκε σφάλμα κατά την ενημέρωση του site token.",
"firsttime": "Είναι η πρώτη σας φορά εδώ;",
"getanothercaptcha": "Πάρε ένα άλλο CAPTCHA",
"help": "Βοήθεια",
+ "helpmelogin": "
Υπάρχουν χιλιάδες Moodle ιστότοποι σε όλο τον κόσμο. Αυτή η εφαρμογή μπορεί να συνδεθεί μόνο σε ιστότοπους Moodle που έχουν ενεργοποιήσει συγκεκριμένα την πρόσβαση σε εφαρμογές για κινητά.
Εάν δεν μπορείτε να συνδεθείτε στον ιστότοπό σας Moodle, πρέπει να επικοινωνήσετε με το διαχειριστή του Moodle ιστότοπου όπου θέλετε να συνδεθείτε και ζητήστε τους να διαβάσουν http://docs.moodle.org/en/Mobile_app
Για να δοκιμάσετε την εφαρμογή σε έναν δοκιμαστικό ιστότοπο Moodle δάσκαλος ή σπουδαστής στο πεδίο Διεύθυνση ιστοτόπου και κάντε κλικ στο κουμπί < .
",
"instructions": "Οδηγίες",
+ "invalidaccount": "Ελέγξτε τα στοιχεία σύνδεσης ή ζητήστε από τον διαχειριστή του ιστότοπού σας να ελέγξει τη διαμόρφωση του ιστότοπου.",
+ "invaliddate": "Η ημερομηνία δεν είναι σωστή",
"invalidemail": "Εσφαλμένη διεύθυνση ηλεκτρονικού ταχυδρομείου",
- "invalidurl": "Το URL που εισαγάγατε δεν είναι έγκυρο",
+ "invalidmoodleversion": "Μη έγκυρη έκδοση Moodle. Η ελάχιστη απαιτούμενη έκδοση είναι η 2.4.",
+ "invalidsite": "Η διεύθυνση ιστότοπου δεν είναι έγκυρη.",
+ "invalidtime": "Μη έγκυρη ώρα",
+ "invalidurl": "Μη έγκυρο URL",
+ "invalidvaluemax": "Η μεγαλύτερη τιμή είναι {{$a}}",
+ "invalidvaluemin": "Η μικρότερη τιμή είναι {{$a}}",
+ "localmobileunexpectedresponse": "Ο έλεγχος επιπρόσθετων λειτουργιών τη εφαρμοργής για κινητά Moodle επέστρεψε μια απροσδόκητη απόκριση, θα πιστοποιηθείτε χρησιμοποιώντας την τυπική υπηρεσία κινητής τηλεφωνίας.",
+ "loggedoutssodescription": "Πρέπει να επαληθεύσετε ξανά τον έλεγχο ταυτότητας. Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.",
"login": "Είσοδος",
+ "loginbutton": "Σύνδεση",
+ "logininsiterequired": "Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.",
"loginsteps": "Γεια σας,\n\nΓια να έχετε πλήρη πρόσβαση σε κάποια μαθήματα θα χρειαστεί να δημιουργήσετε ένα νέο λογαριασμό, ακολουθώντας τα παρακάτω βήματα:\n\n
Ένα μήνυμα ηλεκτρονικού ταχυδρομείου θα αποσταλεί στη διεύθυνσή σας.\n
Διαβάστε το μήνυμα και επιλέξτε τη διεύθυνση που περιέχει.\n
Μετά την επιβεβαίωση του λογαριασμού σας, θα μπορείτε να συνδεθείτε στην ηλεκτρονική τάξη.\n
Αφού έχετε συνδεθεί, μπορείτε να επιλέξτε το μάθημα στο οποίο θέλετε να εγγραφείτε. Αν σας ζητηθεί ένα \"κλειδί εγγραφής\" - χρησιμοποιήστε αυτό που σας έδωσε ο διδάσκοντάς σας.\n
Από εδώ και στο εξής θα έχετε τη δυνατότητα να χρησιμοποιήσετε όλες τις δραστηριότητες και τις πηγές πληροφοριών του μαθήματος.\n
",
"missingemail": "Λείπει η διεύθυνση ηλεκτρονικού ταχυδρομείου",
"missingfirstname": "Λείπει το όνομα",
"missinglastname": "Λείπει το επώνυμο",
+ "mobileservicesnotenabled": "Οι υπηρεσίες κινητής τηλεφωνίας δεν είναι ενεργοποιημένες στον ιστότοπό σας. Παρακαλούμε, επικοινωνήστε με τον διαχειριστή του ιστότοπου εάν πιστεύετε ότι η πρόσβαση στο κινητό θα πρέπει να είναι ενεργοποιημένη.",
"newaccount": "Νέος λογαριασμός",
- "password": "Κωδικός",
+ "newsitedescription": "Καταχωρίστε τη διεύθυνση URL του ιστότοπού σας Moodle. Σημειώστε ότι ενδέχεται να μην έχει ρυθμιστεί να λειτουργεί με αυτήν την εφαρμογή.",
+ "notloggedin": "Πρέπει να συνδεθείτε",
+ "password": "Κωδικός πρόσβασης",
+ "passwordrequired": "Απαιτείται κωδικός πρόσβασης",
"policyaccept": "Καταλαβαίνω και συμφωνώ",
"policyagree": "Πρέπει να συμφωνήσετε σε αυτήν την πολιτική για να συνεχίσετε στο ιστοχώρο. Συμφωνείτε;",
"policyagreement": "Άδεια χρήσης του ιστοχώρου",
"policyagreementclick": "Πατήστε εδώ για να διαβάσετε του όρους χρήσης",
"potentialidps": "Συνδεθείτε χρησιμοποιώντας το λογαριασμό σας στο:",
+ "problemconnectingerror": "Παρουσιάστηκαν προβλήματα σύνδεσης",
+ "problemconnectingerrorcontinue": "Ελέγξτε ότι έχετε εισάγει σωστά τη διεύθυνση και προσπαθήστε ξανά.",
+ "profileinvaliddata": "Μη έγκυρη τιμή",
+ "recaptchachallengeimage": "Εικόνα reCAPTCHA",
+ "reconnect": "Επανασύνδεση",
+ "reconnectdescription": "Η σύνδεση με το λογαριασμό σας δεν είναι έγκυρη ή έχει λήξει, πρέπει να επανασυνδεθείτε με τον ιστότοπο.",
+ "reconnectssodescription": "Η σύνδεση με το λογαριασμό σας δεν είναι έγκυρη ή έχει λήξει, πρέπει να επανασυνδεθείτε με τον ιστότοπο. Θα πρέπει να συνδεθείτε στον ιστότοπο σε ένα παράθυρο του προγράμματος περιήγησης.",
"security_question": "Ερώτηση ασφαλείας",
"selectacountry": "Επιλέξτε μια χώρα",
+ "signupplugindisabled": "{{$a}} δεν έχει ενεργοποιηθεί.",
+ "siteaddress": "Διεύθυνση ιστότοπου",
+ "siteinmaintenance": "Ο ιστότοπός σας βρίσκεται σε λειτουργία συντήρησης",
+ "sitepolicynotagreederror": "Η πολιτική του ιστότοπου δεν έγινε δεκτή.",
+ "siteurl": "URL του ιστότοπου",
+ "siteurlrequired": "Το URL του ιστότοπου είναι απαραίτητο, π.χ. http://www.yourmoodlesite.abc or https://www.yourmoodlesite.efg",
"startsignup": "Ξεκινήστε τώρα δημιουργώντας νέο λογαριασμό!",
+ "stillcantconnect": "Ακόμα δεν μπορείτε να συνδεθείτε;",
"supplyinfo": "Παρακαλώ, δώστε κάποιες πληροφορίες σχετικές με τον εαυτό σας",
"username": "Όνομα χρήστη",
- "usernotaddederror": "Ο χρήστης \"{{$a}}\" δεν προστέθηκε - άγνωστο σφάλμα"
+ "usernamerequired": "Το όνομα χρήστη είναι απαραίτητο",
+ "usernotaddederror": "Ο χρήστης \"{{$a}}\" δεν προστέθηκε - άγνωστο σφάλμα",
+ "visitchangepassword": "Θέλετε να επισκεφτείτε τον ιστότοπο για να αλλάξετε τον κωδικό πρόσβασης;",
+ "webservicesnotenabled": "Οι υπηρεσίες Web δεν είναι ενεργοποιημένες στον ιστότοπό σας. Παρακαλούμε, επικοινωνήστε με τον διαχειριστή του δικτυακού σας τόπου για το Moodle εάν πιστεύετε ότι η πρόσβαση στο κινητό θα πρέπει να είναι ενεργοποιημένη."
}
\ No newline at end of file
diff --git a/www/core/components/login/lang/es-mx.json b/www/core/components/login/lang/es-mx.json
index 6bf776afc12..9533fe383b8 100644
--- a/www/core/components/login/lang/es-mx.json
+++ b/www/core/components/login/lang/es-mx.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es 2.4",
"invalidsite": "La URL del sitio es inválida.",
"invalidtime": "Hora inválida",
- "invalidurl": "URL no válida",
+ "invalidurl": "La URL introducida no es válida",
"invalidvaluemax": "El valor máximo es {{$a}}",
"invalidvaluemin": "El valor mínimo es {{$a}}",
"localmobileunexpectedresponse": "La revisión de las características Adicionales de Moodle Mobile regresó una respuesta inesperada; Usted será autenticado usando el servicio Mobile estándar.",
@@ -44,13 +44,13 @@
"newaccount": "Nueva cuenta",
"newsitedescription": "Por favor escriba la uRL de su sitio Moodle. Tome nota de que este podría no estar configurado para trabajar con esta app.",
"notloggedin": "Usted necesita estar ingresado.",
- "password": "Secreto Compartido",
+ "password": "Contraseña",
"passwordrequired": "Contraseña obligatoria",
"policyaccept": "Entiendo y estoy de acuerdo",
"policyagree": "Usted deberá estar de acuerdo con estas condiciones antes de seguir usando este sitio. ¿Está de acuerdo?",
"policyagreement": "Acuerdo con las Condiciones del Sitio",
"policyagreementclick": "Haga clic aquí para leer el acuerdo con las condiciones del sitio",
- "potentialidps": "¿Entra (se registra) habitualmente en otro sitio antes de llegar aquí? Elija entre las opciones de la siguiente lista para entrar en su sitio habitual:",
+ "potentialidps": "Ingrese usando su cuenta en:",
"problemconnectingerror": "Estamos teniendo dificultades para conectarnos",
"problemconnectingerrorcontinue": "Revise dos veces que Usted haya ingresado la dirección correctamente e inténtelo nuevamente.",
"profileinvaliddata": "Valor inválido",
diff --git a/www/core/components/login/lang/es.json b/www/core/components/login/lang/es.json
index 652d4db8fef..65a96778338 100644
--- a/www/core/components/login/lang/es.json
+++ b/www/core/components/login/lang/es.json
@@ -28,10 +28,11 @@
"invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es:",
"invalidsite": "La URL del sitio es inválida.",
"invalidtime": "Hora incorrecta",
- "invalidurl": "URL no válida",
+ "invalidurl": "La URL introducida no es válida",
"invalidvaluemax": "El valor máximo es {{$a}}",
"invalidvaluemin": "El valor mínimo es {{$a}}",
"localmobileunexpectedresponse": "Las características adicionales de Moodle Mobile han devuelto una respuesta inesperada, debe autenticarse utilizando el servicio estándar de Mobile.",
+ "loggedoutssodescription": "Tiene que autenticarse nuevamente. Necesita acceder al sitio en una ventana del navegador.",
"login": "Acceder",
"loginbutton": "Acceder",
"logininsiterequired": "Para autentificarse en el sitio se ha de abrir una ventana de navegador.",
@@ -43,7 +44,7 @@
"newaccount": "Nueva cuenta",
"newsitedescription": "Introduzca la URL de su sitio Moodle. Tenga en cuenta que podría no estar configurado para trabajar con esta aplicación.",
"notloggedin": "Ha de entrar al sitio.",
- "password": "Clave de matriculación",
+ "password": "Contraseña",
"passwordrequired": "Contraseña obligatoria",
"policyaccept": "Entiendo y estoy de acuerdo",
"policyagree": "Usted deberá estar de acuerdo con estas condiciones antes de seguir usando este sitio. ¿Está de acuerdo?",
@@ -62,6 +63,7 @@
"signupplugindisabled": "{{$a}} no está habilitado",
"siteaddress": "Dirección del sitio",
"siteinmaintenance": "Su sitio está en modo mantenimiento",
+ "sitepolicynotagreederror": "No se aceptó la política del sitio.",
"siteurl": "URL del sitio",
"siteurlrequired": "La URL del sitio es obligatoria, por ejemplo http://www.yourmoodlesite.es o https://www.yourmoodlesite.org",
"startsignup": "Crear nueva cuenta",
diff --git a/www/core/components/login/lang/es_mx.json b/www/core/components/login/lang/es_mx.json
deleted file mode 100644
index 2b074964071..00000000000
--- a/www/core/components/login/lang/es_mx.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "authenticating": "Autenticando",
- "cancel": "Cancelar",
- "connect": "Conectar",
- "help": "Ayuda",
- "helpmelogin": "
Existen varios miles de sitios Moodle en el mundo. Esta App solamente puede conectarse a sitios Moodle que hayan habilitado específicamente el acceso por Mobile App.
Si Usted no puede conectarse a su sitio Moodle, entonces Usted necesita contactar a un administrador de Moodle en el lugar en donde Usted quiere conectarse y pedirle que lea http://docs.moodle.org/en/Mobile_app
Para probar la App en un sitio Demo de Moodle escriba teacher o student en el campo de URL del sitio botón para Añadir.
",
- "invalidaccount": "Por favor, verifique sus datos de acceso, o consulte con el administrador para revisar la configuración del sitio.",
- "invalidmoodleversion": "Versión de Moodle inválida. La versión mínima requerida es:",
- "invalidsite": "La URL del sitio es inválida.",
- "login": "Ingresar",
- "logininsiterequired": "Usted necesita ingresar al sitio con una ventana del navegador.",
- "mobileservicesnotenabled": "Los servicios móviles no están habilitados en su sitio. Por favor, contacte a su administrador del sitio Moodle si Usted piensa que se debería habilitar el acceso por dispositivos móviles.",
- "password": "Contraseña",
- "passwordrequired": "Contraseña obligatoria",
- "siteinmaintenance": "Su sitio está en modo de mantenimiento",
- "siteurl": "URL del sitio",
- "siteurlrequired": "La URL del sitio es obligatoria, por ejemplo http://www.yourmoodlesite.es o https://www.yourmoodlesite.org",
- "username": "Nombre de usuario",
- "usernamerequired": "Nombre de usuario obligatorio",
- "webservicesnotenabled": "Los servicios web no están habilitados en su sitio. Por favor, contacte a su administrador del sitio Moodle si Usted piensa que se debería habilitar el acceso por dispositivos móviles."
-}
\ No newline at end of file
diff --git a/www/core/components/login/lang/eu.json b/www/core/components/login/lang/eu.json
index 61b1d730666..c2a9af12681 100644
--- a/www/core/components/login/lang/eu.json
+++ b/www/core/components/login/lang/eu.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Moodle bertsio baliogabea. Gutxieneko bertsioa hurrengoa da:",
"invalidsite": "Guneko URLa ez da zuzena",
"invalidtime": "Ordu baliogabea",
- "invalidurl": "URL baliogabea",
+ "invalidurl": "Sartu duzun URL-a ez da onargarria",
"invalidvaluemax": "Gehieneko balioa {{$a}} da.",
"invalidvaluemin": "Gutxieneko balioa {{$a}} da.",
"localmobileunexpectedresponse": "Moodle Mobile-ko Funtzio Aurreratuen kontrolak ezusteko erantzuna eman du, Mobile zerbitzu estandarra erabilita autentifikatuko zaitugu.",
@@ -44,7 +44,7 @@
"newaccount": "Kontu berria",
"newsitedescription": "Sartu mesedez zure Moodle guneko URLa. Kontuan hartu app honekin funtzionatzeko gunea aurretik konfiguraturik egon behar dela.",
"notloggedin": "Autentifikaturik egon behar duzu.",
- "password": "Partekatutako sekretua",
+ "password": "Pasahitza",
"passwordrequired": "Pasahitza behar da",
"policyaccept": "Ulertu dut eta ados nago",
"policyagree": "Web gune honetan jarraitu aurretik baldintzekin ados egon behar duzu. Ados al zaude?",
diff --git a/www/core/components/login/lang/fa.json b/www/core/components/login/lang/fa.json
index 742e9639285..e5cd574fd10 100644
--- a/www/core/components/login/lang/fa.json
+++ b/www/core/components/login/lang/fa.json
@@ -17,7 +17,7 @@
"invalidemail": "آدرس پست الکترونیک نامعتبر",
"invalidmoodleversion": "این نسخه از برنامه سایت قابلیت اتصال به موبایل ندارد",
"invalidsite": "نشانی سایت معتبر نیست",
- "invalidurl": "آدرس نامعتبر",
+ "invalidurl": "آدرسی که وارد کردهاید معتبر نیست",
"login": "ورود به سایت",
"logininsiterequired": "لازم است به سایت از طریق مرورگر متصل گردید",
"loginsteps": "برای داشتن دسترسی کامل به این سایت، پیش از هر چیز باید یک حساب کاربری بسازید.",
diff --git a/www/core/components/login/lang/fr.json b/www/core/components/login/lang/fr.json
index 091525791f0..c13712a0f07 100644
--- a/www/core/components/login/lang/fr.json
+++ b/www/core/components/login/lang/fr.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Version de Moodle non valide. La version minimale requise est :",
"invalidsite": "Cette URL n'est pas valide.",
"invalidtime": "Temps non valide",
- "invalidurl": "URL non valide",
+ "invalidurl": "L'URL que vous venez de saisir n'est pas valide",
"invalidvaluemax": "La valeur maximale est {{$a}}",
"invalidvaluemin": "La valeur minimale est {{$a}}",
"localmobileunexpectedresponse": "La vérification des fonctionnalités additionnelles de Moodle Mobile a envoyé une réponse inattendue. Vous allez être connecté au moyen du service mobile standard.",
@@ -44,7 +44,7 @@
"newaccount": "Nouveau compte",
"newsitedescription": "Veuillez saisir l'URL de votre plateforme Moodle.",
"notloggedin": "Vous devez être connecté.",
- "password": "Secret partagé",
+ "password": "Mot de passe",
"passwordrequired": "Mot de passe requis",
"policyaccept": "Je comprends et je me déclare d'accord",
"policyagree": "Vous devez accepter de vous conformer à ce règlement pour continuer à utiliser ce site. Acceptez-vous le règlement ?",
diff --git a/www/core/components/login/lang/he.json b/www/core/components/login/lang/he.json
index 08820ee166c..2c5cbdf946a 100644
--- a/www/core/components/login/lang/he.json
+++ b/www/core/components/login/lang/he.json
@@ -2,7 +2,7 @@
"authenticating": "מאמת נתונים",
"cancel": "ביטול",
"confirmdeletesite": "האם את/ה בטוח/ה שברצונך למחוק את האתר {{sitename}}?",
- "connect": "חיבור",
+ "connect": "התחברות!",
"connecttomoodle": "התחברות למוודל",
"createaccount": "יצירת חשבון חדש",
"createuserandpass": "הזנת שם־משתמש וסיסמה",
@@ -20,7 +20,7 @@
"invalidemail": "כתובת דואר אלקטרוני לא תקפה",
"invalidmoodleversion": "גרסת מוודל לא תקינה. נדרשת גרסה 2.4 ומעלה.",
"invalidsite": "כתובת האתר אינה תקינה.",
- "invalidurl": "URL לא חוקי",
+ "invalidurl": "כתובת ה-URL (אינטרנט) שהזנת כרגע לא תקפה.",
"login": "התחברות",
"loginbutton": "כניסה!",
"logininsiterequired": "עליך להתחבר לאתר בחלון דפדפן.",
@@ -32,7 +32,7 @@
"newaccount": "חשבון חדש",
"newsitedescription": "יש להזין את כתובת אתר המוודל שלך. יש לשים לב כי יתכן והאתר אינו מוגדר לעבוד עם יישומון זו.",
"notloggedin": "עליך להיות מחובר/ת",
- "password": "סיסמה (secret)",
+ "password": "סיסמה",
"passwordrequired": "דרושה סיסמה",
"policyaccept": "אני מבין ומסכים",
"policyagree": "הינך חייב לאשר את מדיניות זו על מנת להמשיך להשתמש באתר זה. האם אתה מסכים?",
diff --git a/www/core/components/login/lang/hu.json b/www/core/components/login/lang/hu.json
index c5c7c062990..03351032c9f 100644
--- a/www/core/components/login/lang/hu.json
+++ b/www/core/components/login/lang/hu.json
@@ -1,6 +1,6 @@
{
"authenticating": "Hitelesítés",
- "cancel": "Mégse",
+ "cancel": "Törlés",
"connect": "Kapcsolódás",
"createaccount": "Új felhasználói azonosítóm létrehozása",
"createuserandpass": "Új felhasználónév és jelszó megadása",
@@ -15,7 +15,7 @@
"invalidemail": "Érvénytelen e-mail cím",
"invalidmoodleversion": "Érvénytelen Moodle-verzió. A minimális verziószám a 2.4.",
"invalidsite": "A portál-URL nem érvényes.",
- "invalidurl": "Érvénytelen URL",
+ "invalidurl": "A megadott URL nem érvényes",
"login": "Belépés",
"logininsiterequired": "A portálra böngészőablakban kell bejelentkeznie.",
"loginsteps": "Ahhoz, hogy teljesen hozzáférjen a portálhoz, először új fiókot kell létrehoznia.",
@@ -24,7 +24,7 @@
"missinglastname": "Hiányzó vezetéknév",
"mobileservicesnotenabled": "Portálján a mobil szolgáltatások nincsenek engedélyezve. A mobil elérhetőség bekapcsolásához forduljon a rendszergazdához.",
"newaccount": "Új fiók",
- "password": "Megosztott titkos jel",
+ "password": "Jelszó",
"passwordrequired": "Jelszó szükséges",
"policyaccept": "Megértettem és elfogadom",
"policyagree": "A portál használatához el kell fogadnia a feltételeket. Elfogadja őket?",
diff --git a/www/core/components/login/lang/it.json b/www/core/components/login/lang/it.json
index 7cec597a221..bc68e3db17c 100644
--- a/www/core/components/login/lang/it.json
+++ b/www/core/components/login/lang/it.json
@@ -21,7 +21,7 @@
"invalidemail": "Indirizzo email non valido",
"invalidmoodleversion": "Versione di Moodle non valida. La versione minima richiesta:",
"invalidsite": "L'URL del sito non è valida",
- "invalidurl": "L'URL non è valido",
+ "invalidurl": "L'URL inserito non è valido",
"localmobileunexpectedresponse": "Il controllo delle Moodle Mobile Additional Feature ha restituito una risposta inattesa, sarai autenticato tramite i servizi Mobile standard.",
"login": "Login",
"loginbutton": "Login!",
diff --git a/www/core/components/login/lang/ja.json b/www/core/components/login/lang/ja.json
index 6b0b86428d5..33dced4b80e 100644
--- a/www/core/components/login/lang/ja.json
+++ b/www/core/components/login/lang/ja.json
@@ -15,8 +15,9 @@
"invalidemail": "無効なメールアドレスです。",
"invalidmoodleversion": "Moodleのバージョンが古すぎます。少なくともこれより新しいMoodleである必要があります:",
"invalidsite": "サイトURLが正しくありません。",
- "invalidurl": "無効なURLです。",
+ "invalidurl": "あなたが入力したURLは正しくありません。",
"login": "ログイン",
+ "loginbutton": "ログイン",
"logininsiterequired": "ブラウザウインドウからサイトにログインする必要があります。",
"loginsteps": "このサイトにフルアクセスするため、あなたは最初にアカウントを作成する必要があります。",
"missingemail": "メールアドレスが入力されていません。",
@@ -24,7 +25,7 @@
"missinglastname": "姓が入力されていません。",
"mobileservicesnotenabled": "あなたのサイトではモバイルサービスが有効になっていません。モバイルアクセスが必要と思うなら、あなたのMoodleサイト管理者にその相談をしてください。",
"newaccount": "新しいアカウント",
- "password": "共有秘密鍵",
+ "password": "パスワード",
"passwordrequired": "パスワードがありません",
"policyaccept": "私は内容を理解および同意します。",
"policyagree": "このサイトを継続して利用するにはあなたは使用許諾に同意する必要があります。同意しますか?",
diff --git a/www/core/components/login/lang/lt.json b/www/core/components/login/lang/lt.json
index f5e96ef8b35..f1c04c57d49 100644
--- a/www/core/components/login/lang/lt.json
+++ b/www/core/components/login/lang/lt.json
@@ -19,7 +19,7 @@
"errorupdatesite": "Klaida atnaujinant svetainės kodą.",
"firsttime": "Ar jūs čia pirmą kartą?",
"getanothercaptcha": "Gauti kitą CAPTCHA",
- "help": "Žinynas",
+ "help": "Pagalba",
"helpmelogin": "
Visame pasaulyje Moodle svetainių yra labai daug. Ši programėlė gali prisijungti prie Moodle svetainių, turinčių specialią Moodle programėlių prieigą.
Norėdami išbandyti programėlės demo versiją surinkite teacher (dėstytojui) ar student (besimokančiajam)Svetainės adreso lauke ir paspauskite Prisijungti mygtuką.
",
"instructions": "Instrukcijos",
"invalidaccount": "Prašome patikrinti prisijungimo duomenis arba paprašyti administratoriaus patikrinti svetainės nustatymus.",
@@ -28,14 +28,14 @@
"invalidmoodleversion": "Negaliojanti Moodle versija. Turi būt ne senesnė nei 2.4.",
"invalidsite": "URL adresas netinkamas.",
"invalidtime": "Netinkamas laikas",
- "invalidurl": "Klaidingas URL",
+ "invalidurl": "Jūsų ką tik įvestas URL yra neleistinas",
"invalidvaluemax": "Didžiausia vertė {{$a}}",
"invalidvaluemin": "Mažiausia vertė {{$a}}",
"localmobileunexpectedresponse": "Moodle Mobilių Papildomų Funkcijų patikra gavo netikėtą atsakymą, būsite autentifikuojamas naudojant standartines mobilias paslaugas.",
"login": "Prisijungti",
"loginbutton": "Prisijungti",
"logininsiterequired": "Prisijunkite prie svetainės naršyklės lange.",
- "loginsteps": "Sveiki! Jei norite gauti visą prieigą prie kursų, turite šioje svetainėje sukurti savo paskyrą. Kiekvieni kursai taip pat gali turėti vienkartinius registracijos raktus, kurių reikės vėliau. Reikia atlikti tokius veiksmus:
Užpildykite naujos paskyros formą, pateikdami savo informaciją.
Jūsų el. pašto adresu bus iš karto išsiųstas el. laiškas.
\n
Perskaitykite el. laišką ir spustelėkite jame esantį saitą.
\n
Jūsų paskyra bus patvirtinta ir galėsite prisijungti.
\n
Tada pasirinkite kursus, kuriuose norite dalyvauti.
\n
Jei jūsų paprašys registracijos rakto, naudokite gautą iš dėstytojo. Taip įsiregistruosite į kursus.
Dabar galėsite pasiekti visą kursų informacija. Nuo šiol jums tereikės įvesti asmeninį naudotojo vardą ir slaptažodį (šio puslapio formoje), kad prisijungtumėte ir pasiektumėte visus kursus, kuriuose įsiregistravote.
",
+ "loginsteps": "Jei norite gauti visą prieigą prie svetainės, turite pirmiausiai sukurti savo paskyrą.",
"missingemail": "Nėra el. pašto adreso",
"missingfirstname": "Nėra pavadinimo",
"missinglastname": "Nėra pavardės",
@@ -43,7 +43,7 @@
"newaccount": "Nauja paskyra",
"newsitedescription": "Įveskite Moodle svetainės URL adresą. Atkreipkite dėmesį, kad gali būti nesukonfigūruotas dirbti su šia programėle.",
"notloggedin": "Turite prisijungti",
- "password": "Bendra paslaptis",
+ "password": "Slaptažodis",
"passwordrequired": "Reikalingas slaptažodis",
"policyaccept": "Suprantu ir sutinku",
"policyagree": "Norėdami toliau naudotis šia svetaine, turite sutikti su šia strategija. Ar sutinkate?",
diff --git a/www/core/components/login/lang/nl.json b/www/core/components/login/lang/nl.json
index c0cf35dece7..d8dae79b1fe 100644
--- a/www/core/components/login/lang/nl.json
+++ b/www/core/components/login/lang/nl.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Ongeldige Moodleversie. De vereiste minimumversie is:",
"invalidsite": "Deze site-URL is niet geldig.",
"invalidtime": "Ongeldige tijd",
- "invalidurl": "Ongeldige url",
+ "invalidurl": "De URL die je net gaf is niet geldig",
"invalidvaluemax": "De maximum waarde is {{$a}}",
"invalidvaluemin": "De minimum waard eis {{$a}}",
"localmobileunexpectedresponse": "Moodle Mobile Additional Features Check gaf een onverwacht antwoord. Je zult aanmelden via de standaard Mobile service.",
@@ -44,7 +44,7 @@
"newaccount": "Nieuwe account",
"newsitedescription": "Geef de URL van je Moodle site. Merk op dat die misschien niet geconfigureerd is om met deze app te werken.",
"notloggedin": "Je moet ingelogd zijn.",
- "password": "Gedeeld geheim",
+ "password": "Wachtwoord",
"passwordrequired": "Wachtwoord vereist",
"policyaccept": "Ik begrijp het en ga akkoord",
"policyagree": "Je moet akkoord gaan met deze overeenkomst voor je verder kunt gaan met het gebruiken van deze site. Ga je akkoord?",
diff --git a/www/core/components/login/lang/pl.json b/www/core/components/login/lang/pl.json
index b4472737bff..3fbd9ef1040 100644
--- a/www/core/components/login/lang/pl.json
+++ b/www/core/components/login/lang/pl.json
@@ -15,7 +15,7 @@
"invalidemail": "Niewłaściwy adres e-mail",
"invalidmoodleversion": "Nieprawidłowa wersja Moodle. Minimalna wymagana wersja to: ",
"invalidsite": "Adres strony jest nieprawidłowy.",
- "invalidurl": "Niepoprawny URL",
+ "invalidurl": "URL właśnie wprowadzony nie jest poprawny",
"login": "Zaloguj się",
"logininsiterequired": "Musisz się zalogować do strony w oknie przeglądarki.",
"loginsteps": "Aby otrzymać pełny dostęp do kursów w tym serwisie, musisz najpierw utworzyć konto.",
@@ -24,7 +24,7 @@
"missinglastname": "Pominięto nazwisko",
"mobileservicesnotenabled": "Usługi mobile nie są włączone na twojej stronie.Skontaktuj się z administratorem strony Moodle jeżeli uważasz, że dostęp mobilny powinien być włączony.",
"newaccount": "Nowe konto",
- "password": "Wspólne tajne hasło",
+ "password": "Hasło",
"passwordrequired": "Hasło wymagane",
"policyaccept": "Rozumiem i zgadzam się",
"policyagree": "Musisz zaakceptować te zasady, żeby używać strony. Czy zgadzasz się?",
diff --git a/www/core/components/login/lang/pt-br.json b/www/core/components/login/lang/pt-br.json
index e46b244e75a..5433d7bf34f 100644
--- a/www/core/components/login/lang/pt-br.json
+++ b/www/core/components/login/lang/pt-br.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "Versão do Moodle inválida. A versão mínima requerida é:",
"invalidsite": "A URL do siteé inválida.",
"invalidtime": "Tempo inválido",
- "invalidurl": "Url inválida",
+ "invalidurl": "A URL inserida não é válida",
"invalidvaluemax": "O valor máximo é {{$a}}",
"invalidvaluemin": "O valor minimo é{{$a}}",
"localmobileunexpectedresponse": "Verificação do Moodle Mobile Additional Features retornou uma resposta inesperada, você ira se autenticar usando o serviço Mobile padrão",
@@ -44,7 +44,7 @@
"newaccount": "Cadastramento de novo usuário",
"newsitedescription": "Por favor, digite a URL do seu site Moodle. Note que, pode ser que ele não esteja configurado para trabalhar com este app.",
"notloggedin": "Você precisa estar logado.",
- "password": "Segredo compartilhado",
+ "password": "Senha",
"passwordrequired": "Senha necessária",
"policyaccept": "Eu compreendo e concordo",
"policyagree": "Para utilizar este site você precisa aceitar o acordo sobre a política de uso do site. Você aceita os termos deste acordo?",
diff --git a/www/core/components/login/lang/pt.json b/www/core/components/login/lang/pt.json
index 80424147ec3..e7d8c53e078 100644
--- a/www/core/components/login/lang/pt.json
+++ b/www/core/components/login/lang/pt.json
@@ -28,7 +28,7 @@
"invalidmoodleversion": "A versão do Moodle é inválida. É necessária a versão 2.4 ou superior.",
"invalidsite": "O URL do site é inválido.",
"invalidtime": "Hora inválida",
- "invalidurl": "URL inválido",
+ "invalidurl": "O URL que introduziu não é válido",
"invalidvaluemax": "O valor máximo é {{$a}}",
"invalidvaluemin": "O valor mínimo é {{$a}}",
"localmobileunexpectedresponse": "A verificação do Moodle Mobile Additional Features teve um erro inesperado, a ligação será feita através do serviço Mobile padrão.",
@@ -44,7 +44,7 @@
"newaccount": "Nova conta",
"newsitedescription": "Por favor, digite o URL do seu site Moodle. Note que o mesmo poderá não estar configurado para funcionar nesta aplicação.",
"notloggedin": "Precisa de estar autenticado.",
- "password": "Senha partilhada",
+ "password": "Senha",
"passwordrequired": "Senha necessária",
"policyaccept": "Compreendo e concordo",
"policyagree": "Deverá aceitar este regulamento para poder proceder a utilizar este site. Aceita o regulamento?",
@@ -69,7 +69,7 @@
"startsignup": "Criar nova conta",
"stillcantconnect": "Continua com problemas na ligação?",
"supplyinfo": "Insira alguma informação sobre si",
- "username": "Nome de utilizador",
+ "username": "Utilizador",
"usernamerequired": "É necessário o nome de utilizador",
"usernotaddederror": "Utilizador não adicionado - erro.",
"visitchangepassword": "Pretende visitar o site para alterar a senha?",
diff --git a/www/core/components/login/lang/pt_br.json b/www/core/components/login/lang/pt_br.json
deleted file mode 100644
index 0ea1899f488..00000000000
--- a/www/core/components/login/lang/pt_br.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "authenticating": "Autenticação",
- "cancel": "Cancelar",
- "connect": "Conectar",
- "help": "Ajuda",
- "helpmelogin": "
Existem milhares de sites usando Moodle no mundo. Este aplicativo somente pode conectar com um Moodle se este foi especialmente configurado para permitir o acesso móvel.
\nSe não conseguir se conectar com o seu Moodle, vai precisar entrar em contato com a administradora do seu Moodle e pedir ela acessar http://docs.moodle.org/en/Mobile_app
\n
Para testar o aplicativo em um site Moodle demo, digite teacher ou estudent no campo Usuário e clique no botão Adicionar.
",
- "invalidaccount": "Por favor, verifique os detalhes de seu Usuário ou peça ao administrador do site para verificar a configuração do site.",
- "invalidmoodleversion": "Versão do Moodle inválida. A versão mínima requerida é:",
- "invalidsite": "A URL do siteé inválida.",
- "login": "Acessar",
- "logininsiterequired": "É preciso logar no site num navegador.",
- "mobileservicesnotenabled": "Os serviços móveis não estão habilitados no seu Moodle. Por favor contate a administradora do seu Moodle se achar que o acesso móvel deveria estar habilitado",
- "password": "Senha",
- "passwordrequired": "Senha necessária",
- "siteinmaintenance": "O site está em modo de manutenção",
- "siteurl": "URL do site",
- "siteurlrequired": "URL do site é obrigatória, por exemplo http://www.yourmoodlesite.abc ou https://www.yourmoodlesite.efg",
- "username": "Nome de Usuário",
- "usernamerequired": "Nome de usuário exigido",
- "webservicesnotenabled": "Web Services não estão ativados em seu site. Por favor, contate a administradora do seu Moodle se você achar que o acesso móvel deve ser ativado."
-}
\ No newline at end of file
diff --git a/www/core/components/login/lang/ro.json b/www/core/components/login/lang/ro.json
index 7eac7e64d7d..3ee06d65b14 100644
--- a/www/core/components/login/lang/ro.json
+++ b/www/core/components/login/lang/ro.json
@@ -2,7 +2,7 @@
"authenticating": "Autentificare",
"cancel": "Anulează",
"confirmdeletesite": "Sunteți sigur că doriți sa ștergeți siteul {{sitename}}?",
- "connect": "Conectare!",
+ "connect": "Conectează",
"connecttomoodle": "Conectare la Moodle",
"createaccount": "Creează noul meu cont",
"createuserandpass": "Alege un nume de utilizator şi o parolă",
@@ -21,7 +21,7 @@
"invalidemail": "Adresă de email incorectă",
"invalidmoodleversion": "Versiunea Moodle este invalidă. Versiunea minimă este 2.4",
"invalidsite": "Adresa URL este invalidă.",
- "invalidurl": "URL incorect",
+ "invalidurl": "URL-ul pe care l-aţi introdus nu este corect",
"localmobileunexpectedresponse": "Verificarea Moodle Mobile Additional Features a returnat un răspuns neașteptat. veți fi autentificat folosind serviciul standard.",
"login": "Autentificare",
"loginbutton": "Logat!",
@@ -34,7 +34,7 @@
"newaccount": "Cont nou",
"newsitedescription": "Introduceți adresa URL a siteului dumneavoastră, dar există posibilitatea ca acesta să nu fie configurat pentru a funcționa cu această aplicație.",
"notloggedin": "Trebuie să fiți logat.",
- "password": "Cheie înscriere",
+ "password": "Parolă",
"passwordrequired": "Este necesară introducerea parolei",
"policyaccept": "Înţeleg şi sunt de acord",
"policyagree": "Pentru a continua să folosiţi acest site, trebuie să fiţi de acord cu termenii de utilizare specificaţi. Sunteţi de acord?",
@@ -52,7 +52,7 @@
"siteurlrequired": "Este necesară adresa URL a siteului, de exemplu http://www.yourmoodlesite.abc sau https://www.yourmoodlesite.efg",
"startsignup": "Creează cont",
"supplyinfo": "Detalii suplimentare",
- "username": "Utilizator",
+ "username": "Nume de utilizator",
"usernamerequired": "Este necesar numele de utilizator",
"usernotaddederror": "Utilizatorul nu a fost adăugat - eroare",
"webservicesnotenabled": "Serviciul Web nu este activat pe siteul dumneavoastră. Va rugăm să contactați administratorul siteului dumneavoastră dacă considerați ca ar trebui activat accesul pentru mobil."
diff --git a/www/core/components/login/lang/ru.json b/www/core/components/login/lang/ru.json
index cb180bd40f9..549581702a7 100644
--- a/www/core/components/login/lang/ru.json
+++ b/www/core/components/login/lang/ru.json
@@ -1,6 +1,6 @@
{
"authenticating": "Аутентификация",
- "cancel": "Отмена",
+ "cancel": "Отменить",
"confirmdeletesite": "Вы уверены, что хотите удалить сайт {{sitename}}?",
"connect": "Подключено!",
"connecttomoodle": "Подключение к Moodle",
@@ -14,14 +14,14 @@
"errorupdatesite": "При обновлении ключа сайта произошла ошибка.",
"firsttime": "Вы в первый раз на нашем сайте?",
"getanothercaptcha": "Получить другой CAPTCHA (тест для различения людей и компьютеров)",
- "help": "Справка",
+ "help": "Помощь",
"helpmelogin": "
Во всем мире есть тысячи сайтов Moodle. Это приложение может подключаться только к тем сайтам Moodle, на которых разрешен доступ конкретному виду мобильного приложения.
Если Вы не можете подключиться к сайту Moodle, то необходимо связаться с администратором сайта, к которому Вы хотите подключиться, и попросить его прочитать http://docs.moodle.org/en/Mobile_app
Чтобы проверить приложение на демо-сайте Moodle, выберите учитель или студент,введите URL-адрес сайта в соответствующее поле и нажмите кнопку «Добавить».
",
"instructions": "Инструкции",
"invalidaccount": "Пожалуйста, проверьте свои регистрационные данные или обратитесь к администратору сайта, чтобы он проверил настройки сайта.",
"invalidemail": "Некорректный формат адреса электронной почты",
"invalidmoodleversion": "Неверная версия Moodle. Минимальная требуемая версия - 2.4.",
"invalidsite": "URL-адрес сайта недействителен.",
- "invalidurl": "Некорректный URL",
+ "invalidurl": "Вы указали некорректный адрес",
"login": "Вход",
"loginbutton": "Вход!",
"logininsiterequired": "Вы должны войти на сайт в окне браузера.",
@@ -33,7 +33,7 @@
"newaccount": "Новая учетная запись",
"newsitedescription": "Пожалуйста, введите URL-адрес своего сайта Moodle. Учтите, что он может быть не настроен для работы с этим приложением.",
"notloggedin": "Вы должны быть идентифицированы.",
- "password": "Общий секретный ключ",
+ "password": "Пароль",
"passwordrequired": "Требуется пароль",
"policyaccept": "Я понял(а) и согласен(на)",
"policyagree": "Чтобы продолжить работу с этим сайтом, Вы должны принять Пользовательское соглашение. Вы согласны?",
diff --git a/www/core/components/login/lang/sr-cr.json b/www/core/components/login/lang/sr-cr.json
new file mode 100644
index 00000000000..8cb06921b18
--- /dev/null
+++ b/www/core/components/login/lang/sr-cr.json
@@ -0,0 +1,77 @@
+{
+ "auth_email": "Самостална регистрација на основу е-адресе",
+ "authenticating": "Провера идентитета",
+ "cancel": "Одустани",
+ "checksiteversion": "Проверите да ли ваш сајт користи Moodle 2.4 или новију верзију.",
+ "confirmdeletesite": "Да ли сте сигурни да желите да обришете сајт {{sitename}}?",
+ "connect": "Повежите се!",
+ "connecttomoodle": "Повежите се са Moodleom",
+ "contactyouradministrator": "Обратите се администратору вашег сајта за даљу помоћ.",
+ "contactyouradministratorissue": "Замолите администратора да провери следећи проблем: {{$a}}",
+ "createaccount": "Креирај мој нови кориснички налог",
+ "createuserandpass": "Изаберите своје корисничко име и лозинку за приступ систему",
+ "credentialsdescription": "За пријаву на систем унесите своје корисничко име и лозинку.",
+ "emailconfirmsent": "
Требало би да је послата порука на вашу е-адресу {{$a}}
Порука садржи једноставна упутства о даљем поступку регистрације.
Ако и даље имате проблема, обратите се администратору сајта.
",
+ "emailnotmatch": "Адресе е-поште се не поклапају",
+ "enterthewordsabove": "Унесите реч изнад",
+ "erroraccesscontrolalloworigin": "Cross-Origin позив који покушавате да изведете је одбијен. Молимо, проверите https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium",
+ "errordeletesite": "Дошло је до грешке приликом брисања овог сајта. Молим, покушајте поново.",
+ "errorupdatesite": "Дошло је до грешке приликом ажурирању токена сајта.",
+ "firsttime": "Да ли сте овде први пут?",
+ "getanothercaptcha": "Преузмите други CAPTCHА",
+ "help": "Помоћ",
+ "helpmelogin": "
Широм света постоји више хиљада Moodle сајтова. Ова апликација може се повезати само са Moodle сајтовима који су наменски омогућили приступ апликацијама за мобилне уређаје.
Ако не можете да се повежете са вашим Moodle сајтом потребно је да се обратите Moodle администратору сајта са којим желите да се повежете и да га замолите да прочитаhttp://docs.moodle.org/en/Mobile_app
За тестирање апликације на Moodle демо сајту унесите teacher или student у поље Адреса сајта и кликните на дугме Повежи се!.
",
+ "instructions": "Упутства",
+ "invalidaccount": "Проверите своје податке за пријаву или замолите вашег администратора да провери конфигурацију сајта.",
+ "invaliddate": "Неисправан датум",
+ "invalidemail": "Неисправна адреса електронске поште",
+ "invalidmoodleversion": "Неисправна Moodle верзија. Неопходна је, минимално, верзија 2.4.",
+ "invalidsite": "URL адреса сајт није исправна.",
+ "invalidtime": "Неисправно време",
+ "invalidurl": "Неисправан url",
+ "invalidvaluemax": "Максимална вредност је {{$a}}",
+ "invalidvaluemin": "Минимална вредност је {{$a}}",
+ "localmobileunexpectedresponse": "Провера Moodle Mobile додатних функционалности вратила је неочекиван одговор. Ваш идентитет биће проверен помоћу стандардног мобилнog сервиса.",
+ "loggedoutssodescription": "Морате поново да потврдите свој идентитет. Потребно је да се пријавите на сајт у прозору веб читача.",
+ "login": "Пријава",
+ "loginbutton": "Пријава",
+ "logininsiterequired": "Потребно је да се пријавите на сајт у прозору веб читача.",
+ "loginsteps": "Како бисте имали пуни приступ овом сајту морате креирати кориснички налог.",
+ "missingemail": "Недостаје адреса е-поште",
+ "missingfirstname": "Недостаје име",
+ "missinglastname": "Недостаје презиме",
+ "mobileservicesnotenabled": "Мобилни сервиси нису омогућени на вашем сајту. Обратите се администратору вашег Moodle сајта ако мислите да мобилни приступ треба да буде омогућен.",
+ "newaccount": "Нови кориснички налог",
+ "newsitedescription": "Унесите URL адресу вашег Moodle сајта. Имајте на уму да сајт можда није конфигурисан да ради са овом апликацијом.",
+ "notloggedin": "Морате бити пријављени.",
+ "password": "Лозинка",
+ "passwordrequired": "Неопходна је лозинка",
+ "policyaccept": "Разумем и пристајем",
+ "policyagree": "Да би сте наставили коришћење овог сајта морате се сложити са правилима коришћења. Да ли се слажете?",
+ "policyagreement": "Сагласност са правилником о коришћењу сајта",
+ "policyagreementclick": "Линк ка правилнику о коришћењу сајта",
+ "potentialidps": "Пријавите се користећи свој налог на:",
+ "problemconnectingerror": "Имамо проблема да се повежемо са",
+ "problemconnectingerrorcontinue": "Добро проверите да ли сте правилно унели адресу и покушајте поново.",
+ "profileinvaliddata": "Неисправна вредност",
+ "recaptchachallengeimage": "reCAPTCHA слика",
+ "reconnect": "Повежите се поново",
+ "reconnectdescription": "Ваш токен за проверу идентитета је неисправан или је истекао. Морате поново да успоставите везу са сајтом.",
+ "reconnectssodescription": "Ваш токен за проверу идентитета је неисправан или је истекао. Морате поново да успоставите везу са сајтом. Потребно је да се пријавите на сајт у прозору веб читача.",
+ "security_question": "Безбедносно питање",
+ "selectacountry": "Изабери државу",
+ "signupplugindisabled": "{{$a}} није омогућен.",
+ "siteaddress": "Адреса сајта",
+ "siteinmaintenance": "Ваш сајт је у режиму одржавања",
+ "sitepolicynotagreederror": "Сагласност са политиком сајта није потврђена.",
+ "siteurl": "URL адреса сајта",
+ "siteurlrequired": "Неопходна је URL адреса, нпр. http://www.yourmoodlesite.abc или https://www.yourmoodlesite.efg",
+ "startsignup": "Креирај нови налог",
+ "stillcantconnect": "Још увек не можете да се повежете?",
+ "supplyinfo": "Више детаља",
+ "username": "Корисничко име",
+ "usernamerequired": "Корисничко име је неопходно",
+ "usernotaddederror": "Корисник није додат - грешка",
+ "visitchangepassword": "Да ли желите да посетите сајт како бисте променили лозинку?",
+ "webservicesnotenabled": "Веб сервиси нису омогућени на вашем сајту. Обратите се администратору вашег Moodle сајта ако мислите да мобилни приступ треба да буде омогућен."
+}
\ No newline at end of file
diff --git a/www/core/components/login/lang/sr-lt.json b/www/core/components/login/lang/sr-lt.json
new file mode 100644
index 00000000000..337bb4983ae
--- /dev/null
+++ b/www/core/components/login/lang/sr-lt.json
@@ -0,0 +1,77 @@
+{
+ "auth_email": "Samostalna registracija na osnovu e-adrese",
+ "authenticating": "Provera identiteta",
+ "cancel": "Odustani",
+ "checksiteversion": "Proverite da li vaš sajt koristi Moodle 2.4 ili noviju verziju.",
+ "confirmdeletesite": "Da li ste sigurni da želite da obrišete sajt {{sitename}}?",
+ "connect": "Povežite se!",
+ "connecttomoodle": "Povežite se sa Moodleom",
+ "contactyouradministrator": "Obratite se administratoru vašeg sajta za dalju pomoć.",
+ "contactyouradministratorissue": "Zamolite administratora da proveri sledeći problem: {{$a}}",
+ "createaccount": "Kreiraj moj novi korisnički nalog",
+ "createuserandpass": "Izaberite svoje korisničko ime i lozinku za pristup sistemu",
+ "credentialsdescription": "Za prijavu na sistem unesite svoje korisničko ime i lozinku.",
+ "emailconfirmsent": "
Trebalo bi da je poslata poruka na vašu e-adresu {{$a}}
Poruka sadrži jednostavna uputstva o daljem postupku registracije.
Ako i dalje imate problema, obratite se administratoru sajta.
",
+ "emailnotmatch": "Adrese e-pošte se ne poklapaju",
+ "enterthewordsabove": "Unesite reč iznad",
+ "erroraccesscontrolalloworigin": "Cross-Origin poziv koji pokušavate da izvedete je odbijen. Molimo, proverite https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium",
+ "errordeletesite": "Došlo je do greške prilikom brisanja ovog sajta. Molim, pokušajte ponovo.",
+ "errorupdatesite": "Došlo je do greške prilikom ažuriranju tokena sajta.",
+ "firsttime": "Da li ste ovde prvi put?",
+ "getanothercaptcha": "Preuzmite drugi CAPTCHA",
+ "help": "Pomoć",
+ "helpmelogin": "
Širom sveta postoji više hiljada Moodle sajtova. Ova aplikacija može se povezati samo sa Moodle sajtovima koji su namenski omogućili pristup aplikacijama za mobilne uređaje.
Ako ne možete da se povežete sa vašim Moodle sajtom potrebno je da se obratite Moodle administratoru sajta sa kojim želite da se povežete i da ga zamolite da pročitahttp://docs.moodle.org/en/Mobile_app
Za testiranje aplikacije na Moodle demo sajtu unesite teacher ili student u polje Adresa sajta i kliknite na dugme Poveži se!.
",
+ "instructions": "Uputstva",
+ "invalidaccount": "Proverite svoje podatke za prijavu ili zamolite vašeg administratora da proveri konfiguraciju sajta.",
+ "invaliddate": "Neispravan datum",
+ "invalidemail": "Neispravna adresa elektronske pošte",
+ "invalidmoodleversion": "Neispravna Moodle verzija. Neophodna je, minimalno, verzija 2.4.",
+ "invalidsite": "URL adresa sajt nije ispravna.",
+ "invalidtime": "Neispravno vreme",
+ "invalidurl": "Neispravan url",
+ "invalidvaluemax": "Maksimalna vrednost je {{$a}}",
+ "invalidvaluemin": "Minimalna vrednost je {{$a}}",
+ "localmobileunexpectedresponse": "Provera Moodle Mobile dodatnih funkcionalnosti vratila je neočekivan odgovor. Vaš identitet biće proveren pomoću standardnog mobilnog servisa.",
+ "loggedoutssodescription": "Morate ponovo da potvrdite svoj identitet. Potrebno je da se prijavite na sajt u prozoru veb čitača.",
+ "login": "Prijava",
+ "loginbutton": "Prijava",
+ "logininsiterequired": "Potrebno je da se prijavite na sajt u prozoru veb čitača.",
+ "loginsteps": "Kako biste imali puni pristup ovom sajtu morate kreirati korisnički nalog.",
+ "missingemail": "Nedostaje adresa e-pošte",
+ "missingfirstname": "Nedostaje ime",
+ "missinglastname": "Nedostaje prezime",
+ "mobileservicesnotenabled": "Mobilni servisi nisu omogućeni na vašem sajtu. Obratite se administratoru vašeg Moodle sajta ako mislite da mobilni pristup treba da bude omogućen.",
+ "newaccount": "Novi korisnički nalog",
+ "newsitedescription": "Unesite URL adresu vašeg Moodle sajta. Imajte na umu da sajt možda nije konfigurisan da radi sa ovom aplikacijom.",
+ "notloggedin": "Morate biti prijavljeni.",
+ "password": "Lozinka",
+ "passwordrequired": "Neophodna je lozinka",
+ "policyaccept": "Razumem i pristajem",
+ "policyagree": "Da bi ste nastavili korišćenje ovog sajta morate se složiti sa pravilima korišćenja. Da li se slažete?",
+ "policyagreement": "Saglasnost sa pravilnikom o korišćenju sajta",
+ "policyagreementclick": "Link ka pravilniku o korišćenju sajta",
+ "potentialidps": "Prijavite se koristeći svoj nalog na:",
+ "problemconnectingerror": "Imamo problema da se povežemo sa",
+ "problemconnectingerrorcontinue": "Dobro proverite da li ste pravilno uneli adresu i pokušajte ponovo.",
+ "profileinvaliddata": "Neispravna vrednost",
+ "recaptchachallengeimage": "reCAPTCHA slika",
+ "reconnect": "Povežite se ponovo",
+ "reconnectdescription": "Vaš token za proveru identiteta je neispravan ili je istekao. Morate ponovo da uspostavite vezu sa sajtom.",
+ "reconnectssodescription": "Vaš token za proveru identiteta je neispravan ili je istekao. Morate ponovo da uspostavite vezu sa sajtom. Potrebno je da se prijavite na sajt u prozoru veb čitača.",
+ "security_question": "Bezbednosno pitanje",
+ "selectacountry": "Izaberi državu",
+ "signupplugindisabled": "{{$a}} nije omogućen.",
+ "siteaddress": "Adresa sajta",
+ "siteinmaintenance": "Vaš sajt je u režimu održavanja",
+ "sitepolicynotagreederror": "Saglasnost sa politikom sajta nije potvrđena.",
+ "siteurl": "URL adresa sajta",
+ "siteurlrequired": "Neophodna je URL adresa, npr. http://www.yourmoodlesite.abc ili https://www.yourmoodlesite.efg",
+ "startsignup": "Kreiraj novi nalog",
+ "stillcantconnect": "Još uvek ne možete da se povežete?",
+ "supplyinfo": "Više detalja",
+ "username": "Korisničko ime",
+ "usernamerequired": "Korisničko ime je neophodno",
+ "usernotaddederror": "Korisnik nije dodat - greška",
+ "visitchangepassword": "Da li želite da posetite sajt kako biste promenili lozinku?",
+ "webservicesnotenabled": "Veb servisi nisu omogućeni na vašem sajtu. Obratite se administratoru vašeg Moodle sajta ako mislite da mobilni pristup treba da bude omogućen."
+}
\ No newline at end of file
diff --git a/www/core/components/login/lang/sv.json b/www/core/components/login/lang/sv.json
index b4041bf5a3d..94336186f13 100644
--- a/www/core/components/login/lang/sv.json
+++ b/www/core/components/login/lang/sv.json
@@ -7,11 +7,11 @@
"createaccount": "Skapa mitt nya konto",
"createuserandpass": "Skapa ett nytt användarnamn och lösenord för att logga in med.",
"credentialsdescription": "Ange ditt användarnamn och lösenord för att logga på",
- "emailconfirmsent": "
Vi har skickat ett e-postbrev som Du bör ha fått till Din adress på {{$a}}
\n
Det innehåller enkla instruktioner som hjälper Dig att fullfölja Din registrering.
\n
Om Du stöter på problem, är Du välkommen att kontakta den som ansvarar för webbplatsen.
",
+ "emailconfirmsent": "
Vi har skickat ett e-postbrev som du bör ha fått till din adress på {{$a}}
\n
Det innehåller enkla instruktioner som hjälper dig att fullfölja din registrering.
\n
Om du stöter på problem, är du välkommen att kontakta den som ansvarar för webbplatsen.
",
"enterthewordsabove": "Mata in de ovanstående orden",
"errordeletesite": "Ett fel inträffade vid borttagning av denna webbsida. Var god försök igen.",
"errorupdatesite": "Ett fel inträffade vid uppdatering av webbplatsens token.",
- "firsttime": "Är det första gången Du är här?",
+ "firsttime": "Är det första gången du är här?",
"getanothercaptcha": "Skaffa en CAPTCHA till",
"help": "Hjälp",
"helpmelogin": "
För att logga in måste du kontrollera att: p> 1. Moodle webbplats är version 2.4 eller högre 2. Moodle administratören har aktiverat Mobil åtkomst
Ett e-postmeddelande kommer därefter\nomedelbart att sändas till\nDin e-postadress.
\n
Läs din e-post, och klicka på webblänken som den innehåller.
\n
Ditt konto kommer därmed att bekräftas\noch Du kommer att loggas in.
\n
Nu kan Du välja vilken kurs Du\nvill delta i.
\n
Om Du måste ange en \"kursnyckel\" - så\nfår Du använda den som Din lärare har\ngivit Dig. Med den kan Du registrera\nDig på en sådan kurs som kräver det.
\n
Nu kan Du använda hela kursen.\nFrån och med nu behöver Du bara skriva\nin Ditt användarnamn och lösenord\n(i formuläret till vänster på denna sida)\nför att logga in och för att nå de kurser\nsom Du är registrerad på.
\n \nOBS! Genom att Du bekräftar kontot så samtycker\nDu till databehandling enligt Personuppgiftslagen.\nOm Du är osäker på vad det innebär så kan Du hitta\nmer information här: 'http://www.datainspektionen.se/lagar-och-regler/personuppgiftslagen/\n'\n\nLycka till!",
+ "loginsteps": "Hej!\n \nDu måste bl.a. skapa ett nytt användarkonto på denna webbplats för att få tillgång till de kurser som du vill delta i. Varje individuell kurs kan också ha en engångsnyckel \"kursnyckel\". Den behöver du dock inte förrän senare.\n Så här skapar du ditt konto:\n \n
Fyll i formuläret på sidan \nNytt konto med de efterfrågade\nuppgifterna om dig själv.
\n
Ett e-postmeddelande kommer därefter\nomedelbart att sändas till\ndin e-postadress.
\n
Läs din e-post, och klicka på webblänken som den innehåller.
\n
Ditt konto kommer därmed att bekräftas\noch du kommer att loggas in.
\n
Nu kan du välja vilken kurs du\nvill delta i.
\n
Om du måste ange en \"kursnyckel\" - så\nfår du använda den som din lärare har\ngivit dig. Med den kan du registrera\ndig på en sådan kurs som kräver det.
\n
Nu kan du använda hela kursen.\nFrån och med nu behöver du bara skriva\nin ditt användarnamn och lösenord\n(i formuläret till vänster på denna sida)\nför att logga in och för att nå de kurser\nsom du är registrerad på.
\n \nOBS! Genom att du bekräftar kontot så samtycker\ndu till databehandling enligt Personuppgiftslagen.\nOm du är osäker på vad det innebär så kan du hitta\nmer information här: 'http://www.datainspektionen.se/lagar-och-regler/personuppgiftslagen/\n'\n\nLycka till!",
"missingemail": "E-postadress saknas",
"missingfirstname": "Förnamn saknas",
"missinglastname": "Efternamn saknas",
@@ -36,7 +36,7 @@
"password": "Lösenord",
"passwordrequired": "Lösenord krävs",
"policyaccept": "Jag förstår och accepterar",
- "policyagree": "Du måste acceptera denna policy för få fortsätta att använda denna webbplats. Accepterar Du denna policy?",
+ "policyagree": "Du måste acceptera denna policy för få fortsätta att använda denna webbplats. Accepterar du denna policy?",
"policyagreement": "Avtal angående webbplatsens policy.",
"policyagreementclick": "Klicka här för att läsa avtalet angående webbplatsens policy.",
"potentialidps": "Logga in med ditt konto på:",
diff --git a/www/core/components/login/lang/tr.json b/www/core/components/login/lang/tr.json
index 46bf85328fd..e417e613e87 100644
--- a/www/core/components/login/lang/tr.json
+++ b/www/core/components/login/lang/tr.json
@@ -17,7 +17,7 @@
"invalidemail": "Geçersiz e-posta adresi",
"invalidmoodleversion": "Geçersiz Moodle sürümü. Sitenizin Sürümünün şundan aşağı olmaması gerekir:",
"invalidsite": "Bu site adresi geçersizdir.",
- "invalidurl": "Geçersiz URL",
+ "invalidurl": "Girdiğiniz URL geçerli değil",
"login": "Giriş yap",
"logininsiterequired": "Bir tarayıcı penceresinde siteye giriş yapmanız gerekiyor.",
"loginsteps": "Bu siteye tam erişim için önce bir hesap oluşturmalısınız.",
diff --git a/www/core/components/login/lang/uk.json b/www/core/components/login/lang/uk.json
index eb2ed868ac3..3288bf24510 100644
--- a/www/core/components/login/lang/uk.json
+++ b/www/core/components/login/lang/uk.json
@@ -1,11 +1,11 @@
{
"auth_email": "Email на основі самостійної реєстрації",
- "authenticating": "Аутинтифікація",
+ "authenticating": "Аутентифікація",
"cancel": "Скасувати",
"checksiteversion": "Переконайтеся, що ваш сайт використовує Moodle 2.4 або більш пізньої версії.",
"confirmdeletesite": "Видалити сайт {{sitename}}?",
"connect": "З'єднано!",
- "connecttomoodle": "Відключитись до Moodle",
+ "connecttomoodle": "Підключитись до Moodle",
"contactyouradministrator": "Зверніться до адміністратора сайту для подальшої допомоги.",
"contactyouradministratorissue": "Будь ласка, зверніться до адміністратора, щоб перевірити наступне питання: {{$a}}",
"createaccount": "Створити запис",
@@ -14,21 +14,21 @@
"emailconfirmsent": "
Лист повинен бути відправлений на Вашу електронну адресу в {{$a}}
Він містить прості інструкції для завершення реєстрації.
Якщо ви продовжуєте зазнавати труднощів, зверніться до адміністратора сайту.
",
"emailnotmatch": "Email не співпадають",
"enterthewordsabove": "Введіть символи, які бачите вище",
- "erroraccesscontrolalloworigin": "Cross-Origin дзвінок Ви намагаєтеся виконати відхилено. Будь ласка, перевірте https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium",
+ "erroraccesscontrolalloworigin": "Cross-Origin дзвінок був відхилений. Будь ласка, перевірте https://docs.moodle.org/dev/Moodle_Mobile_development_using_Chrome_or_Chromium",
"errordeletesite": "Під час видалення цього сайту сталася помилка. Будь ласка спробуйте ще раз.",
"errorupdatesite": "При оновленні токена сайту сталася помилка.",
"firsttime": "Ви вперше на нашому сайті?",
"getanothercaptcha": "Отримати інший варант",
"help": "Допомога",
- "helpmelogin": "
Є багато тисяч сайтів Moodle по всьому світу. Ця програма може підключатися тільки до сайтів Moodle, які спеціально з підтримкою мобільного доступу додатків.
Якщо ви не можете підключитися до вашого сайту Moodle, то вам необхідно звернутися до адміністратора Moodle в тому місці, де планується отримати доступ і попросіть їх прочитати http://docs.moodle.org/en/Mobile_app
Щоб перевірити додаток в типі Moodle демо сайті учитель або студент в адреса сайту поля і натисніть кнопку Підключення .
",
+ "helpmelogin": "
Є багато тисяч сайтів Moodle по всьому світу. Ця програма може підключатися тільки до сайтів Moodle, які є з підтримкою мобільного доступу додатків.
Якщо ви не можете підключитися до вашого сайту Moodle, то вам необхідно звернутися до адміністратора Moodle в тому місці, де планується отримати доступ і попросіть їх прочитати http://docs.moodle.org/en/Mobile_app
Щоб перевірити додаток на Moodle демо сайті в ролі вчителя або студента в полі адреса сайту і натисніть кнопку Підключення .
",
"instructions": "Інструкції",
"invalidaccount": "Будь ласка, перевірте ваші реєстраційні дані, або зверніться до адміністратора сайту, щоб перевірити конфігурацію сайту.",
"invaliddate": "Невірна дата",
"invalidemail": "Неправильний формат для ел.пошти",
- "invalidmoodleversion": "Невірна версія Moodle. Мінімальна версія 2.4 потрібно.",
+ "invalidmoodleversion": "Невірна версія Moodle. Мінімальна версія 2.4.",
"invalidsite": "URL сайту недійсний.",
"invalidtime": "Невірний час",
- "invalidurl": "Неправильний URL",
+ "invalidurl": "Введений вами URL неправильний",
"invalidvaluemax": "Максимальне значення {{$a}}",
"invalidvaluemin": "Мінімальне значення {{$a}}",
"localmobileunexpectedresponse": "Moodle Mobile Additional Features при перевірці повернуло несподівану відповідь, ви будете проходити перевірку автентичності з використанням стандартного мобільного сервісу.",
@@ -40,11 +40,11 @@
"missingemail": "Не вказано адресу електронної пошти",
"missingfirstname": "Не вказано ім'я",
"missinglastname": "Не вказано прізвище",
- "mobileservicesnotenabled": "Мобільні послуги не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, мобільний доступ повинен бути включений.",
+ "mobileservicesnotenabled": "Мобільні послуги не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, що мобільний доступ повинен бути включений.",
"newaccount": "Новий обліковий запис",
- "newsitedescription": "Будь ласка, введіть адресу вашого сайту Moodle. Зверніть увагу, що це не може бути налаштоване для роботи з цим додатком.",
+ "newsitedescription": "Будь ласка, введіть адресу вашого сайту Moodle. Зверніть увагу, що це може бути не налаштоване для роботи з цим додатком.",
"notloggedin": "Ви повинні увійти в систему.",
- "password": "Відкритий ключ",
+ "password": "Пароль",
"passwordrequired": "Пароль необхідний",
"policyaccept": "Я розумію та погоджуюся",
"policyagree": "Ви повинні погодитися з цими правилами для використання цього сайту. Ви згодні?",
@@ -57,7 +57,7 @@
"recaptchachallengeimage": "виклик reCAPTCHA",
"reconnect": "Повторне з'єднання",
"reconnectdescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні підключитися до сайту.",
- "reconnectssodescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні підключитися до сайту. Вам необхідно увійти на сайт у вікні браузера.",
+ "reconnectssodescription": "Ваш маркер аутентифікації недійсний або закінчився, ви повинні перепідключитися до сайту. Вам необхідно увійти на сайт у вікні браузера.",
"security_question": "Контрольне питання",
"selectacountry": "Країна",
"signupplugindisabled": "{{$a}} не доступно.",
@@ -67,11 +67,11 @@
"siteurl": "URL сайту",
"siteurlrequired": "URL сайту повинно бути схоже на http://www.yourmoodlesite.abc or https://www.yourmoodlesite.efg",
"startsignup": "Створити новий обліковий запис",
- "stillcantconnect": "До сих пір не можу підключитися?",
+ "stillcantconnect": "До сих пір не можете підключитися?",
"supplyinfo": "Більше інформації",
- "username": "Ім’я входу",
+ "username": "Псевдо",
"usernamerequired": "Ім'я користувача необхідне",
"usernotaddederror": "Користувач не доданий - помилка",
"visitchangepassword": "Ви хочете відвідати сайт, щоб змінити пароль?",
- "webservicesnotenabled": "Веб-служба не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайт, якщо ви вважаєте, мобільний доступ повинен бути включений."
+ "webservicesnotenabled": "Веб-служба не включені в вашому сайті. Будь ласка, зверніться до адміністратора вашого Moodle сайту, якщо ви вважаєте, що мобільний доступ повинен бути включений."
}
\ No newline at end of file
diff --git a/www/core/components/login/lang/zh-cn.json b/www/core/components/login/lang/zh-cn.json
index 64f858f8e48..7c5cb7f013d 100644
--- a/www/core/components/login/lang/zh-cn.json
+++ b/www/core/components/login/lang/zh-cn.json
@@ -15,7 +15,7 @@
"invalidemail": "Email地址无效",
"invalidmoodleversion": "无效的Moodle版本。最低版本要求是:",
"invalidsite": "网站URL是无效的。",
- "invalidurl": "无效的 网页地址",
+ "invalidurl": "您刚刚输入的 URL 不合法",
"login": "登录",
"logininsiterequired": "您需要在浏览器窗口中登录该站点。",
"loginsteps": "为了能完全访问此网站,您首先需要创建一个帐户。",
@@ -24,7 +24,7 @@
"missinglastname": "姓没填",
"mobileservicesnotenabled": "您的站点没有启用移动服务,如果您觉得有必要开启移动接入功能,请与站点管理员联系。",
"newaccount": "新帐号",
- "password": "设置密码",
+ "password": "密码",
"passwordrequired": "需要密码",
"policyaccept": "我了解和同意了",
"policyagree": "如要继续使用此站,您必须同意此协议。您同意么?",
diff --git a/www/core/components/login/lang/zh-tw.json b/www/core/components/login/lang/zh-tw.json
index bb2823d16de..110d8e28784 100644
--- a/www/core/components/login/lang/zh-tw.json
+++ b/www/core/components/login/lang/zh-tw.json
@@ -19,7 +19,7 @@
"errorupdatesite": "更新網站權杖時出錯.",
"firsttime": "您第一次來訪嗎?",
"getanothercaptcha": "換一個字詞",
- "help": "輔助說明",
+ "help": "幫助",
"helpmelogin": "